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;