Files
waggle-os/docs/ux-refactor/deltas/design-system-delta.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

174 lines
16 KiB
Markdown

# Design System Delta — Waggle OS UX Refactor
**Scope:** PRD §19 (Design System Requirements) + Blueprint "Design System Direction"
mapped against the live Hive DS in `apps/web/src`.
**Execution model (locked):** in-place incremental refactor — reuse existing shadcn/Hive
primitives in `apps/web/src/components/ui/*`; build NEW DS components only where PRD §19.1
names a concept with no existing reusable primitive.
**Grounding sources (read):**
- Tokens: `apps/web/src/index.css` (canonical palette + light theme), `apps/web/src/waggle-theme.css` (aliases), `apps/web/tailwind.config.ts` (token→utility wiring).
- Primitive inventory: `apps/web/src/components/ui/*` (49 files).
- PRD §19.1/§19.2/§19.3 — `docs/.../Waggle_OS_UX_Refactor_PRD.md` lines 1222-1261.
- Blueprint "Design System Direction" — `_blueprint_extracted.txt` lines 479-492.
- Ad-hoc precedents: `MemoryApp.tsx` (provenance chip), `TimelineApp.tsx` (timeline), `OnboardingWizard.tsx` (ad-hoc steps), `ApprovalsApp.tsx` (approvals).
---
## (a) PRD §19.1 Component List — EXISTS vs BUILD-NEW
PRD §19.1 (lines 1226-1242) lists 19 core components. Blueprint adds a few named variants
(ContextCard, MemoryCard, ArtifactRow, AgentCard, SkillCard, ConnectorCard, MCPRow,
AutomationRunRow, EvidencePanel, ApprovalModal — `_blueprint_extracted.txt` lines 487-488).
Mapping below merges both lists.
| PRD §19.1 component | Status | Existing file / build location | Notes |
|---|---|---|---|
| **AppShell** | BUILD-NEW (composes EXISTS) | new `components/os/AppShell.tsx`; compose `ui/sidebar.tsx` + `ui/scroll-area.tsx` | No single AppShell today; current shell is `os/Desktop.tsx` (windowing). PRD §20.3 lists AppShell as Create. Reuse `ui/sidebar.tsx` for left nav. |
| **Primary navigation** | EXISTS (extend) | `ui/sidebar.tsx`, `ui/navigation-menu.tsx` | Full sidebar primitive present (collapsible, rail, groups). Re-label to Work/Intelligence/Extend/Team IA (PRD §3.2). |
| **Workspace switcher** | BUILD-NEW (compose EXISTS) | new; compose `ui/command.tsx` + `ui/dropdown-menu.tsx` | Pattern exists in `sidebar.tsx` docs; assemble against workspace list. |
| **Command Center modal** | EXISTS (primitive) → BUILD-NEW (Ctrl+K shell) | primitive `ui/command.tsx` (cmdk: CommandDialog/Input/Group/Item); new `CommandCenter.tsx` | `ui/command.tsx` is full cmdk wrapper. PRD §20.3 + Blueprint require a global Ctrl+K provider/overlay on top — build the provider, reuse the primitive. Existing `overlays/GlobalSearch.tsx` is a prior, narrower attempt to fold in. |
| **Card: workspace** (ContextCard/MemoryCard/AgentCard/SkillCard/ConnectorCard) | EXISTS (base) → BUILD-NEW (typed variants) | base `ui/card.tsx`; new per-object cards under `components/os/cards/` | `ui/card.tsx` is the generic shadcn card (Header/Title/Content/Footer). Build typed object cards on top (each renders StatusBadge + actions). `.direction-d-card` / `.waggle-card-lift` utilities (`waggle-theme.css`) give the hover/lift treatment. |
| **ArtifactRow / MCPRow / AutomationRunRow** (table rows) | EXISTS (base) | `ui/table.tsx` | Blueprint density rule (line 491): cards for Home/Workspace, **tables** for Memory/Artifacts/Agents/Automations. Use `ui/table.tsx`; build row cell formatters only. |
| **Status badges** | EXISTS (base) → BUILD-NEW (StatusBadge variant) | base `ui/badge.tsx`; new `components/os/StatusBadge.tsx` | `ui/badge.tsx` has only default/secondary/destructive/outline — **no semantic status variants** and no icon/dot. Build `StatusBadge` mapping the state enums (PRD §14: running/paused/failed/healthy/...) to the color semantics in (b), with a **non-color dot + text label** (a11y §19.3). |
| **Confidence badges** | **BUILD-NEW** | new `components/os/ConfidenceBadge.tsx` | No confidence component exists. `MemoryApp.tsx` has no confidence rendering today (grep: only `provenance`). Renders 0-100 (PRD §15.4) as tiered band (high/med/low) with numeric + label; band color from semantics in (b). |
| **Source / evidence chips** (EvidenceChip + EvidencePanel) | **BUILD-NEW** (chip has ad-hoc precedent) | new `components/os/EvidenceChip.tsx` + `components/os/EvidencePanel.tsx` | Closest precedent: the inline provenance pill in `MemoryApp.tsx` (lines ~202-208, `readFrameProvenanceTool`) — promote to a reusable `EvidenceChip`. `EvidencePanel` (Blueprint line 488) is the grouped detail (source + sourceUrl/path + snippet) inside DetailDrawer. |
| **Timeline** | **BUILD-NEW** (logic exists) | new `components/os/Timeline.tsx`; reuse `lib/timeline-events.ts` | `TimelineApp.tsx` + `lib/timeline-events.ts` (`iconForEvent`/`colorForEvent`/`describeEvent`) hold the rendering logic, but it is app-specific, not a reusable DS component. Extract the grouped-by-day list into `Timeline`. |
| **Activity feed** | **BUILD-NEW** | new `components/os/ActivityFeed.tsx` | No reusable feed today. Distinct from Timeline: feed = reverse-chron event stream for Workspace right-panel "last activity" (PRD §12.2) + Home overnight summary (§12.1). Can share the row renderer with Timeline. |
| **Detail drawer** (DetailDrawer) | EXISTS (two bases) → BUILD-NEW (typed wrapper) | bases `ui/sheet.tsx` (right-side, Radix Dialog) and `ui/drawer.tsx` (vaul, bottom); new `components/os/DetailDrawer.tsx` | **Recommend `ui/sheet.tsx` side="right"** as the base — matches Blueprint "optional right context rail" (line 483) and is the standard detail surface for Memory/Artifact/Agent. `ui/drawer.tsx` (vaul) is bottom-sheet, keep for mobile/secondary. Build one `DetailDrawer` wrapper that takes header + EvidencePanel + actions. |
| **Builder stepper** (BuilderStepper) | **BUILD-NEW** | new `components/ui/stepper.tsx` (or `components/os/BuilderStepper.tsx`) | **No Stepper primitive exists.** `OnboardingWizard.tsx` hand-rolls step state (`useState(state.step)` + `goToStep`) with no shared progress UI. PRD §19.2: "Create flows use stepper patterns" — needed by Skill/Agent/Automation builders (PRD §12.6/§12.9/§12.10) + Onboarding. Build once, retrofit onboarding. |
| **Approval prompt** (ApprovalModal) | EXISTS (base + app) → BUILD-NEW (typed modal) | base `ui/alert-dialog.tsx`; existing app `os/apps/ApprovalsApp.tsx` + `overlays/SpawnAgentDialog.tsx`; new `components/os/ApprovalModal.tsx` | `ui/alert-dialog.tsx` (Radix) is the confirm base; `ApprovalsApp.tsx` already implements an approvals inbox surface. Build a shared `ApprovalModal` (declares: actor, requested action, scope, risk badge, approve/deny/modify) for the permission-gated flows (PRD §12.3 command exec, §12.9 agent elevation, §17.3 elevated actions). |
| **Empty state** | **BUILD-NEW** | new `components/os/EmptyState.tsx` | No reusable empty-state component (grep found none). Required on every major screen (PRD §14.1, §22.2). Build icon + headline + body + primary CTA. |
| **Error state** | **BUILD-NEW** (base exists) | base `ui/alert.tsx`; new `components/os/ErrorState.tsx` | `ui/alert.tsx` (default/destructive) covers inline alerts; build a full-surface `ErrorState` (illustration + retry) for screen-level errors (PRD §14.1). |
| **Skeleton loader** | EXISTS | `ui/skeleton.tsx` | Present. Compose per-surface skeletons (card grid / table rows). |
| **Table/list/grid view toggle** | **BUILD-NEW** (base exists) | base `ui/toggle-group.tsx`; new `components/os/ViewToggle.tsx` | `ui/toggle-group.tsx` (Radix, single/multiple) is the base. No `ViewToggle` exists. Build a 3-state (table/list/grid) toggle for Memory/Artifact/Agent surfaces (PRD §19.1 last item, Blueprint density rule). |
### Supporting primitives confirmed present (reuse, do not rebuild)
`ui/tabs.tsx` (workspace tabs PRD §12.2), `ui/dialog.tsx`, `ui/popover.tsx`, `ui/tooltip.tsx` + `ui/hint-tooltip.tsx`, `ui/progress.tsx`, `ui/avatar.tsx` (team avatar stack), `ui/select.tsx`/`ui/checkbox.tsx`/`ui/radio-group.tsx`/`ui/switch.tsx`/`ui/slider.tsx` (builder form fields), `ui/form.tsx` (+ react-hook-form), `ui/chart.tsx` (dashboards/Home metrics), `ui/resizable.tsx` (workspace panels), `ui/scroll-area.tsx`, `ui/separator.tsx`, `ui/breadcrumb.tsx`, `ui/sonner.tsx`/`ui/toast.tsx`/`ui/toaster.tsx` (notifications), `ui/dropdown-menu.tsx`/`ui/context-menu.tsx`, `ui/collapsible.tsx`/`ui/accordion.tsx`.
### Summary counts
- **EXISTS (reuse as-is):** Primary nav (sidebar), Skeleton, Tabs, plus the full supporting-primitive set above.
- **EXISTS-as-base → BUILD typed wrapper:** Command Center, object Cards, Status badge, Detail drawer, Approval modal, Error state, View toggle (7).
- **BUILD-NEW (no reusable base):** ConfidenceBadge, EvidenceChip, EvidencePanel, BuilderStepper, ActivityFeed, Timeline (DS extraction), EmptyState, AppShell, ViewToggle base-toggle exists but component new (≈8 net-new components).
---
## (b) Color Semantics → Hive DS Token Mapping
PRD/Blueprint semantic palette (Blueprint lines 485-486): **blue = command/work, purple =
intelligence, green = healthy/complete, orange = attention/automation, red = risk/failure.**
The Hive DS already ships these as CSS vars in `index.css` and exposes them as Tailwind
utilities via `tailwind.config.ts` (`status.*`, `honey.*`, `hive.*`). **No new base tokens
are required** — only a semantic-alias layer so components reference intent, not raw color.
| UX semantic | Meaning | Existing Hive token (dark, `index.css`) | Tailwind utility | Light-theme value (`index.css` `[data-theme="light"]`) |
|---|---|---|---|---|
| **Blue = command / work** | running, info, in-progress, command surfaces | `--status-info: #60a5fa` | `text-status-info` / `bg-status-info` | `#1d4ed8` (AA on cream, ratio 6.30) |
| **Purple = intelligence** | agents, AI/skills, memory-AI | `--status-ai: #a78bfa` (= DS accent `--accent: 270 60% 68%`) | `text-status-ai` / `bg-status-ai`; `accent` for AI brand | `#6d28d9` (ratio 6.68) |
| **Green = healthy / complete** | success, connected, completed, high confidence | `--status-healthy: #34d399` | `text-status-healthy` / `bg-status-healthy` | `#047857` (ratio 5.16) |
| **Orange = attention / automation** | warning, attention-required, automation, **medium confidence** | `--status-warning: #fbbf24` (NOT honey-brand) | `text-status-warning` / `bg-status-warning` | `#b45309` (ratio 4.72) |
| **Red = risk / failure** | error, failed, high-risk, revoked, **low confidence** | `--status-error: #f87171` (= shadcn `--destructive: 0 72% 63%`) | `text-status-error` / `bg-status-error` / `destructive` | `#b91c1c` (ratio 6.09) |
**Critical disambiguation — orange ≠ brand honey.** The Hive **brand/primary is honey gold**
(`--primary: 40 100% 45%``--honey-500: #e5a000`), used for primary CTAs, focus rings,
selection, and brand accents (`--ring`, `.glow-primary`, `--shadow-honey`). The UX "orange =
attention/automation" semantic must map to **`--status-warning` (#fbbf24)**, a distinct amber,
NOT to honey/primary. Keep "attention" and "brand action" visually separable:
- Brand / primary action → `bg-primary` / `honey-*`.
- Attention / automation status → `bg-status-warning` / `text-status-warning`.
**Confidence band mapping (ConfidenceBadge, PRD §15.4 `confidence: 0-100`):**
- high (≥ ~70) → green `status-healthy`
- medium (~40-69) → orange `status-warning`
- low (< ~40) → red `status-error`
(Thresholds are DS defaults; finalize against the memory scoring scale in `packages/hive-mind-core/src/mind/scoring`.)
**Implementation note — add a semantic alias layer.** Today components would have to reach
for `status-info`/`status-ai` directly. Add intent aliases in `waggle-theme.css` (`:root`
already holds `--success/--warning/--error` at lines 44-46) so the new layer reads:
```
--sem-work: var(--status-info); /* blue */
--sem-intelligence:var(--status-ai); /* purple */
--sem-healthy: var(--status-healthy); /* green */
--sem-attention: var(--status-warning);/* orange */
--sem-risk: var(--status-error); /* red */
```
`StatusBadge`/`ConfidenceBadge`/cards reference `--sem-*` so the mapping lives in one place
and inherits both dark and light themes automatically.
---
## (c) Dark-default + Light-variant Note
- **Dark is the default** (Blueprint line 484: "Dark default for desktop agent feel").
`index.css :root` IS the dark theme (background `222 20% 4%`); no `data-theme` attr needed.
- **Light variant exists and is complete** — `:root[data-theme="light"]` (index.css lines
140-221) overrides background, hive scale (inverted), honey (contrast-adjusted), **and all
`--status-*` + `--kg-*` tokens darkened for WCAG AA on the cream surface** (ratios documented
in source: healthy 5.16, warning 4.72, error 6.09, info 6.30, ai 6.68). Light mode is
explicitly intended for "data-heavy Memory/Artifact tables" (Blueprint line 484).
- **Consequence for new components:** because the semantic mapping in (b) references
`--status-*` (which the light block already overrides), every new component
(StatusBadge, ConfidenceBadge, EvidenceChip, etc.) inherits AA-correct light colors **for
free** as long as it uses tokens — never hardcode hex. This matches the CLAUDE.md §10
closed item "CR-2 hive-950 → semantic tokens" (do not reintroduce raw `hive-950` refs).
- **Theme switch mechanism:** toggling `data-theme="light"` on `:root` (the desktop wallpaper
overlay + honeycomb-bg already branch on it, index.css lines 269/277). New surfaces must not
assume a fixed background.
---
## (d) Accessibility Requirements (PRD §19.3 + Blueprint line 489-490)
PRD §19.3 (lines 1254-1261) + Blueprint "Keyboard-first... no color-only status, text labels
for all badges." Per-component obligations for the new/extended DS components:
1. **Full keyboard support.** Ctrl+K (`CommandCenter`) opens from anywhere via global key
handler; builders, drawers, modals are fully tab-navigable. cmdk (`ui/command.tsx`) and
Radix bases (`alert-dialog`, `sheet`, `dialog`, `toggle-group`) provide focus trap +
arrow-key nav out of the box — preserve, don't override.
2. **Visible focus states.** Use the DS focus ring (`--shadow-focus` / `--ring` = honey).
shadcn primitives already render `focus:ring-2 focus:ring-ring`; new wrappers must keep it.
3. **ARIA labels for command palette + builders.** `CommandCenter` needs `role`/`aria-label`
on the dialog + labelled groups; `BuilderStepper` needs `aria-current="step"` on the active
step and accessible step names (extend from `OnboardingWizard.tsx` `STEP_NAMES`).
4. **Sufficient contrast for dark theme.** Dark `--status-*` are bright on `#08-11` surfaces;
light variants are pre-darkened to ≥4.5:1 (documented in index.css). Do not place
`status-warning`/`status-info` as small text on light surfaces without the light token.
5. **Non-color status indicators (CRITICAL).** `StatusBadge` and `ConfidenceBadge` MUST pair
color with a **text label AND/OR a shape/icon** (dot, icon glyph). PRD §19.3 + Blueprint
"no color-only status" + "text labels for all badges." This is the single biggest gap vs
the current `ui/badge.tsx` (color-only). Confidence must show the number/label, not just a
colored band.
6. **Screen-reader-friendly tables/lists.** Memory/Artifact/Agent/Automation tables
(`ui/table.tsx`) need proper `<th scope>`, caption, and row `aria-label`; `ViewToggle`
needs labelled options ("table view"/"grid view"). `Timeline`/`ActivityFeed` use an ordered
list semantic with per-item timestamps in accessible text.
7. **Approval flows announce intent.** `ApprovalModal` must expose the requested action, scope,
and risk level as text (not icon-only) so denial/approval is an informed, SR-readable
decision (ties to PRD §17.3 elevated-action approval).
---
## Net build list (for the impl plan)
**New DS components to author** (under `components/ui/` for generic, `components/os/` for product-typed):
1. `StatusBadge` (extend `badge.tsx` with semantic variants + non-color indicator)
2. `ConfidenceBadge`
3. `EvidenceChip` (promote from `MemoryApp.tsx` provenance pill)
4. `EvidencePanel`
5. `BuilderStepper` / `stepper.tsx`
6. `DetailDrawer` (wrap `sheet.tsx` right-side)
7. `ApprovalModal` (wrap `alert-dialog.tsx`)
8. `ActivityFeed`
9. `Timeline` (extract from `TimelineApp.tsx` + `lib/timeline-events.ts`)
10. `EmptyState`
11. `ErrorState` (wrap `alert.tsx`)
12. `ViewToggle` (wrap `toggle-group.tsx`)
13. `AppShell` + `WorkspaceSwitcher` + `CommandCenter` (compose existing sidebar/command primitives)
14. Object cards: `WorkspaceCard`/`MemoryCard`/`ArtifactRow`/`AgentCard`/`SkillCard`/`ConnectorCard`/`MCPRow`/`AutomationRunRow`
**Token work:** add `--sem-*` alias layer in `waggle-theme.css` (no new base palette tokens).
All bases for the above already exist in `ui/*`; nothing requires a new dependency.