From 715446272a4fb86e1d905ec4e67698c225a8048c Mon Sep 17 00:00:00 2001 From: Ben Schlegel Date: Tue, 19 Sep 2023 19:41:42 +0200 Subject: [PATCH] feat: add basic satori og image generation --- package.json | 1 + quartz/components/Head.tsx | 59 +++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a2085cef..4bf721f66 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "remark-rehype": "^10.1.0", "remark-smartypants": "^2.0.0", "rimraf": "^5.0.1", + "satori": "^0.10.6", "serve-handler": "^6.1.5", "source-map-support": "^0.5.21", "to-vfile": "^7.2.4", diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index 2bf263817..ccc1d764d 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -1,9 +1,65 @@ import { FullSlug, _stripSlashes, joinSegments, pathToRoot } from "../util/path" import { JSResourceToScriptElement } from "../util/resources" import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import satori from "satori" +import * as fs from "fs" + +const robotoData = await ( + await fetch("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Me5Q.ttf") +).arrayBuffer() + +async function generateSvg(title: string, filePath: string) { + const svg = await satori( +
+ {title} +
, + { + width: 1200, + height: 675, + fonts: [ + { + name: "Roboto", + // Use `fs` (Node.js only) or `fetch` to read the font as Buffer/ArrayBuffer and provide `data` here. + data: robotoData, + weight: 400, + style: "normal", + }, + ], + }, + ) + + fs.writeFileSync(`public/static/${filePath}.svg`, svg) +} export default (() => { function Head({ cfg, fileData, externalResources }: QuartzComponentProps) { + const dir = "public/static" + const slug = fileData.filePath + const filePath = slug?.replaceAll("/", "-") + const ogArr = slug?.split("/") + const ogTitle = fileData.frontmatter?.title ?? "Untitled" + + // const title = fileData?.fron + // console.log("filePath: ", filePath) + // if (ogTitle && filePath) { + console.log("OG title: ", ogTitle) + generateSvg(ogTitle as string, filePath as string) + // } + + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir) + } const title = fileData.frontmatter?.title ?? "Untitled" const description = fileData.description?.trim() ?? "No description provided" const { css, js } = externalResources @@ -14,6 +70,7 @@ export default (() => { const iconPath = joinSegments(baseDir, "static/icon.png") const ogImagePath = `https://${cfg.baseUrl}/static/og-image.png` + const ogImagePathNew = `https://${cfg.baseUrl}/static/${filePath}.svg` return ( @@ -22,7 +79,7 @@ export default (() => { - {cfg.baseUrl && } + {cfg.baseUrl && }