1import { gsap } from 'gsap'; 2import { ScrollToPlugin } from 'gsap/dist/ScrollToPlugin.min.js'; 3import { ScrollTrigger } from 'gsap/dist/ScrollTrigger.min.js'; 4 5import { setupConfettiOnClick } from './confettis-effect.js'; 6import { createBoxes, setupBoxesTimeline } from './scroll-boxes.js'; 7import { setupSectionsAnimations } from './scroll-sections.js'; 8import { 9 goToNextSection, 10 goToPreviousSection, 11 scrollToTarget, 12 setupTimelineActions, 13 setupTimelineScroll, 14} from './scroll-timeline.js'; 15 16// Register GSAP plugins. 17gsap.registerPlugin(ScrollTrigger, ScrollToPlugin); 18 19/** 20 * Initializes page animations and interactions. 21 */ 22async function initializePage() { 23 createBoxes(); 24 await setupBoxesTimeline(); 25 setupSectionsAnimations(); 26 setupTimelineScroll(); 27 setupTimelineActions(); 28 setupConfettiOnClick(); 29 30 // Navigation elements. 31 const logo = document.querySelector('.top-logo'); 32 const scrollButton = document.querySelector('.scroll-button'); 33 const firstSection = document.querySelector('.section'); 34 const targetScrollSection = document.querySelectorAll('.section')[2]; 35 36 // Handle click events for scrolling. 37 if (logo) { 38 logo.addEventListener('click', (e) => { 39 e.stopImmediatePropagation(); 40 e.preventDefault(); 41 scrollToTarget(firstSection); 42 }); 43 } else { 44 console.warn("Element '.top-logo' not found."); 45 } 46 47 if (scrollButton) { 48 scrollButton.addEventListener('click', () => scrollToTarget(targetScrollSection, 1)); 49 } else { 50 console.warn("Element '.scroll-button' not found."); 51 } 52 53 // Logo animation based on first section scroll. 54 gsap.set(logo, { opacity: 0, y: -10, pointerEvents: 'none' }); 55 56 const logoAppearAnimation = gsap.to(logo, { 57 opacity: 1, 58 y: 0, 59 pointerEvents: 'auto', 60 duration: 0.3, 61 ease: 'power1.out', 62 paused: true, 63 reversed: true, 64 }); 65 66 ScrollTrigger.create({ 67 trigger: '#section1', 68 start: 'bottom center', 69 onEnter: () => { 70 logoAppearAnimation.play(); 71 }, 72 onLeaveBack: () => { 73 logoAppearAnimation.reverse(); 74 }, 75 }); 76 77 ScrollTrigger.create({ 78 trigger: '#final', 79 start: 'top center', 80 end: 'top-=10% center', 81 onEnter: () => { 82 logoAppearAnimation.reverse(); 83 }, 84 onLeaveBack: () => { 85 logoAppearAnimation.play(); 86 }, 87 }); 88} 89 90/** 91 * Handles window resizing. 92 */ 93function handleWindowResize() { 94 clearTimeout(window.__resizeTimeout); 95 96 window.__resizeTimeout = setTimeout(() => { 97 // Kill existing ScrollTriggers. 98 ScrollTrigger.getAll().forEach((trigger) => trigger.kill()); 99 100 // Remove 'box' elements. 101 document.querySelectorAll('[class*="box"]').forEach((element) => element.remove()); 102 103 // Recreate and reconfigure components. 104 createBoxes(); 105 setupBoxesTimeline(); 106 setupSectionsAnimations(); 107 setupTimelineScroll(); 108 109 ScrollTrigger.refresh(); 110 }, 250); 111} 112 113// --- Global Event Listeners --- 114window.addEventListener('DOMContentLoaded', async () => await initializePage()); 115window.addEventListener('resize', handleWindowResize); 116 117window.addEventListener('keydown', (e) => { 118 if (e.code === 'ArrowDown' || (e.code === 'Space' && !e.shiftKey)) { 119 e.preventDefault(); 120 goToNextSection(); 121 } else if (e.code === 'ArrowUp' || (e.code === 'Space' && e.shiftKey)) { 122 e.preventDefault(); 123 goToPreviousSection(); 124 } 125});
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.