PageSourceSearch

https://www.accademiamoda.it/wp-content/themes/iuad-theme/src/js/custom/three-card-carousel.js?ver=1.0.0

js accademiamoda.it collected 2026-10-04 13:23:41 UTC 9,274 bytes, 228 lines download raw bytes

1/**
2 * Three Card Carousel - Swiper Centered Mode
3 * Carousel orizzontale con 3 card visibili e centro attivo
4 */
5
6(function() {
7    'use strict';
8
9    document.addEventListener('DOMContentLoaded', function() {
10        // Inizializza il carousel solo se esiste
11        const carouselElement = document.querySelector('.three-card-carousel-swiper');
12        
13        if (!carouselElement) return;
14
15        const slides = carouselElement.querySelectorAll('.swiper-slide');
16        const slidesCount = slides.length;
17        const isDesktop = window.innerWidth >= 1024;
18        const desktopStatic = isDesktop && slidesCount <= 3;
19        const desktopStaticTwo = isDesktop && slidesCount === 2;
20        const desktopStaticThree = isDesktop && slidesCount === 3;
21
22        // Inizializza Swiper con centered mode
23        const threeCardSwiper = new Swiper('.three-card-carousel-swiper', {
24            // Modalità centrata - la slide attiva è sempre al centro
25            centeredSlides: true,
26            
27            // Loop infinito (solo se non siamo in modalità statica desktop)
28            loop: !desktopStatic,
29            
30            // Numero di slide visibili
31            slidesPerView: 1,
32            spaceBetween: 20, // Margine tra slide su mobile
33            
34            // Centra le slide nel container
35            centerInsufficientSlides: true,
36            
37            // Velocità di transizione per effetto bounce (più lenta)
38            speed: 1200,
39            
40            // Effetto di transizione
41            effect: 'slide',
42            
43            // Easing per effetto bounce (cubic-bezier simula un overshoot/bounce)
44            // Questo crea un effetto dove le slide "rimbalzano" leggermente oltre la posizione finale
45            cssMode: false,
46            
47            // Breakpoints responsive
48            breakpoints: {
49                // Mobile (<768px): 1 card (default sopra)
50                
51                // Tablet (>= 768px): 2 card
52                768: {
53                    slidesPerView: 2,
54                    spaceBetween: 20,
55                },
56                // Desktop (>= 1024px): manteniamo sempre layout a 3 card,
57                // anche se i corsi sono <= 3, così le card hanno sempre la stessa dimensione.
58                1024: {
59                    slidesPerView: 3,
60                    spaceBetween: -60,
61                    centeredSlides: true,
62                },
63            },
64            
65            // Navigazione con frecce:
66            // - attiva normalmente
67            // - ma se siamo in modalità statica desktop, verrà disabilitata via CSS/JS
68            navigation: desktopStatic ? {} : {
69                nextEl: '.three-card-carousel .carousel-nav-next',
70                prevEl: '.three-card-carousel .carousel-nav-prev',
71            },
72            
73            // Paginazione con dots
74            pagination: {
75                el: '.three-card-carousel .carousel-dots-container',
76                clickable: true,
77                bulletClass: 'carousel-dot',
78                bulletActiveClass: 'active',
79                renderBullet: function (index, className) {
80                    return '<button class="' + className + '" data-index="' + index + '" aria-label="Go to slide ' + (index + 1) + '"></button>';
81                },
82            },
83            
84            // Grab cursor
85            grabCursor: !desktopStatic,
86            
87            // Keyboard control (disabilitato in modalità statica desktop)
88            keyboard: {
89                enabled: !desktopStatic,
90                onlyInViewport: true,
91            },
92            // Abilita progress per effetto di distacco (solo elementi interni)
93            watchSlidesProgress: true,
94            
95            // Autoplay opzionale (commentato per default)
96            /*
97            autoplay: {
98                delay: 5000,
99                disableOnInteraction: false,
100                pauseOnMouseEnter: true,
101            },
102            */
103            
104            // Callback quando la slide cambia
105            on: {
106                // Dopo l'inizializzazione
107                init: function() {
108                    updateSlideStates(this);
109                    
110                    // Se siamo in modalità statica desktop, disabilita interazioni e UI di navigazione
111                    if (desktopStatic) {
112                        const root = carouselElement.closest('.three-card-carousel');
113                        if (root) {
114                            root.classList.add('three-card-carousel--static-desktop');
115                            if (desktopStaticTwo) {
116                                root.classList.add('three-card-carousel--static-desktop-two');
117                            }
118                        }
119                        // Disabilita drag
120                        this.allowTouchMove = false;
121
122                        // Se abbiamo esattamente 3 slide, forziamo la card centrale come attiva
123                        if (desktopStaticThree && slidesCount === 3) {
124                            this.slideTo(1, 0); // indice centrale
125                        }
126                    }
127                },
128
129                // Durante lo slide aggiorna lo "stacco" sulle slide che escono
130                setTranslate: function() {
131                    applyDetachInner(this);
132                },
133
134                // Dopo ogni cambio slide
135                slideChangeTransitionEnd: function() {
136                    updateSlideStates(this);
137                },
138                transitionStart: function(){
139                    const wrapper = this.wrapperEl;
140                    if (wrapper) {
141                        // Overshoot per bounce (più rapido)
142                        wrapper.style.transitionTimingFunction = 'cubic-bezier(0.34, 1.56, 0.64, 1)';
143                    }
144                },
145                transitionEnd: function(){
146                    const wrapper = this.wrapperEl;
147                    if (wrapper) {
148                        wrapper.style.transitionTimingFunction = '';
149                    }
150                },
151                slideChange: function(){
152                    // assicura immediata riassegnazione durante cambio indice
153                    applyDetachInner(this);
154                },
155                afterInit: function(){
156                    // imposta correttamente al primo load
157                    applyDetachInner(this);
158                }
159            },
160        });
161
162        // Funzione per aggiornare gli stati delle slide (opacità e scala)
163        function updateSlideStates(swiper) {
164            const slides = swiper.slides;
165            
166            slides.forEach((slide, index) => {
167                // Rimuovi tutte le classi di stato
168                slide.classList.remove('slide-active', 'slide-prev', 'slide-next');
169                
170                // La slide attiva è quella centrale
171                if (slide.classList.contains('swiper-slide-active')) {
172                    slide.classList.add('slide-active');
173                }
174                // Slide precedente
175                else if (slide.classList.contains('swiper-slide-prev')) {
176                    slide.classList.add('slide-prev');
177                }
178                // Slide successiva
179                else if (slide.classList.contains('swiper-slide-next')) {
180                    slide.classList.add('slide-next');
181                }
182            });
183        }
184
185        // Effetto di distacco SOLO sugli elementi interni (non sulla slide intera)
186        function applyDetachInner(swiper) {
187            const slides = swiper.slides;
188            const isMobile = window.innerWidth < 1024;
189
190            slides.forEach((slide) => {
191                const p = slide.progress || 0; // -2 .. 2
192                const ap = Math.min(2, Math.abs(p));
193
194                const content = slide.querySelector('.card-item-inner');
195                const bg = slide.querySelector('.card_bg_rotate');
196
197                if (isMobile) {
198                    // MOBILE: Solo rotate ridotto (1deg), no translateY, no scale
199                    if (bg) {
200                        const angle = ap < 0.5 ? -1 : 1; // 1deg invece di 4deg
201                        bg.style.transform = `rotate(${angle}deg)`;
202                    }
203                    if (content) {
204                        content.style.transform = 'none'; // Nessun transform
205                    }
206                } else {
207                    // DESKTOP: Comportamento originale
208                    // Offset progressivo: 0 -> 0px (centro), 1 -> 12px (prev/next), 2 -> 20px (fuori)
209                    const offset = ap <= 1 ? (ap * 12) : (12 + (8 * (ap - 1)));
210
211                    if (content) {
212                        content.style.transform = `translateY(${offset}px)`;
213                    }
214                    if (bg) {
215                        // Vicino al centro: -4deg; man mano che si allontana: 4deg
216                        const angle = ap < 0.5 ? -4 : 4;
217                        bg.style.transform = `rotate(${angle}deg) translateY(${Math.round(offset * 1.2)}px)`;
218                    }
219                }
220            });
221        }
222
223        // Esponi l'istanza Swiper globalmente se necessario
224        window.threeCardSwiper = threeCardSwiper;
225    });
226
227})();
228

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.