v2026.5.39 — Séparation matin/après-midi + Apparence (thème, taille, cache, heures) + À propos

Séparation matin / après-midi
- Pill "MATIN" / "APRÈS-MIDI" entre interventions (vue classique), grise
  neutre, ligne 3px épaisse. Affiché aussi entre les absences partielles.
- Si une période est vide, son séparateur n'apparaît pas.

Timeline — coupure midi très visible
- Bande verticale composée d'un trait massif + stripes diagonales (effet
  césure). Visible immédiatement, sans label superflu.

Vue horizontale (sidebar)
- Tout centré horizontalement (align-items + text-align)
- min-height: calc(100vh * --zoom-inv) — sidebar atteint toujours le bas
  de l'écran, même quand le user dézoom le texte
- Bouton "Aujourd'hui" : style identique aux autres boutons (Absence,
  Douchette...), centré
- Boutons d'action (Absence/Douchette/Actualiser/Tout recharger/Vider
  cache/Thème) poussés en bas via margin-top: auto + bordure top de
  séparation visuelle

Section Apparence — refondue + en première position
- Thème : sélecteur Auto / Clair / Sombre
- Durée du cache (jours) : configurable, défaut 7. Lue par viewer (purge
  auto en cas de quota) ET background (au boot). Tooltip au survol qui
  montre l'emplacement physique du cache (adapté browser + OS)
- Taille du texte : slider horizontal avec 5 dots, 5 paliers (-30%, -15%,
  100%, +10%, +20%). Zoom appliqué uniquement au release (pas pendant le
  drag) pour éviter l'effet yo-yo. Couvre TOUS les textes visibles
  (interventions, popups, absences, réservations, "En pompier du...",
  date+heure de la même taille, etc.)
- Heures de la journée : 2 inputs Début/Fin, défaut 8h-18h. Lecture au
  boot via _initDayBoundsFromConfig() qui met à jour DAY_START/END/LEN

Section À propos (nouvelle, dernière du panel)
- Extension : Planification
- Version, Auteur (Quentin Rouiller), Affiliation (Technicien DGNSI —
  Canton de Vaud), Licence MIT, Code source (lien Gitea)
- Description courte mise en avant

Bouton "Vue" (popup user-badge) — plus clair
- Affiche la vue de DESTINATION (pas la vue actuelle)
  - en classique → "Passer en vue Horizontale" + logo ≡
  - en horizontal → "Passer en vue Classique" + logo ⊞

Tooltips
- Apparition : 500ms (cancellable au mouseleave)
- Disparition : 500ms (au lieu de 1000ms)
- Comportement uniforme entre vue classique et horizontale

Stats
- "X tech. dispo" (nouveau) : disponibles = pas absent + pas réservé
  toute la journée. Pompier compte comme disponible.
This commit is contained in:
2026-04-26 02:20:00 +02:00
parent c9363c64b6
commit a5dc0b3365
5 changed files with 874 additions and 58 deletions
+368 -23
View File
@@ -144,6 +144,17 @@ html, body {
min-width: 0;
}
/* v2026.5.39 r2 : on verrouille l'ordre des élements de la topbar gauche en
vue classique. Le badge user reste à l'extrême gauche, le titre suit, puis
la nav date et enfin la capture-info. Ce verrou évite que des composants
restaurés depuis la sidebar (vue horizontale → classique) finissent dans
le mauvais ordre. */
html.view-classic .topbar-left #user-badge { order: 1; }
html.view-classic .topbar-left #app-title { order: 2; }
html.view-classic .topbar-left .date-nav { order: 3; }
html.view-classic .topbar-left .capture-info { order: 4; }
html.view-classic .topbar-left #refresh-check { order: 5; }
.topbar h1 {
margin: 0;
font-size: 18px;
@@ -761,14 +772,40 @@ html, body {
z-index: 2;
}
/* v2026.5.39 r3 : séparateur "midi" — vraie coupure visuelle.
La timeline-bar a overflow:hidden donc les chevrons qui dépassaient en
haut/bas étaient coupés. On reste DANS la bar mais on rend le trait
massif et fortement contrasté + un effet "encoche" via box-shadow latéral
(pour bien détacher du fond), et on superpose une bande à stripes
diagonales sur 6px de large pour signaler la pause de midi.
Z-index élevé pour passer au-dessus des segments. */
.timeline-noon {
position: absolute;
top: -2px;
bottom: -2px;
width: 1px;
background: var(--border-strong);
z-index: 1;
top: 0;
bottom: 0;
width: 6px;
z-index: 3;
pointer-events: none;
transform: translateX(-3px); /* centrer la bande sur 12h */
background:
/* trait central massif : */
linear-gradient(to right,
transparent 0%, transparent 30%,
var(--text) 30%, var(--text) 70%,
transparent 70%, transparent 100%),
/* fond stripes diagonales pour signaler "césure" : */
repeating-linear-gradient(
45deg,
var(--bg-muted) 0 3px,
var(--text-muted) 3px 4px
);
opacity: 0.95;
}
/* En vue horizontale, timeline-bar est plus haute (22px au lieu de 20px),
on garde le même trait mais légèrement plus large pour la visibilité. */
html.view-horizontal .timeline-noon {
width: 7px;
transform: translateX(-3.5px);
}
.timeline-scale {
@@ -3849,9 +3886,10 @@ html.view-horizontal body > header.topbar {
}
/* 2. Sidebar : structure verticale avec section fixe en haut (user+titre+date)
et section "boutons" en bas poussée via margin-top: auto. */
et section "boutons" en bas poussée via margin-top: auto.
v2026.5.39 r8 : max-height retiré (était en conflit avec min-height
compensé par --zoom-inv quand le user dézoom le texte). */
html.view-horizontal .horizontal-sidebar {
max-height: 100vh !important;
padding-top: 12px !important;
}
@@ -3879,23 +3917,14 @@ html.view-horizontal .horizontal-sidebar #app-title {
html.view-horizontal .horizontal-sidebar .date-nav {
display: contents;
}
/* Le bouton Aujourd'hui devient prominent */
/* Bouton Aujourd'hui — v2026.5.39 r5 : MÊME style que Absence/Douchette
en sidebar. Hérite de la règle générique button.btn (padding/font-size).
On force juste centrage du texte. */
html.view-horizontal .horizontal-sidebar .btn-today {
order: 1; /* tout en haut après titre */
order: 1; /* tout en haut après titre */
width: 100% !important;
justify-content: center !important; /* centrage du label */
text-align: center !important;
padding: 8px 12px !important;
font-size: 13px !important;
font-weight: 600 !important;
background: var(--bg) !important;
border: 1px solid var(--border) !important;
border-radius: 6px !important;
color: var(--text) !important;
justify-content: center !important;
}
html.view-horizontal .horizontal-sidebar .btn-today::before {
content: "↺ ";
margin-right: 4px;
}
/* 5. App-clock (date + heure) centré sous le bouton "Aujourd'hui" */
@@ -3957,10 +3986,24 @@ html.view-horizontal .horizontal-sidebar .capture-info {
}
/* 10. Boutons poussés en bas via margin-top: auto sur le premier d'entre eux
(Absence, qui a order:7) */
(Absence, qui a order:7).
v2026.5.39 r2 : ajout d'une fine bordure top + padding pour visualiser
clairement la séparation entre la zone "info" (capture-info, stats) et
la zone "actions" (boutons). margin-top: auto pousse en bas. */
html.view-horizontal .horizontal-sidebar #absence-btn {
order: 7;
margin-top: auto !important; /* pousse tout ce qui suit en bas */
padding-top: 8px !important; /* respiration au-dessus du bouton */
position: relative;
}
html.view-horizontal .horizontal-sidebar #absence-btn::before {
content: "";
position: absolute;
top: 0;
left: 4px;
right: 4px;
height: 1px;
background: var(--border);
}
html.view-horizontal .horizontal-sidebar #douchette-btn { order: 8; }
html.view-horizontal .horizontal-sidebar #refresh-partial-btn { order: 9; }
@@ -3982,11 +4025,39 @@ html.view-horizontal .horizontal-sidebar #theme-toggle {
justify-content: center !important;
}
/* 12. Sidebar doit être flex column pour que margin-top:auto fonctionne */
/* 12. Sidebar doit être flex column pour que margin-top:auto fonctionne.
v2026.5.39 r3 : on force min-height: 100vh.
v2026.5.39 r5 : tout est centré horizontalement (text-align + align-items).
v2026.5.39 r8 : on compense le body.zoom via --zoom-inv. À 75% de zoom,
100vh ne couvre que 75% de la viewport effective ; on multiplie donc par
l'inverse du zoom pour que la sidebar atteigne TOUJOURS le bas de l'écran. */
html.view-horizontal .horizontal-sidebar {
display: flex !important;
flex-direction: column !important;
align-items: center !important; /* centrage horizontal des enfants */
text-align: center !important; /* centrage des textes */
gap: 6px !important;
min-height: calc(100vh * var(--zoom-inv, 1)) !important;
box-sizing: border-box !important;
}
/* Tous les enfants directs reçoivent text-align: center par héritage,
mais on force aussi sur les boutons (qui ont parfois justify-content:
flex-start) et les blocs de stats. */
html.view-horizontal .horizontal-sidebar > * {
text-align: center !important;
}
html.view-horizontal .horizontal-sidebar button.btn {
justify-content: center !important;
}
html.view-horizontal .horizontal-sidebar #stats .global-stat {
text-align: center !important;
}
html.view-horizontal .horizontal-sidebar .app-clock {
align-items: center !important;
text-align: center !important;
}
html.view-horizontal .horizontal-sidebar .date-custom {
justify-content: center !important;
}
/* 13. Barre de rafraîchissement en vue horizontale : overlay par-dessus
@@ -4030,3 +4101,277 @@ html.view-horizontal .card-status-note.pompier {
letter-spacing: 0.2px;
user-select: none;
}
/* ==========================================================================
v2026.5.39 : Séparateur Matin / Après-midi entre les interventions
Affiché entre les rows .intervention-v2 dans la vue classique. La ligne
est marquée (pas un simple text), avec un label dans une "pill" centrée
sur une fine barre horizontale qui traverse la card.
Caché automatiquement en vue horizontale (les rows .intervention-v2 sont
masquées dans cette vue, donc le séparateur le serait visuellement seul).
========================================================================== */
.day-period-sep {
display: flex;
align-items: center;
gap: 10px;
margin: 14px 0 8px 0;
padding: 0 6px;
position: relative;
user-select: none;
}
/* v2026.5.39 r2 : ligne plus épaisse (3px), continue, sans dégradé. */
.day-period-sep::before,
.day-period-sep::after {
content: "";
flex: 1 1 auto;
height: 3px;
background: var(--border-strong);
border-radius: 2px;
}
/* v2026.5.39 r2 : style neutre — pas de couleur ambre/bleu. */
.day-period-sep .day-period-label {
flex: 0 0 auto;
font-size: 12px;
font-weight: 700;
letter-spacing: 1.4px;
text-transform: uppercase;
color: var(--text-muted);
background: var(--bg-muted);
border: 1px solid var(--border-strong);
border-radius: 14px;
padding: 4px 14px;
white-space: nowrap;
}
/* Premier séparateur : pas de marge top excessive (juste après les stats) */
.card-stats + .day-period-sep {
margin-top: 8px;
}
/* Vue horizontale : la liste détaillée est masquée donc le séparateur aussi */
html.view-horizontal .day-period-sep {
display: none !important;
}
/* ==========================================================================
v2026.5.39 : Admin — section Apparence (rows label/control + select +
groupe boutons zoom).
========================================================================== */
.admin-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
padding: 14px 0;
border-bottom: 1px solid var(--border);
}
.admin-row:last-child {
border-bottom: none;
}
.admin-row-label {
flex: 1 1 auto;
min-width: 0;
}
.admin-row-label strong {
font-size: 14px;
color: var(--text);
}
.admin-row-desc {
font-size: 12px;
color: var(--text-faint);
margin-top: 4px;
line-height: 1.4;
}
.admin-row-control {
flex: 0 0 auto;
display: flex;
align-items: center;
gap: 6px;
}
.admin-select {
padding: 6px 10px;
font-size: 13px;
background: var(--bg-elevated);
color: var(--text);
border: 1px solid var(--border-strong);
border-radius: 4px;
cursor: pointer;
min-width: 200px;
}
.admin-input-num {
width: 80px !important;
text-align: center;
}
.admin-zoom-group {
display: flex;
gap: 4px;
}
.btn-zoom {
min-width: 56px;
padding: 6px 10px;
font-size: 12px;
font-weight: 500;
background: var(--bg-elevated);
color: var(--text-muted);
border: 1px solid var(--border-strong);
border-radius: 4px;
cursor: pointer;
transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.btn-zoom:hover {
background: var(--bg-hover);
color: var(--text);
}
.btn-zoom.active {
background: var(--accent);
color: #fff;
border-color: var(--accent);
}
/* ==========================================================================
v2026.5.39 r5 : zoom texte via variable --text-scale (0.8 à 1.2).
Modifie uniquement les font-size, pas le layout. Stockée par JS dans
admin_config.textZoom et appliquée sur <html> au boot.
On utilise un selecteur `*` ciblant tous les éléments qui ont
`font-size` défini en `px` ou `rem` — nope c'est impossible. Donc on
applique sur :root un font-size inheritable, et on bump les tailles
spécifiques via calc(). Pour simplicité on cible juste body+composants
principaux. Les éléments restants (avec font-size en px hardcodé) seront
inchangés, mais comme la majorité des textes hérite de body, ça suffit
en pratique.
========================================================================== */
/* v2026.5.39 r7 : zoom GLOBAL sur le body — fait scaler TOUS les textes
visibles (interventions, popups, absences, réservations, tooltips, cards,
sidebar, etc.). Application via body.style.zoom = "<pct>" depuis JS.
On garde aussi --text-scale pour la date/heure (qui restent à la même
taille entre elles, même règle calc()). */
:root {
--text-scale: 1;
--zoom-factor: 1;
--zoom-inv: 1;
}
.app-clock-time,
.app-clock-date { font-size: calc(18px * var(--text-scale)) !important; }
/* v2026.5.39 r12 : le panel admin suit le zoom comme tout le reste.
Pas d'effet yo-yo car le zoom n'est plus appliqué pendant le drag du
slider (seulement au release) — voir _applyTextZoom dans viewer.js. */
/* Slider taille texte dans Apparence — v2026.5.39 r6 : 5 dots sur la piste */
.admin-zoom-slider-wrap {
display: flex;
align-items: center;
gap: 12px;
}
.admin-zoom-slider {
width: 220px;
height: 26px;
cursor: pointer;
-webkit-appearance: none;
appearance: none;
background: transparent;
}
.admin-zoom-slider::-webkit-slider-runnable-track {
height: 4px;
background:
radial-gradient(circle at 0% 50%, var(--text-muted) 0 4px, transparent 5px),
radial-gradient(circle at 25% 50%, var(--text-muted) 0 4px, transparent 5px),
radial-gradient(circle at 50% 50%, var(--text-muted) 0 4px, transparent 5px),
radial-gradient(circle at 75% 50%, var(--text-muted) 0 4px, transparent 5px),
radial-gradient(circle at 100% 50%, var(--text-muted) 0 4px, transparent 5px),
var(--border-strong);
border-radius: 2px;
}
.admin-zoom-slider::-moz-range-track {
height: 4px;
background:
radial-gradient(circle at 0% 50%, var(--text-muted) 0 4px, transparent 5px),
radial-gradient(circle at 25% 50%, var(--text-muted) 0 4px, transparent 5px),
radial-gradient(circle at 50% 50%, var(--text-muted) 0 4px, transparent 5px),
radial-gradient(circle at 75% 50%, var(--text-muted) 0 4px, transparent 5px),
radial-gradient(circle at 100% 50%, var(--text-muted) 0 4px, transparent 5px),
var(--border-strong);
border-radius: 2px;
}
.admin-zoom-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--accent);
border: 2px solid var(--bg-elevated);
box-shadow: 0 1px 3px rgba(0,0,0,0.25);
cursor: pointer;
margin-top: -7px;
}
.admin-zoom-slider::-moz-range-thumb {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--accent);
border: 2px solid var(--bg-elevated);
box-shadow: 0 1px 3px rgba(0,0,0,0.25);
cursor: pointer;
}
.admin-zoom-value {
min-width: 48px;
text-align: right;
font-size: 13px;
font-weight: 600;
color: var(--text);
font-variant-numeric: tabular-nums;
}
/* ==========================================================================
v2026.5.39 r6 : section "À propos" du panel admin
========================================================================== */
.admin-about-card {
display: flex;
flex-direction: column;
gap: 0;
background: var(--bg-muted);
border: 1px solid var(--border);
border-radius: 6px;
padding: 16px 20px;
margin-top: 8px;
}
.admin-about-row {
display: flex;
gap: 16px;
padding: 8px 0;
border-bottom: 1px solid var(--border);
}
.admin-about-row:last-child {
border-bottom: none;
}
.admin-about-label {
flex: 0 0 130px;
font-size: 13px;
color: var(--text-muted);
font-weight: 500;
}
.admin-about-value {
flex: 1 1 auto;
font-size: 13px;
color: var(--text);
word-break: break-word;
}
.admin-about-value a {
color: var(--accent);
text-decoration: none;
}
.admin-about-value a:hover {
text-decoration: underline;
}
.admin-about-desc {
margin: 12px 0;
padding: 12px 14px;
background: var(--bg-elevated);
border-left: 3px solid var(--accent);
border-radius: 0 4px 4px 0;
font-size: 13px;
line-height: 1.55;
color: var(--text);
}