返回 presentation-ai
loadCustomFont.ts
根目录 / src / lib / presentation / loadCustomFont.ts
1 /**
2 * Utility functions for loading custom fonts using the FontFace API
3 */
4
5 /**
6 * Get font format from URL extension
7 */
8 function getFontFormat(url: string): string {
9 const extension = url.split(".").pop()?.toLowerCase();
10
11 switch (extension) {
12 case "woff2":
13 return "woff2";
14 case "woff":
15 return "woff";
16 case "ttf":
17 return "truetype";
18 case "otf":
19 return "opentype";
20 default:
21 return "truetype";
22 }
23 }
24
25 /**
26 * Load a custom font using the FontFace API
27 * @param fontFamily - The font family name
28 * @param fontUrl - The URL to the font file
29 * @param weight - Optional font weight (default: 400)
30 * @returns Promise that resolves when the font is loaded
31 */
32 export async function loadCustomFont(
33 fontFamily: string,
34 fontUrl: string,
35 weight: number = 400,
36 ): Promise<void> {
37 try {
38 const font = new FontFace(fontFamily, `url(${fontUrl})`, {
39 weight: weight.toString(),
40 style: "normal",
41 display: "swap",
42 });
43
44 // Check if the font is already loaded
45 const isAlreadyLoaded = Array.from(document.fonts).some(
46 (f) => f.family === fontFamily && f.weight === weight.toString(),
47 );
48
49 if (isAlreadyLoaded) {
50 return;
51 }
52
53 const format = getFontFormat(fontUrl);
54
55 // Load the font
56 const loadedFont = await font.load();
57
58 // Add the loaded font to the document
59 document.fonts.add(loadedFont);
60
61 console.log(
62 `Custom font loaded successfully: ${fontFamily} (${format}) from ${fontUrl}`,
63 );
64 } catch (error) {
65 console.error(`Failed to load custom font ${fontFamily}:`, error);
66 // Don't throw - we want the app to continue even if fonts fail to load
67 }
68 }
69
70 /**
71 * Load custom heading and body fonts if URLs are provided
72 * @param headingFont - The heading font family name
73 * @param headingUrl - The URL to the heading font file (optional)
74 * @param headingWeight - The heading font weight (optional)
75 * @param bodyFont - The body font family name
76 * @param bodyUrl - The URL to the body font file (optional)
77 * @param bodyWeight - The body font weight (optional)
78 */
79 export async function loadCustomFonts(options: {
80 headingFont: string;
81 headingUrl?: string;
82 headingWeight?: number;
83 bodyFont: string;
84 bodyUrl?: string;
85 bodyWeight?: number;
86 }): Promise<void> {
87 const {
88 headingFont,
89 headingUrl,
90 headingWeight = 400,
91 bodyFont,
92 bodyUrl,
93 bodyWeight = 400,
94 } = options;
95
96 const promises: Promise<void>[] = [];
97
98 // Load heading font if URL is provided
99 if (headingUrl) {
100 promises.push(loadCustomFont(headingFont, headingUrl, headingWeight));
101 }
102
103 // Load body font if URL is provided and it's different from heading
104 if (bodyUrl && bodyFont !== headingFont) {
105 promises.push(loadCustomFont(bodyFont, bodyUrl, bodyWeight));
106 } else if (bodyUrl && bodyFont === headingFont && headingUrl !== bodyUrl) {
107 // Same font family but different weight
108 promises.push(loadCustomFont(bodyFont, bodyUrl, bodyWeight));
109 }
110
111 try {
112 await Promise.all(promises);
113 } catch (error) {
114 console.error("Failed to load one or more custom fonts:", error);
115 // Don't throw - we want the app to continue even if fonts fail to load
116 }
117 }
118
118 lines TYPESCRIPT