feat: font specification flexibility

This commit is contained in:
Jacky Zhao 2025-03-06 09:21:50 -08:00
parent 2213424195
commit 6d195fd40a
2 changed files with 61 additions and 6 deletions

View File

@ -1,7 +1,7 @@
import { i18n } from "../i18n" import { i18n } from "../i18n"
import { FullSlug, joinSegments, pathToRoot } from "../util/path" import { FullSlug, joinSegments, pathToRoot } from "../util/path"
import { CSSResourceToStyleElement, JSResourceToScriptElement } from "../util/resources" import { CSSResourceToStyleElement, JSResourceToScriptElement } from "../util/resources"
import { googleFontHref } from "../util/theme" import { getFontSpecificationName, googleFontHref } from "../util/theme"
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import satori, { SatoriOptions } from "satori" import satori, { SatoriOptions } from "satori"
import { loadEmoji, getIconCode } from "../util/emoji" import { loadEmoji, getIconCode } from "../util/emoji"
@ -77,7 +77,9 @@ export default (() => {
// Memoize google fonts // Memoize google fonts
if (!fontsPromise && cfg.generateSocialImages) { if (!fontsPromise && cfg.generateSocialImages) {
fontsPromise = getSatoriFont(cfg.theme.typography.header, cfg.theme.typography.body) const headerFont = getFontSpecificationName(cfg.theme.typography.header)
const bodyFont = getFontSpecificationName(cfg.theme.typography.body)
fontsPromise = getSatoriFont(headerFont, bodyFont)
} }
const slug = fileData.filePath const slug = fileData.filePath

View File

@ -15,11 +15,19 @@ interface Colors {
darkMode: ColorScheme darkMode: ColorScheme
} }
type FontSpecification =
| string
| {
name: string
weights?: number[]
includeItalic?: boolean
}
export interface Theme { export interface Theme {
typography: { typography: {
header: string header: FontSpecification
body: string body: FontSpecification
code: string code: FontSpecification
} }
cdnCaching: boolean cdnCaching: boolean
colors: Colors colors: Colors
@ -32,9 +40,54 @@ const DEFAULT_SANS_SERIF =
'system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"' 'system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"'
const DEFAULT_MONO = "ui-monospace, SFMono-Regular, SF Mono, Menlo, monospace" const DEFAULT_MONO = "ui-monospace, SFMono-Regular, SF Mono, Menlo, monospace"
export function getFontSpecificationName(spec: FontSpecification): string {
if (typeof spec === "string") {
return spec
}
return spec.name
}
function formatFontSpecification(type: "header" | "body" | "code", spec: FontSpecification) {
if (typeof spec === "string") {
spec = { name: spec }
}
const defaultIncludeWeights = type === "header" ? [400, 700] : [400, 600]
const defaultIncludeItalic = type === "body"
const weights = spec.weights ?? defaultIncludeWeights
const italic = spec.includeItalic ?? defaultIncludeItalic
const features: string[] = []
if (italic) {
features.push("ital")
}
if (weights.length > 1) {
const weightSpec = italic
? weights
.flatMap((w) => [`0,${w}`, `1,${w}`])
.sort()
.join(";")
: weights.join(";")
features.push(`wght@${weightSpec}`)
}
if (features.length > 0) {
return `${spec.name}:${features.join(",")}`
}
return spec.name
}
export function googleFontHref(theme: Theme) { export function googleFontHref(theme: Theme) {
const { code, header, body } = theme.typography 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 headerFont = formatFontSpecification("header", header)
const bodyFont = formatFontSpecification("body", body)
const codeFont = formatFontSpecification("code", code)
return `https://fonts.googleapis.com/css2?family=${bodyFont}&family=${headerFont}&family=${codeFont}&display=swap`
} }
export function joinStyles(theme: Theme, ...stylesheet: string[]) { export function joinStyles(theme: Theme, ...stylesheet: string[]) {