Files
admin/apps/admin/ui-style-guide.md
T

9.1 KiB

Admin UI Style Guide

Visual direction for the CRUX admin panel. Use it when creating or simplifying admin screens; Web Studio (apps/admin/src/core/WebStudio/) is the reference implementation.

Design Intent

Quiet, direct, operational — not borderless, but every surface and separator has a clear job:

  • Content and actions more prominent than containers.
  • Whitespace, typography, and alignment before borders.
  • One clear primary action per screen or section.
  • Frequently used controls stay visible.
  • Complex editors feel structured without turning every level into a card.
  • Preserve existing design tokens, accessibility behavior, and shared primitives.

Visual Hierarchy

Build screens in this order — and do not wrap all five levels in a single card; the page canvas is the outer surface:

  1. Module context — module name, compact breadcrumb, global control when needed.
  2. Screen header — title, one-line description, primary action.
  3. Toolbar — search, filters, view controls, secondary actions.
  4. Content — table, editor, form, or settings.
  5. Supporting state — loading, empty, error, pagination, destructive confirmation.

Surface Rules

Choose the lightest surface that communicates the relationship.

Content Preferred treatment
Page canvas bg-background, no border or shadow
Screen header and toolbar Plain layout with spacing
Table Unboxed table with row separators
Sticky editor settings Quiet bg-muted/40 panel
Top-level repeated editor block Flat bg-muted/35 section
Nested field group Left rule and indentation
Selected radio or option Subtle bg-primary/10 state
Empty state Quiet muted surface, concise explanation
Dialog, popover, dropdown, or sheet Floating surface from the shared primitive
Warning, error, or destructive confirmation Explicit semantic component and color
Independent dashboard summary with mixed content Card is acceptable when it is a genuinely separate unit

Border budget: at most one strong boundary per hierarchy level — a muted block surface with one header divider, not nested bordered cards down to the input. Do not combine border, shadow, rounded container, accent background, and hover lift unless the element must read as an independent interactive object.

Page Headers

A concise text-xl title, optional one-line text-muted-foreground text-sm description, primary action aligned to the end, wrapping on narrow viewports. Keep the primary action out of search/filter containers. A back link above an editor header retains relevant query parameters (e.g. selected locale).

Tables and Lists

A working data surface, not a card collection:

  • Title and create action above the data; search and filters in a plain toolbar row.
  • Shared table primitive without a surrounding Card; row separators provide structure.
  • Most useful identity in the first column, supporting route/identifier below it in muted text.
  • Compact status badges only for state; right-aligned ghost icon buttons for row actions.
  • Destructive actions stay semantically destructive without a large filled red surface.
  • Result count and pagination in a plain footer row.
  • Loading, empty, and error states occupy the table area so the layout does not jump.

Editors and Long Forms

Two-column on large screens, stacked on small:

┌──────────────────────┬──────────────────────────────────────────┐
│ sticky page settings │ line tabs: Hero / Blocks / SEO          │
│ approximately 320 px │                                          │
│ quiet muted surface  │ active editor content                    │
└──────────────────────┴──────────────────────────────────────────┘

Page identity, route, locale grouping, and layout live in the narrow settings column; content editing in the wider one. Line-style tabs, not a card per tab. Flat muted surface per top-level block with a simple divider under its header; indentation or a left rule for nested collections (CTA items, FAQ items, columns). Block actions visible and compact; collapse long repeated sections when it materially reduces scrolling; show a useful empty state for empty collections.

Settings Screens

Title + description + save action, line-style tabs for groups, plain section headings, normal form layout without an extra outer card, the same flat nested-group treatment as editors.

Controls and Actions

  • Shared admin primitives from apps/admin/src/shared/ui.
  • Primary button for primary actions; outline for secondary add actions; ghost for inline edit, collapse, duplicate, pagination, and delete triggers.
  • Icon-only buttons need an accessible label; non-submitting buttons in forms need type="button".
  • No essential actions behind hover-only opacity.
  • Sheets or dialogs for selection tasks that interrupt the flow; inside a picker, a divided list over a grid of small bordered cards.

Typography and Spacing

  • text-mono for admin headings where the app already uses it; font-semibold for module, screen, and section headings; text-muted-foreground for descriptions and secondary metadata.
  • gap-2/gap-3 inside compact controls; space-y-5/space-y-6 between major sections; p-4/p-5 on editor surfaces.
  • Keep established logos; avoid decorative icon containers and oversized headings — admin screens prioritize working space.
  • Always theme tokens (background, muted, primary, destructive, border, foreground); no hard-coded colors for ordinary UI.

Status and Semantic Color

Color is reserved for meaning: success = published/completed, warning = draft/pending, destructive = irreversible actions and errors, primary = selection and main action, muted = metadata and passive structure. A badge answers a state or classification question — never decoration.

Responsive Behavior

Headers and toolbars wrap; search may grow while filters keep usable widths. Wide tables scroll horizontally through the shared wrapper. Two-column editors stack before either column gets too narrow; sticky positioning only at the desktop editor breakpoint; compact global controls may shorten labels on small screens.

Accessibility

  • Semantic heading order; header/main/aside/section where they clarify structure.
  • Keep keyboard focus styles from shared primitives.
  • Never encode state with color alone; icon-only actions need accessible names.
  • Collapsible controls stay reachable with a clear visual state.
  • Empty and error states contain text, not only an icon.
  • Destructive mutations require confirmation when data cannot be trivially restored.

Architecture and Ownership

Module-specific redesign: do not modify apps/admin/src/shared; reuse shared primitives through props and className; put module-specific composed UI in the module's view/ui; keep data fetching, DTO mapping, form schemas, mutations, and routing out of presentational refactors.

Admin-wide redesign: audit repeated module-local patterns, confirm a pattern works in at least two independent modules, promote only stable primitives to shared, migrate screens incrementally, and run visual and behavioral checks after each module.

Anti-Patterns

  • A card around the whole page, around a table inside it, or per form section and nested field.
  • Multiple competing primary actions.
  • Borders filling empty visual space; hover lift or shadow on non-clickable containers.
  • Decorative badges and icon tiles; actions visible only on hover.
  • Changing request, form, draft, routing, or mutation logic during a visual-only refactor.
  • Editing shared primitives to solve a single module's spacing problem.

Review Checklist

  • One obvious title and primary action; search and filters separate from it.
  • Main content not wrapped in an unnecessary card; nested borders do not repeat the same hierarchy.
  • Status colors communicate meaning.
  • Empty, loading, error, and destructive states remain clear.
  • Mobile wrapping and editor stacking are intentional.
  • Query parameters and navigation context are preserved.
  • Existing form, mutation, and draft behavior is unchanged; shared UI changed only for system-wide work.
  • Formatting, lint, tests, build, and visual review have been run when available.