Rewrite DESIGN.md for the new tokens, type, icons, motion and components, add the redesign's terms to GLOSSARY.md, and log M1 in the redesign plan.
13 KiB
version, name, description, colors, typography, rounded, spacing, motion
| version | name | description | colors | typography | rounded | spacing | motion | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2.0-alpha | Reactive Resume · Desk & Paper | A quiet, warm desk around a bright page. The resume is the only white, detailed object on screen; one moss-green accent marks the next action. Light and dark themes, with the page always white. |
|
|
|
|
|
Overview
Reactive Resume's interface is a quiet, warm desk around a bright page. The resume or letter page is the only white, detailed object on screen; everything around it uses low-contrast warm neutrals, thin rules instead of boxes, and a single moss-green accent.
The full specification lives in the redesign handoff (design_handoff_reactive_resume_redesign/README.md, kept out of version control) and the milestone plan in REDESIGN_PLAN.md. This document records the rules the code follows.
Five principles decide most questions:
- The page is the interface. The live page is on screen in every editor mode. Clicking a line on the page opens its field.
- One obvious next step. Each view has at most one accent-filled button. Accent means "do this next" or "this is working" and is never decoration.
- Nothing is lost. Everything autosaves and can be undone. Confirmation dialogs are only for irreversible actions.
- Detail on demand. Defaults cover most people; advanced controls sit one disclosure deeper.
- AI proposes, you decide. The assistant never writes directly; every change is a reviewable proposal.
Resume templates keep their Pokémon names (Azurill, Onyx, Glalie…), their own fonts and their own colors. None of the rules below apply inside a template.
Tokens
Tokens are CSS custom properties in packages/ui/src/styles/globals.css, light on :root and dark on .dark. The source of truth is oklch; the hex values above are sRGB approximations. Tailwind exposes each one under the same name: bg-bg, bg-surface, bg-raised, bg-sunken, border-line, border-line-2, text-ink, text-ink-2, text-ink-3, bg-accent, text-on-accent, bg-accent-soft, text-accent-text, bg-danger, bg-danger-soft, text-danger-text, bg-warn, bg-warn-soft, text-warn-text, bg-info-soft, text-info-text, bg-hover, bg-press, bg-scrim, bg-paper and bg-stage-*.
- Surfaces:
bgis the app desk,surfaceholds panels and cards,raisedholds menus, dialogs and inputs,sunkenis for wells, tracks and the page canvas. - Text:
inkfor primary text,ink-2for secondary text,ink-3for meta and placeholders.ink-3is the lightest color allowed for text (about 4.9:1). - Signals:
dangerfor errors and irreversible actions,warnfor check issues and things to review,infofor neutral guidance and the assistant's questions. Success usesaccent-soft. - Overlays:
hoverandpressare translucent, so they work on any surface. - Paper:
--paperis white in both themes. Pages never invert. - Stages: application stage colors share lightness and chroma. They appear only as 8px dots or 6px stepper bars, always next to the stage name.
The previous shadcn-style names (background, foreground, primary, muted, border, input, ring, destructive, card, popover, sidebar-*) still resolve to these tokens so screens that haven't been rebuilt stay legible. Don't use them in new code; they're removed once every screen has moved.
Typography
- Newsreader (display serif, optical sizes 6–72) is only for page titles, dialog and sheet titles, empty-state headlines and large stat numerals. Use
font-display. - Hanken Grotesk handles everything functional. It's the default
font-sans. - JetBrains Mono is for shortcuts, URLs and slugs, file names, counts and section eyebrows. Use
font-mono. - Field labels are 12px, medium weight,
ink-2, above the control with a 5–6px gap. Uppercase group eyebrows are 12px semiboldink-3with 0.02em tracking. - Inputs render at 16px on touch devices so iOS doesn't zoom.
- All three fonts are self-hosted through
@fontsource-variable.
Iconography
App icons are Material Symbols Rounded at weight 300, rendered by Icon from @reactive-resume/ui/components/icon. The font is a self-hosted subset that contains only the glyphs listed in packages/ui/src/icons/names.ts:
- Add the name to that list (TypeScript then accepts it in
<Icon name="…" />). - Run
pnpm icons:build. The script checks every name against the published codepoints, downloads the subset and updates the manifest. A unit test fails if the manifest and the list disagree.
Rules:
- 20px on desktop, 24px on touch. Outline by default;
filledonly for the selected navigation item. - Icons always sit beside a text label, except back, close, more, undo/redo, history, assistant and zoom. Those use
IconButton, which requires a label and shows it in a tooltip with the shortcut. Iconisaria-hiddenandtranslate="no", so the ligature text never becomes an accessible name.- Directional icons (arrows, chevrons, undo, redo) mirror in right-to-left layouts automatically.
- Icons inside resumes are a separate system: Phosphor, because resume data stores Phosphor names and the PDF renderer draws them.
Space, shape and elevation
- Spacing follows a 4pt scale: 4, 8, 12, 16, 24, 32, 48, 64. Cards use 16px padding, panels 16–24px, the mobile margin is 16px and the desktop page margin 32–40px.
- Radius:
rounded-sm6px for chips and small buttons,rounded-md8px for controls and inputs,rounded-lg10px for list items,rounded-xl12px for cards and menus,rounded-2xl16px for dialogs,rounded-3xl18px for mobile sheets,rounded-fullfor pills. - Elevation:
shadow-e1for cards,shadow-e2for menus, popovers and hover-lifted cards,shadow-e3for dialogs, sheets and toasts,shadow-pagefor the resume page on the canvas. - Control heights: 28px small, 36px default, 44px touch. Icon buttons are 32–36px on desktop and 44px on touch.
- Layout constants are CSS variables:
--editor-bar56px,--editor-panel400px,--app-sidebar240px,--sheet-share440px,--sheet-detail480px,--assistant400px.
Motion
| Token | Duration | Use |
|---|---|---|
duration-quick |
120ms | hover, press, toggle, checkbox, focus |
duration-standard |
200ms | menus, popovers, expand and collapse, mode switch, dialogs |
duration-emphasized |
320ms | side and bottom sheets, toasts, the assistant column |
- Everything that enters uses
ease-enter(cubic-bezier(0.2, 0.8, 0.2, 1)). Exits run at 70% of the duration. - Motion explains where something went. Nothing loops, bounces or plays on load; loading placeholders stay still. Reflowing the page after an edit is never animated.
- With
prefers-reduced-motion, the duration tokens become 1ms and every CSS transition collapses; spinners keep turning because they're status. - Motion (
motion/react) animations run underMotionConfig reducedMotion="user"; mirror the tokens inapps/web/src/libs/motion.tswhen one needs them.
Components
Generic primitives live in packages/ui/src/components and wrap Base UI (and cmdk for the command bar). Feature-specific UI lives with its feature in apps/web.
- Buttons:
primary(accent fill, the one filled button per view),secondary(bordered surface),ghost,danger,link. Sizessm28,default36,lg44 (touch), plus icon sizes.loadingshows a spinner, setsaria-busyand blocks activation; pair it with a present-participle label ("Preparing…"). - Inputs: 36px (44px on touch),
raisedbackground,line-2border. Focus is an accent border plus a 3pxaccent-softring. Errors appear after the first blur, indanger-text, with an icon and words that say how to fix it. - Switches: prefer
SwitchRow, where the whole row is the switch. Checkboxes are 18px with a 5px radius; radios are 18px with an 8px accent dot. - Segmented controls:
SegmentedControlfor 2–4 options (a radio group);Tabswith the default variant when segments switch panels,Tabs variant="line"for underline tabs. - Menus (dropdown, context, combobox lists): 220px minimum width, 12px radius, 36px items, destructive items last after a separator.
- Layers, lightest to heaviest: menu, popover, sheet, dialog. Sheets are for tasks beside the page and become bottom sheets on mobile. Dialogs are for decisions; destructive confirmations use
AlertDialogand the cancel label says what is kept. - Toasts: one at a time, bottom center, ink on the desk color, 6 seconds, with an optional underlined Undo action.
- Alerts:
info,success,warnanderror; only errors are announced (role="alert"). - Empty states: a Newsreader 22px headline, a 14px body up to 300px wide, then a primary and a secondary action.
Accessibility
WCAG 2.2 AA is the floor.
- Every interactive element shows a 2px accent focus ring with a 2px gap on
:focus-visible. Never remove it; inputs replace it with their accent border and soft ring. - Pointer targets are at least 24px and touch targets at least 44px. Every drag has a keyboard and a menu alternative.
- Color is never the only signal: stages, issues and states always pair color with text and an icon.
- Sheets and dialogs trap focus; Esc closes the top layer and returns focus to its trigger. Save state and toasts announce through a polite live region.
Themes
The theme cookie holds light, dark or system (the default); system follows prefers-color-scheme live. ThemeProvider owns the .dark class on <html>, and an inline script in index.html sets it before first paint. Resumes and letters always render on white paper, whatever the theme.
Internationalization
- Every user-facing string goes through Lingui (
t,msg,<Trans>); catalogs are PO files inapps/web/locales. Primitives inpackages/uican't use Lingui, so they take labels as props (for examplecloseLabel). - 55 interface languages, including right-to-left ones.
<html dir>follows the locale andDirectionProviderpasses it to Base UI. - Use logical properties (
ps,pe,ms,me,inset-s,inset-e) instead of physical ones. - Translations run 30–50% longer than English; avoid fixed widths on text.
Do and don't
- Do keep one accent-filled button per view, and keep accent for next actions and working states.
- Do use
ink-3as the lightest text color, and pair every color signal with text. - Do build states in full: empty, loading (placeholders at their real size), error (why and what to do) and success.
- Don't hard-code colors, including Tailwind palette classes such as
amber-600; use the semantic tokens. - Don't use Newsreader for anything smaller than a sheet title.
- Don't ask for confirmation for something that can be undone; use an undo toast instead.
- Don't skip
data-sloton primitives; tests and styles rely on it.