diff --git a/src/main/index.ts b/src/main/index.ts index 78304a8..ae4eb8b 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -3,6 +3,7 @@ import { app, BrowserWindow } from 'electron'; import { registerIpcHandlers } from '@main/ipc/registerIpcHandlers'; import { EryxAppService } from '@main/EryxAppService'; import { createMainWindow } from '@main/windows/createMainWindow'; +import { applyTitleBarTheme } from '@main/windows/titleBarTheme'; let mainWindow: BrowserWindow | undefined; let appService: EryxAppService | undefined; @@ -13,6 +14,10 @@ async function bootstrap(): Promise { mainWindow = createMainWindow(); registerIpcHandlers(mainWindow, appService); + // Apply persisted theme to the title bar overlay + const workspace = await appService.loadWorkspace(); + applyTitleBarTheme(mainWindow, workspace.settings.theme); + if (!app.isPackaged) { mainWindow.webContents.openDevTools({ mode: 'detach' }); } diff --git a/src/main/ipc/registerIpcHandlers.ts b/src/main/ipc/registerIpcHandlers.ts index 4447443..9d96c35 100644 --- a/src/main/ipc/registerIpcHandlers.ts +++ b/src/main/ipc/registerIpcHandlers.ts @@ -19,6 +19,7 @@ import type { QuerySessionsInput } from '@shared/domain/sessionLibrary'; import type { AppearanceTheme } from '@shared/domain/tooling'; import { EryxAppService } from '@main/EryxAppService'; +import { applyTitleBarTheme } from '@main/windows/titleBarTheme'; export function registerIpcHandlers(window: BrowserWindow, service: EryxAppService): void { ipcMain.handle(ipcChannels.describeSidecarCapabilities, () => service.describeSidecarCapabilities()); @@ -34,9 +35,11 @@ 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.setTheme, async (_event, theme: AppearanceTheme) => { + const result = await service.setTheme(theme); + applyTitleBarTheme(window, theme); + return result; + }); ipcMain.handle(ipcChannels.saveMcpServer, (_event, input: SaveMcpServerInput) => service.saveMcpServer(input.server), ); diff --git a/src/main/windows/titleBarTheme.ts b/src/main/windows/titleBarTheme.ts new file mode 100644 index 0000000..1595e4c --- /dev/null +++ b/src/main/windows/titleBarTheme.ts @@ -0,0 +1,38 @@ +import { nativeTheme, type BrowserWindow } from 'electron'; + +import type { AppearanceTheme } from '@shared/domain/tooling'; + +interface TitleBarColors { + backgroundColor: string; + overlay: { color: string; symbolColor: string }; +} + +const darkColors: TitleBarColors = { + backgroundColor: '#09090b', + overlay: { color: '#09090b', symbolColor: '#a1a1aa' }, +}; + +const lightColors: TitleBarColors = { + backgroundColor: '#ffffff', + overlay: { color: '#ffffff', symbolColor: '#52525b' }, +}; + +function resolveEffectiveTheme(theme: AppearanceTheme): 'dark' | 'light' { + if (theme === 'light') return 'light'; + if (theme === 'dark') return 'dark'; + return nativeTheme.shouldUseDarkColors ? 'dark' : 'light'; +} + +function colorsForTheme(theme: AppearanceTheme): TitleBarColors { + return resolveEffectiveTheme(theme) === 'light' ? lightColors : darkColors; +} + +export function applyTitleBarTheme(window: BrowserWindow, theme: AppearanceTheme): void { + const { backgroundColor, overlay } = colorsForTheme(theme); + window.setBackgroundColor(backgroundColor); + + // setTitleBarOverlay is only available on Windows (and some Linux WMs). + if (typeof window.setTitleBarOverlay === 'function') { + window.setTitleBarOverlay(overlay); + } +}