// Main JavaScript file for portfolio website document.addEventListener('DOMContentLoaded', function() { // Initialize all functionality initMobileMenu(); initSmoothScrolling(); initScrollAnimations(); initFormHandling(); initScrollToTop(); initTypingEffect(); }); // Mobile menu functionality function initMobileMenu() { const mobileMenuButton = document.getElementById('mobile-menu-button'); const mobileMenu = document.getElementById('mobile-menu'); if (mobileMenuButton && mobileMenu) { mobileMenuButton.addEventListener('click', function() { mobileMenu.classList.toggle('hidden'); // Toggle menu icon const icon = mobileMenuButton.querySelector('i'); if (mobileMenu.classList.contains('hidden')) { icon.setAttribute('data-feather', 'menu'); } else { icon.setAttribute('data-feather', 'x'); } feather.replace(); }); // Close mobile menu when clicking on a link const mobileLinks = mobileMenu.querySelectorAll('a'); mobileLinks.forEach(link => { link.addEventListener('click', function() { mobileMenu.classList.add('hidden'); const icon = mobileMenuButton.querySelector('i'); icon.setAttribute('data-feather', 'menu'); feather.replace(); }); }); } } // Smooth scrolling for navigation links function initSmoothScrolling() { const navLinks = document.querySelectorAll('a[href^="#"]'); navLinks.forEach(link => { link.addEventListener('click', function(e) { e.preventDefault(); const targetId = this.getAttribute('href'); const targetSection = document.querySelector(targetId); if (targetSection) { const navHeight = document.querySelector('nav').offsetHeight; const targetPosition = targetSection.offsetTop - navHeight; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); } }); }); } // Scroll-triggered animations function initScrollAnimations() { const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('animate-fade-in-up'); entry.target.style.opacity = '1'; } }); }, observerOptions); // Observe elements for animation const animateElements = document.querySelectorAll('.card-hover, .bg-white, section > div'); animateElements.forEach(el => { el.style.opacity = '0'; observer.observe(el); }); // Scroll-based navigation highlight window.addEventListener('scroll', highlightActiveNav); } function highlightActiveNav() { const sections = document.querySelectorAll('section[id]'); const navLinks = document.querySelectorAll('nav a[href^="#"]'); const navHeight = document.querySelector('nav').offsetHeight; let current = ''; sections.forEach(section => { const sectionTop = section.offsetTop - navHeight - 100; const sectionHeight = section.offsetHeight; if (window.pageYOffset >= sectionTop && window.pageYOffset < sectionTop + sectionHeight) { current = section.getAttribute('id'); } }); navLinks.forEach(link => { link.classList.remove('text-primary-600', 'font-semibold'); link.classList.add('text-secondary-600'); if (link.getAttribute('href') === '#' + current) { link.classList.remove('text-secondary-600'); link.classList.add('text-primary-600', 'font-semibold'); } }); } // Form handling function initFormHandling() { const contactForm = document.querySelector('form'); if (contactForm) { contactForm.addEventListener('submit', function(e) { e.preventDefault(); // Get form data const formData = new FormData(this); const formObject = {}; formData.forEach((value, key) => { formObject[key] = value; }); // Show loading state const submitButton = this.querySelector('button[type="submit"]'); const originalText = submitButton.textContent; submitButton.textContent = 'Sending...'; submitButton.disabled = true; // Simulate form submission (replace with actual API call) setTimeout(() => { // Show success message showNotification('Message sent successfully!', 'success'); // Reset form this.reset(); // Reset button submitButton.textContent = originalText; submitButton.disabled = false; }, 2000); }); } } // Notification system function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `fixed top-20 right-4 z-50 px-6 py-3 rounded-lg shadow-lg transform translate-x-full transition-transform duration-300 ${ type === 'success' ? 'bg-green-500 text-white' : type === 'error' ? 'bg-red-500 text-white' : 'bg-blue-500 text-white' }`; notification.textContent = message; document.body.appendChild(notification); // Slide in setTimeout(() => { notification.classList.remove('translate-x-full'); }, 100); // Slide out and remove setTimeout(() => { notification.classList.add('translate-x-full'); setTimeout(() => { document.body.removeChild(notification); }, 300); }, 4000); } // Scroll to top button function initScrollToTop() { // Create scroll to top button const scrollButton = document.createElement('button'); scrollButton.innerHTML = ''; scrollButton.className = 'fixed bottom-6 right-6 w-12 h-12 bg-primary-600 text-white rounded-full shadow-lg hover:bg-primary-700 transition-colors duration-300 opacity-0 transform translate-y-full z-50'; scrollButton.style.display = 'none'; document.body.appendChild(scrollButton); feather.replace(); // Show/hide based on scroll position window.addEventListener('scroll', function() { if (window.pageYOffset > 300) { scrollButton.style.display = 'block'; setTimeout(() => { scrollButton.classList.remove('opacity-0', 'translate-y-full'); }, 10); } else { scrollButton.classList.add('opacity-0', 'translate-y-full'); setTimeout(() => { scrollButton.style.display = 'none'; }, 300); } }); // Scroll to top functionality scrollButton.addEventListener('click', function() { window.scrollTo({ top: 0, behavior: 'smooth' }); }); } // Typing effect for hero section function initTypingEffect() { const heroTitle = document.querySelector('#home h1'); if (heroTitle) { const text = heroTitle.textContent; heroTitle.textContent = ''; heroTitle.style.borderRight = '2px solid white'; let i = 0; const typeWriter = () => { if (i < text.length) { heroTitle.textContent += text.charAt(i); i++; setTimeout(typeWriter, 100); } else { // Remove cursor after typing is complete setTimeout(() => { heroTitle.style.borderRight = 'none'; }, 1000); } }; // Start typing effect after a short delay setTimeout(typeWriter, 1000); } } // Parallax effect for hero section window.addEventListener('scroll', function() { const scrolled = window.pageYOffset; const heroSection = document.querySelector('#home'); if (heroSection) { const rate = scrolled * -0.5; heroSection.style.transform = `translateY(${rate}px)`; } }); // Counter animation function animateCounters() { const counters = document.querySelectorAll('[data-count]'); counters.forEach(counter => { const target = parseInt(counter.getAttribute('data-count')); const increment = target / 100; let current = 0; const timer = setInterval(() => { current += increment; counter.textContent = Math.floor(current); if (current >= target) { counter.textContent = target; clearInterval(timer); } }, 20); }); } // Initialize counter animation when about section is visible const aboutSection = document.querySelector('#about'); if (aboutSection) { const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting) { animateCounters(); observer.unobserve(entry.target); } }); }, { threshold: 0.5 }); observer.observe(aboutSection); } // Portfolio filter functionality (if needed) function initPortfolioFilter() { const filterButtons = document.querySelectorAll('[data-filter]'); const portfolioItems = document.querySelectorAll('[data-category]'); filterButtons.forEach(button => { button.addEventListener('click', function() { const filter = this.getAttribute('data-filter'); // Update active button filterButtons.forEach(btn => btn.classList.remove('active')); this.classList.add('active'); // Filter portfolio items portfolioItems.forEach(item => { if (filter === 'all' || item.getAttribute('data-category') === filter) { item.style.display = 'block'; } else { item.style.display = 'none'; } }); }); }); } // Theme switcher (for future dark mode implementation) function initThemeSwitcher() { const themeToggle = document.getElementById('theme-toggle'); if (themeToggle) { themeToggle.addEventListener('click', function() { document.body.classList.toggle('dark-theme'); // Save theme preference const isDark = document.body.classList.contains('dark-theme'); localStorage.setItem('theme', isDark ? 'dark' : 'light'); // Update toggle icon const icon = this.querySelector('i'); if (isDark) { icon.setAttribute('data-feather', 'sun'); } else { icon.setAttribute('data-feather', 'moon'); } feather.replace(); }); // Load saved theme preference const savedTheme = localStorage.getItem('theme'); if (savedTheme === 'dark') { document.body.classList.add('dark-theme'); } } } // Performance optimization function optimizePerformance() { // Lazy load images const images = document.querySelectorAll('img[data-src]'); const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.remove('lazy'); imageObserver.unobserve(img); } }); }); images.forEach(img => imageObserver.observe(img)); // Debounce scroll events function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Apply debouncing to scroll events const debouncedScroll = debounce(() => { // Scroll-dependent operations }, 10); window.addEventListener('scroll', debouncedScroll); } // Initialize performance optimizations optimizePerformance();