import fontFaces from './font-faces.json'; export interface FontOption { name: string; category: 'serif' | 'sans'; google: boolean; // true = a Google Font we host ourselves in public/fonts; false = system font fallback: string; } /** * Curated font list for the admin "Design" editor. Kept in sync by hand with * admin/lib/fonts.js (duplicated rather than shared because the Astro site * is ESM/TS and the admin backend is CommonJS). */ export const FONT_OPTIONS: FontOption[] = [ { name: 'Playfair Display', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Lora', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Merriweather', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Libre Baskerville', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'DM Serif Display', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Georgia (Systemschrift)', category: 'serif', google: false, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Inter', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Roboto', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Open Sans', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Poppins', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Montserrat', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Nunito', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Work Sans', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Source Sans 3', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'System UI (Systemschrift)', category: 'sans', google: false, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, ]; export function findFont(name: string): FontOption { return FONT_OPTIONS.find((f) => f.name === name) || FONT_OPTIONS[0]; } export function fontFamilyCss(name: string): string { const font = findFont(name); return font.google ? `'${font.name}', ${font.fallback}` : font.fallback; } /** Builds the @font-face rules for the given font names from the files in * public/fonts (see font-faces.json). The fonts are served from our own * server so a page view never contacts Google. System fonts are skipped. */ export function localFontFacesCss(fontNames: string[]): string { const faces = fontFaces as Record; return fontNames .map(findFont) .filter((f) => f.google) .filter((f, i, arr) => arr.findIndex((g) => g.name === f.name) === i) .flatMap((f) => (faces[f.name] || []).map( (face) => `@font-face { font-family: '${f.name}'; font-style: normal; font-weight: ${face.weight}; ` + `font-display: swap; src: url('${face.file}') format('woff2'); unicode-range: ${face.unicodeRange}; }`, ), ) .join('\n'); } /** Builds `[data-font="Name"] { font-family: ...; }` rules for fonts used * inline via the rich-text editor's per-selection font picker. */ export function inlineFontFacesCss(fontNames: string[]): string { return fontNames.map((name) => `[data-font="${name}"] { font-family: ${fontFamilyCss(name)}; }`).join('\n'); }