From 83f5512cb68f4c8f3fbe757f35f67bbadb0128d2 Mon Sep 17 00:00:00 2001 From: Jacquin Antoine Date: Tue, 8 Sep 2026 22:40:06 +0200 Subject: [PATCH] =?UTF-8?q?Astreintes=20:=20interventions=20dans=20un=20me?= =?UTF-8?q?nu=20d=C3=A9pliant=20ferm=C3=A9,=20cadre=20=C3=A9largi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les heures d'intervention (début, fin, description) passent en trois colonnes alignées, cachées par défaut derrière un bouton « N interventions » ; l'heure de retour et le total restent visibles. L'état déplié survit aux rafraîchissements HTMX. Le conteneur passe de 1100 à 1400 px pour que les lignes ne dépassent plus du cadre. 💘 Generated with Crush Assisted-by: Crush:glm-5.2 --- README.md | 5 +-- app/main.py | 31 ++++++++++------ app/templates/_ligne.html | 74 ++++++++++++++++++++++---------------- app/templates/base.html | 56 +++++++++++++++++++++-------- app/templates/semaine.html | 45 +++++++++++++++++++---- 5 files changed, 147 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index c8fb04c..2a9b96f 100644 --- a/README.md +++ b/README.md @@ -182,8 +182,9 @@ demi-journées restantes. ## Astreinte & repos de 11h Le bouton **AS** marque un jour d'astreinte. Ce jour et son lendemain (la nuit qui -suit), une liste d'événements apparaît sous l'après-midi : autant de lignes que -nécessaire (**+ intervention**), chacune avec un **début**, une **fin** et une +suit), un menu dépliant apparaît sous l'après-midi, fermé par défaut (seuls +l'heure de retour et le total restent visibles). Déplié, il offre autant de lignes +que nécessaire (**+ intervention**) sur trois colonnes : **début**, **fin** et description libre. Une fin antérieure au début (fin < début) désigne une intervention à cheval sur minuit. diff --git a/app/main.py b/app/main.py index 8c0acf7..427b538 100644 --- a/app/main.py +++ b/app/main.py @@ -452,22 +452,23 @@ def _btns_html(date, jour): def _as_event_html(date, ev): - """Une ligne d'intervention d'astreinte : début → fin, description, suppression.""" + """Une ligne d'intervention d'astreinte : début, fin, description (3 colonnes + de la grille), suppression.""" return ( f'
' f'' - f'→' f'' + f'
' f'' f'' - f'
' + f'
' ) def _as_block_html(date, jour): - """Bloc astreinte d'une ligne : événements d'intervention (début/fin, nombre - libre, description), qui déclenchent les 11h de repos et décalent l'heure de - retour, plus le décompte du jour (compteur séparé, hors heures de semaine). + """Bloc astreinte d'une ligne : les heures d'intervention (début, fin, + description) sont regroupées dans un menu dépliant fermé par défaut ; seuls + le bouton, l'heure de retour (11h de repos) et le décompte restent visibles. Rendu sur les jours qualifiés (astreinte ou lendemain) ; div vide ailleurs.""" if not jour.get("astreinte_qualifiee"): return f'
' @@ -481,12 +482,22 @@ def _as_block_html(date, jour): if jour.get("astreinte_min"): total = (f'' f'astreinte : {_e(jour["astreinte_h"])}') + nb = len(events) + label = f'{nb} intervention' + ('s' if nb != 1 else '') return ( - f'
' - f'
{rows}
' + f'
' + f'
' + f'' + f'{hint}{total}' + f'
' + f'
' + f'
' + f'DébutFinDescription' + f'{rows}' + f'
' f'' - f'{hint}' - f'{total}' + f'
' f'
' ) diff --git a/app/templates/_ligne.html b/app/templates/_ligne.html index 7eb2e37..8acd680 100644 --- a/app/templates/_ligne.html +++ b/app/templates/_ligne.html @@ -42,38 +42,50 @@
{% if j.astreinte_qualifiee %} -
-
- {% for ev in j.astreinte_events or [] %} -
- - → - - - -
- {% else %} -
- - → - - - -
- {% endfor %} + {% set nb_as = (j.astreinte_events or []) | length %} +
+
+ + {% if j.retour_min is not none %}retour ≥ {{ j.retour }}{% endif %} + {% if j.astreinte_min %}astreinte : {{ j.astreinte_h }}{% endif %} +
+
+
+ DébutFinDescription + {% for ev in j.astreinte_events or [] %} +
+ + +
+ + +
+
+ {% else %} +
+ + +
+ + +
+
+ {% endfor %} +
+
- - {% if j.retour_min is not none %}retour ≥ {{ j.retour }}{% endif %} - {% if j.astreinte_min %}astreinte : {{ j.astreinte_h }}{% endif %}
{% else %}
diff --git a/app/templates/base.html b/app/templates/base.html index d4ea039..c29465c 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -143,7 +143,7 @@ /* ── Layout ── */ .container { - max-width: 1100px; + max-width: 1400px; margin: 0 auto; padding: 2rem 1.5rem; display: flex; @@ -431,35 +431,62 @@ .btn-cg.btn-as { border-radius: 4px; } .btn-cg.as-on { background: var(--accent); border-color: var(--accent); color: #fff; } - /* Astreinte : opération hors horaires + heure de retour après 11h de repos */ + /* Astreinte : heures d'intervention (début/fin/description) repliées dans un + menu dépliant fermé par défaut ; retour 11h et total restent visibles. */ .as-block { display: flex; - align-items: center; - gap: 5px; - flex-wrap: wrap; + flex-direction: column; + gap: .3rem; padding: .3rem .65rem .45rem; border-top: 1px dashed var(--rule); } - .as-label { + .as-head { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; } + .as-toggle { + display: inline-flex; + align-items: center; + gap: .35rem; + border: 1px solid var(--rule); + background: transparent; + padding: .15rem .5rem; + cursor: pointer; + font-family: var(--mono); + font-size: 9px; + text-transform: uppercase; + letter-spacing: .08em; + color: var(--accent-2); + white-space: nowrap; + transition: border-color .15s; + } + .as-toggle:hover { border-color: var(--accent-2); } + .as-caret { display: inline-block; transition: transform .15s; } + .as-block.open .as-caret { transform: rotate(90deg); } + .as-body { display: none; flex-direction: column; gap: .35rem; } + .as-block.open .as-body { display: flex; } + .as-grid { + display: grid; + grid-template-columns: 84px 84px minmax(110px, 1fr); + gap: 3px 6px; + align-items: center; + } + .as-grid .as-th { font-family: var(--mono); font-size: 9px; letter-spacing: .06em; text-transform: uppercase; - color: var(--accent-2); - white-space: nowrap; + color: var(--muted); } - .as-block .time-input { width: 68px; } + .as-grid .time-input { width: 100%; } + .as-event { display: contents; } + .as-desc-cell { display: flex; align-items: center; gap: 4px; min-width: 0; } .as-hint { font-family: var(--mono); font-size: 10px; color: var(--accent); white-space: nowrap; } - .as-events { display: flex; flex-direction: column; gap: 3px; width: 100%; } - .as-event { display: flex; align-items: center; gap: 4px; } .as-desc { flex: 1; - min-width: 60px; + min-width: 0; border: 1px solid var(--rule); border-radius: 0; padding: .25rem .3rem; @@ -487,6 +514,7 @@ } .as-del:hover { border-color: var(--neg); color: var(--neg); } .as-add { + align-self: flex-start; border: none; background: none; padding: 0; @@ -600,8 +628,8 @@ .pointage-table .btn-valider { width: 40px; height: 40px; font-size: 16px; } .pointage-table .btn-cg { width: 34px; height: 34px; font-size: 11px; } .pointage-table .btn-cg.btn-jour { width: 32px; height: 32px; } - .as-block { padding: .4rem .75rem .55rem; } - .as-block .time-input { width: 92px; } + .pointage-table .as-block { padding: .4rem .75rem .55rem; align-items: stretch; } + .as-grid { grid-template-columns: 82px 82px minmax(90px, 1fr); } .as-desc { font-size: 13px; padding: .4rem .4rem; } } diff --git a/app/templates/semaine.html b/app/templates/semaine.html index 95c02c0..8c7988d 100644 --- a/app/templates/semaine.html +++ b/app/templates/semaine.html @@ -368,19 +368,50 @@ document.addEventListener('input', function(e) { {% endblock %}