Nav mobile v2 : le dropdown sous header devient un panneau plein écran fixed
Standard KA 2026-08-25 : le panneau absolute top-full (dropdown) passe en fixed inset-x-0 top-14 bottom-0 (sous le header sticky h-14) — menu visible peu importe la position de scroll. Liens géants numérotés gk-display, safe-area, verrou de scroll ka-scroll-lock conservé. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 changed file +25 −13
modified
apps/web/components/mobile-nav.tsx
+25 −13
@@ -1,15 +1,16 @@ | ||
| 1 | 1 | /** |
| 2 | − * Trouve-KA — navigation mobile (hamburger + panneau déroulant sous le header) | |
| 2 | + * Trouve-KA — navigation mobile (hamburger + panneau plein écran) | |
| 3 | 3 | * Author: Simon-Pierre Boucher |
| 4 | 4 | * Contact: contact@spboucher.ai |
| 5 | 5 | * |
| 6 | − * Socle mobile Groupe KA (ka/tokens.css) : | |
| 6 | + * Standard KA Nav v2 (2026-08-25) : | |
| 7 | 7 | * · bouton 44×44 (var(--touch)), visible uniquement < 768 px (md:hidden) ; |
| 8 | − * · panneau `absolute top-full` (le header sticky est l'ancêtre positionné — | |
| 9 | − * JAMAIS de position:fixed sous le backdrop-blur du header) ; | |
| 8 | + * · panneau `fixed inset-x-0 top-14 bottom-0` (plein écran sous le header | |
| 9 | + * sticky h-14) — visible peu importe la position de scroll ; le header | |
| 10 | + * n'a PAS de backdrop-filter, le fixed n'est donc pas re-parenté ; | |
| 10 | 11 | * · verrou de scroll via la classe ka-scroll-lock sur <html> ; |
| 11 | − * · fermeture : tap extérieur, Escape (focus rendu au bouton), navigation ; | |
| 12 | − * · items ≥ 44 px de haut, safe-area iPhone en bas du panneau ; | |
| 12 | + * · fermeture : Escape (focus rendu au bouton), navigation, bouton ✕ ; | |
| 13 | + * · liens géants numérotés (gk-display), safe-area iPhone en bas ; | |
| 13 | 14 | * · z-index : échelle --z-* des tokens (900 = --z-modal). |
| 14 | 15 | */ |
| 15 | 16 | |
@@ -103,18 +104,29 @@ export function MobileNav({ links }: MobileNavProps) { | ||
| 103 | 104 | {open && ( |
| 104 | 105 | <div |
| 105 | 106 | id="menu-mobile" |
| 106 | − className="absolute inset-x-0 top-full z-[900] border-b-[1.5px] border-[var(--line-strong)] bg-paper shadow-off-soft" | |
| 107 | − style={{ paddingBottom: "env(safe-area-inset-bottom, 0px)" }} | |
| 107 | + role="dialog" | |
| 108 | + aria-modal="true" | |
| 109 | + aria-label="Menu" | |
| 110 | + className="fixed inset-x-0 bottom-0 top-14 z-[var(--z-modal,900)] flex flex-col overflow-y-auto overscroll-contain bg-paper" | |
| 111 | + style={{ paddingBottom: "max(20px, env(safe-area-inset-bottom, 0px))" }} | |
| 108 | 112 | > |
| 109 | − <ul className="px-4 py-2 sm:px-6"> | |
| 110 | − {links.map((link) => ( | |
| 111 | − <li key={link.href}> | |
| 113 | + <ul className="flex flex-1 flex-col justify-center px-6 py-8"> | |
| 114 | + {links.map((link, i) => ( | |
| 115 | + <li | |
| 116 | + key={link.href} | |
| 117 | + className="border-b-[1.5px] border-dashed border-[var(--line-strong)] last:border-0" | |
| 118 | + > | |
| 112 | 119 | <Link |
| 113 | 120 | href={link.href} |
| 114 | 121 | onClick={() => setOpen(false)} |
| 115 | − className="gk-display flex min-h-[44px] items-center rounded-ctl px-3 text-[15px] font-bold text-ink-2 transition-colors hover:bg-surface hover:text-ink" | |
| 122 | + className="gk-display flex items-baseline gap-3.5 py-5 text-ink" | |
| 116 | 123 | > |
| 117 | − {link.label} | |
| 124 | + <span className="font-mono text-[12px] font-bold text-ink-2"> | |
| 125 | + 0{i + 1} | |
| 126 | + </span> | |
| 127 | + <span className="text-[26px] font-bold uppercase leading-none tracking-[-0.03em]"> | |
| 128 | + {link.label} | |
| 129 | + </span> | |
| 118 | 130 | </Link> |
| 119 | 131 | </li> |
| 120 | 132 | ))} |
| 121 | 133 | |