Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Themes

The admin UI includes built-in theme support with multiple color schemes.

Built-In Themes

ThemeTypeDescription
LightlightDefault theme. Clean blue-accented light design.
Rosé Pine DawnlightWarm, muted light theme based on the Rosé Pine palette.
Tokyo NightdarkCool blue-purple dark theme.
Catppuccin MochadarkPastel-accented dark theme from the Catppuccin palette.
Gruvbox DarkdarkWarm retro dark theme with orange accents.

Switching Themes

Click the palette icon in the admin header to open the theme picker. The selected theme is persisted in localStorage and restored on page load (no flash of unstyled content).

How Themes Work

The default Light theme is defined in :root CSS custom properties in styles.css. Additional themes live in themes.css and override these variables using html[data-theme="<name>"] selectors.

/* Default light theme (styles.css) */
:root {
  color-scheme: light;
  --color-primary: #1677ff;
  --bg-body: #f4f7fc;
  --text-primary: rgba(0, 0, 0, 0.88);
  /* ... */
}

/* Dark theme override (themes.css) */
html[data-theme="tokyo-night"] {
  color-scheme: dark;
  --color-primary: #7aa2f7;
  --bg-body: #1a1b26;
  --text-primary: #c0caf5;
  /* ... */
}

Custom Themes

To create a custom theme, add a CSS file in your config directory’s static/ folder and override the theme picker template.

1. Create the theme CSS

Create static/themes-custom.css in your config directory:

html[data-theme="my-theme"] {
  color-scheme: light; /* or dark */

  /* Primary accent */
  --color-primary: #6366f1;
  --color-primary-hover: #818cf8;
  --color-primary-active: #4f46e5;
  --color-primary-bg: rgba(99, 102, 241, 0.08);

  /* Danger/error */
  --color-danger: #ef4444;
  --color-danger-hover: #f87171;
  --color-danger-active: #dc2626;
  --color-danger-bg: rgba(239, 68, 68, 0.08);

  /* Success */
  --color-success: #22c55e;
  --color-success-bg: rgba(34, 197, 94, 0.08);

  /* Warning */
  --color-warning: #f59e0b;
  --color-warning-bg: rgba(245, 158, 11, 0.08);

  /* Text */
  --text-primary: #1e293b;
  --text-secondary: #475569;
  --text-tertiary: #94a3b8;
  --text-on-primary: #ffffff;

  /* Surfaces */
  --bg-body: #f8fafc;
  --bg-surface: #ffffff;
  --bg-elevated: #f1f5f9;
  --bg-hover: rgba(0, 0, 0, 0.04);

  /* Borders */
  --border-color: rgba(0, 0, 0, 0.08);
  --border-color-hover: rgba(0, 0, 0, 0.15);

  /* Shadows */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);

  /* Inputs */
  --input-bg: #ffffff;
  --input-border: rgba(0, 0, 0, 0.12);

  /* Header */
  --header-bg: #f1f5f9;
  --header-border: rgba(0, 0, 0, 0.08);

  /* Sidebar */
  --sidebar-bg: transparent;
  --sidebar-active-bg: rgba(99, 102, 241, 0.1);
  --sidebar-active-text: #6366f1;
}

2. Import in a styles override

Create static/styles.css in your config directory (the static overlay will serve it instead of the built-in version). Copy the original and add your import at the bottom:

@import url("themes-custom.css");

3. Add the picker option

Override templates/layout/header.hbs and add a button to the .theme-picker__dropdown:

<button type="button" class="theme-picker__option" data-theme-value="my-theme">
  <span class="theme-picker__swatch" style="background:#f8fafc"></span>
  My Theme
</button>

CSS Custom Properties Reference

All variables that themes should override:

VariableDescription
Colors
--color-primaryPrimary accent color
--color-primary-hoverPrimary hover state
--color-primary-activePrimary active/pressed state
--color-primary-bgPrimary tinted background (low opacity)
--color-dangerError/destructive color
--color-danger-hoverDanger hover state
--color-danger-activeDanger active state
--color-danger-bgDanger tinted background
--color-successSuccess color
--color-success-bgSuccess tinted background
--color-warningWarning color
--color-warning-bgWarning tinted background
Text
--text-primaryPrimary text
--text-secondarySecondary/muted text
--text-tertiaryDisabled/hint text
--text-on-primaryText on primary-colored backgrounds
Surfaces
--bg-bodyPage background
--bg-surfaceCard/panel background
--bg-elevatedElevated surface (modals, popovers)
--bg-hoverGeneric hover background
Borders
--border-colorDefault border color
--border-color-hoverBorder hover color
Shadows
--shadow-smSmall shadow (cards)
--shadow-mdMedium shadow (dropdowns)
--shadow-lgLarge shadow (modals)
Inputs
--input-bgForm input background
--input-borderForm input border
--select-arrowSelect dropdown arrow (SVG data URL)
Layout
--header-bgHeader background
--header-borderHeader bottom border
--sidebar-bgSidebar background
--sidebar-active-bgActive sidebar item background
--sidebar-active-textActive sidebar item text color

Variables not typically overridden by themes (inherited from :root): --radius-*, --space-*, --transition-*, --text-xs through --text-2xl, --sidebar-width, --input-height.