Optimized menus for smartphone

This commit is contained in:
Kevin Veen-Birkenbach 2025-01-14 17:08:59 +01:00
parent 1eb673454c
commit 573a3be360
4 changed files with 76 additions and 91 deletions

View File

@ -502,6 +502,7 @@ navigation:
- link: accounts - link: accounts
- name: Imprint - name: Imprint
description: Check out the imprint information
icon: icon:
class: fa-solid fa-scale-balanced class: fa-solid fa-scale-balanced
url: https://s.veen.world/imprint url: https://s.veen.world/imprint

View File

@ -78,66 +78,39 @@ h3.card-title {
h3.footer-title { h3.footer-title {
font-size: 1.3em; font-size: 1.3em;
} }
/* Dropdown-Menüs verstecken */
/* Dropdown menu styles */
.dropdown-menu { .dropdown-menu {
position: absolute !important;
}
.dropdown-menu-footer {
position: absolute !important;
top: auto !important;
bottom: 100%; /* Positions the menu above the trigger */
transform: translateY(-10px); /* Optional spacing for smoother appearance */
}
/* Dropdown submenu styles */
.dropdown-submenu {
position: relative;
list-style: none;
}
.dropdown-submenu > .dropdown-menu {
position: absolute;
top: 0;
left: 100%; /* Default position: open to the right */
margin-top: -1px;
z-index: 1050;
transition: opacity 0.3s ease-in-out; /* Smooth opacity transition */
}
/* Handle collapse behavior for dropdowns */
.dropdown-menu.collapse {
display: none;
}
.dropdown-menu.collapse.show {
display: block;
}
/* Ensure submenus are hidden by default */
.dropdown-submenu .dropdown-menu {
display: none; display: none;
opacity: 0; opacity: 0;
transition: opacity 0.3s ease-in-out; visibility: hidden;
position: absolute; transition: opacity 0.3s ease, visibility 0.3s ease;
left: 100%;
top: 0;
} }
/* Show submenu on hover */ /* Dropdown-Menü beim Hover anzeigen */
.nav-item.dropdown:hover > .dropdown-menu,
.dropdown-submenu:hover > .dropdown-menu { .dropdown-submenu:hover > .dropdown-menu {
display: block; display: block;
opacity: 1; opacity: 1;
visibility: visible;
} }
/* Ensure submenu remains visible when hovered over */ /* Dropdown-Menü bei der Klasse "open" anzeigen */
.dropdown-submenu:hover > .dropdown-menu:hover { .nav-item.dropdown.open > .dropdown-menu,
.dropdown-submenu.open > .dropdown-menu {
display: block; display: block;
opacity: 1; opacity: 1;
visibility: visible;
} }
/* Handle dynamic submenu positioning */ /* Positionierung von Submenüs */
.dropdown-submenu > .dropdown-menu[style*="right: 100%"] { .dropdown-submenu > .dropdown-menu {
left: auto; /* Override left position for leftward opening */ position: absolute;
top: 0;
left: 100%; /* Rechts ausklappen */
}
.dropdown-submenu.open > .dropdown-menu {
display: block;
opacity: 1;
visibility: visible;
} }

View File

@ -1,41 +1,53 @@
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const dropdownSubmenus = document.querySelectorAll('.dropdown-submenu'); const menuItems = document.querySelectorAll('.nav-item.dropdown, .dropdown-submenu');
dropdownSubmenus.forEach(submenu => { menuItems.forEach(item => {
let timeout; let timeout;
// Zeige das Submenü beim Hover // Öffnen beim Hovern
submenu.addEventListener('mouseenter', () => { item.addEventListener('mouseenter', () => {
clearTimeout(timeout); clearTimeout(timeout);
const menu = submenu.querySelector('.dropdown-menu'); openMenu(item);
if (menu) { });
// Dynamische Positionierung
const rect = menu.getBoundingClientRect();
const viewportWidth = window.innerWidth;
// Überprüfen, ob Platz nach rechts ist, sonst nach links öffnen // Verzögertes Schließen beim Verlassen
if (rect.right > viewportWidth) { item.addEventListener('mouseleave', () => {
menu.style.left = 'auto'; timeout = setTimeout(() => closeMenu(item), 500);
menu.style.right = '100%'; });
// 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 { } else {
menu.style.left = '100%'; openMenu(item);
menu.style.right = 'auto';
}
menu.style.display = 'block';
menu.style.opacity = '1';
} }
}); });
});
// Verstecke das Submenü nach 0.5 Sekunden // Globale Klick-Listener, um Menüs zu schließen, wenn außerhalb geklickt wird
submenu.addEventListener('mouseleave', () => { document.addEventListener('click', () => {
const menu = submenu.querySelector('.dropdown-menu'); menuItems.forEach(item => closeMenu(item));
if (menu) { });
timeout = setTimeout(() => {
menu.style.display = 'none'; function openMenu(item) {
menu.style.opacity = '0'; item.classList.add('open');
}, 500); // 0.5 Sekunden Verzögerung const submenu = item.querySelector('.dropdown-menu');
if (submenu) {
submenu.style.display = 'block';
submenu.style.opacity = '1';
submenu.style.visibility = 'visible';
}
}
function closeMenu(item) {
item.classList.remove('open');
const submenu = item.querySelector('.dropdown-menu');
if (submenu) {
submenu.style.display = 'none';
submenu.style.opacity = '0';
submenu.style.visibility = 'hidden';
}
} }
});
});
}); });

View File

@ -3,7 +3,7 @@
{% for subitem in subitems %} {% for subitem in subitems %}
{% if subitem.subitems %} {% if subitem.subitems %}
<li class="dropdown-submenu position-relative"> <li class="dropdown-submenu position-relative">
<a class="dropdown-item dropdown-toggle" href="#" title="{{ subitem.description }}"> <a class="dropdown-item dropdown-toggle" title="{{ subitem.description }}">
{% if subitem.icon is defined and subitem.icon.class is defined %} {% if subitem.icon is defined and subitem.icon.class is defined %}
<i class="{{ subitem.icon.class }}"></i> {{ subitem.name }} <i class="{{ subitem.icon.class }}"></i> {{ subitem.name }}
{% else %} {% else %}
@ -33,8 +33,7 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endmacro %} {% endmacro %}
<!-- Navigation Bar -->
<!-- Navigation Bar -->
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid"> <div class="container-fluid">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav{{menu_type}}" aria-controls="navbarNav{{menu_type}}" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav{{menu_type}}" aria-controls="navbarNav{{menu_type}}" aria-expanded="false" aria-label="Toggle navigation">
@ -53,14 +52,14 @@
{% else %} {% else %}
<!-- Dropdown Menu --> <!-- Dropdown Menu -->
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ loop.index }}" role="button" data-bs-toggle="dropdown" data-bs-display="dynamic" data-popper-placement="top" title="{{ item.description }}" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ loop.index }}" role="button" data-bs-toggle="dropdown" aria-expanded="false">
{% if item.icon is defined and item.icon.class is defined %} {% if item.icon is defined and item.icon.class is defined %}
<i class="{{ item.icon.class }}" data-bs-toggle="tooltip"></i> {{ item.name }} <i class="{{ item.icon.class }}"></i> {{ item.name }}
{% else %} {% else %}
<p>Missing icon in item: {{ item }}</p> <p>Missing icon in item: {{ item }}</p>
{% endif %} {% endif %}
</a> </a>
<ul class="dropdown-menu dropdown-menu-{{menu_type}}" aria-labelledby="navbarDropdown{{ loop.index }}"> <ul class="dropdown-menu">
{{ render_subitems(item.subitems) }} {{ render_subitems(item.subitems) }}
</ul> </ul>
</li> </li>