Skip to content

Dark mode: one click away, light by default, one theme for every device - #212

Merged
danielehrhardt merged 3 commits into
mainfrom
feat/dark-mode
Oct 19, 2026
Merged

danielehrhardt merged 3 commits into
mainfrom
feat/dark-mode

Conversation

@danielehrhardt

Copy link
Copy Markdown
Contributor

Dark mode, light by default

The anthracite palette was already there, but only reachable through Settings → General, and the choice lived in the browser's localStorage only. Now dark mode is one click away and the same setting applies everywhere.

What changes

  • Sidebar toggle: a sun/moon button in the sidebar footer switches light and dark in one click. Also ⌘⇧L (Ctrl+Shift+L), the command palette ("Switch to dark mode") and the shortcuts list.
  • Light by default: a new install, a new browser or an unknown value opens light, even when the OS is dark. "System" in Settings still follows the OS, live.
  • One setting for every device: settings.general.theme is the source of truth. The desktop app, the browser dashboard, the cloud UI and the phone all follow it, and a change on one device (or by an agent through settings_update) shows on the others right away. localStorage only keeps it for the first paint.
  • Smooth switch: the palette swaps in one step (transitions paused for a frame, so controls don't fade one by one) with a soft crossfade where the webview supports View Transitions; off with reduced motion. The native window (title bar, resize fill) follows as before.
  • Phone app: no longer always follows the phone's own scheme. It uses the computer's theme (light until picked), remembers it for the next cold start, and Settings → Preferences has a Light / Dark / System row. Takes effect with the next phone build.
  • Core: phones may change general.theme; theme and interface mode values are checked against THEMES / INTERFACE_MODES for the dashboard, phones and agents alike (purple is refused).
  • Cloud dashboard: people the owner invited (operators, viewers) keep a theme of their own in their browser and never change the owner's.

Screenshots

Sidebar toggle with its tooltip, light and dark:

Home, light (default) and dark:

A chat with a table, code and tool calls:

Settings → General → Appearance:

Tested

  • Playwright against a scratch core + vite: default light with a dark OS, toggle saves the setting, ⌘⇧L, live update when another client changes the setting, new browser follows the saved setting, System follows the OS live, Settings segmented control, palette entry, double click (no flicker, ends right) and a held shortcut (toggles once): 15/15 pass.
  • Screenshots of 40 pages and dialogs in dark checked by eye.
  • tsc for desktop, core, shared and mobile; desktop production build; core tests incl. new theme.test.ts and phone theme cases in mobile.test.ts (3 failures in mods.test.ts / updates.test.ts fail the same way on main).
  • Separate review pass; its findings (stale refresh during a save, theme values on the human/cloud path, cloud non-owners, late crossfade, key repeat) are fixed.
  • Phone app: typechecked only (no simulator build in this run).

- Sidebar toggle, Cmd/Ctrl+Shift+L, palette entry and shortcuts list row
- settings.general.theme is the source of truth for the desktop app, the
  browser dashboard and the phone; localStorage only for the first paint
- Palette swaps in one step with a soft crossfade where supported
- Phone app follows the computer's theme (light until picked) with a
  Light / Dark / System row in Settings
- Core validates theme values for the human, phones and agents
# Conflicts:
#	packages/core/src/services/agentSettings.ts
@danielehrhardt
danielehrhardt merged commit 33204fc into main Oct 19, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant