mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-31 00:34:05 -06:00
feat: use config header + body fonts for satori
This commit is contained in:
parent
5ea283ac1a
commit
346dbfe3e3
@ -3,7 +3,7 @@ import { JSResourceToScriptElement } from "../util/resources"
|
|||||||
import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
||||||
import satori from "satori"
|
import satori from "satori"
|
||||||
import * as fs from "fs"
|
import * as fs from "fs"
|
||||||
import { getTtfFromGfont } from "../util/fonts"
|
import { getSatoriFont } from "../util/fonts"
|
||||||
import { GlobalConfiguration } from "../cfg"
|
import { GlobalConfiguration } from "../cfg"
|
||||||
import sharp from "sharp"
|
import sharp from "sharp"
|
||||||
|
|
||||||
@ -12,20 +12,22 @@ import sharp from "sharp"
|
|||||||
* @param title what title to use
|
* @param title what title to use
|
||||||
* @param description what description to use
|
* @param description what description to use
|
||||||
* @param fileName what fileName to use when writing to disk
|
* @param fileName what fileName to use when writing to disk
|
||||||
* @param fontName name of font to use (must be google font)
|
* @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 cfg `GlobalConfiguration` of quartz
|
* @param cfg `GlobalConfiguration` of quartz
|
||||||
*/
|
*/
|
||||||
async function generateSocialImage(
|
async function generateSocialImage(
|
||||||
title: string,
|
title: string,
|
||||||
description: string,
|
description: string,
|
||||||
fileName: string,
|
fileName: string,
|
||||||
fontName: string,
|
headerFontName: string,
|
||||||
|
bodyFontName: string,
|
||||||
cfg: GlobalConfiguration,
|
cfg: GlobalConfiguration,
|
||||||
colorScheme: "lightMode" | "darkMode",
|
colorScheme: "lightMode" | "darkMode",
|
||||||
) {
|
) {
|
||||||
const font = (await getTtfFromGfont(fontName)) as ArrayBuffer
|
const fonts = await getSatoriFont(headerFontName, bodyFontName)
|
||||||
// How many characters are allowed before switching to smaller font
|
// How many characters are allowed before switching to smaller font
|
||||||
const fontBreakPoint = 26
|
const fontBreakPoint = 22
|
||||||
const useSmallerFont = title.length > fontBreakPoint
|
const useSmallerFont = title.length > fontBreakPoint
|
||||||
const svg = await satori(
|
const svg = await satori(
|
||||||
<div
|
<div
|
||||||
@ -52,28 +54,30 @@ async function generateSocialImage(
|
|||||||
paddingBottom: "2rem",
|
paddingBottom: "2rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<p
|
||||||
style={{
|
style={{
|
||||||
color: cfg.theme.colors[colorScheme].dark,
|
color: cfg.theme.colors[colorScheme].dark,
|
||||||
fontSize: useSmallerFont ? 70 : 80,
|
fontSize: useSmallerFont ? 70 : 82,
|
||||||
marginLeft: "4rem",
|
marginLeft: "4rem",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginRight: "4rem",
|
marginRight: "4rem",
|
||||||
|
fontFamily: fonts[0].name,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</p>
|
||||||
<div
|
<p
|
||||||
style={{
|
style={{
|
||||||
color: cfg.theme.colors[colorScheme].dark,
|
color: cfg.theme.colors[colorScheme].dark,
|
||||||
fontSize: 44,
|
fontSize: 44,
|
||||||
marginLeft: "8rem",
|
marginLeft: "8rem",
|
||||||
marginRight: "8rem",
|
marginRight: "8rem",
|
||||||
lineClamp: 3,
|
lineClamp: 3,
|
||||||
|
fontFamily: fonts[1].name,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{description}
|
{description}
|
||||||
</div>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -88,20 +92,7 @@ async function generateSocialImage(
|
|||||||
{
|
{
|
||||||
width: ogHeight,
|
width: ogHeight,
|
||||||
height: ogWidth,
|
height: ogWidth,
|
||||||
fonts: [
|
fonts: fonts,
|
||||||
{
|
|
||||||
name: fontName,
|
|
||||||
data: font,
|
|
||||||
weight: 800,
|
|
||||||
style: "normal",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: fontName,
|
|
||||||
data: font,
|
|
||||||
weight: 400,
|
|
||||||
style: "normal",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -121,7 +112,7 @@ export default (() => {
|
|||||||
let font: Promise<ArrayBuffer | undefined>
|
let font: Promise<ArrayBuffer | undefined>
|
||||||
function Head({ cfg, fileData, externalResources }: QuartzComponentProps) {
|
function Head({ cfg, fileData, externalResources }: QuartzComponentProps) {
|
||||||
if (!font) {
|
if (!font) {
|
||||||
font = getTtfFromGfont(cfg.theme.typography.header)
|
// font = getSatoriFont(cfg.theme.typography.header)
|
||||||
}
|
}
|
||||||
const slug = fileData.filePath
|
const slug = fileData.filePath
|
||||||
const filePath = slug?.replaceAll("/", "-")
|
const filePath = slug?.replaceAll("/", "-")
|
||||||
@ -133,6 +124,7 @@ export default (() => {
|
|||||||
description,
|
description,
|
||||||
filePath as string,
|
filePath as string,
|
||||||
cfg.theme.typography.header,
|
cfg.theme.typography.header,
|
||||||
|
cfg.theme.typography.body,
|
||||||
cfg,
|
cfg,
|
||||||
"lightMode",
|
"lightMode",
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,14 +1,38 @@
|
|||||||
|
import { FontWeight, SatoriOptions } from "satori/wasm"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the `.ttf` file (as ArrayBuffer) of a font by google font name
|
* Get an array of `FontOptions` (for satori) given google font names
|
||||||
* @param font a valid google font
|
* @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 getTtfFromGfont(font: string) {
|
export async function getSatoriFont(headerFontName: string, bodyFontName: string) {
|
||||||
const css = await (await fetch(`https://fonts.googleapis.com/css?family=${font}`)).text()
|
const headerFont = await fetchTtf(headerFontName, 700)
|
||||||
const urlRegex = /url\((https:\/\/fonts.gstatic.com\/s\/.*?.ttf)\)/g
|
const bodyFont = await fetchTtf(bodyFontName, 400)
|
||||||
const match = urlRegex.exec(css)
|
|
||||||
if (match) {
|
const fonts: SatoriOptions["fonts"] = [headerFont, bodyFont]
|
||||||
// fontData is an ArrayBuffer containing the .ttf file data
|
return fonts
|
||||||
const fontTtf = await (await fetch(match[1])).arrayBuffer()
|
|
||||||
return fontTtf
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetchTtf(
|
||||||
|
fontName: string,
|
||||||
|
weight: FontWeight,
|
||||||
|
): Promise<GetElementType<SatoriOptions["fonts"]>> {
|
||||||
|
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 any[]> = T extends (infer U)[] ? U : never
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user