1/** 2 * categories.js â Carrossel de categorias 3 * Funcionalidades: 4 * - Setas prev/next (translateX no track) com wrap circular 5 * - Swipe mobile 6 * - Dimensões cacheadas (recalcula só no resize) 7 */ 8 9document.addEventListener('DOMContentLoaded', () => { 10 11 const section = document.querySelector('.categories-section'); 12 if (!section) return; 13 14 // âââ Elementos ââââââââââââââââââââââââââââââââââââââââââââââââ 15 const wrapper = section.querySelector('.categories-section__wrapper'); 16 const track = section.querySelector('.categories-section__track'); 17 const btnPrev = section.querySelector('.categories-section__arrow--prev'); 18 const btnNext = section.querySelector('.categories-section__arrow--next'); 19 20 if (!track || !wrapper) return; 21 22 const items = [...track.children]; 23 if (!items.length) return; 24 25 // âââ Estado âââââââââââââââââââââââââââââââââââââââââââââââââââ 26 let currentOffset = 0; 27 let cachedStep = 0; 28 let cachedMaxOffset = 0; 29 30 // âââ Cachear dimensões (evita reflow a cada interação) âââââââ 31 function cacheDimensions() { 32 const gap = parseFloat(window.getComputedStyle(track).gap) || 0; 33 cachedStep = items[0].offsetWidth + gap; 34 cachedMaxOffset = Math.max(0, track.scrollWidth - wrapper.offsetWidth); 35 } 36 37 cacheDimensions(); 38 39 // âââ Mover para offset ââââââââââââââââââââââââââââââââââââââââ 40 function goToOffset(offset) { 41 currentOffset = Math.max(0, Math.min(offset, cachedMaxOffset)); 42 track.style.transform = `translate3d(-${currentOffset}px, 0, 0)`; 43 } 44 45 // âââ Setas (com wrap: primeiroâúltimo, últimoâprimeiro) ââââââ 46 btnPrev?.addEventListener('click', () => { 47 if (currentOffset <= 0) { 48 goToOffset(cachedMaxOffset); 49 } else { 50 goToOffset(currentOffset - cachedStep); 51 } 52 }); 53 54 btnNext?.addEventListener('click', () => { 55 if (currentOffset >= cachedMaxOffset) { 56 goToOffset(0); 57 } else { 58 goToOffset(currentOffset + cachedStep); 59 } 60 }); 61 62 // âââ Swipe mobile âââââââââââââââââââââââââââââââââââââââââââââ 63 let touchStartX = 0; 64 const SWIPE_THRESHOLD = 30; 65 66 track.addEventListener('touchstart', (e) => { 67 touchStartX = e.touches[0].clientX; 68 }, { passive: true }); 69 70 track.addEventListener('touchend', (e) => { 71 const diff = touchStartX - e.changedTouches[0].clientX; 72 if (Math.abs(diff) > SWIPE_THRESHOLD) { 73 goToOffset(currentOffset + (diff > 0 ? cachedStep : -cachedStep)); 74 } 75 }, { passive: true }); 76 77 // âââ Resize handler (debounce) ââââââââââââââââââââââââââââââââ 78 let resizeTimer; 79 80 window.addEventListener('resize', () => { 81 clearTimeout(resizeTimer); 82 resizeTimer = setTimeout(() => { 83 cacheDimensions(); 84 goToOffset(Math.min(currentOffset, cachedMaxOffset)); 85 }, 150); 86 }); 87 88 // âââ Inicialização ââââââââââââââââââââââââââââââââââââââââââââ 89 goToOffset(0); 90 91});
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.