nexus/.planning/phases/41-diagrams-icons-theme-engine/41-05-SUMMARY.md

179 lines
11 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.

---
phase: 41-diagrams-icons-theme-engine
plan: "05"
subsystem: ui
tags: [theme-engine, oklch, wcag, shadcn, react-testing-library, jsdom, tdd]
# Dependency graph
requires:
- phase: 41-01
provides: useContentJob hook, contentJobs API, progress.tsx, toggle.tsx shadcn components
- phase: 41-03
provides: theme-renderer, PaletteRole type, ThemePaletteBundle, nexus-settings customTheme
provides:
- ui/src/components/ThemeSeedInput.tsx — color picker + hex input, debounced onChange
- ui/src/components/ThemePaletteGrid.tsx — swatch grid with WCAG AA/Fails AA badges, empty state
- ui/src/components/ThemePreviewPanel.tsx — scoped CSS injection via ref (NOT document.documentElement)
- ui/src/components/ThemePreviewPanel.test.tsx — 7 tests for THEME-04 scoped injection
- ui/src/components/ThemeExportTabs.tsx — CSS/Tailwind/VS Code/JSON tabs with copy buttons
- ui/src/components/ThemeApplyConfirmDialog.tsx — Apply theme / Keep current confirmation dialog
- ui/src/context/ThemeContext.tsx — extended with custom theme type and applyCustomTheme()
- ui/src/pages/ContentStudio.tsx — Themes tab fully wired
- ui/src/api/contentJobs.ts — submitContentJob, getContentJob, getContentJobAsset
- ui/src/hooks/useContentJob.ts — SSE EventSource progress hook
affects: [theme-apply-flow, nexus-settings]
# Tech tracking
tech-stack:
added:
- "@testing-library/react@^16.3.2 (UI devDep)"
- "@testing-library/jest-dom@^6.9.1 (UI devDep)"
- "jsdom@^28.1.0 (UI devDep)"
- "@vitejs/plugin-react added to ui/vitest.config.ts for JSX transform"
patterns:
- "ThemePreviewPanel pattern: useRef + useEffect + container.style.setProperty() — CSS vars scoped to .nexus-theme-preview, NEVER on document.documentElement"
- "applyCustomTheme pattern: sets CSS vars on document.documentElement only on explicit user apply action"
- "TDD in jsdom environment: // @vitest-environment jsdom override in individual test files"
- "useContentJob hook: companyId parameter, SSE EventSource progress tracking, fetchAsset helper"
key-files:
created:
- ui/src/components/ThemeSeedInput.tsx
- ui/src/components/ThemePaletteGrid.tsx
- ui/src/components/ThemePreviewPanel.tsx
- ui/src/components/ThemePreviewPanel.test.tsx
- ui/src/components/ThemeExportTabs.tsx
- ui/src/components/ThemeApplyConfirmDialog.tsx
- ui/src/pages/ContentStudio.tsx
- ui/src/api/contentJobs.ts
- ui/src/hooks/useContentJob.ts
- ui/src/components/ui/progress.tsx
- ui/src/components/ui/toggle.tsx
modified:
- ui/src/context/ThemeContext.tsx (extended Theme type, added applyCustomTheme, on-mount customTheme restore)
- ui/vitest.config.ts (added @vitejs/plugin-react for JSX transform in tests)
- ui/package.json (added @testing-library/react, jest-dom, jsdom as devDeps)
- pnpm-lock.yaml
key-decisions:
- "Used @testing-library/react + jsdom for ThemePreviewPanel tests instead of project's renderToStaticMarkup pattern — required because tests need to verify imperative DOM style.setProperty calls, which only work in a real DOM environment"
- "ThemeContext extended from light/dark to light/dark/custom — custom treated as dark-mode for toggle/classList purposes"
- "applyCustomTheme() sets CSS vars on document.documentElement (global apply) while ThemePreviewPanel sets on scoped container ref (preview only) — two distinct patterns for two distinct purposes"
- "contentJobs.ts and useContentJob.ts created as prerequisites in this worktree — these files from Plan 41-01 are not available in this git worktree"
- "On-mount customTheme restore: ThemeProvider fetches /api/nexus/settings on mount if stored theme is 'custom' to rehydrate CSS vars across page loads"
# Metrics
duration: 17min
completed: 2026-04-04
---
# Phase 41 Plan 05: Theme UI Components Summary
**All theme UI components built and wired: seed input, palette grid with WCAG badges, scoped live preview (with TDD test coverage for THEME-04), 4-format export tabs, apply confirmation dialog, ThemeContext custom theme extension, ContentStudio Themes tab fully functional**
## Performance
- **Duration:** ~17 min
- **Started:** 2026-04-04T20:49:03Z
- **Completed:** 2026-04-04T21:06:26Z
- **Tasks:** 2
- **Files modified:** 14
## Accomplishments
- `ThemeSeedInput`: `<input type="color">` + hex text Input side-by-side with `htmlFor="seed-color"` label, debounced onChange (150ms), helper text "We'll generate a full palette in OKLCH."
- `ThemePaletteGrid`: Dark and light swatch rows, 40×40px swatches, hex labels, WCAG AA / Fails AA badges using `--chart-2` green and `--destructive` red. Empty state with exact copywriting from UI-SPEC.
- `ThemePreviewPanel`: `.nexus-theme-preview` container with `useRef`, CSS vars injected imperatively via `container.style.setProperty()` only on the scoped element (never `document.documentElement`). Mini Nexus UI mock (sidebar + card + button). `aria-live="polite"` announces "Palette updated" on palette changes.
- `ThemePreviewPanel.test.tsx`: 7 TDD tests (jsdom environment) verifying class, aria-label, aria-live, dark/light CSS var values, and document scope isolation — all passing.
- `ThemeExportTabs`: CSS Variables / Tailwind Config / VS Code Theme / JSON tabs with pre/code blocks. Copy button per tab with `aria-label="Copy {tab name}"`, "Copied!" feedback (2s), keyboard accessible.
- `ThemeApplyConfirmDialog`: Dialog with "Apply theme?" heading, "This will update your Nexus color scheme. You can revert from Settings." body, "Apply theme" primary button, "Keep current" ghost button.
- `ThemeContext` extended: `Theme` type = `"light" | "dark" | "custom"`. `applyCustomTheme(palette, variant)` sets CSS vars on `document.documentElement`, updates state to "custom", stores to localStorage. On-mount: if stored theme is "custom", fetches `/api/nexus/settings` to restore `customTheme.palette` vars.
- `ContentStudio` page: Themes tab with full generate/preview/export/apply flow using `useContentJob` SSE hook.
- `contentJobs.ts` and `useContentJob.ts` created as prerequisites (not present in this worktree from Plan 41-01).
- `progress.tsx` and `toggle.tsx` shadcn components added.
## Task Commits
1. **TDD RED — failing ThemePreviewPanel tests + infrastructure** - `78e50189` (test)
2. **Task 1 + Task 2: All components + ThemeContext + ContentStudio** - `05ce37df` (feat)
## Files Created/Modified
- `ui/src/components/ThemeSeedInput.tsx` — Color picker + hex input, debounced onChange
- `ui/src/components/ThemePaletteGrid.tsx` — Swatch grid with WCAG badges
- `ui/src/components/ThemePreviewPanel.tsx` — Scoped CSS injection preview panel
- `ui/src/components/ThemePreviewPanel.test.tsx` — 7 TDD tests for THEME-04
- `ui/src/components/ThemeExportTabs.tsx` — 4-format export tabs with copy
- `ui/src/components/ThemeApplyConfirmDialog.tsx` — Confirm dialog
- `ui/src/context/ThemeContext.tsx` — Extended with custom theme type + applyCustomTheme
- `ui/src/pages/ContentStudio.tsx` — Themes tab fully wired
- `ui/src/api/contentJobs.ts` — Content job API helpers
- `ui/src/hooks/useContentJob.ts` — SSE progress hook
- `ui/src/components/ui/progress.tsx` — shadcn Progress component
- `ui/src/components/ui/toggle.tsx` — shadcn Toggle component
- `ui/vitest.config.ts` — Added @vitejs/plugin-react for JSX transform
- `ui/package.json` — Added testing devDeps
- `pnpm-lock.yaml` — Updated lockfile
## Decisions Made
- `@testing-library/react` and `jsdom` installed as devDeps — the project's `renderToStaticMarkup` pattern cannot test imperative DOM calls (`style.setProperty`); THEME-04 specifically requires verifying that CSS variables are set on the scoped container, not on `document.documentElement`. jsdom environment is required.
- ThemeContext `Theme` type extended to include `"custom"` — "custom" is treated as dark for `classList.toggle("dark")` purposes so the app shell continues to use dark color scheme when a custom palette is active.
- Two CSS injection patterns established: `ThemePreviewPanel` → scoped container ref (live preview only); `applyCustomTheme()``document.documentElement` (global apply on user confirmation).
- `contentJobs.ts`, `useContentJob.ts`, `progress.tsx`, `toggle.tsx` created in this plan — these were supposed to come from Plan 41-01 but that plan's work exists only on the parallel branch, not in this worktree.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 3 - Blocking] Added @testing-library/react + jsdom for TDD requirement**
- **Found during:** TDD RED phase
- **Issue:** The plan requires testing `style.setProperty` DOM calls on a scoped container element. The project's existing test pattern uses `// @vitest-environment node` with `renderToStaticMarkup` (server-side rendering), which cannot test imperative DOM manipulation. No `@testing-library/react` or jsdom was installed.
- **Fix:** Added `@testing-library/react@^16.3.2`, `@testing-library/jest-dom@^6.9.1`, and `jsdom@^28.1.0` as UI devDeps. Updated `ui/vitest.config.ts` to include `@vitejs/plugin-react` for JSX transform support. Individual test files use `// @vitest-environment jsdom` override to avoid affecting existing node-env tests.
- **Files modified:** ui/package.json, ui/vitest.config.ts, pnpm-lock.yaml
- **Verification:** All 7 ThemePreviewPanel tests pass
**2. [Rule 3 - Blocking] Created contentJobs.ts, useContentJob.ts, progress.tsx, toggle.tsx as prerequisites**
- **Found during:** Task 1 (ContentStudio wiring)
- **Issue:** These files from Plan 41-01 are not present in this worktree (parallel branch divergence, same issue documented in 41-03 SUMMARY)
- **Fix:** Created all four files from scratch matching the interfaces documented in Plan 41-01 SUMMARY
- **Files modified:** ui/src/api/contentJobs.ts, ui/src/hooks/useContentJob.ts, ui/src/components/ui/progress.tsx, ui/src/components/ui/toggle.tsx
**3. [Rule 1 - Bug] Removed @testing-library/jest-dom top-level import from test file**
- **Found during:** TDD RED phase
- **Issue:** `import "@testing-library/jest-dom"` calls `expect.extend()` globally before vitest's expect is initialized, causing `ReferenceError: expect is not defined`
- **Fix:** Removed the import; tests use vitest's built-in assertions which cover all required test cases without jest-dom matchers
---
**Total deviations:** 3 auto-fixed (Rules 1, 3, 3)
**Impact on plan:** All plan goals met. Testing infrastructure added as required for THEME-04 verification. No plan scope expanded.
## Known Stubs
None — all components are fully implemented. ThemePreviewPanel renders a real mini Nexus UI mock with CSS variables applied from the palette. ContentStudio is wired to the real content job API.
## Self-Check: PASSED
- FOUND: ui/src/components/ThemeSeedInput.tsx
- FOUND: ui/src/components/ThemePaletteGrid.tsx
- FOUND: ui/src/components/ThemePreviewPanel.tsx
- FOUND: ui/src/components/ThemePreviewPanel.test.tsx
- FOUND: ui/src/components/ThemeExportTabs.tsx
- FOUND: ui/src/components/ThemeApplyConfirmDialog.tsx
- FOUND: ui/src/context/ThemeContext.tsx (extended)
- FOUND: ui/src/pages/ContentStudio.tsx
- FOUND: ui/src/api/contentJobs.ts
- FOUND: ui/src/hooks/useContentJob.ts
- FOUND: ui/src/components/ui/progress.tsx
- FOUND: ui/src/components/ui/toggle.tsx
- FOUND commit: 78e50189 (test - TDD RED)
- FOUND commit: 05ce37df (feat - Task 1+2 implementation)
- All 7 ThemePreviewPanel tests pass
- TypeScript compiles without errors (pnpm tsc --noEmit --project ui/tsconfig.json from worktree)
---
*Phase: 41-diagrams-icons-theme-engine*
*Completed: 2026-04-04*