alejandrogs.es/public/js/toc.js
alejandrogs73 4fb49961b4
All checks were successful
Zola / build-and-deploy (push) Successful in 11s
feat(infra): migración a tema Apollo, reestructuración del blog y página 'Sobre mí'
- Implementado tema Apollo como base visual.
- Segregación de contenido: Artículos movidos a /blog.
- Creación de identidad: Nueva página 'Sobre mí' (about.md).
- CI/CD: Actualizado workflow para soporte de submódulos recursivos.
- UX: Ajustes en homepage para listado de últimos posts.
2025-12-14 19:05:54 +01:00

49 lines
1.5 KiB
JavaScript

document.addEventListener("DOMContentLoaded", () => {
let observer = new IntersectionObserver(handler, {
threshold: [0],
});
let paragraphs = [...document.querySelectorAll("section > *")];
let submenu = [...document.querySelectorAll(".toc a")];
function previousHeaderId(e) {
for (; e && !e.matches("h1, h2, h3, h4"); ) e = e.previousElementSibling;
return e?.id;
}
let paragraphMenuMap = paragraphs.reduce((e, t) => {
let n = previousHeaderId(t);
if (((t.previousHeader = n), n)) {
let t = submenu.find((e) => decodeURIComponent(e.hash) === "#" + n);
e[n] = t;
}
return e;
}, {});
paragraphs.forEach((e) => observer.observe(e));
let selection;
function handler(e) {
selection = (selection || e).map(
(t) => e.find((e) => e.target === t.target) || t,
);
for (s of selection)
s.isIntersecting ||
paragraphMenuMap[
s.target.previousHeader
]?.parentElement.classList.remove("selected", "parent");
for (s of selection)
if (s.isIntersecting) {
let e = paragraphMenuMap[s.target.previousHeader]?.closest("li");
if ((e?.classList.add("selected"), e === void 0)) continue;
// Find the anchor element within the list item
let t = e.querySelector("a");
if (t) {
t.scrollIntoView({
block: "nearest",
inline: "nearest",
});
}
for (; e; ) {
e?.classList.add("parent"), (e = e.parentElement.closest("li"));
}
}
}
});