// Renders every registered template with one fixed sample invoice into public/templates/.png, the // static thumbnails of the template picker. Run: npm run thumbnails (the PNGs are committed). // The sample is the harness's tax invoice with The sample vendor's logo; the picker says that thumbnails use sample data. import { mkdirSync, writeFileSync } from "node:fs"; import path from "node:path"; import { ROOT, loadRenderer, rasterize } from "./templates/lib.mjs"; const OUT = path.join(ROOT, "public", "templates"); const WIDTH = 420; const A4_WIDTH_PT = 595.28; const ITEMS = [ ["Voice-over narration", 4, 1500], ["Audio mastering", 2, 800], ].map(([description, quantity, rate], i) => ({ id: i + 1, description, mode: "rate", rate, unit: "hour", quantity, amount: 0, sortOrder: i, hsnSac: "998397", })); const SAMPLE = { name: "thumbnail", items: ITEMS, logo: "real", signature: false, // A leaner supplier block keeps the whole design (closing block included) on the thumbnail's one page. vendor: { vendorEmail: "", vendorPhone: "", vendorPan: "" }, invoice: { poNumber: "", notes: "" }, }; const r = await loadRenderer(); r.ensureSetup(); mkdirSync(OUT, { recursive: true }); for (const id of Object.keys(r.TEMPLATES)) { const rendered = await r.renderFixture(SAMPLE, r.prefsFor("A4", { templateId: id })); const canvas = await rasterize(rendered.result.bytes, 1, WIDTH / A4_WIDTH_PT); const file = path.join(OUT, `${id}.png`); writeFileSync(file, canvas.toBuffer("image/png")); console.log(`${id}: ${canvas.width} x ${canvas.height} px, ${rendered.result.pages} page(s), ${rendered.result.issues.length} audit issue(s)`); }