Skip to content

Commit e865440

Browse files
committed
fix: parse parallelization chunk arg, inline b64 for og image
1 parent a737207 commit e865440

File tree

4 files changed

+49
-35
lines changed

4 files changed

+49
-35
lines changed

quartz/plugins/emitters/ogImage.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { QuartzEmitterPlugin } from "../types"
22
import { i18n } from "../../i18n"
33
import { unescapeHTML } from "../../util/escape"
4-
import { FullSlug, getFileExtension } from "../../util/path"
4+
import { FullSlug, getFileExtension, joinSegments, QUARTZ } from "../../util/path"
55
import { ImageOptions, SocialImageOptions, defaultImage, getSatoriFonts } from "../../util/og"
66
import sharp from "sharp"
77
import satori, { SatoriOptions } from "satori"
@@ -10,6 +10,8 @@ import { Readable } from "stream"
1010
import { write } from "./helpers"
1111
import { BuildCtx } from "../../util/ctx"
1212
import { QuartzPluginData } from "../vfile"
13+
import fs from "node:fs/promises"
14+
import chalk from "chalk"
1315

1416
const defaultOptions: SocialImageOptions = {
1517
colorScheme: "lightMode",
@@ -28,7 +30,25 @@ async function generateSocialImage(
2830
userOpts: SocialImageOptions,
2931
): Promise<Readable> {
3032
const { width, height } = userOpts
31-
const imageComponent = userOpts.imageStructure(cfg, userOpts, title, description, fonts, fileData)
33+
const iconPath = joinSegments(QUARTZ, "static", "icon.png")
34+
let iconBase64: string | undefined = undefined
35+
try {
36+
const iconData = await fs.readFile(iconPath)
37+
iconBase64 = `data:image/png;base64,${iconData.toString("base64")}`
38+
} catch (err) {
39+
console.warn(chalk.yellow(`Warning: Could not find icon at ${iconPath}`))
40+
}
41+
42+
const imageComponent = userOpts.imageStructure({
43+
cfg,
44+
userOpts,
45+
title,
46+
description,
47+
fonts,
48+
fileData,
49+
iconBase64,
50+
})
51+
3252
const svg = await satori(imageComponent, {
3353
width,
3454
height,

quartz/processors/parse.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise<Pro
172172
workerType: "thread",
173173
})
174174
const errorHandler = (err: any) => {
175-
console.error(`${err}`.replace(/^error:\s*/i, ""))
175+
console.error(err)
176176
process.exit(1)
177177
}
178178

@@ -201,7 +201,7 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise<Pro
201201

202202
const markdownToHtmlPromises: WorkerPromise<ProcessedContent[]>[] = []
203203
processedFiles = 0
204-
for (const [mdChunk, _] of mdResults) {
204+
for (const mdChunk of mdResults) {
205205
markdownToHtmlPromises.push(pool.exec("processHtml", [serializableCtx, mdChunk]))
206206
}
207207
const results: ProcessedContent[][] = await Promise.all(

quartz/util/log.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export class QuartzLogger {
3535
const truncated = truncate(output, columns)
3636
process.stdout.write(truncated)
3737
this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerChars.length
38-
}, 20)
38+
}, 50)
3939
}
4040
}
4141

quartz/util/og.tsx

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import chalk from "chalk"
1313

1414
const defaultHeaderWeight = [700]
1515
const defaultBodyWeight = [400]
16+
1617
export async function getSatoriFonts(headerFont: FontSpecification, bodyFont: FontSpecification) {
1718
// Get all weights for header and body fonts
1819
const headerWeights: FontWeight[] = (
@@ -134,21 +135,12 @@ export type SocialImageOptions = {
134135
excludeRoot: boolean
135136
/**
136137
* JSX to use for generating image. See satori docs for more info (https://github.com/vercel/satori)
137-
* @param cfg global quartz config
138-
* @param userOpts options that can be set by user
139-
* @param title title of current page
140-
* @param description description of current page
141-
* @param fonts global font that can be used for styling
142-
* @param fileData full fileData of current page
143-
* @returns prepared jsx to be used for generating image
144138
*/
145139
imageStructure: (
146-
cfg: GlobalConfiguration,
147-
userOpts: UserOpts,
148-
title: string,
149-
description: string,
150-
fonts: SatoriOptions["fonts"],
151-
fileData: QuartzPluginData,
140+
options: ImageOptions & {
141+
userOpts: UserOpts
142+
iconBase64?: string
143+
},
152144
) => JSXInternal.Element
153145
}
154146

@@ -178,17 +170,17 @@ export type ImageOptions = {
178170
}
179171

180172
// This is the default template for generated social image.
181-
export const defaultImage: SocialImageOptions["imageStructure"] = (
182-
cfg: GlobalConfiguration,
183-
{ colorScheme }: UserOpts,
184-
title: string,
185-
description: string,
186-
_fonts: SatoriOptions["fonts"],
187-
fileData: QuartzPluginData,
188-
) => {
173+
export const defaultImage: SocialImageOptions["imageStructure"] = ({
174+
cfg,
175+
userOpts,
176+
title,
177+
description,
178+
fileData,
179+
iconBase64,
180+
}) => {
181+
const { colorScheme } = userOpts
189182
const fontBreakPoint = 32
190183
const useSmallerFont = title.length > fontBreakPoint
191-
const iconPath = `https://${cfg.baseUrl}/static/icon.png`
192184

193185
// Format date if available
194186
const rawDate = getDate(cfg, fileData)
@@ -226,14 +218,16 @@ export const defaultImage: SocialImageOptions["imageStructure"] = (
226218
marginBottom: "0.5rem",
227219
}}
228220
>
229-
<img
230-
src={iconPath}
231-
width={56}
232-
height={56}
233-
style={{
234-
borderRadius: "50%",
235-
}}
236-
/>
221+
{iconBase64 && (
222+
<img
223+
src={iconBase64}
224+
width={56}
225+
height={56}
226+
style={{
227+
borderRadius: "50%",
228+
}}
229+
/>
230+
)}
237231
<div
238232
style={{
239233
display: "flex",

0 commit comments

Comments
 (0)