fix(og): search for font family properly
This commit is contained in:
parent
696403d3fa
commit
5928d82a56
2 changed files with 47 additions and 35 deletions
|
@ -234,7 +234,7 @@ export const ComponentResources: QuartzEmitterPlugin = () => {
|
||||||
for (const fontFile of fontFiles) {
|
for (const fontFile of fontFiles) {
|
||||||
const res = await fetch(fontFile.url)
|
const res = await fetch(fontFile.url)
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`failed to fetch font ${fontFile.filename}`)
|
throw new Error(`Failed to fetch font ${fontFile.filename}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const buf = await res.arrayBuffer()
|
const buf = await res.arrayBuffer()
|
||||||
|
|
|
@ -3,12 +3,13 @@ import { FontWeight, SatoriOptions } from "satori/wasm"
|
||||||
import { GlobalConfiguration } from "../cfg"
|
import { GlobalConfiguration } from "../cfg"
|
||||||
import { QuartzPluginData } from "../plugins/vfile"
|
import { QuartzPluginData } from "../plugins/vfile"
|
||||||
import { JSXInternal } from "preact/src/jsx"
|
import { JSXInternal } from "preact/src/jsx"
|
||||||
import { FontSpecification, ThemeKey } from "./theme"
|
import { FontSpecification, getFontSpecificationName, ThemeKey } from "./theme"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { QUARTZ } from "./path"
|
import { QUARTZ } from "./path"
|
||||||
import { formatDate, getDate } from "../components/Date"
|
import { formatDate, getDate } from "../components/Date"
|
||||||
import readingTime from "reading-time"
|
import readingTime from "reading-time"
|
||||||
import { i18n } from "../i18n"
|
import { i18n } from "../i18n"
|
||||||
|
import chalk from "chalk"
|
||||||
|
|
||||||
const defaultHeaderWeight = [700]
|
const defaultHeaderWeight = [700]
|
||||||
const defaultBodyWeight = [400]
|
const defaultBodyWeight = [400]
|
||||||
|
@ -26,29 +27,38 @@ export async function getSatoriFonts(headerFont: FontSpecification, bodyFont: Fo
|
||||||
const headerFontName = typeof headerFont === "string" ? headerFont : headerFont.name
|
const headerFontName = typeof headerFont === "string" ? headerFont : headerFont.name
|
||||||
const bodyFontName = typeof bodyFont === "string" ? bodyFont : bodyFont.name
|
const bodyFontName = typeof bodyFont === "string" ? bodyFont : bodyFont.name
|
||||||
|
|
||||||
// Fetch fonts for all weights
|
// Fetch fonts for all weights and convert to satori format in one go
|
||||||
const headerFontPromises = headerWeights.map((weight) => fetchTtf(headerFontName, weight))
|
const headerFontPromises = headerWeights.map(async (weight) => {
|
||||||
const bodyFontPromises = bodyWeights.map((weight) => fetchTtf(bodyFontName, weight))
|
const data = await fetchTtf(headerFontName, weight)
|
||||||
|
if (!data) return null
|
||||||
|
return {
|
||||||
|
name: headerFontName,
|
||||||
|
data,
|
||||||
|
weight,
|
||||||
|
style: "normal" as const,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const [headerFontData, bodyFontData] = await Promise.all([
|
const bodyFontPromises = bodyWeights.map(async (weight) => {
|
||||||
|
const data = await fetchTtf(bodyFontName, weight)
|
||||||
|
if (!data) return null
|
||||||
|
return {
|
||||||
|
name: bodyFontName,
|
||||||
|
data,
|
||||||
|
weight,
|
||||||
|
style: "normal" as const,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const [headerFonts, bodyFonts] = await Promise.all([
|
||||||
Promise.all(headerFontPromises),
|
Promise.all(headerFontPromises),
|
||||||
Promise.all(bodyFontPromises),
|
Promise.all(bodyFontPromises),
|
||||||
])
|
])
|
||||||
|
|
||||||
// Convert fonts to satori font format and return
|
// Filter out any failed fetches and combine header and body fonts
|
||||||
const fonts: SatoriOptions["fonts"] = [
|
const fonts: SatoriOptions["fonts"] = [
|
||||||
...headerFontData.map((data, idx) => ({
|
...headerFonts.filter((font): font is NonNullable<typeof font> => font !== null),
|
||||||
name: headerFontName,
|
...bodyFonts.filter((font): font is NonNullable<typeof font> => font !== null),
|
||||||
data,
|
|
||||||
weight: headerWeights[idx],
|
|
||||||
style: "normal" as const,
|
|
||||||
})),
|
|
||||||
...bodyFontData.map((data, idx) => ({
|
|
||||||
name: bodyFontName,
|
|
||||||
data,
|
|
||||||
weight: bodyWeights[idx],
|
|
||||||
style: "normal" as const,
|
|
||||||
})),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
return fonts
|
return fonts
|
||||||
|
@ -61,10 +71,11 @@ export async function getSatoriFonts(headerFont: FontSpecification, bodyFont: Fo
|
||||||
* @returns `.ttf` file of google font
|
* @returns `.ttf` file of google font
|
||||||
*/
|
*/
|
||||||
export async function fetchTtf(
|
export async function fetchTtf(
|
||||||
fontName: string,
|
rawFontName: string,
|
||||||
weight: FontWeight,
|
weight: FontWeight,
|
||||||
): Promise<Buffer<ArrayBufferLike>> {
|
): Promise<Buffer<ArrayBufferLike> | undefined> {
|
||||||
const cacheKey = `${fontName.replaceAll(" ", "-")}-${weight}`
|
const fontName = rawFontName.replaceAll(" ", "+")
|
||||||
|
const cacheKey = `${fontName}-${weight}`
|
||||||
const cacheDir = path.join(QUARTZ, ".quartz-cache", "fonts")
|
const cacheDir = path.join(QUARTZ, ".quartz-cache", "fonts")
|
||||||
const cachePath = path.join(cacheDir, cacheKey)
|
const cachePath = path.join(cacheDir, cacheKey)
|
||||||
|
|
||||||
|
@ -87,20 +98,19 @@ export async function fetchTtf(
|
||||||
const match = urlRegex.exec(css)
|
const match = urlRegex.exec(css)
|
||||||
|
|
||||||
if (!match) {
|
if (!match) {
|
||||||
throw new Error("Could not fetch font")
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
`\nWarning: Failed to fetch font ${rawFontName} with weight ${weight}, got ${cssResponse.statusText}`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// fontData is an ArrayBuffer containing the .ttf file data
|
// fontData is an ArrayBuffer containing the .ttf file data
|
||||||
const fontResponse = await fetch(match[1])
|
const fontResponse = await fetch(match[1])
|
||||||
const fontData = Buffer.from(await fontResponse.arrayBuffer())
|
const fontData = Buffer.from(await fontResponse.arrayBuffer())
|
||||||
|
|
||||||
try {
|
|
||||||
await fs.mkdir(cacheDir, { recursive: true })
|
await fs.mkdir(cacheDir, { recursive: true })
|
||||||
await fs.writeFile(cachePath, fontData)
|
await fs.writeFile(cachePath, fontData)
|
||||||
} catch (error) {
|
|
||||||
console.warn(`Failed to cache font: ${error}`)
|
|
||||||
// Continue even if caching fails
|
|
||||||
}
|
|
||||||
|
|
||||||
return fontData
|
return fontData
|
||||||
}
|
}
|
||||||
|
@ -173,7 +183,7 @@ export const defaultImage: SocialImageOptions["imageStructure"] = (
|
||||||
{ colorScheme }: UserOpts,
|
{ colorScheme }: UserOpts,
|
||||||
title: string,
|
title: string,
|
||||||
description: string,
|
description: string,
|
||||||
fonts: SatoriOptions["fonts"],
|
_fonts: SatoriOptions["fonts"],
|
||||||
fileData: QuartzPluginData,
|
fileData: QuartzPluginData,
|
||||||
) => {
|
) => {
|
||||||
const fontBreakPoint = 32
|
const fontBreakPoint = 32
|
||||||
|
@ -192,6 +202,8 @@ export const defaultImage: SocialImageOptions["imageStructure"] = (
|
||||||
|
|
||||||
// Get tags if available
|
// Get tags if available
|
||||||
const tags = fileData.frontmatter?.tags ?? []
|
const tags = fileData.frontmatter?.tags ?? []
|
||||||
|
const bodyFont = getFontSpecificationName(cfg.theme.typography.body)
|
||||||
|
const headerFont = getFontSpecificationName(cfg.theme.typography.header)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -202,7 +214,7 @@ export const defaultImage: SocialImageOptions["imageStructure"] = (
|
||||||
width: "100%",
|
width: "100%",
|
||||||
backgroundColor: cfg.theme.colors[colorScheme].light,
|
backgroundColor: cfg.theme.colors[colorScheme].light,
|
||||||
padding: "2.5rem",
|
padding: "2.5rem",
|
||||||
fontFamily: fonts[1].name,
|
fontFamily: bodyFont,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Header Section */}
|
{/* Header Section */}
|
||||||
|
@ -227,7 +239,7 @@ export const defaultImage: SocialImageOptions["imageStructure"] = (
|
||||||
display: "flex",
|
display: "flex",
|
||||||
fontSize: 32,
|
fontSize: 32,
|
||||||
color: cfg.theme.colors[colorScheme].gray,
|
color: cfg.theme.colors[colorScheme].gray,
|
||||||
fontFamily: fonts[1].name,
|
fontFamily: bodyFont,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{cfg.baseUrl}
|
{cfg.baseUrl}
|
||||||
|
@ -246,7 +258,7 @@ export const defaultImage: SocialImageOptions["imageStructure"] = (
|
||||||
style={{
|
style={{
|
||||||
margin: 0,
|
margin: 0,
|
||||||
fontSize: useSmallerFont ? 64 : 72,
|
fontSize: useSmallerFont ? 64 : 72,
|
||||||
fontFamily: fonts[0].name,
|
fontFamily: headerFont,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
color: cfg.theme.colors[colorScheme].dark,
|
color: cfg.theme.colors[colorScheme].dark,
|
||||||
lineHeight: 1.2,
|
lineHeight: 1.2,
|
||||||
|
|
Loading…
Add table
Reference in a new issue