Skip to content
File

Blob: src/sites/excerpt.ts

typescript34 lines
1import type { JSONContent } from "@tiptap/core";
2 
3const DESCRIPTION_MIN_BREAK = 150;
4const DESCRIPTION_MAX_LENGTH = 160;
5const DESCRIPTION_ELLIPSIS = "...";
6 
7export function extractSiteDescription(content: JSONContent): string | null {
8 const text = collapseWhitespace(collectText(content).join(" "));
9 if (!text) return null;
10 if (text.length <= DESCRIPTION_MAX_LENGTH) return text;
11 
12 const window = text.slice(0, DESCRIPTION_MAX_LENGTH);
13 const breakAt = window.search(/\s+\S*$/);
14 if (breakAt >= DESCRIPTION_MIN_BREAK) {
15 return `${window.slice(0, breakAt).trimEnd()}${DESCRIPTION_ELLIPSIS}`;
16 }
17 return `${text.slice(0, DESCRIPTION_MAX_LENGTH - DESCRIPTION_ELLIPSIS.length).trimEnd()}${DESCRIPTION_ELLIPSIS}`;
18}
19 
20function collectText(node: JSONContent): string[] {
21 if (!node || typeof node !== "object") return [];
22 const chunks: string[] = [];
23 if (typeof node.text === "string") chunks.push(node.text);
24 if (node.type === "hardBreak") chunks.push(" ");
25 if (Array.isArray(node.content)) {
26 for (const child of node.content) chunks.push(...collectText(child));
27 }
28 return chunks;
29}
30 
31function collapseWhitespace(value: string): string {
32 return value.replace(/\s+/g, " ").trim();
33}