feat: tableur mobile — barres repliées par défaut, bascule unique #189
CI / lint (push) Successful in 2m42s
CI / security (push) Successful in 1m38s
CI / test (push) Successful in 4m19s
CI / build (push) Successful in 1m27s
CI / e2e (push) Successful in 17m12s

Sous 768 px, la barre de menus, le ruban et le groupe Recherche sont
repliés par défaut : la barre de formule (fx), les onglets et Enregistrer
restent visibles et la grille récupère la hauteur d'écran. Un bouton
unique (#xlsx-tools-toggle) dans la barre des feuilles déplie/replie
l'ensemble (aria-expanded, état actif) ; desktop inchangé.

Ergonomie tactile : cibles ≥ 44 px, onglets en défilement horizontal,
champs de la barre de formule en 16 px (anti-zoom iOS), barre de formule
en 2 lignes quand les outils sont ouverts.

Tests : JSDOM xlsx-viewer.test.mjs (+2, 165/165), E2E mobile (repli par
défaut, dépliage, no-overflow ruban, cibles 44 px) ; openXlsx() déplie
automatiquement ≤ 768 px pour les tests desktop.
This commit is contained in:
2026-10-08 15:45:39 -04:00
parent e01e837a2a
commit 36b4962efb
17 changed files with 341 additions and 17 deletions
+19
View File
@@ -1473,6 +1473,11 @@ const GRID_CHUNK_ROWS = 100; // rows materialised per extension step
<span class="xlsx-toolbar-actions">${actionsHtml}</span>
</div>
<div class="xlsx-sheetbar">
<button class="btn-action xlsx-tools-toggle" id="xlsx-tools-toggle" type="button"
aria-expanded="false" title="${escapeHtml(t("xlsx.tools_toggle"))}"
aria-label="${escapeHtml(t("xlsx.tools_toggle"))}">
<i data-lucide="menu" style="width:18px;height:18px" aria-hidden="true"></i>
</button>
${tabs}
<span class="xlsx-sheetbar-end">${fileHtml}</span>
</div>
@@ -1526,6 +1531,20 @@ const GRID_CHUNK_ROWS = 100; // rows materialised per extension step
// A re-render invalidates any open context menu (it targets the old DOM).
closeContextMenu();
// #189 — mobile : la barre de menus + le ruban sont repliés par défaut
// (cf. style.css ≤768px). Ce bouton, seul dans la barre des feuilles,
// déplie/replie le tout sans jamais masquer la barre de formule.
const toolsToggle = area.querySelector("#xlsx-tools-toggle");
const toolsBar = area.querySelector(".xlsx-toolbar");
if (toolsToggle && toolsBar) {
toolsToggle.addEventListener("click", () => {
const open = toolsBar.classList.toggle("xlsx-tools-open");
toolsToggle.setAttribute("aria-expanded", String(open));
toolsToggle.classList.toggle("active", open);
safeCreateIcons();
});
}
// ── #153 A17 — dashboard panel: named ranges, objects, per-sheet KPI ──
// Fetched lazily on first open of the dashboard tab; a workbook without
// anything notable hides the button entirely (no empty panel).
+1
View File
@@ -2050,6 +2050,7 @@
"xlsx.mbar_label": "Spreadsheet menus",
"xlsx.cmdbar_label": "Spreadsheet command bar",
"xlsx.tools_toggle": "Show / hide toolbars",
"xlsx.mbar_file": "File",
"xlsx.mbar_edit": "Edit",
"xlsx.mbar_view": "View",
+1
View File
@@ -2050,6 +2050,7 @@
"xlsx.mbar_label": "Menus du tableur",
"xlsx.cmdbar_label": "Barre de commandes du tableur",
"xlsx.tools_toggle": "Afficher / masquer les barres d'outils",
"xlsx.mbar_file": "Fichier",
"xlsx.mbar_edit": "Modifier",
"xlsx.mbar_view": "Affichage",
+79
View File
@@ -12172,6 +12172,85 @@ body.desktop-mode .editor-container {
max-width: 92vw;
}
}
/* #189 — mise en page mobile : par défaut seuls restent la barre des
feuilles (avec le basculeur) et la barre de formule. La barre de menus et
le ruban sont repliés derrière #xlsx-tools-toggle ; le groupe Recherche,
logé dans la barre de formule, suit le même état pour ne pas écraser le
champ de saisie. */
.xlsx-tools-toggle {
display: none;
}
@media (max-width: 768px) {
.xlsx-tools-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 44px;
height: 44px;
flex: 0 0 auto;
}
.xlsx-menubar,
.xlsx-cmdbar,
.xlsx-find-group {
display: none;
}
.xlsx-toolbar.xlsx-tools-open .xlsx-menubar {
display: flex;
}
.xlsx-toolbar.xlsx-tools-open .xlsx-cmdbar {
display: flex;
}
.xlsx-toolbar.xlsx-tools-open .xlsx-find-group {
display: flex;
}
/* La barre de formule ne déborde jamais : elle passe en 2 lignes quand le
groupe Recherche réapparaît avec les outils ouverts. */
.xlsx-toolbar.xlsx-tools-open .xlsx-formula-bar {
flex-wrap: wrap;
}
/* Une seule ligne de feuilles : les onglets défilent horizontalement au
lieu d'enrouler et de grignoter la hauteur de la grille. */
.xlsx-sheetbar {
flex-wrap: nowrap;
}
.xlsx-sheetbar .xlsx-tabs {
flex-wrap: nowrap;
overflow-x: auto;
scrollbar-width: none;
}
.xlsx-sheetbar .xlsx-tabs::-webkit-scrollbar {
display: none;
}
/* Cibles tactiles : le ruban replié n'existe que derrière le basculeur,
mais une fois ouvert chaque commande reste atteignable au doigt. */
.xlsx-toolbar .btn-action {
min-width: 44px;
height: 44px;
}
/* À 44px un groupe (police, nombre…) dépasse la largeur d'un téléphone :
il doit pouvoir se réduire ET s'enrouler plutôt que déborder. */
.xlsx-cmdbar .xlsx-cmd-group {
flex: 0 1 auto;
min-width: 0;
flex-wrap: wrap;
}
.xlsx-menubtn {
padding: 12px 14px;
min-height: 44px;
}
.xlsx-tab,
.xlsx-tab-add {
padding: 10px 14px;
min-height: 44px;
}
/* 16px minimum : en dessous iOS zoome automatiquement la page dès que le
champ reçoit le focus, ce qui fait « sauter » l'interface. */
.xlsx-active-cell,
.xlsx-formula-input,
.xlsx-find-input {
font-size: 16px;
}
}
.xlsx-context-item {
text-align: left;
border: none;