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

8.9 KiB
Raw Permalink Blame History

#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.