feat: implement light mode with settings toggle

Add appearance theme support (dark/light/system) using CSS custom
property overrides. In light mode the Tailwind zinc scale is inverted
and semantic surface/border tokens are swapped, so all existing
utility classes pick up the new palette automatically.

- Add AppearanceTheme type and theme field to WorkspaceSettings
- Add setTheme IPC channel wiring (contracts, preload, handler, service)
- Add [data-theme='light'] CSS overrides for zinc scale, surface tokens,
  scrollbar, and markdown prose colours
- Add Appearance section to SettingsPanel with radio-button theme picker
- Apply data-theme attribute on document root via useEffect in App.tsx,
  with matchMedia listener for the system option

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-24 19:28:48 +01:00
co-authored by Copilot
parent 33c4cee0b4
commit 973e5eb25c
11 changed files with 174 additions and 14 deletions
+8
View File
@@ -51,6 +51,8 @@ import {
} from '@shared/domain/runTimeline';
import {
createSessionToolingSelection,
normalizeTheme,
type AppearanceTheme,
type LspProfileDefinition,
type McpServerDefinition,
normalizeLspProfileDefinition,
@@ -201,6 +203,12 @@ export class EryxAppService extends EventEmitter<AppServiceEvents> {
return this.persistAndBroadcast(workspace);
}
async setTheme(theme: AppearanceTheme): Promise<WorkspaceState> {
const workspace = await this.loadWorkspace();
workspace.settings.theme = normalizeTheme(theme);
return this.persistAndBroadcast(workspace);
}
async deletePattern(patternId: string): Promise<WorkspaceState> {
if (isBuiltinPattern(patternId)) {
throw new Error('Built-in patterns cannot be deleted.');
+4
View File
@@ -16,6 +16,7 @@ import type {
UpdateScratchpadSessionConfigInput,
} from '@shared/contracts/ipc';
import type { QuerySessionsInput } from '@shared/domain/sessionLibrary';
import type { AppearanceTheme } from '@shared/domain/tooling';
import { EryxAppService } from '@main/EryxAppService';
@@ -33,6 +34,9 @@ export function registerIpcHandlers(window: BrowserWindow, service: EryxAppServi
ipcMain.handle(ipcChannels.setPatternFavorite, (_event, input: SetPatternFavoriteInput) =>
service.setPatternFavorite(input.patternId, input.isFavorite),
);
ipcMain.handle(ipcChannels.setTheme, (_event, theme: AppearanceTheme) =>
service.setTheme(theme),
);
ipcMain.handle(ipcChannels.saveMcpServer, (_event, input: SaveMcpServerInput) =>
service.saveMcpServer(input.server),
);