// Initialize Lucide Icons lucide.createIcons(); // ===== MOBILE MENU ===== const menuBtn = document.getElementById('menuBtn'); const closeMenuBtn = document.getElementById('closeMenu'); const mobileMenu = document.getElementById('mobileMenu'); const mobileLinks = document.querySelectorAll('.mobile-nav-link'); function toggleMenu() { mobileMenu.classList.toggle('open'); } menuBtn.addEventListener('click', toggleMenu); closeMenuBtn.addEventListener('click', toggleMenu); mobileLinks.forEach(link => { link.addEventListener('click', () => { mobileMenu.classList.remove('open'); }); }); // ===== NAVBAR SCROLL EFFECT ===== const navbar = document.getElementById('navbar'); window.addEventListener('scroll', () => { if (window.scrollY > 50) { navbar.classList.add('scrolled'); } else { navbar.classList.remove('scrolled'); } }); // ===== ACTIVE NAV LINK ===== const sections = document.querySelectorAll('section[id]'); const navLinks = document.querySelectorAll('.nav-link'); function updateActiveNav() { const scrollY = window.scrollY + 100; sections.forEach(section => { const sectionTop = section.offsetTop; const sectionHeight = section.offsetHeight; const sectionId = section.getAttribute('id'); if (scrollY >= sectionTop && scrollY < sectionTop + sectionHeight) { navLinks.forEach(link => { link.classList.remove('active'); if (link.getAttribute('href') === '#' + sectionId) { link.classList.add('active'); } }); // Also update mobile nav mobileLinks.forEach(link => { link.classList.remove('active'); if (link.getAttribute('href') === '#' + sectionId) { link.classList.add('active'); } }); } }); } window.addEventListener('scroll', updateActiveNav); // ===== SCROLL ANIMATIONS ===== const scrollElements = document.querySelectorAll('.scroll-animate'); const observer = new IntersectionObserver( (entries) => { entries.forEach((entry, index) => { if (entry.isIntersecting) { // Add staggered delay based on element position setTimeout(() => { entry.target.classList.add('visible'); }, 100); observer.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px', } ); scrollElements.forEach(el => observer.observe(el)); // ===== SKILL BARS ANIMATION ===== const skillObserver = new IntersectionObserver( (entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const bar = entry.target.querySelector('.skill-bar-fill'); if (bar) { setTimeout(() => { bar.classList.add('animate'); }, 200); } skillObserver.unobserve(entry.target); } }); }, { threshold: 0.3, } ); document.querySelectorAll('.skill-item').forEach(item => { skillObserver.observe(item); }); // ===== BACK TO TOP ===== const backToTop = document.getElementById('backToTop'); window.addEventListener('scroll', () => { if (window.scrollY > 500) { backToTop.classList.add('visible'); } else { backToTop.classList.remove('visible'); } }); backToTop.addEventListener('click', () => { window.scrollTo({ top: 0, behavior: 'smooth' }); }); // ===== CONTACT FORM ===== const contactForm = document.getElementById('contactForm'); const formSuccess = document.getElementById('formSuccess'); contactForm.addEventListener('submit', (e) => { e.preventDefault(); // Simple visual feedback const btn = contactForm.querySelector('button[type="submit"]'); btn.innerHTML = 'Sending...'; btn.disabled = true; setTimeout(() => { contactForm.reset(); formSuccess.classList.remove('hidden'); formSuccess.style.display = 'block'; btn.innerHTML = 'Send Message'; btn.disabled = false; lucide.createIcons(); setTimeout(() => { formSuccess.classList.add('hidden'); formSuccess.style.display = 'none'; }, 4000); }, 1200); }); // ===== FILE UPLOAD ===== const fileInput = document.getElementById('fileInput'); const fileDropZone = document.getElementById('fileDropZone'); const fileList = document.getElementById('fileList'); let uploadedFiles = []; function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; } function getFileIcon(fileName) { const ext = fileName.split('.').pop().toLowerCase(); const iconMap = { pdf: 'file-text', doc: 'file-text', docx: 'file-text', txt: 'file-text', png: 'image', jpg: 'image', jpeg: 'image', gif: 'image', svg: 'image', webp: 'image', zip: 'archive', rar: 'archive', }; return iconMap[ext] || 'file'; } function renderFileList() { fileList.innerHTML = ''; uploadedFiles.forEach((file, index) => { const fileItem = document.createElement('div'); fileItem.className = 'flex items-center justify-between gap-3 p-3 rounded-lg bg-white/[0.03] border border-white/[0.08] group/file transition-all'; fileItem.innerHTML = `
${file.name}
${formatFileSize(file.size)}