Files
collective-lists/DESIGN.md
Oier Bravo Urtasun f5903ef442 Add planning docs, design system, and Stitch mockups
- CLAUDE.md: project guidance (stack, domain model, auth, i18n, gotchas)
- DESIGN.md: full design system spec derived from Stitch mockups (slate
  monochrome, Inter, shadcn-svelte, screen patterns for all 5 views)
- README.md: development plan with Justfile commands
- analysis/: functional spec (domain model, use cases, business rules)
- plan/: phase-by-phase implementation plans (Fase 0–4)
- .stitch/designs/: generated mockups (lists, shopping session, notes,
  tasks, list detail with frequency chips)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 06:35:07 +02:00

443 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DESIGN.md
Design reference for the Colectivo app. Stack: SvelteKit + shadcn-svelte + Tailwind CSS.
Generated mockups are in `.stitch/designs/`. Stitch project ID: `10316144241804324155`.
---
## Visual Style
### Direction
Clean and minimal. Content is the UI — no decorative elements, no gradients, no shadows unless they carry meaning. Generous whitespace. Every element earns its place.
### Color
Monochromatic slate palette. No accent color — contrast and weight carry hierarchy.
```
--background: slate-50 / slate-950
--surface: white / slate-900
--surface-raised: slate-100 / slate-800
--border: slate-200 / slate-700
--text-primary: slate-900 / slate-50
--text-secondary: slate-500 / slate-400
--text-disabled: slate-300 / slate-600
--destructive: red-500 / red-400 ← only color in the UI
```
Interactive elements (buttons, checkboxes, active states) use `slate-900` on light and `slate-50` on dark — inverting the surface. The only true color is destructive red.
### Typography
Font: **Inter** (or `system-ui` as fallback — acceptable on iOS/macOS).
| Role | Size | Weight | Notes |
|---|---|---|---|
| Screen title | 20px | 600 | |
| Section label | 13px | 600 | Uppercase, `letter-spacing: 0.05em` |
| Body / list item | 16px | 400 | |
| Meta / secondary | 13px | 400 | `text-slate-500` |
| Badge / tag | 11px | 500 | Uppercase, `rounded-full` |
| Input | 16px | 400 | Min 16px prevents iOS zoom on focus |
Line height: 1.5 for body, 1.2 for headings. No text smaller than 11px.
### Spacing
Base unit: 4px (Tailwind default). Prefer multiples of 4. Common values:
- List item padding: `px-4 py-3` (min 48px touch target)
- Screen horizontal margin: `px-4` (mobile), `px-6` (desktop)
- Section gap: `gap-6`
- Between section label and content: `mt-2`
- Bottom nav / sticky input safe area: always account for `env(safe-area-inset-bottom)`
### Iconography
**Lucide** (ships with shadcn-svelte). Size `20px` inline, `24px` for nav and primary actions. Stroke width `1.5`. Never fill icons.
### Dark Mode
Class-based (`dark` on `<html>`). Respect `prefers-color-scheme` on first load, then persist user preference in `localStorage`. shadcn-svelte's CSS variable system handles theming — no additional setup needed per component.
---
## Component Library
**shadcn-svelte** — copy-paste components built on bits-ui + Tailwind. No runtime dependency, full ownership of component code.
### Conventions
- Copy components into `apps/web/src/lib/components/ui/` (shadcn-svelte default)
- App-specific compositions go in `apps/web/src/lib/components/` (e.g. `ItemRow.svelte`, `ListCard.svelte`)
- Never modify shadcn-svelte primitives directly — compose or wrap them
- Use shadcn-svelte's `cn()` utility for conditional classes
### Key components to install
| Component | Used for |
|---|---|
| `Button` | All actions |
| `Input` | Add item, search, forms |
| `Checkbox` | Shopping items, tasks |
| `Sheet` | Mobile bottom drawers (item edit, member invite, avatar picker) |
| `Dialog` | Confirmations (delete list, dissolve collective) |
| `Popover` | Presence avatars tooltip |
| `Badge` | Priority tags (TODAY, URGENT), status labels (DRAFT, HIGH PRIORITY) |
| `Skeleton` | Loading states |
| `Sonner` | Toast notifications (sync errors, member joined, undo delete) |
---
## Layout & Navigation
### App Shell
Two-column on desktop, single-column on mobile.
```
Mobile Desktop (lg+)
┌─────────────────────┐ ┌──────────┬──────────────────────┐
│ Header │ │ │ Breadcrumb / Title │
├─────────────────────┤ │ Sidebar │──────────────────────┤
│ │ │ │ │
│ Content │ │ │ Content │
│ │ │ │ │
├─────────────────────┤ │ User │ │
│ Bottom Nav │ │ Info │ │
└─────────────────────┘ └──────────┴──────────────────────┘
```
### Sidebar (desktop)
Fixed left sidebar, `surface-raised` background (vs `surface` main area — tonal shift, no border line).
```
┌──────────────┐
│ Colectivo │ ← collective name, 14px/600
├──────────────┤
│ 🛒 Lists │ ← active item: slate-900 bg, white text
│ ✓ Tasks │ ← inactive: slate-500 text
│ 📄 Notes │
│ 🔍 Search │
│ │
│ (spacer) │
│ │
│ ┌──┐ Name │ ← user avatar + display name
│ │AG│ Role │ ⚙ ← settings gear icon
└──────────────┘
```
- Collective name at top, 14px/600
- 4 nav items: Lists, Tasks, Notes, Search
- User avatar + display name + settings gear at bottom
- Width: `w-56` (`224px`)
### Navigation (mobile)
Fixed bottom tab bar, 4 tabs. Icons only — no text labels. Active icon: `slate-900`. Inactive: `slate-400`. Glassmorphism background: `backdrop-blur-md bg-white/80`. Respects `safe-area-inset-bottom`.
| Tab | Icon | Route |
|---|---|---|
| Lists | `shopping-cart` | `/lists` |
| Tasks | `check-square` | `/tasks` |
| Notes | `file-text` | `/notes` |
| Search | `search` | `/search` |
### Page Headers
Desktop: breadcrumb-style context path above the title, in uppercase 11px/500 `text-slate-400`:
```
WORKSPACE OVERVIEW
Shared Lists
```
```
PROJECT ATLAS / Tasks
```
Mobile: plain title with optional back arrow and overflow `⋯` menu on the right.
### Responsive Breakpoints
Tailwind defaults: `sm` (640), `md` (768), `lg` (1024). Sidebar appears at `lg`. Content max-width: `max-w-2xl` centered on large screens.
---
## Screen Patterns
### Lists View (`/lists`)
Featured card for the primary/active list (full width, larger), secondary lists in a 2-column grid below.
```
WORKSPACE OVERVIEW
Shared Lists
┌─────────────────────────────────────┐
│ Home 👤👤 │ ← featured card
│ 12 items · Updated 2h ago │
│ [GROCERIES] [HOUSEHOLD] │ ← category tags, rounded-full
└─────────────────────────────────────┘
┌──────────────┐ ┌──────────────┐
│ Office │ │ Party │
│ 5 items │ │ 26 items │
│ 🗂 │ │ HIGH PRTY │ ← badge
└──────────────┘ └──────────────┘
┌─────────────────────────────────────┐
│ + Create a new shared list... [Create] │ ← sticky bottom input
└─────────────────────────────────────┘
```
- Category tags on list cards: `rounded-full text-xs font-medium bg-slate-100 px-2 py-0.5`
- Presence avatars overlap on cards with active members
### List Detail (`/lists/[id]`)
Normal (non-session) view. Items with quantity controls.
```
ACTIVE LIST
Grocery List ⋯
┌─────────────────────────────────────┐
│ ☐ Honeycrisp Apples 6 + │
│ ☐ Organic Baby Spinach 2 + │
│ ☐ Whole milk 1L 2 + │
│ ☐ Salted Butter 1 + │
└─────────────────────────────────────┘
[MILK] [BREAD] [EGGS] [COFFEE] [APPLES] ← frequency chips
┌─────────────────────────────────────┐
│ Add item (e.g. Greek Yogurt 500g) [+] │
└─────────────────────────────────────┘
```
- Quantity controls: `` count `+` inline at the right of each row
- Frequency chips always visible above the input (not just on focus); active chip: `bg-slate-900 text-white`; inactive: `bg-slate-100 text-slate-700`
### Shopping Session Mode (`/lists/[id]/session`)
Full-screen takeover. No sidebar, no bottom nav.
```
✕ Compra semanal 👤👤
─────────────────────────────────────
TO BUY
☐ Whole milk 1L
☐ Bread
☐ Eggs 12 uds
☐ Avocados
CHECKED
☑ Butter 250g (muted, struck through)
☑ Olive Oil 1L
─────────────────────────────────────
[ Finish shopping ● ]
```
- `TO BUY` and `CHECKED` are uppercase section labels, not divider lines
- Items slide from TO BUY to CHECKED on tap — no page scroll
- Minimum tap target: `min-h-[56px]`
- Presence avatars: `size-6 rounded-full`, overlapping, top-right of header
- "Finish shopping" button: full-width, `bg-slate-900 text-white`, with a subtle pulse indicator dot (●)
### Tasks View (`/tasks`)
Tasks grouped into named sections. Filter pills at the bottom.
```
PROJECT ATLAS / Tasks 👤👤
─────────────────────────────────────
HIGH PRIORITY
☐ Finalize Q4 strategy deck TODAY
☐ Coordinate with design on monolith tokens URGENT
PRODUCT DEVELOPMENT
☐ Core API Integration
☐ Review documentation for Auth endpoints (indented sub-item)
☑ Map database schema to editorial structure (completed)
☐ User testing: Editorial workflow
BACKLOG
☐ Update dependency libraries
─────────────────────────────────────
[DAILY] [WEEKLY] [URGENT] ← filter pills
┌─────────────────────────────────────┐
│ Add task to Tasks... [Save] │
└─────────────────────────────────────┘
```
- Section names are user-defined (not system-fixed)
- Priority badges on individual tasks: `text-xs uppercase text-slate-400` (TODAY, URGENT)
- Filter pills: same style as frequency chips; filter the visible tasks
### Notes View (`/notes`)
Notes displayed as cards in a masonry-style grid, grouped by user-defined categories.
```
WORKSPACE / NOTES 🔔 ⊞ 👤
─────────────────────────────────────
CATEGORY
Meeting Notes
┌─────────────────┐ ┌─────────────────┐
│ Q4 Product │ │ Sprint Retro: │
│ Roadmap... │ │ Project Apollo │
│ Oct 24, 2023 │ │ Oct 22, 2023 │
└─────────────────┘ └─────────────────┘
CATEGORY
Project Ideas
┌─────────────────┐
│ Minimalist │
│ Portfolio... │
└─────────────────┘
─────────────────────────────────────
│ Capture a new thought... # @ [SAVE] │
```
- Cards: `bg-white rounded-md` on `surface-raised` background (tonal lift, no shadow)
- Category labels: uppercase section labels above each group
- Inline new-note input at the bottom (not a separate screen)
---
## UX Patterns
### Optimistic Updates
All mutations update the local store immediately before the server responds. On error, revert and show a toast. Never block the UI waiting for a network response.
### Offline Indicator
A slim bar at the top of the content area (not the header) when offline:
```
No connection · Saving locally
```
`bg-slate-800 text-slate-100`, 36px tall. Mounts/unmounts immediately — no animation.
### Frequency Chips (Add Item Input)
Sticky input area at the bottom of list and task screens. Frequency chips are **always visible** above the input, not conditional on focus.
```
[MILK] [BREAD ●] [EGGS] [COFFEE] [APPLES] ← scrollable row
┌─────────────────────────────────────────────────┐
│ Add item (e.g. Greek Yogurt 500g) [+] │
└─────────────────────────────────────────────────┘
```
- Chips: `rounded-full text-xs font-medium px-3 py-1 bg-slate-100` (inactive) / `bg-slate-900 text-white` (active/selected)
- Tapping a chip fills the input; user can still edit before confirming
- While typing, chips switch to prefix-filtered suggestions (max 10, same pill style)
- Confirm with `+` button or `Enter`
### Swipe to Delete
On list items and tasks. Swipe left reveals a red destructive zone:
```
┌────────────────────────────────────────┐
│ ☐ Whole milk 1L ░░░░░░ │ ← item sliding left
│ [🗑] │ ← red-500 zone, trash icon only
└────────────────────────────────────────┘
```
Full swipe: immediate deletion + Sonner toast "Deleted · Undo" (4 seconds). Partial swipe: snaps back. No confirmation dialog for single items.
### Drag & Drop Reordering
Handle (`grip-vertical` Lucide icon) on the left — always visible on desktop, revealed on long-press on mobile. Use `svelte-dnd-action`. During drag: lifted item has `shadow-md bg-white`, others compress to show insertion point.
### Confirmations
**Destructive, hard-to-reverse actions** (delete list, remove member, dissolve collective): `Dialog` with explicit description text. No shortcut.
**Soft deletions** (single item, single task): swipe + Sonner undo. No dialog.
### Avatar Component
Three mutually exclusive states, all `rounded-full`.
| State | Appearance | Size tokens |
|---|---|---|
| `initials` | Initials on `slate-700` bg, white 600-weight text | `size-6` presence, `size-8` lists, `size-16` settings |
| `emoji` | Emoji centered on `slate-700` bg | same |
| `upload` | `<img object-cover>`, fallback to initials on error | same |
Initials rule: first letter of first + last word in `display_name` ("Ana García" → "AG", "Borja" → "B").
### User Settings Screen (`/settings`)
In the desktop sidebar shell. Content area:
```
← Settings
┌──────┐
│ AG │ ← size-16 avatar
└──────┘
Change avatar
DISPLAY NAME
┌────────────────────────────────┐
│ Ana García │ ← auto-save, 500ms debounce
└────────────────────────────────┘
Changes saved automatically ← slate-400 hint
LANGUAGE
[ English ] [ Español ] ← pill segmented control
English selected: slate-900/white. Instant effect, no reload.
ACCOUNT ← background shift (no line)
Email & password → ← external link to Keycloak
Managed in Keycloak ← slate-400
DANGER ZONE ← section label in red-500
[ Delete account ] ← ghost red button
```
**Avatar sheet**`Sheet` (bottom on mobile, dialog on desktop):
- Segmented tabs: Initials | Emoji | Photo
- Emoji grid: 8 columns, ~40 emoji (🐸 🐼 🦊 🐨 🦁 🐯 🐻 🦋 🌵 🌻 🍀 🌈 ⭐ 🔥 💎 🎯 🎸 🎹 🎨 📚 ✈️ 🏔️ 🌊 🎭 🍕 🍜 🍣 ☕ 🍎 🥑 🍓 🎂 🏠 🚲 🛹 ⚽ 🏄 🧘 🎮 🤿)
- Photo upload: file picker → 1:1 crop in-browser → preview → confirm. Max 2MB. JPG/PNG/WebP.
### Empty States
Text-only, no illustrations. `text-slate-500`, centered in content area.
```
No lists yet.
Tap + to create one.
```
Two lines max.
### Loading States
`Skeleton` components matching the shape of the content (list rows, card grids). Spinner only for full-screen blocking operations (login, initial data fetch).
---
## Stitch Mockup Inventory
Screens in `.stitch/designs/` — project `10316144241804324155`:
| File | Screen | Status |
|---|---|---|
| `01-lists-view.png` | Lists View | ✅ |
| `02-shopping-session.png` | Shopping Session | ✅ |
| `03-notes-view.png` | Notes View | ✅ |
| `04-tasks-view.png` | Tasks View | ✅ |
| `05-list-detail.png` | List Detail with frequency chips | ✅ |
| — | User Settings | ⏳ pending generation |
| — | Collective Management | ⏳ pending generation |