| |
|
|
| document.addEventListener('DOMContentLoaded', function() { |
| |
| initMobileMenu(); |
| initSmoothScrolling(); |
| initScrollAnimations(); |
| initFormHandling(); |
| initScrollToTop(); |
| initTypingEffect(); |
| }); |
|
|
| |
| 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'); |
| |
| |
| const icon = mobileMenuButton.querySelector('i'); |
| if (mobileMenu.classList.contains('hidden')) { |
| icon.setAttribute('data-feather', 'menu'); |
| } else { |
| icon.setAttribute('data-feather', 'x'); |
| } |
| feather.replace(); |
| }); |
| |
| |
| 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(); |
| }); |
| }); |
| } |
| } |
|
|
| |
| 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' |
| }); |
| } |
| }); |
| }); |
| } |
|
|
| |
| 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); |
| |
| |
| const animateElements = document.querySelectorAll('.card-hover, .bg-white, section > div'); |
| animateElements.forEach(el => { |
| el.style.opacity = '0'; |
| observer.observe(el); |
| }); |
| |
| |
| 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'); |
| } |
| }); |
| } |
|
|
| |
| function initFormHandling() { |
| const contactForm = document.querySelector('form'); |
| |
| if (contactForm) { |
| contactForm.addEventListener('submit', function(e) { |
| e.preventDefault(); |
| |
| |
| const formData = new FormData(this); |
| const formObject = {}; |
| formData.forEach((value, key) => { |
| formObject[key] = value; |
| }); |
| |
| |
| const submitButton = this.querySelector('button[type="submit"]'); |
| const originalText = submitButton.textContent; |
| submitButton.textContent = 'Sending...'; |
| submitButton.disabled = true; |
| |
| |
| setTimeout(() => { |
| |
| showNotification('Message sent successfully!', 'success'); |
| |
| |
| this.reset(); |
| |
| |
| submitButton.textContent = originalText; |
| submitButton.disabled = false; |
| }, 2000); |
| }); |
| } |
| } |
|
|
| |
| 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); |
| |
| |
| setTimeout(() => { |
| notification.classList.remove('translate-x-full'); |
| }, 100); |
| |
| |
| setTimeout(() => { |
| notification.classList.add('translate-x-full'); |
| setTimeout(() => { |
| document.body.removeChild(notification); |
| }, 300); |
| }, 4000); |
| } |
|
|
| |
| function initScrollToTop() { |
| |
| const scrollButton = document.createElement('button'); |
| scrollButton.innerHTML = '<i data-feather="arrow-up"></i>'; |
| 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(); |
| |
| |
| 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); |
| } |
| }); |
| |
| |
| scrollButton.addEventListener('click', function() { |
| window.scrollTo({ |
| top: 0, |
| behavior: 'smooth' |
| }); |
| }); |
| } |
|
|
| |
| 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 { |
| |
| setTimeout(() => { |
| heroTitle.style.borderRight = 'none'; |
| }, 1000); |
| } |
| }; |
| |
| |
| setTimeout(typeWriter, 1000); |
| } |
| } |
|
|
| |
| 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)`; |
| } |
| }); |
|
|
| |
| 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); |
| }); |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| 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'); |
| |
| |
| filterButtons.forEach(btn => btn.classList.remove('active')); |
| this.classList.add('active'); |
| |
| |
| portfolioItems.forEach(item => { |
| if (filter === 'all' || item.getAttribute('data-category') === filter) { |
| item.style.display = 'block'; |
| } else { |
| item.style.display = 'none'; |
| } |
| }); |
| }); |
| }); |
| } |
|
|
| |
| function initThemeSwitcher() { |
| const themeToggle = document.getElementById('theme-toggle'); |
| |
| if (themeToggle) { |
| themeToggle.addEventListener('click', function() { |
| document.body.classList.toggle('dark-theme'); |
| |
| |
| const isDark = document.body.classList.contains('dark-theme'); |
| localStorage.setItem('theme', isDark ? 'dark' : 'light'); |
| |
| |
| const icon = this.querySelector('i'); |
| if (isDark) { |
| icon.setAttribute('data-feather', 'sun'); |
| } else { |
| icon.setAttribute('data-feather', 'moon'); |
| } |
| feather.replace(); |
| }); |
| |
| |
| const savedTheme = localStorage.getItem('theme'); |
| if (savedTheme === 'dark') { |
| document.body.classList.add('dark-theme'); |
| } |
| } |
| } |
|
|
| |
| function optimizePerformance() { |
| |
| 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)); |
| |
| |
| function debounce(func, wait) { |
| let timeout; |
| return function executedFunction(...args) { |
| const later = () => { |
| clearTimeout(timeout); |
| func(...args); |
| }; |
| clearTimeout(timeout); |
| timeout = setTimeout(later, wait); |
| }; |
| } |
| |
| |
| const debouncedScroll = debounce(() => { |
| |
| }, 10); |
| |
| window.addEventListener('scroll', debouncedScroll); |
| } |
|
|
| |
| optimizePerformance(); |