Files
xavierk aa7a407944 Add the Neutral template family, template picker and text-only logo allowances
Linea (the vendor's original format.pdf design), Monogram and Serenity are
rebuilt from the reference PDFs as one parametric family on the engine, with
the user's logo in the measured slot, a home for every GST field and
A4/Letter support. Adds static Montserrat, Open Sans and Poppins fonts and
a generated Ms Madi outline for Serenity's vertical word. Text-only logo
placeholders (Monolith, Tangerine) use a doc-derived allowance box. A
Carbon TemplatePicker with committed thumbnails opens from the page
setup controls.
2026-10-04 07:27:12 +05:30

47 lines
1.6 KiB
JavaScript

// Renders every registered template with one fixed sample invoice into public/templates/<id>.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)`);
}