/** * Generate brand image assets from the icon-only master mark. * Usage (from repo root): node scripts/generate-brand-icons.mjs * * Requires: npm install sharp to-ico (dev/one-off; or already present) */ import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import sharp from 'sharp' import toIco from 'to-ico' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const root = path.resolve(__dirname, '..') const master = path.join(__dirname, 'brand-assets', 'hedena-icon.webp') if (!fs.existsSync(master)) { console.error('Missing master:', master) process.exit(1) } async function writePng(outPath, size) { await fs.promises.mkdir(path.dirname(outPath), { recursive: true }) await sharp(master) .resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 1 } }) .png() .toFile(outPath) console.log('wrote', path.relative(root, outPath)) } async function writeWebp(outPath, size) { await fs.promises.mkdir(path.dirname(outPath), { recursive: true }) await sharp(master) .resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 1 } }) .webp({ quality: 90 }) .toFile(outPath) console.log('wrote', path.relative(root, outPath)) } async function writeFull(outPath, format) { await fs.promises.mkdir(path.dirname(outPath), { recursive: true }) const pipeline = sharp(master) if (format === 'png') await pipeline.png().toFile(outPath) else await pipeline.webp({ quality: 90 }).toFile(outPath) console.log('wrote', path.relative(root, outPath)) } async function writeIco(outPath, sizes = [16, 32, 48]) { const bufs = await Promise.all( sizes.map((s) => sharp(master) .resize(s, s, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 1 } }) .png() .toBuffer(), ), ) const ico = await toIco(bufs) await fs.promises.mkdir(path.dirname(outPath), { recursive: true }) await fs.promises.writeFile(outPath, ico) console.log('wrote', path.relative(root, outPath)) } const userPublic = path.join(root, 'apps/user-app/public') const userAssets = path.join(root, 'apps/user-app/src/assets/img') const adminPublic = path.join(root, 'apps/admin-panel/public') const adminLogo = path.join(root, 'apps/admin-panel/src/assets/images/logo') // Ensure adminPublic exists before writing no-items under it await fs.promises.mkdir(path.join(adminPublic, 'img'), { recursive: true }) await writeFull(path.join(userPublic, 'img/brand-logo.png'), 'png') await writeFull(path.join(userPublic, 'img/brand-logo.webp'), 'webp') await writeFull(path.join(userAssets, 'brand-logo.png'), 'png') // Product / missing-image placeholder — same mark await writeFull(path.join(userPublic, 'img/no-items.png'), 'png') await writeFull(path.join(userAssets, 'no-items.png'), 'png') await writeFull(path.join(adminPublic, 'img/no-items.png'), 'png') await writeFull(path.join(adminLogo, 'brand-icon.png'), 'png') await writeFull(path.join(adminLogo, 'brand-icon.webp'), 'webp') await writeFull(path.join(adminLogo, 'brand-horizontal.png'), 'png') await writePng(path.join(userPublic, 'icon-192.png'), 192) await writePng(path.join(userPublic, 'icon-512.png'), 512) await writePng(path.join(adminPublic, 'icon-192.png'), 192) await writePng(path.join(adminPublic, 'icon-512.png'), 512) await writePng(path.join(adminPublic, 'favicon.png'), 32) await writeIco(path.join(userPublic, 'favicon.ico')) await writeIco(path.join(adminPublic, 'favicon.ico')) await writeIco(path.join(adminLogo, 'favicon.ico')) console.log('done')