SPB Git forge

spb/ka-ui

Public
30commits 1branches 0releases
145.7 MBsize
maindefault branch
27 days agolast push
Python 33.5% JavaScript 30.1% TypeScript 25% CSS 10% Shell 1.4%

nav/ : règle ✕-dans-le-panneau + fix-mm-close.py (correctif 2026-08-25)

Le bouton de fermeture doit vivre dans le panneau fixed (jamais seulement le
burger du header, hors écran quand le header n'est pas épinglé en bas de page).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed 1 mo ago (Aug 25, 2026) parent 36b608e

2 changed files +66 −0

modified nav/NAV-STANDARD.md +6 −0
@@ -28,6 +28,12 @@ d'un site à l'autre.
28 28
29 29 ## Règles
30 30 - JAMAIS de dropdown `position:absolute` ancré au header pour le menu mobile.
31 +- **Le ✕ de fermeture DOIT vivre DANS le panneau** (barre interne ou bouton
32 + `position:fixed` en haut à droite), jamais uniquement dans le header : si le
33 + header n'est pas épinglé (bas de page, sticky cassé par un ancêtre overflow),
34 + le burger→✕ défile hors écran alors que le panneau fixed reste affiché
35 + (bug corrigé le 2026-08-25 sur les 6 apps React + trouve-ka : `.mm-close`
36 + fixed + burger `visibility:hidden` à l'ouverture — une seule commande).
31 37 - Le hamburger et le ✕ font ≥44×44px (cible tactile).
32 38 - Les liens du panneau reprennent EXACTEMENT les liens de la nav desktop (+ liens
33 39 secondaires du footer si pertinent), i18n fr-CA.
added nav/fix-mm-close.py +60 −0
@@ -0,0 +1,60 @@
1 +#!/usr/bin/env python3
2 +"""KA Nav v2 — correctif ✕ (2026-08-25) : le bouton de fermeture vivait dans le
3 +header (burger→✕) ; si le header n'est pas épinglé (bas de page), il est hors
4 +écran alors que le panneau fixed est visible. On met un ✕ FIXE dans le panneau
5 +et on masque le burger à l'ouverture (une seule commande de fermeture).
6 +Usage : fix-mm-close.py <racine app> <has|menu-open>"""
7 +import sys
8 +
9 +root, variant = sys.argv[1], sys.argv[2]
10 +tsx_path = f"{root}/frontend/src/App.tsx"
11 +css_path = f"{root}/frontend/src/styles.css"
12 +
13 +# --- App.tsx : ✕ premier enfant du panneau -------------------------------
14 +tsx = open(tsx_path).read()
15 +if "mm-close" in tsx:
16 + print("App.tsx: deja fait")
17 +else:
18 + anchor = '<div className={`mobile-menu ${open ? "open" : ""}`} role="navigation" aria-label="Menu mobile">'
19 + assert anchor in tsx, "ancre mobile-menu introuvable"
20 + btn = anchor + (
21 + "\n {/* ✕ fixe du panneau : visible peu importe le scroll,"
22 + " le burger du header est masqué à l'ouverture */}"
23 + '\n <button type="button" className="mm-close" aria-label="Fermer le menu"'
24 + "\n onClick={() => setOpen(false)}>✕</button>"
25 + )
26 + tsx = tsx.replace(anchor, btn, 1)
27 + open(tsx_path, "w").write(tsx)
28 + print("App.tsx: OK")
29 +
30 +# --- styles.css : burger masqué à l'ouverture + style du ✕ ----------------
31 +css = open(css_path).read()
32 +old_comment = "/* le rang du header (marque + burger devenu X) reste au-dessus du panneau */\n"
33 +old_has = old_comment + ".header:has(.mobile-menu.open) .header-inner { position: relative; z-index: 60; }"
34 +old_mo = old_comment + ".header.menu-open .header-inner { position: relative; z-index: 60; }"
35 +hide = ("/* burger masque a l'ouverture : la fermeture passe par le X fixe du panneau */\n"
36 + + (".header:has(.mobile-menu.open) .menu-btn { visibility: hidden; }"
37 + if variant == "has" else
38 + ".header.menu-open .menu-btn { visibility: hidden; }"))
39 +mm_close = hide + """
40 +/* bouton de fermeture du panneau : fixe en haut a droite du viewport */
41 +.mm-close {
42 + position: fixed; top: 10px; right: 14px; z-index: 2;
43 + width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
44 + border: 1.5px solid var(--ink); border-radius: 999px;
45 + background: var(--ink); color: var(--paper);
46 + font-size: 17px; font-weight: 700; line-height: 1; cursor: pointer; padding: 0;
47 +}"""
48 +done = False
49 +for old in (old_has, old_mo):
50 + if old in css:
51 + css = css.replace(old, mm_close, 1)
52 + done = True
53 + break
54 +if not done and ".mm-close" in css:
55 + print("styles.css: deja fait")
56 +elif not done:
57 + raise SystemExit("regle header-inner z-60 introuvable")
58 +else:
59 + open(css_path, "w").write(css)
60 + print("styles.css: OK")
61