mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-28 07:14:05 -06:00
feat: add config option for social images
This commit is contained in:
parent
b207477248
commit
997044d6d1
@ -1,4 +1,5 @@
|
||||
import { ValidDateType } from "./components/Date"
|
||||
import { SocialImageOptions } from "./components/Head"
|
||||
import { QuartzComponent } from "./components/types"
|
||||
import { PluginTypes } from "./plugins/types"
|
||||
import { Theme } from "./util/theme"
|
||||
@ -33,6 +34,10 @@ export interface GlobalConfiguration {
|
||||
* Quartz will avoid using this as much as possible and use relative URLs most of the time
|
||||
*/
|
||||
baseUrl?: string
|
||||
/**
|
||||
* Wether to generate and use social images (Open Graph and Twitter standard) for link previews
|
||||
*/
|
||||
generateSocialImages: boolean | SocialImageOptions
|
||||
theme: Theme
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,13 @@ import { getSatoriFont } from "../util/fonts"
|
||||
import { GlobalConfiguration } from "../cfg"
|
||||
import sharp from "sharp"
|
||||
|
||||
export type SocialImageOptions = {
|
||||
/**
|
||||
* What color scheme to use for image generation (uses colors from config theme)
|
||||
*/
|
||||
colorScheme?: "lightMode" | "darkMode"
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates social image (OG/twitter standard) and saves it as `.web` inside the public folder
|
||||
* @param title what title to use
|
||||
@ -22,13 +29,18 @@ async function generateSocialImage(
|
||||
fileName: string,
|
||||
fontsPromise: Promise<SatoriOptions["fonts"]>,
|
||||
cfg: GlobalConfiguration,
|
||||
colorScheme: "lightMode" | "darkMode",
|
||||
) {
|
||||
const fonts = await fontsPromise
|
||||
|
||||
// How many characters are allowed before switching to smaller font
|
||||
const fontBreakPoint = 22
|
||||
const useSmallerFont = title.length > fontBreakPoint
|
||||
|
||||
// Get color scheme preference from config (use lightMode by default)
|
||||
let colorScheme: SocialImageOptions["colorScheme"] = "lightMode"
|
||||
if (typeof cfg.generateSocialImages !== "boolean" && cfg.generateSocialImages.colorScheme) {
|
||||
colorScheme = cfg.generateSocialImages.colorScheme
|
||||
}
|
||||
const svg = await satori(
|
||||
<div
|
||||
style={{
|
||||
@ -119,11 +131,16 @@ export default (() => {
|
||||
const title = fileData.frontmatter?.title ?? "Untitled"
|
||||
const description = fileData.description?.trim() ?? "No description provided"
|
||||
|
||||
generateSocialImage(title, description, filePath as string, fontsPromise, cfg, "lightMode")
|
||||
if (cfg.generateSocialImages) {
|
||||
// Generate folders for social images (if they dont exist yet)
|
||||
if (!fs.existsSync(imageDir)) {
|
||||
fs.mkdirSync(imageDir, { recursive: true })
|
||||
}
|
||||
|
||||
if (!fs.existsSync(imageDir)) {
|
||||
fs.mkdirSync(imageDir, { recursive: true })
|
||||
// Generate social image (happens async)
|
||||
generateSocialImage(title, description, filePath as string, fontsPromise, cfg)
|
||||
}
|
||||
|
||||
const { css, js } = externalResources
|
||||
|
||||
const url = new URL(`https://${cfg.baseUrl ?? "example.com"}`)
|
||||
@ -131,13 +148,16 @@ export default (() => {
|
||||
const baseDir = fileData.slug === "404" ? path : pathToRoot(fileData.slug!)
|
||||
|
||||
const iconPath = joinSegments(baseDir, "static/icon.png")
|
||||
const useDefaultOgImage = filePath === undefined
|
||||
|
||||
const ogImageDefaultPath = `https://${cfg.baseUrl}/static/og-image.png`
|
||||
const ogImageGeneratedPath = `https://${cfg.baseUrl}/${imageDir.replace(
|
||||
"public/",
|
||||
"",
|
||||
)}/${filePath}.${extension}`
|
||||
|
||||
// Use default og image if filePath doesnt exist (for autogenerated paths with no .md file)
|
||||
const useDefaultOgImage = filePath === undefined || !cfg.generateSocialImages
|
||||
|
||||
const ogImagePath = useDefaultOgImage ? ogImageDefaultPath : ogImageGeneratedPath
|
||||
|
||||
return (
|
||||
@ -145,25 +165,30 @@ export default (() => {
|
||||
<title>{title}</title>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
{/* OG/Twitter meta tags */}
|
||||
<meta name="og:site_name" content={cfg.pageTitle}></meta>
|
||||
<meta property="og:url" content={`https://${cfg.baseUrl}/${fileData.slug}`}></meta>
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image:type" content={`image/${extension}`} />
|
||||
<meta property="og:image:alt" content={fileData.description} />
|
||||
<meta property="og:image:width" content={"" + ogWidth} />
|
||||
<meta property="og:image:height" content={"" + ogHeight} />
|
||||
<meta property="og:image:url" content={ogImagePath} />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta property="twitter:url" content={`https://${cfg.baseUrl}/${fileData.slug}`}></meta>
|
||||
<meta property="twitter:domain" content={cfg.baseUrl}></meta>
|
||||
{cfg.baseUrl && <meta name="twitter:image" content={ogImagePath} />}
|
||||
{cfg.baseUrl && <meta property="og:image" content={ogImagePath} />}
|
||||
<meta property="og:width" content="1200" />
|
||||
<meta property="og:height" content="675" />
|
||||
<meta property="og:width" content={"" + ogWidth} />
|
||||
<meta property="og:height" content={"" + ogHeight} />
|
||||
{cfg.baseUrl && (
|
||||
<>
|
||||
<meta name="twitter:image" content={ogImagePath} />
|
||||
<meta property="og:image" content={ogImagePath} />
|
||||
<meta property="twitter:domain" content={cfg.baseUrl}></meta>
|
||||
<meta property="og:url" content={`https://${cfg.baseUrl}/${fileData.slug}`}></meta>
|
||||
<meta property="twitter:url" content={`https://${cfg.baseUrl}/${fileData.slug}`}></meta>
|
||||
</>
|
||||
)}
|
||||
<link rel="icon" href={iconPath} />
|
||||
<meta name="description" content={description} />
|
||||
<meta name="generator" content="Quartz" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user