PageSourceSearch

https://www.ascee.nl/wp-content/themes/ascee/assets/js/site.js?ver=1.0.0.1790321533

js ascee.nl collected 2026-10-07 04:29:25 UTC 6,628 bytes, 163 lines download raw bytes

1/* ============================================================
2   Site-wide interactivity:
3     1. Sticky navbar — IntersectionObserver on the in-hero `.navbar-wrap`.
4        When it leaves the viewport, body gains `.is-scrolled` → the body-level
5        `.sticky-nav` slides down via CSS transition.
6     2. Mobile menu — any `[data-mobile-toggle]` button toggles `body.menu-open`.
7        Closes on ESC, on link click inside the overlay, and on backdrop click.
8   ============================================================ */
9(function () {
10    'use strict';
11	
12			// Auto-inject fade-up op alle <section> elementen die nog geen data-aos hebben
13		document.querySelectorAll('section:not([data-aos]) > div').forEach(section => {
14			section.setAttribute('data-aos', 'fade-up');
15		});
16
17		AOS.init({
18			duration: 800,
19			easing: 'ease-out-cubic',
20			once: true,
21			offset: 80,
22		});
23
24    /* ---------- 1. Sticky navbar ------------------------------------------ */
25    function initStickyNav() {
26        var sentinel = document.querySelector('.hero .navbar-wrap');
27        var body     = document.body;
28        if (!sentinel || !('IntersectionObserver' in window)) return;
29
30        var observer = new IntersectionObserver(function (entries) {
31            entries.forEach(function (entry) {
32                // intersectionRatio === 0 → fully out of view → show sticky
33                body.classList.toggle('is-scrolled', !entry.isIntersecting);
34            });
35        }, { rootMargin: '0px', threshold: 0 });
36
37        observer.observe(sentinel);
38    }
39
40    /* ---------- 2. Mobile menu toggle ------------------------------------- */
41    function initMobileMenu() {
42        var body    = document.body;
43        var toggles = document.querySelectorAll('[data-mobile-toggle]');
44        var overlay = document.getElementById('mobile-menu');
45        if (!toggles.length || !overlay) return;
46
47        function setOpen(open) {
48            body.classList.toggle('menu-open', open);
49            overlay.setAttribute('aria-hidden', open ? 'false' : 'true');
50            // sync any hamburger triggers (the one in navbar) — close button inside the overlay stays at false
51            document.querySelectorAll('.navbar__hamburger').forEach(function (b) {
52                b.setAttribute('aria-expanded', open ? 'true' : 'false');
53            });
54            // Focus management: move focus into the menu when opening for keyboard users
55            if (open) {
56                var firstLink = overlay.querySelector('a, button');
57                if (firstLink) firstLink.focus({ preventScroll: true });
58            }
59        }
60
61        toggles.forEach(function (btn) {
62            btn.addEventListener('click', function () {
63                setOpen(!body.classList.contains('menu-open'));
64            });
65        });
66
67        // Close on ESC
68        document.addEventListener('keydown', function (e) {
69            if (e.key === 'Escape' && body.classList.contains('menu-open')) {
70                setOpen(false);
71            }
72        });
73
74        // Close on link click inside overlay (so anchor + same-page navigation feels right)
75        overlay.addEventListener('click', function (e) {
76            var a = e.target.closest('a');
77            if (a) setOpen(false);
78        });
79    }
80
81    document.addEventListener('DOMContentLoaded', function () {
82        initStickyNav();
83        initMobileMenu();
84    });
85})();
86
87document.addEventListener('DOMContentLoaded', () => {
88  document.querySelectorAll('.btn--gradient').forEach(btn => {
89    // Skip als al verwerkt
90    if (btn.querySelector('.btn__eq')) return;
91    
92    // Wrap bestaande tekst in een label-span
93    const label = document.createElement('span');
94    label.className = 'btn__label';
95    while (btn.firstChild) label.appendChild(btn.firstChild);
96    
97    // EQ container met 22 bars
98    const eq = document.createElement('span');
99    eq.className = 'btn__eq';
100    eq.setAttribute('aria-hidden', 'true');
101    
102    for (let i = 0; i < 12; i++) {
103      const bar = document.createElement('span');
104      bar.style.setProperty('--dur', (0.5 + Math.random() * 0.7).toFixed(2) + 's');
105      bar.style.setProperty('--del', (Math.random() * -1.5).toFixed(2) + 's');
106      eq.appendChild(bar);
107    }
108    
109    btn.appendChild(eq);
110    btn.appendChild(label);
111  });
112});
113
114/* ==========================================================================
115   Featured-CTA overlay — ruimte eronder precies passend maken.
116
117   De .featured-cta hangt absoluut gepositioneerd over de vorige sectie heen.
118   De hostsectie moet daar met padding-top omheen, maar hoeveel hangt af van de
119   hoogte van de kaart — en die verschilt per pagina, want de tekst verschilt.
120   Eén vaste clamp in CSS is daardoor altijd óf te krap (kop plakt tegen de
121   kaart) óf te ruim (gat onder de kaart). Hier meten we de werkelijke overlap
122   en zetten we de padding daarop.
123
124   De CSS-clamp blijft als fallback staan voor het geval JS niet draait.
125   ========================================================================== */
126document.addEventListener('DOMContentLoaded', () => {
127    const GAP = 100; // gewenste ruimte tussen onderkant kaart en eerste inhoud
128
129    const hosts = document.querySelectorAll('.section--about--featured, .section--features--has-overlap');
130    if (!hosts.length) return;
131
132    const fit = () => {
133        hosts.forEach((host) => {
134            const card = host.querySelector('.featured-cta');
135            if (!card) return;
136
137            /* Onder de breakpoint laat de CSS de kaart los uit de absolute
138               positionering: hij staat dan gewoon in de flow van de vórige
139               sectie en overlapt niets. Zonder deze check zou de meting hem
140               alsnog als overlap zien en er honderden pixels padding onder
141               plakken. */
142            if (getComputedStyle(card).position !== 'absolute') {
143                host.style.removeProperty('padding-top');
144                return;
145            }
146
147            // Meet zonder onze eigen padding, anders meten we onszelf mee.
148            host.style.paddingTop = '0px';
149            const overlap = card.getBoundingClientRect().bottom - host.getBoundingClientRect().top;
150
151            if (overlap > 0) {
152                host.style.paddingTop = Math.round(overlap + GAP) + 'px';
153            } else {
154                host.style.removeProperty('padding-top');
155            }
156        });
157    };
158
159    fit();
160    window.addEventListener('resize', fit);
161    // Webfonts veranderen de kaarthoogte nadat DOMContentLoaded al geweest is.
162    if (document.fonts && document.fonts.ready) document.fonts.ready.then(fit);
163});

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.