kinetic-slider
Version:
A WebGL-powered kinetic slider component using PIXI.js
186 lines (183 loc) • 5.29 kB
JavaScript
import { Assets } from 'pixi.js';
const SYSTEM_FONTS = [
// Sans-serif fonts
"Arial",
"Helvetica",
"Helvetica Neue",
"Verdana",
"Tahoma",
"Trebuchet MS",
"Segoe UI",
"Roboto",
"Open Sans",
"Liberation Sans",
"Noto Sans",
"Ubuntu",
// Serif fonts
"Times",
"Times New Roman",
"Georgia",
"Palatino",
"Garamond",
"Bookman",
"Cambria",
"Constantia",
"Liberation Serif",
"Noto Serif",
// Monospace fonts
"Courier",
"Courier New",
"Monaco",
"Consolas",
"Liberation Mono",
"Menlo",
// Generic families
"sans-serif",
"serif",
"monospace",
"cursive",
"fantasy",
"system-ui"
];
const FONT_EXTENSIONS = [".woff2", ".woff", ".ttf", ".otf"];
function parseFontStack(fontStack) {
if (!fontStack) return [];
return fontStack.split(",").map((font) => {
return font.replace(/^["'\s]+|["'\s]+$/g, "").trim();
}).filter(Boolean);
}
function identifyCustomFonts(parsedFonts) {
return parsedFonts.filter(
(font) => (
// Not in our system fonts list and not a generic family
!SYSTEM_FONTS.some(
(systemFont) => systemFont.toLowerCase() === font.toLowerCase()
)
)
);
}
async function findFontFile(fontName, extensions = FONT_EXTENSIONS) {
const fontPaths = [];
for (const ext of extensions) {
fontPaths.push(`/fonts/${fontName}${ext}`);
fontPaths.push(`/fonts/${fontName.toLowerCase()}${ext}`);
}
const additionalPaths = [];
for (const ext of extensions) {
additionalPaths.push(`/public/fonts/${fontName}${ext}`);
additionalPaths.push(`/public/fonts/${fontName.toLowerCase()}${ext}`);
}
const allPaths = [...fontPaths, ...additionalPaths];
for (const path of allPaths) {
try {
const response = await fetch(path, { method: "HEAD" });
if (response.ok) {
console.log(`Found font file at: ${path}`);
return path;
}
} catch (error) {
}
}
console.warn(`No font file found for: ${fontName}`);
return null;
}
async function loadCustomFonts(fontStack) {
if (!fontStack) return [];
const parsedFonts = parseFontStack(fontStack);
const customFonts = identifyCustomFonts(parsedFonts);
if (!customFonts.length) {
console.log("No custom fonts identified in font stack:", fontStack);
return [];
}
console.log("Identified custom fonts:", customFonts);
const loadedFonts = [];
for (const fontName of customFonts) {
try {
const cleanFontName = fontName.replace(/['"]/g, "");
const fontPath = await findFontFile(cleanFontName);
if (fontPath) {
console.log(`Loading font: ${cleanFontName} from ${fontPath}`);
try {
await Assets.load({
src: fontPath,
data: {
// Add font-specific metadata if needed
family: cleanFontName
}
});
loadedFonts.push(fontPath);
console.log(`Successfully loaded font: ${cleanFontName}`);
} catch (loadError) {
console.warn(`Failed to load font ${cleanFontName}:`, loadError);
}
}
} catch (error) {
console.warn(`Error processing font ${fontName}:`, error);
}
}
return loadedFonts;
}
function createFontFaceCSS(fontPaths) {
return fontPaths.map((path) => {
const fontName = path.split("/").pop()?.split(".")[0] || "";
const fontFormat = path.split(".").pop();
let format;
switch (fontFormat) {
case "woff2":
format = "woff2";
break;
case "woff":
format = "woff";
break;
case "ttf":
format = "truetype";
break;
case "otf":
format = "opentype";
break;
default:
format = "truetype";
}
return `
@font-face {
font-family: '${fontName}';
src: url('${path}') format('${format}');
font-weight: normal;
font-style: normal;
font-display: swap;
}
`;
}).join("\n");
}
function injectFontFaceCSS(css) {
if (typeof document === "undefined" || !css) return;
const style = document.createElement("style");
style.textContent = css;
style.setAttribute("data-kinetic-slider-fonts", "true");
document.head.appendChild(style);
}
async function setupCustomFonts(titleFontStack, subtitleFontStack) {
if (typeof window === "undefined") return;
console.log("Setting up custom fonts:", { titleFontStack, subtitleFontStack });
const loadedFontPaths = [];
if (titleFontStack) {
const titleFontPaths = await loadCustomFonts(titleFontStack);
loadedFontPaths.push(...titleFontPaths);
}
if (subtitleFontStack) {
const subtitleFontPaths = await loadCustomFonts(subtitleFontStack);
const newPaths = subtitleFontPaths.filter((path) => !loadedFontPaths.includes(path));
loadedFontPaths.push(...newPaths);
}
if (loadedFontPaths.length > 0) {
const fontFaceCSS = createFontFaceCSS(loadedFontPaths);
injectFontFaceCSS(fontFaceCSS);
console.log("Injected font-face CSS for:", loadedFontPaths);
return new Promise((resolve) => {
setTimeout(resolve, 100);
});
}
return Promise.resolve();
}
export { createFontFaceCSS, findFontFile, identifyCustomFonts, injectFontFaceCSS, loadCustomFonts, parseFontStack, setupCustomFonts };
//# sourceMappingURL=fontUtils.js.map