refactor: make image generation cleaner

This commit is contained in:
Ben Schlegel 2023-09-24 13:36:17 +02:00
parent 3a47f383b0
commit bb9e857bf7
No known key found for this signature in database
GPG Key ID: 8BDB8891C1575E22
2 changed files with 74 additions and 21 deletions

View File

@ -14,21 +14,56 @@ export type SocialImageOptions = {
colorScheme?: "lightMode" | "darkMode"
}
type ImageOptions = {
/**
* what title to use as header in image
*/
title: string
/**
* what description to use as body in image
*/
description: string
/**
* what fileName to use when writing to disk
*/
fileName: string
/**
* what directory to store image in
*/
fileDir: string
/**
* what file extension to use (should be `webp` unless you also change sharp conversion)
*/
fileExt: string
/**
* What height to generate image with (in px)
*/
imgHeight: number
/**
* What width to generate image with (in px)
*/
imgWidth: number
/**
* header + body font to be used when generating satori image (as promise to work around sync in component)
*/
fontsPromise: Promise<SatoriOptions["fonts"]>
/**
* `GlobalConfiguration` of quartz (used for theme/typography)
*/
cfg: GlobalConfiguration
imageHtml?: (
cfg: GlobalConfiguration,
title: string,
description: string,
) => Parameters<typeof satori>["0"]
}
/**
* Generates social image (OG/twitter standard) and saves it as `.web` inside the public folder
* @param title what title to use
* @param description what description to use
* @param fileName what fileName to use when writing to disk
* @param fontsPromise header + body font to be used when generating satori image (as promise to work around sync in component)
* @param cfg `GlobalConfiguration` of quartz
* @param opts options for generating image
*/
async function generateSocialImage(
title: string,
description: string,
fileName: string,
fontsPromise: Promise<SatoriOptions["fonts"]>,
cfg: GlobalConfiguration,
) {
async function generateSocialImage(opts: ImageOptions) {
const { cfg, description, fileName, fontsPromise, title, imageHtml } = opts
const fonts = await fontsPromise
// How many characters are allowed before switching to smaller font
@ -126,7 +161,8 @@ export default (() => {
fontsPromise = getSatoriFont(cfg.theme.typography.header, cfg.theme.typography.body)
}
const slug = fileData.filePath
const filePath = slug?.replaceAll("/", "-")
// since "/" is not a valid character in file names, replace with "-"
const fileName = slug?.replaceAll("/", "-")
const title = fileData.frontmatter?.title ?? "Untitled"
// Get file description (priority: frontmatter > fileData > default)
@ -141,8 +177,20 @@ export default (() => {
fs.mkdirSync(imageDir, { recursive: true })
}
// Generate social image (happens async)
generateSocialImage(title, description, filePath as string, fontsPromise, cfg)
if (fileName) {
// Generate social image (happens async)
generateSocialImage({
title,
description,
fileName,
fileDir: imageDir,
imgHeight: ogHeight,
imgWidth: ogWidth,
fileExt: extension,
fontsPromise,
cfg,
})
}
}
const { css, js } = externalResources
@ -157,10 +205,10 @@ export default (() => {
const ogImageGeneratedPath = `https://${cfg.baseUrl}/${imageDir.replace(
"public/",
"",
)}/${filePath}.${extension}`
)}/${fileName}.${extension}`
// Use default og image if filePath doesnt exist (for autogenerated paths with no .md file)
const useDefaultOgImage = filePath === undefined || !cfg.generateSocialImages
const useDefaultOgImage = fileName === undefined || !cfg.generateSocialImages
// Path to og/social image (priority: frontmatter > generated image (if enabled) > default image)
let ogImagePath = useDefaultOgImage ? ogImageDefaultPath : ogImageGeneratedPath
@ -185,11 +233,11 @@ export default (() => {
<meta property="og:description" content={description} />
<meta property="og:image:type" content={`image/${extension}`} />
<meta property="og:image:alt" content={description} />
<meta property="og:image:width" content={"" + ogWidth} />
<meta property="og:image:height" content={"" + ogHeight} />
<meta property="og:image:width" content={ogWidth.toString()} />
<meta property="og:image:height" content={ogHeight.toString()} />
<meta property="og:image:url" content={ogImagePath} />
<meta property="og:width" content={"" + ogWidth} />
<meta property="og:height" content={"" + ogHeight} />
<meta property="og:width" content={ogWidth.toString()} />
<meta property="og:height" content={ogHeight.toString()} />
{cfg.baseUrl && (
<>
<meta name="twitter:image" content={ogImagePath} />

View File

@ -0,0 +1,5 @@
import { GlobalConfiguration } from "../cfg"
export const defaultImage = (cfg: GlobalConfiguration, title: string, description: string) => (
<div />
)