diff --git a/electron/electronAPI.d.ts b/electron/electronAPI.d.ts index c9bd56e84..7a0788abc 100644 --- a/electron/electronAPI.d.ts +++ b/electron/electronAPI.d.ts @@ -120,6 +120,8 @@ export interface ElectronAPI { sendSettingsUpdate(globalCfg: GlobalConfigState): void; + updateTitleBarDarkMode(isDarkMode: boolean): void; + registerGlobalShortcuts(keyboardConfig: KeyboardConfig): void; showFullScreenBlocker(args: { msg?: string; takeABreakCfg: TakeABreakConfig }): void; diff --git a/electron/main-window.ts b/electron/main-window.ts index fece7210b..a6eb993d6 100644 --- a/electron/main-window.ts +++ b/electron/main-window.ts @@ -7,6 +7,7 @@ import { Menu, MenuItem, MenuItemConstructorOptions, + nativeTheme, shell, } from 'electron'; import { errorHandlerWithFrontendInform } from './error-handler-with-frontend-inform'; @@ -85,11 +86,13 @@ export const createWindow = async ({ persistedIsUseCustomWindowTitleBar ?? legacyIsUseObsidianStyleHeader ?? true; const titleBarStyle: BrowserWindowConstructorOptions['titleBarStyle'] = isUseCustomWindowTitleBar || IS_MAC ? 'hidden' : 'default'; + // Determine initial symbol color based on system theme preference + const initialSymbolColor = nativeTheme.shouldUseDarkColors ? '#fff' : '#000'; const titleBarOverlay: BrowserWindowConstructorOptions['titleBarOverlay'] = isUseCustomWindowTitleBar && !IS_MAC ? { color: '#00000000', - symbolColor: '#fff', + symbolColor: initialSymbolColor, height: 44, } : undefined; @@ -221,6 +224,23 @@ export const createWindow = async ({ mainWinModule.isAppReady = true; }); + // Listen for theme changes to update title bar overlay symbol color + if (isUseCustomWindowTitleBar && !IS_MAC) { + ipcMain.on(IPC.UPDATE_TITLE_BAR_DARK_MODE, (ev, isDarkMode: boolean) => { + try { + const symbolColor = isDarkMode ? '#fff' : '#000'; + mainWin.setTitleBarOverlay({ + color: '#00000000', + symbolColor, + height: 44, + }); + } catch (e) { + // setTitleBarOverlay may not be available on all platforms + log('Failed to update title bar overlay:', e); + } + }); + } + return mainWin; }; diff --git a/electron/preload.ts b/electron/preload.ts index c64c965fd..17a305aa8 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -99,6 +99,8 @@ const ea: ElectronAPI = { sendAppSettingsToElectron: (globalCfg) => _send('TRANSFER_SETTINGS_TO_ELECTRON', globalCfg), sendSettingsUpdate: (globalCfg) => _send('UPDATE_SETTINGS', globalCfg), + updateTitleBarDarkMode: (isDarkMode: boolean) => + _send('UPDATE_TITLE_BAR_DARK_MODE', isDarkMode), registerGlobalShortcuts: (keyboardCfg) => _send('REGISTER_GLOBAL_SHORTCUTS', keyboardCfg), showFullScreenBlocker: (args) => _send('FULL_SCREEN_BLOCKER', args), diff --git a/electron/shared-with-frontend/ipc-events.const.ts b/electron/shared-with-frontend/ipc-events.const.ts index 1b71842f8..dffeefc43 100644 --- a/electron/shared-with-frontend/ipc-events.const.ts +++ b/electron/shared-with-frontend/ipc-events.const.ts @@ -69,6 +69,7 @@ export enum IPC { PLUGIN_EXEC_NODE_SCRIPT = 'PLUGIN_EXEC_NODE_SCRIPT', UPDATE_SETTINGS = 'UPDATE_SETTINGS', + UPDATE_TITLE_BAR_DARK_MODE = 'UPDATE_TITLE_BAR_DARK_MODE', // maybe_UPDATE_CURRENT_TASK = 'UPDATE_CURRENT_TASK', // maybe_IS_IDLE = 'IS_IDLE', diff --git a/src/app/core/theme/global-theme.service.ts b/src/app/core/theme/global-theme.service.ts index c436a6ea5..e3ac59f84 100644 --- a/src/app/core/theme/global-theme.service.ts +++ b/src/app/core/theme/global-theme.service.ts @@ -5,6 +5,7 @@ import { Injectable, runInInjectionContext, signal, + untracked, } from '@angular/core'; import { toObservable, toSignal } from '@angular/core/rxjs-interop'; import { BodyClass, IS_ELECTRON } from '../../app.constants'; @@ -231,6 +232,19 @@ export class GlobalThemeService { this._setColorTheme(theme), ); this._isDarkThemeObs$.subscribe((isDarkTheme) => this._setDarkTheme(isDarkTheme)); + + // Update Electron title bar overlay when dark mode changes + if (IS_ELECTRON && !IS_MAC) { + effect(() => { + const isDark = this.isDarkTheme(); + // Use untracked to prevent reading misc from creating a dependency + const misc = untracked(() => this._globalConfigService.misc()); + // Only update if custom window title bar is enabled + if (misc?.isUseCustomWindowTitleBar !== false) { + window.ea.updateTitleBarDarkMode(isDark); + } + }); + } } private _initHandlersForInitialBodyClasses(): void {