feat(mobile): editeur mobile natif - interface tactile optimisee (#69)
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
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
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.
This commit is contained in:
+4
-14
@@ -44,17 +44,6 @@
|
||||
|
||||
## ⚪ Backlog — Priorité 4 (P4)
|
||||
|
||||
### 69. Éditeur mobile natif — Interface tactile optimisée
|
||||
|
||||
- **Effort :** 2-3 jours | **Impact :** 🟢
|
||||
- **Description :** Refonte de l'expérience mobile pour l'édition : barre d'outils contextuelle, presse-papiers optimisé, gestes tactiles (swipe pour actions rapides), mode lecture plein écran.
|
||||
- **Sous-tâches :**
|
||||
- [ ] Barre d'outils mobile flottante : **bold**, *italic*, `code`, liste, lien (inspirée de l'éditeur Obsidian mobile)
|
||||
- [ ] Raccourcis swipe : gauche → backlinks, droite → table des matières
|
||||
- [ ] Mode lecture : cache sidebar + header, plein écran, swipe horizontal pour page suivante
|
||||
- [ ] Presse-papiers : bouton « Coller » persistant (iOS contourne restriction clipboard)
|
||||
- [ ] Adaptation CodeMirror : hauteur ajustable, police agrandissable (pinch zoom)
|
||||
|
||||
### 70. Recherche sémantique — Embeddings vectoriels
|
||||
|
||||
- **Effort :** 4-5 jours | **Impact :** 🟢
|
||||
@@ -126,6 +115,7 @@
|
||||
| 62 | Collaboration temps réel — Édition simultanée (Yjs/CRDT, WebSocket, awareness) | 2.3.0 | [features/collaboration.md](./features/collaboration.md) |
|
||||
| 79 | Assistant IA — Outils (function calling) & serveur MCP | 2.3.0 | [features/ai-tools-mcp.md](./features/ai-tools-mcp.md) |
|
||||
| 80 | Assistant IA — Rendu Markdown, liens fichiers/paths & sessions | 2.3.0 | [features/ai-assistant-ux.md](./features/ai-assistant-ux.md) |
|
||||
| 69 | Éditeur mobile natif — Interface tactile optimisée | 2.3.0 | [features/mobile-editor.md](./features/mobile-editor.md) |
|
||||
| 77 | Application Desktop native — Tauri | 🔵 en cours | [features/desktop-tauri.md](./features/desktop-tauri.md) |
|
||||
|
||||
---
|
||||
@@ -134,10 +124,10 @@
|
||||
|
||||
| Priorité | Items | Effort total estimé |
|
||||
|---|---|---|
|
||||
| ✅ Complété | #1 → #59, #61–68, #71, #72, #74–76, #78–80 | ~97 jours réalisés |
|
||||
| ✅ Complété | #1 → #59, #61–72, #74–76, #78–80 | ~99 jours réalisés |
|
||||
| 🔵 P2 restant | #77 Desktop : signature code (optionnel), wizard 1er lancement (optionnel), 6 tests E2E **manuels** | ~1-2 jours |
|
||||
| ⚪ P4 restant | #69 Mobile éditeur (2-3j) · #70 Sémantique (4-5j) · #73 Sync (6-8j) | 11-16 jours |
|
||||
| **Total restant** | **4 items + finitions** | **~12-18 jours** |
|
||||
| ⚪ P4 restant | #70 Sémantique (4-5j) · #73 Sync (6-8j) | 10-13 jours |
|
||||
| **Total restant** | **3 items + finitions** | **~11-15 jours** |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# #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](../ROADMAP.md) · [Changelog](../../CHANGELOG.md)
|
||||
|
||||
- **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à.
|
||||
Reference in New Issue
Block a user