1/** 2 * Portfolio Home Mobile - Scroll Animation 3 * Titolo verticale, portfolio card che salgono dal basso e si sovrappongono 4 */ 5(function() { 6 'use strict'; 7 8 document.addEventListener('DOMContentLoaded', () => { 9 const portfolioBlock = document.querySelector('.portfolio-home-mobile'); 10 11 if (!portfolioBlock) return; 12 13 // Verifica che l'elemento sia visibile (non nascosto da display:none) 14 const isVisible = window.getComputedStyle(portfolioBlock).display !== 'none'; 15 if (!isVisible) { 16 // Se non è visibile, aspetta che diventi visibile (per template responsive dinamici) 17 const checkVisibility = () => { 18 const checkVisible = window.getComputedStyle(portfolioBlock).display !== 'none'; 19 if (checkVisible) { 20 initPortfolioHomeMobileAnimation(); 21 } else { 22 setTimeout(checkVisibility, 100); 23 } 24 }; 25 checkVisibility(); 26 return; 27 } 28 29 initPortfolioHomeMobileAnimation(); 30 }); 31 32 function initPortfolioHomeMobileAnimation() { 33 const portfolioBlock = document.querySelector('.portfolio-home-mobile'); 34 if (!portfolioBlock) return; 35 36 // Verifica nuovamente la visibilità prima di inizializzare 37 if (window.getComputedStyle(portfolioBlock).display === 'none') { 38 return; 39 } 40 41 const titleWrapper = portfolioBlock.querySelector('.portfolio-home-mobile__title-wrapper'); 42 const cards = portfolioBlock.querySelectorAll('.portfolio-card-mobile'); 43 const footer = portfolioBlock.querySelector('.portfolio-home-mobile__footer'); 44 45 if (!titleWrapper || cards.length === 0) return; 46 47 // Registra ScrollTrigger plugin 48 gsap.registerPlugin(ScrollTrigger); 49 50 const viewportHeight = window.innerHeight; 51 const numCards = cards.length; 52 53 // === STATO INIZIALE === 54 // Titolo: posizionato direttamente nel contenitore (nessuna animazione di ingresso) 55 // Usa xPercent/yPercent per mantenere il centraggio CSS 56 gsap.set(titleWrapper, { 57 xPercent: -50, // Mantiene il centramento orizzontale 58 yPercent: -50, // Mantiene il centramento verticale 59 y: 0, // Già centrato, nessun movimento 60 opacity: 1 61 }); 62 63 // Tutte le card partono dal basso 64 gsap.set(cards, { 65 y: viewportHeight, 66 opacity: 1 67 }); 68 69 // Footer parte dal basso (NO FADE) 70 if (footer) { 71 gsap.set(footer, { 72 y: 50, 73 opacity: 1 // Sempre visibile 74 }); 75 } 76 77 // === ANIMAZIONE CON PIN (IDENTICO a exchange program) === 78 // Durata calcolata: titolo + (card à numCards) + footer 79 const totalPhases = 1 + numCards + 1; // Titolo + cards + footer 80 const pinDuration = `+=${totalPhases * 100}%`; 81 82 const mainTimeline = gsap.timeline({ 83 scrollTrigger: { 84 trigger: portfolioBlock, 85 start: 'top top', 86 end: pinDuration, // Dinamico come exchange 87 pin: true, 88 scrub: 1, 89 anticipatePin: 1, 90 // markers: true, // Debug 91 } 92 }); 93 94 // FASE 1: Titolo rimane fisso e centrato (non animiamo, il CSS lo centra) 95 // Manteniamo xPercent e yPercent per il centraggio, y: 0 già impostato nello stato iniziale 96 97 // Pausa minima (0-5% timeline) 98 mainTimeline.to({}, { duration: 0.05 }); 99 100 // FASI 2-N: Ogni card sale singolarmente al centro (5-80% timeline) - Inizia subito 101 cards.forEach((card, index) => { 102 const startTime = 0.05 + (index * 0.12); 103 104 // Card sale dal basso al centro (y: 0, sovrapposta) 105 mainTimeline.to(card, { 106 y: 0, 107 duration: 0.12, 108 ease: 'none', 109 onStart: () => { 110 // Z-index crescente per sovrapposizione corretta 111 card.style.zIndex = 10 + index; 112 } 113 }, startTime); 114 }); 115 116 // FASE FINALE: Footer sale (80-100% timeline) - NO FADE 117 if (footer) { 118 const footerStartTime = 0.05 + (numCards * 0.12) + 0.03; 119 120 mainTimeline.to(footer, { 121 y: 0, // Solo movimento, no opacity 122 duration: 0.2, 123 ease: 'none', 124 }, footerStartTime); 125 } 126 127 //console.log('Portfolio Home Mobile initialized:', numCards, 'portfolio items'); 128 } 129 130})(); 131
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.