From a32701ef8d6565875d126115389839abaea72c21 Mon Sep 17 00:00:00 2001 From: Theo Browne Date: Thu, 19 Feb 2026 01:21:16 -0800 Subject: [PATCH] use icon --- apps/desktop/src/main.ts | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 55fd1b46b57ebf07dacef5c47c6f6bea44d7f1ee..4e046415593daae3479411b5875e3c493f94f8c7 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -21,6 +21,8 @@ const BACKEND_ENTRY = path.join(ROOT_DIR, "apps/server/dist/index.mjs"); const WEB_ENTRY = path.join(ROOT_DIR, "apps/web/dist/index.html"); const STATE_DIR = path.join(os.homedir(), ".t3", "userdata"); const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL); +const APP_DISPLAY_NAME = "T3 Code"; +const APP_USER_MODEL_ID = "com.t3tools.t3code"; let mainWindow: BrowserWindow | null = null; let backendProcess: ChildProcess | null = null; @@ -31,6 +33,41 @@ let restartAttempt = 0; let restartTimer: ReturnType | null = null; let isQuitting = false; +function resolveResourcePath(fileName: string): string | null { + const candidates = [ + path.join(__dirname, "../resources", fileName), + path.join(process.resourcesPath, "resources", fileName), + path.join(process.resourcesPath, fileName), + ]; + + for (const candidate of candidates) { + if (fs.existsSync(candidate)) { + return candidate; + } + } + + return null; +} + +function resolveIconPath(ext: "ico" | "icns" | "png"): string | null { + return resolveResourcePath(`icon.${ext}`); +} + +function configureAppIdentity(): void { + app.setName(APP_DISPLAY_NAME); + + if (process.platform === "win32") { + app.setAppUserModelId(APP_USER_MODEL_ID); + } + + if (process.platform === "darwin" && app.dock) { + const iconPath = resolveIconPath("png"); + if (iconPath) { + app.dock.setIcon(iconPath); + } + } +} + async function reserveLoopbackPort(): Promise { return new Promise((resolve, reject) => { const probe = net.createServer(); @@ -207,7 +244,8 @@ function registerIpcHandlers(): void { function getIconOption(): { icon: string } | Record { if (process.platform === "darwin") return {}; // macOS uses .icns from app bundle const ext = process.platform === "win32" ? "ico" : "png"; - return { icon: path.join(__dirname, `../resources/icon.${ext}`) }; + const iconPath = resolveIconPath(ext); + return iconPath ? { icon: iconPath } : {}; } function createWindow(): BrowserWindow { @@ -219,6 +257,7 @@ function createWindow(): BrowserWindow { show: false, autoHideMenuBar: true, ...getIconOption(), + title: APP_DISPLAY_NAME, titleBarStyle: "hiddenInset", trafficLightPosition: { x: 16, y: 18 }, webPreferences: { @@ -253,6 +292,8 @@ function createWindow(): BrowserWindow { return window; } +configureAppIdentity(); + async function bootstrap(): Promise { backendPort = await reserveLoopbackPort(); backendAuthToken = randomBytes(24).toString("hex"); -- 2.54.0