| 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; | |