- Add theme variables and restyle popup/options using Primary 3 as background and Primary 2 as surfaces; accents use Primary 1.\n- Move Save to a footer section on the options page; add responsive layout and button variants.\n- Update icon build defaults to use Primary 2 for add-on and Primary 1 for toolbar icons.\n- Add build-and-commit helper to run build, stage generated assets, commit, and optionally push.\n- Add npm scripts: build:commit and build:commit:push.
90 lines
3 KiB
JavaScript
90 lines
3 KiB
JavaScript
#!/usr/bin/env node
|
||
/*
|
||
Generates extension and toolbar PNG icons from the base SVG with transparent
|
||
background and configurable stroke colors. Requires ImageMagick (`magick`).
|
||
|
||
Theme defaults (aligned with project palette):
|
||
Primary 2 (deep): #223544 → add-on icon strokes (default)
|
||
Primary 1 (light): #5AC3D6 → toolbar icon strokes (default)
|
||
|
||
Override via environment variables (optional):
|
||
ICON_COLOR_ADDON – hex color for add-on icons (48/96/128). Default: #223544
|
||
ICON_COLOR_TOOLBAR – hex color for toolbar icons (16/32). Default: #5AC3D6
|
||
|
||
Usage:
|
||
node scripts/build-icons.js
|
||
*/
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const { spawnSync } = require('child_process');
|
||
|
||
const REPO_ROOT = path.join(__dirname, '..');
|
||
const ICONS_DIR = path.join(REPO_ROOT, 'icons');
|
||
const SRC_SVG = path.join(ICONS_DIR, 'file-search.svg');
|
||
|
||
const ADDON_SIZES = [48, 96, 128];
|
||
const TOOLBAR_SIZES = [16, 32];
|
||
|
||
const COLOR_ADDON = process.env.ICON_COLOR_ADDON || '#223544';
|
||
const COLOR_TOOLBAR = process.env.ICON_COLOR_TOOLBAR || '#5AC3D6';
|
||
|
||
function ensureMagick() {
|
||
// Prefer calling binaries directly to avoid shell init output polluting stdout.
|
||
let ok = spawnSync('magick', ['-version']);
|
||
if (ok && ok.status === 0) return 'magick';
|
||
ok = spawnSync('convert', ['-version']);
|
||
if (ok && ok.status === 0) return 'convert';
|
||
return null;
|
||
}
|
||
|
||
function readSvg() {
|
||
if (!fs.existsSync(SRC_SVG)) {
|
||
console.error(`Base SVG not found: ${path.relative(REPO_ROOT, SRC_SVG)}`);
|
||
process.exit(1);
|
||
}
|
||
return fs.readFileSync(SRC_SVG, 'utf8');
|
||
}
|
||
|
||
function colorize(svg, color) {
|
||
// Replace currentColor with explicit hex color. Keep case-insensitive safety.
|
||
return svg.replace(/currentColor/gi, color);
|
||
}
|
||
|
||
function rasterize(magickBin, svgString, size, outPath) {
|
||
// Use ImageMagick, transparent background, high density for crisp vector rasterization.
|
||
const args = ['-background', 'none', '-density', '384', 'svg:-', '-resize', `${size}x${size}`, outPath];
|
||
const proc = spawnSync(magickBin, args, { input: svgString, stdio: ['pipe', 'inherit', 'inherit'] });
|
||
if (proc.status !== 0) {
|
||
console.error(`Failed to generate ${outPath}`);
|
||
process.exit(proc.status || 1);
|
||
}
|
||
}
|
||
|
||
function main() {
|
||
const magick = ensureMagick();
|
||
if (!magick) {
|
||
console.error('ImageMagick not found. Please install it or adjust this script to use inkscape/rsvg-convert.');
|
||
process.exit(1);
|
||
}
|
||
if (!fs.existsSync(ICONS_DIR)) fs.mkdirSync(ICONS_DIR, { recursive: true });
|
||
|
||
const base = readSvg();
|
||
|
||
// Add-on icons
|
||
const addonSvg = colorize(base, COLOR_ADDON);
|
||
for (const s of ADDON_SIZES) {
|
||
const out = path.join(ICONS_DIR, `icon-${s}.png`);
|
||
rasterize(magick, addonSvg, s, out);
|
||
console.log(`Generated ${path.relative(REPO_ROOT, out)}`);
|
||
}
|
||
|
||
// Toolbar icons
|
||
const toolbarSvg = colorize(base, COLOR_TOOLBAR);
|
||
for (const s of TOOLBAR_SIZES) {
|
||
const out = path.join(ICONS_DIR, `icon-${s}.png`);
|
||
rasterize(magick, toolbarSvg, s, out);
|
||
console.log(`Generated ${path.relative(REPO_ROOT, out)}`);
|
||
}
|
||
}
|
||
|
||
main();
|