Files
docs/examples/marble-cms/lib/render-html.tsx
T

58 lines
1.4 KiB
TypeScript

import type { TOCItemType } from 'fumadocs-core/toc';
import Slugger from 'github-slugger';
import parse, { type DOMNode, domToReact } from 'html-react-parser';
import { Heading } from 'fumadocs-ui/components/heading';
import { ServerCodeBlock } from 'fumadocs-ui/components/codeblock.rsc';
export function renderFromHtml(content: string) {
const toc: TOCItemType[] = [];
const slugger = new Slugger();
const node = parse(content, {
replace(node) {
if (node.type !== 'tag') return node;
const heading = /^h(\d)$/.exec(node.name);
if (heading) {
const depth = Number(heading[1]);
const string = stringify(node);
const id = slugger.slug(string);
toc.push({
title: string,
depth,
url: `#${id}`,
});
return (
<Heading as={`h${depth}` as 'h1'} id={id}>
{domToReact(node.children as DOMNode[])}
</Heading>
);
}
if (node.name === 'pre') {
return <ServerCodeBlock lang="tsx" code={stringify(node)} />;
}
},
});
return { node, toc };
}
function stringify(node: DOMNode): string {
if (node.type === 'text') return node.data;
if ('children' in node) {
return node.children
.map((node) => {
if (node.type === 'cdata' || node.type === 'root') return;
return stringify(node);
})
.filter(Boolean)
.join('');
}
return '';
}