fix: parse parallelization chunk arg, inline b64 for og image
This commit is contained in:
parent
a737207981
commit
e86544064c
4 changed files with 49 additions and 35 deletions
|
@ -1,7 +1,7 @@
|
|||
import { QuartzEmitterPlugin } from "../types"
|
||||
import { i18n } from "../../i18n"
|
||||
import { unescapeHTML } from "../../util/escape"
|
||||
import { FullSlug, getFileExtension } from "../../util/path"
|
||||
import { FullSlug, getFileExtension, joinSegments, QUARTZ } from "../../util/path"
|
||||
import { ImageOptions, SocialImageOptions, defaultImage, getSatoriFonts } from "../../util/og"
|
||||
import sharp from "sharp"
|
||||
import satori, { SatoriOptions } from "satori"
|
||||
|
@ -10,6 +10,8 @@ import { Readable } from "stream"
|
|||
import { write } from "./helpers"
|
||||
import { BuildCtx } from "../../util/ctx"
|
||||
import { QuartzPluginData } from "../vfile"
|
||||
import fs from "node:fs/promises"
|
||||
import chalk from "chalk"
|
||||
|
||||
const defaultOptions: SocialImageOptions = {
|
||||
colorScheme: "lightMode",
|
||||
|
@ -28,7 +30,25 @@ async function generateSocialImage(
|
|||
userOpts: SocialImageOptions,
|
||||
): Promise<Readable> {
|
||||
const { width, height } = userOpts
|
||||
const imageComponent = userOpts.imageStructure(cfg, userOpts, title, description, fonts, fileData)
|
||||
const iconPath = joinSegments(QUARTZ, "static", "icon.png")
|
||||
let iconBase64: string | undefined = undefined
|
||||
try {
|
||||
const iconData = await fs.readFile(iconPath)
|
||||
iconBase64 = `data:image/png;base64,${iconData.toString("base64")}`
|
||||
} catch (err) {
|
||||
console.warn(chalk.yellow(`Warning: Could not find icon at ${iconPath}`))
|
||||
}
|
||||
|
||||
const imageComponent = userOpts.imageStructure({
|
||||
cfg,
|
||||
userOpts,
|
||||
title,
|
||||
description,
|
||||
fonts,
|
||||
fileData,
|
||||
iconBase64,
|
||||
})
|
||||
|
||||
const svg = await satori(imageComponent, {
|
||||
width,
|
||||
height,
|
||||
|
|
|
@ -172,7 +172,7 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise<Pro
|
|||
workerType: "thread",
|
||||
})
|
||||
const errorHandler = (err: any) => {
|
||||
console.error(`${err}`.replace(/^error:\s*/i, ""))
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise<Pro
|
|||
|
||||
const markdownToHtmlPromises: WorkerPromise<ProcessedContent[]>[] = []
|
||||
processedFiles = 0
|
||||
for (const [mdChunk, _] of mdResults) {
|
||||
for (const mdChunk of mdResults) {
|
||||
markdownToHtmlPromises.push(pool.exec("processHtml", [serializableCtx, mdChunk]))
|
||||
}
|
||||
const results: ProcessedContent[][] = await Promise.all(
|
||||
|
|
|
@ -35,7 +35,7 @@ export class QuartzLogger {
|
|||
const truncated = truncate(output, columns)
|
||||
process.stdout.write(truncated)
|
||||
this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerChars.length
|
||||
}, 20)
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import chalk from "chalk"
|
|||
|
||||
const defaultHeaderWeight = [700]
|
||||
const defaultBodyWeight = [400]
|
||||
|
||||
export async function getSatoriFonts(headerFont: FontSpecification, bodyFont: FontSpecification) {
|
||||
// Get all weights for header and body fonts
|
||||
const headerWeights: FontWeight[] = (
|
||||
|
@ -134,21 +135,12 @@ export type SocialImageOptions = {
|
|||
excludeRoot: boolean
|
||||
/**
|
||||
* JSX to use for generating image. See satori docs for more info (https://github.com/vercel/satori)
|
||||
* @param cfg global quartz config
|
||||
* @param userOpts options that can be set by user
|
||||
* @param title title of current page
|
||||
* @param description description of current page
|
||||
* @param fonts global font that can be used for styling
|
||||
* @param fileData full fileData of current page
|
||||
* @returns prepared jsx to be used for generating image
|
||||
*/
|
||||
imageStructure: (
|
||||
cfg: GlobalConfiguration,
|
||||
userOpts: UserOpts,
|
||||
title: string,
|
||||
description: string,
|
||||
fonts: SatoriOptions["fonts"],
|
||||
fileData: QuartzPluginData,
|
||||
options: ImageOptions & {
|
||||
userOpts: UserOpts
|
||||
iconBase64?: string
|
||||
},
|
||||
) => JSXInternal.Element
|
||||
}
|
||||
|
||||
|
@ -178,17 +170,17 @@ export type ImageOptions = {
|
|||
}
|
||||
|
||||
// This is the default template for generated social image.
|
||||
export const defaultImage: SocialImageOptions["imageStructure"] = (
|
||||
cfg: GlobalConfiguration,
|
||||
{ colorScheme }: UserOpts,
|
||||
title: string,
|
||||
description: string,
|
||||
_fonts: SatoriOptions["fonts"],
|
||||
fileData: QuartzPluginData,
|
||||
) => {
|
||||
export const defaultImage: SocialImageOptions["imageStructure"] = ({
|
||||
cfg,
|
||||
userOpts,
|
||||
title,
|
||||
description,
|
||||
fileData,
|
||||
iconBase64,
|
||||
}) => {
|
||||
const { colorScheme } = userOpts
|
||||
const fontBreakPoint = 32
|
||||
const useSmallerFont = title.length > fontBreakPoint
|
||||
const iconPath = `https://${cfg.baseUrl}/static/icon.png`
|
||||
|
||||
// Format date if available
|
||||
const rawDate = getDate(cfg, fileData)
|
||||
|
@ -226,14 +218,16 @@ export const defaultImage: SocialImageOptions["imageStructure"] = (
|
|||
marginBottom: "0.5rem",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={iconPath}
|
||||
width={56}
|
||||
height={56}
|
||||
style={{
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
/>
|
||||
{iconBase64 && (
|
||||
<img
|
||||
src={iconBase64}
|
||||
width={56}
|
||||
height={56}
|
||||
style={{
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
|
|
Loading…
Add table
Reference in a new issue