From 3a47f383b09486e76f9282ad55fa20b2e619df6e Mon Sep 17 00:00:00 2001 From: Ben Schlegel Date: Sun, 24 Sep 2023 12:58:31 +0200 Subject: [PATCH] refactor: clean font helpers, rename fonts helper --- quartz/components/Head.tsx | 5 ++-- quartz/util/fonts.ts | 38 ----------------------------- quartz/util/imageHelper.ts | 49 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 41 deletions(-) delete mode 100644 quartz/util/fonts.ts create mode 100644 quartz/util/imageHelper.ts diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index deda84745..88e877b74 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -3,7 +3,7 @@ import { JSResourceToScriptElement } from "../util/resources" import { QuartzComponentConstructor, QuartzComponentProps } from "./types" import satori, { SatoriOptions } from "satori" import * as fs from "fs" -import { getSatoriFont } from "../util/fonts" +import { getSatoriFont } from "../util/imageHelper" import { GlobalConfiguration } from "../cfg" import sharp from "sharp" @@ -19,8 +19,7 @@ export type SocialImageOptions = { * @param title what title to use * @param description what description to use * @param fileName what fileName to use when writing to disk - * @param headerFontName name of font to use for header (must be google font) - * @param bodyFontName name of font to use for body (must be google font) + * @param fontsPromise header + body font to be used when generating satori image (as promise to work around sync in component) * @param cfg `GlobalConfiguration` of quartz */ async function generateSocialImage( diff --git a/quartz/util/fonts.ts b/quartz/util/fonts.ts deleted file mode 100644 index bf5859e18..000000000 --- a/quartz/util/fonts.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { FontWeight, SatoriOptions } from "satori/wasm" - -/** - * Get an array of `FontOptions` (for satori) given google font names - * @param headerFontName name of google font used for header - * @param bodyFontName name of google font used for body - * @returns FontOptions for header and body - */ -export async function getSatoriFont(headerFontName: string, bodyFontName: string) { - const headerFont = await fetchTtf(headerFontName, 700) - const bodyFont = await fetchTtf(bodyFontName, 400) - - const fonts: SatoriOptions["fonts"] = [headerFont, bodyFont] - return fonts -} - -function fetchTtf( - fontName: string, - weight: FontWeight, -): Promise> { - return new Promise(async (resolve, reject) => { - const css = await ( - await fetch(`https://fonts.googleapis.com/css?family=${fontName}:${weight}`) - ).text() - const urlRegex = /url\((https:\/\/fonts.gstatic.com\/s\/.*?.ttf)\)/g - const match = urlRegex.exec(css) - if (match) { - // fontData is an ArrayBuffer containing the .ttf file data - const fontTtf = await (await fetch(match[1])).arrayBuffer() - resolve({ name: fontName, data: fontTtf, weight: weight as FontWeight, style: "normal" }) - } else { - reject("Could not fetch font") - } - }) -} - -// Type helper -type GetElementType = T extends (infer U)[] ? U : never diff --git a/quartz/util/imageHelper.ts b/quartz/util/imageHelper.ts new file mode 100644 index 000000000..71119240a --- /dev/null +++ b/quartz/util/imageHelper.ts @@ -0,0 +1,49 @@ +import { FontWeight, SatoriOptions } from "satori/wasm" + +/** + * Get an array of `FontOptions` (for satori) given google font names + * @param headerFontName name of google font used for header + * @param bodyFontName name of google font used for body + * @returns FontOptions for header and body + */ +export async function getSatoriFont(headerFontName: string, bodyFontName: string) { + const headerWeight = 700 as FontWeight + const bodyWeight = 400 as FontWeight + + // Fetch fonts + const headerFont = await fetchTtf(headerFontName, headerWeight) + const bodyFont = await fetchTtf(bodyFontName, bodyWeight) + + // Convert fonts to satori font format and return + const fonts: SatoriOptions["fonts"] = [ + { name: headerFontName, data: headerFont, weight: headerWeight, style: "normal" }, + { name: bodyFontName, data: bodyFont, weight: bodyWeight, style: "normal" }, + ] + return fonts +} + +/** + * Get the `.ttf` file of a google font + * @param fontName name of google font + * @param weight what font weight to fetch font + * @returns `.ttf` file of google font + */ +function fetchTtf(fontName: string, weight: FontWeight): Promise { + return new Promise(async (resolve, reject) => { + // Get css file from google fonts + const css = await ( + await fetch(`https://fonts.googleapis.com/css?family=${fontName}:${weight}`) + ).text() + + // Extract .ttf url from css file + const urlRegex = /url\((https:\/\/fonts.gstatic.com\/s\/.*?.ttf)\)/g + const match = urlRegex.exec(css) + if (match) { + // fontData is an ArrayBuffer containing the .ttf file data + const fontData = await (await fetch(match[1])).arrayBuffer() + resolve(fontData) + } else { + reject("Could not fetch font") + } + }) +}