@@ -0,0 +1,398 @@
|
|||||||
|
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}`);
|
||||||
@@ -7,6 +7,7 @@ import { I18nextProvider } from "react-i18next";
|
|||||||
import "react-multi-date-picker/styles/layouts/mobile.css";
|
import "react-multi-date-picker/styles/layouts/mobile.css";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import "./assets/fonts/irancell/style.css";
|
import "./assets/fonts/irancell/style.css";
|
||||||
|
import "./assets/fonts/irancell/fonts-editor/fonts.css";
|
||||||
import ToastContainer from "./components/Toast";
|
import ToastContainer from "./components/Toast";
|
||||||
import MainRouter from "./router/MainRouter";
|
import MainRouter from "./router/MainRouter";
|
||||||
|
|
||||||
|
|||||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user