// Theme Management const themeToggle = document.getElementById('theme-toggle'); const htmlElement = document.documentElement; const darkIcon = document.querySelector('.dark-icon'); const lightIcon = document.querySelector('.light-icon'); // Check for saved theme preference or default to dark const currentTheme = localStorage.getItem('theme') || 'dark'; if (currentTheme === 'light') { htmlElement.classList.add('light'); darkIcon.classList.remove('hidden'); lightIcon.classList.add('hidden'); } themeToggle.addEventListener('click', () => { const isLight = htmlElement.classList.contains('light'); if (isLight) { htmlElement.classList.remove('light'); darkIcon.classList.add('hidden'); lightIcon.classList.remove('hidden'); localStorage.setItem('theme', 'dark'); } else { htmlElement.classList.add('light'); darkIcon.classList.remove('hidden'); lightIcon.classList.add('hidden'); localStorage.setItem('theme', 'light'); } }); // Intersection Observer for scroll animations 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('visible'); } }); }, observerOptions); // Observe all fade-in elements document.addEventListener('DOMContentLoaded', () => { const fadeElements = document.querySelectorAll('.fade-in-on-scroll'); fadeElements.forEach(el => observer.observe(el)); }); // 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' }); // Update URL without jumping history.pushState(null, null, this.getAttribute('href')); } }); }); // Mock Projects Data (In real app, fetch from API) const mockProjects = [ { title: "Cosmic Dashboard", description: "A real-time analytics dashboard with stunning visualizations and smooth animations.", image: "http://static.photos/technology/640x360/123", tags: ["React", "D3.js", "Node.js"], demoUrl: "#", codeUrl: "#" }, { title: "Nebula Commerce", description: "Modern e-commerce platform with AR product preview and AI recommendations.", image: "http://static.photos/retail/640x360/456", tags: ["Next.js", "Stripe", "PostgreSQL"], demoUrl: "#", codeUrl: "#" }, { title: "Stellar Chat", description: "Real-time messaging app with end-to-end encryption and video calls.", image: "http://static.photos/people/640x360/789", tags: ["TypeScript", "WebRTC", "Socket.io"], demoUrl: "#", codeUrl: "#" }, { title: "Aurora CMS", description: "Headless CMS with visual content modeling and GraphQL API.", image: "http://static.photos/office/640x360/101", tags: ["Vue.js", "GraphQL", "MongoDB"], demoUrl: "#", codeUrl: "#" }, { title: "Lunar Tasks", description: "Minimalist task manager with focus mode and productivity insights.", image: "http://static.photos/minimal/640x360/202", tags: ["React", "PWA", "Firebase"], demoUrl: "#", codeUrl: "#" }, { title: "Quantum Blog", description: "Lightning-fast blog platform with MDX support and theme switching.", image: "http://static.photos/nature/640x360/303", tags: ["Remix", "Prisma", "Tailwind"], demoUrl: "#", codeUrl: "#" } ]; // Inject projects into the grid function loadProjects() { const projectsGrid = document.getElementById('projects-grid'); mockProjects.forEach((project, index) => { const projectCard = document.createElement('project-card'); projectCard.setAttribute('title', project.title); projectCard.setAttribute('description', project.description); projectCard.setAttribute('image', project.image); projectCard.setAttribute('tags', JSON.stringify(project.tags)); projectCard.setAttribute('demo-url', project.demoUrl); projectCard.setAttribute('code-url', project.codeUrl); projectCard.style.animationDelay = `${index * 0.1}s`; projectsGrid.appendChild(projectCard); }); } // Initialize projects when DOM is ready document.addEventListener('DOMContentLoaded', loadProjects); // Add parallax effect to hero section window.addEventListener('scroll', () => { const scrolled = window.pageYOffset; const parallax = document.querySelector('#particles'); if (parallax) { parallax.style.transform = `translateY(${scrolled * 0.5}px)`; } }); // Add active state to nav links based on scroll position window.addEventListener('scroll', () => { const sections = document.querySelectorAll('section[id]'); const navLinks = document.querySelectorAll('.nav-link'); let current = ''; sections.forEach(section => { const sectionTop = section.offsetTop; const sectionHeight = section.clientHeight; if (scrollY >= sectionTop - 200) { current = section.getAttribute('id'); } }); navLinks.forEach(link => { link.classList.remove('active'); if (link.getAttribute('href') === `#${current}`) { link.classList.add('active'); } }); }); // Create dynamic particles function createParticles() { const container = document.getElementById('particles'); if (!container) return; for (let i = 0; i < 50; i++) { const particle = document.createElement('div'); particle.style.position = 'absolute'; particle.style.width = Math.random() * 4 + 'px'; particle.style.height = particle.style.width; particle.style.backgroundColor = Math.random() > 0.5 ? 'rgba(99, 102, 241, 0.5)' : 'rgba(168, 85, 247, 0.5)'; particle.style.borderRadius = '50%'; particle.style.left = Math.random() * 100 + '%'; particle.style.top = Math.random() * 100 + '%'; particle.style.animation = `float ${Math.random() * 10 + 10}s infinite ease-in-out`; particle.style.animationDelay = Math.random() * 5 + 's'; container.appendChild(particle); } } // Initialize particles document.addEventListener('DOMContentLoaded', createParticles); // Mobile menu toggle (for navbar component) window.toggleMobileMenu = function() { const menu = document.getElementById('mobile-menu'); menu.classList.toggle('hidden'); menu.classList.toggle('mobile-menu-enter'); };