---
phase: 41
slug: diagrams-icons-theme-engine
status: draft
shadcn_initialized: true
preset: new-york / neutral / cssVariables / lucide
created: 2026-04-04
---

# Phase 41 — UI Design Contract

> Visual and interaction contract for Phase 41: Diagrams, Icons & Theme Engine.
> Generated by gsd-ui-researcher. Verified by gsd-ui-checker.

---

## Design System

| Property | Value | Source |
|----------|-------|--------|
| Tool | shadcn | components.json detected |
| Style | new-york | components.json |
| Preset | neutral base color, cssVariables, radius=0 | ui/src/index.css |
| Component library | Radix UI (via shadcn) | components.json |
| Icon library | lucide-react | components.json |
| Font | System UI (inherited from body; no custom font loaded) | index.css |

**Existing components available (no reinstall needed):**
`button`, `badge`, `breadcrumb`, `card`, `checkbox`, `collapsible`, `command`, `dialog`, `dropdown-menu`, `input`, `label`, `popover`, `scroll-area`, `select`, `separator`, `sheet`, `skeleton`, `tabs`, `textarea`, `tooltip`

**New shadcn components needed for Phase 41:**
- `progress` — job progress bar (SSE render progress)
- `toggle` — dark/light variant switcher in theme preview
- `slider` — color seed hue picker (optional; Input[type=color] is acceptable fallback)

---

## Spacing Scale

Declared values (multiples of 4). Source: existing Tailwind scale in project.

| Token | Value | Usage |
|-------|-------|-------|
| xs | 4px | Icon gaps, badge padding, inline chip gaps |
| sm | 8px | Compact element spacing, button icon gap |
| md | 16px | Default card padding, form field spacing |
| lg | 24px | Section padding, panel gaps |
| xl | 32px | Layout column gaps, page section breaks |
| 2xl | 48px | Major section breaks (e.g. diagram panel → source panel) |
| 3xl | 64px | Not used in Phase 41 |

**Exceptions (Phase 41 specific):**
- Touch targets on coarse-pointer devices: `min-height: 44px` on all interactive controls (already enforced by `@media (pointer: coarse)` rule in index.css — no new work needed).
- Diagram preview container: no fixed height. Use `overflow-x: auto` with `width: max-content; min-width: 100%` (matches `.paperclip-mermaid svg` pattern already in index.css).
- Theme swatch grid: 8px gap between swatches, swatches 40×40px minimum.
- Color seed input: 48px height to meet touch targets on mobile.

---

## Typography

Source: index.css `.paperclip-markdown`, button.tsx, existing component patterns.

| Role | Size | Weight | Line Height | Usage |
|------|------|--------|-------------|-------|
| Body | 15px (0.9375rem) | 400 (regular) | 1.6 | Diagram source editor, theme description text |
| Label | 14px (0.875rem) | 400 (regular) | 1.5 | Form labels, badge text, panel section titles |
| Heading | 20px (1.25rem) | 600 (semibold) | 1.3 | Panel titles ("Generate Diagram", "Theme Preview") |
| Display | 28px (1.75rem) | 600 (semibold) | 1.2 | Not used in Phase 41 |

**Declared weights: 2 — 400 (regular) and 600 (semibold).**
- 400 (regular): body text, labels, badge text, monospace code blocks.
- 600 (semibold): panel headings, dialog headings, section titles.

**Monospace (code/source):** `ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace` at 14px, weight 400, line-height 1.6. Used for the Mermaid source collapsible panel and palette export code blocks.

---

## Color

Source: index.css CSS custom properties — Catppuccin Latte (light) + Catppuccin Mocha (dark).

| Role | Light value | Dark value | Usage |
|------|-------------|------------|-------|
| Dominant (60%) | `#eff1f5` (--background) | `#1e1e2e` (--background) | Page background, diagram canvas background |
| Secondary (30%) | `#e6e9ef` (--card) | `#181825` (--card) | Diagram panel card, theme preview panel, icon result card |
| Muted surface | `#ccd0da` (--secondary) | `#313244` (--secondary) | Source code panel background, export format tabs, collapsible header |
| Accent (10%) | `#bcc0cc` (--accent) | `#45475a` (--accent) | Hover states on non-primary interactive elements |
| Primary | `#1e66f5` (--primary) | `#89b4fa` (--primary) | See "Accent reserved for" below |
| Destructive | `#d20f39` (--destructive) | `#f38ba8` (--destructive) | Destructive actions only |
| Border | `#ccd0da` (--border) | `#313244` (--border) | Panel edges, dividers, input outlines |
| Muted foreground | `#9ca0b0` (--muted-foreground) | `#6c7086` (--muted-foreground) | Helper text, secondary labels, status text |

**Accent (--primary) reserved for:**
1. "Generate" / "Apply Theme" primary CTA buttons
2. Job progress bar fill
3. Active tab indicator in export format tabs
4. Seed color ring/focus ring on color input
5. WCAG PASS badges (green: use `--chart-2 #40a02b` light / `#a6e3a1` dark)
6. WCAG FAIL badges (red: use `--destructive`)

**Theme Preview special case:** The theme preview panel injects CSS custom properties dynamically from the generated palette. It must not inherit `--primary` from the app shell. Scope theme preview under a `.nexus-theme-preview` container class so injected tokens do not leak into nav/sidebar.

---

## Component Inventory (Phase 41)

### Diagram Panel

- **DiagramGeneratePanel** — Full-width card. Contains: prompt textarea (4 rows), diagram type selector (Select component, options: Architecture, Flowchart, ERD, Sequence, Mind Map), "Generate Diagram" Button (primary).
- **DiagramPreview** — Renders SVG output inside `.paperclip-mermaid` container (reuse existing CSS class). Shows status line ("Rendering…" / error) using `.paperclip-mermaid-status` / `.paperclip-mermaid-status-error` classes. Download buttons (SVG, PNG) appear below the preview as ghost buttons.
- **DiagramSourcePanel** — Collapsible (shadcn `collapsible`). Shows Mermaid source in monospace Textarea (read/write). "Copy source" IconButton at top-right. IconButton must carry `aria-label="Copy source"` and `title="Copy source"`.
- **DiagramAttachToChatBadge** — After successful render, a badge appears in the conversation thread: "Diagram attached — SVG + PNG". Reuse ChatTaskCreatedBadge visual pattern.

### Icon Generation Panel

- **IconGeneratePanel** — Card with: description textarea (3 rows), style selector (Select, options: Outline, Filled, Rounded), count selector (Select: 1, 4, 8, 16), "Generate Icons" Button (primary).
- **IconResultGrid** — CSS grid, 4 columns on desktop / 2 on mobile. Each cell: white card, SVG preview centered, icon name label below (text-xs). Hover reveals download row (SVG, PNG 16, PNG 32, PNG 64) as a bottom sheet within the card.
- **IconDownloadBar** — Appears below grid when any icon is selected (checkbox on card corner). "Download selected (N)" Button (primary), format selector (Select: SVG, PNG 16, PNG 32, PNG 64).

### Theme Engine Panel

- **ThemeSeedInput** — Color picker (`<input type="color">` styled with ring) + hex text Input side-by-side. Label: "Seed color". Helper text: "We'll generate a full palette in OKLCH."
- **ThemeVariantToggle** — Toggle group (light / dark), uses shadcn `Toggle`. Default: dark.
- **ThemePaletteGrid** — Displays generated swatches. Two rows: Light variant, Dark variant. Columns: Background, Surface, Overlay, Text, Accent-1, Accent-2, Accent-3. Each swatch: 40×40px minimum, hex label below (text-xs, monospace), WCAG badge (AA PASS / FAIL) inline.
- **ThemePreviewPanel** — Scoped under `.nexus-theme-preview`. Renders a mini mock of Nexus UI (sidebar strip + one card) with injected CSS variables. "Apply to Nexus" Button (primary, full-width at panel bottom).
- **ThemeExportTabs** — Tabs component. Tabs: CSS Variables, Tailwind Config, VS Code Theme, JSON. Each tab: pre/code block (monospace 14px), "Copy export" IconButton top-right. IconButton must carry `aria-label="Copy {tab name}"` (e.g. `aria-label="Copy CSS Variables"`) and a matching `title` attribute.
- **ThemeApplyConfirmDialog** — Dialog. Heading: "Apply theme?". Body: "This will update your Nexus color scheme. You can revert from Settings." Confirm: "Apply theme" (primary). Cancel: "Keep current" (ghost).

---

## Interaction Contracts

### Job Progress (shared pattern across all three generators)

1. User submits prompt → Button shows spinner + label "Generating…" (disabled). Primary CTA label changes in-place; no separate loading overlay.
2. SSE events arrive → Progress bar (shadcn `progress`, primary fill) animates from 0→100%. Progress bar sits directly below the CTA button, full-width of the panel.
3. On `ready`: progress bar disappears (fade out 200ms), result panel slides down (height animation 300ms ease-out). Button reverts to "Generate again" (secondary variant).
4. On `error`: progress bar fills destructive color, error message appears below bar ("Render failed — {detail}. Try again."), Button reverts to "Generate Diagram" (primary, enabled).
5. Reconnect on SSE disconnect: silent reconnect, no user-facing error unless render ultimately fails.

### Mermaid Source Collapsible

- Default state: collapsed.
- Trigger label: "View Mermaid source" (chevron right). Expanded: "Hide source" (chevron down).
- Height transition: 250ms ease.
- Textarea is editable. "Re-render diagram" Button (secondary, xs size) appears at bottom-right of expanded panel when source is modified.
- Security stripping is server-side. No client-side feedback needed beyond standard error state.

### Theme Live Preview

- Preview updates on every palette recalculation (debounced 150ms after seed color change).
- No full-page refresh. CSS variables injected via JS into `.nexus-theme-preview` scope only.
- "Apply to Nexus" triggers ThemeApplyConfirmDialog before writing to settings.
- After apply: toast notification "Theme applied. Reload to see full effect." (not destructive; use default toast variant).

### Icon Selection

- Checkbox appears on card hover (top-left corner, 16px). On coarse pointer: always visible.
- Multi-select: selecting any card shows the DiagramDownloadBar at the bottom of the panel (sticky, z-index above scroll content).
- Deselect all: "Clear selection" link in the sticky bar.

---

## Copywriting Contract

| Element | Copy |
|---------|------|
| Diagram CTA | "Generate Diagram" |
| Diagram generating state | "Generating…" |
| Diagram re-render CTA | "Re-render diagram" |
| Diagram download (SVG) | "Download SVG" |
| Diagram download (PNG) | "Download PNG" |
| Diagram source toggle (collapsed) | "View Mermaid source" |
| Diagram source toggle (expanded) | "Hide source" |
| Diagram attach confirmation | "Diagram attached — SVG + PNG" |
| Icon CTA | "Generate Icons" |
| Icon generating state | "Generating…" |
| Icon download (selected) | "Download selected ({N})" |
| Icon empty state heading | "No icons yet" |
| Icon empty state body | "Describe what you need and we'll generate a cohesive set." |
| Theme CTA | "Generate Palette" |
| Theme generating state | "Generating…" |
| Theme apply CTA | "Apply to Nexus" |
| Theme apply dialog heading | "Apply theme?" |
| Theme apply dialog body | "This will update your Nexus color scheme. You can revert from Settings." |
| Theme apply confirm | "Apply theme" |
| Theme apply cancel | "Keep current" |
| Theme applied toast | "Theme applied. Reload to see full effect." |
| WCAG pass badge | "AA" |
| WCAG fail badge | "Fails AA" |
| Export copy button (visible label) | "Copy {tab name}" (e.g. "Copy CSS Variables") |
| Export copy button (aria-label) | `aria-label="Copy {tab name}"` matching visible label |
| Export copied state | "Copied!" (reverts after 2s) |
| Diagram source copy button (aria-label) | `aria-label="Copy source"` |
| Generic render error | "Render failed — {detail}. Try again." |
| Mermaid security strip notice | "Unsafe directives were removed before rendering." (shown as muted helper text below diagram, only when stripping occurred) |
| Empty diagram state heading | "No diagram yet" |
| Empty diagram state body | "Describe an architecture, flow, or sequence and we'll render it." |
| Empty theme state heading | "No palette yet" |
| Empty theme state body | "Pick a seed color to generate a full OKLCH palette with dark and light variants." |

**Destructive actions in Phase 41:** None. "Apply theme" is reversible (can revert from Settings). Confirm dialog is informational, not destructive-red.

---

## Registry Safety

| Registry | Blocks Used | Safety Gate |
|----------|-------------|-------------|
| shadcn official | `progress`, `toggle`, `slider` (optional) | not required |

No third-party registries declared for Phase 41.

---

## Accessibility

- All color swatches must render WCAG AA badge computed at runtime — not decorative.
- Diagram SVG output passes DOMPurify before DOM insertion (server responsibility; client renders trusted output only).
- Color seed `<input type="color">` must have an associated `<label>` with `for` binding.
- Icon grid checkboxes must have `aria-label="Select {icon name}"`.
- Progress bar must use `role="progressbar"` with `aria-valuenow`, `aria-valuemin=0`, `aria-valuemax=100`.
- Theme preview panel: `aria-label="Theme preview"` on the container, `aria-live="polite"` for palette update announcements.
- DiagramSourcePanel "Copy source" IconButton: `aria-label="Copy source"` and `title="Copy source"` required (no visible text label on the icon-only button).
- ThemeExportTabs copy IconButton per tab: `aria-label="Copy {tab name}"` and `title="Copy {tab name}"` required (e.g. `aria-label="Copy CSS Variables"`).
- Keyboard: Tab order in ThemeExportTabs follows tab order; Copy button reachable via keyboard.
- `prefers-reduced-motion`: disable height/slide animations for collapsible and result panel; keep progress bar (functional feedback).

---

## Checker Sign-Off

- [ ] Dimension 1 Copywriting: PASS
- [ ] Dimension 2 Visuals: PASS
- [ ] Dimension 3 Color: PASS
- [ ] Dimension 4 Typography: PASS
- [ ] Dimension 5 Spacing: PASS
- [ ] Dimension 6 Registry Safety: PASS

**Approval:** pending
