PageSourceSearch

https://www.ciudaddelaluz.com/components/Carousel.js

js ciudaddelaluz.com collected 2026-09-25 00:46:30 UTC 5,602 bytes, 126 lines download raw bytes

1// services/Carousel.js
2import { i18n } from "../services/I18nService.js";
3import { mediaService } from "../services/MediaService.js";
4
5export function initCarousel(gallery) {
6    const track = document.querySelector('.carousel-track');
7    const container = document.querySelector('.carousel-container');
8    const nextBtn = document.querySelector('.carousel-next');
9    const prevBtn = document.querySelector('.carousel-prev');
10    const popupModal = document.getElementById('image-popup-modal');
11    const popupImg = document.getElementById('popup-image-content');
12    const popupCloseBtn = document.querySelector('[data-modal-close]');
13    
14    let currentIndex = 0;
15    let autoPlayInterval;
16    const slidesCount = (gallery?.length || 0);
17
18    const goToSlide = (index) => {
19        if (!track || !container) return;
20        const width = container.offsetWidth;
21        track.style.transform = `translateX(-${width * index}px)`;
22        currentIndex = index;
23    };
24
25    const startAutoPlay = () => {
26        stopAutoPlay();
27        autoPlayInterval = setInterval(() => {
28            let nextIndex = (currentIndex + 1) % slidesCount;
29            goToSlide(nextIndex);
30        }, 10000); 
31    };
32
33    const stopAutoPlay = () => {
34        if (autoPlayInterval) clearInterval(autoPlayInterval);
35    };
36
37    startAutoPlay();
38
39    if (nextBtn) {
40        nextBtn.addEventListener('click', (e) => {
41            e.stopPropagation();
42            let nextIndex = (currentIndex + 1) % slidesCount;
43            goToSlide(nextIndex);
44            startAutoPlay(); 
45        });
46    }
47
48    if (prevBtn) {
49        prevBtn.addEventListener('click', (e) => {
50            e.stopPropagation();
51            let prevIndex = (currentIndex - 1 + slidesCount) % slidesCount;
52            goToSlide(prevIndex);
53            startAutoPlay();
54        });
55    }
56
57    // Evento para abrir Popup
58    const setupPopupTrigger = (imgElement) => {
59        imgElement.style.cursor = 'zoom-in';
60        imgElement.addEventListener('click', () => {
61            // Usamos la URL original (sin formato) para el popup
62            const originalUrl = imgElement.dataset.originalUrl || imgElement.src;
63            popupImg.src = originalUrl;
64            popupModal.classList.remove('hidden');
65            stopAutoPlay();
66        });
67    };
68
69    if (popupCloseBtn) {
70        popupCloseBtn.addEventListener('click', () => {
71            popupModal.classList.add('hidden');
72            startAutoPlay();
73        });
74    }
75    
76    if(popupModal){
77            popupModal.addEventListener('click', (e) => {
78            if(e.target === popupModal) {
79                popupModal.classList.add('hidden');
80                startAutoPlay();
81            }
82        });
83    }
84
85    document.querySelectorAll('.carousel-slide img').forEach(setupPopupTrigger);
86}
87
88export function renderCarousel(gallery) {
89    gallery = gallery.url ? gallery.url : gallery;
90
91    return `<div class="carousel-container relative w-full !p-0 !m-0 aspect-video rounded-[2.5rem] overflow-hidden shadow-2xl cinematic-shadow border-4 border-white group bg-slate-200">
92        <div class="carousel-track flex h-full w-full transition-transform duration-500 ease-out">
93            ${gallery?.map(img => `
94                <div class="carousel-slide min-w-full h-full flex-shrink-0 flex flex-col">
95                    <img src="${mediaService.getImageUrl(img, 'large')}" class="w-full h-full object-cover object-center rounded-[2.5rem]" data-orientation-fit="auto" alt="Vista de Galería">
96                    <div class="absolute ${img.caption ? '' : 'hidden'} w-max max-w-[400px] rounded-[2.5rem] bottom-0 bg-neutral-600/70 text-white m-3 p-4 flex items-center gap-3 justify-start">
97                        <p class="font-bold text-lg">
98                            ${img.caption || ''}
99                        </p>
100                    </div>
101                </div>
102            `).join('') || ''}
103        </div>
104        
105        <button class="carousel-prev ${gallery.length > 1 ? '' : 'hidden'} absolute left-4 top-1/2 -translate-y-1/2 w-12 h-12 bg-white/30 backdrop-blur-md rounded-full flex items-center justify-center text-white border border-white/50 opacity-0 group-hover:opacity-100 transition-all hover:bg-white/50 hover:scale-110 shadow-lg z-10">
106            <i data-lucide="chevron-left" class="w-6 h-6"></i>
107        </button>
108        <button class="carousel-next ${gallery.length > 1 ? '' : 'hidden'} absolute right-4 top-1/2 -translate-y-1/2 w-12 h-12 bg-white/30 backdrop-blur-md rounded-full flex items-center justify-center text-white border border-white/50 opacity-0 group-hover:opacity-100 transition-all hover:bg-white/50 hover:scale-110 shadow-lg z-10">
109            <i data-lucide="chevron-right" class="w-6 h-6"></i>
110        </button>
111    </div>
112    `
113}
114
115export function renderPopup() {
116    const t = (key) => i18n.t(key);
117    
118    return `<div id="image-popup-modal" class="modal-overlay hidden fixed inset-0 z-[100] flex items-center justify-center bg-slate-900/95 backdrop-blur-xl p-4">
119            <div class="relative max-w-6xl w-full flex flex-col items-end">
120                <button data-modal-close class="text-white hover:text-cdl-gold transition-colors flex items-center gap-2 font-black uppercase text-xs tracking-widest mb-6">
121                    <span>${t('plato_detail.image_close') || 'Cerrar'}</span> <i data-lucide="x" class="w-6 h-6"></i>
122                </button>
123                <img id="popup-image-content" src="" class="w-full h-auto max-h-[80vh] object-contain rounded-2xl shadow-2xl border border-white/10">
124            </div>
125        </div>`
126}

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.