import { Link } from "@onegeo/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={`w-72 min-w-min fixed right-0 h-screen bg-slate-50 p-5 ${className}`} > <div className="text-2xl pb-5 flex flex-row"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6 mt-2" > <path strokeLinecap="round" strokeLinejoin="round" d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" /> </svg> <p className="px-2 mt-0.5"> Menu interne </p> </div> <nav style={navStyle}> <ul style={navulliStyle}> {headings.map((heading:any) => ( <li key={heading.id} className={getClassName(heading.level)} style={navulliStyle} > <Link to={`#${heading.id}`} onClick={(e:any) => { e.preventDefault() const element = document.querySelector( `#${heading.id}` ) if (element) { element?.scrollIntoView({ behavior: "smooth", }) } else { console.log("No element") } }} activeClassName={`${activeId == heading.id ? "font-bold" : "font-normal"} font-serif`} > {heading.text} </Link> </li> ))} </ul> </nav> </aside> ) } export default Toc