class PresentationApp { constructor() { this.currentSlide = 1; this.totalSlides = 26; this.isFullscreen = false; this.autoAdvance = false; this.autoAdvanceInterval = null; this.touchStartX = 0; this.touchStartY = 0; this.init(); } init() { this.setupElements(); this.setupEventListeners(); this.updateDisplay(); this.preloadSlides(); } setupElements() { this.slidesContainer = document.getElementById('slidesContainer'); this.slides = document.querySelectorAll('.slide'); this.prevBtn = document.getElementById('prevBtn'); this.nextBtn = document.getElementById('nextBtn'); this.currentSlideSpan = document.getElementById('currentSlide'); this.totalSlidesSpan = document.getElementById('totalSlides'); this.progressFill = document.querySelector('.progress-fill'); this.fullscreenBtn = document.getElementById('fullscreenBtn'); this.overviewBtn = document.getElementById('overviewBtn'); // Update total slides display this.totalSlidesSpan.textContent = this.totalSlides; } setupEventListeners() { // Navigation buttons this.prevBtn.addEventListener('click', () => this.previousSlide()); this.nextBtn.addEventListener('click', () => this.nextSlide()); // Keyboard navigation document.addEventListener('keydown', (e) => { switch(e.key) { case 'ArrowRight': case ' ': case 'PageDown': e.preventDefault(); this.nextSlide(); break; case 'ArrowLeft': case 'PageUp': e.preventDefault(); this.previousSlide(); break; case 'Home': e.preventDefault(); this.goToSlide(1); break; case 'End': e.preventDefault(); this.goToSlide(this.totalSlides); break; case 'Escape': if (this.isFullscreen) { this.exitFullscreen(); } break; case 'f': case 'F': this.toggleFullscreen(); break; } }); // Click to advance this.slidesContainer.addEventListener('click', (e) => { // Don't advance if clicking on interactive elements if (e.target.tagName === 'BUTTON' || e.target.closest('button')) { return; } this.nextSlide(); }); // Touch/swipe support this.slidesContainer.addEventListener('touchstart', (e) => { this.touchStartX = e.touches[0].clientX; this.touchStartY = e.touches[0].clientY; }, { passive: true }); this.slidesContainer.addEventListener('touchend', (e) => { if (!this.touchStartX || !this.touchStartY) return; const touchEndX = e.changedTouches[0].clientX; const touchEndY = e.changedTouches[0].clientY; const deltaX = this.touchStartX - touchEndX; const deltaY = this.touchStartY - touchEndY; // Check if horizontal swipe is more significant than vertical if (Math.abs(deltaX) > Math.abs(deltaY)) { if (Math.abs(deltaX) > 50) { // Minimum swipe distance if (deltaX > 0) { this.nextSlide(); } else { this.previousSlide(); } } } this.touchStartX = 0; this.touchStartY = 0; }, { passive: true }); // Control buttons this.fullscreenBtn.addEventListener('click', () => this.toggleFullscreen()); this.overviewBtn.addEventListener('click', () => this.showOverview()); // Fullscreen change events document.addEventListener('fullscreenchange', () => { this.isFullscreen = !this.isFullscreen; this.updateFullscreenButton(); }); // Prevent context menu on right click document.addEventListener('contextmenu', (e) => { e.preventDefault(); }); // Handle window resize window.addEventListener('resize', () => { this.handleResize(); }); } preloadSlides() { // Add entrance animations to bullet points this.slides.forEach((slide, index) => { const bullets = slide.querySelectorAll('.bullet-list li'); bullets.forEach((bullet, bulletIndex) => { bullet.style.animationDelay = `${(bulletIndex + 1) * 0.1}s`; }); }); } nextSlide() { if (this.currentSlide < this.totalSlides) { this.goToSlide(this.currentSlide + 1); } } previousSlide() { if (this.currentSlide > 1) { this.goToSlide(this.currentSlide - 1); } } goToSlide(slideNumber) { if (slideNumber < 1 || slideNumber > this.totalSlides) return; // Remove active class from current slide const currentSlideElement = document.querySelector('.slide.active'); if (currentSlideElement) { currentSlideElement.classList.remove('active'); currentSlideElement.classList.add('prev'); } // Add active class to new slide const newSlideElement = document.querySelector(`[data-slide="${slideNumber}"]`); if (newSlideElement) { // Remove prev class from all slides this.slides.forEach(slide => slide.classList.remove('prev')); newSlideElement.classList.add('active'); // Trigger entrance animations this.triggerSlideAnimations(newSlideElement); } this.currentSlide = slideNumber; this.updateDisplay(); } triggerSlideAnimations(slideElement) { // Reset and trigger bullet point animations const bullets = slideElement.querySelectorAll('.bullet-list li'); bullets.forEach((bullet, index) => { bullet.style.animation = 'none'; bullet.offsetHeight; // Trigger reflow bullet.style.animation = `fadeInUp 0.6s ease-out ${(index + 1) * 0.1}s both`; }); // Trigger other element animations const animatedElements = slideElement.querySelectorAll('.aspect-card, .transform-item, .mode-card'); animatedElements.forEach((element, index) => { element.style.transform = 'translateY(20px)'; element.style.opacity = '0'; setTimeout(() => { element.style.transition = 'all 0.6s ease-out'; element.style.transform = 'translateY(0)'; element.style.opacity = '1'; }, (index + 1) * 100); }); } updateDisplay() { // Update slide counter this.currentSlideSpan.textContent = this.currentSlide; // Update progress bar const progress = (this.currentSlide / this.totalSlides) * 100; this.progressFill.style.width = `${progress}%`; // Update navigation buttons this.prevBtn.disabled = this.currentSlide === 1; this.nextBtn.disabled = this.currentSlide === this.totalSlides; // Update button opacity based on state this.prevBtn.style.opacity = this.currentSlide === 1 ? '0.5' : '1'; this.nextBtn.style.opacity = this.currentSlide === this.totalSlides ? '0.5' : '1'; } toggleFullscreen() { if (!this.isFullscreen) { this.enterFullscreen(); } else { this.exitFullscreen(); } } enterFullscreen() { const element = document.documentElement; if (element.requestFullscreen) { element.requestFullscreen(); } else if (element.mozRequestFullScreen) { element.mozRequestFullScreen(); } else if (element.webkitRequestFullscreen) { element.webkitRequestFullscreen(); } else if (element.msRequestFullscreen) { element.msRequestFullscreen(); } } exitFullscreen() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } } updateFullscreenButton() { this.fullscreenBtn.textContent = this.isFullscreen ? '⛶' : '⛶'; this.fullscreenBtn.title = this.isFullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'; } showOverview() { // Create overview modal const modal = document.createElement('div'); modal.className = 'overview-modal'; modal.innerHTML = `