diff --git a/app.js b/app.js index d5591aea..a40647c1 100644 --- a/app.js +++ b/app.js @@ -1,25 +1,161 @@ -const hamburger = document.querySelector('.header .nav-bar .nav-list .hamburger'); -const mobile_menu = document.querySelector('.header .nav-bar .nav-list ul'); -const menu_item = document.querySelectorAll('.header .nav-bar .nav-list ul li a'); -const header = document.querySelector('.header.container'); - -hamburger.addEventListener('click', () => { - hamburger.classList.toggle('active'); - mobile_menu.classList.toggle('active'); -}); - -document.addEventListener('scroll', () => { - var scroll_position = window.scrollY; - if (scroll_position > 250) { - header.style.backgroundColor = '#29323c'; - } else { - header.style.backgroundColor = 'transparent'; - } -}); - -menu_item.forEach((item) => { - item.addEventListener('click', () => { - hamburger.classList.toggle('active'); - mobile_menu.classList.toggle('active'); - }); -}); +// Enhanced JavaScript with smooth scroll, scroll-spy active link, touch support and better performance + +(function () { + // DOM Elements + const hamburger = document.querySelector('.header .nav-bar .nav-list .hamburger'); + const mobileMenu = document.querySelector('.header .nav-bar .nav-list ul'); + const menuItems = document.querySelectorAll('.header .nav-bar .nav-list ul li a'); + const header = document.querySelector('.header.container'); + const sections = document.querySelectorAll('section'); + + // Helper: toggle hamburger + menu + function toggleMenu() { + if (!hamburger || !mobileMenu) return; + hamburger.classList.toggle('active'); + mobileMenu.classList.toggle('active'); + // Prevent body scroll when menu is open (improve UX) + document.body.style.overflow = mobileMenu.classList.contains('active') ? 'hidden' : ''; + } + + // Close menu when a link is clicked + function closeMenuOnLinkClick() { + if (mobileMenu && mobileMenu.classList.contains('active')) { + hamburger.classList.remove('active'); + mobileMenu.classList.remove('active'); + document.body.style.overflow = ''; + } + } + + // Event listeners for hamburger + if (hamburger) { + hamburger.addEventListener('click', toggleMenu); + // Accessibility: allow Enter key + hamburger.addEventListener('keypress', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + toggleMenu(); + } + }); + } + + // Close menu on each menu item click (with smooth scroll offset) + menuItems.forEach(item => { + item.addEventListener('click', (e) => { + // Get target section id from href + const targetId = item.getAttribute('href'); + if (targetId && targetId !== '#') { + e.preventDefault(); + const targetElement = document.querySelector(targetId); + if (targetElement) { + // Smooth scroll with offset for fixed header + const offsetTop = targetElement.offsetTop - 70; // 70px offset for fixed header + window.scrollTo({ + top: offsetTop, + behavior: 'smooth' + }); + // Update URL without jumping (optional) + history.pushState(null, null, targetId); + } + } + closeMenuOnLinkClick(); + }); + }); + + // Scroll event: change header background + active nav link (scroll spy) + function handleScroll() { + // Change header background after scroll + if (header) { + const scrollPos = window.scrollY; + if (scrollPos > 80) { + header.style.backgroundColor = '#1e1e2a'; + header.style.boxShadow = '0 2px 10px rgba(0,0,0,0.1)'; + } else { + header.style.backgroundColor = 'rgba(31, 30, 30, 0.24)'; + header.style.boxShadow = 'none'; + } + } + + // Scroll spy: highlight active menu item based on visible section + let current = ''; + const scrollPosition = window.scrollY + 150; // offset for better accuracy + + sections.forEach(section => { + const sectionTop = section.offsetTop; + const sectionHeight = section.clientHeight; + if (scrollPosition >= sectionTop && scrollPosition < sectionTop + sectionHeight) { + current = section.getAttribute('id'); + } + }); + + menuItems.forEach(link => { + link.classList.remove('active'); + const href = link.getAttribute('href').substring(1); // remove # + if (href === current) { + link.classList.add('active'); + // optional: change style + link.style.color = '#e63946'; + } else { + link.style.color = ''; + } + }); + } + + // Throttle scroll event for performance + let ticking = false; + window.addEventListener('scroll', () => { + if (!ticking) { + requestAnimationFrame(() => { + handleScroll(); + ticking = false; + }); + ticking = true; + } + }); + + // Run once on load + window.addEventListener('DOMContentLoaded', () => { + handleScroll(); + // Fix initial active link if hash exists + if (window.location.hash) { + const target = document.querySelector(window.location.hash); + if (target) { + setTimeout(() => { + window.scrollTo({ + top: target.offsetTop - 70, + behavior: 'smooth' + }); + }, 100); + } + } + }); + + // Close mobile menu on window resize (if open) + window.addEventListener('resize', () => { + if (window.innerWidth > 1200 && mobileMenu && mobileMenu.classList.contains('active')) { + closeMenuOnLinkClick(); + } + }); + + // Touch-friendly: close menu on tapping outside (for mobile) + document.addEventListener('click', (e) => { + if (mobileMenu && mobileMenu.classList.contains('active')) { + const isClickInsideMenu = mobileMenu.contains(e.target); + const isHamburger = hamburger && hamburger.contains(e.target); + if (!isClickInsideMenu && !isHamburger) { + closeMenuOnLinkClick(); + } + } + }); + + // Prevent scroll chaining when menu is open on touch devices + if (mobileMenu) { + mobileMenu.addEventListener('touchmove', (e) => { + if (mobileMenu.classList.contains('active')) { + e.preventDefault(); + } + }, { passive: false }); + } + + // Optional: add active class styling in CSS for current menu item + // we already set color inline, but you can also add class .active-link +})(); \ No newline at end of file diff --git a/index.html b/index.html index 1a429961..91f3816f 100644 --- a/index.html +++ b/index.html @@ -3,9 +3,9 @@
- + -Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ipsum deleniti maiores pariatur assumenda quas - magni et, doloribus quod voluptate quasi molestiae magnam officiis dolorum, dolor provident atque molestias - voluptatum explicabo!
+I craft modern, responsive web experiences with clean UI/UX. From concept to launch, I provide full-cycle web + solutions tailored to your brand.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Corporis debitis rerum, magni voluptatem sed - architecto placeat beatae tenetur officia quod
+Pixel-perfect, mobile-first designs that engage users and reflect your identity.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Corporis debitis rerum, magni voluptatem sed - architecto placeat beatae tenetur officia quod
+Interactive, dynamic interfaces using HTML5, CSS3, JS. Performance optimized.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Corporis debitis rerum, magni voluptatem sed - architecto placeat beatae tenetur officia quod
+Seamless experience across tablets, phones, and desktops. Fluid layouts.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Corporis debitis rerum, magni voluptatem sed - architecto placeat beatae tenetur officia quod
+Lightning-fast load times, optimized assets, clean code for better SEO.
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ad, iusto cupiditate voluptatum impedit unde - rem ipsa distinctio illum quae mollitia ut, accusantium eius odio ducimus illo neque atque libero non sunt - harum? Ipsum repellat animi, fugit architecto voluptatum odit et!
-
+ Modern admin panel with dynamic charts, product management, and real-time analytics.

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ad, iusto cupiditate voluptatum impedit unde - rem ipsa distinctio illum quae mollitia ut, accusantium eius odio ducimus illo neque atque libero non sunt - harum? Ipsum repellat animi, fugit architecto voluptatum odit et!
-
+ Interactive storytelling hub with smooth transitions, lazy loading, and immersive gallery.

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ad, iusto cupiditate voluptatum impedit unde - rem ipsa distinctio illum quae mollitia ut, accusantium eius odio ducimus illo neque atque libero non sunt - harum? Ipsum repellat animi, fugit architecto voluptatum odit et!
-
+ Customizable portfolio template for creatives, with dark/light mode and filtering.

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ad, iusto cupiditate voluptatum impedit unde - rem ipsa distinctio illum quae mollitia ut, accusantium eius odio ducimus illo neque atque libero non sunt - harum? Ipsum repellat animi, fugit architecto voluptatum odit et!
-
+ Online ordering system with reservation module, menu showcase, and location finder.

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ad, iusto cupiditate voluptatum impedit unde - rem ipsa distinctio illum quae mollitia ut, accusantium eius odio ducimus illo neque atque libero non sunt - harum? Ipsum repellat animi, fugit architecto voluptatum odit et!
-
+ Workout log, progress charts, and goal tracking. Interactive UI with local storage.

- 
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Asperiores, velit alias eius non illum beatae atque - repellat ratione qui veritatis repudiandae adipisci maiores. At inventore necessitatibus deserunt - exercitationem cumque earum omnis ipsum rem accusantium quis, quas quia, accusamus provident suscipit magni! - Expedita sint ad dolore, commodi labore nihil velit earum ducimus nulla quae nostrum fugit aut, deserunt - reprehenderit libero enim!
+I'm Arfan, a passionate front-end developer with 5+ years of experience crafting engaging digital + experiences. I focus on clean code, modern design systems, and user-centric performance. Let's build something + amazing together.
Download Resume