1document.addEventListener("DOMContentLoaded", function () { 2 const tocLinks = document.querySelectorAll(".toc-link"); 3 const headings = document.querySelectorAll("h2, h3"); 4 5 // --- 1. SMOOTH SCROLLING --- 6 tocLinks.forEach((link) => { 7 link.addEventListener("click", function (e) { 8 e.preventDefault(); 9 const targetHref = this.getAttribute("href"); // e.g., "#36-of-workers..." 10 if (!targetHref) return; 11 const targetId = targetHref.substring(1); // e.g., "36-of-workers..." 12 const targetElement = document.getElementById(targetId); 13 14 if (targetElement) { 15 targetElement.scrollIntoView({ 16 behavior: "smooth", 17 block: "start", 18 }); 19 } 20 }); 21 }); 22 23 // --- 2. ANIMATION SETUP --- 24 25 // Define Tailwind classes for animation states 26 const baseAnimClasses = ['block', 'transition-all', 'duration-300', 'ease-in-out']; 27 28 // Classes for the VISIBLE state 29 // max-h-20 = 5rem 30 const visibleClasses = ['opacity-100', 'visible', 'max-h-20', 'mb-2']; 31 32 // Classes for the HIDDEN state 33 const hiddenClasses = ['opacity-0', 'invisible', 'max-h-0', 'pt-0', 'pb-0', 'mt-0', 'mb-0', 'pointer-events-none']; 34 35 /** 36 * Helper function to SHOW a submenu link using Tailwind classes 37 * @param {Element} link - The TOC link element to show 38 */ 39 function showSubmenuLink(link) { 40 link.classList.remove(...hiddenClasses); 41 link.classList.add(...visibleClasses); 42 } 43 44 /** 45 * Helper function to HIDE a submenu link using Tailwind classes 46 * @param {Element} link - The TOC link element to hide 47 */ 48 function hideSubmenuLink(link) { 49 link.classList.remove(...visibleClasses); 50 link.classList.add(...hiddenClasses); 51 } 52 53 // Find all h3/h4 links and prepare them for animation 54 tocLinks.forEach((link) => { 55 const targetHref = link.getAttribute("href"); 56 if (!targetHref || targetHref === "#") return; 57 const targetId = targetHref.substring(1); 58 const targetElement = document.getElementById(targetId); 59 60 61 if (targetElement) { 62 const tag = targetElement.tagName.toLowerCase(); 63 64 if (tag === 'h2') { 65 // Get the parent <li> element 66 const parentLi = link.parentElement; 67 68 // Style the <li>, NOT the <a> 69 if (parentLi) { 70 // Remove the "mb-0" from your PHP and add the margin we want 71 parentLi.classList.remove("mb-0"); 72 parentLi.classList.add("mb-2"); // Or "mb-1" 73 } 74 } 75 76 if (tag === "h3" || tag === "h4") { 77 // Add a class for JS to select them 78 link.classList.add("submenu-item"); 79 80 // Add the base classes for transition 81 link.classList.add(...baseAnimClasses); 82 83 // Start them all as hidden 84 hideSubmenuLink(link); 85 } 86 } 87 }); 88 89 // --- Utility Function --- 90 function getSubheadingsUnderH2(h2) { 91 const subs = []; 92 let el = h2.nextElementSibling; 93 while (el && el.tagName.toLowerCase() !== "h2") { 94 const tag = el.tagName.toLowerCase(); 95 if (tag === "h3" || tag === "h4") { 96 subs.push(el); 97 } 98 el = el.nextElementSibling; 99 } 100 return subs; 101 } 102 103 // --- Observer Logic --- 104 let previouslyActiveH2 = null; 105 106 const observer = new IntersectionObserver( 107 (entries) => { 108 entries.forEach((entry) => { 109 if (!entry.isIntersecting) return; 110 111 const activeHeading = entry.target; 112 const id = activeHeading.getAttribute("id"); 113 if (!id) return; 114 115 // Highlighting Logic 116 tocLinks.forEach((link) => { 117 link.classList.remove("text-primary!", "[text-shadow:0.5px_0_0_var(--color-primary)]"); 118 }); 119 120 // We define tocLink here 121 const tocLink = document.querySelector(`.toc-link[href="#${id}"]`); 122 tocLink?.classList.add("text-primary!", "[text-shadow:0.5px_0_0_var(--color-primary)]"); 123 124 let currentH2; 125 if (activeHeading.tagName.toLowerCase() === "h2") { 126 currentH2 = activeHeading; 127 } else if (activeHeading.tagName.toLowerCase() === "h3") { 128 let el = activeHeading.previousElementSibling; 129 while (el) { 130 if (el.tagName.toLowerCase() === "h2") { 131 currentH2 = el; 132 break; 133 } 134 el = el.previousElementSibling; 135 } 136 if (currentH2) { 137 const parentH2Link = document.querySelector( 138 `.toc-link[href="#${currentH2.getAttribute("id")}"]` 139 ); 140 parentH2Link?.classList.add("text-primary!", "[text-shadow:0.5px_0_0_var(--color-primary)]"); 141 } 142 } 143 144 // --- 3. ANIMATION LOGIC (Now using class helpers) --- 145 if (currentH2) { 146 if (previouslyActiveH2 && previouslyActiveH2 !== currentH2) { 147 // HIDE old sub-links 148 const prevSubHeadings = getSubheadingsUnderH2(previouslyActiveH2);
149 prevSubHeadings.forEach((heading) => { 150 const subId = heading.getAttribute("id"); 151 if (!subId) return; 152 const oldLinks = document.querySelectorAll(`a.submenu-item[href="#${subId}"]`); 153 oldLinks.forEach(hideSubmenuLink); 154 }); 155 } 156 157 // SHOW new sub-links 158 const subHeadings = getSubheadingsUnderH2(currentH2); 159 subHeadings.forEach((heading) => { 160 const subId = heading.getAttribute("id"); 161 if (!subId) return; 162 const links = document.querySelectorAll(`a.submenu-item[href="#${subId}"]`); 163 links.forEach(showSubmenuLink); 164 }); 165 166 previouslyActiveH2 = currentH2; 167 } 168 169 // --- 4. SCROLL TOC TO ACTIVE LINK (NEW CODE) --- 170 if (tocLink) { 171 // Use 'nearest' to avoid the whole page jumping, just the container 172 tocLink.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); 173 } 174 }); 175 }, 176 { 177 // --- 4. OBSERVER OPTIONS --- 178 threshold: 0, 179 rootMargin: "0px 0px -70% 0px", 180 } 181 ); 182
183 headings.forEach((heading) => observer.observe(heading)); 184});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.