ScoriaWeb.UI (scoria v0.1.2)

Copy Markdown View Source

Scoria's shared dashboard component vocabulary.

Function components emit the brand-book semantic classes (see assets/css/04-components.css) driven entirely by design tokens. This is the single home for tone/status → color mapping, replacing the per-component badge_class/status_color/trace_badge_class/flash_kind_class helpers that previously drifted across the codebase.

Import into a LiveView/component with import ScoriaWeb.UI.

Summary

Functions

Status Home attention strip card for nonzero actionable states. Renders as an <a> tag — callers pass a path, not a click handler. Attrs: count (numeric highlight), label (category name), detail (supporting copy), cta (call-to-action text), path (link target), tone (semantic tone atom controlling color treatment, default :neutral).

Status badge. Always renders a text label alongside color (a11y: never color-alone).

Primary/ghost/danger button (brand book §8.5).

Server-rendered command palette shell. Client-side filtering lives in assets/js/scoria.js.

Slot-based drawer panel shell (DS-02). Renders nothing when show=false. When show=true, renders a scrim + aside panel with a consistent triple dismiss contract: Close drawer button + scrim click + Escape key. The caller owns all dismiss events via on_dismiss.

Empty state: status + learning cue + optional primary action (NN/g).

Compact evidence action/link row. Callers own the action/link semantics. Used for per-section action links in evidence panels (e.g. "View trace", "Open replay", "Go to approval"). Renders :inner_block inside a flex container with consistent action-row spacing — place <a> or <.button> elements inside.

Notebook-scoped evidence empty state. Used for empty :tab slot panels in <.notebook> when no evidence data is available for a section. The :title attr is required and names what is absent (e.g. "No approvals", "No connector invocations"). Optional :inner_block can provide supplementary copy or a link.

Stable key-value evidence rows for adapter-projected values. Renders a <dl> of <dt>/<dd> pairs. The :rows attr accepts a list of either %{label: _, value: _} maps or {label, value} two-tuples — both forms are normalized by normalize_evidence_rows/1 before rendering. Use inside <.evidence_section> :inner_block for structured label-value evidence data (e.g. model name, token count, latency).

Notebook-scoped evidence section with optional status badge and action slot. Used inside <.notebook> :tab slot panels to group a titled block of evidence content. Attrs: title (section heading), description (optional supporting copy), tone (semantic tone atom for the badge color), badge (optional badge label — rendered only when present). Slots: :actions for action buttons rendered in the section header; :inner_block (required) for evidence rows and action rows.

Small uppercase category/status label (brand book card eyebrow). Used in panel headers, object headers, and card hierarchy labeling to provide a typographic tier above the primary title.

Form field wrapper (DS-03). Renders a label + caller-provided input slot + optional help text + validation error. Error is surfaced via an exclamation icon + text (never error by color alone). Required fields include an aria-hidden asterisk and a visually-hidden '(required)' span. The caller provides the actual input/select/textarea element via the inner_block slot.

Dashboard flash banners. Single home for flash kind → tone styling (DS-05). Renders semantic scoria-flash--{tone} BEM modifier classes via string-keyed clauses (Phoenix @flash always provides string keys, not atoms). Each banner carries role="alert" and a 16×16 tone icon so status is never communicated by color alone.

Form section group (DS-03). Groups related <.field> components under a section heading with an optional description.

Copyable monospace identifier (run/trace/actor IDs). Uses the CopyId JS hook.

Keyboard shortcut chip. Renders a <kbd> element styled with the brand-book monospace treatment. Used inline in command palette rows and help text to label key bindings (e.g. ⌘K, Escape, ↑↓).

Metric card: label, big value, explicit delta (brand book §11.3 — never a magic score).

Slot-based modal dialog shell (DS-02). Renders nothing when show=false. When show=true, renders a scrim + panel with a consistent triple dismiss contract: close button + scrim click + Escape key. The caller owns all dismiss events via on_dismiss.

Unified tabbed evidence panel shell (DS-04). Renders a <nav role='tablist'> tab bar with one <button role='tab'> per <:tab> slot. The tab matching @selected_tab carries aria-selected='true'. Clicking a tab emits phx-click={@on_tab_change} phx-value-tab={key}. When @empty is true, the :empty_slot body is rendered instead of the tab bar and panel.

Object-page orientation header: parent crumb, copyable ID, status, provenance, and return context.

Panel/card surface with optional eyebrow + title + actions header.

Raw evidence details/pre block (DS-04). Renders a <details>/<summary> with a <pre> code block. Background and font tokens are applied via CSS class — not overridden in HEEx.

Loading skeleton placeholder (DS-05). Renders stacked skeleton lines with aria-label='Loading…' and role='status'. Pulse animation + prefers-reduced-motion suppression are handled by CSS.

Human label for a status string (title-cased, underscores → spaces).

Honest reserved-capability stub page. Future-tense only; no fake rows or charts.

Sortable, density-aware, paginated data table (DS-01). Renders column headers from typed <:col> slots; emits sort events for keyed columns only when on_sort is supplied by the parent LiveView. Uses density modifier classes from density_class/1. Falls back to a default empty state when rows is empty (overridable via <:empty>). Pagination strip shown when total_pages > 1. Density controls render only when on_density_change is supplied by the parent LiveView.

Transient toast notification (DS-05). Driven by a server @toasts assign. Auto-dismisses via phx-mounted={JS.hide(...)}. Manual dismiss X button is also provided. Does NOT use a JS hook (untestable in LiveViewTest). The phx-mounted auto-dismiss omits 'to:' so it self-targets the toast div (Pitfall 3); the dismiss button MUST target the toast by id (to: '#id') — a bare JS.hide there would hide the button, not the toast.

Maps a domain status/kind string (or atom) to a semantic tone atom.

Functions

attention_card(assigns)

Status Home attention strip card for nonzero actionable states. Renders as an <a> tag — callers pass a path, not a click handler. Attrs: count (numeric highlight), label (category name), detail (supporting copy), cta (call-to-action text), path (link target), tone (semantic tone atom controlling color treatment, default :neutral).

Attributes

  • count (:any) (required)
  • label (:string) (required)
  • detail (:string) (required)
  • cta (:string) (required)
  • path (:string) (required)
  • tone (:atom) - Defaults to :neutral.
  • class (:string) - Defaults to nil.

badge(assigns)

Status badge. Always renders a text label alongside color (a11y: never color-alone).

Attributes

  • tone (:atom) - Defaults to :neutral.
  • label (:string) - Defaults to nil.
  • dot (:boolean) - Defaults to true.
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • inner_block

button(assigns)

Primary/ghost/danger button (brand book §8.5).

Attributes

  • variant (:atom) - Defaults to :primary. Must be one of :primary, :ghost, or :danger.
  • size (:atom) - Defaults to :md. Must be one of :md, or :sm.
  • type (:string) - Defaults to "button".
  • class (:string) - Defaults to nil.
  • Global attributes are accepted. Supports all globals plus: ["phx-click", "phx-target", "phx-value-id", "phx-value-approval-id", "phx-value-dataset-id", "phx-disable-with", "disabled", "form", "name", "value", "href", "aria-current"].

Slots

  • inner_block (required)

command_palette(assigns)

Server-rendered command palette shell. Client-side filtering lives in assets/js/scoria.js.

Attributes

  • id (:string) (required)
  • sections (:list) - Defaults to [].
  • title (:string) - Defaults to "Open command palette".
  • placeholder (:string) - Defaults to "Search screens, recent objects, and actions".
  • empty_copy (:string) - Defaults to "No matches. The palette covers screens, recent objects, and actions — full object search lands in a later release.".
  • class (:string) - Defaults to nil.

drawer(assigns)

Slot-based drawer panel shell (DS-02). Renders nothing when show=false. When show=true, renders a scrim + aside panel with a consistent triple dismiss contract: Close drawer button + scrim click + Escape key. The caller owns all dismiss events via on_dismiss.

Attributes

  • id (:string) (required)
  • show (:boolean) (required)
  • on_dismiss (:string) (required)
  • title (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • eyebrow
  • title_slot
  • actions
  • inner_block (required)

empty_state(assigns)

Empty state: status + learning cue + optional primary action (NN/g).

Attributes

  • title (:string) (required)
  • class (:string) - Defaults to nil.

Slots

  • inner_block
  • action

evidence_action_row(assigns)

Compact evidence action/link row. Callers own the action/link semantics. Used for per-section action links in evidence panels (e.g. "View trace", "Open replay", "Go to approval"). Renders :inner_block inside a flex container with consistent action-row spacing — place <a> or <.button> elements inside.

Attributes

  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • inner_block (required)

evidence_empty(assigns)

Notebook-scoped evidence empty state. Used for empty :tab slot panels in <.notebook> when no evidence data is available for a section. The :title attr is required and names what is absent (e.g. "No approvals", "No connector invocations"). Optional :inner_block can provide supplementary copy or a link.

Attributes

  • title (:string) (required)
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • inner_block (required)

evidence_rows(assigns)

Stable key-value evidence rows for adapter-projected values. Renders a <dl> of <dt>/<dd> pairs. The :rows attr accepts a list of either %{label: _, value: _} maps or {label, value} two-tuples — both forms are normalized by normalize_evidence_rows/1 before rendering. Use inside <.evidence_section> :inner_block for structured label-value evidence data (e.g. model name, token count, latency).

Attributes

  • rows (:list) (required)
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

evidence_section(assigns)

Notebook-scoped evidence section with optional status badge and action slot. Used inside <.notebook> :tab slot panels to group a titled block of evidence content. Attrs: title (section heading), description (optional supporting copy), tone (semantic tone atom for the badge color), badge (optional badge label — rendered only when present). Slots: :actions for action buttons rendered in the section header; :inner_block (required) for evidence rows and action rows.

Attributes

  • title (:string) (required)
  • description (:string) - Defaults to nil.
  • tone (:atom) - Defaults to :neutral. Must be one of :pass, :info, :warn, :fail, :trace, :brand, or :neutral.
  • badge (:string) - Defaults to nil.
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • actions
  • inner_block (required)

eyebrow(assigns)

Small uppercase category/status label (brand book card eyebrow). Used in panel headers, object headers, and card hierarchy labeling to provide a typographic tier above the primary title.

Attributes

  • class (:string) - Defaults to nil.

Slots

  • inner_block (required)

field(assigns)

Form field wrapper (DS-03). Renders a label + caller-provided input slot + optional help text + validation error. Error is surfaced via an exclamation icon + text (never error by color alone). Required fields include an aria-hidden asterisk and a visually-hidden '(required)' span. The caller provides the actual input/select/textarea element via the inner_block slot.

Attributes

  • id (:string) (required)
  • label (:string) (required)
  • help (:string) - Defaults to nil.
  • error (:string) - Defaults to nil.
  • required (:boolean) - Defaults to false.
  • Global attributes are accepted.

Slots

  • inner_block (required)

flash_group(assigns)

Dashboard flash banners. Single home for flash kind → tone styling (DS-05). Renders semantic scoria-flash--{tone} BEM modifier classes via string-keyed clauses (Phoenix @flash always provides string keys, not atoms). Each banner carries role="alert" and a 16×16 tone icon so status is never communicated by color alone.

Attributes

  • flash (:map) - Defaults to %{}.

form_section(assigns)

Form section group (DS-03). Groups related <.field> components under a section heading with an optional description.

Attributes

  • title (:string) (required)
  • description (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • inner_block (required)

id(assigns)

Copyable monospace identifier (run/trace/actor IDs). Uses the CopyId JS hook.

The DOM id must be stable across renders so LiveView/morphdom patches the existing element in place rather than tearing down and re-mounting the CopyId hook. When no caller-supplied id is given it is derived deterministically from the displayed value; prefer passing an explicit id where two identical values can appear on one page.

Attributes

  • value (:string) (required)
  • copy (:string) - Defaults to nil.
  • id (:string) - Defaults to nil.
  • title (:string) - Defaults to "Click to copy".
  • class (:string) - Defaults to nil.

kbd(assigns)

Keyboard shortcut chip. Renders a <kbd> element styled with the brand-book monospace treatment. Used inline in command palette rows and help text to label key bindings (e.g. ⌘K, Escape, ↑↓).

Attributes

  • class (:string) - Defaults to nil.

Slots

  • inner_block (required)

metric(assigns)

Metric card: label, big value, explicit delta (brand book §11.3 — never a magic score).

Attributes

  • label (:string) (required)
  • value (:string) (required)
  • delta (:string) - Defaults to nil.
  • delta_tone (:atom) - Defaults to :neutral.
  • class (:string) - Defaults to nil.

modal(assigns)

Slot-based modal dialog shell (DS-02). Renders nothing when show=false. When show=true, renders a scrim + panel with a consistent triple dismiss contract: close button + scrim click + Escape key. The caller owns all dismiss events via on_dismiss.

Attributes

  • id (:string) (required)
  • show (:boolean) (required)
  • on_dismiss (:string) (required)
  • title (:string) - Defaults to nil.
  • max_width (:string) - Defaults to "560px".
  • Global attributes are accepted.

Slots

  • title_slot
  • inner_block (required)
  • footer

notebook(assigns)

Unified tabbed evidence panel shell (DS-04). Renders a <nav role='tablist'> tab bar with one <button role='tab'> per <:tab> slot. The tab matching @selected_tab carries aria-selected='true'. Clicking a tab emits phx-click={@on_tab_change} phx-value-tab={key}. When @empty is true, the :empty_slot body is rendered instead of the tab bar and panel.

Attributes

  • id (:string) (required)
  • title (:string) (required)
  • eyebrow (:string) - Defaults to nil.
  • empty (:boolean) - Defaults to false.
  • selected_tab (:string) - Defaults to nil.
  • on_tab_change (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • tab - One tab panel. Accepts attributes:
    • key (:string) (required)
    • label (:string) (required)
  • empty_slot

object_header(assigns)

Object-page orientation header: parent crumb, copyable ID, status, provenance, and return context.

Attributes

  • parent_label (:string) (required)
  • parent_path (:string) (required)
  • object_type (:string) (required)
  • object_id (:string) (required)
  • status (:any) - Defaults to nil.
  • key_scalar (:string) - Defaults to nil.
  • provenance (:string) - Defaults to nil.
  • origin (:map) - Defaults to nil.
  • class (:string) - Defaults to nil.
  • id (:string) - Defaults to nil.
  • Global attributes are accepted.

panel(assigns)

Panel/card surface with optional eyebrow + title + actions header.

Attributes

  • variant (:atom) - Defaults to :flat. Must be one of :flat, or :raised.
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • eyebrow
  • title
  • actions
  • inner_block (required)

raw_evidence(assigns)

Raw evidence details/pre block (DS-04). Renders a <details>/<summary> with a <pre> code block. Background and font tokens are applied via CSS class — not overridden in HEEx.

Attributes

  • label (:string) - Defaults to "Advanced raw evidence".

Slots

  • inner_block (required)

skeleton(assigns)

Loading skeleton placeholder (DS-05). Renders stacked skeleton lines with aria-label='Loading…' and role='status'. Pulse animation + prefers-reduced-motion suppression are handled by CSS.

Attributes

  • class (:string) - Defaults to nil.
  • rows (:integer) - Defaults to 1.
  • Global attributes are accepted.

status_label(status)

Human label for a status string (title-cased, underscores → spaces).

stub_page(assigns)

Honest reserved-capability stub page. Future-tense only; no fake rows or charts.

Attributes

  • title (:string) (required)
  • description (:string) (required)
  • works_today (:list) - Defaults to [].
  • tracking_url (:string) - Defaults to nil.
  • class (:string) - Defaults to nil.

table(assigns)

Sortable, density-aware, paginated data table (DS-01). Renders column headers from typed <:col> slots; emits sort events for keyed columns only when on_sort is supplied by the parent LiveView. Uses density modifier classes from density_class/1. Falls back to a default empty state when rows is empty (overridable via <:empty>). Pagination strip shown when total_pages > 1. Density controls render only when on_density_change is supplied by the parent LiveView.

Attributes

  • rows (:list) (required)
  • sort_by (:any) - Defaults to nil.
  • sort_dir (:atom) - Defaults to :asc. Must be one of :asc, or :desc.
  • density (:atom) - Defaults to :default. Must be one of :compact, :default, or :comfortable.
  • id (:string) (required)
  • page (:integer) - Defaults to 1.
  • total_pages (:integer) - Defaults to 1.
  • on_sort (:string) - Defaults to nil.
  • on_page_change (:string) - Defaults to nil.
  • on_density_change (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • col - Table column. Accepts attributes:
    • label (:string) (required)
    • key (:atom)
    • class (:string)
  • empty
  • action
  • filter
  • mobile_summary - Opt-in per-row mobile summary rendered in a sibling container hidden at >=768px. Exposes object label, status badge text, one key scalar/time, and a primary action. When absent, the table keeps honest overflow at all widths.

toast(assigns)

Transient toast notification (DS-05). Driven by a server @toasts assign. Auto-dismisses via phx-mounted={JS.hide(...)}. Manual dismiss X button is also provided. Does NOT use a JS hook (untestable in LiveViewTest). The phx-mounted auto-dismiss omits 'to:' so it self-targets the toast div (Pitfall 3); the dismiss button MUST target the toast by id (to: '#id') — a bare JS.hide there would hide the button, not the toast.

Attributes

  • id (:string) (required)
  • tone (:atom) - Defaults to :neutral. Must be one of :pass, :fail, :warn, :info, or :neutral.
  • message (:string) (required)
  • duration_ms (:integer) - Defaults to 4000.

tone(status)

Maps a domain status/kind string (or atom) to a semantic tone atom.

Tones: :pass | :info | :warn | :fail | :trace | :brand | :neutral. Unknown values fall back to :neutral. This is the single source of truth for status coloring.