179 lines
11 KiB
Markdown
179 lines
11 KiB
Markdown
---
|
||
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*
|