feat(themes): custom themes with CSS editor, AI prompt, WCAG validation, and light/dark slots#117
feat(themes): custom themes with CSS editor, AI prompt, WCAG validation, and light/dark slots#117brooksc wants to merge 3 commits into
Conversation
|
Review pass against the net diff from
Verification: |
…on, and light/dark slots Add a fully-featured custom theme system: - Themes settings tab with Light/Dark/System appearance modes; each slot holds an independent built-in preset + optional custom overlay - Custom theme editor (CSS paste + live parse/validate) with AI prompt generator that can be copied to Claude Code or any LLM - WCAG AA contrast checker with per-pair warnings (theme still saves) - CSS parser: header-comment metadata (name, description, terminalBackground), comment-stripping before :root scan, brace-counting block extractor, declaration-by-declaration regex, nested-rule detection - Built-in preset cards show "Clone" → opens editor pre-filled; custom cards show "Edit" overlay; tone-based slot assignment on save - Themes persisted as ~/.../themes/<id>.css; atomic writes; VALID_THEME_ID allowlist on all IPC handlers; ENOENT-only swallow on delete - Startup sequence: loadState → loadCustomThemes → applyAppearanceMode; both dark and light slots sanitized (stale IDs cleared) on every apply - Save/delete IPC awaited before store mutation (pessimistic); save error kept in a separate signal so live-validation edits don't clear it - Legacy JSON customThemes migration via Promise.allSettled; malformed theme files logged with console.warn and skipped gracefully - Light theme xterm palette override so terminal text is readable on light backgrounds; luminance-based tone detection via colord - OpenSpec change proposal (openspec/changes/custom-themes/) Also includes: prompt cancel-option dialog, pagination-dot Linux fix, keybinding word-select shadow fix, mobile QR intermittent rendering fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
757e815 to
0f22f29
Compare
Startup race: applyAppearanceMode() was sanitizing persisted custom-theme slot IDs against an empty store before loadCustomThemes() had run, permanently losing the user's selections. loadCustomThemes() now returns false on IPC failure so markCustomThemesReady() (which unlocks sanitization) is only called after a successful load. Clone overlay: readCssVarsForPreset() now clears data-custom-theme and the injected custom-theme <style> tag while sampling built-in preset vars, so computed values come from the preset alone rather than the active overlay. Tests: added startup-race guard test; sanitization tests now call markCustomThemesReady() explicitly to simulate post-load phase. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Addressed both review findings: Startup race (persisted selections lost): Clone copies custom overlay: Tests: Added a passing test for the startup-race guard ("pre-load preserves IDs"). The two existing sanitization tests now call |
|
Thanks for the large themes pass. I found a few issues that should be fixed before merge:
|
Close watchdog: removed premature WindowCloseHandling ack that fired before
the async pre-work in the close handler (captureWindowState, saveState,
CountRunningAgents). The ack now only fires inside preventDefault(), keeping
the 5s force-close fallback armed through the pre-work path.
CSS value validation: added isAllowedCssValue() that rejects url(), image-set(),
@-containing, and control-character values before they enter the store or get
injected into the custom-theme <style> tag. --island-radius additionally
restricted to px/0 values only.
Save & Apply label: button now shows "Save to {tone} slot" when a new theme's
detected tone doesn't match the currently-active slot, so the label accurately
reflects whether the theme will be visible immediately.
Tests: 14 new tests covering CSS value validation (url, @, control chars,
island-radius, hex, gradient) and detectThemeTone (dark, light, fallbacks,
gradient, unparseable).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Addressed the remaining three findings: Close watchdog (issue 2): Removed the premature CSS value validation (issue 4): Added Save & Apply label (issue 5): The button now reactively shows Tests: 14 new tests — CSS value validation (url, @, control chars, island-radius, valid hex/gradient) and |



Core feature: Custom Themes
Theming mechanics
~/.../themes/<id>.css; atomic writes; ID allowlist enforced in all IPC handlers:rootscan, brace-counting block extractor, declaration-level regex, nested-rule detectionloadState → loadCustomThemes → applyAppearanceMode; both slots sanitized on every apply; stale IDs clearedcustomThemesJSON migration viaPromise.allSettled; malformed files logged and skippedOther fixes bundled in
Alt+Shift+←/→on macOS,Ctrl+Shiftelsewhere)OpenSpec
openspec/specs/custom-themes/spec.md🤖 Generated with Claude Code