From 529fc9148abccb67ebbc9d49291ce0751ce48b5d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Jul 2025 16:52:48 +0200 Subject: [PATCH] fix navigation --- hub/services/static/js/nav.js | 96 ++++++++++++++++++++++++++++++++ hub/services/templates/base.html | 21 +++---- 2 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 hub/services/static/js/nav.js diff --git a/hub/services/static/js/nav.js b/hub/services/static/js/nav.js new file mode 100644 index 0000000..e756e98 --- /dev/null +++ b/hub/services/static/js/nav.js @@ -0,0 +1,96 @@ +document.addEventListener('DOMContentLoaded', function () { + // Mobile navigation toggle functionality + const navToggle = document.getElementById('navToggle'); + const navMenu = document.getElementById('navMenu'); + const headerNav = document.getElementById('headerNav'); + const topLine = document.getElementById('topLine'); + const middleLine = document.getElementById('middleLine'); + const bottomLine = document.getElementById('bottomLine'); + + let isMenuOpen = false; + + // Toggle mobile menu + navToggle.addEventListener('click', function () { + isMenuOpen = !isMenuOpen; + + // Toggle menu visibility classes + if (isMenuOpen) { + navMenu.classList.remove('nav__menu-hidden'); + navMenu.classList.add('nav__menu-active'); + navToggle.setAttribute('aria-expanded', 'true'); + + // Animate hamburger to X + topLine.classList.add('svg-line-top'); + middleLine.classList.add('svg-line-center'); + bottomLine.classList.add('svg-line-bottom'); + } else { + navMenu.classList.remove('nav__menu-active'); + navMenu.classList.add('nav__menu-hidden'); + navToggle.setAttribute('aria-expanded', 'false'); + + // Animate X back to hamburger + topLine.classList.remove('svg-line-top'); + middleLine.classList.remove('svg-line-center'); + bottomLine.classList.remove('svg-line-bottom'); + } + }); + + // Close menu when clicking on menu items (mobile) + const menuItems = navMenu.querySelectorAll('.menu__item-link'); + menuItems.forEach(function (item) { + item.addEventListener('click', function () { + if (window.innerWidth < 992 && isMenuOpen) { + // Trigger the toggle to close menu + navToggle.click(); + } + }); + }); + + // Header scroll behavior + let isAtTop = true; + + function handleScroll() { + const scrollTop = window.pageYOffset || document.documentElement.scrollTop; + const newAtTop = scrollTop <= 200; + + if (newAtTop !== isAtTop) { + isAtTop = newAtTop; + + if (isAtTop) { + headerNav.classList.remove('header-nav--fixed'); + headerNav.classList.add('header-nav--top'); + } else { + headerNav.classList.remove('header-nav--top'); + headerNav.classList.add('header-nav--fixed'); + } + } + } + + // Throttle scroll events for better performance + let scrollThrottle = false; + window.addEventListener('scroll', function () { + if (!scrollThrottle) { + requestAnimationFrame(function () { + handleScroll(); + scrollThrottle = false; + }); + scrollThrottle = true; + } + }); + + // Handle window resize to ensure proper menu state + window.addEventListener('resize', function () { + if (window.innerWidth >= 992 && isMenuOpen) { + // Reset menu state on desktop + isMenuOpen = false; + navMenu.classList.remove('nav__menu-active'); + navMenu.classList.add('nav__menu-hidden'); + navToggle.setAttribute('aria-expanded', 'false'); + + // Reset hamburger animation + topLine.classList.remove('svg-line-top'); + middleLine.classList.remove('svg-line-center'); + bottomLine.classList.remove('svg-line-bottom'); + } + }); +}); \ No newline at end of file diff --git a/hub/services/templates/base.html b/hub/services/templates/base.html index bc702cc..dcc291b 100644 --- a/hub/services/templates/base.html +++ b/hub/services/templates/base.html @@ -23,9 +23,9 @@ {% endif %} - + {% block extra_js %}{% endblock %} @@ -40,9 +40,8 @@ -