diff --git a/src/app/[[...slug]]/page.tsx b/src/app/[[...slug]]/page.tsx index 99b3af3..0b8a5f8 100644 --- a/src/app/[[...slug]]/page.tsx +++ b/src/app/[[...slug]]/page.tsx @@ -76,7 +76,7 @@ const DocsPage = async ({ {/* Content */} -
+
diff --git a/src/components/on-this-page.tsx b/src/components/on-this-page.tsx index 46d23cf..cd24ad7 100644 --- a/src/components/on-this-page.tsx +++ b/src/components/on-this-page.tsx @@ -1,8 +1,9 @@ "use client"; -import { ReactElement, useEffect, useState } from "react"; +import { ReactElement, useEffect, useRef, useState } from "react"; import { Bars3CenterLeftIcon } from "@heroicons/react/24/outline"; import Link from "next/link"; +import { cn } from "@/lib/utils"; type Header = { id: string; @@ -12,6 +13,10 @@ type Header = { const OnThisPage = ({ page }: { page: DocsContentMetadata }): ReactElement => { const [headers, setHeaders] = useState([]); + const [activeHeader, setActiveHeader] = useState( + undefined + ); + const observerRef = useRef(undefined); useEffect(() => { // Regular expression to match markdown headers @@ -33,10 +38,41 @@ const OnThisPage = ({ page }: { page: DocsContentMetadata }): ReactElement => { setHeaders(extractedHeaders); }, [page.content]); + useEffect(() => { + // Cleanup existing observer + if (observerRef.current) { + observerRef.current.disconnect(); + } + + const observer = new IntersectionObserver( + (entries: IntersectionObserverEntry[]) => { + entries.forEach((entry: IntersectionObserverEntry) => { + if (entry.isIntersecting) { + setActiveHeader(entry.target.id); + } + }); + }, + { rootMargin: "0px 0px -80% 0px", threshold: 0.1 } + ); + observerRef.current = observer; + + // Observe all header elements + headers.forEach((header: Header) => { + const element: HTMLElement | null = document.getElementById( + header.id + ); + if (element) { + observer.observe(element); + } + }); + + return () => observer.disconnect(); + }, [headers]); + return ( -
+
{/* Title */} -
+

On This Page

@@ -46,10 +82,17 @@ const OnThisPage = ({ page }: { page: DocsContentMetadata }): ReactElement => { {headers.map((header: Header) => (
  • - {header.text} + + {header.text} +
  • ))}