From e702e21296a231908b3519c7dbfe4e09a7298ab4 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Tue, 8 Sep 2026 01:53:49 +0200 Subject: [PATCH] =?UTF-8?q?fix(layout):=20barre=20de=20navigation=20mobile?= =?UTF-8?q?=20en=20ic=C3=B4nes=20seules=20(#105)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sur téléphone, l'onglet « Liste de courses » (16 caractères) passait sur 2 lignes dans un onglet à ~90px alors que « Planning »/« Recettes »/« Plus » tenaient sur 1 ligne : son bloc icône+libellé centré était plus haut, donc son icône visiblement plus haute que les autres. `AppLayout.scss` `.app-bottom-nav` : le `.label` est masqué visuellement (à la manière du rail desktop replié — `position: absolute; clip; …`), pas retiré du DOM, donc chaque ``/bouton garde son nom accessible (un lecteur d'écran annonce toujours « Planning », « Liste de courses »…) sans `aria-label` qui dupliquerait la chaîne i18n. Icônes légèrement agrandies (1.375rem → 1.5rem) puisqu'elles sont désormais seules. Tests : `layout.cy.ts` — l'onglet expose son `span.label` dans le DOM mais `not.be.visible`, l'icône `svg` visible (mise à jour de l'assertion qui attendait le libellé visible). `sidebar.cy.ts` / `planning-page.cy.ts` (nav desktop) inchangés. Suite layout/sidebar/planning revérifiée, 27/27. Closes #105 Co-Authored-By: Claude Sonnet 5 --- apps/web/cypress/e2e/layout.cy.ts | 16 ++++++++++------ apps/web/src/layouts/AppLayout.scss | 23 +++++++++++++++++++---- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/apps/web/cypress/e2e/layout.cy.ts b/apps/web/cypress/e2e/layout.cy.ts index 0672284..ceaa09d 100644 --- a/apps/web/cypress/e2e/layout.cy.ts +++ b/apps/web/cypress/e2e/layout.cy.ts @@ -186,7 +186,7 @@ describe("Responsive breakpoint — the sidebar becomes a bottom tab bar under 6 cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null }); }); - it("renders the bottom nav instead of the sidebar, with every route tab legible and a working Plus tab", () => { + it("renders the bottom nav instead of the sidebar, icon-only, with a working Plus tab", () => { cy.setViewport("phone"); cy.visit("/"); @@ -202,11 +202,15 @@ describe("Responsive breakpoint — the sidebar becomes a bottom tab bar under 6 expect(getComputedStyle($nav[0]).position).to.equal("fixed"); }); - // Every route tab keeps its icon *and* label legible — this bar never - // falls back to icon-only or horizontal scroll, unlike the old - // squashed sidebar treatment it replaces (only 4 short tabs, always - // fits). - cy.contains(".app-bottom-nav a", "Planning").find("span.label").should("be.visible"); + // Issue #105 — icon-only bar: each tab's `span.label` stays in the DOM + // (accessible name for the link) but is visually hidden, only the icon + // shows. Same treatment as the desktop collapsed rail (sidebar.cy.ts). + cy.contains(".app-bottom-nav a", "Planning") + .should("have.attr", "href", "/") + .within(() => { + cy.get("span.label").should("exist").and("not.be.visible"); + cy.get("svg").should("be.visible"); + }); cy.contains(".app-bottom-nav a", "Recettes").should("have.attr", "href", "/recettes"); cy.contains(".app-bottom-nav a", "Liste de courses").should( "have.attr", diff --git a/apps/web/src/layouts/AppLayout.scss b/apps/web/src/layouts/AppLayout.scss index b91fca7..d30ce4a 100644 --- a/apps/web/src/layouts/AppLayout.scss +++ b/apps/web/src/layouts/AppLayout.scss @@ -415,13 +415,28 @@ cursor: pointer; svg { - width: 1.375rem; - height: 1.375rem; + width: 1.5rem; + height: 1.5rem; } + // Icon-only bar (issue #105): the visible label is dropped. "Liste de + // courses" (16 chars) wrapped to two lines in a ~90px tab while the + // others stayed on one, so its icon+label block was taller and its + // icon sat visibly higher than the rest. Kept in the DOM, visually + // hidden the accessibility-safe way, so a screen reader still announces + // each tab by name and the ``/button keeps its accessible + // label (no `aria-label` to duplicate the i18n string). .label { - font-size: var(--font-size-xs); - font-weight: 600; + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0 0 0 0); + clip-path: inset(50%); + white-space: nowrap; + border: 0; } // Applied by NavLink itself (see AppLayout.tsx's `className` prop) for -- 2.45.2