aboutsummaryrefslogtreecommitdiff
path: root/examples/docs/src/components/RightSidebar/TableOfContents.tsx
diff options
context:
space:
mode:
authorGravatar Rishi Raj Jain <rjain@llnw.com> 2022-11-17 21:18:57 +0530
committerGravatar GitHub <noreply@github.com> 2022-11-17 10:48:57 -0500
commitfcfd166f2d52dcf800fbaff6d618ad57eaf3cc9b (patch)
treeb9f79e2c4ab451e3e3f8706806bc92d9be64931c /examples/docs/src/components/RightSidebar/TableOfContents.tsx
parent12236dbc06e1e43618b61d180020a67cb31499f8 (diff)
downloadastro-fcfd166f2d52dcf800fbaff6d618ad57eaf3cc9b.tar.gz
astro-fcfd166f2d52dcf800fbaff6d618ad57eaf3cc9b.tar.zst
astro-fcfd166f2d52dcf800fbaff6d618ad57eaf3cc9b.zip
fix: Docs Site - Table of contents highlight not working (#5411)
* fix: Docs Site - Table of contents highlight not working * Add html-escaper devDep * add html-escaper via pnpm
Diffstat (limited to 'examples/docs/src/components/RightSidebar/TableOfContents.tsx')
-rw-r--r--examples/docs/src/components/RightSidebar/TableOfContents.tsx59
1 files changed, 48 insertions, 11 deletions
diff --git a/examples/docs/src/components/RightSidebar/TableOfContents.tsx b/examples/docs/src/components/RightSidebar/TableOfContents.tsx
index 5c6851462..34b0ab732 100644
--- a/examples/docs/src/components/RightSidebar/TableOfContents.tsx
+++ b/examples/docs/src/components/RightSidebar/TableOfContents.tsx
@@ -1,6 +1,7 @@
+import { unescape } from 'html-escaper';
+import type { MarkdownHeading } from 'astro';
import type { FunctionalComponent } from 'preact';
import { useState, useEffect, useRef } from 'preact/hooks';
-import type { MarkdownHeading } from 'astro';
type ItemOffsets = {
id: string;
@@ -10,9 +11,10 @@ type ItemOffsets = {
const TableOfContents: FunctionalComponent<{ headings: MarkdownHeading[] }> = ({
headings = [],
}) => {
+ const toc = useRef<HTMLUListElement>();
+ const onThisPageID = 'on-this-page-heading';
const itemOffsets = useRef<ItemOffsets[]>([]);
- // FIXME: Not sure what this state is doing. It was never set to anything truthy.
- const [activeId] = useState<string>('');
+ const [currentID, setCurrentID] = useState('overview');
useEffect(() => {
const getItemOffsets = () => {
const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)');
@@ -30,22 +32,57 @@ const TableOfContents: FunctionalComponent<{ headings: MarkdownHeading[] }> = ({
};
}, []);
+ useEffect(() => {
+ if (!toc.current) return;
+
+ const setCurrent: IntersectionObserverCallback = (entries) => {
+ for (const entry of entries) {
+ if (entry.isIntersecting) {
+ const { id } = entry.target;
+ if (id === onThisPageID) continue;
+ setCurrentID(entry.target.id);
+ break;
+ }
+ }
+ };
+
+ const observerOptions: IntersectionObserverInit = {
+ // Negative top margin accounts for `scroll-margin`.
+ // Negative bottom margin means heading needs to be towards top of viewport to trigger intersection.
+ rootMargin: '-100px 0% -66%',
+ threshold: 1,
+ };
+
+ const headingsObserver = new IntersectionObserver(setCurrent, observerOptions);
+
+ // Observe all the headings in the main page content.
+ document.querySelectorAll('article :is(h1,h2,h3)').forEach((h) => headingsObserver.observe(h));
+
+ // Stop observing when the component is unmounted.
+ return () => headingsObserver.disconnect();
+ }, [toc.current]);
+
+ const onLinkClick = (e) => {
+ setCurrentID(e.target.getAttribute('href').replace('#', ''));
+ };
+
return (
<>
- <h2 className="heading">On this page</h2>
- <ul>
- <li className={`heading-link depth-2 ${activeId === 'overview' ? 'active' : ''}`.trim()}>
- <a href="#overview">Overview</a>
- </li>
+ <h2 id={onThisPageID} className="heading">
+ On this page
+ </h2>
+ <ul ref={toc}>
{headings
.filter(({ depth }) => depth > 1 && depth < 4)
.map((heading) => (
<li
- className={`heading-link depth-${heading.depth} ${
- activeId === heading.slug ? 'active' : ''
+ className={`header-link depth-${heading.depth} ${
+ currentID === heading.slug ? 'current-header-link' : ''
}`.trim()}
>
- <a href={`#${heading.slug}`}>{heading.text}</a>
+ <a href={`#${heading.slug}`} onClick={onLinkClick}>
+ {unescape(heading.text)}
+ </a>
</li>
))}
</ul>