┌─ TS ───────────────────────────────────────────────────────────────────────┐│ // Page descriptions for <meta>, OG, and feeds - derived from the first ││ // prose paragraph of a markdown body so notes don't need a description ││ // field in frontmatter. ││ ││ /** First prose paragraph, markdown stripped, truncated at a word ││ * boundary. Empty string when the body has no prose (tables, code, ││ * and headings don't count). */ ││ export function describeBody(md: string, max = 160): string { ││ let text = ""; ││ for (const raw of md.split(/\n\s*\n/)) { ││ const b = raw.trim(); ││ if (!b) continue; ││ if (/^(#|```|~~~|\||>|[-*+] |\d+\. |!\[|<)/.test(b)) continue; ││ text = b; ││ break; ││ } ││ if (!text) return ""; ││ const clean = text ││ .replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g, "$2") ││ .replace(/\[\[([^\]|]+)\]\]/g, "$1") ││ .replace(/\[([^\]]+)\]\([^)]*\)/g, "$1") ││ .replace(/[`*_]/g, "") ││ .replace(/\s+/g, " ") ││ .trim(); ││ if ([...clean].length <= max) return clean; ││ const cut = [...clean].slice(0, max - 3).join(""); ││ return cut.replace(/\s+\S*$/, "") + "..."; ││ } │└────────────────────────────────────────────────────────────────────────────────────┘
┌─ TS ─────────────────────────────────┐│ // Page descriptions for <meta>, OG, and fee ││ ds - derived from the first ││ // prose paragraph of a markdown body so not ││ es don't need a description ││ // field in frontmatter. ││ ││ /** First prose paragraph, markdown stripped ││ , truncated at a word ││ * boundary. Empty string when the body has ││ no prose (tables, code, ││ * and headings don't count). */ ││ export function describeBody(md: string, max ││ = 160): string { ││ let text = ""; ││ for (const raw of md.split(/\n\s*\n/)) { ││ const b = raw.trim(); ││ if (!b) continue; ││ if (/^(#|```|~~~|\||>|[-*+] |\d+\. |!\[| ││ <)/.test(b)) continue; ││ text = b; ││ break; ││ } ││ if (!text) return ""; ││ const clean = text ││ .replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g, ││ "$2") ││ .replace(/\[\[([^\]|]+)\]\]/g, "$1") ││ .replace(/\[([^\]]+)\]\([^)]*\)/g, "$1") ││ .replace(/[`*_]/g, "") ││ .replace(/\s+/g, " ") ││ .trim(); ││ if ([...clean].length <= max) return clean ││ ; ││ const cut = [...clean].slice(0, max - 3).j ││ oin(""); ││ return cut.replace(/\s+\S*$/, "") + "..."; ││ } │└──────────────────────────────────────────────┘