style: enforce Vazirmatn-FD Persian digits across world economy, bonds and entire dashboard
This commit is contained in:
parent
d5dffd0980
commit
984d44a18b
|
|
@ -79,7 +79,12 @@ import { LmeView } from "@/components/LmeView";
|
||||||
import { ImeView } from "@/components/ImeView";
|
import { ImeView } from "@/components/ImeView";
|
||||||
import { Building2 } from "lucide-react";
|
import { Building2 } from "lucide-react";
|
||||||
|
|
||||||
const API = API_BASE; // dev: "" (same-origin via Vite proxy); prod: VITE_API_BASE
|
const API = API_BASE;
|
||||||
|
|
||||||
|
const faDigits = (s: string | number | null | undefined): string => {
|
||||||
|
if (s == null) return "—";
|
||||||
|
return String(s).replace(/[0-9]/g, (d) => "۰۱۲۳۴۵۶۷۸۹"[+d]);
|
||||||
|
}; // dev: "" (same-origin via Vite proxy); prod: VITE_API_BASE
|
||||||
|
|
||||||
export const Route = createFileRoute("/dashboard")({
|
export const Route = createFileRoute("/dashboard")({
|
||||||
head: () => ({
|
head: () => ({
|
||||||
|
|
@ -1365,8 +1370,7 @@ const STEEL_FLAGS: Record<string, string> = {
|
||||||
"Saudi Arabia": "🇸🇦",
|
"Saudi Arabia": "🇸🇦",
|
||||||
};
|
};
|
||||||
|
|
||||||
// ASCII→Persian digits for any already-formatted string (keeps $ % T B . , # ▼ ▲)
|
// faDigits declared globally at top
|
||||||
const faDigits = (s: string) => s.replace(/[0-9]/g, (d) => "۰۱۲۳۴۵۶۷۸۹"[+d]);
|
|
||||||
|
|
||||||
const usd = (n: number, frac = 2) =>
|
const usd = (n: number, frac = 2) =>
|
||||||
faDigits(n.toLocaleString("en-US", { minimumFractionDigits: frac, maximumFractionDigits: frac }));
|
faDigits(n.toLocaleString("en-US", { minimumFractionDigits: frac, maximumFractionDigits: frac }));
|
||||||
|
|
@ -2747,8 +2751,8 @@ function WorldEconomyView() {
|
||||||
|
|
||||||
const fmtCell = (col: (typeof WE_COLS)[number], val: number | null) => {
|
const fmtCell = (col: (typeof WE_COLS)[number], val: number | null) => {
|
||||||
if (val == null) return "—";
|
if (val == null) return "—";
|
||||||
if (col.gdp) return (val / 1000).toLocaleString("fa-IR", { maximumFractionDigits: 2 }) + " T$";
|
if (col.gdp) return faDigits((val / 1000).toFixed(2) + " T$");
|
||||||
return formatNumber(val) + (col.suffix || "");
|
return faDigits(formatNumber(val) + (col.suffix || ""));
|
||||||
};
|
};
|
||||||
|
|
||||||
const us10y = bonds.find((b) => b.code === "US10Y");
|
const us10y = bonds.find((b) => b.code === "US10Y");
|
||||||
|
|
@ -2851,12 +2855,12 @@ function WorldEconomyView() {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex items-baseline justify-between">
|
<div className="mt-2 flex items-baseline justify-between">
|
||||||
<span className="text-2xl font-bold font-mono tabular-nums text-foreground">
|
<span className="text-2xl font-bold font-mono tabular-nums text-foreground">
|
||||||
{us10y?.yield ? us10y.yield.toFixed(3) + "%" : "—"}
|
{us10y?.yield ? faDigits(us10y.yield.toFixed(3) + "%") : "—"}
|
||||||
</span>
|
</span>
|
||||||
{us10y && <DeltaPill pct={us10y.change} dir={us10y.change >= 0 ? "up" : "down"} />}
|
{us10y && <DeltaPill pct={us10y.change} dir={us10y.change >= 0 ? "up" : "down"} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
||||||
تغییر: {us10y ? (us10y.change_abs >= 0 ? "+" : "") + (us10y.change_abs * 100).toFixed(1) + " bps" : "—"}
|
تغییر: {us10y ? faDigits((us10y.change_abs >= 0 ? "+" : "") + (us10y.change_abs * 100).toFixed(1) + " bps") : "—"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -2867,12 +2871,12 @@ function WorldEconomyView() {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex items-baseline justify-between">
|
<div className="mt-2 flex items-baseline justify-between">
|
||||||
<span className="text-2xl font-bold font-mono tabular-nums text-foreground">
|
<span className="text-2xl font-bold font-mono tabular-nums text-foreground">
|
||||||
{de10y?.yield ? de10y.yield.toFixed(3) + "%" : "—"}
|
{de10y?.yield ? faDigits(de10y.yield.toFixed(3) + "%") : "—"}
|
||||||
</span>
|
</span>
|
||||||
{de10y && <DeltaPill pct={de10y.change} dir={de10y.change >= 0 ? "up" : "down"} />}
|
{de10y && <DeltaPill pct={de10y.change} dir={de10y.change >= 0 ? "up" : "down"} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
||||||
تغییر: {de10y ? (de10y.change_abs >= 0 ? "+" : "") + (de10y.change_abs * 100).toFixed(1) + " bps" : "—"}
|
تغییر: {de10y ? faDigits((de10y.change_abs >= 0 ? "+" : "") + (de10y.change_abs * 100).toFixed(1) + " bps") : "—"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -2883,12 +2887,12 @@ function WorldEconomyView() {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex items-baseline justify-between">
|
<div className="mt-2 flex items-baseline justify-between">
|
||||||
<span className="text-2xl font-bold font-mono tabular-nums text-foreground">
|
<span className="text-2xl font-bold font-mono tabular-nums text-foreground">
|
||||||
{gb10y?.yield ? gb10y.yield.toFixed(3) + "%" : "—"}
|
{gb10y?.yield ? faDigits(gb10y.yield.toFixed(3) + "%") : "—"}
|
||||||
</span>
|
</span>
|
||||||
{gb10y && <DeltaPill pct={gb10y.change} dir={gb10y.change >= 0 ? "up" : "down"} />}
|
{gb10y && <DeltaPill pct={gb10y.change} dir={gb10y.change >= 0 ? "up" : "down"} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
||||||
تغییر: {gb10y ? (gb10y.change_abs >= 0 ? "+" : "") + (gb10y.change_abs * 100).toFixed(1) + " bps" : "—"}
|
تغییر: {gb10y ? faDigits((gb10y.change_abs >= 0 ? "+" : "") + (gb10y.change_abs * 100).toFixed(1) + " bps") : "—"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -2899,7 +2903,7 @@ function WorldEconomyView() {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex items-baseline justify-between">
|
<div className="mt-2 flex items-baseline justify-between">
|
||||||
<span className={cn("text-2xl font-bold font-mono tabular-nums", (spread10_2 ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
<span className={cn("text-2xl font-bold font-mono tabular-nums", (spread10_2 ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
||||||
{spread10_2 != null ? (spread10_2 >= 0 ? "+" : "") + (spread10_2 * 100).toFixed(1) + " bps" : "—"}
|
{spread10_2 != null ? faDigits((spread10_2 >= 0 ? "+" : "") + (spread10_2 * 100).toFixed(1) + " bps") : "—"}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[11px] px-2 py-0.5 rounded-full font-mono font-medium bg-muted text-muted-foreground">
|
<span className="text-[11px] px-2 py-0.5 rounded-full font-mono font-medium bg-muted text-muted-foreground">
|
||||||
{(spread10_2 ?? 0) >= 0 ? "نرمال" : "وارونه (Inverted)"}
|
{(spread10_2 ?? 0) >= 0 ? "نرمال" : "وارونه (Inverted)"}
|
||||||
|
|
@ -2943,28 +2947,28 @@ function WorldEconomyView() {
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center font-mono text-xs text-muted-foreground">
|
<td className="p-3 text-center font-mono text-xs text-muted-foreground">
|
||||||
<span className="px-2 py-0.5 rounded bg-muted/80">{b.tenor}</span>
|
<span className="px-2 py-0.5 rounded bg-muted/80">{faDigits(b.tenor)}</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center font-mono font-bold text-base text-foreground tabular-nums">
|
<td className="p-3 text-center font-mono font-bold text-base text-foreground tabular-nums">
|
||||||
{b.yield != null ? b.yield.toFixed(3) + "%" : "—"}
|
{b.yield != null ? faDigits(b.yield.toFixed(3) + "%") : "—"}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center font-mono text-xs tabular-nums">
|
<td className="p-3 text-center font-mono text-xs tabular-nums">
|
||||||
<DeltaPill pct={b.change} dir={isUp ? "up" : "down"} />
|
<DeltaPill pct={b.change} dir={isUp ? "up" : "down"} />
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center font-mono text-xs tabular-nums text-foreground">
|
<td className="p-3 text-center font-mono text-xs tabular-nums text-foreground">
|
||||||
{b.change_abs != null ? (b.change_abs >= 0 ? "+" : "") + (b.change_abs * 100).toFixed(1) : "—"}
|
{b.change_abs != null ? faDigits((b.change_abs >= 0 ? "+" : "") + (b.change_abs * 100).toFixed(1)) : "—"}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center font-mono text-xs text-muted-foreground tabular-nums">
|
<td className="p-3 text-center font-mono text-xs text-muted-foreground tabular-nums">
|
||||||
{b.low != null && b.high != null ? `${b.low.toFixed(2)} - ${b.high.toFixed(2)}` : "—"}
|
{b.low != null && b.high != null ? faDigits(`${b.low.toFixed(2)} - ${b.high.toFixed(2)}`) : "—"}
|
||||||
</td>
|
</td>
|
||||||
<td className={cn("p-3 text-center font-mono text-xs tabular-nums", (b.perf_w ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
<td className={cn("p-3 text-center font-mono text-xs tabular-nums", (b.perf_w ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
||||||
{b.perf_w != null ? (b.perf_w >= 0 ? "+" : "") + b.perf_w.toFixed(2) + "%" : "—"}
|
{b.perf_w != null ? faDigits((b.perf_w >= 0 ? "+" : "") + b.perf_w.toFixed(2) + "%") : "—"}
|
||||||
</td>
|
</td>
|
||||||
<td className={cn("p-3 text-center font-mono text-xs tabular-nums", (b.perf_m ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
<td className={cn("p-3 text-center font-mono text-xs tabular-nums", (b.perf_m ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
||||||
{b.perf_m != null ? (b.perf_m >= 0 ? "+" : "") + b.perf_m.toFixed(2) + "%" : "—"}
|
{b.perf_m != null ? faDigits((b.perf_m >= 0 ? "+" : "") + b.perf_m.toFixed(2) + "%") : "—"}
|
||||||
</td>
|
</td>
|
||||||
<td className={cn("p-3 text-center font-mono text-xs tabular-nums", (b.perf_y ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
<td className={cn("p-3 text-center font-mono text-xs tabular-nums", (b.perf_y ?? 0) >= 0 ? "text-emerald-700" : "text-red-600")}>
|
||||||
{b.perf_y != null ? (b.perf_y >= 0 ? "+" : "") + b.perf_y.toFixed(2) + "%" : "—"}
|
{b.perf_y != null ? faDigits((b.perf_y >= 0 ? "+" : "") + b.perf_y.toFixed(2) + "%") : "—"}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center w-28">
|
<td className="p-3 text-center w-28">
|
||||||
{b.sparkline && b.sparkline.length > 1 && (
|
{b.sparkline && b.sparkline.length > 1 && (
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
@import "vazirmatn/misc/Farsi-Digits/Vazirmatn-FD-font-face.css";
|
||||||
@import "vazirmatn/Vazirmatn-font-face.css";
|
@import "vazirmatn/Vazirmatn-font-face.css";
|
||||||
@import "tailwindcss" source(none);
|
@import "tailwindcss" source(none);
|
||||||
@source "../src";
|
@source "../src";
|
||||||
|
|
@ -257,8 +258,8 @@
|
||||||
--color-chart-3: var(--chart-3);
|
--color-chart-3: var(--chart-3);
|
||||||
--color-chart-4: var(--chart-4);
|
--color-chart-4: var(--chart-4);
|
||||||
--color-chart-5: var(--chart-5);
|
--color-chart-5: var(--chart-5);
|
||||||
--font-sans: Vazirmatn, system-ui, sans-serif;
|
--font-sans: "Vazirmatn FD", Vazirmatn, system-ui, sans-serif;
|
||||||
--font-mono: Vazirmatn, system-ui, sans-serif;
|
--font-mono: "Vazirmatn FD", Vazirmatn, system-ui, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
|
@ -299,7 +300,7 @@
|
||||||
@layer base {
|
@layer base {
|
||||||
* { border-color: var(--color-border); }
|
* { border-color: var(--color-border); }
|
||||||
/* Unzoomable PWA: block double-tap zoom (pinch handled by the viewport meta) */
|
/* Unzoomable PWA: block double-tap zoom (pinch handled by the viewport meta) */
|
||||||
html, body { font-family: var(--font-sans); touch-action: manipulation; }
|
html, body { font-family: "Vazirmatn FD", Vazirmatn, system-ui, sans-serif; touch-action: manipulation; }
|
||||||
body {
|
body {
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
background-image:
|
background-image:
|
||||||
|
|
@ -312,12 +313,14 @@
|
||||||
color: var(--color-foreground);
|
color: var(--color-foreground);
|
||||||
direction: rtl;
|
direction: rtl;
|
||||||
}
|
}
|
||||||
/* Enforce Vazirmatn for all numbers, tabular-nums, and monospace elements */
|
/* Enforce Vazirmatn with Persian digits for all numbers, tabular-nums, and monospace elements */
|
||||||
.font-mono,
|
.font-mono,
|
||||||
.tabular-nums,
|
.tabular-nums,
|
||||||
span.font-mono,
|
span.font-mono,
|
||||||
div.font-mono {
|
div.font-mono,
|
||||||
font-family: Vazirmatn, system-ui, sans-serif !important;
|
td.tabular-nums,
|
||||||
|
span.tabular-nums {
|
||||||
|
font-family: "Vazirmatn FD", Vazirmatn, system-ui, sans-serif !important;
|
||||||
font-feature-settings: "tnum" 1;
|
font-feature-settings: "tnum" 1;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue