Allow users to create, edit, share, and apply custom color schemes without editing source files, with automatic light/dark tone detection and WCAG AA contrast validation.
Custom themes SHALL be stored as .css files with a mandatory header comment
and a :root {} block of CSS variable overrides.
- GIVEN a CSS file with a
/* name: … terminalBackground: … */header comment and a:root { --bg: …; … }block - WHEN
parseThemeCssis called with that content - THEN it returns
{ name, description, terminalBackground, vars }with no error
- GIVEN CSS that begins with
:root {and has no/* */comment - WHEN
parseThemeCssis called - THEN it throws with a message containing
"header comment block"
- GIVEN a header comment that contains
terminalBackground:but notname: - WHEN
parseThemeCssis called - THEN it throws with a message containing
"name"
- GIVEN a header comment that contains
name:but notterminalBackground: - WHEN
parseThemeCssis called - THEN it throws with a message containing
"terminalBackground"
- GIVEN a declaration like
--bg: #0f0e17; /* App background */ - WHEN
parseThemeCssprocesses that block - THEN
vars['--bg']equals'#0f0e17'and the comment is discarded
- GIVEN a
:rootblock containing--unknown-key: #fff - WHEN
parseThemeCssprocesses it - THEN
--unknown-keydoes not appear in the returnedvars
Custom themes SHALL be stored as individual .css files under
~/.config/parallel-code/themes/<id>.css. The customThemes object SHALL NOT
be written to state.json.
- WHEN the renderer sends
save_custom_themewith a valididandcss - THEN the main process writes
<configDir>/themes/<id>.csswith that content
- WHEN the renderer sends
load_custom_themes - THEN the main process returns an array of
{ id, css }for every.cssfile in the themes directory
- WHEN the renderer sends
delete_custom_themewith anid - THEN the main process removes
<configDir>/themes/<id>.css
- WHEN
save_custom_themeordelete_custom_themeis called with anidthat contains characters outside[a-zA-Z0-9_-] - THEN the main process throws an error and does not touch the filesystem
Custom themes SHALL appear in the same preset grid as built-in themes, filtered by auto-detected tone (light or dark).
- GIVEN a custom theme whose
--bg-elevatedhas luminance ≤ 0.5 - WHEN the Themes settings tab is shown in dark appearance mode
- THEN the theme card appears in the dark preset grid
- GIVEN a custom theme whose
--bg-elevatedhas luminance > 0.5 - WHEN the Themes settings tab is shown in light appearance mode
- THEN the theme card appears in the light preset grid
- GIVEN a mix of built-in and custom theme cards in the grid
- WHEN the user hovers a custom card
- THEN an Edit button is shown (not Clone)
- AND WHEN the user hovers a built-in card
- THEN a Clone button is shown
The data-look HTML attribute SHALL always reflect the active base preset so
that structural CSS rules (layout, spacing, radius) are never lost when a
custom theme overrides color variables.
- GIVEN a built-in preset
indigois selected and a custom theme is active - WHEN the app renders
- THEN
document.documentElement.dataset.lookequals"indigo" - AND
document.documentElement.dataset.customThemeequals the custom theme'sid
The terminal emulator SHALL use a dark foreground color and a
GitHub-light-compatible ANSI palette when a custom theme's
terminalBackground has luminance > 0.5 so colored output remains legible.
- GIVEN a custom theme with
terminalBackground: #ffffff - WHEN
getTerminalThemeForCustomis called with that value - THEN the returned object includes
foreground: '#1f2329'
- GIVEN a custom theme with
terminalBackground: #1e1e2e - WHEN
getTerminalThemeForCustomis called - THEN the returned object does NOT include a
foregroundkey
The theme dialog SHALL report contrast warnings for pairs that fail WCAG AA thresholds so users can correct them before saving.
- GIVEN the theme dialog validates a custom theme
- WHEN it computes WCAG contrast warnings
- THEN it checks these foreground/background pairs:
| Foreground | Background | Required ratio |
|---|---|---|
--fg |
--bg-elevated |
4.5 : 1 |
--fg-muted |
--bg-elevated |
3.0 : 1 |
--fg |
--bg-selected |
4.5 : 1 |
--accent-text |
--accent |
4.5 : 1 |
- AND translucent backgrounds are composited over
--bg-elevatedbefore the ratio is computed to avoid false positives