Brand-book-aligned shared UI atoms used throughout mailglass_admin.
Components
icon/1— Heroicon via the vendoredheroicons.jsTailwind plugin (Phoenix 1.8 installer convention). Classes matching the patternhero-<name>are resolved at build time into inline SVG.logo/1— sealed-flap mailglass lockup rendered inline so it inherits admin chrome color; the stablelogo.svgroute remains served frompriv/static/mailglass-logo.svgviaMailglassAdmin.Controllers.Assets.flash/1— toast-style flash message for LiveReload + success notifications. Brand-voice: no "Oops!", no "Uh oh!"; specific and composed per brand book §5.badge/1— sidebar status badge with two variants::warning(preview_props/0 raised) and:stub(no preview_props defined).
Brand voice enforcement
Copy throughout these atoms follows the 05-UI-SPEC Copywriting Contract: clear, exact, confident, warm, technical — "a thoughtful maintainer." Banned phrases ("Oops", "Whoops", "Uh oh", "Something went wrong") never appear in this module; the voice test greps the rendered HTML to enforce the floor.
Boundary classification: submodule auto-classifies into the
MailglassAdmin root boundary declared in lib/mailglass_admin.ex;
classify_to: is reserved for mix tasks and protocol implementations
and is not used here.
Summary
Functions
Sidebar status badge. Two variants
Renders the thin group-surface shell: border, radius, surface tone, and outer padding only.
Renders one of four distinct data-state templates.
Renders one explicit, labelled filter control.
Renders a visible filter control group.
Renders a brand-voice flash message in a daisyUI toast wrapper.
Renders a Heroicon via the vendored heroicons.js Tailwind plugin.
Renders the sealed-flap mailglass lockup inline for theme-aware color.
Masks the local/domain halves of an already-split email address. Public so
the inbound components can mask address-shaped values that are pre-split.
Masks a recipient email for operator display (PII minimization).
Masks a single value: keeps the first grapheme, stars the rest. Public so other admin surfaces reuse the one masking primitive rather than reinventing it.
Renders the desktop operator navigation link primitive.
Renders the compact operator navigation pill primitive.
Normalizes inbound @outcomes singular atoms to the canonical past-tense atoms expected by status_badge/1. The mailglass_inbound @outcomes schema (locked 1.0 contract) is never modified; normalization is admin-side only.
Renders a canonical stat card with label, no-wrap value, and severity.
Unified delivery, inbound, and timeline status badge. Renders an outline Heroicon (decorative, aria-hidden) and a text label inside a daisyUI badge container.
Renders the read-only tenant context chip.
Renders the three-choice theme picker primitive.
Functions
Sidebar status badge. Two variants:
:warning— preview_props/0 raised; shows an exclamation-triangle Heroicon + the literal copy "Error" (per 05-UI-SPEC Badge section).:stub— mailable has no preview_props/0 defined; shows the "—" glyph in Slate (secondary) color.
Attributes
variant(:atom) (required) - Must be one of:warning, or:stub.
Renders the thin group-surface shell: border, radius, surface tone, and outer padding only.
This is the single source for the group-surface shell. It deliberately owns no
layout engine — no header/footer/grid slots, no inter-card rhythm, no dl/ol
spacing. shadow-raised and data-group-card are applied at call sites, not
baked in here. Padding is the one closed knob (:md -> p-md, :lg -> p-lg).
Attributes
padding(:atom) - Defaults to:md. Must be one of:md, or:lg.- Global attributes are accepted.
Slots
inner_block(required)
Renders one of four distinct data-state templates.
Each kind maps to a unique testid, icon, and icon color so that permission-denied is never mistaken for no-data, and error is never conflated with stale-data.
Kinds
:empty— no records; rendered withhero-inboxandtext-secondary:error— unavailable/error; rendered withhero-exclamation-circleandtext-error:permission_denied— access restricted; rendered withhero-lock-closedandtext-warning:stale— data may be out of date; rendered withhero-clockandtext-secondary
Attributes
kind(:atom) (required) - Must be one of:empty,:error,:permission_denied, or:stale.title(:string) (required)body(:string) (required)icon(:string) - Defaults tonil.- Global attributes are accepted.
Renders one explicit, labelled filter control.
Defaults derive from Phoenix.HTML.FormField metadata when field is
provided. Explicit id, name, and value remain supported for gallery
and certification surfaces that render without a form struct.
Attributes
field(:any) - Defaults tonil.id(:string) - Defaults tonil.name(:string) - Defaults tonil.value(:any) - Defaults tonil.type(:atom) - Defaults to:text. Must be one of:text,:number,:select,:textarea, or:checkbox.label(:string) (required)help(:string) - Defaults tonil.error(:any) - Defaults tonil.options(:list) - Defaults to[].prompt(:string) - Defaults tonil.disabled(:boolean) - Defaults tofalse.readonly(:boolean) - Defaults tofalse.display_value(:string) - Defaults tonil.submit_readonly(:boolean) - Defaults totrue.- Global attributes are accepted. Supports all globals plus:
["autocomplete", "inputmode", "max", "min", "pattern", "placeholder", "step"].
Renders a visible filter control group.
The primitive uses native fieldset/legend semantics so pages can group related filters without duplicating page-local label/control wrappers.
Attributes
title(:string) (required)description(:string) - Defaults tonil.- Global attributes are accepted.
Slots
inner_block(required)
Renders a brand-voice flash message in a daisyUI toast wrapper.
Used for LiveReload notifications ("Reloaded: {file}") and other
transient signals. Includes role="status" + aria-live="polite"
per the 05-UI-SPEC Accessibility Interactions contract.
Attributes
kind(:atom) - Defaults to:info. Must be one of:info,:success,:warning, or:error.message(:string) (required)
Renders a Heroicon via the vendored heroicons.js Tailwind plugin.
The plugin resolves classes matching hero-<name> into inline SVG at
build time. Usage: <.icon name="hero-envelope" class="w-5 h-5" />.
Attributes
name(:string) (required)class(:any) - Defaults tonil.
Renders the sealed-flap mailglass lockup inline for theme-aware color.
The public logo.svg route remains served by
MailglassAdmin.Controllers.Assets at <mount>/logo.svg; the admin UI
renders inline so the currentColor paths inherit text-base-content in
light and dark chrome.
Attributes
class(:any) - Defaults tonil.
Masks the local/domain halves of an already-split email address. Public so
the inbound components can mask address-shaped values that are pre-split.
Masks a recipient email for operator display (PII minimization).
The ONE audited masking definition in the admin package: both
MailglassAdmin.Operator.DeliveriesList (outbound) and the inbound
components call this so there is never a second, drifting copy. Keeps the first
grapheme of each segment and stars the rest, preserving the email shape:
mask_recipient("alice@example.com") #=> "a****@e******.com"
mask_recipient(nil) #=> "Unavailable"
Masks a single value: keeps the first grapheme, stars the rest. Public so other admin surfaces reuse the one masking primitive rather than reinventing it.
Normalizes inbound @outcomes singular atoms to the canonical past-tense atoms expected by status_badge/1. The mailglass_inbound @outcomes schema (locked 1.0 contract) is never modified; normalization is admin-side only.
Maps: :accept → :accepted, :reject → :rejected, :bounce → :bounced.
All other atoms (including nil) pass through unchanged.
Renders a canonical stat card with label, no-wrap value, and severity.
Severity is a closed set and always renders as icon plus visible label plus semantic color.
Attributes
id(:string) - Defaults tonil.label(:string) (required)value(:any) - Defaults tonil.severity(:atom) - Defaults to:neutral. Must be one of:neutral,:info,:success,:warning, or:error.severity_label(:string) - Defaults tonil.state(:atom) - Defaults to:ready. Must be one of:ready,:empty,:loading, or:unavailable.empty_text(:string) - Defaults to"No data yet".loading_text(:string) - Defaults to"Resolving".unavailable_text(:string) - Defaults to"Unavailable".- Global attributes are accepted.
Unified delivery, inbound, and timeline status badge. Renders an outline Heroicon (decorative, aria-hidden) and a text label inside a daisyUI badge container.
The base badge class is always emitted by this component — call sites must NOT prepend 'badge' or 'badge badge-sm'. Use size: :sm (default) for list rows; size: :md for detail headers.
Attributes
status(:atom) (required) - Must be one of:dispatched,:queued,:sent,:delivered,:deferred,:bounced,:failed,:rejected,:complained,:unsubscribed,:opened,:clicked,:autoresponded,:unknown,:accepted,:no_match,:ignore,:failed_ingest,:webhook_replay_requested,:webhook_replay_succeeded,:webhook_replay_failed,:reconciled, or:suppressed.size(:atom) - Defaults to:sm. Must be one of:sm, or:md.
Renders the read-only tenant context chip.
The chip intentionally does not expose switching, loading, or navigation behavior.
Attributes
tenant(:string) - Defaults tonil.- Global attributes are accepted.
Renders the three-choice theme picker primitive.
The primitive owns radio semantics only. Persistence, cookie naming, root theme resolution, browser storage, and first-paint behavior are downstream shell concerns.
Attributes
selected(:atom) - Defaults to:system. Must be one of:system,:light, or:dark.name(:string) - Defaults to"theme".disabled(:boolean) - Defaults tofalse.event(:string) - Defaults tonil.target(:any) - Defaults tonil.- Global attributes are accepted.