PageSourceSearch

https://eepymep.netlify.app/js/nav-block.js

js eepymep.netlify.app collected 2026-10-03 10:41:08 UTC 3,867 bytes, 85 lines download raw bytes

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.