/**
* @file Marks the contents link for the section being read, on the style guide
* and the CSS reference.
*
* Both pages put a numbered contents list beside one long reading column. As
* the reader scrolls, the link for the section crossing the reading line (a
* quarter of the way down the window) gets `aria-current="true"`, which the
* stylesheet draws as full-strength ink and the nav's Sky underline.
*
* ## Authored markup
*
* ```html
* <nav data-toc aria-label="Contents">
* <ol><li><a href="#palette">Palette</a></li>…</ol>
* </nav>
* <section id="palette">…</section>
* ```
*
* The list works as plain in-page links without this script; nothing is hidden
* or moved. The hook is a data attribute, not a class, because Tailwind scans
* `src/js/` for both stylesheets and a class named here would pull the guide's
* rules into the stylesheet every visitor loads.
*
* ## Loading
*
* A module (`<script type="module">`) at the end of the two pages. The site's
* Content-Security-Policy allows same-origin scripts only, so this can't be an
* inline script.
*
* @module style-guide
*/
/**
* The contents links that point at a section of this page.
* @type {HTMLAnchorElement[]}
*/
const links = Array.from(document.querySelectorAll('[data-toc] a[href^="#"]'));
if (links.length && 'IntersectionObserver' in window) {
/**
* Contents links by the id of the section they point at, in page order.
* @type {Map<string, HTMLAnchorElement>}
*/
const byId = new Map(links.map((a) => [a.getAttribute('href').slice(1), a]));
/**
* Ids of the sections crossing the reading line right now.
* @type {Set<string>}
*/
const onLine = new Set();
/**
* Moves `aria-current` to the first section on the reading line. When the
* line sits in the gap between two sections, the last mark stays.
*
* @param {IntersectionObserverEntry[]} entries Sections that crossed the line.
* @returns {void}
*/
const mark = (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) onLine.add(entry.target.id);
else onLine.delete(entry.target.id);
});
const current = [...byId.keys()].find((id) => onLine.has(id));
if (!current) return;
links.forEach((a) => a.removeAttribute('aria-current'));
byId.get(current).setAttribute('aria-current', 'true');
};
// A zero-height band a quarter of the way down the window: the reading line.
const observer = new IntersectionObserver(mark, { rootMargin: '-25% 0px -75% 0px' });
byId.forEach((link, id) => {
const section = document.getElementById(id);
if (section) observer.observe(section);
});
}