feat: add Nimbus UI mode with adaptive scrollbars and layout improvements

This commit is contained in:
2025-10-15 11:57:32 -04:00
parent 5a95b33081
commit 55a7a06daa
29 changed files with 1669 additions and 36 deletions
+209
View File
@@ -0,0 +1,209 @@
/* ===============================
Overlay Scrollbar — Cross-browser (Edge/Firefox/Chrome/Safari)
Fichier : _overlay-scrollbar.css
=============================== */
/* ---------- Thèmes & variables ---------- */
:root {
/* Couleurs (clair) */
--ovsb-track-bg: rgba(15, 23, 42, 0.12);
--ovsb-thumb-bg: rgba(100, 116, 139, 0.55);
--ovsb-thumb-bg-active: rgba(59, 130, 246, 0.75);
/* Géométrie & transitions */
--ovsb-trans: 240ms ease;
--ovsb-right: 2px; /* Décalage à droite de l’overlay */
--ovsb-thumb-height: 24px; /* Hauteur mini du thumb */
/* Épaisseurs / états
Astuce : on anime l’épaisseur via scaleX pour éviter les changements de hit-area.
Le track garde une largeur de hit-test stable. */
--ovsb-active-width: 10px; /* largeur visuelle en état "active" */
--ovsb-mini-width: 2px; /* largeur visuelle en état "mini" */
/* Ratio (mini vs active) → sert à scaleX. Si vous modifiez les largeurs, adaptez ce ratio. */
--ovsb-mini-scale: 0.2; /* 2 / 10 = 0.2 */
}
.dark,
[data-theme="dark"] {
--ovsb-track-bg: rgba(148, 163, 184, 0.28);
--ovsb-thumb-bg: rgba(226, 232, 240, 0.72);
--ovsb-thumb-bg-active: rgba(241, 245, 249, 0.92);
}
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
.ovsb,
.ovsb__root,
.ovsb__track,
.ovsb__thumb {
transition: none !important;
}
}
/* ========================================
1) Conteneur scrollable (hôte de l’overlay)
======================================== */
/* IMPORTANT : appliquer .ovsb-host sur l’élément QUI SCROLLE réellement */
.ovsb-host {
position: relative; /* nécessaire pour positionner l’overlay en absolute */
overflow: auto; /* c’est bien LUI qui scrolle */
/* Masquer la scrollbar native (Firefox + Edge/Chrome/Safari) */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* Edge/IE legacy */
}
.ovsb-host::-webkit-scrollbar {
width: 0 !important; /* Chrome/Edge/Safari */
height: 0 !important;
background: transparent !important;
}
.ovsb-host::-webkit-scrollbar-thumb,
.ovsb-host::-webkit-scrollbar-track,
.ovsb-host::-webkit-scrollbar-corner {
background: transparent !important;
border: none !important;
}
/* Cas où le DOCUMENT scrolle (évitez si possible). Décommentez si nécessaire. */
/*
html, body {
scrollbar-width: none;
-ms-overflow-style: none;
}
html::-webkit-scrollbar,
body::-webkit-scrollbar {
width: 0 !important;
height: 0 !important;
}
*/
/* Si vous décidez de garder la native (non recommandé ici), stabilisez le gutter : */
/*
@supports (scrollbar-gutter: stable) {
.ovsb-host-native {
scrollbar-gutter: stable both-edges;
}
}
*/
/* ========================================
2) Overlay (track + thumb)
======================================== */
/* Racine overlay : ne capture pas les events hors track/thumb */
.ovsb {
position: absolute;
top: 0;
right: var(--ovsb-right);
bottom: 0;
width: 12px; /* largeur de HIT-TEST stable (garde la zone de survol constante) */
pointer-events: none; /* la racine ne capte pas, on laisse le contenu défiler naturellement */
z-index: 10;
contain: layout paint; /* isolation pour perf */
}
/* Nœud interne (utile si vous voulez des wrappers) */
.ovsb__root {
position: absolute;
inset: 0;
}
/* Piste (track) — zone cliquable/drag */
.ovsb__track {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 12px; /* hit-area stable */
border-radius: 9999px;
background: var(--ovsb-track-bg);
opacity: 0; /* géré par états */
pointer-events: auto; /* le track doit capter pour hover/drag */
transition: opacity var(--ovsb-trans);
will-change: opacity;
}
/* Thumb (manette) — épaisseur animée via scaleX (pas de shift) */
.ovsb__thumb {
position: absolute;
top: 0; /* la position Y est appliquée via transform translateY */
right: 1px; /* léger décalage pour équilibre visuel */
width: var(--ovsb-active-width);
height: var(--ovsb-thumb-height);
border-radius: 9999px;
background: var(--ovsb-thumb-bg);
/* Position & épaisseur animées :
translateY: mis à jour dynamiquement (via style inline ou CSS var)
scaleX: mini/active
*/
transform: translateY(var(--ovsb-thumb-y, 0px)) scaleX(var(--ovsb-mini-scale));
transform-origin: right center;
transition: transform var(--ovsb-trans), background-color var(--ovsb-trans), opacity var(--ovsb-trans);
opacity: 0; /* masqué par défaut */
pointer-events: auto; /* doit capter pour le drag */
will-change: transform, opacity, background-color;
cursor: grab;
}
.ovsb__thumb:active {
cursor: grabbing;
}
/* ========================================
3) États (Hidden / Mini / Active)
======================================== */
/* HIDDEN : invisible, aucune interactivité */
.ovsb--hidden .ovsb__track,
.ovsb--hidden .ovsb__thumb {
opacity: 0;
pointer-events: none; /* rien ne capte, laisse le contenu réagir librement */
}
/* MINI : visible, thumb mince (scaleX mini), track discret */
.ovsb--mini .ovsb__track {
opacity: 1;
}
.ovsb--mini .ovsb__thumb {
opacity: 1;
background: var(--ovsb-thumb-bg);
transform: translateY(var(--ovsb-thumb-y, 0px)) scaleX(var(--ovsb-mini-scale));
}
/* ACTIVE : au survol de la zone scrollbar → thumb plus épais + couleur active */
.ovsb--active .ovsb__track {
opacity: 1;
}
.ovsb--active .ovsb__thumb {
opacity: 1;
background: var(--ovsb-thumb-bg-active);
transform: translateY(var(--ovsb-thumb-y, 0px)) scaleX(1);
}
/* Hover direct sur la zone track → active visuelle (utile en desktop) */
.ovsb__track:hover ~ .ovsb__thumb,
.ovsb__thumb:hover {
background: var(--ovsb-thumb-bg-active);
}
/* ========================================
4) Divers (compat & accessibilité visuelle)
======================================== */
/* Améliore la réactivité GPU (Edge/Chrome) */
.ovsb__track,
.ovsb__thumb {
backface-visibility: hidden;
}
/* Quand overlay affiché, éviter le scroll chaining vers parent si souhaité */
.ovsb-host {
overscroll-behavior: contain;
}
/* Cas tactile : permettre drag propre sans scroll involontaire horizontal */
.ovsb__thumb,
.ovsb__track {
touch-action: none;
}