--- phase: 12 slug: cloud-resource-foundation status: draft shadcn_initialized: false preset: none created: 2026-06-18 --- # Phase 12 — UI Design Contract > Visual and interaction contract for Phase 12: cloud-resource-foundation. > Generated by gsd-ui-researcher, verified by gsd-ui-checker. --- ## Design System | Property | Value | |----------|-------| | Tool | none — manual Tailwind CSS | | Preset | not applicable | | Component library | none (Vue 3 custom components) | | Icon library | AppIcon.vue (Heroicons-based, internal wrapper) | | Font | system-ui / Inter (Tailwind default sans stack) | No `components.json` was found. The project uses manual Tailwind CSS v3 with `@tailwindcss/forms`. No shadcn initialization is needed or applicable. All new UI must match the existing `StorageBrowser.vue` component patterns. --- ## Spacing Scale Declared values (must be multiples of 4): | Token | Value | Usage | |-------|-------|-------| | xs | 4px | Icon gaps, inline badge padding (`gap-1`, `px-1`) | | sm | 8px | Compact element spacing, toolbar icon buttons (`p-2`, `gap-2`) | | md | 16px | Default element spacing, row padding (`px-4`) | | lg | 24px | Section padding, horizontal gutters (`px-6`) | | xl | 32px | Layout gaps | | 2xl | 48px | Major section breaks | | 3xl | 64px | Page-level spacing | Exceptions: - Touch target minimum: 36×36px (`min-w-[36px] min-h-[36px]`) for row action buttons on mobile — matches existing `StorageBrowser.vue` pattern. - Sync indicator: inline next to breadcrumb or toolbar, 20×20px icon (`w-5 h-5`), no extra surrounding padding. --- ## Typography | Role | Size | Weight | Line Height | |------|------|--------|-------------| | Body | 14px (`text-sm`) | 400 regular (`font-normal`) | 1.5 | | Label / metadata | 12px (`text-xs`) | 600 semibold (`font-semibold`) | 1.4 | | Row primary name | 14px (`text-sm`) | 600 semibold (`font-semibold`) | 1.5 | | Column header | 12px (`text-xs`) | 600 semibold, `uppercase tracking-wider` | 1.4 | Two weights only: `font-normal` (400) for body, `font-semibold` (600) for all labels, metadata, column headers, and row primary names. `font-medium` (500) is not used. Source: extracted from `StorageBrowser.vue` — do not deviate without updating this contract. --- ## Color | Role | Tailwind Token | Usage | |------|----------------|-------| | Dominant (60%) | `white` / `bg-white` | Page background, sticky toolbar, row base | | Secondary (30%) | `gray-50` / `gray-100` | List header row, alternating hover state, sidebar | | Accent (10%) | `indigo-500` / `indigo-600` | See reserved list below | | Warning | `amber-400` / `amber-500` | Folder icons, new-folder input border | | Destructive | `red-500` / `red-50` | Delete action hover, error text | **Accent (`indigo`) reserved exclusively for:** - Primary action buttons (e.g., "Connect account", "Browse") - Focus rings (`focus-visible:ring-indigo-500`) on all interactive elements - Active/selected navigation items - Inline text links and "Clear search" calls-to-action - Connection root icon in breadcrumb bar **Do NOT use indigo for:** - Disabled/unsupported action controls (use `gray-400` text on `gray-100` background) - Temporary-failure warning state (use `amber-600` text on `amber-50` background) - Metadata labels or column headers ### New semantic colors for Phase 12 | Semantic role | Tailwind token | Applied to | |---------------|----------------|------------| | Unsupported (permanent) | `text-gray-400 bg-gray-100` | Disabled action buttons for structurally unsupported operations | | Temporarily blocked | `text-amber-600 bg-amber-50 border-amber-200` | Disabled action buttons for recoverable failures (scope, auth, offline) | | Refreshing | `text-indigo-400` (animated) | Breadcrumb sync spinner | | Up to date | `text-green-500` | Breadcrumb sync indicator after successful refresh | | Connection warning | `text-amber-500` | Breadcrumb sync indicator on refresh failure | Source: D-09 from CONTEXT.md — grey = structurally unsupported; amber/warning = temporarily blocked. --- ## Component Inventory These components are extended or introduced in Phase 12. All must follow existing architecture rules: views are thin data providers; smart components receive props and emit actions. ### Extended: `StorageBrowser.vue` **New props (data-driven):** | Prop | Type | Description | |------|------|-------------| | `capabilities` | `Record` | Map of action name to `{ state: 'supported' \| 'unsupported' \| 'temporarily_unavailable', message: string, reasonCode: string }` | | `folderFreshness` | `'fresh' \| 'refreshing' \| 'warning'` | Current sync state of the displayed folder | | `lastRefreshedAt` | `string \| null` | ISO timestamp for tooltip on sync indicator | | `connectionRoot` | `{ id: string, displayName: string, providerType: string }` | Identity of the current connection root | | `byteAvailability` | `Record` | Per-item byte state keyed by DocuVault item UUID | **Existing `mode` prop behavior change:** replace `mode === 'local'` action-hiding with capability rendering. Local mode supplies a full-supported capability set; cloud mode supplies provider-normalized capabilities. One rendering path serves both. **New emitted events:** | Event | Payload | Description | |-------|---------|-------------| | `capability-explain` | `{ actionKey: string, message: string }` | User tapped/focused a disabled control on touch | ### Extended: `BreadcrumbBar.vue` Adds a sync state indicator immediately after the last breadcrumb segment: - Refreshing: `AppSpinner` sized 16px (`w-4 h-4`) in `text-indigo-400` - Up to date: checkmark icon 16px in `text-green-500`, fades out after 3 s - Connection warning: warning triangle icon 16px in `text-amber-500`, persists Tooltip on the indicator (desktop hover, touch tap): `"Last updated [relative time]"` or `"Refresh failed — retrying"`. The breadcrumb root segment shows the connection display name and a small provider/cloud icon (16px) before it. No separate `Cloud` prefix segment. ### New: Disabled action button pattern Unsupported and temporarily-blocked actions render as `