Files
ObsiGate/docs/features/mobile-editor.md
T
bruno 45be3125de
CI / lint (push) Successful in 1m3s
CI / security (push) Successful in 46s
CI / test (push) Successful in 2m43s
CI / build (push) Successful in 38s
CI / e2e (push) Successful in 11m12s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
feat(mobile): editeur mobile natif - interface tactile optimisee (#69)
Barre d'outils Markdown flottante (gras/italique/code/liste/lien) sur la selection CodeMirror, bouton Coller persistant (contournement iOS), zoom par pincement + hauteur ajustable persistes, raccourcis swipe (gauche -> liens entrants, droite -> table des matieres), mode lecture plein ecran avec navigation entre fichiers du dossier. 22 tests JSDOM + spec E2E mobile. Docs: fiche feature, CHANGELOG, ROADMAP, guide i18n FR/EN, README.
2026-09-11 23:51:16 -04:00

6.3 KiB
Raw Blame History

#69 - Éditeur mobile natif — Interface tactile optimisée

Statut : ✅ Terminé — 100 % implémenté + 22 tests frontend (2026-09-11) Effort : 2-3 jours (réalisé) | Impact : 🟢 Références : Roadmap · Changelog

  • Fichiers clés :

    • frontend/js/mobile-editor.js — module complet (helpers purs + câblage UI)
    • frontend/style.css — barre flottante, poignée de redimensionnement, mode lecture, bottom sheet
    • frontend/index.html — section « Édition mobile » du guide intégré + lien de navigation
    • frontend/locales/{fr,en}.json — clés mobile_editor.* et help.mobile_editor_*
    • frontend/js/app.js — appel initMobileEditor() au démarrage
    • tests/frontend/mobile-editor.test.mjs — 22 tests JSDOM (helpers + câblage DOM)
    • .gitea/workflows/ci.yml — test ajouté au job lint
  • Description : sur téléphone et tablette, l'édition et la lecture s'adaptent au tactile : barre d'outils Markdown flottante, bouton « Coller » persistant, zoom par pincement, hauteur ajustable, gestes de balayage (liens entrants / table des matières) et mode lecture plein écran avec navigation d'un fichier à l'autre.


Architecture

mobile-editor.js
├── Helpers purs (testables)     clampZoom · detectSwipe · formatChange · insertText
│                                applyFormatToView · applyFormatToTextarea
└── Câblage UI (initMobileEditor)
    ├── Barre d'outils flottante  #me-toolbar        (gras/italique/code/liste/lien + A−/A+)
    ├── Presse-papiers            #me-paste          (Clipboard API + repli iOS)
    ├── Zoom pincement            touchstart/move    (2 doigts → taille de police)
    ├── Hauteur ajustable         #me-resize-handle  (poignée, persistée)
    ├── Bottom sheet              #me-sheet          (liens entrants / table des matières)
    ├── Raccourcis swipe          #content-area      (gauche → backlinks, droite → TOC)
    └── Mode lecture              #me-reading-btn    (plein écran + navigation fichiers)

1. Barre d'outils mobile flottante

Injectée dans #editor-modal et affichée uniquement sous 768px lorsque l'éditeur est actif (.editor-modal.active .me-toolbar). Chaque bouton applique une transformation Markdown à la sélection courante de CodeMirror (ou du textarea de secours) :

Bouton Action Transformation
B bold **texte**
I italic *texte*
<> code `texte`
• list préfixe - sur chaque ligne sélectionnée
🔗 link [texte](url) avec le curseur placé sur url
  • Toggle : ré-appuyer sur un bouton alors que la sélection porte déjà les marqueurs retire ces marqueurs (ex. **hi** sélectionné → hi).
  • Sans sélection : les marqueurs sont insérés et le curseur est placé à l'intérieur.
  • Les helpers formatChange() (calcul de la transaction) et applyFormatToView() / applyFormatToTextarea() (application) sont purs côté calcul → testables sans CodeMirror.

2. Presse-papiers — bouton « Coller » persistant

iOS Safari n'autorise navigator.clipboard.readText() que sur geste utilisateur explicite et peut le refuser. Le bouton 📋 :

  1. tente navigator.clipboard.readText() ;
  2. en cas de refus ou d'absence, affiche un message d'aide (mobile_editor.paste_hint) invitant à appuyer longuement dans le champ puis à choisir « Coller » ;
  3. en cas de succès, insère le texte au niveau du curseur (CodeMirror ou textarea).

3. Adaptation CodeMirror

  • Zoom par pincement : deux doigts sur #editor-body calculent le ratio de distance et ajustent la taille de police du .cm-scroller (bornée 10–28px). Boutons A−/A+ pour les utilisateurs sans geste tactile.
  • Hauteur ajustable : une poignée (#me-resize-handle) entre le corps de l'éditeur et le pied permet d'étirer/réduire la zone d'édition (flex: 0 0 <px>), bornée à 140px.
  • Les deux valeurs sont persistées dans localStorage (obsigate-editor-font-size, obsigate-editor-height) et réappliquées à chaque ouverture / changement de fichier via un MutationObserver.

4. Raccourcis swipe (lecture)

Sur #content-area, un touchstart/touchend unique détecte un geste horizontal (detectSwipe, seuil 60px, dominance horizontale requise) :

  • Balayage gauche → bottom sheet des liens entrants (fetch /api/file/{vault}/backlinks, clic → ouverture dans un onglet) ;
  • Balayage droite → bottom sheet de la table des matières (state.headingsCache, clic → scrollIntoView).

5. Mode lecture plein écran

Le bouton flottant 📖 (#me-reading-btn) bascule body.reading-mode :

  • masque l'en-tête, la sidebar, la barre latérale droite, la barre d'outils mobile et les actions de fichier ; centre le contenu en colonne de lecture ;
  • demande l'API Fullscreen (repli silencieux si non supportée, ex. iOS) ; la sortie du plein écran (Échap) resynchronise la classe ;
  • en mode lecture, le balayage horizontal navigue vers le fichier suivant/précédent du même dossier (/api/vault/{vault}/files?dir=…&recursive=false, tri alphabétique, bouclage borné avec message si extrémité atteinte) ;
  • l'état est mémorisé (obsigate-reading-mode) et restauré au rechargement sur mobile.

Tests

tests/frontend/mobile-editor.test.mjs (JSDOM, 22 tests) couvre :

  • FORMAT_ACTIONS, clampZoom, detectSwipe (seuil, dominance verticale, gauche/droite) ;
  • formatChange pour bold/italic/code/liste/lien, avec et sans sélection, toggle et ligne unique ;
  • insertText, applyFormatToTextarea, applyEditorFontSize (clamp + persistance) ;
  • le câblage DOM : construction de #me-toolbar, idempotence, contrôles du mode lecture, bascule toggleReadingMode/isReadingMode.

Les chemins réseau (backlinks, fichiers adjacents) et les gestes réels restent à valider en E2E navigateur / test manuel mobile.

Notes

  • Le module n'importe ui.js, auth.js et viewer.js que dynamiquement dans les fonctions concernées, afin de rester testable en JSDOM sans charger la pile applicative complète.
  • Aucune modification backend : les endpoints réutilisés (/backlinks, /vault/{vault}/files) existaient déjà.