From 9817a80f32724818ef498b45550e5a53c4af844b Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sun, 12 Apr 2026 20:08:44 +0200 Subject: [PATCH] docs(31): UI design contract for mobile icon buttons --- .../phases/31-mobile-polish/31-UI-SPEC.md | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 .planning/phases/31-mobile-polish/31-UI-SPEC.md diff --git a/.planning/phases/31-mobile-polish/31-UI-SPEC.md b/.planning/phases/31-mobile-polish/31-UI-SPEC.md new file mode 100644 index 0000000..1ff6482 --- /dev/null +++ b/.planning/phases/31-mobile-polish/31-UI-SPEC.md @@ -0,0 +1,161 @@ +--- +phase: 31 +slug: mobile-polish +status: draft +shadcn_initialized: false +preset: none +created: 2026-04-12 +--- + +# Phase 31 — UI Design Contract + +> Visual and interaction contract for mobile icon-based action buttons. Generated by gsd-ui-researcher, verified by gsd-ui-checker. + +--- + +## Design System + +| Property | Value | +|----------|-------| +| Tool | none | +| Preset | not applicable | +| Component library | none (plain Tailwind) | +| Icon library | lucide-react via LucideIcon component | +| Font | System default (Tailwind default stack) | + +--- + +## Spacing Scale + +Declared values (must be multiples of 4): + +| Token | Value | Usage | +|-------|-------|-------| +| xs | 4px | Icon gaps, inline padding | +| sm | 8px | Compact element spacing, icon button padding | +| md | 16px | Default element spacing | +| lg | 24px | Section padding | +| xl | 32px | Layout gaps | +| 2xl | 48px | Major section breaks | +| 3xl | 64px | Page-level spacing | + +Exceptions: Touch targets minimum 44x44px (11 Tailwind units) for icon-only buttons on mobile + +--- + +## Typography + +| Role | Size | Weight | Line Height | +|------|------|--------|-------------| +| Body | 14px (text-sm) | 400 | 1.5 | +| Label | 12px (text-xs) | 500 | 1.5 | +| Heading | 24px (text-2xl) | 700 (bold) | 1.2 | +| Display | 20px (text-xl) | 600 (semibold) | 1.2 | + +Note: Icon-only buttons have no text labels on mobile. Tooltips (if added) use text-xs (12px). + +--- + +## Color + +| Role | Value | Usage | +|------|-------|-------| +| Dominant (60%) | white (#ffffff) | Background, surfaces | +| Secondary (30%) | gray-50 (#f9fafb) / gray-100 (#f3f4f6) | Cards, hover states, icon button hover bg | +| Accent (10%) | gray-700 (#374151) | Primary action icon buttons (Edit) | +| Destructive | red-500 (#ef4444) | Delete/Remove icon buttons only | + +Accent reserved for: Edit button (primary action), icon button active/pressed states + +### Icon Button Color Mapping + +| Action | Icon Color | Hover BG | Notes | +|--------|-----------|----------|-------| +| Edit | gray-700 (white bg variant) | gray-100 | Primary action, most prominent | +| Duplicate | gray-500 | gray-50 | Secondary action | +| Delete/Remove | red-400 | red-50 | Destructive — matches existing pattern | +| Pick as Winner | amber-700 | amber-100 | Matches existing candidate resolve pattern | +| Add to Collection | white (on gray-700 bg) | gray-800 | Primary CTA on catalog detail | +| Add to Thread | gray-700 | gray-50 | Secondary CTA on catalog detail | + +--- + +## Copywriting Contract + +| Element | Copy | +|---------|------| +| Primary CTA | n/a (icon-only on mobile, text preserved on desktop) | +| Empty state heading | n/a (no new empty states in this phase) | +| Empty state body | n/a | +| Error state | n/a (no new error states in this phase) | +| Destructive confirmation | Existing ConfirmDialog patterns unchanged | + +### Icon-to-Action Mapping (Mobile) + +| Action | Lucide Icon Name | Size | aria-label | +|--------|-----------------|------|------------| +| Edit | `pencil` | 16px | "Edit" | +| Delete | `trash-2` | 16px | "Delete" | +| Remove from Collection | `trash-2` | 16px | "Remove from Collection" | +| Duplicate | `copy` | 16px | "Duplicate" | +| Pick as Winner | `trophy` | 14px | "Pick as winner" | +| Add to Collection | `plus` | 16px | "Add to Collection" | +| Add to Thread | `message-square-plus` | 16px | "Add to Thread" | +| Add Items (setup) | `plus` | 16px | "Add Items" | +| Toggle Public | `globe` | 16px | "Toggle public" | +| Delete Setup | `trash-2` | 16px | "Delete Setup" | + +### Accessibility + +- Every icon-only button MUST have `aria-label` matching the action text shown on desktop +- Icon buttons use `title` attribute matching `aria-label` for hover tooltip on touch-and-hold +- Minimum touch target: 44x44px (achieved via `min-w-[44px] min-h-[44px]` or equivalent padding) + +--- + +## Responsive Breakpoint Contract + +| Breakpoint | Behavior | +|------------|----------| +| Below `md:` (< 768px) | Icon-only buttons, no text labels | +| `md:` and above (>= 768px) | Full text buttons (current behavior, unchanged) | + +Implementation pattern: +```tsx +{/* Desktop: text button */} + +{/* Mobile: icon-only button */} + +``` + +--- + +## Registry Safety + +| Registry | Blocks Used | Safety Gate | +|----------|-------------|-------------| +| n/a | none | not required | + +No shadcn or third-party registries. All components are hand-rolled with Tailwind CSS. + +--- + +## 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