PageSourceSearch

https://socem.pt/40-anos/assets/script.js

js socem.pt collected 2026-10-08 06:46:25 UTC 3,143 bytes, 85 lines download raw bytes

1// language toggle
2const buttons = document.querySelectorAll('.lang-toggle button');
3buttons.forEach(btn => {
4  btn.addEventListener('click', () => {
5    const lang = btn.dataset.setLang;
6    document.body.setAttribute('data-lang', lang);
7    buttons.forEach(b => {
8      b.classList.toggle('active', b === btn);
9      b.setAttribute('aria-pressed', b === btn ? 'true' : 'false');
10    });
11  });
12});
13
14// nav scroll state + logo swap (white on hero, dark once scrolled)
15const nav = document.getElementById('siteNav');
16const navLogo = document.getElementById('navLogo');
17const LOGO_DARK = 'assets/logo_nav_light.png';
18const LOGO_LIGHT = 'assets/logo_nav_dark.png';
19window.addEventListener('scroll', () => {
20  const scrolled = window.scrollY > 60;
21  nav.classList.toggle('scrolled', scrolled);
22  nav.classList.toggle('on-dark', !scrolled);
23  navLogo.src = scrolled ? LOGO_DARK : LOGO_LIGHT;
24}, { passive: true });
25
26// reveal on scroll
27const revealEls = document.querySelectorAll('.reveal');
28const io = new IntersectionObserver((entries) => {
29  entries.forEach(e => {
30    if(e.isIntersecting){ e.target.classList.add('in'); io.unobserve(e.target); }
31  });
32}, { threshold: 0.12 });
33revealEls.forEach(el => io.observe(el));
34
35// animated counters
36const counters = document.querySelectorAll('[data-count]');
37const counterIO = new IntersectionObserver((entries) => {
38  entries.forEach(entry => {
39    if(!entry.isIntersecting) return;
40    const el = entry.target;
41    const target = parseInt(el.dataset.count, 10);
42    const duration = 1400;
43    const start = performance.now();
44    function tick(now){
45      const progress = Math.min((now - start) / duration, 1);
46      const eased = 1 - Math.pow(1 - progress, 3);
47      const value = Math.floor(eased * target);
48      el.textContent = value.toLocaleString('pt-PT');
49      if(progress < 1){ requestAnimationFrame(tick); } else { el.textContent = target.toLocaleString('pt-PT'); }
50    }
51    requestAnimationFrame(tick);
52    counterIO.unobserve(el);
53  });
54}, { threshold: 0.4 });
55counters.forEach(el => counterIO.observe(el));
56
57// Video modal
58function openVideoModal() {
59  const modal = document.getElementById('videoModal');
60  const video = document.getElementById('modalVideo');
61  modal.classList.add('open');
62  document.body.style.overflow = 'hidden';
63  video.play().catch(() => {});
64}
65
66function closeVideoModal(e) {
67  // close only if clicking the backdrop (not the inner panel), or the close button
68  if (e && e.target !== document.getElementById('videoModal') && !e.target.closest('.video-modal-close')) return;
69  const modal = document.getElementById('videoModal');
70  const video = document.getElementById('modalVideo');
71  modal.classList.remove('open');
72  document.body.style.overflow = '';
73  video.pause();
74  video.currentTime = 0;
75}
76
77// Close modal with Escape key
78document.addEventListener('keydown', function(e) {
79  if (e.key === 'Escape') {
80    const modal = document.getElementById('videoModal');
81    if (modal && modal.classList.contains('open')) {
82      closeVideoModal({ target: modal });
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.