docs(phase-5): UI design contract for Design System Token Rework
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
235
.planning/phases/05-design-system-token-rework/05-UI-SPEC.md
Normal file
235
.planning/phases/05-design-system-token-rework/05-UI-SPEC.md
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
---
|
||||||
|
phase: 5
|
||||||
|
slug: design-system-token-rework
|
||||||
|
status: draft
|
||||||
|
shadcn_initialized: true
|
||||||
|
preset: new-york / neutral / lucide
|
||||||
|
created: 2026-04-20
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 5 — UI Design Contract
|
||||||
|
|
||||||
|
> Visual and interaction contract for Phase 5: Design System Token Rework.
|
||||||
|
> Generated by gsd-ui-researcher, verified by gsd-ui-checker.
|
||||||
|
>
|
||||||
|
> This phase is a pure token and spacing rework — no new components, no new features.
|
||||||
|
> Every entry in this contract describes what must be TRUE after the change, not before.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design System
|
||||||
|
|
||||||
|
| Property | Value | Source |
|
||||||
|
|----------|-------|--------|
|
||||||
|
| Tool | shadcn/ui | components.json |
|
||||||
|
| Style | new-york | components.json |
|
||||||
|
| Preset | neutral base, cssVariables: true | components.json |
|
||||||
|
| Component library | Radix UI (via shadcn) | components.json |
|
||||||
|
| Icon library | lucide-react | components.json |
|
||||||
|
| Font | Inter (--font-sans) | src/index.css |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Spacing Scale
|
||||||
|
|
||||||
|
Declared values (all multiples of 4):
|
||||||
|
|
||||||
|
| Token | px Value | Tailwind Class | Usage |
|
||||||
|
|-------|----------|----------------|-------|
|
||||||
|
| xs | 4px | gap-1 / p-1 | Icon gaps, inline tight spacing |
|
||||||
|
| sm | 8px | gap-2 / p-2 | Compact inline elements, badge padding |
|
||||||
|
| md | 16px | gap-4 / p-4 | Default inline element spacing |
|
||||||
|
| lg | 24px | gap-6 / p-6 | Card internal padding (upgraded from p-4) |
|
||||||
|
| xl | 32px | gap-8 | Section gaps between cards and sections (upgraded from gap-6) |
|
||||||
|
| 2xl | 48px | gap-12 | Major section breaks, page-level vertical rhythm |
|
||||||
|
| 3xl | 64px | py-16 | Auth page vertical centering, hero areas |
|
||||||
|
|
||||||
|
**Phase 5 spacing changes (from CONTEXT.md):**
|
||||||
|
- Card internal padding: `p-4` → `p-6` across all 9 pages
|
||||||
|
- Section gaps: `gap-4` → `gap-6`, `gap-6` → `gap-8` across all pages
|
||||||
|
- Page header bottom margin: standardize to `mb-6` everywhere
|
||||||
|
- Section-to-section gap: standardize to `gap-8`
|
||||||
|
|
||||||
|
Exceptions: none — 8-point scale applies without exception.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Typography
|
||||||
|
|
||||||
|
| Role | Size | Tailwind | Weight | Weight Class | Line Height | Usage |
|
||||||
|
|------|------|----------|--------|--------------|-------------|-------|
|
||||||
|
| Caption | 12px | text-xs | 400 | font-normal | 1.5 | Subtitles, secondary metadata |
|
||||||
|
| Body / Label | 14px | text-sm | 500 | font-medium | 1.5 | Table cells, form labels, card labels, stat subtitles |
|
||||||
|
| Base | 16px | text-base | 500 | font-medium | 1.5 | Card titles (e.g. chart section headings) |
|
||||||
|
| Heading | 24px | text-2xl | 600 | font-semibold | 1.2 | Page titles (PageShell h1), auth card titles, template names |
|
||||||
|
|
||||||
|
Source: Existing usage in PageShell, StatCard, DashboardPage, LoginPage, RegisterPage confirmed these four sizes as the complete in-use set.
|
||||||
|
|
||||||
|
Weights used: exactly 2 — `font-medium` (500) for body/data, `font-semibold` (600) for headings. The rare `font-bold` (700) occurrences in StatCard value display are reclassified as `font-semibold` for consistency.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Color
|
||||||
|
|
||||||
|
### Base UI Tokens (post-rework values)
|
||||||
|
|
||||||
|
| Role | OKLCH Value | Usage |
|
||||||
|
|------|-------------|-------|
|
||||||
|
| Background (dominant, 60%) | oklch(0.98 0.01 260) | Page background — chroma lifted 0.005→0.01 for subtle warmth |
|
||||||
|
| Card / Popover (secondary, 30%) | oklch(1 0 0) | Cards, modals, popovers, sidebar surface |
|
||||||
|
| Sidebar | oklch(0.97 0.008 260) | Sidebar background — no change |
|
||||||
|
| Primary accent (10%) | oklch(0.55 0.15 260) | Active nav items, primary buttons, focus rings |
|
||||||
|
| Secondary / Muted | oklch(0.93 0.02 260) | Secondary buttons, muted chip backgrounds |
|
||||||
|
| Border / Input | oklch(0.88 0.01 260) | All borders and input outlines |
|
||||||
|
| Destructive | oklch(0.6 0.2 25) | Delete actions, error alerts only |
|
||||||
|
|
||||||
|
Accent reserved for: primary action buttons, active sidebar navigation item, focus ring outlines, primary CTA buttons. No other elements may use the primary OKLCH(0.55 0.15 260) value.
|
||||||
|
|
||||||
|
### Category Text Colors (WCAG 4.5:1 contrast on white — no change to lightness/chroma)
|
||||||
|
|
||||||
|
| Token | OKLCH Value | Hue |
|
||||||
|
|-------|-------------|-----|
|
||||||
|
| --color-income | oklch(0.55 0.17 155) | Green |
|
||||||
|
| --color-bill | oklch(0.55 0.17 25) | Orange-red |
|
||||||
|
| --color-variable-expense | oklch(0.58 0.16 50) | Amber |
|
||||||
|
| --color-debt | oklch(0.52 0.18 355) | Red |
|
||||||
|
| --color-saving | oklch(0.55 0.16 220) | Blue |
|
||||||
|
| --color-investment | oklch(0.55 0.16 285) | Violet |
|
||||||
|
|
||||||
|
### Category Fill Colors (post-rework — chroma raised to 0.22+)
|
||||||
|
|
||||||
|
These replace the current fill tokens (C=0.18-0.20). Exact values are at Claude's discretion per CONTEXT.md as long as chroma >= 0.22 and the fills remain visually distinct from each other.
|
||||||
|
|
||||||
|
| Token | Target OKLCH | Constraint |
|
||||||
|
|-------|--------------|------------|
|
||||||
|
| --color-income-fill | oklch(0.72 0.22 155) | C >= 0.22, L ~0.70-0.75 |
|
||||||
|
| --color-bill-fill | oklch(0.70 0.22 25) | C >= 0.22, L ~0.68-0.73 |
|
||||||
|
| --color-variable-expense-fill | oklch(0.74 0.22 50) | C >= 0.22, L ~0.70-0.76 |
|
||||||
|
| --color-debt-fill | oklch(0.66 0.23 355) | C >= 0.22, L ~0.64-0.70 |
|
||||||
|
| --color-saving-fill | oklch(0.72 0.22 220) | C >= 0.22, L ~0.70-0.75 |
|
||||||
|
| --color-investment-fill | oklch(0.68 0.22 285) | C >= 0.22, L ~0.65-0.72 |
|
||||||
|
|
||||||
|
### Chart Colors (post-rework — aligned to fill tokens)
|
||||||
|
|
||||||
|
The `--color-chart-1` through `--color-chart-5` variables are REMOVED. Chart components reference `--color-*-fill` tokens directly. This eliminates the duplicate color system.
|
||||||
|
|
||||||
|
| Removed | Replaced by |
|
||||||
|
|---------|-------------|
|
||||||
|
| --color-chart-1 | --color-income-fill |
|
||||||
|
| --color-chart-2 | --color-bill-fill |
|
||||||
|
| --color-chart-3 | --color-variable-expense-fill |
|
||||||
|
| --color-chart-4 | --color-debt-fill |
|
||||||
|
| --color-chart-5 | --color-saving-fill |
|
||||||
|
|
||||||
|
### Corner Radius
|
||||||
|
|
||||||
|
| Token | Current Value | Post-Rework Value | Effect |
|
||||||
|
|-------|--------------|-------------------|--------|
|
||||||
|
| --radius | 0.625rem (10px) | 0rem (0px) | All shadcn components become sharp-cornered |
|
||||||
|
|
||||||
|
Third-party overrides required (applied via CSS selectors in src/index.css):
|
||||||
|
- Recharts bar elements: force `rx="0" ry="0"` or CSS `border-radius: 0`
|
||||||
|
- Sonner toast container: override `.sonner-toast` border-radius to 0
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Copywriting Contract
|
||||||
|
|
||||||
|
Phase 5 is a pure visual rework — no new user-facing copy is introduced. The following existing copy elements remain unchanged and are documented here as the confirmed contract.
|
||||||
|
|
||||||
|
| Element | Copy | Notes |
|
||||||
|
|---------|------|-------|
|
||||||
|
| Primary CTA (Budget List) | "New Budget" | Existing — unchanged |
|
||||||
|
| Primary CTA (Template) | "Add item" | Existing — unchanged |
|
||||||
|
| Primary CTA (Categories) | "New Category" | Existing — unchanged |
|
||||||
|
| Empty state (Dashboard) | Translation key: `dashboard.noBudgetForMonth` | Existing — no copy changes this phase |
|
||||||
|
| Error state (auth forms) | Translation key: `auth.error` + specific message | Existing — no copy changes this phase |
|
||||||
|
| Destructive actions | None introduced in this phase | Token rework only |
|
||||||
|
|
||||||
|
No new destructive actions are introduced. No new confirmation dialogs. No new empty states.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Component Inventory
|
||||||
|
|
||||||
|
Components affected by token changes (no code changes required — token cascade handles it):
|
||||||
|
|
||||||
|
| Component | Location | Rounding Source | Change Required |
|
||||||
|
|-----------|----------|-----------------|-----------------|
|
||||||
|
| Button | src/components/ui/button.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Card | src/components/ui/card.tsx | --radius token | Automatic; padding class updated to p-6 |
|
||||||
|
| Input | src/components/ui/input.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Badge | src/components/ui/badge.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Select | src/components/ui/select.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Sheet | src/components/ui/sheet.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Dialog | src/components/ui/dialog.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Popover | src/components/ui/popover.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Sidebar | src/components/ui/sidebar.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Dropdown Menu | src/components/ui/dropdown-menu.tsx | --radius token | Automatic via --radius: 0 |
|
||||||
|
| Recharts bars | SpendBarChart, IncomeBarChart | SVG rx/ry attrs | Explicit CSS override needed |
|
||||||
|
| Sonner toasts | src/components/ui/sonner.tsx | Sonner inline styles | CSS selector override needed |
|
||||||
|
| Category swatches | CategoriesPage, CategorySection | Hardcoded rounded-* | Audit and remove rounded-* classes |
|
||||||
|
| Budget progress bars | BudgetDetailPage | Hardcoded rounded-* | Audit and remove rounded-* classes |
|
||||||
|
|
||||||
|
Pages to audit for inline `rounded-*` classes (must be zero after this phase):
|
||||||
|
1. DashboardPage — CategorySection swatches, StatCard
|
||||||
|
2. BudgetListPage — budget item rows
|
||||||
|
3. BudgetDetailPage — progress bars, budget row items
|
||||||
|
4. TemplatePage — template item rows, category group headers
|
||||||
|
5. CategoriesPage — category color swatches
|
||||||
|
6. QuickAddPage — picker items
|
||||||
|
7. SettingsPage — form elements
|
||||||
|
8. LoginPage — auth card
|
||||||
|
9. RegisterPage — auth card
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Registry Safety
|
||||||
|
|
||||||
|
| Registry | Blocks Used | Safety Gate |
|
||||||
|
|----------|-------------|-------------|
|
||||||
|
| shadcn official (new-york) | button, card, badge, input, label, select, sheet, dialog, popover, sidebar, dropdown-menu, separator, skeleton, table, tooltip, sonner, chart, collapsible | not required |
|
||||||
|
| Third-party | none | not applicable |
|
||||||
|
|
||||||
|
No third-party registries. No vetting gate required.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Interaction Contract
|
||||||
|
|
||||||
|
Phase 5 introduces no new interaction patterns. Existing interactions are preserved. The following are confirmed unchanged:
|
||||||
|
|
||||||
|
- Collapsible sections: 200ms ease-out open/close animation (--animate-collapsible-open/close) — no change
|
||||||
|
- Sidebar navigation: active state uses primary color — no change to behavior
|
||||||
|
- Form validation: error states use `--color-destructive` — no change
|
||||||
|
- Chart tooltips: Recharts default — style override via chart.tsx config only
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Visual Regression Checklist
|
||||||
|
|
||||||
|
The executor must perform a manual visual pass after all token changes confirming:
|
||||||
|
|
||||||
|
- [ ] No pill buttons visible on any of the 9 pages
|
||||||
|
- [ ] No rounded cards visible on any of the 9 pages
|
||||||
|
- [ ] No rounded inputs visible on any of the 9 pages
|
||||||
|
- [ ] Category fill colors are visibly colorful against white (not grey-tinted)
|
||||||
|
- [ ] Category text colors still appear dark/readable (not washed out by chroma increase)
|
||||||
|
- [ ] Section gaps feel generous — no visual crowding between cards
|
||||||
|
- [ ] Card internal padding feels spacious — content not flush against card edges
|
||||||
|
- [ ] Page headers have consistent bottom margin before first content section
|
||||||
|
- [ ] Recharts bars are square-ended (no rounded caps)
|
||||||
|
- [ ] Sonner toasts have sharp corners
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checker Sign-Off
|
||||||
|
|
||||||
|
- [ ] Dimension 1 Copywriting: PASS
|
||||||
|
- [ ] Dimension 2 Visuals: PASS
|
||||||
|
- [ ] Dimension 3 Color: PASS
|
||||||
|
- [ ] Dimension 4 Typography: PASS
|
||||||
|
- [ ] Dimension 5 Spacing: PASS
|
||||||
|
- [ ] Dimension 6 Registry Safety: PASS
|
||||||
|
|
||||||
|
**Approval:** pending
|
||||||
Reference in New Issue
Block a user