Newer
Older
import React from "react";
import { useEffect, useState } from "react";
import { useHeadsObserver } from "./utils/hook";
const rnd = (() => {
const gen = (min, max) => max++ && [...Array(max-min)].map((s, i) => String.fromCharCode(min+i));
const sets = {
alphaLower: gen(97,122),
alphaUpper: gen(65,90)
};
function* iter(len, set) {
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, ...set) => [...iter(len, set.flat())].join('')), sets);
})();
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
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) => {
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) => ({
text: elem.textContent,
level: Number(elem.nodeName.charAt(1)),
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
setHeadings(elements);
}, []);
return (
<aside
className={`w-[20%] fixed right-0 top-auto 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) => (
<li
key={heading.id}
className={getClassName(heading.level)}
style={navulliStyle}
>
<a
href={`#${heading.id}`}
onClick={(e) => {
e.preventDefault();
const element = document.querySelector(`#${heading.id}`);
if(element) {
element?.scrollIntoView({
behavior: "smooth",
});
}
else {
}
}}
style={{
fontWeight: activeId == heading.id ? "bold" : "normal",
fontFamily: "Georgia, serif",
}}
>
{heading.text}
</a>
</li>
))}
</ul>
</nav>
</aside>
);
};
export default Toc;