fix: proper macOS dock icon via .icns bundle replacement
Replace the Swift squircle hack with the correct Apple approach: generate a proper .icns using sips + iconutil, then replace electron.icns in the Electron bundle before launch. macOS applies its native squircle mask + shadow from the .icns automatically.
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:ts": "tsc",
|
"build:ts": "tsc",
|
||||||
"dev": "mkdir -p build && cp ../../icon.png build/icon.png && node -e \"try{require('child_process').execSync('swift scripts/gen-dock-icon.swift',{stdio:'inherit'})}catch(e){}\" && tsc && electron .",
|
"dev": "mkdir -p build && cp ../../icon.png build/icon.png && bash scripts/gen-icns.sh && cp build/icon.icns $(find ../../node_modules -path '*/electron/dist/Electron.app/Contents/Resources/electron.icns' 2>/dev/null | head -1) 2>/dev/null; tsc && electron .",
|
||||||
"prebuild": "mkdir -p build && cp ../../icon.png build/icon.png",
|
"prebuild": "mkdir -p build && cp ../../icon.png build/icon.png",
|
||||||
"build": "tsc && electron-builder",
|
"build": "tsc && electron-builder",
|
||||||
"clean": "rm -rf dist dist-electron"
|
"clean": "rm -rf dist dist-electron"
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
// Generates a squircle-masked dock icon for macOS dev mode.
|
|
||||||
// macOS only applies the squircle mask to packaged .app bundles,
|
|
||||||
// so app.dock.setIcon() needs a pre-masked PNG.
|
|
||||||
|
|
||||||
import AppKit
|
|
||||||
|
|
||||||
let src = NSImage(contentsOfFile: "build/icon.png")!
|
|
||||||
let size = src.size
|
|
||||||
let out = NSImage(size: size)
|
|
||||||
|
|
||||||
out.lockFocus()
|
|
||||||
let radius = size.width * 0.2237
|
|
||||||
let path = NSBezierPath(roundedRect: NSRect(origin: .zero, size: size), xRadius: radius, yRadius: radius)
|
|
||||||
path.addClip()
|
|
||||||
src.draw(in: NSRect(origin: .zero, size: size), from: NSRect(origin: .zero, size: size), operation: .sourceOver, fraction: 1.0)
|
|
||||||
out.unlockFocus()
|
|
||||||
|
|
||||||
let tiff = out.tiffRepresentation!
|
|
||||||
let rep = NSBitmapImageRep(data: tiff)!
|
|
||||||
let png = rep.representation(using: .png, properties: [:])!
|
|
||||||
try! png.write(to: URL(fileURLWithPath: "build/icon-dock.png"))
|
|
||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Generates a proper macOS .icns from the master icon PNG using Apple's iconutil.
|
||||||
|
# macOS applies squircle mask + shadow natively from .icns — no manual masking needed.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SRC="build/icon.png"
|
||||||
|
ICONSET="build/icon.iconset"
|
||||||
|
|
||||||
|
mkdir -p "$ICONSET"
|
||||||
|
sips -z 16 16 "$SRC" --out "$ICONSET/icon_16x16.png" >/dev/null
|
||||||
|
sips -z 32 32 "$SRC" --out "$ICONSET/icon_16x16@2x.png" >/dev/null
|
||||||
|
sips -z 32 32 "$SRC" --out "$ICONSET/icon_32x32.png" >/dev/null
|
||||||
|
sips -z 64 64 "$SRC" --out "$ICONSET/icon_32x32@2x.png" >/dev/null
|
||||||
|
sips -z 128 128 "$SRC" --out "$ICONSET/icon_128x128.png" >/dev/null
|
||||||
|
sips -z 256 256 "$SRC" --out "$ICONSET/icon_128x128@2x.png" >/dev/null
|
||||||
|
sips -z 256 256 "$SRC" --out "$ICONSET/icon_256x256.png" >/dev/null
|
||||||
|
sips -z 512 512 "$SRC" --out "$ICONSET/icon_256x256@2x.png" >/dev/null
|
||||||
|
sips -z 512 512 "$SRC" --out "$ICONSET/icon_512x512.png" >/dev/null
|
||||||
|
sips -z 1024 1024 "$SRC" --out "$ICONSET/icon_512x512@2x.png" >/dev/null
|
||||||
|
|
||||||
|
iconutil -c icns "$ICONSET" -o build/icon.icns
|
||||||
|
rm -rf "$ICONSET"
|
||||||
@@ -513,16 +513,6 @@ if (!gotTheLock) {
|
|||||||
// ─── App Lifecycle ──────────────────────────────────────────────────────────
|
// ─── App Lifecycle ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
app.whenReady().then(async () => {
|
app.whenReady().then(async () => {
|
||||||
// Set dock icon on macOS (overrides default Electron icon in dev mode)
|
|
||||||
if (process.platform === 'darwin' && app.dock) {
|
|
||||||
const dockIcon = path.join(__dirname, '..', 'build', 'icon-dock.png');
|
|
||||||
const fallbackIcon = path.join(__dirname, '..', 'build', 'icon.png');
|
|
||||||
const iconPath = fs.existsSync(dockIcon) ? dockIcon : fallbackIcon;
|
|
||||||
if (fs.existsSync(iconPath)) {
|
|
||||||
app.dock.setIcon(iconPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// macOS application menu with "Change Instance"
|
// macOS application menu with "Change Instance"
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
const appMenu = Menu.buildFromTemplate([
|
const appMenu = Menu.buildFromTemplate([
|
||||||
|
|||||||
Reference in New Issue
Block a user