Version 2026.5.37 — Refonte vue horizontale (sidebar complète)

- Topbar supprimée, user-badge + titre déplacés en sidebar
- Bouton Aujourd'hui pleine largeur, stats empilées
- Banderole pompier masquée en vue horizontale
This commit is contained in:
2026-04-25 18:00:00 +02:00
parent cd54764dd5
commit 0fbc1997bb
3 changed files with 501 additions and 27 deletions
+218
View File
@@ -1075,6 +1075,224 @@ function _applyViewMode() {
// Mettre à jour la classe sur <html> pour les règles CSS
document.documentElement.classList.remove("view-classic", "view-horizontal");
document.documentElement.classList.add("view-" + mode);
// Liste des IDs à déplacer entre topbar (classique) et sidebar (horizontal)
// Ordre = ordre visuel dans la sidebar en mode horizontal (haut → bas)
// v2026.5.37 : user-badge, app-title, theme-toggle déplacés aussi → la topbar
// devient vide en vue horizontale.
const ELEMENTS_TO_RELOCATE = [
"user-badge", // tout en haut de la sidebar
"app-title", // juste après user-badge
"date-nav", // (pas un id mais une classe, traité à part)
"app-clock",
"capture-info",
"stats", // conteneur stats globales (généré dynamiquement)
"absence-btn",
"douchette-btn",
"refresh-partial-btn",
"refresh-btn",
"abort-btn",
"clear-cache-btn",
"theme-toggle" // tout en bas de la sidebar
];
if (mode === "horizontal") {
_moveElementsToSidebar(ELEMENTS_TO_RELOCATE);
} else {
_restoreElementsToTopbar(ELEMENTS_TO_RELOCATE);
}
console.log(`[viewMode] application terminée (mode=${mode})`);
}
/**
* v2026.5.36 : crée ou retrouve la sidebar, et y déplace les éléments listés.
* Les éléments sont déplacés dans l'ordre du tableau.
*/
function _moveElementsToSidebar(ids) {
// Créer (ou retrouver) le wrapper qui contiendra sidebar + main côte à côte
let wrapper = document.getElementById("horizontal-wrapper");
const mainEl = document.getElementById("main");
if (!wrapper) {
wrapper = document.createElement("div");
wrapper.id = "horizontal-wrapper";
wrapper.className = "horizontal-wrapper";
// Placer le wrapper à la place de <main>, puis mettre <main> DEDANS
if (mainEl && mainEl.parentNode) {
mainEl.parentNode.insertBefore(wrapper, mainEl);
wrapper.appendChild(mainEl);
console.log("[viewMode] wrapper créé, <main> encapsulé");
} else {
console.warn("[viewMode] <main> introuvable, wrapper ajouté à <body>");
document.body.appendChild(wrapper);
}
}
// Créer la sidebar si elle n'existe pas, et la mettre EN PREMIER dans le wrapper
let sidebar = document.getElementById("horizontal-sidebar");
if (!sidebar) {
sidebar = document.createElement("aside");
sidebar.id = "horizontal-sidebar";
sidebar.className = "horizontal-sidebar";
wrapper.insertBefore(sidebar, wrapper.firstChild);
console.log("[viewMode] sidebar créée et insérée en tête du wrapper");
} else if (sidebar.parentNode !== wrapper) {
// Sidebar existe ailleurs, on la remet dans le wrapper
wrapper.insertBefore(sidebar, wrapper.firstChild);
}
// Traitement spécial : .date-nav (classe, pas id)
// v2026.5.37 : en vue horizontale, on décompose .date-nav pour :
// - Mettre btn-today en haut
// - Intercaler app-clock entre btn-today et date-custom
// - Grouper les 2 flèches dans un wrapper #sidebar-arrows pour qu'elles
// soient côte à côte et même largeur
const dateNav = document.querySelector(".date-nav");
if (dateNav) {
_memorizeOriginalParent(dateNav);
sidebar.appendChild(dateNav);
console.log("[viewMode] déplacé dans sidebar : .date-nav");
// Créer le wrapper des flèches si pas déjà fait, et y mettre prev + next
let arrowsWrap = document.getElementById("sidebar-arrows");
if (!arrowsWrap) {
arrowsWrap = document.createElement("div");
arrowsWrap.id = "sidebar-arrows";
sidebar.appendChild(arrowsWrap);
console.log("[viewMode] wrapper flèches #sidebar-arrows créé");
}
const prevBtn = document.getElementById("nav-prev");
const nextBtn = document.getElementById("nav-next");
if (prevBtn && !arrowsWrap.contains(prevBtn)) {
_memorizeOriginalParent(prevBtn);
arrowsWrap.appendChild(prevBtn);
}
if (nextBtn && !arrowsWrap.contains(nextBtn)) {
_memorizeOriginalParent(nextBtn);
arrowsWrap.appendChild(nextBtn);
}
}
// Pour chaque ID listé, trouver et déplacer
for (const id of ids) {
if (id === "date-nav") continue; // déjà traité
const el = document.getElementById(id);
if (!el) {
console.log(`[viewMode] élément #${id} introuvable (optionnel) — skip`);
continue;
}
_memorizeOriginalParent(el);
sidebar.appendChild(el);
console.log(`[viewMode] déplacé dans sidebar : #${id}`);
}
}
/**
* v2026.5.36 : restaure chaque élément à son parent d'origine (mémorisé dans
* data-orig-parent). Utilisé quand on revient en vue classique.
*/
function _restoreElementsToTopbar(ids) {
// v2026.5.37 : d'abord remettre les flèches dans .date-nav (avant de
// restaurer .date-nav à son parent d'origine), puis supprimer le wrapper
// #sidebar-arrows.
const dateNav = document.querySelector(".date-nav");
const prevBtn = document.getElementById("nav-prev");
const nextBtn = document.getElementById("nav-next");
if (dateNav && prevBtn && !dateNav.contains(prevBtn)) {
// Remettre prev en premier dans date-nav
dateNav.insertBefore(prevBtn, dateNav.firstChild);
}
if (dateNav && nextBtn && !dateNav.contains(nextBtn)) {
// Remettre next après date-custom-wrapper (position d'origine) :
// l'ordre d'origine est [prev, date-custom-wrapper, next, today].
const dateCustomWrap = dateNav.querySelector(".date-custom-wrapper");
if (dateCustomWrap && dateCustomWrap.nextSibling) {
dateNav.insertBefore(nextBtn, dateCustomWrap.nextSibling);
} else {
dateNav.appendChild(nextBtn);
}
}
// Supprimer le wrapper des flèches (normalement vide maintenant)
const arrowsWrap = document.getElementById("sidebar-arrows");
if (arrowsWrap) {
arrowsWrap.remove();
console.log("[viewMode] wrapper #sidebar-arrows supprimé");
}
// Restaurer .date-nav à son parent d'origine
if (dateNav) _restoreToOriginalParent(dateNav, ".date-nav");
for (const id of ids) {
if (id === "date-nav") continue;
const el = document.getElementById(id);
if (!el) continue;
_restoreToOriginalParent(el, "#" + id);
}
// Supprimer la sidebar si elle existe et est vide
const sidebar = document.getElementById("horizontal-sidebar");
if (sidebar && sidebar.children.length === 0) {
sidebar.remove();
console.log("[viewMode] sidebar supprimée (vide)");
}
// Sortir <main> du wrapper et supprimer le wrapper
const wrapper = document.getElementById("horizontal-wrapper");
if (wrapper) {
const mainEl = wrapper.querySelector("#main");
if (mainEl && wrapper.parentNode) {
wrapper.parentNode.insertBefore(mainEl, wrapper);
console.log("[viewMode] <main> restauré hors du wrapper");
}
wrapper.remove();
console.log("[viewMode] wrapper supprimé");
}
}
function _memorizeOriginalParent(el) {
if (el.dataset.origParent) return; // déjà mémorisé
const parent = el.parentNode;
if (!parent || !parent.id) {
// Parent sans id : on mémorise par selector (parent tag + classes)
let selector = parent.tagName.toLowerCase();
if (parent.className) {
const cls = parent.className.split(/\s+/)[0];
if (cls) selector += "." + cls;
}
el.dataset.origParent = "SEL:" + selector;
} else {
el.dataset.origParent = "ID:" + parent.id;
}
// Mémoriser aussi l'index d'origine pour restaurer l'ordre
const siblings = Array.from(parent.children);
el.dataset.origIndex = String(siblings.indexOf(el));
}
function _restoreToOriginalParent(el, label) {
const orig = el.dataset.origParent;
if (!orig) {
console.log(`[viewMode] ${label} n'a pas de parent d'origine mémorisé — skip`);
return;
}
let parent = null;
if (orig.startsWith("ID:")) {
parent = document.getElementById(orig.substring(3));
} else if (orig.startsWith("SEL:")) {
parent = document.querySelector(orig.substring(4));
}
if (!parent) {
console.warn(`[viewMode] parent d'origine pour ${label} introuvable (orig=${orig})`);
return;
}
// Insérer à l'index d'origine si possible
const idx = parseInt(el.dataset.origIndex || "0", 10);
const refChild = parent.children[idx] || null;
if (refChild && refChild !== el) {
parent.insertBefore(el, refChild);
} else {
parent.appendChild(el);
}
console.log(`[viewMode] restauré à ${orig} : ${label}`);
}
// v5.0.0 : horloge HH:MM au milieu de la topbar. Mise à jour toutes les 30s