Files
ObsiGate/docs/features/settings-mobile-114.md
T
bruno 9fb094f505
CI / lint (push) Successful in 2m1s
CI / security (push) Successful in 1m26s
CI / test (push) Successful in 4m50s
CI / build (push) Successful in 1m22s
CI / e2e (push) Successful in 15m34s
feat: refonte mobile de la section Configurations #114
2026-09-24 08:43:18 -04:00

173 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# #114 — Configuration — refonte mobile-responsive de la section Settings
> **Statut :** 🟢 · **Impact :** 🟡 · **Zone :** frontend (mobile, ≤ 768 px)
> **Fichiers :** `frontend/index.html`, `frontend/js/config.js`, `frontend/style.css`,
> `frontend/locales/{fr,en}.json`, `tests/frontend/config-mobile.test.mjs`,
> `tests/e2e/config-mobile.spec.js`.
## Contexte
La page **Configurations** (`#config-modal`) était utilisable en mobile seulement
partiellement (correctifs BUG-071) : le sommaire s'ouvrait en bloc haut, la modale
n'était pas plein écran, les cibles tactiles étaient sous 44 px, le clavier virtuel
iOS zoomait les champs, la rangée « Sauvegarder » disparaissait au scroll et plusieurs
dettes HTML/i18n étaient restées en place.
## Ce qui a été livré
### A. Sommaire en drawer coulissant
- `#config-nav` devient un **panneau coulissant gauche** (`position: fixed`,
`width: min(320px, 88vw)`, `z-index: 40`) sous un fond assombri
(`#config-modal.config-toc-open::before`, `z-index: 35`).
- Ouverture/fermeture pilotée par la classe **`.config-toc-open`** sur `#config-modal`
(JS `_setConfigNav`) + un `display` inline conservé pour le contrat de reset.
- Bouton **`#config-toc-close`** (classe `.help-toc-close`, `aria-label`
`config.toc_close`) dans l'en-tête du drawer ; visible uniquement dans le drawer
de la config (masqué sur desktop où la nav est toujours visible).
- **Backdrop** : un tap hors du drawer ferme d'abord le drawer, pas la modale
(`e.target === modal` → `config-toc-open` présent → `_setConfigNav(false)`).
- **Échap** : ferme le drawer d'abord, puis la modale.
- Fermeture de la modale (`closeConfigModal`) nettoie toujours la classe
`config-toc-open` et le `display` inline (aucun fond ne subsiste).
- Animation `config-toc-slide-in` (translateX) à l'ouverture.
### B. Modale plein écran
- `#config-modal` : `padding: 0`, `.editor-container` en `100vw × 100dvh`
(`100dvh` = hauteur du viewport dynamique, tient compte de la barre du navigateur
mobile), `border-radius: 0`, `border: none`.
- Le contenu (`#config-scroll`) garde son scroll propre ; le sous-bloc
`.config-content` reçoit un `padding-bottom: 80 px` pour ne jamais passer sous la
rangée sticky.
### C. Cibles tactiles ≥ 44 px & anti-zoom iOS
- **Champs** : `.config-input`, `.config-select`, `.help-nav-search`,
`.profile-field .config-input/.config-select` → `min-height: 44px` +
`font-size: 16px` (**anti-zoom iOS** : un `font-size < 16px` déclenche le zoom
automatique au focus). La règle est **scoppée `#config-modal`** pour ne pas écraser
`.mfa-code-input` (qui a sa propre typographie).
- **Boutons** : `.config-btn-save`, `.config-btn-secondary`, `.config-btn-primary`,
`.config-btn-danger`, `.config-btn-add`, `.config-btn-sm`, `.mfa-link-btn`,
`.theme-action-btn`, `.profile-avatar-actions .config-btn-secondary`,
`.editor-btn` (fermer), `#config-hamburger`, `#config-toc-close`,
`.help-search-clear` → `min-height/min-width: 44px`.
- **Liens du sommaire** : `.help-nav-link` → `min-height: 44px` (ligne tactile
confortable).
- `.help-hamburger` passe de 36 px à **44 px** en mobile (règle partagée avec le
modal d'aide).
### D. Rangée « Sauvegarder » sticky
- `.config-actions-row` (dans `#cfg-backend-settings`) → `position: sticky;
bottom: 0`, empilée verticalement (`flex-direction: column`), boutons pleine
largeur 44 px, fond opaque + bordure, `padding-bottom` avec
`env(safe-area-inset-bottom)` (barre home iOS).
- La rangée reste visible pendant le scroll de la section backend ; le
`padding-bottom: 80px` de `.config-content` garantit qu'elle ne masque jamais les
derniers contrôles.
### E. Formulaires 1 colonne & grilles
- `.config-row` → 1 colonne (`grid-template-columns: 1fr`), `.config-input--num`
pleine largeur, `text-align: left`.
- `.ai-default-grid` / `.ai-provider-fields` → 1 colonne.
- Add-rows (`.config-add-row`, `.config-add-pattern`) → wrap + largeurs inline
(`180/140/100px`) neutralisées (`width: auto !important`).
- Items webhook/token/share → wrap ; URLs/méta sur leur propre ligne
(`overflow-wrap: anywhere`) ; boutons de suppression 44 px.
- `.hidden-files-add-row` → wrap, input pleine largeur.
- `.config-diag-row` → wrap.
- `.profile-avatar-row` → wrap ; `.profile-form` → `max-width: 100%`.
- `.webauthn-key-item` → wrap ; `.webauthn-key-label` → pleine largeur.
- `.theme-grid` reste en `auto-fill minmax(160px, 1fr)` (déjà responsive).
### F. MFA & sécurité
- `.mfa-recovery-list` → **1 colonne** en mobile (2 colonnes illisibles à 360 px).
- `.mfa-verify-section`, `.mfa-recovery-actions`, `.mfa-disable-actions` → wrap ;
champs/boutons enfants en pleine largeur.
- `.mfa-code-input` → `width: 100%`, `max-width: 320px`, `letter-spacing: 6px`
(au lieu de 12 px qui débordait), `min-height: 52px`.
- `.mfa-secret-code` → `word-break: break-all` (secret TOTP long).
- `.mfa-code-input-group` → wrap.
- Règle morte **`.mfa-recovery-input`** supprimée (auth.js utilise
`mfa-code-input recovery-input`).
### G. Dettes HTML corrigées
- `.config-actions-row` (Sauvegarder / Réindexer / Réinitialiser) déplacée
**dans** `#cfg-backend-settings` (elle était hors de toute section → le sticky
n'avait pas de conteneur de scroll fiable) ; `</section>` orphelin supprimé.
- Id dupliqué **`cfg-partages-publics`** retiré du `<h2>` (l'id reste sur la
`<section>`, cf. #113).
- Conteneur mort **`#plugins-settings-container`** supprimé (le rendu réel est
`#cfg-plugins` via `plugins.js`).
- Sections plugins/about ré-indentées.
- **`#mt-explorer`** : libellé brut `settings.search` remplacé par
`<span data-i18n="settings.explorer">` (i18n correct, FR « Explorateur » / EN
« Files »).
- Doublons CSS **`.config-btn-add`** (3 définitions) réduits à la définition de
référence.
### H. i18n FR/EN
- **Purge des clés mortes** (aucune référence HTML/JS/tests/backend) :
`settings.backend`, `settings.backend_hint`, `settings.restart_badge`,
`settings.save`, `settings.plugins`.
- **Ajouts** : `settings.explorer` (FR « Explorateur » / EN « Files »),
`config.toc_close` (FR « Fermer le sommaire » / EN « Close contents »).
- **Correctif** : `settings.tabs` en FR était le mot anglais « Tabs » →
**« Onglets »** (EN reste « Tabs »).
- Clés vivantes conservées : `settings.reindex`, `settings.no_restart_badge`,
`settings.backend_section`, `settings.security`, `settings.search`,
`settings.tabs`, `settings.search_placeholder`.
## Tests
### Statics — `tests/frontend/config-mobile.test.mjs` (27, au CI)
- BUG-071a–e (hamburger, toggle JS, grilles/wrap, ancres mortes,
`data-i18n-attr` multi-paires) — conservés et adaptés au drawer.
- **#114a** : `#config-toc-close` présent + i18n ; `_setConfigNav` bascule
`.config-toc-open` ; backdrop `::before` (z-index 35) ; `.help-toc-close`
masqué sur desktop / visible dans le drawer ; Échap et backdrop ferment le
drawer d'abord ; `closeConfigModal` nettoie la classe.
- **#114b** : modale `100dvh` + `padding: 0` ; inputs/selects `16px` +
`44px` ; boutons `44px` ; rangée sticky (`position: sticky` +
`flex-direction: column` + safe-area) ; MFA 1 colonne + wrap + code
full-width ; `.config-actions-row` bien dans `#cfg-backend-settings`.
- **#114i18n** : clés mortes purgées ; `settings.explorer` FR/EN ;
`settings.tabs` FR = « Onglets » ; `#mt-explorer` porte
`data-i18n="settings.explorer"` ; `#plugins-settings-container` absent.
### E2E — `tests/e2e/config-mobile.spec.js` (5, projet `chromium-mobile`)
1. Hamburger → drawer `position: fixed` + classe `config-toc-open` sur la modale.
2. Bouton `#config-toc-close` et tap backdrop ferment le drawer **sans** fermer la
modale.
3. Sélection d'une section → scroll doux + lien actif + repli du drawer.
4. Modale plein écran (largeur/hauteur ≈ viewport) + `#config-hamburger`,
`#config-close` et `#cfg-save-backend` ≥ 44 px.
5. Aucun débordement horizontal à 393 px (sections IA / tokens / webhooks /
partages).
## Détails d'implémentation notables
- **Spécificité CSS** : les règles `#config-modal #config-nav` (2 ids) priment sur
les règles génériques `.help-nav` / `body .help-nav` qui masquent la nav en
mobile — pas besoin de `!important`.
- **Backdrop = pseudo-élément** : les clics sur `::before` sont attribués à
l'élément or (`#config-modal`), donc le handler `e.target === modal` existant
fonctionne sans node supplémentaire.
- **Contrat de reset conservé** : `configNavOnOpen.style.display = ''` à
l'ouverture (test statique BUG-071b) — le CSS reprend la main (drawer masqué par
défaut sur mobile).
- **`100dvh` avec repli `100vh`** : les navigateurs sans support `dvh` gardent le
comportement précédent.
- La règle `.help-hamburger { display: inline-flex }` du bloc mobile du modal
d'aide est **partagée** (44 px) ; le drawer de la config double avec
`#config-modal .help-hamburger` pour rester robuste à un réordonnancement des
règles.