From 50673717aa940c72f57a5d7d19e2e756cde5d312 Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Sat, 22 Aug 2026 19:27:33 +0200 Subject: [PATCH] fix(window): force dark native title bar Apply Electron nativeTheme dark mode before creating the main window so the Windows title bar remains dark across local, server, and RDP user profiles. Add focused coverage for the native theme contract. --- src/main/main.ts | 9 ++++++--- src/main/native-theme.ts | 7 +++++++ tests/native-theme.test.ts | 12 ++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 src/main/native-theme.ts create mode 100644 tests/native-theme.test.ts diff --git a/src/main/main.ts b/src/main/main.ts index 93df68f..c26e946 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; import { pathToFileURL } from "node:url"; -import { app, BrowserWindow, clipboard, dialog, ipcMain, Menu, powerMonitor, safeStorage, shell, Tray, type IpcMainEvent, type IpcMainInvokeEvent } from "electron"; +import { app, BrowserWindow, clipboard, dialog, ipcMain, Menu, nativeTheme, powerMonitor, safeStorage, shell, Tray, type IpcMainEvent, type IpcMainInvokeEvent } from "electron"; import { AddLinksPayload, AppSettings, DebridProvider, EnableRemoteDiagnosticsInput, RendererSettingsUpdate, UpdateInstallProgress } from "../shared/types"; import { AppController } from "./app-controller"; import { IPC_CHANNELS } from "../shared/ipc"; @@ -25,8 +25,11 @@ import { validateRealDebridLoginRequest } from "../shared/preload-api"; import { migrateProductUserDataDirectory } from "./storage"; import { validateCollectorContainerInspectionRequest, validateCollectorInspectionRequest } from "../shared/collector"; import { DailyStartScheduler, hasDailyStartRulePatch, prepareDailyStartSettingsPatch } from "./daily-start-scheduler"; - -function validateString(value: unknown, name: string): string { +import { forceDarkNativeTheme } from "./native-theme"; + +forceDarkNativeTheme(nativeTheme); + +function validateString(value: unknown, name: string): string { if (typeof value !== "string") { throw new Error(`${name} muss ein String sein`); } diff --git a/src/main/native-theme.ts b/src/main/native-theme.ts new file mode 100644 index 0000000..ab2a982 --- /dev/null +++ b/src/main/native-theme.ts @@ -0,0 +1,7 @@ +export interface NativeThemeTarget { + themeSource: string; +} + +export function forceDarkNativeTheme(theme: NativeThemeTarget): void { + theme.themeSource = "dark"; +} diff --git a/tests/native-theme.test.ts b/tests/native-theme.test.ts new file mode 100644 index 0000000..8e5e5be --- /dev/null +++ b/tests/native-theme.test.ts @@ -0,0 +1,12 @@ +import { describe, expect, it } from "vitest"; +import { forceDarkNativeTheme } from "../src/main/native-theme"; + +describe("native window theme", () => { + it("forces the native Windows title bar to use the dark theme", () => { + const theme = { themeSource: "system" }; + + forceDarkNativeTheme(theme); + + expect(theme.themeSource).toBe("dark"); + }); +});