From ff379ad6e3167c755ce964a61a39bb5e9e4627c7 Mon Sep 17 00:00:00 2001 From: curo1305 Date: Mon, 25 May 2026 14:23:29 +0200 Subject: [PATCH] docs(04): UI design contract for folders, sharing, quotas & document UX phase Co-Authored-By: Claude Sonnet 4.6 --- .../04-UI-SPEC.md | 390 ++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 .planning/phases/04-folders-sharing-quotas-document-ux/04-UI-SPEC.md diff --git a/.planning/phases/04-folders-sharing-quotas-document-ux/04-UI-SPEC.md b/.planning/phases/04-folders-sharing-quotas-document-ux/04-UI-SPEC.md new file mode 100644 index 0000000..85cbd97 --- /dev/null +++ b/.planning/phases/04-folders-sharing-quotas-document-ux/04-UI-SPEC.md @@ -0,0 +1,390 @@ +--- +phase: 4 +slug: folders-sharing-quotas-document-ux +status: draft +shadcn_initialized: false +preset: none +created: 2026-05-25 +--- + +# Phase 4 — UI Design Contract + +> Visual and interaction contract for Phase 4: Folders, Sharing, Quotas & Document UX. +> Generated by gsd-ui-researcher, verified by gsd-ui-checker. +> Source: existing codebase scan + 04-CONTEXT.md decisions. + +--- + +## Design System + +| Property | Value | +|----------|-------| +| Tool | none | +| Preset | not applicable | +| Component library | none (inline SVG icons, Tailwind utility classes only) | +| Icon library | Inline SVG (Heroicons stroke style, w-4 h-4 / w-5 h-5) — do not add an icon package | +| Font | System font stack (Tailwind default — no custom font loaded) | + +No design system change for Phase 4. All new components extend the existing Tailwind utility pattern established in Phase 2/3. + +--- + +## Spacing Scale + +Declared values (multiples of 4 only). Source: existing component scan — `p-4`, `px-6 py-5`, `gap-3`, `px-3 py-2`. + +| Token | Value | Usage | +|-------|-------|-------| +| xs | 4px | Icon gaps, topic badge gaps (`gap-1`) | +| sm | 8px | Compact element spacing, inline button padding (`py-1.5`) | +| md | 16px | Default element spacing, card padding (`p-4`) | +| lg | 24px | Section padding (`px-6 py-5`), page section breaks | +| xl | 32px | Page content padding (`p-8`) | +| 2xl | 48px | Major empty-state vertical padding (`py-12`) | +| 3xl | 64px | Not used in Phase 4 | + +Exceptions: +- Touch targets (icon-only buttons): minimum 44px height enforced via `min-h-[44px]` (established in ConfirmBlock.vue — apply to all icon-only action buttons in this phase). +- Breadcrumb segment gap: 8px (`gap-2`) with a separator chevron (SVG, w-3 h-3). +- Modal overlay: full-viewport fixed overlay `inset-0`, modal panel `max-w-md w-full` centered with `p-6` internal padding. +- Breadcrumb truncation ellipsis button: `px-1 py-0.5` compact. + +--- + +## Typography + +Extend existing scale — do not introduce new sizes. Source: DocumentCard.vue, AppSidebar.vue, DocumentView.vue. + +| Role | Size | Weight | Line Height | Tailwind classes | +|------|------|--------|-------------|-----------------| +| Page heading | 24px (text-2xl) | 700 (font-bold) | 1.2 | `text-2xl font-bold text-gray-900` | +| Section heading | 18px (text-lg) | 600 (font-semibold) | 1.3 | `text-lg font-semibold text-gray-800` | +| Body / card label | 14px (text-sm) | 500 (font-medium) | 1.5 | `text-sm font-medium text-gray-900` | +| Caption / metadata | 12px (text-xs) | 400 (normal) | 1.4 | `text-xs text-gray-400` | + +Weights in use: 400 (normal), 500 (medium), 600 (semibold), 700 (bold). No new weights added. + +Monospace (extracted text panel): `text-xs font-mono` at `text-gray-600` on `bg-gray-50` — established in DocumentView.vue, reuse for audit log detail cells. + +Section label / nav category: `text-xs font-semibold text-gray-400 uppercase tracking-wider` — established pattern, reuse for folder section header in sidebar. + +--- + +## Color + +Source: AppSidebar.vue, QuotaBar.vue, DocumentCard.vue, DocumentView.vue. No new colors introduced. + +| Role | Tailwind value | Hex (approx) | Usage | +|------|---------------|--------------|-------| +| Dominant (60%) | `bg-white` | #ffffff | Page background, cards, sidebar background | +| Secondary (30%) | `bg-gray-50` / `border-gray-200` | #f9fafb / #e5e7eb | Card hover surface, extracted text block background, modal backdrop inner panel, table row stripes | +| Accent (10%) | `indigo-600` / `indigo-50` / `indigo-700` | #4f46e5 | Reserved-for list below | +| Destructive | `red-600` / `red-700` | #dc2626 | Destructive action buttons only | +| Warning — quota amber | `amber-500` / `amber-600` | #f59e0b | QuotaBar 80–95% (pre-existing, do not change) | +| Warning — quota red | `red-500` / `red-600` | #ef4444 | QuotaBar ≥95% (pre-existing, do not change) | + +**Accent (indigo) reserved for:** +- Active nav link background: `bg-indigo-50 text-indigo-700` +- Primary action buttons (filled): `bg-indigo-600 hover:bg-indigo-700 text-white` +- Document icon background: `bg-indigo-50` with `text-indigo-500` icon +- Logo text: `text-indigo-600` +- User avatar background: `bg-indigo-100 text-indigo-700` +- QuotaBar fill (normal state): `bg-indigo-500` +- Link text (back navigation, inline links): `text-indigo-600 hover:underline` +- Checkbox / radio checked state: `text-indigo-600` (Tailwind form plugin default) +- Share badge (shared indicator on document card): `bg-indigo-50 text-indigo-600` pill + +Accent is NOT used on: hover states of neutral UI, sort controls, breadcrumb separators, audit log rows, sidebar section labels, permission badges (use gray), or any informational text. + +**Shared indicator badge** (SHARE-05): small `bg-indigo-50 text-indigo-600 text-xs font-medium px-2 py-0.5 rounded-full` pill labeled "Shared" — shown inline in DocumentCard below the metadata line when `doc.share_count > 0`. + +**"Shared with me" virtual folder entry** (D-06): rendered with a distinct inbox-style icon (`bg-purple-50 text-purple-500`) to visually separate it from user-owned folders. Purple is used ONLY for this one sidebar entry to signal "received from others" vs. "my own". No other UI element uses purple. + +Folder row icons in main content: `bg-gray-100 text-gray-500` (neutral — folders are structural, not accent). + +--- + +## Component Inventory + +New components required for Phase 4. All follow existing utility-class patterns. + +### FolderRow.vue +- Used in HomeView main content area to render sub-folders within a folder. +- Layout: `flex items-center gap-3 px-4 py-3 bg-white border border-gray-200 rounded-xl hover:border-indigo-300 hover:shadow-sm transition-all cursor-pointer` +- Left: folder icon `w-9 h-9 rounded-lg bg-gray-100 flex items-center justify-center` with `text-gray-500` SVG folder icon (w-5 h-5). +- Middle: folder name `font-medium text-gray-900 text-sm`, sub-label `text-xs text-gray-400` showing document count (e.g., "3 documents"). +- Right: three-dot menu button `text-gray-400 hover:text-gray-600` with dropdown for Rename and Delete actions. + +### FolderBreadcrumb.vue +- Rendered above document list when inside a folder. +- Segments: `flex items-center gap-2 text-sm`. +- Each clickable segment: `text-indigo-600 hover:underline font-medium`. +- Separator: SVG chevron-right `w-3 h-3 text-gray-400 shrink-0`. +- Truncation rule (D-02): when depth > 4, show first segment + `…` button (plain text, `px-1 py-0.5 text-gray-400 hover:text-gray-600`) + last 2 segments. +- Current (non-clickable) final segment: `text-gray-900 font-medium`. + +### ShareModal.vue +- Triggered by share icon button on DocumentCard. +- Modal overlay: `fixed inset-0 bg-black/40 flex items-center justify-center z-50`. +- Panel: `bg-white rounded-2xl shadow-xl p-6 max-w-md w-full mx-4`. +- Title: `text-lg font-semibold text-gray-900 mb-4` — "Share document". +- Handle input row: `flex gap-2` — `` + primary button "Share" `bg-indigo-600 hover:bg-indigo-700 text-white text-sm px-4 py-2 rounded-lg`. +- Separator: `border-t border-gray-100 my-4`. +- Recipients list: each row `flex items-center justify-between py-2`. + - Left: handle `text-sm text-gray-900` + permission badge `text-xs bg-gray-100 text-gray-600 px-2 py-0.5 rounded-full font-medium ml-2` (shows "view"). + - Right: "Revoke" `text-xs text-red-500 hover:text-red-700 font-medium` button. +- Empty state: `text-sm text-gray-400 italic py-2` — "Not shared with anyone yet." +- Close button: top-right `absolute top-4 right-4`, `text-gray-400 hover:text-gray-600`, SVG X icon w-5 h-5. + +### FolderDeleteModal.vue +- Triggered when deleting a non-empty folder (D-03). +- Reuses ConfirmBlock.vue pattern but rendered in a modal panel (same overlay style as ShareModal). +- Warning icon: `w-10 h-10 bg-red-50 rounded-full flex items-center justify-center` with `text-red-500` exclamation SVG, centered at top of modal. +- Heading: `text-lg font-semibold text-gray-900 mt-4 text-center` — "Delete folder?" +- Body: `text-sm text-gray-600 text-center mt-2 mb-6` — "This folder contains {N} documents. Deleting it will permanently delete all documents inside. This cannot be undone." +- Buttons: `flex gap-3 justify-end`. Cancel: `text-sm text-gray-600 hover:text-gray-800 px-4 py-2`. Confirm: `bg-red-600 hover:bg-red-700 text-white text-sm font-semibold px-4 py-2 rounded-lg min-h-[44px]` — "Delete folder and documents". + +### DocumentPreviewModal.vue (in-app mode only) +- Used when `user.pdf_open_mode === 'in_app'` (D-10). +- Overlay: `fixed inset-0 bg-black/60 z-50 flex flex-col`. +- Header bar: `bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between`. + - Left: document name `text-sm font-medium text-gray-900 truncate max-w-xs`. + - Right: close button `text-gray-400 hover:text-gray-600`, SVG X w-5 h-5. +- Content: `flex-1 overflow-hidden` — `