CtrlK
BlogDocsLog inGet started
Tessl Logo

theme-factory

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.

65

Quality

77%

Does it follow best practices?

Impact

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Optimize this skill with Tessl

npx tessl skill review --optimize ./.aider-desk/skills/theme-factory/SKILL.md
SKILL.md
Quality
Evals
Security

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:
    • normal
    • hover/active

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):

VariableUsageWhere visible
bg-primaryDeepest background — app body, outer containersbody, outer page wrapper, main content areas, inline edit panels
bg-primary-lightPrimary raised surface — task bars, sidebar items, file viewers, content panelsTaskBar, TaskItem (idle), file viewer scrollable area, top-bar gradient end
bg-primary-light-strongSemi-transparent overlay — selected items, diff/file headers, notifications, tooltip arrows, reflected messagesTaskItem (selected), PierreDiffViewer header, toast notification bg
bg-secondaryCard/panel surface — input fields, dialog content, chips, selected/hovered task itemsModel dialog, chip items, settings cards, hover on menu items
bg-secondary-lightElevated input container — search/dropdown wrappers, dropdown menus, merge button popoverTag input containers, settings dropdown focus wrappers
bg-secondary-light-strongestOpaque elevated surface — dialogs (BaseDialog), thinking blocks, inactive tab hoverBaseDialog bg, ThinkingAnswerBlock, inactive project tab hover
bg-tertiaryHover/highlight surface — icon button hover, menu item hover, scrollbar thumb, diff gutter omit, CodeMirror autocomplete borderAll icon button hovers, menu item hovers, scrollbar thumbs
bg-tertiary-emphasisAccent-tinted hover — uses the theme's accent color at ~25% opacity for tinted hover statesHeader icon button hover, delete button hover backgrounds, task badges
bg-tertiary-strongStronger tinted hover — accent color at ~50% opacityActive project tab hover
bg-fourthSeparator / small control surface — vertical dividers in TaskBar, checkbox checked state, close button bg, tab hover for active tabTaskBar dividers, Checkbox checked bg, BaseDialog close button
bg-fourth-mutedAccent-tinted subtle bg — accent color at ~20% opacityDecorative/special accent backgrounds
bg-fourth-emphasisAccent-tinted medium bg — accent color at ~30% opacityDecorative/special accent backgrounds
bg-fifthHighest hover state — used for "close" button hover in dialogsBaseDialog close button hover
bg-selectionText selection highlight — used in PromptField for text selection colorPromptField ::selection color
bg-code-blockCode block background — standalone code blocks, diff file items, log viewerCodeBlock component, DiffFileItem, LogsPage pre blocks

Diff viewer backgrounds (--color-bg-diff-viewer-*)

VariableUsage
diff-viewer-old-primaryDeleted line background (used in DiffViewer.scss, CompactDiffViewer)
diff-viewer-old-secondaryDeleted line character-level edit highlight
diff-viewer-new-primaryInserted line background
diff-viewer-new-secondaryInserted line character-level edit highlight

Text hierarchy (--color-text-*)

VariableUsageVisible on
text-primaryPrimary text — labels, headings, button text, body textMost text throughout the app
text-secondarySecondary text — icons in header, model subtitles, status textHeader icons (notebook, chart, settings), model provider text
text-tertiaryTertiary text — hover state for muted items, diff modified markers, toolbar button hoverHover state text, diff line numbers, expanded toolbar buttons
text-muted-lightDimmed text — reflected messages, placeholder labelsReflectedMessageBlock, disabled-state labels
text-mutedMuted text — description paragraphs, log viewer text, empty statesSettings descriptions, log output, chip empty labels
text-muted-darkDark muted — input placeholders, section dividersPromptField placeholder, TaskSectionHeader
text-darkDarkest text — very deep background text, decorativeRarely used, deepest layer text

Border hierarchy (--color-border-*)

VariableUsageVisible on
border-darkSubtlest border — outer container edges, sticky headersHome page outer border, UpdatedFilesDiffModal header, bash blocks
border-dark-lightLight subtle border — code blocks, sidebar section separators, task item bordersCodeBlock border, TaskSectionHeader top border, TaskItem border
border-dark-light-strongSemi-transparent subtle border — reflected messages, code block <hr>ReflectedMessageBlock, CodeBlock horizontal rules
border-default-darkMedium border — prompt input borders (unfocused), diff comment panelPromptField unfocused border
border-defaultStandard border — inputs, cards, dividers, containers (most common)Settings inputs, Home container, inline edit panels, TaskItem
border-accentAccent border — focused inputs, checked checkboxes/radios, diff headers, badge bordersPromptField focus, Checkbox checked, PierreDiffViewer header
border-lightLightest border — selected/focused inputs, active tab indicatorsSettings active option border, input focus state

Accent colors (--color-accent-*)

VariableUsage
accent-primaryBrand accent — AI sparkle icon, welcome message bullets, commit badges, voice recording indicator
accent-secondarySecondary accent — selected answer highlights, decorative accents
accent-lightHighlight 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:

VariantUsage in containedUsage in textUsage in outline
(base)BackgroundBorder color
-lightHover background
-subtleHover backgroundHover background
-emphasisHover background (danger)
-textText colorText colorText 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

  • Theme not showing up:

    • missing @use import in src/renderer/src/themes/themes.scss
    • missing entry in THEMES array in packages/common/src/types/common.ts
    • typo mismatch between .theme-<name> and the <name> stored in settings
  • Some UI areas look "unstyled":

    • you likely missed one or more --color-* variables; compare against a known-good theme and fill in the missing ones.
  • Input fields don't match theme:

    • Components use bg-bg-secondary + border-border-default for inputs, not the input-* tokens. Focus on the bg/border/text hierarchies instead.
Repository
hotovo/aider-desk
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.