Adds Fixel Text as a new UI font option Allows font sources to load from direct URLs Keeps existing fontsource-based loading working
64 lines
1.9 KiB
TypeScript
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);
|