This commit is contained in:
2025-12-22 09:07:01 +00:00
parent 094929a2db
commit fb78962fc1
3 changed files with 394 additions and 54 deletions

View File

@@ -135,4 +135,151 @@ html {
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* ============================================
MENU UNIQUE OUVERT - STYLES AMÉLIORÉS
============================================ */
/* Animation pour les sous-menus */
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
max-height: 0;
}
to {
opacity: 1;
transform: translateY(0);
max-height: 500px;
}
}
@keyframes slideUp {
from {
opacity: 1;
transform: translateY(0);
max-height: 500px;
}
to {
opacity: 0;
transform: translateY(-10px);
max-height: 0;
}
}
/* Styles pour les sous-menus */
.nav-submenu {
max-height: 0;
overflow: hidden;
display: none;
transition: max-height 0.3s ease, opacity 0.3s ease;
}
.nav-submenu.show {
display: block;
animation: slideDown 0.3s ease forwards;
}
.nav-submenu:not(.show) {
animation: slideUp 0.3s ease forwards;
}
/* Indicateur visuel pour le menu actif */
.nav-link.active {
background-color: rgba(255, 255, 255, 0.15) !important;
color: white !important;
font-weight: 500 !important;
position: relative;
}
.nav-link.active::after {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 3px;
height: 60%;
background-color: white;
border-radius: 0 2px 2px 0;
}
/* Flèche du menu */
.nav-arrow {
transition: transform 0.3s ease;
margin-left: auto;
}
.nav-link[aria-expanded="true"] .nav-arrow {
transform: rotate(90deg);
}
.nav-link[aria-expanded="false"] .nav-arrow {
transform: rotate(0deg);
}
/* Hover amélioré */
.nav-link:hover:not(.active) {
background-color: rgba(255, 255, 255, 0.08) !important;
}
/* Transition fluide pour les sous-menus actifs */
.nav-submenu[data-parent-id].show {
background-color: rgba(0, 0, 0, 0.1);
border-radius: 6px;
margin: 4px 16px 4px 16px;
}
/* Élément actif dans le sous-menu */
.nav-submenu .nav-link.active {
background-color: rgba(255, 255, 255, 0.2) !important;
font-weight: 600 !important;
}
/* ============================================
RESPONSIVE - MENU MOBILE
============================================ */
@media (max-width: 768px) {
.nav-submenu.show {
animation: slideDown 0.2s ease forwards;
}
.nav-submenu:not(.show) {
animation: slideUp 0.2s ease forwards;
}
/* Masquer les sous-menus par défaut sur mobile */
.app-sidebar:not(.mobile-open) .nav-submenu {
display: none !important;
}
.app-sidebar.mobile-open .nav-submenu.show {
display: block !important;
}
}
/* ============================================
ACCESSIBILITÉ AMÉLIORÉE
============================================ */
.nav-link:focus {
outline: 2px solid rgba(255, 255, 255, 0.6);
outline-offset: -2px;
}
.nav-submenu .nav-link:focus {
outline-offset: -4px;
}
/* Focus visible pour navigation clavier */
.nav-link:focus-visible {
outline: 3px solid rgba(255, 255, 255, 0.8);
outline-offset: 2px;
}
/* Indicateur pour menu ouvert au clavier */
.nav-link[aria-expanded="true"]:focus {
background-color: rgba(255, 255, 255, 0.2) !important;
}

View File

@@ -81,60 +81,85 @@ class UXManager {
}
}
// Navigation Manager - Gestion des menus
// Navigation Manager - Gestion des menus (VERSION CORRIGÉE)
class NavigationManager {
constructor() {
this.currentOpenMenu = null;
this.activeMenuId = null; // Menu actif basé sur la page courante
}
init() {
this.setupActiveMenu();
this.setupMenuBehavior();
this.setupKeyboardNavigation();
this.setupActiveMenu();
}
setupActiveMenu() {
// Déterminer le menu actif basé sur la page courante
const activeParentId = window.appConfig?.activeParentId;
const activeLink = window.appConfig?.activeLink;
console.log('[Navigation] Page active:', activeLink, 'Parent ID:', activeParentId);
if (activeParentId !== null && activeParentId !== '') {
this.activeMenuId = `submenu${activeParentId}`;
console.log('[Navigation] Menu actif détecté:', this.activeMenuId);
// Ouvrir seulement le menu actif
setTimeout(() => {
this.openMenu(this.activeMenuId);
this.currentOpenMenu = this.activeMenuId;
}, 100);
} else {
console.log('[Navigation] Aucun menu actif détecté');
// Fermer tous les menus par défaut
this.closeAllMenus();
}
}
setupMenuBehavior() {
// Désactiver le comportement Bootstrap par défaut
// Pour chaque lien de menu avec sous-menu
document.querySelectorAll('.nav-link[data-bs-toggle="collapse"]').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
const targetId = link.getAttribute('href').substring(1);
this.toggleMenu(targetId, e);
console.log('[Navigation] Clic sur menu:', targetId);
// Si on clique sur le menu déjà ouvert, on le ferme
if (this.currentOpenMenu === targetId) {
this.closeMenu(targetId);
this.currentOpenMenu = null;
} else {
// Fermer le menu précédent si différent
if (this.currentOpenMenu && this.currentOpenMenu !== targetId) {
this.closeMenu(this.currentOpenMenu);
}
// Ouvrir le nouveau menu
this.openMenu(targetId);
this.currentOpenMenu = targetId;
}
});
});
// Fermer le menu en cliquant ailleurs
// Fermer les menus en cliquant ailleurs
document.addEventListener('click', (e) => {
if (!e.target.closest('.app-sidebar')) {
this.closeAllMenus();
// Ne pas fermer le menu actif s'il correspond à la page courante
if (this.currentOpenMenu !== this.activeMenuId) {
this.closeAllMenus();
}
}
});
}
toggleMenu(menuId, event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
const menu = document.getElementById(menuId);
const link = document.querySelector(`[href="#${menuId}"]`);
if (!menu || !link) return;
// Si ce menu est déjà ouvert, le fermer
if (this.currentOpenMenu === menuId) {
this.closeMenu(menuId);
this.currentOpenMenu = null;
} else {
// Fermer le menu actuellement ouvert
if (this.currentOpenMenu) {
this.closeMenu(this.currentOpenMenu);
}
// Ouvrir le nouveau menu
this.openMenu(menuId);
this.currentOpenMenu = menuId;
}
// Empêcher la fermeture du menu actif
document.querySelectorAll('.nav-submenu').forEach(menu => {
menu.addEventListener('click', (e) => {
e.stopPropagation();
});
});
}
openMenu(menuId) {
@@ -142,10 +167,29 @@ class NavigationManager {
const link = document.querySelector(`[href="#${menuId}"]`);
if (menu && link) {
// Retirer 'show' de tous les autres menus
document.querySelectorAll('.nav-submenu.show').forEach(otherMenu => {
if (otherMenu.id !== menuId) {
otherMenu.classList.remove('show');
const otherLink = document.querySelector(`[href="#${otherMenu.id}"]`);
if (otherLink) {
otherLink.setAttribute('aria-expanded', 'false');
otherLink.classList.remove('active');
const arrow = otherLink.querySelector('.nav-arrow');
if (arrow) arrow.style.transform = 'rotate(0deg)';
}
}
});
// Ouvrir le menu sélectionné
menu.classList.add('show');
link.classList.add('active');
link.setAttribute('aria-expanded', 'true');
link.querySelector('.nav-arrow').style.transform = 'rotate(90deg)';
link.classList.add('active');
const arrow = link.querySelector('.nav-arrow');
if (arrow) arrow.style.transform = 'rotate(90deg)';
console.log('[Navigation] Menu ouvert:', menuId);
}
}
@@ -154,19 +198,35 @@ class NavigationManager {
const link = document.querySelector(`[href="#${menuId}"]`);
if (menu && link) {
// Ne pas fermer le menu actif si c'est celui de la page courante
if (menuId === this.activeMenuId) {
console.log('[Navigation] Menu actif, ne pas fermer:', menuId);
return;
}
menu.classList.remove('show');
link.classList.remove('active');
link.setAttribute('aria-expanded', 'false');
link.querySelector('.nav-arrow').style.transform = 'rotate(0deg)';
link.classList.remove('active');
const arrow = link.querySelector('.nav-arrow');
if (arrow) arrow.style.transform = 'rotate(0deg)';
console.log('[Navigation] Menu fermé:', menuId);
}
}
closeAllMenus() {
// Ne fermer que les menus qui ne sont pas actifs
document.querySelectorAll('.nav-submenu.show').forEach(menu => {
const menuId = menu.id;
this.closeMenu(menuId);
if (menu.id !== this.activeMenuId) {
this.closeMenu(menu.id);
}
});
this.currentOpenMenu = null;
// Si aucun menu actif, réinitialiser
if (!this.activeMenuId) {
this.currentOpenMenu = null;
}
}
setupKeyboardNavigation() {
@@ -197,16 +257,15 @@ class NavigationManager {
}
}
setupActiveMenu() {
// Ouvrir automatiquement le menu actif au chargement
const activeParentId = window.appConfig.activeParentId;
if (activeParentId !== null && activeParentId !== '') {
const menuId = `submenu${activeParentId}`;
setTimeout(() => {
this.openMenu(menuId);
this.currentOpenMenu = menuId;
}, 100);
}
// Méthode publique pour forcer l'ouverture d'un menu
openMenuById(menuId) {
this.openMenu(menuId);
this.currentOpenMenu = menuId;
}
// Méthode publique pour forcer la fermeture
closeAllExceptActive() {
this.closeAllMenus();
}
}