Spaces:
Running
Running
| /* Slide Deck 16:9 Controller */ | |
| (function () { | |
| const container = document.getElementById('slideContainer'); | |
| const slides = Array.from(container.querySelectorAll('.slide')); | |
| const prevBtn = document.getElementById('prevBtn'); | |
| const nextBtn = document.getElementById('nextBtn'); | |
| const dotsWrap = document.getElementById('dots'); | |
| const progressBar = document.getElementById('progressBar'); | |
| const themeToggle = document.getElementById('themeToggle'); | |
| const fullscreenBtn = document.getElementById('fullscreenBtn'); | |
| const replayBtn = document.getElementById('replayBtn'); | |
| const copyBtn = document.getElementById('copyCode'); | |
| const codeSample = document.getElementById('codeSample'); | |
| const state = { | |
| index: 0, | |
| total: slides.length | |
| }; | |
| // Build dots | |
| slides.forEach((_, i) => { | |
| const dot = document.createElement('button'); | |
| dot.className = 'dot' + (i === 0 ? ' is-active' : ''); | |
| dot.setAttribute('role', 'tab'); | |
| dot.setAttribute('aria-label', `Ir para slide ${i + 1}`); | |
| dot.addEventListener('click', () => goTo(i)); | |
| dotsWrap.appendChild(dot); | |
| }); | |
| const dots = Array.from(dotsWrap.querySelectorAll('.dot')); | |
| function updateUI() { | |
| slides.forEach((s, i) => s.classList.toggle('is-active', i === state.index)); | |
| dots.forEach((d, i) => d.classList.toggle('is-active', i === state.index)); | |
| prevBtn.disabled = state.index === 0; | |
| nextBtn.disabled = state.index === state.total - 1; | |
| progressBar.style.width = `${((state.index + 1) / state.total) * 100}%`; | |
| // Announce for a11y | |
| const activeSlide = slides[state.index]; | |
| activeSlide?.setAttribute('aria-label', `Slide ${state.index + 1} de ${state.total}`); | |
| } | |
| function next() { | |
| if (state.index < state.total - 1) { | |
| state.index++; | |
| updateUI(); | |
| } | |
| } | |
| function prev() { | |
| if (state.index > 0) { | |
| state.index--; | |
| updateUI(); | |
| } | |
| } | |
| function goTo(i) { | |
| state.index = Math.max(0, Math.min(state.total - 1, i)); | |
| updateUI(); | |
| } | |
| // Events | |
| nextBtn.addEventListener('click', next); | |
| prevBtn.addEventListener('click', prev); | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === 'ArrowRight' || e.key === 'PageDown') { | |
| e.preventDefault(); | |
| next(); | |
| } else if (e.key === 'ArrowLeft' || e.key === 'PageUp') { | |
| e.preventDefault(); | |
| prev(); | |
| } else if (e.key === 'Home') { | |
| e.preventDefault(); | |
| goTo(0); | |
| } else if (e.key === 'End') { | |
| e.preventDefault(); | |
| goTo(state.total - 1); | |
| } | |
| }); | |
| // Touch swipe | |
| let touchStartX = null; | |
| container.addEventListener('touchstart', (e) => { | |
| touchStartX = e.changedTouches[0].clientX; | |
| }, { passive: true }); | |
| container.addEventListener('touchend', (e) => { | |
| if (touchStartX === null) return; | |
| const dx = e.changedTouches[0].clientX - touchStartX; | |
| if (Math.abs(dx) > 40) { | |
| dx < 0 ? next() : prev(); | |
| } | |
| touchStartX = null; | |
| }, { passive: true }); | |
| // Theme toggle (undefined mode -> light by default) | |
| themeToggle.addEventListener('click', () => { | |
| const wrapper = document.querySelector('.theme-wrapper'); | |
| wrapper.classList.toggle('dark'); | |
| themeToggle.innerHTML = wrapper.classList.contains('dark') | |
| ? '<i data-feather="moon"></i>' | |
| : '<i data-feather="sun"></i>'; | |
| if (window.feather) feather.replace(); | |
| }); | |
| // Fullscreen | |
| function toggleFullscreen() { | |
| const elem = document.documentElement; | |
| if (!document.fullscreenElement) { | |
| (elem.requestFullscreen || elem.webkitRequestFullscreen || elem.msRequestFullscreen)?.call(elem); | |
| } else { | |
| (document.exitFullscreen || document.webkitExitFullscreen || document.msExitFullscreen)?.call(document); | |
| } | |
| } | |
| fullscreenBtn.addEventListener('click', toggleFullscreen); | |
| document.addEventListener('fullscreenchange', () => { | |
| fullscreenBtn.innerHTML = document.fullscreenElement | |
| ? '<i data-feather="minimize"></i>' | |
| : '<i data-feather="maximize"></i>'; | |
| if (window.feather) feather.replace(); | |
| }); | |
| // Replay / CTA shortcuts | |
| document.getElementById('startSlides')?.addEventListener('click', () => goTo(1)); | |
| document.getElementById('viewSamples')?.addEventListener('click', () => goTo(2)); | |
| document.getElementById('replayBtn')?.addEventListener('click', () => goTo(0)); | |
| document.getElementById('contactBtn')?.addEventListener('click', (e) => { | |
| e.preventDefault(); | |
| alert('Obrigado! Vamos conversarei em breve.'); | |
| }); | |
| // Copy code | |
| copyBtn?.addEventListener('click', async () => { | |
| try { | |
| await navigator.clipboard.writeText(codeSample?.textContent || ''); | |
| copyBtn.innerHTML = '<i data-feather="check"></i>'; | |
| if (window.feather) feather.replace(); | |
| setTimeout(() => { | |
| copyBtn.innerHTML = '<i data-feather="copy"></i>'; | |
| if (window.feather) feather.replace(); | |
| }, 1200); | |
| } catch (_) {} | |
| }); | |
| // Init icons and UI | |
| if (window.feather) feather.replace(); | |
| updateUI(); | |
| })(); |