theseus/nsis/make-icons.mjs
Local Dev 49dde73c6b Ship Theseus 0.2.3 3abaeff7 (new brand icon + multi-panel picker + Startpage default)
Setup    3abaeff73afcecc9e4f05f749765e168a97a377890211dbae4345654c84ce2f1
Portable 71017563d6ba107cb25e24be240abcb78e34491d8f7aa42e095421edbc482a85

Brand: the red-N compass from theseus.x is now the taskbar / titlebar /
File Explorer icon everywhere. Source SVG lives at
site-theseus-x/assets/favicon.svg so brand + browser icon stay in sync.
nsis/make-icons.mjs renders it to build/icon.png (512x512) and
build/icon.ico (multi-resolution: 16/24/32/48/64/128/256). Wired into
package.json: build.win.icon, build.nsis.installerIcon + uninstaller
+ header; the ico ships as an extraResource so main.js's BrowserWindow
also uses it at runtime. Icons live in build/ which is gitignored -
run `node nsis/make-icons.mjs` when the SVG changes.

Sidebar: multi-panel picker strip. When 2+ extensions register sidebar
panels, sidebar-preload.js injects a 32-px tab strip at the top of
every panel's document. Click a tab -> ipcRenderer sidebar-open ->
loadFile switch. Preload also injects box-sizing:border-box + a
33-px body padding so height:100% panels don't overflow. Solo-panel
case is unchanged (strip only appears when panels.length >= 2).

Search: Startpage is the new default. Both the default id and the
enabled-list ordering put it first. DDG stays enabled by default too.

Deploy: scp installers + manifest + tools/ + releases/ to VPS,
sia-upload of both trees, verified HEAD 200 and manifest 0.2.3.

Icons regenerated from theseus.x's favicon.svg; the .svg itself
shipped in the 0.1.x window when the theseus.x site went live.
2026-08-31 16:32:16 +02:00

48 lines
2 KiB
JavaScript

// One-shot script: render site-theseus-x/assets/favicon.svg to the icon
// files electron-builder wants — a 512x512 PNG (main icon) and a multi-
// resolution .ico (Windows taskbar / installer / shortcut icon).
//
// Not in the runtime app bundle; run manually when the brand changes:
// node nsis/make-icons.mjs
// Outputs build/icon.png and build/icon.ico (both gitignored regenerated).
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import sharp from "sharp";
import pngToIco from "png-to-ico";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// SVG source lives in the theseus.x standalone site so the browser icon
// and the site brand stay in lockstep.
const SVG = path.join(__dirname, "..", "..", "site-theseus-x", "assets", "favicon.svg");
// Icons drop into build/, which is gitignored (regenerated artifacts).
// electron-builder picks them up from there via package.json.
const OUT_DIR = path.join(__dirname, "..", "build");
const PNG_512 = path.join(OUT_DIR, "icon.png");
const ICO = path.join(OUT_DIR, "icon.ico");
const TMP_DIR = path.join(OUT_DIR, ".icon-tmp");
const ICO_SIZES = [16, 24, 32, 48, 64, 128, 256];
if (!fs.existsSync(SVG)) throw new Error("SVG not found at " + SVG);
console.log("source:", SVG);
// Main 512x512 PNG for macOS / linux / electron-builder auto-derived Windows.
await sharp(SVG).resize(512, 512).png().toFile(PNG_512);
console.log("wrote", PNG_512);
// Write individual sized PNGs to a temp dir, then feed their paths to
// png-to-ico so it preserves each as a distinct image inside the .ico.
fs.mkdirSync(TMP_DIR, { recursive: true });
const paths = [];
for (const size of ICO_SIZES) {
const p = path.join(TMP_DIR, `icon-${size}.png`);
await sharp(SVG).resize(size, size).png().toFile(p);
paths.push(p);
}
const ico = await pngToIco(paths);
fs.writeFileSync(ICO, ico);
console.log("wrote", ICO, `(${ICO_SIZES.length} sizes)`);
// Clean up the temp PNGs.
for (const p of paths) fs.unlinkSync(p);
fs.rmdirSync(TMP_DIR);