import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const ROOT = path.join(__dirname, "../src/assets/fonts/irancell/fonts-editor"); const OUT_JSON = path.join(ROOT, "fonts.json"); const OUT_CSS = path.join(ROOT, "fonts.css"); const WEIGHT_LABELS = { 100: "Thin", 200: "Extra Light", 300: "Light", 400: "Regular", 500: "Medium", 600: "Semi Bold", 700: "Bold", 800: "Extra Bold", 900: "Black", }; /** @type {Array<{ id: string; label: string; cssFamily: string; category: "persian" | "english"; faces: Array<{ weight: number; src: string; format?: string }> }>} */ const FONT_FAMILIES = [ { id: "irancell", label: "ایرانسل", cssFamily: "editor-irancell", category: "persian", defaultWeight: "300", faces: [ { weight: 200, src: "../irancell-extralight.ttf" }, { weight: 300, src: "../irancell-light.ttf" }, { weight: 600, src: "../irancell-bold.ttf" }, { weight: 700, src: "../irancell-bold.ttf" }, ], }, { id: "peyda", label: "پیدا", cssFamily: "editor-peyda", category: "persian", faces: [ { weight: 100, src: "Persian Font/peyda/woff2/PeydaWeb-Thin.woff2", format: "woff2" }, { weight: 200, src: "Persian Font/peyda/woff2/peydaWeb-extralight.woff2", format: "woff2" }, { weight: 300, src: "Persian Font/peyda/woff2/peydaWeb-light.woff2", format: "woff2" }, { weight: 400, src: "Persian Font/peyda/woff2/PeydaWeb-Regular.woff2", format: "woff2" }, { weight: 500, src: "Persian Font/peyda/woff2/PeydaWeb-Medium.woff2", format: "woff2" }, { weight: 600, src: "Persian Font/peyda/woff2/PeydaWeb-SemiBold.woff2", format: "woff2" }, { weight: 700, src: "Persian Font/peyda/woff2/PeydaWeb-Bold.woff2", format: "woff2" }, { weight: 800, src: "Persian Font/peyda/woff2/PeydaWeb-ExtraBold.woff2", format: "woff2" }, { weight: 900, src: "Persian Font/peyda/woff2/PeydaWeb-Black.woff2", format: "woff2" }, ], }, { id: "iransans-fanum", label: "ایران‌سنس (اعداد فارسی)", cssFamily: "editor-iransans-fanum", category: "persian", faces: [ { weight: 200, src: "Persian Font/IRANSansWeb(FaNum)_UltraLight.ttf" }, { weight: 300, src: "Persian Font/IRANSansWeb(FaNum)_Light.ttf" }, { weight: 400, src: "Persian Font/IRANSansWeb(FaNum).ttf" }, { weight: 500, src: "Persian Font/IRANSansWeb(FaNum)_Medium.ttf" }, { weight: 700, src: "Persian Font/IRANSansWeb(FaNum)_Bold.ttf" }, ], }, { id: "sahel", label: "ساحل", cssFamily: "editor-sahel", category: "persian", faces: [{ weight: 400, src: "Persian Font/Sahel-VF.ttf" }], }, { id: "yekan", label: "یکان", cssFamily: "editor-yekan", category: "persian", faces: [ { weight: 400, src: "Persian Font/Yekan.ttf" }, { weight: 700, src: "Persian Font/BYekan.ttf" }, ], }, { id: "btehran", label: "تهران", cssFamily: "editor-btehran", category: "persian", faces: [{ weight: 400, src: "Persian Font/BTehran.ttf" }], }, { id: "byagut", label: "یاقوت", cssFamily: "editor-byagut", category: "persian", faces: [{ weight: 400, src: "Persian Font/BYagut.ttf" }], }, { id: "byas", label: "یاس", cssFamily: "editor-byas", category: "persian", faces: [{ weight: 400, src: "Persian Font/BYas.ttf" }], }, { id: "bzar", label: "زر", cssFamily: "editor-bzar", category: "persian", faces: [{ weight: 700, src: "Persian Font/BZarBd.ttf" }], }, { id: "bkoodak", label: "کودک", cssFamily: "editor-bkoodak", category: "persian", faces: [{ weight: 700, src: "Persian Font/BKoodakBold.ttf" }], }, { id: "bbaran", label: "باران", cssFamily: "editor-bbaran", category: "persian", faces: [{ weight: 400, src: "Persian Font/BBaran.ttf" }], }, { id: "broya", label: "رویا", cssFamily: "editor-broya", category: "persian", faces: [{ weight: 400, src: "Persian Font/BRoya.ttf" }], }, { id: "bmahsa", label: "مهسا", cssFamily: "editor-bmahsa", category: "persian", faces: [{ weight: 400, src: "Persian Font/BMahsa.ttf" }], }, { id: "bmorvarid", label: "مروارید", cssFamily: "editor-bmorvarid", category: "persian", faces: [{ weight: 400, src: "Persian Font/BMorvarid.ttf" }], }, { id: "bbc-nassim", label: "نسیم", cssFamily: "editor-bbc-nassim", category: "persian", faces: [{ weight: 400, src: "Persian Font/BBCNassim.ttf" }], }, { id: "far-titr", label: "تیتر", cssFamily: "editor-far-titr", category: "persian", faces: [{ weight: 400, src: "Persian Font/Far_TitrDF.ttf" }], }, { id: "roboto", label: "Roboto", cssFamily: "editor-roboto", category: "english", faces: [ { weight: 100, src: "English Font/Roboto-Thin-webfont.ttf" }, { weight: 300, src: "English Font/Roboto-Light-webfont.ttf" }, { weight: 400, src: "English Font/Roboto-Regular-webfont.ttf" }, { weight: 500, src: "English Font/Roboto-Medium-webfont.ttf" }, { weight: 700, src: "English Font/Roboto-Bold-webfont.ttf" }, { weight: 900, src: "English Font/Roboto-Black-webfont.ttf" }, ], }, { id: "roboto-condensed", label: "Roboto Condensed", cssFamily: "editor-roboto-condensed", category: "english", faces: [ { weight: 400, src: "English Font/Roboto-Condensed-webfont.ttf" }, { weight: 700, src: "English Font/Roboto-BoldCondensed-webfont.ttf" }, ], }, { id: "vollkorn", label: "Vollkorn", cssFamily: "editor-vollkorn", category: "english", faces: [ { weight: 400, src: "English Font/Vollkorn-Regular.ttf" }, { weight: 500, src: "English Font/Vollkorn-Medium.ttf" }, { weight: 600, src: "English Font/Vollkorn-Semibold.ttf" }, { weight: 700, src: "English Font/Vollkorn-Bold.ttf" }, ], }, { id: "caviar-dreams", label: "Caviar Dreams", cssFamily: "editor-caviar-dreams", category: "english", faces: [ { weight: 400, src: "English Font/CaviarDreams.ttf" }, { weight: 700, src: "English Font/CaviarDreams_Bold.ttf" }, ], }, { id: "raleway", label: "Raleway", cssFamily: "editor-raleway", category: "english", faces: [ { weight: 200, src: "English Font/raleway-extralight-webfont.ttf" }, { weight: 400, src: "English Font/raleway-regular-webfont.ttf" }, { weight: 500, src: "English Font/raleway-medium-webfont.ttf" }, { weight: 600, src: "English Font/raleway-semibold-webfont.ttf" }, { weight: 700, src: "English Font/raleway-bold-webfont.ttf" }, { weight: 800, src: "English Font/raleway-extrabold-webfont.ttf" }, ], }, { id: "proxima-nova", label: "Proxima Nova", cssFamily: "editor-proxima-nova", category: "english", faces: [ { weight: 300, src: "English Font/proximanova-light-webfont.ttf" }, { weight: 400, src: "English Font/proximanova-reg-webfont.ttf" }, { weight: 600, src: "English Font/proximanova-semibold-webfont.ttf" }, { weight: 700, src: "English Font/proximanova-bold-webfont.ttf" }, { weight: 800, src: "English Font/proximanova-extrabold-webfont.ttf" }, { weight: 900, src: "English Font/proximanova-black-webfont.ttf" }, ], }, { id: "proxima-nova-condensed", label: "Proxima Nova Condensed", cssFamily: "editor-proxima-nova-condensed", category: "english", faces: [ { weight: 300, src: "English Font/proximanovacond-light-webfont.ttf" }, { weight: 600, src: "English Font/proximanovacond-semiboldit-webfont.ttf" }, ], }, { id: "din-pro", label: "DIN Pro", cssFamily: "editor-din-pro", category: "english", faces: [ { weight: 400, src: "English Font/dinpro-regular.ttf" }, { weight: 500, src: "English Font/dinpro-medium.ttf" }, { weight: 700, src: "English Font/dinpro-bold.ttf" }, { weight: 900, src: "English Font/dinpro-black.ttf" }, ], }, { id: "din-alternate", label: "DIN Alternate", cssFamily: "editor-din-alternate", category: "english", faces: [ { weight: 300, src: "English Font/din-lightalternate.ttf" }, { weight: 400, src: "English Font/din-regularalternate.ttf" }, { weight: 500, src: "English Font/din-mediumalternate.ttf" }, { weight: 700, src: "English Font/din-boldalternate.ttf" }, { weight: 900, src: "English Font/din-blackalternate.ttf" }, ], }, { id: "abril-fatface", label: "Abril Fatface", cssFamily: "editor-abril-fatface", category: "english", faces: [{ weight: 400, src: "English Font/AbrilFatface-Regular.otf", format: "opentype" }], }, { id: "anton", label: "Anton", cssFamily: "editor-anton", category: "english", faces: [{ weight: 400, src: "English Font/Anton.ttf" }], }, { id: "bebas-neue", label: "Bebas Neue", cssFamily: "editor-bebas-neue", category: "english", faces: [{ weight: 400, src: "English Font/Bebas Neue.ttf" }], }, { id: "kepler-std", label: "Kepler Std", cssFamily: "editor-kepler-std", category: "english", faces: [{ weight: 400, src: "English Font/kepler-std.ttf" }], }, { id: "playfair-display", label: "Playfair Display", cssFamily: "editor-playfair-display", category: "english", faces: [{ weight: 900, src: "English Font/playfairdisplay-black-webfont.ttf" }], }, ]; function encodeUrlSegment(segment) { return segment .split("/") .map((part) => encodeURIComponent(part)) .join("/"); } function buildCss(families) { const blocks = families.flatMap((family) => family.faces.map((face) => { const formatSuffix = face.format ? ` format("${face.format}")` : ""; const url = encodeUrlSegment(face.src); return `@font-face { font-family: "${family.cssFamily}"; font-style: normal; font-weight: ${face.weight}; src: url("${url}")${formatSuffix}; }`; }), ); return `/* Auto-generated by scripts/generate-editor-fonts.mjs — do not edit manually */\n\n${blocks.join("\n\n")}\n`; } function buildJson(families) { const fonts = families.map((family) => { const srcToFace = new Map(); for (const face of family.faces) { const existing = srcToFace.get(face.src); if (!existing || face.weight > existing.weight) { srcToFace.set(face.src, face); } } const uniqueWeightFaces = [...srcToFace.values()].sort( (a, b) => a.weight - b.weight, ); const uniqueWeights = uniqueWeightFaces.map((f) => f.weight); return { id: family.id, label: family.label, cssFamily: family.cssFamily, category: family.category, defaultWeight: family.defaultWeight ? String(family.defaultWeight) : uniqueWeights.includes(400) ? "400" : String(uniqueWeights[0]), weights: uniqueWeightFaces.map((face) => ({ value: String(face.weight), label: WEIGHT_LABELS[face.weight] || String(face.weight), })), }; }); return { version: 1, fonts, }; } function verifySources(families) { const missing = []; for (const family of families) { for (const face of family.faces) { const resolved = face.src.startsWith("../") ? path.join(ROOT, face.src) : path.join(ROOT, face.src); if (!fs.existsSync(resolved)) { missing.push(resolved); } } } if (missing.length) { console.error("Missing font files:\n" + missing.map((m) => ` - ${m}`).join("\n")); process.exit(1); } } verifySources(FONT_FAMILIES); const json = buildJson(FONT_FAMILIES); const css = buildCss(FONT_FAMILIES); fs.writeFileSync(OUT_JSON, JSON.stringify(json, null, 2) + "\n"); fs.writeFileSync(OUT_CSS, css); console.log(`Wrote ${OUT_JSON}`); console.log(`Wrote ${OUT_CSS}`); console.log(`Fonts: ${json.fonts.length}`);