Theme Factory
Use this skill when you need to add a new theme to AiderDesk.
AiderDesk themes are implemented as SCSS files that define a .theme-<name> class with a full set of CSS custom properties (variables). The UI uses Tailwind utilities mapped to these CSS variables.
Where themes live
- Theme files:
src/renderer/src/themes/theme-<name>.scss
- Theme aggregator (imports all themes):
src/renderer/src/themes/themes.scss
- Theme type registry:
packages/common/src/types/common.ts (THEMES)
- Theme selector UI:
src/renderer/src/components/settings/GeneralSettings.tsx
- Theme application:
src/renderer/src/App.tsx (applies theme-<name> class to document.body)
- Theme display names (i18n):
packages/common/src/locales/en.json (themeOptions.<name>)
packages/common/src/locales/zh.json (themeOptions.<name>)
Definition format
Each theme is a class:
- Class name:
.theme-<name>
- Contents: a complete set of
--color-* variables.
Best workflow: copy an existing theme (e.g. theme-dark.scss) and adjust values.
Checklist: add a new theme
1) Choose a theme name
Pick a kebab-case name, e.g. sunset, nord, paper.
You will reference it consistently in:
- CSS class:
.theme-<name>
- filename:
theme-<name>.scss
THEMES array value: '<name>'
- i18n key:
themeOptions.<name>
2) Create the theme SCSS file
Create:
src/renderer/src/themes/theme-<name>.scss
Start by copying a similar theme (dark -> dark-ish, light -> light-ish), then update the hex colors.
Minimum requirement: define all variables expected by the app.
Practical way to ensure completeness:
- Compare with
src/renderer/src/themes/theme-dark.scss (or another full theme)
- Keep variable names identical; only change values.
3) Register the theme in the theme aggregator
Edit:
src/renderer/src/themes/themes.scss
Add:
@use 'theme-<name>.scss';
If the file is not imported here, it won’t be included in the built CSS.
4) Register the theme in TypeScript types
Edit:
packages/common/src/types/common.ts
Add '<name>' to the exported THEMES array.
This makes the theme selectable and type-safe.
5) Add i18n display names
Edit:
packages/common/src/locales/en.json
packages/common/src/locales/zh.json
Add entries under themeOptions:
{
"themeOptions": {
"<name>": "Your Theme Name"
}
}
6) Verify in the UI
- Open Settings → General → Theme
- Confirm the new theme appears in the dropdown
- Switch to it and confirm the whole UI updates (no restart)
7) Quality checks
- Contrast: confirm text is readable on all backgrounds (aim for WCAG AA)
- Verify key surfaces:
- main background panels
- inputs
- buttons
- borders/dividers
- diff viewer colors
- code blocks
- muted/secondary text
- Check both states:
Color Variable Reference
Each variable maps from --color-<group>-<variant> in SCSS to a Tailwind utility like bg-<group>-<variant>, text-<group>-<variant>, or border-<group>-<variant>. The mapping is defined in tailwind.config.js.
Background layer system (--color-bg-*)
The app uses a 5-tier surface hierarchy from darkest to lightest (for dark themes; reversed for light):
| Variable |
Usage |
Where visible |
bg-primary |
Deepest background — app body, outer containers |
body, outer page wrapper, main content areas, inline edit panels |
bg-primary-light |
Primary raised surface — task bars, sidebar items, file viewers, content panels |
TaskBar, TaskItem (idle), file viewer scrollable area, top-bar gradient end |
bg-primary-light-strong |
Semi-transparent overlay — selected items, diff/file headers, notifications, tooltip arrows, reflected messages |
TaskItem (selected), PierreDiffViewer header, toast notification bg |
bg-secondary |
Card/panel surface — input fields, dialog content, chips, selected/hovered task items |
Model dialog, chip items, settings cards, hover on menu items |
bg-secondary-light |
Elevated input container — search/dropdown wrappers, dropdown menus, merge button popover |
Tag input containers, settings dropdown focus wrappers |
bg-secondary-light-strongest |
Opaque elevated surface — dialogs (BaseDialog), thinking blocks, inactive tab hover |
BaseDialog bg, ThinkingAnswerBlock, inactive project tab hover |
bg-tertiary |
Hover/highlight surface — icon button hover, menu item hover, scrollbar thumb, diff gutter omit, CodeMirror autocomplete border |
All icon button hovers, menu item hovers, scrollbar thumbs |
bg-tertiary-emphasis |
Accent-tinted hover — uses the theme's accent color at ~25% opacity for tinted hover states |
Header icon button hover, delete button hover backgrounds, task badges |
bg-tertiary-strong |
Stronger tinted hover — accent color at ~50% opacity |
Active project tab hover |
bg-fourth |
Separator / small control surface — vertical dividers in TaskBar, checkbox checked state, close button bg, tab hover for active tab |
TaskBar dividers, Checkbox checked bg, BaseDialog close button |
bg-fourth-muted |
Accent-tinted subtle bg — accent color at ~20% opacity |
Decorative/special accent backgrounds |
bg-fourth-emphasis |
Accent-tinted medium bg — accent color at ~30% opacity |
Decorative/special accent backgrounds |
bg-fifth |
Highest hover state — used for "close" button hover in dialogs |
BaseDialog close button hover |
bg-selection |
Text selection highlight — used in PromptField for text selection color |
PromptField ::selection color |
bg-code-block |
Code block background — standalone code blocks, diff file items, log viewer |
CodeBlock component, DiffFileItem, LogsPage pre blocks |
Diff viewer backgrounds (--color-bg-diff-viewer-*)
| Variable |
Usage |
diff-viewer-old-primary |
Deleted line background (used in DiffViewer.scss, CompactDiffViewer) |
diff-viewer-old-secondary |
Deleted line character-level edit highlight |
diff-viewer-new-primary |
Inserted line background |
diff-viewer-new-secondary |
Inserted line character-level edit highlight |
Text hierarchy (--color-text-*)
| Variable |
Usage |
Visible on |
text-primary |
Primary text — labels, headings, button text, body text |
Most text throughout the app |
text-secondary |
Secondary text — icons in header, model subtitles, status text |
Header icons (notebook, chart, settings), model provider text |
text-tertiary |
Tertiary text — hover state for muted items, diff modified markers, toolbar button hover |
Hover state text, diff line numbers, expanded toolbar buttons |
text-muted-light |
Dimmed text — reflected messages, placeholder labels |
ReflectedMessageBlock, disabled-state labels |
text-muted |
Muted text — description paragraphs, log viewer text, empty states |
Settings descriptions, log output, chip empty labels |
text-muted-dark |
Dark muted — input placeholders, section dividers |
PromptField placeholder, TaskSectionHeader |
text-dark |
Darkest text — very deep background text, decorative |
Rarely used, deepest layer text |
Border hierarchy (--color-border-*)
| Variable |
Usage |
Visible on |
border-dark |
Subtlest border — outer container edges, sticky headers |
Home page outer border, UpdatedFilesDiffModal header, bash blocks |
border-dark-light |
Light subtle border — code blocks, sidebar section separators, task item borders |
CodeBlock border, TaskSectionHeader top border, TaskItem border |
border-dark-light-strong |
Semi-transparent subtle border — reflected messages, code block <hr> |
ReflectedMessageBlock, CodeBlock horizontal rules |
border-default-dark |
Medium border — prompt input borders (unfocused), diff comment panel |
PromptField unfocused border |
border-default |
Standard border — inputs, cards, dividers, containers (most common) |
Settings inputs, Home container, inline edit panels, TaskItem |
border-accent |
Accent border — focused inputs, checked checkboxes/radios, diff headers, badge borders |
PromptField focus, Checkbox checked, PierreDiffViewer header |
border-light |
Lightest border — selected/focused inputs, active tab indicators |
Settings active option border, input focus state |
Accent colors (--color-accent-*)
| Variable |
Usage |
accent-primary |
Brand accent — AI sparkle icon, welcome message bullets, commit badges, voice recording indicator |
accent-secondary |
Secondary accent — selected answer highlights, decorative accents |
accent-light |
Highlight accent — token usage bar fill, hover text for commit links |
Status colors (--color-success-*, --color-warning-*, --color-error-*, --color-info-*)
Each has up to 7 variants with consistent suffix semantics:
- (base) — solid color for icons, text, badges
- -light — lighter shade for hover states
- -lighter / -lightest — progressively lighter for gradient effects (error, info only)
- -subtle — ~10% opacity for very faint backgrounds
- -muted — ~20% opacity for muted backgrounds
- -emphasis — ~30% opacity for medium-strength backgrounds
- -strong — ~50% opacity for strong backgrounds (error only)
- -dark — darker variant for darkened states (error only)
- -text — text color to use on top of the base color (warning, buttons)
Button colors (--color-button-*)
Three button palettes (primary, secondary, danger) each with 5 variants. See Button.tsx for the full mapping:
| Variant |
Usage in contained |
Usage in text |
Usage in outline |
(base) |
Background |
— |
Border color |
-light |
Hover background |
— |
— |
-subtle |
— |
Hover background |
Hover background |
-emphasis |
Hover background (danger) |
— |
— |
-text |
Text color |
Text color |
Text color |
The tertiary button color uses bg-primary/bg-secondary + text-primary instead of dedicated button tokens.
Disabled buttons use: bg-bg-tertiary-strong background + text-text-muted text.
Input colors (--color-input-*)
Currently not directly used in TSX components — inputs use bg-bg-secondary + border-border-default + text-text-primary instead. These are defined for potential future use or custom components.
Agent colors (--color-agent-*)
Semantic colors for tool/badge indicators in the AgentSelector and related UI:
agent-auto-approve — auto-approve toggle indicator
agent-aider-tools — aider tools icon
agent-power-tools — power tools icon
agent-todo-tools — todo tool badge
agent-tasks-tools — tasks tool badge
agent-memory-tools — memory tool badge
agent-skills-tools — skills tool badge
agent-subagents-tools — subagents tool badge
agent-context-files — context file indicator
agent-repo-map — repo map indicator
agent-ai-request — AI request indicator
agent-sub-agent — sub-agent indicator
Dark theme registration
Dark themes (those that need a dark code editor) must also be added to the isCodeEditorDarkTheme array in packages/common/src/types/common.ts.
Color opacity suffix convention
Many variables include an inline hex alpha suffix (e.g. #D4A05440 = accent at ~25% opacity). The convention is:
1a ≈ 10% — subtle
19 ≈ 10% — subtle (alternate)
26 ≈ 15% — muted
33 ≈ 20% — muted
4c ≈ 30% — emphasis
4d ≈ 30% — emphasis (alternate)
50 ≈ 31% — selection
60 ≈ 38% — strong
7f ≈ 50% — strong (alternate)
80 ≈ 50% — semi-transparent
f2 ≈ 95% — almost opaque
Global color applications (non-Tailwind)
Some components use CSS variables directly via var(--color-*) instead of Tailwind utilities:
main.css: body background/text, CodeMirror editor styling, resize handle
DiffViewer.scss / PierreDiffViewer.scss: diff line backgrounds, gutters
notifications.ts: toast background/text styling
PromptField.tsx: text selection color
Troubleshooting
1---2name: theme-factory3description: Create new AiderDesk UI themes by defining SCSS color variables, registering theme types, and adding i18n display names. Use when adding a theme, creating a color scheme, customizing appearance, or implementing dark mode and light mode variants.4---56# Theme Factory78Use this skill when you need to add a **new theme** to AiderDesk.910AiderDesk themes are implemented as **SCSS files** that define a `.theme-<name>` class with a full set of **CSS custom properties** (variables). The UI uses Tailwind utilities mapped to these CSS variables.1112## Where themes live1314- Theme files: `src/renderer/src/themes/theme-<name>.scss`15- Theme aggregator (imports all themes): `src/renderer/src/themes/themes.scss`16- Theme type registry: `packages/common/src/types/common.ts` (`THEMES`)17- Theme selector UI: `src/renderer/src/components/settings/GeneralSettings.tsx`18- Theme application: `src/renderer/src/App.tsx` (applies `theme-<name>` class to `document.body`)19- Theme display names (i18n):20 - `packages/common/src/locales/en.json` (`themeOptions.<name>`)21 - `packages/common/src/locales/zh.json` (`themeOptions.<name>`)2223## Definition format2425Each theme is a class:2627- Class name: `.theme-<name>`28- Contents: a complete set of `--color-*` variables.2930Best workflow: **copy an existing theme** (e.g. `theme-dark.scss`) and adjust values.3132## Checklist: add a new theme3334### 1) Choose a theme name3536Pick a kebab-case name, e.g. `sunset`, `nord`, `paper`.3738You will reference it consistently in:39- CSS class: `.theme-<name>`40- filename: `theme-<name>.scss`41- `THEMES` array value: `'<name>'`42- i18n key: `themeOptions.<name>`4344### 2) Create the theme SCSS file4546Create:47- `src/renderer/src/themes/theme-<name>.scss`4849Start by copying a similar theme (dark -> dark-ish, light -> light-ish), then update the hex colors.5051Minimum requirement: define **all variables** expected by the app.5253Practical way to ensure completeness:54- Compare with `src/renderer/src/themes/theme-dark.scss` (or another full theme)55- Keep variable names identical; only change values.5657### 3) Register the theme in the theme aggregator5859Edit:60- `src/renderer/src/themes/themes.scss`6162Add:63```scss64@use 'theme-<name>.scss';65```6667If the file is not imported here, it won’t be included in the built CSS.6869### 4) Register the theme in TypeScript types7071Edit:72- `packages/common/src/types/common.ts`7374Add `'<name>'` to the exported `THEMES` array.7576This makes the theme selectable and type-safe.7778### 5) Add i18n display names7980Edit:81- `packages/common/src/locales/en.json`82- `packages/common/src/locales/zh.json`8384Add entries under `themeOptions`:8586```json87{88 "themeOptions": {89 "<name>": "Your Theme Name"90 }91}92```9394### 6) Verify in the UI9596- Open Settings → General → Theme97- Confirm the new theme appears in the dropdown98- Switch to it and confirm the whole UI updates (no restart)99100### 7) Quality checks101102- Contrast: confirm text is readable on all backgrounds (aim for WCAG AA)103- Verify key surfaces:104 - main background panels105 - inputs106 - buttons107 - borders/dividers108 - diff viewer colors109 - code blocks110 - muted/secondary text111- Check both states:112 - normal113 - hover/active114115## Color Variable Reference116117Each variable maps from `--color-<group>-<variant>` in SCSS to a Tailwind utility like `bg-<group>-<variant>`, `text-<group>-<variant>`, or `border-<group>-<variant>`. The mapping is defined in `tailwind.config.js`.118119### Background layer system (`--color-bg-*`)120121The app uses a **5-tier surface hierarchy** from darkest to lightest (for dark themes; reversed for light):122123| Variable | Usage | Where visible |124|---|---|---|125| `bg-primary` | **Deepest background** — app body, outer containers | `body`, outer page wrapper, main content areas, inline edit panels |126| `bg-primary-light` | **Primary raised surface** — task bars, sidebar items, file viewers, content panels | TaskBar, TaskItem (idle), file viewer scrollable area, top-bar gradient end |127| `bg-primary-light-strong` | **Semi-transparent overlay** — selected items, diff/file headers, notifications, tooltip arrows, reflected messages | TaskItem (selected), PierreDiffViewer header, toast notification bg |128| `bg-secondary` | **Card/panel surface** — input fields, dialog content, chips, selected/hovered task items | Model dialog, chip items, settings cards, hover on menu items |129| `bg-secondary-light` | **Elevated input container** — search/dropdown wrappers, dropdown menus, merge button popover | Tag input containers, settings dropdown focus wrappers |130| `bg-secondary-light-strongest` | **Opaque elevated surface** — dialogs (BaseDialog), thinking blocks, inactive tab hover | BaseDialog bg, ThinkingAnswerBlock, inactive project tab hover |131| `bg-tertiary` | **Hover/highlight surface** — icon button hover, menu item hover, scrollbar thumb, diff gutter omit, CodeMirror autocomplete border | All icon button hovers, menu item hovers, scrollbar thumbs |132| `bg-tertiary-emphasis` | **Accent-tinted hover** — uses the theme's accent color at ~25% opacity for tinted hover states | Header icon button hover, delete button hover backgrounds, task badges |133| `bg-tertiary-strong` | **Stronger tinted hover** — accent color at ~50% opacity | Active project tab hover |134| `bg-fourth` | **Separator / small control surface** — vertical dividers in TaskBar, checkbox checked state, close button bg, tab hover for active tab | TaskBar dividers, Checkbox checked bg, BaseDialog close button |135| `bg-fourth-muted` | **Accent-tinted subtle bg** — accent color at ~20% opacity | Decorative/special accent backgrounds |136| `bg-fourth-emphasis` | **Accent-tinted medium bg** — accent color at ~30% opacity | Decorative/special accent backgrounds |137| `bg-fifth` | **Highest hover state** — used for "close" button hover in dialogs | BaseDialog close button hover |138| `bg-selection` | **Text selection highlight** — used in PromptField for text selection color | PromptField `::selection` color |139| `bg-code-block` | **Code block background** — standalone code blocks, diff file items, log viewer | CodeBlock component, DiffFileItem, LogsPage pre blocks |140141### Diff viewer backgrounds (`--color-bg-diff-viewer-*`)142143| Variable | Usage |144|---|---|145| `diff-viewer-old-primary` | Deleted line background (used in DiffViewer.scss, CompactDiffViewer) |146| `diff-viewer-old-secondary` | Deleted line character-level edit highlight |147| `diff-viewer-new-primary` | Inserted line background |148| `diff-viewer-new-secondary` | Inserted line character-level edit highlight |149150### Text hierarchy (`--color-text-*`)151152| Variable | Usage | Visible on |153|---|---|---|154| `text-primary` | **Primary text** — labels, headings, button text, body text | Most text throughout the app |155| `text-secondary` | **Secondary text** — icons in header, model subtitles, status text | Header icons (notebook, chart, settings), model provider text |156| `text-tertiary` | **Tertiary text** — hover state for muted items, diff modified markers, toolbar button hover | Hover state text, diff line numbers, expanded toolbar buttons |157| `text-muted-light` | **Dimmed text** — reflected messages, placeholder labels | ReflectedMessageBlock, disabled-state labels |158| `text-muted` | **Muted text** — description paragraphs, log viewer text, empty states | Settings descriptions, log output, chip empty labels |159| `text-muted-dark` | **Dark muted** — input placeholders, section dividers | PromptField placeholder, TaskSectionHeader |160| `text-dark` | **Darkest text** — very deep background text, decorative | Rarely used, deepest layer text |161162### Border hierarchy (`--color-border-*`)163164| Variable | Usage | Visible on |165|---|---|---|166| `border-dark` | **Subtlest border** — outer container edges, sticky headers | Home page outer border, UpdatedFilesDiffModal header, bash blocks |167| `border-dark-light` | **Light subtle border** — code blocks, sidebar section separators, task item borders | CodeBlock border, TaskSectionHeader top border, TaskItem border |168| `border-dark-light-strong` | **Semi-transparent subtle border** — reflected messages, code block `<hr>` | ReflectedMessageBlock, CodeBlock horizontal rules |169| `border-default-dark` | **Medium border** — prompt input borders (unfocused), diff comment panel | PromptField unfocused border |170| `border-default` | **Standard border** — inputs, cards, dividers, containers (most common) | Settings inputs, Home container, inline edit panels, TaskItem |171| `border-accent` | **Accent border** — focused inputs, checked checkboxes/radios, diff headers, badge borders | PromptField focus, Checkbox checked, PierreDiffViewer header |172| `border-light` | **Lightest border** — selected/focused inputs, active tab indicators | Settings active option border, input focus state |173174### Accent colors (`--color-accent-*`)175176| Variable | Usage |177|---|---|178| `accent-primary` | Brand accent — AI sparkle icon, welcome message bullets, commit badges, voice recording indicator |179| `accent-secondary` | Secondary accent — selected answer highlights, decorative accents |180| `accent-light` | Highlight accent — token usage bar fill, hover text for commit links |181182### Status colors (`--color-success-*`, `--color-warning-*`, `--color-error-*`, `--color-info-*`)183184Each has up to 7 variants with consistent suffix semantics:185- **(base)** — solid color for icons, text, badges186- **-light** — lighter shade for hover states187- **-lighter** / **-lightest** — progressively lighter for gradient effects (error, info only)188- **-subtle** — ~10% opacity for very faint backgrounds189- **-muted** — ~20% opacity for muted backgrounds190- **-emphasis** — ~30% opacity for medium-strength backgrounds191- **-strong** — ~50% opacity for strong backgrounds (error only)192- **-dark** — darker variant for darkened states (error only)193- **-text** — text color to use on top of the base color (warning, buttons)194195### Button colors (`--color-button-*`)196197Three button palettes (`primary`, `secondary`, `danger`) each with 5 variants. See `Button.tsx` for the full mapping:198199| Variant | Usage in `contained` | Usage in `text` | Usage in `outline` |200|---|---|---|---|201| `(base)` | Background | — | Border color |202| `-light` | Hover background | — | — |203| `-subtle` | — | Hover background | Hover background |204| `-emphasis` | Hover background (danger) | — | — |205| `-text` | Text color | Text color | Text color |206207The **tertiary** button color uses `bg-primary`/`bg-secondary` + `text-primary` instead of dedicated button tokens.208209Disabled buttons use: `bg-bg-tertiary-strong` background + `text-text-muted` text.210211### Input colors (`--color-input-*`)212213Currently **not directly used** in TSX components — inputs use `bg-bg-secondary` + `border-border-default` + `text-text-primary` instead. These are defined for potential future use or custom components.214215### Agent colors (`--color-agent-*`)216217Semantic colors for tool/badge indicators in the AgentSelector and related UI:218- `agent-auto-approve` — auto-approve toggle indicator219- `agent-aider-tools` — aider tools icon220- `agent-power-tools` — power tools icon221- `agent-todo-tools` — todo tool badge222- `agent-tasks-tools` — tasks tool badge223- `agent-memory-tools` — memory tool badge224- `agent-skills-tools` — skills tool badge225- `agent-subagents-tools` — subagents tool badge226- `agent-context-files` — context file indicator227- `agent-repo-map` — repo map indicator228- `agent-ai-request` — AI request indicator229- `agent-sub-agent` — sub-agent indicator230231### Dark theme registration232233Dark themes (those that need a dark code editor) must also be added to the `isCodeEditorDarkTheme` array in `packages/common/src/types/common.ts`.234235### Color opacity suffix convention236237Many variables include an inline hex alpha suffix (e.g. `#D4A05440` = accent at ~25% opacity). The convention is:238- `1a` ≈ 10% — subtle239- `19` ≈ 10% — subtle (alternate)240- `26` ≈ 15% — muted241- `33` ≈ 20% — muted242- `4c` ≈ 30% — emphasis243- `4d` ≈ 30% — emphasis (alternate)244- `50` ≈ 31% — selection245- `60` ≈ 38% — strong246- `7f` ≈ 50% — strong (alternate)247- `80` ≈ 50% — semi-transparent248- `f2` ≈ 95% — almost opaque249250### Global color applications (non-Tailwind)251252Some components use CSS variables directly via `var(--color-*)` instead of Tailwind utilities:253- `main.css`: body background/text, CodeMirror editor styling, resize handle254- `DiffViewer.scss` / `PierreDiffViewer.scss`: diff line backgrounds, gutters255- `notifications.ts`: toast background/text styling256- `PromptField.tsx`: text selection color257258## Troubleshooting259260- Theme not showing up:261 - missing `@use` import in `src/renderer/src/themes/themes.scss`262 - missing entry in `THEMES` array in `packages/common/src/types/common.ts`263 - typo mismatch between `.theme-<name>` and the `<name>` stored in settings264265- Some UI areas look "unstyled":266 - you likely missed one or more `--color-*` variables; compare against a known-good theme and fill in the missing ones.267268- Input fields don't match theme:269 - Components use `bg-bg-secondary` + `border-border-default` for inputs, not the `input-*` tokens. Focus on the bg/border/text hierarchies instead.