feat: font specification flexibility
This commit is contained in:
		@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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[]) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user