// Enhanced Mobile Navigation Class
class MobileNavigation {
constructor() {
this.navbar = document.querySelector('.navbar');
this.mobileToggle = document.querySelector('#mobileMenuToggle');
this.navbarNav = document.querySelector('#navbarNav');
this.isAnimating = false;
this.init();
}
init() {
if (!this.mobileToggle || !this.navbarNav) {
console.warn('Mobile navigation elements not found');
return;
}
console.log('Initializing mobile navigation...');
this.setupEventListeners();
this.setupScrollEffect();
}
setupEventListeners() {
// Mobile menu toggle
this.mobileToggle.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log('Mobile toggle clicked');
this.toggleMobileMenu();
});
// Keyboard support for toggle
this.mobileToggle.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.toggleMobileMenu();
}
});
// Close menu when clicking outside navbar
document.addEventListener('click', (e) => {
if (!e.target.closest('.navbar') && this.isMobileMenuOpen()) {
console.log('Clicking outside - closing menu');
this.closeMobileMenu();
}
});
// Close menu on escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.isMobileMenuOpen()) {
console.log('Escape pressed - closing menu');
this.closeMobileMenu();
this.mobileToggle.focus();
}
});
// Close menu on window resize to desktop
window.addEventListener('resize', () => {
if (window.innerWidth > 768 && this.isMobileMenuOpen()) {
console.log('Resized to desktop - closing menu');
this.closeMobileMenu();
}
});
// Close menu when clicking navigation links
const navLinks = this.navbarNav.querySelectorAll('.dropdown-item, .nav-link');
navLinks.forEach(link => {
link.addEventListener('click', (e) => {
// Only close if it's an actual navigation link (has href that's not just "#")
const href = link.getAttribute('href');
if (href && href !== '#' && href.length > 1) {
if (this.isMobileMenuOpen()) {
console.log('Nav link clicked - closing menu');
setTimeout(() => this.closeMobileMenu(), 150);
}
}
});
});
}
setupScrollEffect() {
if (!this.navbar) return;
let ticking = false;
const handleScroll = () => {
if (!ticking) {
requestAnimationFrame(() => {
const scrolled = window.scrollY > 100;
this.navbar.classList.toggle('scrolled', scrolled);
ticking = false;
});
ticking = true;
}
};
window.addEventListener('scroll', handleScroll, { passive: true });
}
toggleMobileMenu() {
if (this.isAnimating) {
console.log('Animation in progress - ignoring toggle');
return;
}
if (this.isMobileMenuOpen()) {
this.closeMobileMenu();
} else {
this.openMobileMenu();
}
}
openMobileMenu() {
console.log('Opening mobile menu');
this.isAnimating = true;
// Add active classes
this.mobileToggle.classList.add('active');
this.navbarNav.classList.add('mobile-open');
document.body.classList.add('mobile-menu-open');
// Update ARIA attributes
this.mobileToggle.setAttribute('aria-expanded', 'true');
this.navbarNav.setAttribute('aria-hidden', 'false');
// Focus management
setTimeout(() => {
const firstLink = this.navbarNav.querySelector('.nav-link');
if (firstLink) {
firstLink.focus();
}
this.isAnimating = false;
console.log('Mobile menu opened');
}, 300);
}
closeMobileMenu() {
console.log('Closing mobile menu');
this.isAnimating = true;
// Remove active classes
this.mobileToggle.classList.remove('active');
this.navbarNav.classList.remove('mobile-open');
document.body.classList.remove('mobile-menu-open');
// Update ARIA attributes
this.mobileToggle.setAttribute('aria-expanded', 'false');
this.navbarNav.setAttribute('aria-hidden', 'true');
setTimeout(() => {
this.isAnimating = false;
console.log('Mobile menu closed');
}, 300);
}
isMobileMenuOpen() {
return this.navbarNav && this.navbarNav.classList.contains('mobile-open');
}
}
// Update your existing Navigation class or replace the mobile menu section
class Navigation {
constructor() {
this.navbar = Utils.querySelector('.navbar');
this.mobileToggle = Utils.querySelector('#mobileMenuToggle');
this.navbarNav = Utils.querySelector('#navbarNav');
this.backToTop = Utils.querySelector('#backToTop');
this.mobileNav = new MobileNavigation(); // Use the new mobile navigation
this.init();
}
init() {
try {
this.setupBackToTop();
this.setupSmoothScrolling();
// Mobile navigation is now handled by MobileNavigation class
} catch (error) {
console.error('Error initializing Navigation:', error);
}
}
// Keep your existing setupBackToTop and setupSmoothScrolling methods...
setupBackToTop() {
if (!this.backToTop) return;
if (Utils.hasFeature('intersectionObserver')) {
const heroSection = Utils.querySelector('.hero');
if (heroSection) {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
const isVisible = !entry.isIntersecting;
this.backToTop.style.opacity = isVisible ? '1' : '0';
this.backToTop.style.visibility = isVisible ? 'visible' : 'hidden';
this.backToTop.setAttribute('aria-hidden', !isVisible);
});
},
{ threshold: 0.1 }
);
observer.observe(heroSection);
}
}
this.backToTop.addEventListener('click', (e) => {
e.preventDefault();
this.smoothScrollToTop();
});
}
setupSmoothScrolling() {
const anchorLinks = document.querySelectorAll('a[href^="#"]');
anchorLinks.forEach(anchor => {
anchor.addEventListener('click', (e) => {
const targetId = anchor.getAttribute('href');
if (targetId === '#' || targetId.length <= 1) {
return;
}
e.preventDefault();
const target = Utils.querySelector(targetId);
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
// Close mobile menu if open
if (this.mobileNav && this.mobileNav.isMobileMenuOpen()) {
this.mobileNav.closeMobileMenu();
}
target.setAttribute('tabindex', '-1');
target.focus();
setTimeout(() => target.removeAttribute('tabindex'), 1000);
}
});
});
}
smoothScrollToTop() {
if ('scrollBehavior' in document.documentElement.style) {
window.scrollTo({ top: 0, behavior: 'smooth' });
} else {
const scrollToTop = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, scrollTop - scrollTop / 8);
}
};
scrollToTop();
}
}
}