Skip to main content

lib/rulestead_admin/components/operator_components.ex

defmodule RulesteadAdmin.Components.OperatorComponents do
  @moduledoc false

  use Phoenix.Component

  attr(:title, :string, required: true)
  attr(:body, :string, required: true)
  attr(:tone, :string, default: "neutral")
  attr(:aria_label, :string, default: nil)

  def banner(assigns) do
    ~H"""
    <section class="rs-banner" data-tone={@tone} aria-label={@aria_label}>
      <h2><%= @title %></h2>
      <p><%= @body %></p>
    </section>
    """
  end

  attr(:title, :string, required: true)
  attr(:summary, :string, default: nil)
  slot(:inner_block)

  def page_section(assigns) do
    ~H"""
    <section class="rs-page-section">
      <h2><%= @title %></h2>
      <p :if={@summary}><%= @summary %></p>
      <%= render_slot(@inner_block) %>
    </section>
    """
  end

  attr(:title, :string, required: true)
  attr(:href, :string, required: true)
  attr(:meta, :string, default: nil)
  attr(:tone, :string, default: "neutral")
  slot(:inner_block)
  slot(:actions)

  def record_row(assigns) do
    ~H"""
    <article class="rs-record-row" data-tone={@tone}>
      <header class="rs-record-row__header">
        <div>
          <h3 class="rs-record-row__title"><a href={@href}><%= @title %></a></h3>
          <p :if={@meta} class="rs-record-row__meta"><%= @meta %></p>
        </div>
        <div :if={@actions != []} class="rs-record-row__actions">
          <%= render_slot(@actions) %>
        </div>
      </header>
      <div :if={@inner_block != []} class="rs-record-row__body">
        <%= render_slot(@inner_block) %>
      </div>
    </article>
    """
  end

  attr(:rows, :list, default: [])

  def detail_grid(assigns) do
    ~H"""
    <dl class="rs-kv-grid">
      <div :for={row <- @rows}>
        <dt><%= row.label %></dt>
        <dd><%= row.value %></dd>
      </div>
    </dl>
    """
  end

  attr(:title, :string, required: true)
  attr(:summary, :string, default: nil)
  attr(:href, :string, required: true)
  attr(:tone, :string, default: "neutral")
  attr(:primary?, :boolean, default: false)

  def task_link(assigns) do
    ~H"""
    <a
      class={["rs-task-link", @primary? && "rs-task-link--primary"]}
      data-tone={@tone}
      href={@href}
    >
      <strong><%= @title %></strong>
      <span :if={@summary}><%= @summary %></span>
    </a>
    """
  end

  attr(:label, :string, required: true)
  attr(:value, :any, required: true)
  attr(:tone, :string, default: "neutral")

  def signal(assigns) do
    ~H"""
    <div class="rs-signal" data-tone={@tone}>
      <span><%= @label %></span>
      <strong><%= @value %></strong>
    </div>
    """
  end

  attr(:title, :string, required: true)
  attr(:body, :string, required: true)
  attr(:icon, :string, default: nil)
  attr(:id, :string, default: nil)
  attr(:variant, :string, default: "default")
  slot(:actions)

  def empty_state(assigns) do
    ~H"""
    <section id={@id} class="rs-empty-state" data-variant={@variant} aria-label={@title}>
      <div :if={@icon} class="rs-empty-state__icon" aria-hidden="true"><%= @icon %></div>
      <h2 class="rs-empty-state__title"><%= @title %></h2>
      <p class="rs-empty-state__text"><%= @body %></p>
      <div :if={@actions != []} class="rs-empty-state__actions">
        <%= render_slot(@actions) %>
      </div>
    </section>
    """
  end

  attr(:links, :list, default: [])

  def related_links(assigns) do
    ~H"""
    <nav class="rs-related-links" aria-label="Related routes">
      <a :for={link <- @links} href={link.path}><%= link.label %></a>
    </nav>
    """
  end

  attr(:items, :list, default: [])
  attr(:aria_label, :string, default: "Summary")

  def summary_grid(assigns) do
    ~H"""
    <section class="rs-summary-grid" aria-label={@aria_label}>
      <article :for={item <- @items} class="rs-stat" data-tone={Map.get(item, :tone, "neutral")}>
        <p class="rs-stat__title"><%= item.title %></p>
        <p class="rs-stat__value"><%= item.value %></p>
      </article>
    </section>
    """
  end

  attr(:title, :string, required: true)
  attr(:reason, :string, required: true)
  attr(:tone, :string, default: "warning")

  def capability_explanation(assigns) do
    ~H"""
    <div class="rs-capability-explanation" data-tone={@tone}>
      <strong><%= @title %></strong>
      <span><%= @reason %></span>
    </div>
    """
  end

  attr(:label, :string, required: true)
  attr(:help, :string, default: nil)
  attr(:error, :string, default: nil)
  attr(:feedback_for, :string, default: nil)
  attr(:wide?, :boolean, default: false)
  slot(:inner_block, required: true)

  def form_field(assigns) do
    ~H"""
    <div
      phx-feedback-for={@feedback_for}
      class={["rs-form-field", @wide? && "rs-form-field--wide"]}
    >
      <label>
        <span><%= @label %></span>
        <%= render_slot(@inner_block) %>
        <p :if={@help} class="rs-field-help"><%= @help %></p>
      </label>
      <p :if={@error} class="rs-form-error" role="alert"><%= @error %></p>
    </div>
    """
  end

  attr(:aria_label, :string, default: nil)
  attr(:wide?, :boolean, default: false)
  slot(:inner_block, required: true)
  slot(:note)

  def action_row(assigns) do
    ~H"""
    <div
      class={["rs-form-actions", @wide? && "rs-form-field--wide"]}
      aria-label={@aria_label}
    >
      <%= render_slot(@inner_block) %>
      <p :if={@note != []} class="rs-field-help"><%= render_slot(@note) %></p>
    </div>
    """
  end

  attr(:title, :string, required: true)
  attr(:body, :string, required: true)
  attr(:tone, :string, default: "warning")
  attr(:role, :string, default: "status")
  slot(:actions)

  def state_note(assigns) do
    ~H"""
    <section class="rs-capability-explanation rs-state-note" data-tone={@tone} role={@role}>
      <div>
        <strong><%= @title %></strong>
        <span><%= @body %></span>
      </div>
      <div :if={@actions != []} class="rs-state-note__actions">
        <%= render_slot(@actions) %>
      </div>
    </section>
    """
  end

  attr(:title, :string, required: true)
  attr(:summary, :string, required: true)
  attr(:rows, :list, default: [])

  def trace_panel(assigns) do
    ~H"""
    <section class="rs-trace-panel">
      <h2><%= @title %></h2>
      <p><%= @summary %></p>
      <dl>
        <div :for={row <- @rows}>
          <dt><%= row.label %></dt>
          <dd><code><%= row.value %></code></dd>
        </div>
      </dl>
    </section>
    """
  end

  attr(:title, :string, required: true)
  attr(:entries, :list, default: [])

  def status_list(assigns) do
    ~H"""
    <section class="rs-status-list" aria-label={@title}>
      <h2><%= @title %></h2>
      <dl>
        <div :for={entry <- @entries} class="rs-status-list__row" data-tone={Map.get(entry, :tone, "neutral")}>
          <dt><%= entry.label %></dt>
          <dd>
            <strong><%= entry.value %></strong>
            <span :if={Map.get(entry, :summary)}><%= entry.summary %></span>
          </dd>
        </div>
      </dl>
    </section>
    """
  end

  attr(:steps, :list, default: [])
  attr(:current, :string, default: nil)

  def rollout_ladder(assigns) do
    ~H"""
    <section class="rs-rollout-ladder" aria-label="Suggested rollout ladder">
      <ol>
        <li :for={step <- @steps} data-current={to_string(step == @current)}>
          <strong><%= step %></strong>
          <span :if={step == @current}>Current recommendation</span>
        </li>
      </ol>
    </section>
    """
  end

  attr(:title, :string, required: true)
  attr(:summary, :string, required: true)
  attr(:confirmation_hint, :string, required: true)
  attr(:action_label, :string, required: true)

  def confirm_modal_shell(assigns) do
    ~H"""
    <section class="rs-confirm-modal" aria-label={@title}>
      <h2><%= @title %></h2>
      <p><%= @summary %></p>
      <p><strong>Confirmation:</strong> <%= @confirmation_hint %></p>
      <button type="button" disabled><%= @action_label %></button>
    </section>
    """
  end

  attr(:title, :string, required: true)
  attr(:entries, :list, default: [])

  def audit_timeline(assigns) do
    ~H"""
    <section class="rs-audit-timeline" aria-label={@title}>
      <h2><%= @title %></h2>
      <ul>
        <li :for={entry <- @entries}>
          <strong><%= entry.title %></strong>
          <span><%= entry.meta %></span>
          <p><%= entry.summary %></p>
        </li>
      </ul>
    </section>
    """
  end
end