From 33df72c6f4cac6b7179013e5a7205f6cc3030326 Mon Sep 17 00:00:00 2001 From: Xu Liang Date: Sun, 31 May 2026 14:12:35 +0800 Subject: [PATCH] feat(tray): add Windows tray icon support and update icon selection logic --- apps/desktop-client/scripts/generate-brand-icons.cjs | 4 ++++ apps/desktop-client/src/main/brand-icons.ts | 4 ++++ apps/desktop-client/src/main/tray.ts | 9 ++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/desktop-client/scripts/generate-brand-icons.cjs b/apps/desktop-client/scripts/generate-brand-icons.cjs index 6ff52f7..2c40596 100644 --- a/apps/desktop-client/scripts/generate-brand-icons.cjs +++ b/apps/desktop-client/scripts/generate-brand-icons.cjs @@ -176,6 +176,7 @@ function buildMainProcessIcons() { // Tray icons are 32x32 px and loaded @2x in tray.ts (=> ~16pt on retina). // Glyph size is controlled by targetH in trayLogoSvg(), not by an rsvg -h. const trayNormal = b64(svgToPng(trayLogoSvg(), 'tray-normal')) + const trayWindows = b64(svgToPng(trayLogoSvg(BRAND_BLUE), 'tray-windows')) const trayDanger = b64(svgToPng(trayLogoSvg(DANGER_RED), 'tray-danger')) // Dock / window icons: logo on the brand plate (normal) and danger plate. @@ -200,6 +201,9 @@ function buildMainProcessIcons() { '// macOS menu-bar template silhouette (rendered @2x).', `export const TRAY_ICON_BASE64 =\n '${trayNormal}'`, '', + '// Windows tray icon: brand-blue silhouette for light tray flyouts.', + `export const TRAY_WINDOWS_ICON_BASE64 =\n '${trayWindows}'`, + '', '// Tray icon shown when accounts have health issues (rendered @2x, not a template).', `export const TRAY_DANGER_ICON_BASE64 =\n '${trayDanger}'`, '', diff --git a/apps/desktop-client/src/main/brand-icons.ts b/apps/desktop-client/src/main/brand-icons.ts index 42e9e03..04f0835 100644 --- a/apps/desktop-client/src/main/brand-icons.ts +++ b/apps/desktop-client/src/main/brand-icons.ts @@ -7,6 +7,10 @@ export const TRAY_ICON_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAACt0lEQVRYhe1WPWgUQRT+3ty6ZqM5jAYvCJqbNTHEwiKkCAiRExvRxspOQbCwiIVoYSGEYCEp/GnEQkgrplEiNrEJWBhEBAnEI97OXC4EEaIgXgzJ7jwLN+GyucvdJppC74OFnffzvW/evP0B6qjjfwfFTchmsy22bb8GcJCZB/L5/L1MJuNvVoCIm2Db9nEAnQAaiWgonU5PaK27t00AEUVzuo0xE1rroUKh4Px1AUEQfALwMyLKYuYbQRB80FqfjMNXdQY8z3tMRJlw+WV+fr6vp6dnGQCmp6eTlmWNAugrSWEAw0KI621tbd+q8VftgBDiBAA3vHpTqVTTiq+jo+M7EY1HUgjAJWPMlFLq/JYFbAEpAE+01qO5XO5QpaA1RzAzM3OAmRsAwBgzJ6VcVEq9BHA6DPns+37atu3DABxjjAXgAYAuAAER7WDm3euKEP0wxtyUUj4kIlNWQD6fP2qMmSyxPZJSXomS5XK5U0KIsRLTMynlOQBgZqG1HgZwocKG3wRBcLm9vX1yxVB6BM2RjuwvxyCE2BfZ3WzJvWHmtxWKA0BvIpEYZ+ZEOQE1gZl5Iz8RNVahmMXvJwUAYK0qEWLKGPOciHaFhUYAQCnVC+BYSF4wxkwAGCUih5l9Zn6nlBoA0EBECWa+WKHwEoC7juPcLp2Dqu8BpVQWwJFQlE9ETVLKxRW/53m3iGiwCs0YM/e7rpuNOqxy0ZViiMhaWFhYk0NEG3EUmPm667pPq5JXQjhYq+tkMhmU+pm5hWhdI5cA3HccZ7C1tbW4EX8tHbiKcAaYec73/Z1KqTtE1MzMTcx8NiL4FTP3Syk/1sAd/39Aa32GmV+sIyKaNcZcc113JA7fZr6GUdHLAIaKxWJX3OJAbUewBrZtv/d9/yuAvXHb/ceglNrjeV7nthato45/Fr8AC58XxWfGw7UAAAAASUVORK5CYII=' +// Windows tray icon: brand-blue silhouette for light tray flyouts. +export const TRAY_WINDOWS_ICON_BASE64 = + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABsklEQVR42u1WTyhlURzWM+I1EtK3oGbKhsSGxSg7zUaULDAbZWX1tnwrhQ3DapJsWLCfiKJYWbGxmJ1JNjOLkaIkCuVzTh11OznvzeO5NvdX3+b8fvd83/39u7eoKLHEEsvTQNWAOgJ1bTAK6kPcAnpBKYJDUK1xCujzBFjcg5oFlY5DQAuom2dEWByD6iw04RKoE4d9UCURXwWoPU/EA6hlUFWFEnDsEVR7/qlANk5BDb6ngCdsgvr0v2S1oOodytzZVuSyf6BKQTWZi9tAfQF1AOoS1AWoq4AIe54xYlPZyJtc/Z4eWgzEffUuX4v4UqBWsmTD9lBzSECHF/wzEDfoxc17/kyOkpyDKn6NgIEcAsZyCPj1bClsc4FaN0J2Hb6583ZQIw5doD6bzbfhYrZBDYOaMD0zA2oO1FmA+Nb0z7SJ+ZjvFPz2Nl6Z5x/P8cYWO6AaXjqGJ95l5Z5/MgvxH1uyQu+BtOdfCKT7e97pDgiwdafDEKhKs2Z/mF2xakfQlSVKbnuj8S0/Rt2BdP8F1R/H17DHI75z6S6P63+gzi2Tt093FhGVLx6rxBJLzLNHNYJJiPdgfH4AAAAASUVORK5CYII=' + // Tray icon shown when accounts have health issues (rendered @2x, not a template). export const TRAY_DANGER_ICON_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAACl0lEQVRYhe2WS0hUcRTGf+fOdXyUoaVJQREFiQkuZiUERtFG8t6ZFkO7gqBFC1tELVoEg7QIFz02ERK4jVykM5qgLUZokUQJIZjQJhSJoCRTHOdxTwttdK4zjjOYi5oPLtz/Od/5zvd/3AeUUML/Dim0QC2rDow3wBFUQywuPJRoNFmsAaOImtNAI1CFSDfVNeNqWb7dM6CGq0Z9YIyr7e/WYLDy7xvw8BlYdkVNlNvE4h/Vss4VIpf3DKhlPwPOrtG/caihTXp6EgDa3r4P0xsB2jaWoNKLJm7J0NB8Pv1trICcATm+etHKl/nqdGZ4eAF0zF2A6FUMc0o7/Jd2wEDRaEB4rpYdUcs6mouUsQVq24dJlVUAsPR9TqLRmFr2K5D2NcpXkvFjeL0nSEolppo4PAaagBRQBuzN0mcR0Tv4fE8kFHKyGlC//xQOk+mY8FTCA9fdSur3n8dhdEOoXyIDFwE0FDL4MNGLcjnHhN/iGNdk6OXkn8D6FqjWZqyIysGsEikOZDqS2fRsQiEH9F2O5gCtGM6YBoOezQa2CxHdmmBU5VGYpbk5rWGmwyvlU3gTA6juWdVx+gDUsloRTwsAygwpYxxPKoJSiZBEeK92IIRqBeBBnSs5nu448ICV5Xsbz0H+94Dtn0Y5uTZM8utntUSjsfV84C6qXVuryCjidEo4PO3OmNnomQ7U3ODTpL7e3JzPiRmQWxLpf5GLkN8A4rgCKde4LktRHNVHxGNdMjKytJX6dgzcAG1Zu58jkShXy38fqAWqgY4MuvIacTplMPIpv3Yx/wO2fQGVwSxKs6A3JRzuK0SviM+xx206gWo35d6mQpvDtrbAbSAxgXh+APsLXe4dgwYCNWrbjbvatIQS/ln8Bo995P1hCXtRAAAAAElFTkSuQmCC' diff --git a/apps/desktop-client/src/main/tray.ts b/apps/desktop-client/src/main/tray.ts index efd3fc5..7c9a867 100644 --- a/apps/desktop-client/src/main/tray.ts +++ b/apps/desktop-client/src/main/tray.ts @@ -2,7 +2,7 @@ import { nativeImage } from 'electron/common' import type { Tray as ElectronTray } from 'electron/main' import { Menu, Tray, app } from 'electron/main' -import { TRAY_DANGER_ICON_BASE64, TRAY_ICON_BASE64 } from './brand-icons' +import { TRAY_DANGER_ICON_BASE64, TRAY_ICON_BASE64, TRAY_WINDOWS_ICON_BASE64 } from './brand-icons' type TrayIconImage = ReturnType @@ -32,12 +32,15 @@ function createTrayIcon(tone: 'normal' | 'danger'): TrayIconImage { return normalTrayIcon } - const buffer = Buffer.from(TRAY_ICON_BASE64, 'base64') + const buffer = Buffer.from( + process.platform === 'win32' ? TRAY_WINDOWS_ICON_BASE64 : TRAY_ICON_BASE64, + 'base64', + ) const icon = nativeImage.createFromBuffer(buffer, { scaleFactor: TRAY_ICON_SCALE_FACTOR }) if (icon.isEmpty()) { return nativeImage.createEmpty() } - icon.setTemplateImage(true) + icon.setTemplateImage(process.platform === 'darwin') normalTrayIcon = icon return icon }