File size: 3,249 Bytes
fa9c65f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | import { scheduleAfterFirstPaint } from '@/utils/after-paint';
let vercelAnalyticsScheduled = false;
let dashboardFontsScheduled = false;
export interface DashboardFontContext {
variant?: string | null;
lang?: string | null;
dir?: string | null;
}
export type DashboardFontFamily = 'nunito' | 'tajawal';
// Which web-font families the dashboard actually needs for a given variant/locale.
// The default (full variant, LTR/non-Arabic) needs none — its body font is the
// system/mono stack — so those users download zero web fonts.
export function dashboardFontFamilies(context: DashboardFontContext = {}): DashboardFontFamily[] {
const variant = (context.variant || 'full').toLowerCase();
const lang = (context.lang || 'en').split('-')[0]?.toLowerCase() || 'en';
const dir = (context.dir || '').toLowerCase();
const families: DashboardFontFamily[] = [];
if (variant === 'happy') families.push('nunito'); // happy theme body font
if (dir === 'rtl' || lang === 'ar') families.push('tajawal'); // Arabic body font
return families;
}
// Self-hosted @fontsource loaders — Vite bundles these to hashed /assets/*.woff2,
// served immutable (vercel.json) and therefore cached at the CDN/Cloudflare edge
// (unlike fonts.gstatic.com, a third-party origin). Each family pulls only the
// weights the UI actually uses.
const DASHBOARD_FONT_LOADERS: Record<DashboardFontFamily, () => Promise<unknown>> = {
nunito: () => Promise.all([
import('@fontsource/nunito/400.css'),
import('@fontsource/nunito/600.css'),
import('@fontsource/nunito/700.css'),
import('@fontsource/nunito/400-italic.css'),
]),
tajawal: () => Promise.all([
import('@fontsource/tajawal/400.css'),
import('@fontsource/tajawal/500.css'),
import('@fontsource/tajawal/700.css'),
]),
};
function getBuildVariant(): string {
try {
return import.meta.env.VITE_VARIANT || 'full';
} catch {
return 'full';
}
}
let dashboardFontsLoaded = false;
function loadDeferredDashboardFonts(): void {
if (typeof document === 'undefined' || dashboardFontsLoaded) return;
const root = document.documentElement;
const families = dashboardFontFamilies({
variant: root.dataset.variant || getBuildVariant(),
lang: root.lang || 'en',
dir: root.dir || '',
});
if (families.length === 0) return;
dashboardFontsLoaded = true;
void Promise.all(families.map((family) => DASHBOARD_FONT_LOADERS[family]())).catch(() => {
// Self-hosted fonts are best-effort; the system fallback stack covers failures.
});
}
export function initDeferredDashboardFonts(): void {
if (dashboardFontsScheduled) return;
dashboardFontsScheduled = true;
scheduleAfterFirstPaint(loadDeferredDashboardFonts, 3000);
}
export function initVercelAnalytics(): void {
if (vercelAnalyticsScheduled || typeof window === 'undefined') return;
vercelAnalyticsScheduled = true;
scheduleAfterFirstPaint(() => {
void import('@vercel/analytics')
.then(({ inject }) => {
inject({
beforeSend: (event) => (Math.random() > 0.1 ? null : event),
});
})
.catch(() => {
// Analytics is best-effort. Ad blockers/offline users should not affect boot.
});
}, 3000);
}
|