Files
openchamber/packages/ui/src/lib/fontLoader.ts
T
Bohdan Triapitsyn 76128b615f feat: add Fixel font support
Adds Fixel Text as a new UI font option
Allows font sources to load from direct URLs
Keeps existing fontsource-based loading working
2026-09-03 11:49:35 +03:00

64 lines
1.9 KiB
TypeScript

import { CODE_FONT_OPTION_MAP, UI_FONT_OPTION_MAP, type FontFaceSource, type MonoFontOption, type UiFontOption } from '@/lib/fontOptions';
const loadedFaces = new Set<string>();
const pendingFaces = new Map<string, Promise<void>>();
const buildFontUrl = (source: FontFaceSource, weight: number) => {
if ('urls' in source) {
return source.urls[weight];
}
const packageName = encodeURIComponent(source.packageName).replace('%40', '@').replace('%2F', '/');
return `https://cdn.jsdelivr.net/npm/${packageName}/files/${source.filePrefix}-latin-${weight}-normal.woff2`;
};
const loadFace = (source: FontFaceSource, weight: number) => {
const key = `${source.family}:${weight}`;
if (loadedFaces.has(key)) {
return Promise.resolve();
}
const pending = pendingFaces.get(key);
if (pending) {
return pending;
}
if (typeof document === 'undefined' || typeof FontFace === 'undefined' || !document.fonts) {
return Promise.resolve();
}
const face = new FontFace(source.family, `url(${buildFontUrl(source, weight)}) format('woff2')`, {
style: 'normal',
weight: String(weight),
display: 'swap',
});
document.fonts.add(face);
const promise = face.load()
.then(() => {
loadedFaces.add(key);
})
.catch((error) => {
document.fonts.delete(face);
console.warn(`Failed to load font: ${source.family} ${weight}`, error);
})
.finally(() => {
pendingFaces.delete(key);
});
pendingFaces.set(key, promise);
return promise;
};
const loadSource = (source: FontFaceSource | undefined) => {
if (!source) {
return Promise.resolve();
}
return Promise.all(source.weights.map((weight) => loadFace(source, weight))).then(() => undefined);
};
export const loadUiFont = (font: UiFontOption) => loadSource(UI_FONT_OPTION_MAP[font]?.source);
export const loadMonoFont = (font: MonoFontOption) => loadSource(CODE_FONT_OPTION_MAP[font]?.source);