// Downloads the app's Google fonts once (latin + latin-ext subsets) into // frontend/fonts/ and writes frontend/fonts/fonts.css pointing at them. // Re-run only when the font list changes. const fs = require('node:fs'); const path = require('node:path'); const CSS_URL = 'https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,600..800&family=Hanken+Grotesk:wght@400..700&family=JetBrains+Mono:wght@400..700&display=swap'; const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36'; const OUT = path.join(__dirname, '..', 'frontend', 'fonts'); (async () => { fs.mkdirSync(OUT, { recursive: true }); const css = await (await fetch(CSS_URL, { headers: { 'User-Agent': UA } })).text(); // parts[k] ends with the "/* */" comment of the block in parts[k+1]. const parts = css.split('@font-face'); let out = '/* Generated by scripts/fetch-fonts.js — do not edit by hand. */\n'; let n = 0; for (let k = 1; k < parts.length; k++) { const subset = (parts[k - 1].match(/\/\*\s*([\w-]+)\s*\*\/\s*$/) || [])[1]; const b = parts[k].slice(0, parts[k].indexOf('}') + 1); // just this block if (subset !== 'latin' && subset !== 'latin-ext') continue; const url = (b.match(/url\((https:[^)]+\.woff2)\)/) || [])[1]; const fam = (b.match(/font-family:\s*'([^']+)'/) || [])[1]; if (!url || !fam) continue; const file = `${fam.replace(/\s+/g, '')}-${subset}.woff2`; const buf = Buffer.from(await (await fetch(url)).arrayBuffer()); fs.writeFileSync(path.join(OUT, file), buf); out += '@font-face' + b.replace(url, file).trimEnd() + '\n'; n++; } fs.writeFileSync(path.join(OUT, 'fonts.css'), out); console.log(`wrote ${n} font files + fonts.css`); })().catch((e) => { console.error(e); process.exit(1); });