From 97e7c319d656a5f05489ca996e249e7359303d4d Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 31 May 2026 22:42:33 +0000
Subject: [PATCH] =Jakevan edits done?
---
build/glossary/view.js | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 165 insertions(+), 1 deletions(-)
diff --git a/build/glossary/view.js b/build/glossary/view.js
index 1b7171f..36573e5 100644
--- a/build/glossary/view.js
+++ b/build/glossary/view.js
@@ -1 +1,165 @@
-(()=>{class t{constructor(t="dl.glossary",e="nav.glossary-index"){this.glossary=document.querySelector(t),this.nav=document.querySelector(e),this.glossary&&this.nav&&(this.terms=this.glossary.querySelectorAll("dt[id]"),this.navList=this.nav.querySelector("ul"),this.activeClass="active",this.currentActive=null,this.breakpoint=768,this.init(),this.setupResizeHandler())}init(){const t={root:null,rootMargin:this.getRootMargin(),threshold:0};this.observer=new IntersectionObserver((t=>this.handleIntersection(t)),t),this.terms.forEach((t=>this.observer.observe(t))),this.handleScroll=this.debounce((()=>this.checkActiveTerm()),100),window.addEventListener("scroll",this.handleScroll,{passive:!0})}getRootMargin(){if(window.innerWidth<this.breakpoint){const t=parseFloat(getComputedStyle(document.documentElement).fontSize),e=Math.round(5*t);return`-${e}px 0px -${e}px 0px`}return"-50% 0px -50% 0px"}setupResizeHandler(){let t;window.addEventListener("resize",(()=>{clearTimeout(t),t=setTimeout((()=>{this.reinitialize()}),250)}))}reinitialize(){this.observer&&this.observer.disconnect(),this.init()}handleIntersection(t){const e=t.find((t=>t.isIntersecting));e&&this.setActive(e.target)}checkActiveTerm(){const t=4*parseFloat(getComputedStyle(document.documentElement).fontSize);let e=null,i=1/0;this.terms.forEach((s=>{const n=s.getBoundingClientRect();if(window.innerWidth<this.breakpoint?n.top>=t&&n.top<=window.innerHeight-t:n.top+n.height/2>=0&&n.top+n.height/2<=window.innerHeight){const o=window.innerWidth<this.breakpoint?t:window.innerHeight/2,r=Math.abs(n.top-o);r<i&&(i=r,e=s)}})),e&&this.setActive(e)}setActive(t){this.currentActive!==t&&(this.currentActive&&this.currentActive.classList.remove(this.activeClass),t.classList.add(this.activeClass),this.currentActive=t,this.updateNavigation(t.id))}updateNavigation(t){this.nav.querySelectorAll("a").forEach((t=>t.classList.remove(this.activeClass)));const e=this.nav.querySelector(`a[href="#${t}"]`);e&&(e.classList.add(this.activeClass),this.centerNavItem(e))}centerNavItem(t){const e=this.navList.getBoundingClientRect(),i=t.getBoundingClientRect(),s=this.navList.scrollTop,n=i.top-e.top,o=e.height/2-i.height/2;this.navList.scrollTo({top:s+n-o,behavior:"smooth"})}debounce(t,e){let i;return function(...s){clearTimeout(i),i=setTimeout((()=>{clearTimeout(i),t(...s)}),e)}}destroy(){this.observer&&this.observer.disconnect(),window.removeEventListener("scroll",this.handleScroll)}}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",(()=>{new t})):new t})();
\ No newline at end of file
+/******/ (() => { // webpackBootstrap
+/*!******************************!*\
+ !*** ./src/glossary/view.js ***!
+ \******************************/
+/**
+ * Glossary Navigation Active State Manager
+ * Handles highlighting active terms as they scroll into view
+ * and syncing navigation with scroll position
+ */
+class GlossaryNavigator {
+ constructor(glossarySelector = 'dl.glossary', navSelector = 'nav.glossary-index') {
+ this.glossary = document.querySelector(glossarySelector);
+ this.nav = document.querySelector(navSelector);
+ if (!this.glossary || !this.nav) return;
+ this.terms = this.glossary.querySelectorAll('dt[id]');
+ this.navList = this.nav.querySelector('ul');
+ this.activeClass = 'active';
+ this.currentActive = null;
+ this.init();
+ this.setupResizeHandler();
+ }
+ init() {
+ // Set up Intersection Observer with screen-size appropriate margins
+ const observerOptions = {
+ root: null,
+ // viewport
+ rootMargin: this.getRootMargin(),
+ threshold: 0
+ };
+ this.observer = new IntersectionObserver(entries => this.handleIntersection(entries), observerOptions);
+
+ // Observe all terms
+ this.terms.forEach(term => this.observer.observe(term));
+
+ // Also handle manual scroll for edge cases
+ this.handleScroll = this.debounce(() => this.checkActiveTerm(), 100);
+ window.addEventListener('scroll', this.handleScroll, {
+ passive: true
+ });
+ }
+ getRootMargin() {
+ // On larger screens: centered (50% from top and bottom)
+ return '-50% 0px -50% 0px';
+ }
+ setupResizeHandler() {
+ let resizeTimer;
+ window.addEventListener('resize', () => {
+ clearTimeout(resizeTimer);
+ resizeTimer = setTimeout(() => {
+ // Reinitialize observer with new margins on resize
+ this.reinitialize();
+ }, 250);
+ });
+ }
+ reinitialize() {
+ // Disconnect old observer
+ if (this.observer) {
+ this.observer.disconnect();
+ }
+
+ // Create new observer with updated margins
+ this.init();
+ }
+ handleIntersection(entries) {
+ // Find the entry that's intersecting
+ const intersecting = entries.find(entry => entry.isIntersecting);
+ if (intersecting) {
+ this.setActive(intersecting.target);
+ }
+ }
+ checkActiveTerm() {
+ // Fallback method to find which term is in the trigger zone
+ const remInPixels = parseFloat(getComputedStyle(document.documentElement).fontSize);
+ const margin = remInPixels * 4;
+ let closestTerm = null;
+ let closestDistance = Infinity;
+ this.terms.forEach(term => {
+ const rect = term.getBoundingClientRect();
+ const isInZone = rect.top + rect.height / 2 >= 0 && rect.top + rect.height / 2 <= window.innerHeight;
+ if (isInZone) {
+ // Find closest to the trigger point
+ const triggerPoint = window.innerHeight / 2;
+ const distance = Math.abs(rect.top - triggerPoint);
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestTerm = term;
+ }
+ }
+ });
+ if (closestTerm) {
+ this.setActive(closestTerm);
+ }
+ }
+ setActive(term) {
+ if (this.currentActive === term) return;
+
+ // Remove active class from previous term
+ if (this.currentActive) {
+ this.currentActive.classList.remove(this.activeClass);
+ }
+
+ // Add active class to current term
+ term.classList.add(this.activeClass);
+ this.currentActive = term;
+
+ // Update navigation
+ this.updateNavigation(term.id);
+ }
+ updateNavigation(termId) {
+ // Remove active from all nav links
+ const navLinks = this.nav.querySelectorAll('a');
+ navLinks.forEach(link => link.classList.remove(this.activeClass));
+
+ // Find and activate corresponding nav link
+ const activeLink = this.nav.querySelector(`a[href="#${termId}"]`);
+ if (activeLink) {
+ activeLink.classList.add(this.activeClass);
+
+ // Scroll the nav list to center the active link
+ this.centerNavItem(activeLink);
+ }
+ }
+ centerNavItem(link) {
+ const listRect = this.navList.getBoundingClientRect();
+ const linkRect = link.getBoundingClientRect();
+
+ // Calculate position to center the link in the nav container
+ const scrollTop = this.navList.scrollTop;
+ const linkOffset = linkRect.top - listRect.top;
+ const centerOffset = listRect.height / 2 - linkRect.height / 2;
+ this.navList.scrollTo({
+ top: scrollTop + linkOffset - centerOffset,
+ behavior: 'smooth'
+ });
+ }
+ debounce(func, wait) {
+ let timeout;
+ return function executedFunction(...args) {
+ const later = () => {
+ clearTimeout(timeout);
+ func(...args);
+ };
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ };
+ }
+ destroy() {
+ if (this.observer) {
+ this.observer.disconnect();
+ }
+ window.removeEventListener('scroll', this.handleScroll);
+ }
+}
+
+// Initialize when DOM is ready
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', () => {
+ new GlossaryNavigator();
+ });
+} else {
+ new GlossaryNavigator();
+}
+/******/ })()
+;
+//# sourceMappingURL=view.js.map
\ No newline at end of file
--
Gitblit v1.10.0