// Initialize animations and interactions document.addEventListener('DOMContentLoaded', function() { // Reveal animations on scroll const reveals = document.querySelectorAll('.reveal'); function checkReveal() { reveals.forEach(element => { const windowHeight = window.innerHeight; const elementTop = element.getBoundingClientRect().top; const elementVisible = 150; if (elementTop < windowHeight - elementVisible) { element.classList.add('active'); } }); } window.addEventListener('scroll', checkReveal); checkReveal(); // Smooth scroll for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function(e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); // Parallax effect const parallaxElements = document.querySelectorAll('.parallax'); window.addEventListener('scroll', () => { const scrolled = window.pageYOffset; parallaxElements.forEach(element => { const speed = element.dataset.speed || 0.5; element.style.transform = `translateY(${scrolled * speed}px)`; }); }); // Counter animation const counters = document.querySelectorAll('[data-counter]'); const speed = 200; const countUp = () => { counters.forEach(counter => { const updateCount = () => { const target = +counter.getAttribute('data-counter'); const count = +counter.innerText; const inc = target / speed; if (count < target) { counter.innerText = Math.ceil(count + inc); setTimeout(updateCount, 1); } else { counter.innerText = target; } }; updateCount(); }); }; // Trigger counter animation when in view const observerOptions = { threshold: 0.5 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { countUp(); observer.unobserve(entry.target); } }); }, observerOptions); counters.forEach(counter => { observer.observe(counter); }); // Interactive hover effects const cards = document.querySelectorAll('.card-hover'); cards.forEach(card => { card.addEventListener('mousemove', (e) => { const rect = card.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const centerX = rect.width / 2; const centerY = rect.height / 2; const rotateX = (y - centerY) / 10; const rotateY = (centerX - x) / 10; card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.05, 1.05, 1.05)`; }); card.addEventListener('mouseleave', () => { card.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)'; }); }); // Form validation const forms = document.querySelectorAll('form'); forms.forEach(form => { form.addEventListener('submit', (e) => { e.preventDefault(); const formData = new FormData(form); const data = Object.fromEntries(formData); // Basic validation let isValid = true; const requiredFields = form.querySelectorAll('[required]'); requiredFields.forEach(field => { if (!field.value.trim()) { field.classList.add('border-red-500'); isValid = false; } else { field.classList.remove('border-red-500'); } }); if (isValid) { // Show success message const successMessage = document.createElement('div'); successMessage.className = 'fixed top-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50'; successMessage.textContent = 'Form submitted successfully!'; document.body.appendChild(successMessage); setTimeout(() => { successMessage.remove(); }, 3000); form.reset(); } }); }); // Dynamic year in footer const yearElements = document.querySelectorAll('[data-year]'); const currentYear = new Date().getFullYear(); yearElements.forEach(element => { element.textContent = currentYear; }); // Theme switcher const themeToggle = document.querySelector('[data-theme-toggle]'); if (themeToggle) { themeToggle.addEventListener('click', () => { document.body.classList.toggle('dark'); const isDark = document.body.classList.contains('dark'); localStorage.setItem('theme', isDark ? 'dark' : 'light'); }); // Load saved theme const savedTheme = localStorage.getItem('theme'); if (savedTheme === 'dark') { document.body.classList.add('dark'); } } }); // Utility functions const utils = { debounce: (func, wait) => { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }, throttle: (func, limit) => { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }, animateValue: (element, start, end, duration) => { let startTimestamp = null; const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); element.textContent = Math.floor(progress * (end - start) + start); if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); } }; // Export utilities for use in components window.utils = utils;