From d50adc72e9279bcd6f07c4e71c8b33f1318ce884 Mon Sep 17 00:00:00 2001 From: Julien Calixte Date: Mon, 27 Apr 2026 10:12:12 +0200 Subject: [PATCH] refactor(downloadFont): handle generic families and multi-family strings Strips generic CSS families (serif, monospace, etc.) before building the font API URL, and correctly parses comma-separated font stacks. --- src/utils/downloadFont.ts | 53 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/utils/downloadFont.ts b/src/utils/downloadFont.ts index dcc789d..7e01e45 100644 --- a/src/utils/downloadFont.ts +++ b/src/utils/downloadFont.ts @@ -1,33 +1,48 @@ import FontFaceObserver from "fontfaceobserver" -const assembleFontLink = (font: string) => { - return `https://api.fonts.coollabs.io/css2?display=swap&family=${font - .replaceAll(",", "&family=") - .replaceAll(" ", "+")}` +const GENERIC_FAMILIES = new Set([ + "serif", "sans-serif", "monospace", "cursive", "fantasy", + "system-ui", "ui-serif", "ui-sans-serif", "ui-monospace", "ui-rounded", +]) + +const parseWebFontFamilies = (font: string): string[] => + font + .split(",") + .map(f => f.trim().replace(/^["']|["']$/g, "")) + .filter(f => f && !GENERIC_FAMILIES.has(f)) + +const assembleFontLink = (families: string[]): string | null => { + if (families.length === 0) return null + return `https://api.fonts.coollabs.io/css2?display=swap&${ + families.map(f => `family=${f.replaceAll(" ", "+")}`).join("&") + }` } export const downloadFont = async ( font: string, cssVar = "--font-family" ): Promise => { - const href = assembleFontLink(font) + const families = parseWebFontFamilies(font) + const href = assembleFontLink(families) - // check if the href already exists - const existingLink = document.querySelector(`link[href="${href}"]`) + if (href) { + const alreadyLoaded = Array.from( + document.head.querySelectorAll('link[rel="stylesheet"]') + ).some(link => link.href === href) - if (!existingLink) { - const link = document.createElement("link") - link.href = href - link.rel = "stylesheet" + if (!alreadyLoaded) { + const link = document.createElement("link") + link.href = href + link.rel = "stylesheet" + document.head.appendChild(link) + } - document.head.appendChild(link) + try { + await new FontFaceObserver(families[0]).load() + } catch { + console.warn("error when loading font") + } } - try { - await new FontFaceObserver(font).load() - - document.documentElement.style.setProperty(cssVar, font) - } catch (error) { - console.warn("error when loading font") - } + document.documentElement.style.setProperty(cssVar, font) }