import { Link } from "@onegeo-suite/gatsby-theme-onegeo" import React from "react" import { useEffect, useState } from "react" import { useHeadsObserver } from "./utils/hook" const rnd = (() => { const gen = (min: number, max: number) => max++ && [...Array(max - min)].map((s, i) => String.fromCharCode(min + i)) const sets = { alphaLower: gen(97, 122), alphaUpper: gen(65, 90), } function* iter(len: number, set: any) { if (set.length < 1) set = Object.values(sets).flat() for (let i = 0; i < len; i++) yield set[(Math.random() * set.length) | 0] } return Object.assign( (len: number, ...set: any) => [...iter(len, set.flat())].join(""), sets ) })() const navStyle = { position: "sticky -webkit-sticky", top: "24px", maxHeight: "calc(100vh - 40px)", overflow: "auto", } as unknown as React.CSSProperties let navulliStyle = { marginBottom: "15px", } as React.CSSProperties const getClassName = (level: number) => { switch (level) { case 1: navulliStyle = { ...navulliStyle, marginLeft: "0px", } return "head1" case 2: navulliStyle = { ...navulliStyle, marginLeft: "10px", } return "head2" case 3: navulliStyle = { ...navulliStyle, marginLeft: "20px", } return "head3" case 4: navulliStyle = { ...navulliStyle, marginLeft: "30px", } return "head4" default: return undefined } } interface Props { className?: string } const Toc = (props: Props) => { const { className = "" } = props const [headings, setHeadings] = useState<any>([]) const { activeId } = useHeadsObserver() useEffect(() => { const elements = Array.from( document.querySelectorAll("h1, h2, h3, h4") ).map((elem) => ({ id: elem.id ? elem.id : (elem.id = rnd(4)), text: elem.textContent, level: Number(elem.nodeName.charAt(1)), })) setHeadings(elements) }, []) return ( <aside className={`bg-base-100 sticky top-24 hidden h-full max-w-xs rounded-xl p-6 shadow-lg lg:block ${className}`} > <nav style={navStyle}> <ul style={navulliStyle}> {headings.map((heading: any) => ( <li key={heading.id} className={getClassName(heading.level)} style={navulliStyle} > <Link to={`#${heading.id}`}>{heading.text}</Link> </li> ))} </ul> </nav> </aside> ) } export default Toc