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:
- Module context — module name, compact breadcrumb, global control when needed.
- Screen header — title, one-line description, primary action.
- Toolbar — search, filters, view controls, secondary actions.
- Content — table, editor, form, or settings.
- 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;
outlinefor secondary add actions;ghostfor 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-monofor admin headings where the app already uses it;font-semiboldfor module, screen, and section headings;text-muted-foregroundfor descriptions and secondary metadata.gap-2/gap-3inside compact controls;space-y-5/space-y-6between major sections;p-4/p-5on 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/sectionwhere 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.