docs(32): UI design contract
This commit is contained in:
225
.planning/phases/32-setup-sharing-system/32-UI-SPEC.md
Normal file
225
.planning/phases/32-setup-sharing-system/32-UI-SPEC.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
---
|
||||||
|
phase: 32
|
||||||
|
slug: setup-sharing-system
|
||||||
|
status: approved
|
||||||
|
shadcn_initialized: false
|
||||||
|
preset: none
|
||||||
|
created: 2026-04-13
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 32 — UI Design Contract
|
||||||
|
|
||||||
|
> Visual and interaction contract for the Setup Sharing System. Covers share button, share modal, visibility picker, and shared setup viewer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design System
|
||||||
|
|
||||||
|
| Property | Value |
|
||||||
|
|----------|-------|
|
||||||
|
| Tool | none |
|
||||||
|
| Preset | not applicable |
|
||||||
|
| Component library | none (custom Tailwind components) |
|
||||||
|
| Icon library | Lucide via `LucideIcon` component from `lib/iconData` |
|
||||||
|
| Font | System font stack (inherited from existing app) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Spacing Scale
|
||||||
|
|
||||||
|
Declared values (must be multiples of 4):
|
||||||
|
|
||||||
|
| Token | Value | Usage |
|
||||||
|
|-------|-------|-------|
|
||||||
|
| xs | 4px | Icon gaps, inline padding |
|
||||||
|
| sm | 8px | Compact element spacing, gap-2 |
|
||||||
|
| md | 16px | Default element spacing, gap-4, p-4 |
|
||||||
|
| lg | 24px | Section padding, p-6 |
|
||||||
|
| xl | 32px | Layout gaps |
|
||||||
|
| 2xl | 48px | Major section breaks |
|
||||||
|
| 3xl | 64px | Page-level spacing |
|
||||||
|
|
||||||
|
Exceptions: none
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Typography
|
||||||
|
|
||||||
|
| Role | Size | Weight | Line Height |
|
||||||
|
|------|------|--------|-------------|
|
||||||
|
| Body | 14px (text-sm) | 400 | 1.5 |
|
||||||
|
| Label | 14px (text-sm) | 500 (font-medium) | 1.5 |
|
||||||
|
| Heading | 16px (text-base) | 600 (font-semibold) | 1.5 |
|
||||||
|
| Display | 20px (text-xl) | 600 (font-semibold) | 1.5 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Color
|
||||||
|
|
||||||
|
| Role | Value | Usage |
|
||||||
|
|------|-------|-------|
|
||||||
|
| Dominant (60%) | gray-50 (#f9fafb) | Page background, surfaces |
|
||||||
|
| Secondary (30%) | white (#ffffff) | Cards, modals, panels |
|
||||||
|
| Accent (10%) | gray-700 (#374151) | Primary action buttons (Add Items, share CTA) |
|
||||||
|
| Destructive | red-600 (#dc2626) | Revoke link, delete actions |
|
||||||
|
|
||||||
|
Accent reserved for: primary action buttons only (Add Items, Create Link)
|
||||||
|
|
||||||
|
### Visibility State Colors
|
||||||
|
|
||||||
|
| State | Icon | Text Color | Background |
|
||||||
|
|-------|------|------------|------------|
|
||||||
|
| Private | `lock` | gray-500 | gray-50 |
|
||||||
|
| Link | `link` | blue-600 | blue-50 |
|
||||||
|
| Public | `globe` | green-700 | green-50 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Component Specifications
|
||||||
|
|
||||||
|
### Share Button (replaces globe toggle)
|
||||||
|
|
||||||
|
**Desktop variant:**
|
||||||
|
- Position: same location as current globe toggle button in setup detail header bar
|
||||||
|
- Layout: `inline-flex items-center gap-1.5 px-3 py-2`
|
||||||
|
- Text: "Share" (always visible regardless of visibility state)
|
||||||
|
- Icon: varies by visibility state (see color table above), size 16px
|
||||||
|
- Background/text color: matches visibility state from color table
|
||||||
|
- Rounded: `rounded-lg`
|
||||||
|
- Hover: lighten background one shade
|
||||||
|
|
||||||
|
**Mobile variant:**
|
||||||
|
- Layout: `inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2`
|
||||||
|
- Icon only (no text), same icon/color logic as desktop
|
||||||
|
- `aria-label`: "Share settings"
|
||||||
|
- Rounded: `rounded-lg`
|
||||||
|
|
||||||
|
### Share Modal
|
||||||
|
|
||||||
|
**Overlay:** `fixed inset-0 z-50 bg-black/50 flex items-center justify-center`
|
||||||
|
|
||||||
|
**Modal container:**
|
||||||
|
- Desktop: `bg-white rounded-xl shadow-lg p-6 max-w-md mx-4 w-full`
|
||||||
|
- Max height: `max-h-[80vh] overflow-y-auto`
|
||||||
|
- Matches existing modal pattern (see ConfirmDialog.tsx, CreateThreadModal.tsx)
|
||||||
|
|
||||||
|
**Header:**
|
||||||
|
- Title: "Share Setup" (`text-lg font-semibold text-gray-900`)
|
||||||
|
- Close button: top-right, `LucideIcon name="x" size={20}`, `text-gray-400 hover:text-gray-600`
|
||||||
|
- Divider: `border-b border-gray-100 pb-4 mb-4`
|
||||||
|
|
||||||
|
**Visibility Picker Section:**
|
||||||
|
- Label: "Visibility" (`text-sm font-medium text-gray-700 mb-2`)
|
||||||
|
- Three radio-style buttons in a vertical stack, `gap-2`
|
||||||
|
- Each option: `flex items-center gap-3 p-3 rounded-lg border cursor-pointer transition-colors`
|
||||||
|
- Unselected: `border-gray-200 hover:border-gray-300`
|
||||||
|
- Selected: `border-{state-color}-200 bg-{state-color}-50`
|
||||||
|
- Option layout:
|
||||||
|
- Icon (size 20, state color)
|
||||||
|
- Label (`text-sm font-medium text-gray-900`): "Private" / "Link sharing" / "Public"
|
||||||
|
- Description (`text-xs text-gray-500`): "Only you can access" / "Anyone with the link" / "Visible on your profile"
|
||||||
|
|
||||||
|
**Create Link Section (visible when visibility is `link` or `public`):**
|
||||||
|
- Divider: `border-t border-gray-100 pt-4 mt-4`
|
||||||
|
- Section label: "Share Links" (`text-sm font-medium text-gray-700 mb-3`)
|
||||||
|
- Create row: `flex items-center gap-2`
|
||||||
|
- Expiration dropdown: `select` element styled with `px-3 py-2 text-sm border border-gray-200 rounded-lg bg-white`
|
||||||
|
- Options: "7 days", "14 days" (default), "30 days", "No expiration"
|
||||||
|
- Create button: `px-4 py-2 bg-gray-700 hover:bg-gray-800 text-white text-sm font-medium rounded-lg`
|
||||||
|
- Text: "Create Link"
|
||||||
|
|
||||||
|
**Active Links List:**
|
||||||
|
- Each link: `flex items-center gap-2 p-3 bg-gray-50 rounded-lg mb-2`
|
||||||
|
- URL display: `text-sm text-gray-600 truncate flex-1` showing `/s/{token-prefix}...`
|
||||||
|
- Expiration badge: `text-xs text-gray-400` showing "Expires {date}" or "No expiration"
|
||||||
|
- Copy button: `p-1.5 text-gray-400 hover:text-gray-600 rounded` with `LucideIcon name="copy" size={16}`
|
||||||
|
- After copy: icon changes to `check` with `text-green-500` for 2 seconds
|
||||||
|
- Revoke button: `p-1.5 text-gray-400 hover:text-red-500 rounded` with `LucideIcon name="x" size={16}`
|
||||||
|
|
||||||
|
**Empty state (no links yet):**
|
||||||
|
- Text: "No share links yet" (`text-sm text-gray-400 text-center py-4`)
|
||||||
|
|
||||||
|
**Deactivation warning (when switching to private with active links):**
|
||||||
|
- Inline warning below visibility picker: `flex items-start gap-2 p-3 bg-amber-50 border border-amber-200 rounded-lg mt-2`
|
||||||
|
- Icon: `LucideIcon name="alert-triangle" size={16}` in `text-amber-500`
|
||||||
|
- Text: "Switching to private will deactivate all share links. They can be reactivated by switching back." (`text-sm text-amber-700`)
|
||||||
|
|
||||||
|
### Shared Setup Viewer
|
||||||
|
|
||||||
|
**Route:** `/setups/:setupId?share={token}`
|
||||||
|
|
||||||
|
**Shared banner:**
|
||||||
|
- Position: top of setup detail page, before header
|
||||||
|
- Layout: `flex items-center gap-2 px-4 py-2 bg-blue-50 border-b border-blue-100`
|
||||||
|
- Icon: `LucideIcon name="link" size={16}` in `text-blue-500`
|
||||||
|
- Text: "Shared setup" (`text-sm text-blue-700`)
|
||||||
|
- Appears only when viewing via share token
|
||||||
|
|
||||||
|
**Content:** Identical to public setup view (read-only item list with weight summary, no action buttons)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Copywriting Contract
|
||||||
|
|
||||||
|
| Element | Copy |
|
||||||
|
|---------|------|
|
||||||
|
| Modal title | Share Setup |
|
||||||
|
| Visibility: Private label | Private |
|
||||||
|
| Visibility: Private description | Only you can access |
|
||||||
|
| Visibility: Link label | Link sharing |
|
||||||
|
| Visibility: Link description | Anyone with the link |
|
||||||
|
| Visibility: Public label | Public |
|
||||||
|
| Visibility: Public description | Visible on your profile |
|
||||||
|
| Create link CTA | Create Link |
|
||||||
|
| Empty links state | No share links yet |
|
||||||
|
| Deactivation warning | Switching to private will deactivate all share links. They can be reactivated by switching back. |
|
||||||
|
| Copy success toast | Link copied |
|
||||||
|
| Revoke confirmation | Revoke this share link? |
|
||||||
|
| Shared banner text | Shared setup |
|
||||||
|
| Expired link error | This share link has expired |
|
||||||
|
| Invalid link error | This share link is no longer valid |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Registry Safety
|
||||||
|
|
||||||
|
| Registry | Blocks Used | Safety Gate |
|
||||||
|
|----------|-------------|-------------|
|
||||||
|
| No external registries | N/A | N/A |
|
||||||
|
|
||||||
|
All components are custom Tailwind — no shadcn or third-party UI registry blocks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Responsive Behavior
|
||||||
|
|
||||||
|
| Breakpoint | Share Button | Share Modal |
|
||||||
|
|------------|-------------|-------------|
|
||||||
|
| Mobile (<768px) | Icon only, 44x44px touch target | Full width with mx-4 margin |
|
||||||
|
| Desktop (>=768px) | Icon + "Share" text | max-w-md centered |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Interaction States
|
||||||
|
|
||||||
|
| Interaction | Behavior |
|
||||||
|
|-------------|----------|
|
||||||
|
| Open modal | Click share button, modal appears with current visibility pre-selected |
|
||||||
|
| Change visibility | Immediate API call on selection, optimistic update |
|
||||||
|
| Create link | API call, new link appears in list, auto-copy to clipboard |
|
||||||
|
| Copy link | Copy full URL to clipboard, show check icon for 2s |
|
||||||
|
| Revoke link | Confirmation prompt (reuse ConfirmDialog pattern), then remove from list |
|
||||||
|
| Close modal | Click X, click overlay, or press Escape |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checker Sign-Off
|
||||||
|
|
||||||
|
- [x] Dimension 1 Copywriting: PASS
|
||||||
|
- [x] Dimension 2 Visuals: PASS
|
||||||
|
- [x] Dimension 3 Color: PASS
|
||||||
|
- [x] Dimension 4 Typography: PASS
|
||||||
|
- [x] Dimension 5 Spacing: PASS
|
||||||
|
- [x] Dimension 6 Registry Safety: PASS
|
||||||
|
|
||||||
|
**Approval:** approved 2026-04-13
|
||||||
Reference in New Issue
Block a user