Compare commits

..

2 Commits

3 changed files with 60 additions and 12 deletions

View File

@ -16,19 +16,23 @@ export function TableOfContents() {
const getHeadings = () => { const getHeadings = () => {
return data.sections return data.sections
.flatMap((section) => [section, ...section.children])
.map((section) => { .map((section) => {
if (!section.hash) return null; if (!section.hash) return null;
const el = document.getElementById(section.hash); const el = document.getElementById(section.hash);
console.log(section.hash, el);
if (!el) return null; if (!el) return null;
const style = window.getComputedStyle(el); const style = window.getComputedStyle(el);
const scrollMt = Number.parseFloat(style.scrollMarginTop); const scrollMt = Number.parseFloat(style.scrollMarginTop);
const top = window.scrollY + el.getBoundingClientRect().top - scrollMt; const top = window.scrollY + el.getBoundingClientRect().top - scrollMt;
return { id: section.hash, top }; return { id: section.hash, top, level: section.level };
}) })
.filter((x): x is { id: string; top: number } => x !== null); .filter(
(x): x is { id: string; top: number; level: number } => x !== null,
);
}; };
createEffect(() => { createEffect(() => {
@ -46,8 +50,11 @@ export function TableOfContents() {
} }
setCurrentSection(current); setCurrentSection(current);
} }
window.addEventListener("scroll", onScroll, { passive: true }); window.addEventListener("scroll", onScroll, { passive: true });
onScroll(); onScroll();
return () => { return () => {
window.removeEventListener("scroll", onScroll); window.removeEventListener("scroll", onScroll);
}; };
@ -55,10 +62,12 @@ export function TableOfContents() {
function isActive(section: DocSection) { function isActive(section: DocSection) {
if (section.hash === currentSection()) return true; if (section.hash === currentSection()) return true;
return false; if (!section.children) return false;
// if (!section.children) return false;
// return section.children.findIndex(isActive) > -1; return (
section.children.findIndex((child) => child.hash === currentSection()) !==
-1
);
} }
return ( return (
@ -87,6 +96,26 @@ export function TableOfContents() {
{section.content} {section.content}
</Link> </Link>
</h3> </h3>
{section.children.length > 0 && (
<ol class="mt-2 space-y-2 pl-4">
<For each={section.children}>
{(subsection) => (
<li>
<Link
href={`#${subsection.hash}`}
class={clsx(
isActive(subsection)
? "text-violet-500"
: "font-normal text-slate-500 hover:text-slate-700",
)}
>
{subsection.content}
</Link>
</li>
)}
</For>
</ol>
)}
</li> </li>
)} )}
</For> </For>

View File

@ -22,6 +22,7 @@ export type DocSection = {
content: string; content: string;
hash?: string; hash?: string;
subsections: string[]; subsections: string[];
children: DocSection[];
level?: number; level?: number;
}; };
@ -98,15 +99,32 @@ class DocCache {
if (["heading", "paragraph"].includes(node.type)) { if (["heading", "paragraph"].includes(node.type)) {
const content = this.nodeToString(node).trim(); const content = this.nodeToString(node).trim();
if (node.type === "heading" && node.attributes?.level <= 2) { if (node.type === "heading" && node.attributes?.level <= 3) {
const hash = (node.attributes?.id as string) ?? this.slugify(content); const hash = (node.attributes?.id as string) ?? this.slugify(content);
const subsections: string[] = []; const subsections: string[] = [];
if (node.attributes?.level === 2) {
sections.push({ sections.push({
content, content,
hash, hash,
subsections, subsections,
children: [],
level: node.attributes?.level, level: node.attributes?.level,
}); });
} else if (node.attributes?.level === 3) {
const lastSection = sections.at(-1);
if (lastSection) {
lastSection.subsections.push(hash);
lastSection.children.push({
content,
hash,
subsections,
children: [],
level: node.attributes?.level,
});
}
}
} else { } else {
sections.at(-1)?.subsections.push(content); sections.at(-1)?.subsections.push(content);
} }

1
temp.json Normal file
View File

@ -0,0 +1 @@
[{"content":"qu-est-ce-que-le-hook-use-reducer","hash":"qu-est-ce-que-le-hook-use-reducer","level":2,"subsections":[{"content":"quand-utiliser-use-reducer","hash":"quand-utiliser-use-reducer","level":3,"subsections":[{"content":"a-quoi-ressemble-un-reducer","hash":"a-quoi-ressemble-un-reducer","level":2,"subsections":[{"content":"comment-utiliser-use-reducer","hash":"comment-utiliser-use-reducer","level":2,"subsections":[{"content":"on-nettoie-tout-ca","hash":"on-nettoie-tout-ca","level":2,"subsections":[{"content":"typage-des-actions","hash":"typage-des-actions","level":3,"subsections":[{"content":"action-creators","hash":"action-creators","level":3,"subsections":[{"content":"les-fichiers-complets","hash":"les-fichiers-complets","level":2,"subsections":[{"content":"fichier-counter-jsx-ou-counter-tsx","hash":"fichier-counter-jsx-ou-counter-tsx","level":3,"subsections":[{"content":"c-est-l-heure-des-questions","hash":"c-est-l-heure-des-questions","level":2,"subsections":[{"content":"conclusion","hash":"conclusion","level":2,"subsections":[]}]}]}]}]}]}]}]}]}]}]}]