diff --git a/build/build_tray_icon.ts b/build/build_tray_icon.ts
new file mode 100644
index 0000000000..2324f43295
--- /dev/null
+++ b/build/build_tray_icon.ts
@@ -0,0 +1,51 @@
+// Generate tray icons from SVG to PNG + different sizes and colors (B&W)
+// Command: `yarn build:tray-icons`
+import path from "path"
+import sharp from "sharp";
+import jsdom from "jsdom"
+import fs from "fs-extra"
+
+export async function generateTrayIcon(
+ {
+ outputFilename = "tray_icon", // e.g. output tray_icon_dark@2x.png
+ svgIconPath = path.resolve(__dirname, "../src/renderer/components/icon/logo-lens.svg"),
+ outputFolder = path.resolve(__dirname, "./icons"),
+ dpiSuffix = "2x",
+ pixelSize = 32,
+ shouldUseDarkColors = false, // managed by electron.nativeTheme.shouldUseDarkColors
+ } = {}) {
+ outputFilename += shouldUseDarkColors ? "_dark" : ""
+ dpiSuffix = dpiSuffix !== "1x" ? `@${dpiSuffix}` : ""
+ const pngIconDestPath = path.resolve(outputFolder, `${outputFilename}${dpiSuffix}.png`)
+ try {
+ // Modify .SVG colors
+ const trayIconColor = shouldUseDarkColors ? "white" : "black";
+ const svgDom = await jsdom.JSDOM.fromFile(svgIconPath);
+ const svgRoot = svgDom.window.document.body.getElementsByTagName("svg")[0];
+ svgRoot.innerHTML += ``
+ const svgIconBuffer = Buffer.from(svgRoot.outerHTML);
+
+ // Resize and convert to .PNG
+ const pngIconBuffer: Buffer = await sharp(svgIconBuffer)
+ .resize({ width: pixelSize, height: pixelSize })
+ .png()
+ .toBuffer();
+
+ // Save icon
+ await fs.writeFile(pngIconDestPath, pngIconBuffer);
+ console.info(`[DONE]: Tray icon saved at "${pngIconDestPath}"`);
+ } catch (err) {
+ console.error(`[ERROR]: ${err}`);
+ }
+}
+
+// Run
+const iconSizes: Record = {
+ "1x": 16,
+ "2x": 32,
+ "3x": 48,
+};
+Object.entries(iconSizes).forEach(([dpiSuffix, pixelSize]) => {
+ generateTrayIcon({ dpiSuffix, pixelSize, shouldUseDarkColors: false });
+ generateTrayIcon({ dpiSuffix, pixelSize, shouldUseDarkColors: true });
+});
diff --git a/build/icons/tray_icon.png b/build/icons/tray_icon.png
new file mode 100644
index 0000000000..73c7346d33
Binary files /dev/null and b/build/icons/tray_icon.png differ
diff --git a/build/icons/tray_icon@2x.png b/build/icons/tray_icon@2x.png
new file mode 100644
index 0000000000..71206802ac
Binary files /dev/null and b/build/icons/tray_icon@2x.png differ
diff --git a/build/icons/tray_icon@3x.png b/build/icons/tray_icon@3x.png
new file mode 100644
index 0000000000..a293ba7d32
Binary files /dev/null and b/build/icons/tray_icon@3x.png differ
diff --git a/build/icons/tray_icon_dark.png b/build/icons/tray_icon_dark.png
new file mode 100644
index 0000000000..568d13e00b
Binary files /dev/null and b/build/icons/tray_icon_dark.png differ
diff --git a/build/icons/tray_icon_dark@2x.png b/build/icons/tray_icon_dark@2x.png
new file mode 100644
index 0000000000..3f28605dbf
Binary files /dev/null and b/build/icons/tray_icon_dark@2x.png differ
diff --git a/build/icons/tray_icon_dark@3x.png b/build/icons/tray_icon_dark@3x.png
new file mode 100644
index 0000000000..5e682a5d82
Binary files /dev/null and b/build/icons/tray_icon_dark@3x.png differ
diff --git a/package.json b/package.json
index e84e3e69b3..eea0c95166 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
"download-bins": "concurrently yarn:download:*",
"download:kubectl": "yarn run ts-node build/download_kubectl.ts",
"download:helm": "yarn run ts-node build/download_helm.ts",
+ "build:tray-icons": "yarn run ts-node build/build_tray_icon.ts",
"lint": "eslint $@ --ext js,ts,tsx --max-warnings=0 src/",
"rebuild-pty": "yarn run electron-rebuild -f -w node-pty"
},
@@ -89,8 +90,8 @@
"filter": "!**/main.js"
},
{
- "from": "src/renderer/components/icon/logo-lens.svg",
- "to": "static/logo.svg"
+ "from": "build/icons/",
+ "to": "build/icons/"
},
"LICENSE"
],
@@ -177,7 +178,6 @@
"@types/node": "^12.12.45",
"@types/proper-lockfile": "^4.1.1",
"@types/react-beautiful-dnd": "^13.0.0",
- "@types/sharp": "^0.26.0",
"@types/tar": "^4.0.3",
"array-move": "^3.0.0",
"chalk": "^4.1.0",
@@ -207,14 +207,13 @@
"openid-client": "^3.15.2",
"path-to-regexp": "^6.1.0",
"proper-lockfile": "^4.1.1",
- "react-beautiful-dnd": "^13.0.0",
"react": "^16.13.1",
+ "react-beautiful-dnd": "^13.0.0",
"react-router": "^5.2.0",
"request": "^2.88.2",
"request-promise-native": "^1.0.8",
"semver": "^7.3.2",
"serializr": "^2.0.3",
- "sharp": "^0.26.1",
"shell-env": "^3.0.0",
"spdy": "^4.0.2",
"tar": "^6.0.2",
@@ -260,6 +259,7 @@
"@types/request": "^2.48.5",
"@types/request-promise-native": "^1.0.17",
"@types/semver": "^7.2.0",
+ "@types/sharp": "^0.26.0",
"@types/shelljs": "^0.8.8",
"@types/spdy": "^3.4.4",
"@types/tcp-port-used": "^1.0.0",
@@ -317,6 +317,7 @@
"react-select": "^3.1.0",
"react-window": "^1.8.5",
"sass-loader": "^8.0.2",
+ "sharp": "^0.26.1",
"spectron": "11.0.0",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^3.0.3",
diff --git a/src/main/tray.ts b/src/main/tray.ts
index 5a43aec50a..72bbf51874 100644
--- a/src/main/tray.ts
+++ b/src/main/tray.ts
@@ -1,9 +1,6 @@
import path from "path"
-import sharp from "sharp";
-import jsdom from "jsdom"
import packageInfo from "../../package.json"
-import { app, dialog, Menu, NativeImage, nativeImage, nativeTheme, Tray } from "electron"
-import { isDevelopment, isMac } from "../common/vars";
+import { app, dialog, Menu, NativeImage, nativeTheme, Tray } from "electron"
import { autorun } from "mobx";
import { showAbout } from "./menu";
import { AppUpdater } from "./app-updater";
@@ -16,26 +13,22 @@ import logger from "./logger";
// note: instance of Tray should be saved somewhere, otherwise it disappears
export let tray: Tray;
-export let trayIcon: NativeImage;
-export const trayIconPath = isDevelopment
- ? path.resolve(__static, "../src/renderer/components/icon/logo-lens.svg")
- : path.resolve(__static, "logo.svg") // electron-builder's extraResources
+// refresh icon when MacOS dark/light theme has changed
+nativeTheme.on("updated", () => tray?.setImage(getTrayIcon()));
-// update icon when MacOS dark/light theme has changed
-nativeTheme.on("updated", async () => {
- if (tray) {
- trayIcon = await createTrayIconFromSvg();
- tray.setImage(trayIcon);
- }
-});
-
-export async function initTray(windowManager: WindowManager) {
- trayIcon = await createTrayIconFromSvg(); // generate icon once on tray activation
+export function getTrayIcon(isDark = nativeTheme.shouldUseDarkColors): string {
+ return path.resolve(__static, "../build/icons", `tray_icon${isDark ? "_dark" : ""}.png`)
+}
+export function initTray(windowManager: WindowManager) {
const dispose = autorun(() => {
- const menu = createTrayMenu(windowManager);
- buildTray(trayIcon, menu);
+ try {
+ const menu = createTrayMenu(windowManager);
+ buildTray(getTrayIcon(), menu);
+ } catch (err) {
+ logger.error(`[TRAY]: building failed: ${err}`);
+ }
})
return () => {
dispose();
@@ -44,24 +37,7 @@ export async function initTray(windowManager: WindowManager) {
}
}
-export async function createTrayIconFromSvg(filePath = trayIconPath): Promise {
- // modify icon's svg
- const svgDom = await jsdom.JSDOM.fromFile(filePath);
- const svgRoot = svgDom.window.document.body.getElementsByTagName("svg")[0];
- const trayIconColor = nativeTheme.shouldUseDarkColors ? "white" : "black";
- svgRoot.innerHTML += ``
- const svgIconBuffer = Buffer.from(svgRoot.outerHTML);
-
- // convert to .png or .ico and resize
- const pngIcon = await sharp(svgIconBuffer).png().toBuffer();
- const iconSize = isMac ? 16 : 32; // todo: verify on windows/linux
- return nativeImage.createFromBuffer(pngIcon).resize({
- width: iconSize,
- height: iconSize
- });
-}
-
-export async function buildTray(icon: NativeImage, menu: Menu) {
+export function buildTray(icon: string | NativeImage, menu: Menu) {
logger.info("[TRAY]: build start");
if (!tray) {
diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts
index e768058fb3..fcee752b05 100644
--- a/src/main/window-manager.ts
+++ b/src/main/window-manager.ts
@@ -81,10 +81,10 @@ export class WindowManager {
this.disposers.menuAutoUpdater = initMenu(this);
}
- protected async initTray() {
- this.disposers.trayAutoBind = reaction(() => userStore.preferences.trayEnabled, async isEnabled => {
+ protected initTray() {
+ this.disposers.trayAutoBind = reaction(() => userStore.preferences.trayEnabled, isEnabled => {
if (isEnabled) {
- this.disposers.trayAutoUpdater = await initTray(this);
+ this.disposers.trayAutoUpdater = initTray(this);
} else if (this.disposers.trayAutoUpdater) {
this.disposers.trayAutoUpdater();
}
diff --git a/src/renderer/components/icon/logo-kontena.svg b/src/renderer/components/icon/logo-kontena.svg
deleted file mode 100644
index 6b05f1ba17..0000000000
--- a/src/renderer/components/icon/logo-kontena.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
\ No newline at end of file