File size: 1,845 Bytes
b9fe2b4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
import { Anchor } from 'antd';
import type { AnchorLinkItemProps } from 'antd/es/anchor/Anchor';
import React, { useEffect, useState } from 'react';
interface MarkdownTocProps {
content: string;
}
const MarkdownToc: React.FC<MarkdownTocProps> = ({ content }) => {
const [items, setItems] = useState<AnchorLinkItemProps[]>([]);
useEffect(() => {
const generateTocItems = () => {
const headings = document.querySelectorAll(
'.wmde-markdown h2, .wmde-markdown h3',
);
const tocItems: AnchorLinkItemProps[] = [];
let currentH2Item: AnchorLinkItemProps | null = null;
headings.forEach((heading) => {
const title = heading.textContent || '';
const id = heading.id;
const isH2 = heading.tagName.toLowerCase() === 'h2';
if (id && title) {
const item: AnchorLinkItemProps = {
key: id,
href: `#${id}`,
title,
};
if (isH2) {
currentH2Item = item;
tocItems.push(item);
} else {
if (currentH2Item) {
if (!currentH2Item.children) {
currentH2Item.children = [];
}
currentH2Item.children.push(item);
} else {
tocItems.push(item);
}
}
}
});
setItems(tocItems.slice(1));
};
setTimeout(generateTocItems, 100);
}, [content]);
return (
<div
className="markdown-toc"
style={{
position: 'fixed',
right: 20,
top: 100,
width: 200,
background: '#fff',
padding: '10px',
maxHeight: 'calc(100vh - 170px)',
overflowY: 'auto',
zIndex: 1000,
}}
>
<Anchor items={items} affix={false} />
</div>
);
};
export default MarkdownToc;
|