Rend l'interface utilisable sur téléphone

Le nav et l'en-tête de semaine passent sur plusieurs lignes sous 700px,
le tableau hebdo devient une liste de cartes empilées par jour (au lieu
d'un scroll horizontal forcé), avec des cibles tactiles plus grandes.
Corrige au passage le popup calendrier qui débordait de l'écran sur mobile.
This commit is contained in:
Antoine
2026-08-20 17:26:59 +02:00
parent c1c063da51
commit 7423b68ac9
4 changed files with 112 additions and 15 deletions

View File

@ -383,7 +383,7 @@ def _oob_time_cells(date, jour, plages):
matin_cls = "td-fill cg" if matin_cg else ("td-fill warn" if matin_warn else "td-fill") matin_cls = "td-fill cg" if matin_cg else ("td-fill warn" if matin_warn else "td-fill")
aprem_cls = "td-fill cg" if aprem_cg else ("td-fill warn" if aprem_warn else "td-fill") aprem_cls = "td-fill cg" if aprem_cg else ("td-fill warn" if aprem_warn else "td-fill")
matin_html = ( matin_html = (
f'<div id="cg-matin-{_e(date)}" hx-swap-oob="true" class="{matin_cls}">' f'<div id="cg-matin-{_e(date)}" hx-swap-oob="true" data-label="Matin" class="{matin_cls}">'
f'<div class="time-pair">' f'<div class="time-pair">'
f'<input class="time-input" type="time" name="matin_entree" data-date="{_e(date)}" value="{_e(jour["matin_entree"] or "")}">' f'<input class="time-input" type="time" name="matin_entree" data-date="{_e(date)}" value="{_e(jour["matin_entree"] or "")}">'
f'<span class="time-sep">→</span>' f'<span class="time-sep">→</span>'
@ -391,7 +391,7 @@ def _oob_time_cells(date, jour, plages):
f'</div></div>' f'</div></div>'
) )
aprem_html = ( aprem_html = (
f'<div id="cg-aprem-{_e(date)}" hx-swap-oob="true" class="{aprem_cls}">' f'<div id="cg-aprem-{_e(date)}" hx-swap-oob="true" data-label="Après-midi" class="{aprem_cls}">'
f'<div class="time-pair">' f'<div class="time-pair">'
f'<input class="time-input" type="time" name="aprem_entree" data-date="{_e(date)}" value="{_e(jour["aprem_entree"] or "")}">' f'<input class="time-input" type="time" name="aprem_entree" data-date="{_e(date)}" value="{_e(jour["aprem_entree"] or "")}">'
f'<span class="time-sep">→</span>' f'<span class="time-sep">→</span>'

View File

@ -16,7 +16,7 @@
</td> </td>
<td class="c-matin"> <td class="c-matin">
<div id="cg-matin-{{ j.date }}" class="td-fill{% if matin_cg %} cg{% elif matin_warn %} warn{% endif %}"> <div id="cg-matin-{{ j.date }}" data-label="Matin" class="td-fill{% if matin_cg %} cg{% elif matin_warn %} warn{% endif %}">
<div class="time-pair"> <div class="time-pair">
<input class="time-input" type="time" name="matin_entree" <input class="time-input" type="time" name="matin_entree"
data-date="{{ j.date }}" value="{{ j.matin_entree or '' }}"> data-date="{{ j.date }}" value="{{ j.matin_entree or '' }}">
@ -28,7 +28,7 @@
</td> </td>
<td class="c-aprem"> <td class="c-aprem">
<div id="cg-aprem-{{ j.date }}" class="td-fill{% if aprem_cg %} cg{% elif aprem_warn %} warn{% endif %}"> <div id="cg-aprem-{{ j.date }}" data-label="Après-midi" class="td-fill{% if aprem_cg %} cg{% elif aprem_warn %} warn{% endif %}">
<div class="time-pair"> <div class="time-pair">
<input class="time-input" type="time" name="aprem_entree" <input class="time-input" type="time" name="aprem_entree"
data-date="{{ j.date }}" value="{{ j.aprem_entree or '' }}"> data-date="{{ j.date }}" value="{{ j.aprem_entree or '' }}">
@ -39,13 +39,13 @@
</div> </div>
</td> </td>
<td class="col-calc"> <td class="col-calc" data-label="Travaillé">
<span id="calc-{{ j.date }}-trav"> <span id="calc-{{ j.date }}-trav">
<span class="calc-num">{{ j.travaille if j.travaille_min else '—' }}</span> <span class="calc-num">{{ j.travaille if j.travaille_min else '—' }}</span>
</span> </span>
</td> </td>
<td class="col-calc"> <td class="col-calc" data-label="Δ jour">
<span id="calc-{{ j.date }}-delta"> <span id="calc-{{ j.date }}-delta">
<span class="{% if j.travaille_min and j.delta_min > 0 %}delta-pos{% elif j.travaille_min and j.delta_min < 0 %}delta-neg{% else %}delta-zero{% endif %}"> <span class="{% if j.travaille_min and j.delta_min > 0 %}delta-pos{% elif j.travaille_min and j.delta_min < 0 %}delta-neg{% else %}delta-zero{% endif %}">
{%- if j.travaille_min -%} {%- if j.travaille_min -%}
@ -55,7 +55,7 @@
</span> </span>
</td> </td>
<td class="col-cumul"> <td class="col-cumul" data-label="Δ sem.">
<span id="calc-{{ j.date }}-cumul"> <span id="calc-{{ j.date }}-cumul">
{%- if j.cumul_visible -%} {%- if j.cumul_visible -%}
<span class="{% if j.delta_cumul_min > 0 %}delta-pos{% elif j.delta_cumul_min < 0 %}delta-neg{% else %}delta-zero{% endif %}"> <span class="{% if j.delta_cumul_min > 0 %}delta-pos{% elif j.delta_cumul_min < 0 %}delta-neg{% else %}delta-zero{% endif %}">
@ -67,7 +67,7 @@
</span> </span>
</td> </td>
<td class="col-cible"> <td class="col-cible" data-label="Cible">
<span id="calc-{{ j.date }}-cible"> <span id="calc-{{ j.date }}-cible">
{%- if j.cible_matin or j.cible_aprem -%} {%- if j.cible_matin or j.cible_aprem -%}
{%- if j.cible_matin -%}<span class="cible-num">M {{ j.cible_matin_entree }} → {{ j.cible_matin }}</span>{%- endif -%} {%- if j.cible_matin -%}<span class="cible-num">M {{ j.cible_matin_entree }} → {{ j.cible_matin }}</span>{%- endif -%}
@ -87,7 +87,7 @@
title="Enregistrer">✓</button> title="Enregistrer">✓</button>
</td> </td>
<td class="col-conge"> <td class="col-conge" data-label="Congé">
<div id="cg-btn-{{ j.date }}"> <div id="cg-btn-{{ j.date }}">
<div class="conge-btns"> <div class="conge-btns">
<button hx-post="/conge/{{ j.date }}/matin" <button hx-post="/conge/{{ j.date }}/matin"

View File

@ -44,11 +44,12 @@
nav { nav {
background: var(--nav-bg); background: var(--nav-bg);
color: var(--ground); color: var(--ground);
height: 50px; min-height: 50px;
padding: 0 2rem; padding: .5rem 2rem;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 2rem; flex-wrap: wrap;
gap: .6rem 2rem;
border-bottom: 3px solid var(--accent-2); border-bottom: 3px solid var(--accent-2);
} }
.nav-brand { .nav-brand {
@ -87,6 +88,11 @@
} }
.nav-logout { opacity: .6; font-size: 11px; } .nav-logout { opacity: .6; font-size: 11px; }
@media (max-width: 700px) {
nav { padding: .5rem 1rem; gap: .5rem 1rem; }
nav .spacer { flex-basis: 100%; height: 0; }
}
/* ── Layout ── */ /* ── Layout ── */
.container { .container {
max-width: 1100px; max-width: 1100px;
@ -96,15 +102,23 @@
flex-direction: column; flex-direction: column;
gap: 1.75rem; gap: 1.75rem;
} }
@media (max-width: 700px) {
.container { padding: 1rem .75rem; gap: 1.25rem; }
}
/* ── Week header ── */ /* ── Week header ── */
.week-header { .week-header {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 1rem; flex-wrap: wrap;
gap: .6rem 1rem;
border-bottom: 2px solid var(--text); border-bottom: 2px solid var(--text);
padding-bottom: .75rem; padding-bottom: .75rem;
} }
@media (max-width: 700px) {
.week-header-spacer { display: none; }
.export-btn { order: 10; flex-basis: 100%; text-align: center; }
}
.week-nav-arrows { display: flex; gap: .4rem; } .week-nav-arrows { display: flex; gap: .4rem; }
.arrow-btn { .arrow-btn {
width: 28px; height: 28px; width: 28px; height: 28px;
@ -360,6 +374,69 @@
.btn-cg.btn-jour { border-radius: 50%; width: 22px; height: 22px; font-size: 9px; } .btn-cg.btn-jour { border-radius: 50%; width: 22px; height: 22px; font-size: 9px; }
.btn-cg.jour-on { background: var(--accent-2); border-color: #955505; color: #fff; } .btn-cg.jour-on { background: var(--accent-2); border-color: #955505; color: #fff; }
/* ── Tableau hebdo en cartes empilées sous 700px (évite le scroll horizontal) ── */
@media (max-width: 700px) {
.pointage-table thead { display: none; }
.pointage-table, .pointage-table tbody, .pointage-table tr, .pointage-table td {
display: block;
width: 100%;
}
.pointage-table { border: none; background: none; }
.pointage-table tbody tr {
border: 1.5px solid var(--rule);
background: var(--surface);
margin-bottom: .75rem;
}
.pointage-table tbody tr:not(:last-child) td { border-bottom: none; }
.pointage-table td {
border-bottom: 1px solid var(--rule-l) !important;
padding: .55rem .75rem;
}
.pointage-table td:last-child { border-bottom: none !important; }
.pointage-table td.col-jour {
background: var(--ground);
border-bottom: 2px solid var(--text) !important;
}
.pointage-table .jour-nom, .pointage-table .jour-date { display: inline; }
.pointage-table .jour-date::before { content: ' · '; }
.pointage-table [data-label] {
display: flex;
align-items: center;
justify-content: space-between;
gap: .75rem;
}
.pointage-table [data-label]::before {
content: attr(data-label);
font-family: var(--mono);
font-size: 9px;
letter-spacing: .1em;
text-transform: uppercase;
color: var(--muted);
flex-shrink: 0;
}
.pointage-table td.c-matin, .pointage-table td.c-aprem { padding: 0; }
.pointage-table td.c-matin .td-fill, .pointage-table td.c-aprem .td-fill {
padding: .55rem .75rem;
}
.pointage-table .time-input { width: 84px; font-size: 14px; padding: .45rem .4rem; }
.pointage-table td.col-calc,
.pointage-table td.col-cumul,
.pointage-table td.col-cible {
text-align: left;
padding-left: .75rem;
min-width: 0;
}
.pointage-table td.col-save { text-align: right; }
.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; }
}
/* ── Historique ── */ /* ── Historique ── */
.history { .history {
display: flex; display: flex;
@ -440,6 +517,7 @@
box-shadow: 0 4px 20px rgba(28,23,18,.12); box-shadow: 0 4px 20px rgba(28,23,18,.12);
padding: .75rem; padding: .75rem;
min-width: 260px; min-width: 260px;
max-width: calc(100vw - 2rem);
} }
.cal-popup[hidden] { display: none; } .cal-popup[hidden] { display: none; }

View File

@ -44,7 +44,7 @@
<!-- Tableau --> <!-- Tableau -->
<div class="table-section"> <div class="table-section">
<table> <table class="pointage-table">
<thead> <thead>
<tr class="th-group"> <tr class="th-group">
<th class="g-jour" rowspan="2">Jour</th> <th class="g-jour" rowspan="2">Jour</th>
@ -198,7 +198,26 @@
const open = popup.hidden; const open = popup.hidden;
popup.hidden = !open; popup.hidden = !open;
btn.setAttribute('aria-expanded', String(open)); btn.setAttribute('aria-expanded', String(open));
if (open) renderCal(); if (open) {
renderCal();
// Sous ~700px, le popup est positionné en fixed pour ne jamais déborder
// du viewport (son ancrage absolu normal suit la position du trigger,
// qui n'est pas centré horizontalement sur mobile).
if (window.innerWidth <= 700) {
const rect = btn.getBoundingClientRect();
popup.style.position = 'fixed';
popup.style.top = (rect.bottom + 8) + 'px';
popup.style.left = '.75rem';
popup.style.right = '.75rem';
popup.style.width = 'auto';
} else {
popup.style.position = '';
popup.style.top = '';
popup.style.left = '';
popup.style.right = '';
popup.style.width = '';
}
}
}; };
// Close on outside click // Close on outside click