Improve preview title and description extraction

This commit is contained in:
Meta Vens 2026-05-01 14:40:23 +01:00
commit bbdc45eca3
2 changed files with 30 additions and 25 deletions

View file

@ -28,23 +28,12 @@ function isElementNode(node: RootContent): node is Element {
return node.type === "element"
}
function isMeaningfulNode(node: RootContent): boolean {
return normalizeWhitespace(toString(node)).length > 0
function isHeadingElement(node: RootContent): node is Element {
return isElementNode(node) && /^h[1-6]$/.test(node.tagName)
}
function isDuplicateTitleHeading(node: RootContent, pageTitle?: string): boolean {
if (!isElementNode(node) || node.tagName !== "h1") {
return false
}
const headingText = normalizeWhitespace(toString(node))
const normalizedTitle = normalizeWhitespace(pageTitle ?? "")
if (headingText.length === 0) {
return false
}
return normalizedTitle.length > 0 ? headingText === normalizedTitle : true
function isMeaningfulNode(node: RootContent): boolean {
return normalizeWhitespace(toString(node)).length > 0
}
function isStandalonePreviewTagline(node: RootContent): boolean {
@ -67,14 +56,12 @@ function isStandalonePreviewTagline(node: RootContent): boolean {
export function extractDescriptionText(tree: HTMLRoot, pageTitle?: string): string {
const children = [...tree.children]
let startIdx = 0
let strippedTitle = false
while (startIdx < children.length && !isMeaningfulNode(children[startIdx])) {
startIdx++
}
if (startIdx < children.length && isDuplicateTitleHeading(children[startIdx], pageTitle)) {
strippedTitle = true
while (startIdx < children.length && isHeadingElement(children[startIdx])) {
startIdx++
}
@ -82,11 +69,7 @@ export function extractDescriptionText(tree: HTMLRoot, pageTitle?: string): stri
startIdx++
}
if (
startIdx < children.length &&
(strippedTitle || pageTitle) &&
isStandalonePreviewTagline(children[startIdx])
) {
if (startIdx < children.length && pageTitle && isStandalonePreviewTagline(children[startIdx])) {
startIdx++
}

View file

@ -3,6 +3,8 @@ import remarkFrontmatter from "remark-frontmatter"
import { QuartzTransformerPlugin } from "../types"
import yaml from "js-yaml"
import toml from "toml"
import { Root as MdRoot } from "mdast"
import { toString } from "mdast-util-to-string"
import { FilePath, FullSlug, getFileExtension, slugifyFilePath, slugTag } from "../../util/path"
import { QuartzPluginData } from "../vfile"
import { i18n } from "../../i18n"
@ -52,6 +54,23 @@ function getAliasSlugs(aliases: string[]): FullSlug[] {
return res
}
function getFirstMarkdownHeading(root: MdRoot): string | undefined {
const firstMeaningfulNode = root.children.find((node) => {
if (node.type === "yaml") {
return false
}
return toString(node).trim().length > 0
})
if (!firstMeaningfulNode || firstMeaningfulNode.type !== "heading") {
return undefined
}
const text = toString(firstMeaningfulNode).trim()
return text.length > 0 ? text : undefined
}
export const FrontMatter: QuartzTransformerPlugin<Partial<Options>> = (userOpts) => {
const opts = { ...defaultOptions, ...userOpts }
return {
@ -61,7 +80,7 @@ export const FrontMatter: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
return [
[remarkFrontmatter, ["yaml", "toml"]],
() => {
return (_, file) => {
return (tree: MdRoot, file) => {
const fileData = Buffer.from(file.value as Uint8Array)
const { data } = matter(fileData, {
...opts,
@ -74,7 +93,10 @@ export const FrontMatter: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
if (data.title != null && data.title.toString() !== "") {
data.title = data.title.toString()
} else {
data.title = file.stem ?? i18n(cfg.configuration.locale).propertyDefaults.title
data.title =
getFirstMarkdownHeading(tree) ??
file.stem ??
i18n(cfg.configuration.locale).propertyDefaults.title
}
const tags = coerceToArray(coalesceAliases(data, ["tags", "tag"]))