Shared application shell for the operator surface — the chrome wrapping both
MailglassAdmin.OperatorLive (deliveries) and MailglassAdmin.InboundLive
(inbound records). The two screens mount in the SAME operator live_session
(one Operator.Mount + Auth gate), so a shared shell is a within-surface
concern, not a cross-mount one — it never reaches the dev-preview surface.
Provides:
- a persistent left sidebar that navigates BETWEEN surfaces (Deliveries /
Inbound) — navigation, not filtering. The Inbound item is conditionally
omitted via
inbound_available?(the sameOptionalDeps.MailglassInboundgate the router uses to decide whether to emit the/inboundroute), so an operator without the inbound package never sees a dead link. - a read-only tenant-context chip (forensic trust: always show whose data is on screen).
- a shell-owned theme toggle (the dark theme is fully built but was
previously unreachable from the operator UI). Theme is carried in the URL
?theme=param so it survives both Deliveries↔Inbound navigation and refresh — mirroring the preview surface's pattern.
Nav links reset to each surface's base path (no delivery_id/inbound_id,
no stale filters): switching surfaces is a fresh question, and inheriting a
selected id across surfaces is the classic sidebar-nav footgun.
This is internal UI — not part of the stable router/auth contract.
Summary
Functions
True when the resolved theme selection is dark.
Whether the inbound surface is present — the SAME gate the router uses to
decide whether to emit the /inbound route. Centralized here so the nav and
the route never disagree.
Renders the orientation strip for an operator surface — a persistent, symptom-first guidance panel that appears when no record is selected. Each surface has frozen per-surface copy keyed on the most common operator questions for that surface.
Builds the target for setting the theme picker value through the HTTP
persistence seam while preserving unrelated query params in return_to.
Renders the operator shell around a surface's body (passed as the inner block).
Derives the {deliveries, inbound} nav paths from a screen's base_path,
carrying the ?tenant_id= and ?theme= params so the tenant scope AND the
active theme survive cross-surface navigation. active tells us which surface
we're on so we can recover the operator root (the inbound screen's base_path
has a trailing /inbound to strip).
Builds a same-surface tenant switch path from the current URL.
Resolves the shell's three-choice picker state from the URL theme param, falling back to the persisted theme cookie.
Builds the push_patch target for the theme toggle: flips the theme param on
the CURRENT url, preserving every other filter/selection param.
Functions
True when the resolved theme selection is dark.
Whether the inbound surface is present — the SAME gate the router uses to
decide whether to emit the /inbound route. Centralized here so the nav and
the route never disagree.
Renders the orientation strip for an operator surface — a persistent, symptom-first guidance panel that appears when no record is selected. Each surface has frozen per-surface copy keyed on the most common operator questions for that surface.
Placed after defp flash_region/1 as the last function component in the module.
No motion classes — born token-clean.
Attributes
surface(:atom) (required) - Must be one of:deliveries,:inbound, or:preview.
Builds the target for setting the theme picker value through the HTTP
persistence seam while preserving unrelated query params in return_to.
The system choice removes the explicit theme query key.
Renders the operator shell around a surface's body (passed as the inner block).
Attributes
active(:atom) (required) - Must be one of:deliveries, or:inbound.deliveries_path(:string) (required)inbound_path(:string) (required)inbound_available?(:boolean) - Defaults tofalse.dark_chrome(:boolean) - Defaults tofalse.theme_choice(:atom) - Defaults to:system. Must be one of:system,:light, or:dark.tenant(:string) - Defaults tonil.title(:string) (required)subtitle(:string) - Defaults tonil.flash(:map) - Defaults to%{}.
Slots
inner_block(required)
Derives the {deliveries, inbound} nav paths from a screen's base_path,
carrying the ?tenant_id= and ?theme= params so the tenant scope AND the
active theme survive cross-surface navigation. active tells us which surface
we're on so we can recover the operator root (the inbound screen's base_path
has a trailing /inbound to strip).
Only tenant_id is carried across surfaces — it is the shared scoping
dimension. Surface-specific filters (delivery vs inbound status sets) are
intentionally left behind, since they don't translate between surfaces.
Attributes
state(:atom) (required) - Must be one of:select_required, or:none.tenant_options(:list) - Defaults to[].current_uri(:string) (required)
Builds a same-surface tenant switch path from the current URL.
Tenant switches preserve compatible filters and theme while dropping selected record ids that cannot safely carry across tenants.
Resolves the shell's three-choice picker state from the URL theme param, falling back to the persisted theme cookie.
An explicit ?theme= query value wins (a per-link override, matching the
root layout's precedence); otherwise the persisted cookie decides; absent
both, :system. The operator/inbound theme picker persists via cookie + a
param-stripping redirect (set_theme_path/2 → ThemeController), so the
cookie — not the URL — is the source of truth across navigations.
Builds the push_patch target for the theme toggle: flips the theme param on
the CURRENT url, preserving every other filter/selection param.