fix: admin — icône fermeture modale utilisateurs + sections du dashboard affichées une à la fois BUG-111
CI / lint (push) Successful in 2m54s
CI / security (push) Successful in 1m41s
CI / test (push) Successful in 4m36s
CI / build (push) Successful in 1m34s
CI / e2e (push) Successful in 17m56s

This commit is contained in:
2026-10-10 17:17:14 -04:00
parent 8662d23ec8
commit fd192df036
12 changed files with 47 additions and 51 deletions
+19 -38
View File
@@ -394,54 +394,35 @@ function _wireAuditFilters() {
}
}
// ── Section nav (scrollspy) ───────────────────────────────────────────
// ── Section nav (une seule section visible à la fois) ──────────────────
/**
* Wire the sticky section nav: smooth-scroll on click + highlight the section
* currently in view (IntersectionObserver). Falls back to default anchor jump
* if the observer is unavailable.
* Wire the sticky section nav: clicking a link shows ONLY that section
* (the others are hidden). The first section (Stats) is shown on load.
*/
function _wireSectionNav() {
const links = Array.from(document.querySelectorAll("#admin-subnav a"));
if (!links.length) return;
const targets = links
.map((a) => document.getElementById((a.getAttribute("href") || "#").slice(1)))
.filter(Boolean);
const sections = Array.from(document.querySelectorAll("#admin-main .admin-section"));
// Smooth scroll on click
links.forEach((a) => {
a.addEventListener("click", (e) => {
const href = a.getAttribute("href");
if (!href || !href.startsWith("#")) return;
const t = document.getElementById(href.slice(1));
if (!t) return;
e.preventDefault();
t.scrollIntoView({ behavior: "smooth", block: "start" });
});
});
// Scrollspy: mark the section currently at the top of the viewport
let active = null;
const setActive = (id) => {
if (active === id) return;
active = id;
const show = (id) => {
sections.forEach((s) => { s.style.display = s.id === id ? "" : "none"; });
links.forEach((l) => l.classList.toggle("active", l.getAttribute("href") === "#" + id));
};
if ("IntersectionObserver" in window) {
const io = new IntersectionObserver(
(entries) => {
entries.forEach((en) => {
if (en.isIntersecting) setActive(en.target.id);
});
},
{ rootMargin: "-64px 0px -70% 0px", threshold: 0 }
);
targets.forEach((t) => io.observe(t));
} else {
// Fallback: highlight the first section only (no scroll observation)
links[0] && links[0].classList.add("active");
}
links.forEach((a) => {
a.addEventListener("click", (e) => {
e.preventDefault();
const href = a.getAttribute("href") || "";
if (!href.startsWith("#")) return;
show(href.slice(1));
window.scrollTo({ top: 0, behavior: "smooth" });
});
});
// État initial : seule la section demandée par le hash (ou la première) est visible.
const initial = (location.hash && sections.find((s) => "#" + s.id === location.hash)) || sections[0];
if (initial) show(initial.id);
}
// ── Auth gate ────────────────────────────────────────────────────────────