templates/home/components/_popup.html.twig line 1

Open in your IDE?
  1. <template id="popup-template">
        <div class="c-popup" aria-hidden="true">
            <div class="c-popup__overlay"></div>
    
            <div class="c-popup__box">
                <button class="c-popup__close" data-action="close">×</button>
    
                <h2 class="c-popup__title"></h2>
    
                <div class="c-popup__content"></div>
    
                <label class="c-popup__remember hidden">
                    <input type="checkbox">
                    No volver a mostrar
                </label>
    
                <div class="c-popup__actions">
                    <button class="btn-g borde c-btn--cancel" data-action="cancel"></button>
                    <button class="btn-g borde c-btn--confirm" data-action="confirm"></button>
                </div>
            </div>
        </div>
    </template>
    
    <script src="https://cdn.jsdelivr.net/npm/swiper/swiper-bundle.min.js"></script>
    
    
    <script>
        /* =====================================================
        POPUP GENÉRICO REUTILIZABLE
        ===================================================== */
        class Popup {
            constructor(options = {}) {
                this.options = options;
    
                // Evitar mostrar si está recordado
                if (options.rememberKey && localStorage.getItem(options.rememberKey)) {
                    return;
                }
    
                this.template = document.getElementById('popup-template');
                if (!this.template) {
                    console.error('Popup template no encontrado');
                    return;
                }
    
                this.popup = this.template.content.firstElementChild.cloneNode(true);
    
                this.cache();
                this.bind();
                this.render();
            }
    
            /* -----------------------------
            Cachear elementos
            ------------------------------ */
            cache() {
                this.overlay = this.popup.querySelector('.c-popup__overlay');
                this.titleEl = this.popup.querySelector('.c-popup__title');
                this.contentEl = this.popup.querySelector('.c-popup__content');
                this.btnConfirm = this.popup.querySelector('[data-action="confirm"]');
                this.btnCancel = this.popup.querySelector('[data-action="cancel"]');
                this.btnClose = this.popup.querySelector('[data-action="close"]');
                this.rememberWrap = this.popup.querySelector('.c-popup__remember');
                this.rememberInput = this.rememberWrap.querySelector('input');
            }
    
            /* -----------------------------
            Eventos
            ------------------------------ */
            bind() {
                this.overlay.addEventListener('click', () => this.close());
                this.btnClose.addEventListener('click', () => this.close());
    
                this.btnConfirm.addEventListener('click', () => this.confirm());
                this.btnCancel.addEventListener('click', () => this.cancel());
    
                document.addEventListener('keydown', this.handleEsc);
            }
    
            handleEsc = (e) => {
                if (e.key === 'Escape') {
                    this.close();
                }
            }
    
            /* -----------------------------
            Render
            ------------------------------ */
            render() {
                const o = this.options;
    
                this.titleEl.textContent = o.title || '';
    
                this.contentEl.innerHTML = this.buildContent(o);
    
                /*this.btnConfirm.textContent = o.confirmText || 'Continuar';
    
                this.btnCancel.textContent = o.cancelText || 'Cancelar';*/
    
                const actionsWrap = this.popup.querySelector('.c-popup__actions');
    
                console.log('actionsWrap', actionsWrap);
    
                /* -------- CONFIRM -------- */
                if (o.confirmText) {
                    this.btnConfirm.textContent = o.confirmText;
                    this.btnConfirm.classList.remove('hidden');
                } else {
                    this.btnConfirm.classList.add('hidden');
                }
    
                /* -------- CANCEL -------- */
                if (o.cancelText) {
                    this.btnCancel.textContent = o.cancelText;
                    this.btnCancel.classList.remove('hidden');    
                } else {
                    this.btnCancel.classList.add('hidden');
                }
    
                /* -------- CONTENEDOR -------- */
                const hasAnyAction = !!(o.confirmText || o.cancelText);
                actionsWrap.classList.toggle('hidden', !hasAnyAction);
    
    
    
                this.rememberWrap.classList.toggle('hidden', !o.rememberKey);
    
                document.body.appendChild(this.popup);
    
                requestAnimationFrame(() => {
                    this.popup.classList.add('is-open');
    
                    if (o.type === 'gallery') {
                        // Espera un frame más para que el layout exista
                        console.log('llama swiper');
                        requestAnimationFrame(() => {
                            this.initGallerySwiper();
                        });
                    }
                });
            }
    
            /* -----------------------------
            Contenido dinámico
            ------------------------------ */
            buildContent(o) {
                switch (o.type) {
                    case 'image':
                        return `<img src="${o.src}" alt="">`;
    
                   case 'gallery':
                        return `
                            <div class="gallery-content">
                                <div class="swiper-gallery-property swiper">
                                    <div class="swiper-wrapper">
                                        ${o.images.map(src => `
                                        <div class="swiper-slide">
                                            <div class="swiper-wp">
                                                <img src="${src}"/>
                                            </div>    
                                        </div>`).join('')}
                                    </div>
                                </div>
                            </div>
                            <div class="gallery-content-thumbnails">
                                <div thumbsSlider="" class="swiper swiper-thumbs-gallery-detail-property">
                                    <div class="swiper-wrapper">
                                        ${o.images.map(src => `
                                        <div class="swiper-slide">
                                            <div class="gallery-content-thumbnails-item">
                                                <img src="${src}"/>
                                            </div>
                                        </div>`).join('')}
                                    </div>
                                </div>
                            </div>
                        `;
    
                    case 'video':
                        return `
                            <video controls>
                                <source src="${o.src}">
                            </video>
                        `;
    
                    case 'html':
                        return o.html;
    
                    case 'message':
                    default:
                        return `<p>${o.message || ''}</p>`;
                }
            }
    
            /* -----------------------------
            Acciones
            ------------------------------ */
            confirm() {
                if (this.rememberInput.checked && this.options.rememberKey) {
                    localStorage.setItem(this.options.rememberKey, '1');
                }
    
                this.options.onConfirm?.();
                this.close();
            }
    
            cancel() {
                this.options.onCancel?.();
                this.close();
            }
    
            close() {
                this.popup.classList.remove('is-open');
    
                document.removeEventListener('keydown', this.handleEsc);
    
                if (this.mainSwiper) {
                    this.mainSwiper.destroy(true, true);
                }
    
                this.popup.addEventListener('transitionend', () => {
                    this.popup.remove();
                }, { once: true });
            }
    
            initGallerySwiper() {
                
                const mainEl = this.popup.querySelector('.swiper-gallery-property');
                const thumbsEl = this.popup.querySelector('.swiper-thumbs-gallery-detail-property');
    
                console.log('swiper', mainEl);
    
                if (!mainEl || !thumbsEl || typeof Swiper === 'undefined') return;
    
    
    
                const thumbsSwiper = new Swiper(thumbsEl, {
                    slidesPerView: 5,
                    spaceBetween: 5,
                    watchSlidesProgress: true,
                    freeMode: true,
                });
    
                this.mainSwiper = new Swiper(mainEl, {
                    spaceBetween: 10,
                    slidesPerView: 1,
                    thumbs: {
                        swiper: thumbsSwiper,
                    },
                });
            }
    
        }
    
    
        
    
        /* =====================================================
        LISTENER GLOBAL PARA BOTONES
        ===================================================== */
        document.addEventListener('click', function (e) {
            const btn = e.target.closest('.call-popup');
            if (!btn) return;
    
            e.preventDefault();
    
            const type = btn.dataset.type;
            if (!type) return;
    
            const options = {
                type,
                title: btn.dataset.title || '',
                confirmText: btn.dataset.confirmText || null,
                cancelText: btn.dataset.cancelText || null,
                rememberKey: btn.dataset.remember || null
            };
    
            /* ---------- GALERÍA ---------- */
            if (type === 'gallery') {
                const galleryId = btn.dataset.gallery;
                const galleryEl = document.getElementById(galleryId);
    
                if (!galleryEl) return;
    
                options.images = [...galleryEl.querySelectorAll('img')]
                    .map(img => img.src);
            }
    
            /* ---------- IMAGEN ---------- */
            if (type === 'image') {
                options.src = btn.dataset.src;
            }
    
            /* ---------- VIDEO ---------- */
            if (type === 'video') {
                options.src = btn.dataset.src;
            }
    
            /* ---------- HTML ---------- */
            if (type === 'html') {
                const htmlId = btn.dataset.html;
                const htmlEl = document.getElementById(htmlId);
                options.html = htmlEl ? htmlEl.innerHTML : '';
            }
    
            /* ---------- MENSAJE ---------- */
            if (type === 'message') {
                options.message = btn.dataset.message || '';
            }
    
            new Popup(options);
        });
    
    
        
    
    
    </script>