Rendre l'application utilisable sur mobile pour les cadres

- Calendrier : sous 640px, la grille 7 colonnes devient une liste
  verticale (une ligne pleine largeur par jour), boutons AM/PM en
  cibles tactiles de 44px minimum.
- Popover de statut : positionnement recalculé pour rester dans
  l'écran (bascule au-dessus de la cellule et se recale à gauche si
  besoin) au lieu de pouvoir déborder hors viewport.
- Tableaux admin (sociétés, utilisateurs, validation) : scroll
  horizontal indépendant pour ne pas casser la mise en page sur petit
  écran.
- Nav admin et en-tête compactés sur mobile.

Testé avec Playwright en viewport mobile (375x812) : calendrier liste,
popover, connexion et vues admin.
This commit is contained in:
Claude committed 2026-07-06 11:15:26 +00:00
1 parent 0c438275b5
commit 767b7aaa3b
3 files changed
+91 -19

No files matched your search

+54 -3
View File
@@ -330,9 +330,60 @@ h2 { font-size: 17px; margin: 0 0 4px; }
.view[hidden] { display: none; }
.day-weekday-mobile { display: none; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 720px) {
.main { padding: 20px 14px 50px; }
.day-cell { min-height: 70px; }
.half-day { font-size: 9px; min-height: 28px; }
.main { padding: 16px 12px 50px; }
.selector-card { flex-direction: column; align-items: stretch; }
.topbar { padding: 10px 14px; }
.topbar-user { gap: 8px; }
}
/* Below this width the 7-column grid becomes unusable by touch, so the
calendar switches to a single-column list: one full-width row per day. */
@media (max-width: 640px) {
.calendar-header { flex-direction: column; }
.calendar-weekdays { display: none; }
.calendar-grid {
display: flex;
flex-direction: column;
gap: 6px;
}
.day-cell {
flex-direction: row;
align-items: center;
min-height: unset;
padding: 10px;
gap: 10px;
}
.day-cell.empty { display: none; }
.day-number {
flex: 0 0 auto;
width: 46px;
display: flex;
flex-direction: column;
align-items: center;
line-height: 1.2;
}
.day-weekday-mobile {
display: block;
font-size: 10px;
font-weight: 700;
color: var(--color-muted);
text-transform: uppercase;
}
.half-day-row { gap: 8px; }
.half-day { min-height: 44px; font-size: 11px; }
.calendar-actions { justify-content: stretch; }
.calendar-actions .btn { width: 100%; }
.legend { gap: 10px 14px; font-size: 12px; }
.popover { max-width: calc(100vw - 16px); }
.modal { padding: 20px; }
}
+18 -12
View File
@@ -98,10 +98,12 @@
<button id="add-company-btn" class="btn btn-primary">+ Nouvelle société</button>
</div>
<div class="card">
<table class="data-table">
<thead><tr><th>Nom</th><th>Cadres actifs</th><th>Créée le</th><th></th></tr></thead>
<tbody id="companies-tbody"></tbody>
</table>
<div class="table-scroll">
<table class="data-table">
<thead><tr><th>Nom</th><th>Cadres actifs</th><th>Créée le</th><th></th></tr></thead>
<tbody id="companies-tbody"></tbody>
</table>
</div>
</div>
</section>
@@ -117,10 +119,12 @@
<select id="users-filter-company"><option value="">Toutes</option></select>
</label>
</div>
<table class="data-table">
<thead><tr><th>Nom</th><th>E-mail</th><th>Rôle</th><th>Société</th><th>Statut</th><th></th></tr></thead>
<tbody id="users-tbody"></tbody>
</table>
<div class="table-scroll">
<table class="data-table">
<thead><tr><th>Nom</th><th>E-mail</th><th>Rôle</th><th>Société</th><th>Statut</th><th></th></tr></thead>
<tbody id="users-tbody"></tbody>
</table>
</div>
</div>
</section>
@@ -165,10 +169,12 @@
<button id="reopen-company-btn" class="btn btn-outline">Réouvrir</button>
</div>
</div>
<table class="data-table">
<thead><tr><th>Cadre</th><th>Statut</th><th>Validé le</th><th></th></tr></thead>
<tbody id="validation-cadres-tbody"></tbody>
</table>
<div class="table-scroll">
<table class="data-table">
<thead><tr><th>Cadre</th><th>Statut</th><th>Validé le</th><th></th></tr></thead>
<tbody id="validation-cadres-tbody"></tbody>
</table>
</div>
<div class="export-row">
<span>Export :</span>
<button id="export-pdf-btn" class="btn btn-outline">Télécharger PDF</button>
+19 -4
View File
@@ -1,6 +1,7 @@
(() => {
'use strict';
const WEEKDAY_SHORT = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'];
const MONTH_NAMES = [
'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre',
@@ -224,7 +225,7 @@
const num = document.createElement('div');
num.className = 'day-number';
num.textContent = d;
num.innerHTML = `<span class="day-weekday-mobile">${WEEKDAY_SHORT[dateObj.getDay()]}</span> ${d}`;
cell.appendChild(num);
const row = document.createElement('div');
@@ -258,10 +259,24 @@
popoverTarget = half;
const label = half.dataset.period === 'AM' ? 'Matin' : 'Après-midi';
document.getElementById('popover-title').textContent = `${half.dataset.date} — ${label}`;
const rect = half.getBoundingClientRect();
popover.style.top = `${window.scrollY + rect.bottom + 6}px`;
popover.style.left = `${window.scrollX + rect.left}px`;
popover.hidden = false;
const rect = half.getBoundingClientRect();
const popRect = popover.getBoundingClientRect();
const viewportWidth = document.documentElement.clientWidth;
const viewportHeight = document.documentElement.clientHeight;
const margin = 8;
let top = window.scrollY + rect.bottom + 6;
if (rect.bottom + popRect.height + margin > viewportHeight) {
top = window.scrollY + rect.top - popRect.height - 6;
}
let left = window.scrollX + rect.left;
const maxLeft = window.scrollX + viewportWidth - popRect.width - margin;
left = Math.min(left, Math.max(window.scrollX + margin, maxLeft));
popover.style.top = `${Math.max(window.scrollY + margin, top)}px`;
popover.style.left = `${left}px`;
});
document.addEventListener('click', (e) => {