From 520059d8667b503664ecaf18eb0514696500d8f1 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Sun, 13 Sep 2026 11:49:45 -0400 Subject: [PATCH] feat(mobile): ruban d'edition style Obsidian + correctifs mobile (#83, BUG-017 a BUG-020) - #83: ruban horizontal defilable ancre au-dessus du clavier, commandes etendues (titres, barre, surligne, code bloc, citation, listes, cases, wikilinks, tags, pieces jointes, undo/redo, colle, police) et personnalisation persistee via l'icone engrenage - BUG-017: cartes du tableau de bord compressibles (min-width:0) - BUG-018: en-tete editeur mobile compact, boutons Annuler/Sauvegarder accessibles, barre IA plus tactile - BUG-019: ancrage du ruban via visualViewport (--kb-offset) - BUG-020: suppression de la double barre de defilement Tests: mobile-editor 35/35, ai 50/50, 9 suites JSDOM, validate-imports, pytest 961 passed / 6 skipped, ruff + mypy 0. --- CHANGELOG.md | 30 ++ docs/ISSUES_TODOLIST.md | 9 +- docs/ROADMAP.md | 17 +- docs/archive/COMPLETED_v1-v2.md | 20 ++ frontend/index.html | 4 + frontend/js/mobile-editor.js | 476 +++++++++++++++++++++++--- frontend/locales/en.json | 37 +- frontend/locales/fr.json | 37 +- frontend/style.css | 241 ++++++++++--- tests/e2e/mobile-editor.spec.js | 14 +- tests/frontend/mobile-editor.test.mjs | 82 ++++- 11 files changed, 841 insertions(+), 126 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecdbc18..fca781d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,16 @@ et [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Ajouté +- **#83 Barre d'outils d'édition mobile — ruban style Obsidian Android** — la barre de mise en + forme flottante est remplacée par un **ruban horizontal défilable** ancré juste au-dessus du + clavier virtuel : fond anthracite aux coins arrondis, insertion/enrobage au curseur ou sur la + sélection. Commandes : annuler/refaire, `[[ ]]` (lien interne), fichiers/modèles, tag `#`, + pièce jointe, H1–H6, gras, italique, barré (`~~`), surligné (`==`), code en ligne/bloc, citation, + lien externe, listes à puces/numérotées, case à cocher, indenter/désindenter, coller, A−/A+. + Une icône **⚙** ouvre un panneau de personnalisation (ajouter / retirer / réordonner, persistance + `localStorage`). i18n FR/EN. Helpers purs exportés (`formatChange`, `normalizeRibbonCommands`, + `moveRibbonCommand`). Tests JSDOM `tests/frontend/mobile-editor.test.mjs` (+13) et E2E mobile. + - **#82 Assistant IA — menu `@` instantané** — nouvel endpoint `GET /api/vault/{vault}/paths` (liste plate et plafonnée de l'index des chemins). Le frontend la récupère **une fois par vault** (préchargée à l'ouverture du panneau) puis filtre **côté client** pendant la frappe : l'affichage @@ -291,6 +301,26 @@ et [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Corrigé +- **BUG-017 — Accueil mobile : tuiles « Favoris » / « Récents » mal dimensionnées** — les cartes + de tableau de bord débordaient horizontalement à cause d'un titre/chemin `nowrap` : ajout de + `min-width: 0` et `overflow: hidden` sur `.dashboard-card` (et ses en-têtes/pieds) pour que la + grille mobile (1 colonne) respecte la largeur du viewport. Les tuiles « Partagés » étaient déjà + conformes. + +- **BUG-018 — Éditeur mobile : boutons « Annuler » / « Sauvegarder » inaccessibles** — l'en-tête + cumulait marque, titre, nom de fichier et actions, poussant les boutons hors écran. Sur mobile, + les éléments secondaires (marque, séparateur, espaceur, présence) sont masqués, les champs + titre/nom de fichier deviennent compressibles (`flex`, `min-width: 0`) et le libellé « Saved » + est masqué (le point d'état reste). La barre d'outils IA reçoit des cibles tactiles plus grandes. + +- **BUG-019 — Éditeur mobile : barre d'outils masquée par le clavier** — le ruban est désormais + ancré via `window.visualViewport` (`--kb-offset`) pour rester juste au-dessus du clavier, quel + que soit le défilement, et le scroller CodeMirror reçoit un `padding-bottom` pour ne pas cacher + le curseur. + +- **BUG-020 — Éditeur mobile : double barre de défilement** — `.editor-body` passe en + `overflow: hidden` + colonne flex ; seul le scroller CodeMirror défile. + - **BUG-016 — Mobile : le bouton « mode lecture » recouvre le bouton d'envoi de l'assistant** — le bouton flottant `📖` (`#me-reading-btn`, `z-index: 890`) passait au-dessus du panneau assistant plein écran sur mobile (`z-index: 100`) et masquait le bouton d'envoi `✈️`. Il diff --git a/docs/ISSUES_TODOLIST.md b/docs/ISSUES_TODOLIST.md index 13cc22b..4d04eb6 100644 --- a/docs/ISSUES_TODOLIST.md +++ b/docs/ISSUES_TODOLIST.md @@ -126,10 +126,10 @@ Avant de corriger quoi que ce soit, un agent IA doit : | *BUG-014* | Assistant IA : les flèches ↑/↓ ne naviguent pas dans les menus `/` et `@` | 🟢 corrigé | P1 | 📱 frontend | IA | `frontend/js/bookslm.js` | Ouvrir `/`, puis ↑/↓ (y compris après un clic hors zone de texte) | Navigation gérée au niveau du **panneau en phase de capture** (`panel.addEventListener('keydown', ..., true)`), donc indépendante du focus | Le `keydown` n'était écouté que sur la zone de texte ; dès que le focus changeait, les flèches étaient ignorées. Tests : `tests/frontend/ai.test.mjs` (+1) | | *BUG-015* | Assistant IA : la ligne sélectionnée des menus `/` et `@` est invisible au clavier | 🟢 corrigé | P2 | 📱 frontend | IA | `frontend/style.css` | Ouvrir `/` ou `@`, naviguer avec ↑/↓ | État `.active` en `--bg-hover` + barre d'accent à gauche (`inset 3px 0 0 var(--accent)`) au lieu de `--surface2` | `--surface2` est identique à `--bg-primary` (fond du menu) en thème sombre : la sélection ne se voyait pas. Idem pour la liste de modèles | | *BUG-016* | Mobile : le bouton « mode lecture » flottant recouvre le bouton d'envoi de l'assistant IA | 🟢 corrigé | P2 | 📱 frontend | IA | `frontend/js/mobile-editor.js`, `frontend/style.css` | Mobile, sans fichier ouvert : ouvrir l'assistant puis constater que `📖` masque `✈️` | `updateReadingButtonVisibility()` n'affiche `#me-reading-btn` que si `state.currentPath` est défini **et** que le panneau assistant est fermé ; resynchronisé à chaque mutation de `#content-area` et sur `bookslm:opened`/`bookslm:closed` ; règle `.me-reading-btn[hidden]{display:none}` | Le bouton flottant (z-index 890) passait au-dessus du panneau plein écran mobile (z-index 100). Tests : `tests/frontend/mobile-editor.test.mjs` (+2) | -| *BUG-017* | Accueil mobile : les tuiles de « Favoris » et « Récents » ne s'affichent pas correctement en largeur (l'onglet « Partagés » s'affiche correctement) | 🔴 ouvert | P2 | 📱 frontend | IA | `frontend/js/dashboard.js`, `frontend/js/viewer.js`, `frontend/style.css` | Mobile : page d'accueil → onglets Favoris / Récents | — | Grille de tuiles non adaptée au viewport (largeur / nombre de colonnes) ; l'onglet « Partagés » (`.shared-card`) est conforme | -| *BUG-018* | Éditeur mobile : mise en page inadaptée — boutons « Annuler » / « Sauvegarder » inaccessibles et barre d'outils IA non optimisée | 🔴 ouvert | P1 | 📱 frontend | IA | `frontend/index.html`, `frontend/style.css`, `frontend/js/ai.js` | Mobile : ouvrir un fichier → barre d'outils de l'éditeur puis panneau assistant | — | Boutons de l'éditeur hors écran / masqués sur petit écran ; barre d'outils IA trop dense ou mal positionnée | -| *BUG-019* | Éditeur mobile : la barre d'outils du bas n'est pas toujours visible au-dessus du clavier quand le curseur n'est pas en bas de l'éditeur | 🔴 ouvert | P1 | 📱 frontend | IA | `frontend/js/mobile-editor.js`, `frontend/style.css` | Mobile : ouvrir un fichier, placer le curseur au milieu du document, afficher le clavier | — | La barre ne suit pas la position du curseur / n'est pas ancrée au-dessus du clavier virtuel | -| *BUG-020* | Éditeur mobile : deux barres de défilement verticales à droite de la page en mode édition | 🔴 ouvert | P3 | 📱 frontend | IA | `frontend/style.css` | Mobile : ouvrir l'éditeur et observer le bord droit | — | Double scrollbar (conteneur de l'éditeur + `.cm-scroller`) peu naturelle pour un éditeur | +| *BUG-017* | Accueil mobile : les tuiles de « Favoris » et « Récents » ne s'affichent pas correctement en largeur (l'onglet « Partagés » s'affiche correctement) | 🟢 corrigé | P2 | 📱 frontend | IA | `frontend/style.css` | Mobile : page d'accueil → onglets Favoris / Récents | `frontend/style.css` : `min-width:0` + `overflow:hidden` sur `.dashboard-card` (et header/footer) → la grille 1 colonne ne déborde plus | Cause : titre/chemin `nowrap` forçaient la largeur mini de la carte | +| *BUG-018* | Éditeur mobile : mise en page inadaptée — boutons « Annuler » / « Sauvegarder » inaccessibles et barre d'outils IA non optimisée | 🟢 corrigé | P1 | 📱 frontend | IA | `frontend/style.css` | Mobile : ouvrir un fichier → barre d'outils de l'éditeur puis panneau assistant | `frontend/style.css` : en-tête mobile compact (marque/séparateur/espaceur/présence masqués, champs compressibles, libellé « Saved » masqué) + cibles tactiles `.ai-toolbar-btn` agrandies | Les 3 boutons d'action restent accessibles ; voir aussi #83 pour le ruban | +| *BUG-019* | Éditeur mobile : la barre d'outils du bas n'est pas toujours visible au-dessus du clavier quand le curseur n'est pas en bas de l'éditeur | 🟢 corrigé | P1 | 📱 frontend | IA | `frontend/js/mobile-editor.js`, `frontend/style.css` | Mobile : ouvrir un fichier, placer le curseur au milieu du document, afficher le clavier | `initKeyboardAnchor()` utilise `window.visualViewport` (`--kb-offset`) pour ancrer le ruban au-dessus du clavier ; `padding-bottom` sur `.cm-scroller` | Fonctionne quel que soit le défilement / la position du curseur | +| *BUG-020* | Éditeur mobile : deux barres de défilement verticales à droite de la page en mode édition | 🟢 corrigé | P3 | 📱 frontend | IA | `frontend/style.css` | Mobile : ouvrir l'éditeur et observer le bord droit | `frontend/style.css` : `.editor-body` en `overflow:hidden` + colonne flex ; seul `.cm-scroller` défile | Une seule barre de défilement | | *BUG-021* | [🔴 CRITIQUE] XSS stocké via le rendu markdown (`escape=False`) | 🟢 corrigé | P0 | 🔐 sécurité | IA | `backend/services/sanitizer.py`, `backend/main.py` | Ouvrir une note contenant `` | `backend/services/sanitizer.py` (whitelist stdlib) appliqué après `_add_heading_ids` dans `_render_markdown` ; tests `tests/test_security_hardening.py` | HTML brut d'un vault injecté dans le DOM → JS dans le navigateur de chaque utilisateur. DOMPurify client non ajouté (défense serveur suffisante) | | *BUG-022* | [🔴 CRITIQUE] XSS stocké sur la page publique `/s/{token}` (title + frontmatter non échappés) | 🟢 corrigé | P0 | 🔐 sécurité | IA | `backend/main.py` | Partager une note dont le frontmatter contient un `title` avec `