// HarborSmith - Main JavaScript // ======================== // Theme Management const themeManager = { init() { this.themeToggle = document.getElementById('themeToggle'); this.themeDropdown = document.getElementById('themeDropdown'); this.themeOptions = document.querySelectorAll('.theme-option'); // Load saved theme or default to nautical const savedTheme = localStorage.getItem('harborsmith-theme') || 'nautical'; this.setTheme(savedTheme); // Event listeners this.themeToggle?.addEventListener('click', (e) => { e.stopPropagation(); this.themeDropdown.classList.toggle('active'); }); this.themeOptions.forEach(option => { option.addEventListener('click', (e) => { const theme = e.currentTarget.dataset.theme; this.setTheme(theme); this.themeDropdown.classList.remove('active'); }); }); // Close dropdown when clicking outside document.addEventListener('click', () => { this.themeDropdown?.classList.remove('active'); }); }, setTheme(theme) { document.documentElement.setAttribute('data-theme', theme); localStorage.setItem('harborsmith-theme', theme); // Update active state this.themeOptions.forEach(option => { option.classList.toggle('active', option.dataset.theme === theme); }); } }; // Navigation const navigation = { init() { this.navbar = document.getElementById('navbar'); this.navToggle = document.getElementById('navToggle'); this.navMenu = document.getElementById('navMenu'); this.navLinks = document.querySelectorAll('.nav-link'); // Mobile menu toggle this.navToggle?.addEventListener('click', () => { this.navToggle.classList.toggle('active'); this.navMenu.classList.toggle('active'); }); // Close mobile menu on link click this.navLinks.forEach(link => { link.addEventListener('click', () => { this.navToggle?.classList.remove('active'); this.navMenu?.classList.remove('active'); }); }); // Scroll behavior window.addEventListener('scroll', () => { if (window.scrollY > 50) { this.navbar?.classList.add('scrolled'); } else { this.navbar?.classList.remove('scrolled'); } }); // Active link highlighting this.updateActiveLink(); }, updateActiveLink() { const currentPath = window.location.pathname.split('/').pop() || 'index.html'; this.navLinks.forEach(link => { const href = link.getAttribute('href'); if (href === currentPath) { link.classList.add('active'); } }); } }; // Smooth Scrolling const smoothScroll = { init() { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', (e) => { e.preventDefault(); const target = document.querySelector(anchor.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); } }; // Testimonial Slider const testimonialSlider = { init() { this.cards = document.querySelectorAll('.testimonial-card'); this.dots = document.querySelectorAll('.dot'); this.currentIndex = 0; if (this.cards.length === 0) return; // Auto-play this.startAutoPlay(); // Dot navigation this.dots.forEach((dot, index) => { dot.addEventListener('click', () => { this.goToSlide(index); this.resetAutoPlay(); }); }); }, goToSlide(index) { this.cards[this.currentIndex]?.classList.remove('active'); this.dots[this.currentIndex]?.classList.remove('active'); this.currentIndex = index; this.cards[this.currentIndex]?.classList.add('active'); this.dots[this.currentIndex]?.classList.add('active'); }, nextSlide() { const nextIndex = (this.currentIndex + 1) % this.cards.length; this.goToSlide(nextIndex); }, startAutoPlay() { this.autoPlayInterval = setInterval(() => { this.nextSlide(); }, 5000); }, resetAutoPlay() { clearInterval(this.autoPlayInterval); this.startAutoPlay(); } }; // Counter Animation const counterAnimation = { init() { this.counters = document.querySelectorAll('.stat-number'); this.animated = false; if (this.counters.length === 0) return; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && !this.animated) { this.animateCounters(); this.animated = true; } }); }, { threshold: 0.5 }); const statsSection = document.querySelector('.stats-section'); if (statsSection) { observer.observe(statsSection); } }, animateCounters() { this.counters.forEach(counter => { const target = parseInt(counter.dataset.count); const duration = 2000; const increment = target / (duration / 16); let current = 0; const updateCounter = () => { current += increment; if (current < target) { counter.textContent = Math.floor(current); requestAnimationFrame(updateCounter); } else { counter.textContent = target; } }; updateCounter(); }); } }; // Form Validation const formValidation = { init() { const forms = document.querySelectorAll('form'); forms.forEach(form => { form.addEventListener('submit', (e) => { if (!this.validateForm(form)) { e.preventDefault(); } }); // Real-time validation const inputs = form.querySelectorAll('input, textarea, select'); inputs.forEach(input => { input.addEventListener('blur', () => { this.validateField(input); }); }); }); }, validateForm(form) { const inputs = form.querySelectorAll('[required]'); let isValid = true; inputs.forEach(input => { if (!this.validateField(input)) { isValid = false; } }); return isValid; }, validateField(field) { const value = field.value.trim(); const type = field.type; let isValid = true; // Remove previous error field.classList.remove('error'); const errorMsg = field.parentElement.querySelector('.error-message'); if (errorMsg) { errorMsg.remove(); } // Required field if (field.hasAttribute('required') && !value) { this.showError(field, 'This field is required'); return false; } // Email validation if (type === 'email' && value) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(value)) { this.showError(field, 'Please enter a valid email address'); return false; } } // Phone validation if (type === 'tel' && value) { const phoneRegex = /^[\d\s\-\+\(\)]+$/; if (!phoneRegex.test(value)) { this.showError(field, 'Please enter a valid phone number'); return false; } } return isValid; }, showError(field, message) { field.classList.add('error'); const errorElement = document.createElement('div'); errorElement.className = 'error-message'; errorElement.textContent = message; field.parentElement.appendChild(errorElement); } }; // Yacht Quick View Modal const yachtModal = { init() { const viewButtons = document.querySelectorAll('.yacht-view-btn'); viewButtons.forEach(btn => { btn.addEventListener('click', (e) => { e.preventDefault(); this.openModal(); }); }); }, openModal() { // For now, just alert - in production, would open a modal alert('Quick view modal would open here with yacht details and 360° view'); } }; // Parallax Effects const parallaxEffects = { init() { this.elements = document.querySelectorAll('.parallax'); if (this.elements.length === 0) return; window.addEventListener('scroll', () => { this.updateParallax(); }); }, updateParallax() { const scrolled = window.pageYOffset; this.elements.forEach(element => { const rate = element.dataset.rate || 0.5; const yPos = -(scrolled * rate); element.style.transform = `translateY(${yPos}px)`; }); } }; // Initialize everything when DOM is ready document.addEventListener('DOMContentLoaded', () => { themeManager.init(); navigation.init(); smoothScroll.init(); testimonialSlider.init(); counterAnimation.init(); formValidation.init(); yachtModal.init(); parallaxEffects.init(); // Log successful initialization console.log('HarborSmith website initialized successfully!'); });