sites: scroll-spy tracks scroll position, fires the last section on bottom
The IntersectionObserver-based spy only fired when a section entered a narrow band 40–45% down the viewport. Short sections at the tail of a page — Operator key and Roadmap on theseus.x/extensions, whatever came last on the other pages — never made it into that band because the page runs out of scroll before their top crosses 40%, so their sidebar links stayed dim no matter how far the reader scrolled. Rewrote the spy across every page with a sidebar (theseus.x home / plug-ins / extensions and sirius.x home / tld / theseus / docs / admin / brand): it listens to window scroll, picks the last section whose top has crossed 35% of the viewport, and — when the window is scrolled to within 4px of the bottom — snaps to the final section regardless of where its top is. Every link in the rail can now activate. theseus.x/extensions also had the spy IIFE bundled with the manifest loader in one <script> block near the middle of the page, so at run time the parser hadn't yet reached the last three sections and only Bundled/Community/Build were ever registered. Moved the spy to its own <script> just before </body> so it sees every section that ships.
This commit is contained in:
parent
0e8e1949df
commit
172d16e84b
3 changed files with 686 additions and 655 deletions
|
|
@ -260,23 +260,6 @@
|
|||
</div>`).join("");
|
||||
} catch (e) { box.innerHTML = '<div class="ext" style="color:var(--dim)">Catalog unavailable right now.</div>'; }
|
||||
})();
|
||||
|
||||
// Sidenav scroll-spy: highlight the section currently in view.
|
||||
(() => {
|
||||
const links = document.querySelectorAll(".sidenav a[href^='#']");
|
||||
if (!links.length) return;
|
||||
const map = new Map();
|
||||
links.forEach((a) => { const el = document.querySelector(a.getAttribute("href")); if (el) map.set(el, a); });
|
||||
const io = new IntersectionObserver((entries) => {
|
||||
entries.forEach((en) => {
|
||||
if (!en.isIntersecting) return;
|
||||
const a = map.get(en.target); if (!a) return;
|
||||
links.forEach((l) => l.classList.remove("active"));
|
||||
a.classList.add("active");
|
||||
});
|
||||
}, { rootMargin: "-40% 0px -55% 0px", threshold: 0 });
|
||||
map.forEach((_, el) => io.observe(el));
|
||||
})();
|
||||
</script>
|
||||
|
||||
<section id="updates">
|
||||
|
|
@ -318,5 +301,33 @@
|
|||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Sidenav scroll-spy: highlight the section currently in view.
|
||||
// Uses scroll-position tracking so short sections at the end of the page
|
||||
// still activate their link when the reader scrolls to them.
|
||||
(() => {
|
||||
const links = document.querySelectorAll(".sidenav a[href^='#']");
|
||||
if (!links.length) return;
|
||||
const entries = [];
|
||||
links.forEach((a) => { const el = document.querySelector(a.getAttribute("href")); if (el) entries.push({ el, link: a }); });
|
||||
if (!entries.length) return;
|
||||
const setActive = (link) => { links.forEach((l) => l.classList.remove("active")); link.classList.add("active"); };
|
||||
const update = () => {
|
||||
const doc = document.documentElement;
|
||||
const scrollBottom = window.scrollY + window.innerHeight;
|
||||
if (scrollBottom >= (doc.scrollHeight - 4)) { setActive(entries[entries.length - 1].link); return; }
|
||||
const line = window.scrollY + window.innerHeight * 0.35;
|
||||
let active = entries[0].link;
|
||||
for (const e of entries) {
|
||||
if (e.el.getBoundingClientRect().top + window.scrollY <= line) active = e.link;
|
||||
else break;
|
||||
}
|
||||
setActive(active);
|
||||
};
|
||||
window.addEventListener("scroll", update, { passive: true });
|
||||
window.addEventListener("resize", update);
|
||||
update();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
32
index.html
32
index.html
|
|
@ -375,20 +375,30 @@ Expected:
|
|||
})();
|
||||
|
||||
// Sidenav scroll-spy: highlight the section currently in view.
|
||||
// Uses scroll-position tracking so short sections at the end of the page
|
||||
// still activate their link when the reader scrolls to them.
|
||||
(() => {
|
||||
const links = document.querySelectorAll(".sidenav a[href^='#']");
|
||||
if (!links.length) return;
|
||||
const map = new Map();
|
||||
links.forEach((a) => { const el = document.querySelector(a.getAttribute("href")); if (el) map.set(el, a); });
|
||||
const io = new IntersectionObserver((entries) => {
|
||||
entries.forEach((en) => {
|
||||
if (!en.isIntersecting) return;
|
||||
const a = map.get(en.target); if (!a) return;
|
||||
links.forEach((l) => l.classList.remove("active"));
|
||||
a.classList.add("active");
|
||||
});
|
||||
}, { rootMargin: "-40% 0px -55% 0px", threshold: 0 });
|
||||
map.forEach((_, el) => io.observe(el));
|
||||
const entries = [];
|
||||
links.forEach((a) => { const el = document.querySelector(a.getAttribute("href")); if (el) entries.push({ el, link: a }); });
|
||||
if (!entries.length) return;
|
||||
const setActive = (link) => { links.forEach((l) => l.classList.remove("active")); link.classList.add("active"); };
|
||||
const update = () => {
|
||||
const doc = document.documentElement;
|
||||
const scrollBottom = window.scrollY + window.innerHeight;
|
||||
if (scrollBottom >= (doc.scrollHeight - 4)) { setActive(entries[entries.length - 1].link); return; }
|
||||
const line = window.scrollY + window.innerHeight * 0.35;
|
||||
let active = entries[0].link;
|
||||
for (const e of entries) {
|
||||
if (e.el.getBoundingClientRect().top + window.scrollY <= line) active = e.link;
|
||||
else break;
|
||||
}
|
||||
setActive(active);
|
||||
};
|
||||
window.addEventListener("scroll", update, { passive: true });
|
||||
window.addEventListener("resize", update);
|
||||
update();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -223,20 +223,30 @@
|
|||
})();
|
||||
|
||||
// Sidenav scroll-spy: highlight the section currently in view.
|
||||
// Uses scroll-position tracking so short sections at the end of the page
|
||||
// still activate their link when the reader scrolls to them.
|
||||
(() => {
|
||||
const links = document.querySelectorAll(".sidenav a[href^='#']");
|
||||
if (!links.length) return;
|
||||
const map = new Map();
|
||||
links.forEach((a) => { const el = document.querySelector(a.getAttribute("href")); if (el) map.set(el, a); });
|
||||
const io = new IntersectionObserver((entries) => {
|
||||
entries.forEach((en) => {
|
||||
if (!en.isIntersecting) return;
|
||||
const a = map.get(en.target); if (!a) return;
|
||||
links.forEach((l) => l.classList.remove("active"));
|
||||
a.classList.add("active");
|
||||
});
|
||||
}, { rootMargin: "-40% 0px -55% 0px", threshold: 0 });
|
||||
map.forEach((_, el) => io.observe(el));
|
||||
const entries = [];
|
||||
links.forEach((a) => { const el = document.querySelector(a.getAttribute("href")); if (el) entries.push({ el, link: a }); });
|
||||
if (!entries.length) return;
|
||||
const setActive = (link) => { links.forEach((l) => l.classList.remove("active")); link.classList.add("active"); };
|
||||
const update = () => {
|
||||
const doc = document.documentElement;
|
||||
const scrollBottom = window.scrollY + window.innerHeight;
|
||||
if (scrollBottom >= (doc.scrollHeight - 4)) { setActive(entries[entries.length - 1].link); return; }
|
||||
const line = window.scrollY + window.innerHeight * 0.35;
|
||||
let active = entries[0].link;
|
||||
for (const e of entries) {
|
||||
if (e.el.getBoundingClientRect().top + window.scrollY <= line) active = e.link;
|
||||
else break;
|
||||
}
|
||||
setActive(active);
|
||||
};
|
||||
window.addEventListener("scroll", update, { passive: true });
|
||||
window.addEventListener("resize", update);
|
||||
update();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue