Optimized logic in which direction menus open

This commit is contained in:
Kevin Veen-Birkenbach 2025-01-14 17:34:30 +01:00
parent 7c51ac6bbc
commit f017cacebe
2 changed files with 81 additions and 8 deletions

View File

@ -1,5 +1,6 @@
document.addEventListener('DOMContentLoaded', () => {
const menuItems = document.querySelectorAll('.nav-item.dropdown, .dropdown-submenu');
const menuItems = document.querySelectorAll('.nav-item.dropdown');
const subMenuItems = document.querySelectorAll('.dropdown-submenu');
menuItems.forEach(item => {
let timeout;
@ -7,7 +8,7 @@ document.addEventListener('DOMContentLoaded', () => {
// Öffnen beim Hovern
item.addEventListener('mouseenter', () => {
clearTimeout(timeout);
openMenu(item);
openMenu(item, true);
});
// Verzögertes Schließen beim Verlassen
@ -21,20 +22,46 @@ document.addEventListener('DOMContentLoaded', () => {
if (item.classList.contains('open')) {
closeMenu(item);
} else {
openMenu(item);
openMenu(item, true);
}
});
});
subMenuItems.forEach(item => {
let timeout;
// Öffnen beim Hovern
item.addEventListener('mouseenter', () => {
clearTimeout(timeout);
openMenu(item, false);
});
// Verzögertes Schließen beim Verlassen
item.addEventListener('mouseleave', () => {
timeout = setTimeout(() => closeMenu(item), 500);
});
// Offen lassen beim Klicken
item.addEventListener('click', (e) => {
e.stopPropagation(); // Verhindert das Schließen von Menüs bei Klick
if (item.classList.contains('open')) {
closeMenu(item);
} else {
openMenu(item, false);
}
});
});
// Globale Klick-Listener, um Menüs zu schließen, wenn außerhalb geklickt wird
document.addEventListener('click', () => {
menuItems.forEach(item => closeMenu(item));
[...menuItems, ...subMenuItems].forEach(item => closeMenu(item));
});
function openMenu(item) {
function openMenu(item, isTopLevel) {
item.classList.add('open');
const submenu = item.querySelector('.dropdown-menu');
if (submenu) {
adjustMenuPosition(submenu, item, isTopLevel);
submenu.style.display = 'block';
submenu.style.opacity = '1';
submenu.style.visibility = 'visible';
@ -50,4 +77,49 @@ document.addEventListener('DOMContentLoaded', () => {
submenu.style.visibility = 'hidden';
}
}
});
function adjustMenuPosition(submenu, parent, isTopLevel) {
const rect = submenu.getBoundingClientRect();
const parentRect = parent.getBoundingClientRect();
// Platzberechnung
const spaceAbove = parentRect.top;
const spaceBelow = window.innerHeight - parentRect.bottom;
const spaceLeft = parentRect.left;
const spaceRight = window.innerWidth - parentRect.right;
// Standardpositionierung
submenu.style.top = '';
submenu.style.bottom = '';
submenu.style.left = '';
submenu.style.right = '';
if (isTopLevel) {
// Top-Level-Menüs öffnen nur nach oben oder unten
if (spaceBelow < rect.height && spaceAbove > rect.height) {
submenu.style.top = 'auto';
submenu.style.bottom = '100%';
} else {
submenu.style.top = '100%';
submenu.style.bottom = 'auto';
}
} else {
// Submenüs öffnen in die Richtung mit mehr Platz
if (spaceRight < rect.width && spaceLeft > rect.width) {
submenu.style.left = 'auto';
submenu.style.right = '100%';
} else {
submenu.style.left = '100%';
submenu.style.right = 'auto';
}
if (spaceBelow < rect.height && spaceAbove > rect.height) {
submenu.style.top = 'auto';
submenu.style.bottom = '100%';
} else {
submenu.style.top = '0';
submenu.style.bottom = 'auto';
}
}
}
});

View File

@ -3,7 +3,7 @@
{% for subitem in subitems %}
{% if subitem.subitems %}
<li class="dropdown-submenu position-relative">
<a class="dropdown-item dropdown-toggle" title="{{ subitem.description }}">
<a class="dropdown-item dropdown-toggle" href="#" title="{{ subitem.description }}">
{% if subitem.icon is defined and subitem.icon.class is defined %}
<i class="{{ subitem.icon.class }}"></i> {{ subitem.name }}
{% else %}
@ -33,6 +33,7 @@
{% endif %}
{% endfor %}
{% endmacro %}
<!-- Navigation Bar -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
@ -52,7 +53,7 @@
{% else %}
<!-- Dropdown Menu -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ loop.index }}" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ loop.index }}" role="button" data-bs-toggle="dropdown" data-bs-display="dynamic" aria-expanded="false">
{% if item.icon is defined and item.icon.class is defined %}
<i class="{{ item.icon.class }}"></i> {{ item.name }}
{% else %}