1/* 2 * nav-block.js â Feature Navigation Panels 3 * ââââââââââââââââââââââââââââââââââââââââââ 4 * Handles hover (desktop) and tap (mobile) interactions 5 * for the left/right feature panels. 6 * 7 * KEY CONCEPTS TO EXPLORE HERE: 8 * querySelectorAll + forEach â loop over every nav block on the page 9 * dataset â reads data-* attributes from HTML elements 10 * e.g. data-target="media-0" â item.dataset.target 11 * mouseenter / mouseleave â fire when the cursor enters/leaves an element 12 * (unlike mouseover, they don't bubble up) 13 * click â fires on tap too, so works for mobile 14 * window.innerWidth â current viewport width in px 15 * Arrow function () => {} â shorter function syntax; inherits 'this' 16 * from the surrounding scope 17 */ 18 19(function () { 20 21 // Returns true when the screen is phone-sized 22 const isMobile = () => window.innerWidth <= 680; 23 24 document.querySelectorAll('.nav-block').forEach(block => { 25 const items = block.querySelectorAll('.nav-item'); 26 const content = block.querySelector('.nav-content'); 27 28 // ââ activate ââââââââââââââââââââââââââââââââââââââââââââ 29 // Shows the panel that matches the hovered/clicked item. 30 function activate(item) { 31 const targetId = item.dataset.target; // reads data-target="..." 32 const panel = document.getElementById(targetId); 33 if (!panel) return; 34 35 // Clear all active states first 36 block.querySelectorAll('.nav-item').forEach(i => i.classList.remove('active')); 37 block.querySelectorAll('.nav-panel').forEach(p => p.classList.remove('visible')); 38 39 // Apply active state to this item and its panel 40 item.classList.add('active'); 41 panel.classList.add('visible'); 42 content.classList.add('has-active'); // hides the empty-state hint 43 } 44 45 // ââ deactivate ââââââââââââââââââââââââââââââââââââââââââ 46 // Called on mouse leave â falls back to the first item 47 // so something is always shown rather than going blank. 48 function deactivate() { 49 if (isMobile()) return; // mobile uses tap, not hover 50 if (items.length) activate(items[0]); 51 } 52 53 // Show the first item by default on page load 54 if (items.length) activate(items[0]); 55 56 // ââ Attach events ââââââââââââââââââââââââââââââââââââââââ 57 items.forEach(item => { 58 59 // Desktop: hover to reveal 60 item.addEventListener('mouseenter', () => { if (!isMobile()) activate(item); }); 61 item.addEventListener('mouseleave', () => { if (!isMobile()) deactivate(); }); 62 63 // Mobile: tap to toggle open/closed 64 item.addEventListener('click', () => { 65 if (!isMobile()) return; 66 67 if (item.classList.contains('active')) { 68 // Tap the active item again â collapse it 69 item.classList.remove('active'); 70 const panel = document.getElementById(item.dataset.target); 71 if (panel) panel.classList.remove('visible'); 72 // If nothing is active anymore, remove has-active so hint shows 73 if (!block.querySelector('.nav-item.active')) { 74 content.classList.remove('has-active'); 75 } 76 } else { 77 // Tap a different item â switch to it 78 activate(item); 79 } 80 }); 81 82 }); 83 }); 84 85})();
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.