class PresentationController { constructor() { this.currentSlide = 1; this.totalSlides = 12; 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.isTransitioning = false; this.init(); } init() { // Set total slides this.totalSlidesSpan.textContent = this.totalSlides; // Add event listeners this.prevBtn.addEventListener('click', () => this.previousSlide()); this.nextBtn.addEventListener('click', () => this.nextSlide()); // Keyboard navigation document.addEventListener('keydown', (e) => this.handleKeyboard(e)); // Initialize first slide this.showSlide(1); // Initialize progress bar this.initProgressBar(); console.log('Presentation initialized with', this.totalSlides, 'slides'); } initProgressBar() { // Create and add progress bar const progressBar = document.createElement('div'); progressBar.className = 'progress-bar'; progressBar.innerHTML = '
'; document.body.insertBefore(progressBar, document.body.firstChild); this.progressBar = progressBar; this.updateProgress(); } showSlide(slideNumber) { if (slideNumber < 1 || slideNumber > this.totalSlides || this.isTransitioning) { return; } this.isTransitioning = true; // Hide all slides this.slides.forEach(slide => { slide.classList.remove('active', 'exiting'); slide.style.opacity = '0'; slide.style.visibility = 'hidden'; slide.style.transform = 'translateX(50px)'; }); // Update current slide this.currentSlide = slideNumber; // Show target slide with a small delay to ensure clean transition setTimeout(() => { const targetSlide = document.querySelector(`[data-slide="${slideNumber}"]`); if (targetSlide) { targetSlide.style.visibility = 'visible'; targetSlide.classList.add('active'); // Force a repaint targetSlide.offsetHeight; targetSlide.style.opacity = '1'; targetSlide.style.transform = 'translateX(0)'; } // Update UI elements this.updateButtonStates(); this.updateSlideCounter(); this.updateProgress(); // Allow next transition after animation completes setTimeout(() => { this.isTransitioning = false; }, 450); }, 50); } nextSlide() { if (this.currentSlide < this.totalSlides && !this.isTransitioning) { this.showSlide(this.currentSlide + 1); } } previousSlide() { if (this.currentSlide > 1 && !this.isTransitioning) { this.showSlide(this.currentSlide - 1); } } updateButtonStates() { // Update previous button this.prevBtn.disabled = (this.currentSlide === 1); // Update next button this.nextBtn.disabled = (this.currentSlide === this.totalSlides); } updateSlideCounter() { this.currentSlideSpan.textContent = this.currentSlide; } updateProgress() { if (this.progressBar) { const progressFill = this.progressBar.querySelector('.progress-fill'); const percentage = (this.currentSlide / this.totalSlides) * 100; progressFill.style.width = `${percentage}%`; } } handleKeyboard(e) { // Prevent default behavior for navigation keys if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) { e.preventDefault(); } switch(e.key) { case 'ArrowLeft': this.previousSlide(); break; case 'ArrowRight': this.nextSlide(); break; case 'Home': this.showSlide(1); break; case 'End': this.showSlide(this.totalSlides); break; case 'f': case 'F': this.toggleFullscreen(); break; case 'Escape': this.exitFullscreen(); break; } } toggleFullscreen() { if (!document.fullscreenElement) { document.documentElement.requestFullscreen().catch(err => { console.log(`Error attempting to enable fullscreen: ${err.message}`); }); } else { document.exitFullscreen(); } } exitFullscreen() { if (document.fullscreenElement) { document.exitFullscreen(); } } } // Touch/swipe support for mobile class TouchHandler { constructor(controller) { this.controller = controller; this.touchStartX = 0; this.touchEndX = 0; this.minSwipeDistance = 50; this.init(); } init() { const slidesContainer = document.getElementById('slidesContainer'); slidesContainer.addEventListener('touchstart', (e) => { this.touchStartX = e.changedTouches[0].screenX; }, { passive: true }); slidesContainer.addEventListener('touchend', (e) => { this.touchEndX = e.changedTouches[0].screenX; this.handleSwipe(); }, { passive: true }); } handleSwipe() { const diffX = this.touchStartX - this.touchEndX; if (Math.abs(diffX) > this.minSwipeDistance) { if (diffX > 0) { // Swipe left - next slide this.controller.nextSlide(); } else { // Swipe right - previous slide this.controller.previousSlide(); } } } } // Simple hover effects without problematic animations function addHoverEffects() { const style = document.createElement('style'); style.textContent = ` .tech-card:hover, .company-card:hover, .use-case-card:hover, .challenge-card:hover, .trend-item:hover, .takeaway-card:hover { background: rgba(255, 255, 255, 0.15) !important; cursor: pointer; } `; document.head.appendChild(style); } // Initialize presentation when DOM is loaded document.addEventListener('DOMContentLoaded', function() { // Prevent scrolling and ensure proper viewport document.body.style.overflow = 'hidden'; document.body.style.margin = '0'; document.body.style.padding = '0'; document.documentElement.style.overflow = 'hidden'; // Initialize the presentation controller const presentation = new PresentationController(); // Add touch support new TouchHandler(presentation); // Add simple hover effects addHoverEffects(); // Prevent default scrolling behavior document.addEventListener('wheel', (e) => { e.preventDefault(); }, { passive: false }); // Prevent arrow key scrolling document.addEventListener('keydown', (e) => { if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(e.key)) { e.preventDefault(); } }); // Handle window resize window.addEventListener('resize', () => { // Force a repaint to handle responsive changes const activeSlide = document.querySelector('.slide.active'); if (activeSlide) { activeSlide.style.height = '100%'; } }); console.log('Presentation ready'); }); // Export controller for debugging window.PresentationController = PresentationController;