fix navigation
This commit is contained in:
parent
6f39f73522
commit
529fc9148a
2 changed files with 104 additions and 13 deletions
96
hub/services/static/js/nav.js
Normal file
96
hub/services/static/js/nav.js
Normal file
|
|
@ -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');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -23,9 +23,9 @@
|
||||||
<script defer data-api="/api/event" data-domain="servala.com" src="/js/script.js"></script>
|
<script defer data-api="/api/event" data-domain="servala.com" src="/js/script.js"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script defer src="{% static "js/htmx204.min.js" %}"></script>
|
<script defer src="{% static "js/htmx204.min.js" %}"></script>
|
||||||
<script defer src="{% static "js/alpine-collapse.min.js" %}"></script>
|
|
||||||
<script defer src="{% static "js/bootstrap.bundle.min.js" %}"></script>
|
<script defer src="{% static "js/bootstrap.bundle.min.js" %}"></script>
|
||||||
<script defer src="{% static "js/servala-addons.js" %}"></script>
|
<script defer src="{% static "js/servala-addons.js" %}"></script>
|
||||||
|
<script defer src="{% static "js/nav.js" %}"></script>
|
||||||
{% block extra_js %}{% endblock %}
|
{% block extra_js %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -40,9 +40,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<header x-data="{sideNav: false, atTop: true}" class="site-header position-relative">
|
<header class="site-header position-relative">
|
||||||
<div class="header-nav" :class="{ 'header-nav--top': atTop, 'header-nav--fixed': !atTop }"
|
<div class="header-nav header-nav--top" id="headerNav">
|
||||||
x-on:scroll.window="atTop = (window.pageYOffset > 200) ? false : true;">
|
|
||||||
<div class="container-xl mx-auto px-3 px-lg-0 position-relative">
|
<div class="container-xl mx-auto px-3 px-lg-0 position-relative">
|
||||||
<div class="nav__wrapper d-flex justify-content-between align-items-center">
|
<div class="nav__wrapper d-flex justify-content-between align-items-center">
|
||||||
<div class="nav__brand logo">
|
<div class="nav__brand logo">
|
||||||
|
|
@ -50,7 +49,7 @@
|
||||||
<img src="{% static "img/header-logo.png" %}" alt="Servala Logo" width="191" height="43">
|
<img src="{% static "img/header-logo.png" %}" alt="Servala Logo" width="191" height="43">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak class="nav__menu" :class="sideNav ? 'nav__menu-active' : 'nav__menu-hidden'">
|
<div class="nav__menu nav__menu-hidden" id="navMenu">
|
||||||
<nav class="navbar d-lg-flex justify-content-lg-end align-items-lg-center">
|
<nav class="navbar d-lg-flex justify-content-lg-end align-items-lg-center">
|
||||||
<ul class="navbar__menu menu mr-lg-27">
|
<ul class="navbar__menu menu mr-lg-27">
|
||||||
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:homepage' %}">Home</a></li>
|
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:homepage' %}">Home</a></li>
|
||||||
|
|
@ -66,15 +65,11 @@
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav__toggle">
|
<div class="nav__toggle">
|
||||||
<button @click="sideNav = !sideNav" name="menu" class="nav__button" role="button">
|
<button id="navToggle" name="menu" class="nav__button" role="button" aria-expanded="false" aria-controls="navMenu">
|
||||||
<svg class="nav__button-svg" width="22" height="24">
|
<svg class="nav__button-svg" width="22" height="24">
|
||||||
<line class="button-svg__line" :class="{ 'svg-line-top': sideNav === true }" id="top" x1="0" x2="22"
|
<line class="button-svg__line" id="topLine" x1="0" x2="22" y1="6" y2="6"></line>
|
||||||
y1="6" y2="6"></line>
|
<line class="button-svg__line" id="middleLine" x1="0" x2="22" y1="12" y2="12"></line>
|
||||||
<line class="button-svg__line" :class="{ 'svg-line-center': sideNav === true }" id="middle" x1="0"
|
<line class="button-svg__line" id="bottomLine" x1="0" x2="22" y1="18" y2="18"></line>
|
||||||
x2="22" y1="12" y2="12">
|
|
||||||
</line>
|
|
||||||
<line class="button-svg__line" :class="{ 'svg-line-bottom': sideNav === true }" id="bottom" x1="0"
|
|
||||||
x2="22" y1="18" y2="18"></line>
|
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue