diff --git a/quartz/util/theme.ts b/quartz/util/theme.ts index 9046cec66..579b8bbec 100644 --- a/quartz/util/theme.ts +++ b/quartz/util/theme.ts @@ -15,11 +15,19 @@ interface Colors { darkMode: ColorScheme } +interface FontInfo { + /** + * e.g. "ital,wght@0,400;1,200" + */ + features: string +} + export interface Theme { + fonts?: Record typography: { - header: string - body: string - code: string + header: string | string[] + body: string | string[] + code: string | string[] } cdnCaching: boolean colors: Colors @@ -32,9 +40,39 @@ const DEFAULT_SANS_SERIF = '-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif' const DEFAULT_MONO = "ui-monospace, SFMono-Regular, SF Mono, Menlo, monospace" +function makeFamilySection(theme: Theme, family: string | string[], defaultFeatures: string) { + const families = Array.isArray(family) ? family : [family] + return ( + "family=" + + families + .map((f) => { + const features = theme.fonts?.[f]?.features ?? defaultFeatures + if (features === "") { + return `${f}:wght@400` // matches unplugin-fonts; should be a sane default + } else { + return `${f}:${features}` + } + }) + .join("&family=") + ) +} + export function googleFontHref(theme: Theme) { const { code, header, body } = theme.typography - return `https://fonts.googleapis.com/css2?family=${code}&family=${header}:wght@400;700&family=${body}:ital,wght@0,400;0,600;1,400;1,600&display=swap` + + const codeSection = makeFamilySection(theme, code, "") + const headerSection = makeFamilySection(theme, header, "wght@400;700") + const bodySection = makeFamilySection(theme, body, "ital,wght@0,400;0,600;1,400;1,600") + + return `https://fonts.googleapis.com/css2?${codeSection}&${headerSection}&${bodySection}&display=swap` +} + +function renderFonts(fonts: string | string[]) { + if (Array.isArray(fonts)) { + return fonts.map((s) => `"${s}"`).join(", ") + } else { + return `"${fonts}"` + } } export function joinStyles(theme: Theme, ...stylesheet: string[]) { @@ -52,9 +90,9 @@ ${stylesheet.join("\n\n")} --highlight: ${theme.colors.lightMode.highlight}; --textHighlight: ${theme.colors.lightMode.textHighlight}; - --headerFont: "${theme.typography.header}", ${DEFAULT_SANS_SERIF}; - --bodyFont: "${theme.typography.body}", ${DEFAULT_SANS_SERIF}; - --codeFont: "${theme.typography.code}", ${DEFAULT_MONO}; + --headerFont: ${renderFonts(theme.typography.header)}, ${DEFAULT_SANS_SERIF}; + --bodyFont: ${renderFonts(theme.typography.body)}, ${DEFAULT_SANS_SERIF}; + --codeFont: ${renderFonts(theme.typography.code)}, ${DEFAULT_MONO}; } :root[saved-theme="dark"] {