Skip to content

feat: custom theme system with 18 built-in themes#294

Merged
backnotprop merged 6 commits intomainfrom
feat/custom-theme
Mar 15, 2026
Merged

feat: custom theme system with 18 built-in themes#294
backnotprop merged 6 commits intomainfrom
feat/custom-theme

Conversation

@backnotprop
Copy link
Owner

Summary

  • Consolidate CSS theming into single source of truth (packages/ui/theme.css) — color tokens defined once, imported by all three apps (editor, review-editor, marketing)
  • Replace ~35 hardcoded oklch values with token references (oklch(from var(--token) l c h / alpha))
  • Fix 3 light-mode bugs in review-editor diff colors
  • Introduce multi-theme architecture: each theme defines both dark and light mode variants via .theme-{name} / .theme-{name}.light CSS classes
  • Add Theme tab to Settings with mode toggle (dark/light/system) and theme grid with color swatches
  • ThemeProvider manages colorTheme + mode independently — users pick a palette, then toggle mode within it
  • Dark-only themes (Dracula, Terminal, etc.) suppress .light class; light-only themes (Tinacious) force it
  • Pass theme colors into @pierre/diffs shadow DOM via unsafeCSS for code review diff theming
  • Cookie persistence: plannotator-color-theme for palette, existing plannotator-theme for mode

18 built-in themes: Plannotator, Absolutely, Adwaita, Caffeine, Catppuccin, Doom 64, Dracula, Gruvbox, Monokai Pro, PaulMillr, Quantum Rose, Rosé Pine, Soft Pop, Solar Dusk, Synthwave '84, Terminal, Tinacious, Tokyo Night

Canonical sources: Gruvbox (morhetz/gruvbox), Adwaita (piousdeer/vscode-adwaita), Synthwave '84 (robb0wen/synthwave-vscode), Catppuccin/Rosé Pine/Monokai Pro/PaulMillr/Tokyo Night (Ghostty themes)

Test plan

  • Open Settings > Theme tab — verify 18 theme cards with color swatches
  • Click each theme — verify UI updates immediately in both plan review and code review
  • Toggle dark/light/system mode within each theme
  • Verify dark-only themes (Dracula, Terminal, Monokai Pro, PaulMillr, Synthwave) ignore light mode toggle
  • Verify light-only theme (Tinacious) ignores dark mode toggle
  • Verify theme persists across page refresh (cookie)
  • Verify theme transfers between plan review and code review apps (shared cookie)
  • Verify code review diff viewer background matches active theme
  • Verify annotation highlights, plan diff colors, code blocks adapt to each theme
  • Verify marketing site builds successfully
  • Test on mobile — horizontal tab bar, theme grid responsive

🤖 Generated with Claude Code

backnotprop and others added 6 commits March 13, 2026 22:50
Consolidate CSS theming into a single source of truth (packages/ui/theme.css)
and introduce a multi-theme architecture where each theme defines both dark
and light mode variants. Users can pick a color palette (theme) and separately
toggle dark/light mode within it.

- Extract shared color tokens, Tailwind bridge, and base styles into packages/ui/theme.css
- Replace hardcoded oklch values with token references (oklch from var syntax)
- Fix 3 light-mode bugs in review-editor diff colors
- Create 15 built-in themes: Plannotator (default), Claude+, Soft Pop, Adwaita,
  Caffeine, Cyberdyne, Cyberfunk, Doom 64, Dracula, Gruvbox, PaulMillr,
  Quantum Rose, Solar Dusk, Terminal, Tinacious
- Expand ThemeProvider to manage colorTheme + mode independently
- Add Theme tab to Settings with mode toggle, search, and swatch grid
- Dark-only themes (Dracula, Terminal, etc.) suppress light class to prevent
  broken styling; light-only themes (Tinacious) force it
- Cookie persistence: plannotator-color-theme for palette, existing key for mode
- Include theme conversion script for FinSitter theme adaptation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…4/Tokyo Night

Theme curation:
- Replace Cyberdyne with Synthwave '84 (from robb0wen/synthwave-vscode)
- Replace Cyberfunk with Catppuccin (Mocha dark + Latte light), Rosé Pine
  (dark + Dawn light), Monokai Pro (dark only), Tokyo Night (Storm + Day)
- Rewrite Gruvbox from canonical source (morhetz/gruvbox)
- Rewrite Adwaita from canonical VS Code theme (piousdeer/vscode-adwaita)
- Rewrite PaulMillr from Ghostty canonical palette

Theme fixes:
- Fix faded Send Feedback button on Solar Dusk, Quantum Rose, Caffeine
  (accent colors were too dark/invisible at 15% opacity)
- Fix Dracula/Terminal/PaulMillr/Tinacious light mode breakage — dark-only
  themes now suppress .light class via modeSupport in ThemeProvider
- Fix code block backgrounds — use --code-bg token instead of --muted
- Add faint green grid overlay for Terminal theme
- Alphabetize theme registry (Plannotator first)

Code review diff theming:
- Pass theme colors into @pierre/diffs shadow DOM via unsafeCSS prop
- Dynamic themeType based on resolved mode

18 built-in themes: Plannotator, Absolutely, Adwaita, Caffeine, Catppuccin,
Doom 64, Dracula, Gruvbox, Monokai Pro, PaulMillr, Quantum Rose, Rosé Pine,
Soft Pop, Solar Dusk, Synthwave '84, Terminal, Tinacious, Tokyo Night

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove 340px cap on theme grid, bump content area from 70vh to 85vh
so all themes are visible without scrolling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… up DiffViewer

From /simplify review:
- Export Mode type from ThemeProvider, import in ThemeTab (was duplicated)
- Add resolvedMode to context — consumers no longer re-query matchMedia
- Memoize context value with useMemo, setters with useCallback (prevents
  unnecessary re-renders of all useTheme consumers)
- Consolidate DiffViewer's two pierre state vars into single object
- Use resolvedMode from context in DiffViewer instead of classList check
- Format crammed single-line extended tokens in 4 theme CSS files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e class

P1: Marketing site inline script now sets theme-{name} class on <html>
    before first paint (reads plannotator-color-theme cookie). Without this,
    CSS tokens under .theme-* selectors were never active.

P2: System mode effect now re-reads matchMedia.matches immediately when
    entering system mode, not just on future changes. Fixes stale resolvedMode
    when OS preference changed while pinned to explicit dark/light.

P3: ThemeProvider applies theme class synchronously during render (not in
    a passive useEffect) to prevent flash of unstyled content on hard refresh.
    Also extracted resolveThemeClasses to module scope to avoid useCallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Quick Copy button to annotation panel footer (splits horizontally
  with existing Quick Share). Copies annotations wrapped with the deny
  preamble so output is paste-ready for agent sessions.
- Export Modal annotations copy also wraps with deny preamble
- Extract wrapFeedbackForAgent() utility in parser.ts as single source
  of truth for the preamble text
- Fix desktop import icon to match mobile (arrow-into-document, not download)
- Comment out code review agent badge — unreliable across multiple harnesses

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@backnotprop backnotprop merged commit e1bd27a into main Mar 15, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant