| |
| document.addEventListener('DOMContentLoaded', function() { |
| |
| initAnimations(); |
| |
| |
| initForms(); |
| |
| |
| initScrollEffects(); |
| |
| |
| if ('serviceWorker' in navigator) { |
| navigator.serviceWorker.register('/sw.js') |
| .then(() => console.log('Service Worker Registered')) |
| .catch(err => console.log('Service Worker Registration Failed: ', err)); |
| } |
| }); |
|
|
| function initAnimations() { |
| |
| const observerOptions = { |
| threshold: 0.1, |
| rootMargin: '0px 0px -50px 0px' |
| }; |
|
|
| const observer = new IntersectionObserver((entries) => { |
| entries.forEach(entry => { |
| if (entry.isIntersecting) { |
| entry.target.classList.add('animate-fade-in-up'); |
| observer.unobserve(entry.target); |
| } |
| }); |
| }, observerOptions); |
|
|
| |
| document.querySelectorAll('.animate-on-scroll').forEach(el => { |
| observer.observe(el); |
| }); |
| } |
|
|
| function initForms() { |
| |
| const contactForm = document.getElementById('contactForm'); |
| if (contactForm) { |
| contactForm.addEventListener('submit', function(e) { |
| e.preventDefault(); |
| const submitBtn = this.querySelector('button[type="submit"]'); |
| const originalText = submitBtn.textContent; |
| |
| |
| submitBtn.disabled = true; |
| submitBtn.innerHTML = '<div class="loading-spinner"></div> Processing...'; |
| |
| |
| setTimeout(() => { |
| alert('Thank you for your message! I\'ll get back to you soon.'); |
| contactForm.reset(); |
| submitBtn.disabled = false; |
| submitBtn.textContent = originalText; |
| }, 2000); |
| }); |
| } |
| } |
|
|
| function initScrollEffects() { |
| |
| let lastScrollY = window.scrollY; |
| const navbar = document.querySelector('custom-navbar'); |
| |
| window.addEventListener('scroll', () => { |
| if (!navbar) return; |
| |
| const currentScrollY = window.scrollY; |
| |
| if (currentScrollY > lastScrollY && currentScrollY > 100) { |
| navbar.style.transform = 'translateY(-100%)'; |
| } else { |
| navbar.style.transform = 'translateY(0)'; |
| } |
| |
| lastScrollY = currentScrollY; |
| |
| |
| if (currentScrollY > 50) { |
| navbar.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.1)'; |
| } else { |
| navbar.style.boxShadow = 'none'; |
| } |
| }); |
| } |
|
|
| |
| function smoothScrollTo(target) { |
| const element = document.querySelector(target); |
| if (element) { |
| element.scrollIntoView({ |
| behavior: 'smooth', |
| block: 'start' |
| }); |
| } |
| } |
|
|
| |
| function debounce(func, wait) { |
| let timeout; |
| return function executedFunction(...args) { |
| const later = () => { |
| clearTimeout(timeout); |
| func(...args); |
| }; |
| clearTimeout(timeout); |
| timeout = setTimeout(later, wait); |
| }; |
| } |
|
|
| |
| function formatPhoneNumber(phone) { |
| const cleaned = ('' + phone).replace(/\D/g, ''); |
| const match = cleaned.match(/^(\d{3})(\d{3})(\d{4})$/); |
| if (match) { |
| return '(' + match[1] + ') ' + match[2] + '-' + match[3]; |
| } |
| return phone; |
| } |
|
|
| |
| function isValidEmail(email) { |
| const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; |
| return re.test(email); |
| } |