Files
Website/js/mobile-nav.js
Claude Code 21a0ba0757 Update imprint data and remove trust indicators
- Fix impressum.html with correct HRB 110105 and Amtsgericht Düsseldorf
- Add English versions of legal pages (impressum-en.html, datenschutz-en.html)
- Correct company representatives to Hendrik Gebhardt & Monami Homma
- Remove incorrect Marlon Paulse references and Wiesenstraße address
- Remove trust-indicators section from website (HTML, CSS, JS)
- Add mobile.css and related mobile navigation files

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-05 21:07:24 +00:00

196 Zeilen
6.2 KiB
JavaScript

/**
* Mobile Navigation Handler
* Clean, accessible mobile navigation implementation
*/
class MobileNavigation {
constructor() {
this.menuToggle = document.querySelector('.mobile-menu-toggle');
this.mobileMenu = document.querySelector('.nav-menu-mobile');
this.overlay = document.querySelector('.mobile-menu-overlay');
this.menuLinks = document.querySelectorAll('.nav-menu-mobile a');
this.closeButton = document.querySelector('.mobile-menu-close');
this.isOpen = false;
this.init();
}
init() {
if (!this.menuToggle || !this.mobileMenu) return;
// Toggle button click
this.menuToggle.addEventListener('click', () => this.toggleMenu());
// Close button click
if (this.closeButton) {
this.closeButton.addEventListener('click', () => this.closeMenu());
}
// Overlay click closes menu
this.overlay.addEventListener('click', () => this.closeMenu());
// Menu links click closes menu
this.menuLinks.forEach(link => {
link.addEventListener('click', () => this.closeMenu());
});
// ESC key closes menu
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.isOpen) {
this.closeMenu();
}
});
// Prevent body scroll when menu is open
this.handleBodyScroll();
}
toggleMenu() {
this.isOpen ? this.closeMenu() : this.openMenu();
}
openMenu() {
this.isOpen = true;
this.menuToggle.classList.add('active');
this.mobileMenu.classList.add('active');
this.overlay.classList.add('active');
// Update ARIA attributes
this.menuToggle.setAttribute('aria-expanded', 'true');
this.mobileMenu.setAttribute('aria-hidden', 'false');
// Prevent body scroll
document.body.style.overflow = 'hidden';
// Focus management
setTimeout(() => {
const firstLink = this.mobileMenu.querySelector('a');
if (firstLink) firstLink.focus();
}, 300);
}
closeMenu() {
this.isOpen = false;
this.menuToggle.classList.remove('active');
this.mobileMenu.classList.remove('active');
this.overlay.classList.remove('active');
// Update ARIA attributes
this.menuToggle.setAttribute('aria-expanded', 'false');
this.mobileMenu.setAttribute('aria-hidden', 'true');
// Restore body scroll
document.body.style.overflow = '';
// Return focus to toggle button
this.menuToggle.focus();
}
handleBodyScroll() {
// Save scroll position when menu opens
let scrollPosition = 0;
const observer = new MutationObserver(() => {
if (this.isOpen) {
scrollPosition = window.pageYOffset;
document.body.style.position = 'fixed';
document.body.style.top = `-${scrollPosition}px`;
document.body.style.width = '100%';
} else {
document.body.style.position = '';
document.body.style.top = '';
document.body.style.width = '';
window.scrollTo(0, scrollPosition);
}
});
observer.observe(this.mobileMenu, {
attributes: true,
attributeFilter: ['class']
});
}
}
// Smooth scroll for anchor links
class SmoothScroll {
constructor() {
this.init();
}
init() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', (e) => {
const href = anchor.getAttribute('href');
if (href === '#') return;
e.preventDefault();
const target = document.querySelector(href);
if (target) {
const offset = 80; // Account for fixed navbar
const targetPosition = target.offsetTop - offset;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
}
});
});
}
}
// Responsive image loading
class ResponsiveImages {
constructor() {
this.init();
}
init() {
// Check if user prefers reduced motion
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReducedMotion) {
// Disable animations
document.documentElement.style.setProperty('--animation-duration', '0.01s');
}
// Lazy load images on mobile
if ('IntersectionObserver' in window && window.innerWidth <= 768) {
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
}
}
}
// Initialize on DOM load
document.addEventListener('DOMContentLoaded', () => {
new MobileNavigation();
new SmoothScroll();
new ResponsiveImages();
// Hide mobile menu button styles until JS loads
document.documentElement.classList.add('js-loaded');
});
// Handle orientation change
window.addEventListener('orientationchange', () => {
// Close mobile menu on orientation change
const mobileNav = document.querySelector('.nav-menu-mobile');
if (mobileNav && mobileNav.classList.contains('active')) {
const event = new Event('click');
document.querySelector('.mobile-menu-overlay').dispatchEvent(event);
}
});