diff --git a/src/assets/css/style.css b/src/assets/css/style.css index a98f098..c62ad16 100644 --- a/src/assets/css/style.css +++ b/src/assets/css/style.css @@ -379,14 +379,29 @@ table.cell-table th { background-color: rgb(255 240 240 / 40%); } -/* Barre de défilement horizontale miroir, collée en haut */ +/* Barre de défilement horizontale, collée en haut au-dessus des en-têtes */ .marches_table .dt-hscroll { position: sticky; top: 0; z-index: 11; /* au-dessus des en-têtes sticky */ overflow-x: auto; overflow-y: hidden; - height: 14px; + height: 12px; + scrollbar-color: orange #e0e0e0; + scrollbar-width: thin; +} + +.marches_table .dt-hscroll::-webkit-scrollbar { + height: 12px; +} + +.marches_table .dt-hscroll::-webkit-scrollbar-thumb { + background-color: orange; + border-radius: 6px; +} + +.marches_table .dt-hscroll::-webkit-scrollbar-track { + background-color: #e0e0e0; } .marches_table .dt-hscroll-inner { @@ -397,14 +412,6 @@ table.cell-table th { display: none; } -/* Conteneur scrollable horizontal — overflow-y:clip ne crée pas de scroll container vertical */ -/* donc position:sticky sur th.dash-header reste calé sur la page */ -.marches_table .dt-scroll-wrapper { - overflow-x: auto; - overflow-y: clip; - width: 100%; -} - /* Column Visibility Menu */ .column-actions { margin-right: 8px; diff --git a/src/assets/table_hscroll.js b/src/assets/table_hscroll.js index 29bdaf7..3d518cd 100644 --- a/src/assets/table_hscroll.js +++ b/src/assets/table_hscroll.js @@ -12,45 +12,41 @@ // qui déclencherait rootObs et provoquerait une re-entrée dans setup(). wrapper.dataset.hscrollReady = "1"; - // Injecter le conteneur scrollable horizontal autour du conteneur Dash - const scrollWrapper = document.createElement("div"); - scrollWrapper.className = "dt-scroll-wrapper"; - dashContainer.parentNode.insertBefore(scrollWrapper, dashContainer); - scrollWrapper.appendChild(dashContainer); - - // Injecter la barre de défilement en haut, avant le wrapper scrollable const bar = document.createElement("div"); bar.className = "dt-hscroll is-hidden"; const inner = document.createElement("div"); inner.className = "dt-hscroll-inner"; bar.appendChild(inner); - wrapper.insertBefore(bar, scrollWrapper); + wrapper.insertBefore(bar, wrapper.firstChild); - // syncing évite les boucles dans la même pile d'exécution ; l'affectation de scrollLeft - // déclenche l'événement scroll de façon synchrone dans Chromium. + // La barre synchronise le scroll horizontal de la page (overflow: visible sur les + // conteneurs Dash laisse le scroll se faire au niveau de la page, ce qui permet + // aux en-têtes position:sticky de rester calés sur la fenêtre). + // syncing évite les boucles dans la même pile d'exécution. let syncing = false; const onBar = () => { if (syncing) return; syncing = true; - scrollWrapper.scrollLeft = bar.scrollLeft; + window.scrollTo(bar.scrollLeft, window.scrollY); syncing = false; }; - const onTable = () => { + const onPage = () => { if (syncing) return; syncing = true; - bar.scrollLeft = scrollWrapper.scrollLeft; + bar.scrollLeft = window.scrollX; syncing = false; }; bar.addEventListener("scroll", onBar); - scrollWrapper.addEventListener("scroll", onTable); + // SPA : ce listener est intentionnellement conservé pour toute la durée de vie de la page. + window.addEventListener("scroll", onPage); const refresh = () => { - const total = scrollWrapper.scrollWidth; - const visible = scrollWrapper.clientWidth; + const total = document.documentElement.scrollWidth; + const visible = window.innerWidth; inner.style.width = total + "px"; // +1 absorbe les erreurs d'arrondi sous-pixel bar.classList.toggle("is-hidden", total <= visible + 1); - bar.scrollLeft = scrollWrapper.scrollLeft; + bar.scrollLeft = window.scrollX; }; // Recalcule quand le tableau change (pagination, tri, filtre, données).