{
if (!item.text) return null
- // Text auf ~100 Zeichen stutzen (inkl. Ellipse „…“)
- const previewRaw = truncate(item.text, { limit: 100, ellipsis: true }) as string
+ // Convert Markdown to HTML and truncate with awareness of markup
+ const html = unified()
+ .use(remarkParse)
+ .use(remarkGfm)
+ .use(remarkBreaks)
+ .use(remarkRehype, { allowDangerousHtml: true })
+ .use(rehypeRaw)
+ .use(rehypeStringify, { allowDangerousHtml: true })
+ .processSync(item.text)
+ .toString()
- const withExtraHashes = previewRaw.replace(
- /^(#{1,6})\s/gm,
- (_match: string, hashes: string): string => `${hashes}## `,
- )
+ // decrease heading levels similar to previous Markdown manipulation
+ const withSmallHeadings = html.replace(/<(\/?)h([1-6])/g, (_m, slash, level) => {
+ const newLevel = Math.min(6, Number(level) + 2)
+ return `<${slash}h${newLevel}`
+ })
+
+ // Text auf ~100 Zeichen stutzen (inkl. Ellipse „…“)
+ const previewRaw = htmlTruncate(withSmallHeadings, 100, {
+ ellipsis: '…',
+ reserveLastWord: true,
+ })
return (
@@ -28,7 +47,7 @@ export const TextPreview = ({ item }: { item: Item }) => {
rehypePlugins={[rehypeRaw]}
components={{ span: Span }}
>
- {withExtraHashes}
+ {previewRaw}
)