Compare commits

...
1 Commits
Author SHA1 Message Date
bruno 36b4962efb feat: tableur mobile — barres repliées par défaut, bascule unique #189
CI / lint (push) Successful in 2m42s
CI / security (push) Successful in 1m38s
CI / test (push) Successful in 4m19s
CI / build (push) Successful in 1m27s
CI / e2e (push) Successful in 17m12s
Sous 768 px, la barre de menus, le ruban et le groupe Recherche sont
repliés par défaut : la barre de formule (fx), les onglets et Enregistrer
restent visibles et la grille récupère la hauteur d'écran. Un bouton
unique (#xlsx-tools-toggle) dans la barre des feuilles déplie/replie
l'ensemble (aria-expanded, état actif) ; desktop inchangé.

Ergonomie tactile : cibles ≥ 44 px, onglets en défilement horizontal,
champs de la barre de formule en 16 px (anti-zoom iOS), barre de formule
en 2 lignes quand les outils sont ouverts.

Tests : JSDOM xlsx-viewer.test.mjs (+2, 165/165), E2E mobile (repli par
défaut, dépliage, no-overflow ruban, cibles 44 px) ; openXlsx() déplie
automatiquement ≤ 768 px pour les tests desktop.
2026-10-08 15:45:39 -04:00
17 changed files with 341 additions and 17 deletions
+25 -1
View File
@@ -6,7 +6,7 @@ Format basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/),
et [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
> **En cours de développement** : les changements à venir sont listés dans la section
> [Unreleased](#unreleased). La dernière version livrée est **2.55.0**.
> [Unreleased](#unreleased). La dernière version livrée est **2.56.0**.
---
@@ -14,6 +14,30 @@ et [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
---
## [2.56.0] — 2026-10-08
### Ajouté
- **#189 - Tableur : mise en page mobile (barres repliées, grille prioritaire)**
- Sur mobile (≤ 768 px), la **barre de menus** (Fichier, Modifier…), le
**ruban** de formatage et le **groupe Recherche** sont **repliés par
défaut** : la barre des feuilles et la **barre de formule (fx)** restent
toujours visibles, et la grille récupère la hauteur d'écran perdue
(l'ensemble dépassait 50 % de l'écran).
- Un **bouton unique** (`#xlsx-tools-toggle`, icône ☰) dans la barre des
feuilles déplie/replie le tout (`aria-expanded`, état actif) ; sur
desktop il reste masqué et rien ne bouge.
- **Ergonomie tactile** : cibles ≥ 44 px (boutons, menus, onglets), groupes
du ruban qui s'enroulent au lieu de déborder à cette taille, onglets de
feuilles sur une seule ligne qui **défile horizontalement**, champs de la
barre de formule en 16 px (pas de zoom iOS au focus), barre de formule qui
passe en 2 lignes quand les outils sont ouverts.
- Tests : JSDOM `xlsx-viewer.test.mjs` (bascule + règles CSS, 165/165) et
E2E mobile (repli par défaut, dépliage, ruban sans débordement, cibles
44 px).
---
## [2.55.0] — 2026-10-08
### Ajouté
+4 -4
View File
@@ -4,7 +4,7 @@
**Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive.
[![Version](https://img.shields.io/badge/Version-2.55.0-blue.svg)]()
[![Version](https://img.shields.io/badge/Version-2.56.0-blue.svg)]()
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Docker](https://img.shields.io/badge/Docker-Ready-blue.svg)](https://www.docker.com/)
[![Python](https://img.shields.io/badge/Python-3.11+-green.svg)](https://www.python.org/)
@@ -85,7 +85,7 @@ Les **guides d'utilisation** pas à pas se trouvent dans [`docs/GUIDES/`](docs/G
- **🖼️ Images Obsidian** : Support complet des syntaxes d'images Obsidian avec résolution intelligente
- **🎬 Audio & vidéo** : Lecteurs HTML5 intégrés (`.mp3 .wav .flac .mp4 .webm`…) avec streaming HTTP Range (lecture, déplacement, plein écran) et **lecture persistante** (mini-lecteur flottant / mini-fenêtre vidéo, retour au média ou arrêt à tout moment, contrôles écran verrouillé via Media Session), repli téléchargement si le format n'est pas lisible par le navigateur
- **🎨 Diagrammes Excalidraw** : Visualiseur/éditeur natif des fichiers `.excalidraw` et `.excalidraw.md` (iframe sandboxée, auto-save, thème clair/sombre, texte des diagrammes indexé pour la recherche)
- **📊 Tableurs Excel** : les fichiers `.xlsx` et `.xlsm` s'ouvrent dans un visualiseur dédié — un tableau par feuille avec onglets, en-têtes A1 et édition directe des cellules (`PUT /api/file/{vault}/xlsx/save`, backup automatique, écriture atomique), plus le téléchargement du fichier d'origine. Le visualiseur rend polices, couleurs, cellules fusionnées et volets figés, et offre navigation et raccourcis clavier (`Ctrl+S`, `Suppr`, `F2`, `Ctrl+Origine/Fin`, `PgPréc/PgSuiv`, `Ctrl+flèches`), barre de formule avec noms de fonctions, zone Nom éditable (« Atteindre » `A1:B3`), presse-papiers de plage (copier/couper/coller un bloc, depuis ou vers Excel), un menu **Mise en forme** (gras/italique/souligné, alignements, couleurs, formats de nombre, fusions, volets figés, largeur/hauteur — `PUT /api/file/{vault}/xlsx/style`), tri/filtre/recherche sur toutes les feuilles, export CSV/Markdown/HTML et impression (sélection ou feuille), édition de la structure (feuilles, lignes, colonnes) et un tableau de bord du classeur (plages nommées, détection graphiques/TCD, stats par feuille) ; un `.csv` s'édite dans la même grille (RFC 4180) tandis que `.xls` et `.ods` s'ouvrent en lecture seule. Les classeurs contenant des éléments qu'ObsiGate ne peut pas conserver (valeurs calculées, segments, contrôles de formulaire, signature…) affichent un **avertissement** et demandent confirmation avant l'enregistrement ; une saisie commençant par `=` ou `@` est stockée comme texte sauf activation du bouton `f(x)`, et les écritures concurrentes d'un autre poste sont détectées (`If-Match` → « Réessayer »). L'assistant IA peut lister les feuilles, injecter un tableau borné dans son contexte, rechercher dans le classeur, analyser une plage, modifier des cellules et ajouter des lignes — sur `.xlsx`, `.xlsm` et `.csv`
- **📊 Tableurs Excel** : les fichiers `.xlsx` et `.xlsm` s'ouvrent dans un visualiseur dédié — un tableau par feuille avec onglets, en-têtes A1 et édition directe des cellules (`PUT /api/file/{vault}/xlsx/save`, backup automatique, écriture atomique), plus le téléchargement du fichier d'origine. Le visualiseur rend polices, couleurs, cellules fusionnées et volets figés, et offre navigation et raccourcis clavier (`Ctrl+S`, `Suppr`, `F2`, `Ctrl+Origine/Fin`, `PgPréc/PgSuiv`, `Ctrl+flèches`), barre de formule avec noms de fonctions, zone Nom éditable (« Atteindre » `A1:B3`), presse-papiers de plage (copier/couper/coller un bloc, depuis ou vers Excel), un menu **Mise en forme** (gras/italique/souligné, alignements, couleurs, formats de nombre, fusions, volets figés, largeur/hauteur — `PUT /api/file/{vault}/xlsx/style`), tri/filtre/recherche sur toutes les feuilles, export CSV/Markdown/HTML et impression (sélection ou feuille), édition de la structure (feuilles, lignes, colonnes) et un tableau de bord du classeur (plages nommées, détection graphiques/TCD, stats par feuille) ; un `.csv` s'édite dans la même grille (RFC 4180) tandis que `.xls` et `.ods` s'ouvrent en lecture seule. Les classeurs contenant des éléments qu'ObsiGate ne peut pas conserver (valeurs calculées, segments, contrôles de formulaire, signature…) affichent un **avertissement** et demandent confirmation avant l'enregistrement ; une saisie commençant par `=` ou `@` est stockée comme texte sauf activation du bouton `f(x)`, et les écritures concurrentes d'un autre poste sont détectées (`If-Match` → « Réessayer »). L'assistant IA peut lister les feuilles, injecter un tableau borné dans son contexte, rechercher dans le classeur, analyser une plage, modifier des cellules et ajouter des lignes — sur `.xlsx`, `.xlsm` et `.csv`. Sur mobile (≤ 768 px), la barre de menus et le ruban sont **repliés par défaut** — un bouton ☰ les déplie — pour que la grille occupe toute la hauteur d'écran
- **🎨 Syntax highlight** : Coloration syntaxique des blocs de code
- **🌓 Thème clair/sombre** : Toggle persisté en localStorage
- **📡 Synchronisation temps réel** : Surveillance automatique des fichiers via watchdog avec mise à jour incrémentale de l'index
@@ -976,8 +976,8 @@ Ce projet est sous licence **MIT** — voir le fichier [LICENSE](LICENSE) pour l
## 📝 Changelog
Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v2.55.0).
Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v2.56.0).
---
*Projet : ObsiGate | Version : 2.55.0 | Dernière mise à jour : Septembre 2026*
*Projet : ObsiGate | Version : 2.56.0 | Dernière mise à jour : Septembre 2026*
+4 -4
View File
@@ -2,7 +2,7 @@
**Ultra-light web gateway for your Obsidian vaults** — Access, browse, and search all your Obsidian notes from any device via a modern, responsive web interface.
[![Version](https://img.shields.io/badge/Version-2.55.0-blue.svg)]()
[![Version](https://img.shields.io/badge/Version-2.56.0-blue.svg)]()
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Docker](https://img.shields.io/badge/Docker-Ready-blue.svg)](https://www.docker.com/)
[![Python](https://img.shields.io/badge/Python-3.11+-green.svg)](https://www.python.org/)
@@ -84,7 +84,7 @@ Step-by-step **user guides** live in [`docs/GUIDES/`](docs/GUIDES/):
- **🖼️ Obsidian Images** : Full support for all Obsidian image syntaxes with intelligent resolution
- **🎬 Audio & video** : Built-in HTML5 players (`.mp3 .wav .flac .mp4 .webm`…) with HTTP Range streaming (play, seek, fullscreen) and **persistent playback** (floating mini-player / mini video window, return to media or stop anytime, lock-screen controls via Media Session), falling back to download when the format is not playable in the browser
- **🎨 Excalidraw Diagrams** : Native viewer/editor for `.excalidraw` and `.excalidraw.md` files (sandboxed iframe, autosave, dark/light theme, diagram text indexed for search)
- **📊 Excel Spreadsheets** : `.xlsx` and `.xlsm` files open in a dedicated viewer — one table per sheet with tabs, A1 headers and inline cell editing (`PUT /api/file/{vault}/xlsx/save`, automatic backup, atomic write), plus download of the original file. The viewer renders fonts, colors, merged cells and frozen panes, offers keyboard navigation and shortcuts (`Ctrl+S`, `Delete`, `F2`, `Ctrl+Home/End`, `PgUp/PgDn`, `Ctrl+arrows`), a formula bar with function suggestions, an editable Name Box ("go to" `A1:B3`), a range clipboard (copy/cut/paste a block, from or to Excel), a **Format** menu (bold/italic/underline, alignments, font & fill colours, number formats, merges, frozen panes, column width/row height — `PUT /api/file/{vault}/xlsx/style`), sort/filter/find across every sheet, CSV/Markdown/HTML export and printing (selection or sheet), sheet & row/column structure editing and a workbook dashboard (named ranges, charts/pivot detection, per-sheet stats); `.csv` is edited in the same grid (RFC 4180) while `.xls` and `.ods` open read-only. Workbooks holding elements ObsiGate cannot preserve (cached values, slicers, form controls, signature…) show a **warning** and ask for confirmation before saving; a value starting with `=` or `@` is stored as text unless the `f(x)` toggle is enabled, and concurrent writes from another process are detected (`If-Match` → "Retry"). The AI assistant can list sheets, dump a bounded table to its context, search the workbook, analyze a range, update cells and append rows — on `.xlsx`, `.xlsm` and `.csv`
- **📊 Excel Spreadsheets** : `.xlsx` and `.xlsm` files open in a dedicated viewer — one table per sheet with tabs, A1 headers and inline cell editing (`PUT /api/file/{vault}/xlsx/save`, automatic backup, atomic write), plus download of the original file. The viewer renders fonts, colors, merged cells and frozen panes, offers keyboard navigation and shortcuts (`Ctrl+S`, `Delete`, `F2`, `Ctrl+Home/End`, `PgUp/PgDn`, `Ctrl+arrows`), a formula bar with function suggestions, an editable Name Box ("go to" `A1:B3`), a range clipboard (copy/cut/paste a block, from or to Excel), a **Format** menu (bold/italic/underline, alignments, font & fill colours, number formats, merges, frozen panes, column width/row height — `PUT /api/file/{vault}/xlsx/style`), sort/filter/find across every sheet, CSV/Markdown/HTML export and printing (selection or sheet), sheet & row/column structure editing and a workbook dashboard (named ranges, charts/pivot detection, per-sheet stats); `.csv` is edited in the same grid (RFC 4180) while `.xls` and `.ods` open read-only. Workbooks holding elements ObsiGate cannot preserve (cached values, slicers, form controls, signature…) show a **warning** and ask for confirmation before saving; a value starting with `=` or `@` is stored as text unless the `f(x)` toggle is enabled, and concurrent writes from another process are detected (`If-Match` → "Retry"). The AI assistant can list sheets, dump a bounded table to its context, search the workbook, analyze a range, update cells and append rows — on `.xlsx`, `.xlsm` and `.csv`. On mobile (≤ 768 px), the menu bar and ribbon are **collapsed by default** — a single ☰ button expands them — so the grid gets the full screen height
- **🎨 Syntax Highlight** : Syntax highlighting for code blocks
- **🌓 Light/Dark Theme** : Toggle persisted in localStorage
- **📡 Real-time Sync** : Automatic file monitoring via watchdog with incremental index updates
@@ -1151,8 +1151,8 @@ This project is licensed under the **MIT License** - see the [LICENSE](LICENSE)
## 📝 Changelog
See [CHANGELOG.md](./CHANGELOG.md) for the complete version history (v1.0.0 → v2.55.0).
See [CHANGELOG.md](./CHANGELOG.md) for the complete version history (v1.0.0 → v2.56.0).
---
*Project: ObsiGate | Version: 2.55.0 | Last updated: September 2026*
*Project: ObsiGate | Version: 2.56.0 | Last updated: September 2026*
+1 -1
View File
@@ -1 +1 @@
2.55.0
2.56.0
+1 -1
View File
@@ -2626,7 +2626,7 @@ dependencies = [
[[package]]
name = "obsigate-desktop"
version = "2.55.0"
version = "2.56.0"
dependencies = [
"chrono",
"env_logger",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "obsigate-desktop"
version = "2.55.0"
version = "2.56.0"
description = "ObsiGate Desktop — Porte d'entrée native pour vos vaults Obsidian"
authors = ["Bruno Charest"]
edition = "2021"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/nicedoc/obsigate/main/desktop/tauri.conf.schema.json",
"productName": "ObsiGate",
"version": "2.55.0",
"version": "2.56.0",
"identifier": "com.obsigate.desktop",
"build": {
"frontendDist": "../frontend",
+8
View File
@@ -155,6 +155,14 @@ regroupe figeage, tri, filtre, dimensions, lien, commentaire ; les menus
haut** de la page et l'éditeur occupe toute la largeur du contenu, pour que
les commandes restent atteignables pendant le défilement d'un grand tableau.
**Mise en page mobile** — sur un écran étroit (≤ 768 px), la barre de menus et
le ruban de formatage sont **repliés par défaut** afin que la grille occupe
toute la hauteur disponible : seuls les onglets de feuilles, **Enregistrer** et
la **barre de formule (fx)** restent affichés. Le bouton **☰** (à gauche des
onglets) déplie/replie l'ensemble ; les commandes tactiles font au moins
44 px, les onglets défilent horizontalement et les champs de saisie restent en
16 px pour éviter le zoom automatique d'iOS.
Les largeurs de colonnes et hauteurs de lignes s'ajustent en **glissant le
bord des en-têtes** (souris et tactile) : en plaçant le pointeur sur le bord
d'un en-tête de colonne (`A`, `B`, `C`…) ou de ligne (`1`, `2`, `3`…), le
+30 -1
View File
@@ -1,6 +1,6 @@
# ObsiGate — Roadmap
> **Version :** 2.55.0 | **Dernière mise à jour :** 2026-10-08
> **Version :** 2.56.0 | **Dernière mise à jour :** 2026-10-08
> **Ce fichier ne contient que le travail à venir** (🔵 En cours + ⚪ Backlog) et un index compact
> vers les fonctionnalités livrées.
> - **Méthode de livraison à appliquer pour toute tâche : [DELIVERY_WORKFLOW.md](./DELIVERY_WORKFLOW.md)**
@@ -528,6 +528,34 @@
---
## ✅ Terminé — Mise en page mobile du tableur
### 189. Tableur — mise en page mobile (barres repliées, grille prioritaire)
- **Effort :** 0,5-1 jour | **Impact :** 🟡 | **Framework :** CSS vanilla + `frontend/js/viewer.js`
- **Statut :** ✅ **livré le 2026-10-08** — ouvert le 2026-10-08
- **Fiche :** [features/xlsx-mobile-layout-189.md](./features/xlsx-mobile-layout-189.md)
- **Description :** sur mobile, la barre de menus + le ruban + la barre de
formule s'empilaient et occupaient plus de 50 % de la hauteur d'écran.
Sous 768 px, `.xlsx-menubar`, `.xlsx-cmdbar` et le groupe Recherche sont
**repliés par défaut** (la barre de formule fx et les onglets restent
visibles) et un **bouton unique** `#xlsx-tools-toggle` dans la barre des
feuilles déplie/replie l'ensemble (`aria-expanded`, état actif) — desktop
inchangé (bouton masqué).
- **Sous-tâches :**
- [x] **A1** Repli CSS par défaut ≤ 768 px + révélation via
`.xlsx-toolbar.xlsx-tools-open` (menubar, ruban, Recherche)
- [x] **A2** Bascule `#xlsx-tools-toggle` dans `.xlsx-sheetbar`
(`aria-expanded` + classe `active` + i18n `xlsx.tools_toggle` FR/EN)
- [x] **A3** Tactile : cibles ≥ 44 px, onglets en défilement horizontal,
champs de la barre de formule en 16 px (anti-zoom iOS), barre de
formule en 2 lignes quand les outils sont ouverts
- [x] **A4** Tests : JSDOM `xlsx-viewer.test.mjs` (+2, 165/165) et E2E
mobile (repli par défaut, dépliage, no-overflow ruban, 44 px) ;
`openXlsx()` déplie automatiquement ≤ 768 px pour les tests desktop
---
## ⚪ Backlog — Priorité 4 (P4)
### 73. Synchronisation multi-appareils — Obsidian Sync compatible
@@ -721,6 +749,7 @@
| 185 | Tableur — barre de menus Google Sheets (10 menus), ruban Sheets, grille unie | 2.54.0 | [features/xlsx-menus-185.md](./features/xlsx-menus-185.md) |
| 186 | Création d'un fichier Excel (`.xlsx`) depuis la modale « Créer un fichier » | 2.54.0 | [features/create-file-xlsx-186.md](./features/create-file-xlsx-186.md) |
| 188 | Secrets — détection universelle des clés API & mots de passe, masque cliquable (clic = copie) | Unreleased | [features/secret-mask-188.md](./features/secret-mask-188.md) |
| 189 | Tableur — mise en page mobile : barres repliées par défaut, bascule unique, cibles tactiles 44 px | Unreleased | [features/xlsx-mobile-layout-189.md](./features/xlsx-mobile-layout-189.md) |
| 159 | Desktop — gestion des vaults & dossiers : retrait par menu contextuel + section Configuration (ajout vault/dossier racine) | 2.50.0 | [features/desktop-tauri.md](./features/desktop-tauri.md) |
| 160 | Desktop — premier lancement professionnel (répertoire `%USERPROFILE%\ObsiGate` + `Prise en main.md`) et section Configuration harmonisée | 2.51.0 | [features/desktop-tauri.md](./features/desktop-tauri.md) |
| BUG-047 | Versionnage — source unique `VERSION` + bump SemVer automatique au commit (hooks + tag) | 2.3.0 | [DEVELOPMENT_AND_RELEASES.md](./DEVELOPMENT_AND_RELEASES.md) |
+81
View File
@@ -0,0 +1,81 @@
# #189 — Tableur : mise en page mobile (barres repliées, grille prioritaire)
> **Statut :** ✅ livré (2026-10-08) | **Effort :** 0,5-1 jour | **Impact :** 🟡
> **Références :** [Roadmap](../ROADMAP.md) · [Changelog](../../CHANGELOG.md) ·
> [#180](./xlsx-sheetbar-180.md) · [#185](./xlsx-menus-185.md)
## 1. Constat
Sur mobile, l'empilement `.xlsx-menubar` (10 menus) + `.xlsx-cmdbar`
(~40 boutons qui s'enroulent sur 4-5 rangées) + `.xlsx-sheetbar` +
`.xlsx-formula-bar` occupait **plus de 50 % de la hauteur d'écran** : la
grille, objet premier de l'éditeur, passait après la chrome.
## 2. Livré
### A1 — Repli par défaut (CSS, ≤ 768 px)
Bloc `#189` dans `frontend/style.css` (après les règles `pointer: coarse`) :
- `.xlsx-menubar`, `.xlsx-cmdbar`, `.xlsx-find-group` → `display: none` par
défaut sous 768 px ;
- `.xlsx-toolbar.xlsx-tools-open …` les réaffiche (état de la classe portée
par la **barre entière**, donc menubar + ruban + Recherche restent cohérents) ;
- `.xlsx-formula-bar` reste **toujours visible** (zone Nom + `fx` + champ) et
passe en `flex-wrap` quand les outils sont ouverts (le groupe Recherche
réapparaît sur une 2ᵉ ligne) ;
- `.xlsx-tools-toggle { display: none }` sur desktop : **zéro changement
visuel hors mobile**.
### A2 — Bascule unique (JS)
`frontend/js/viewer.js` (`renderXlsxViewer`) :
- bouton `#xlsx-tools-toggle` (icône Lucide `menu`, `aria-expanded`,
`aria-label` i18n `xlsx.tools_toggle`) inséré **en tête de
`.xlsx-sheetbar`** — donc toujours visible, entre les onglets et Enregistrer ;
- listener : bascule `.xlsx-tools-open` sur `.xlsx-toolbar`, met à jour
`aria-expanded` + classe `active`, `safeCreateIcons()` pour l'icône.
### A3 — Ergonomie tactile (CSS)
- cibles ≥ **44 px** : `.xlsx-toolbar .btn-action`, `.xlsx-menubtn`,
`.xlsx-tab` / `.xlsx-tab-add` ; à cette taille un groupe du ruban
(police, nombre…) déborde d'un téléphone : `.xlsx-cmd-group` passe en
`flex: 0 1 auto; min-width: 0; flex-wrap: wrap` pour s'enrouler au lieu
de sortir de l'écran (contre-preuve E2E : `scrollWidth - clientWidth ≤ 1`) ;
- onglets de feuilles : une seule ligne, **défilement horizontal**
(`overflow-x: auto`, scrollbars masquées) au lieu d'enrouler ;
- champs de la barre de formule en **16 px** : en dessous, iOS zoome
automatiquement la page au focus (la « classique » debout de l'UI) ;
- groupe Recherche masqué avec le ruban pour ne pas écraser le champ de saisie.
### A4 — i18n
Clé `xlsx.tools_toggle` : FR « Afficher / masquer les barres d'outils » /
EN « Show / hide toolbars » (parité vérifiée par `tests/test_i18n_parity.py`).
## 3. Tests
- `tests/frontend/xlsx-viewer.test.mjs` (+2, **165/165**) :
1. la bascule vit dans la barre des feuilles et flippe correctement
classe / `aria-expanded` / `active` (aller-retour) ;
2. `style.css` masque menubar/ruban/Recherche par défaut sous 768 px et les
réaffiche via `.xlsx-tools-open` (44 px, onglets scrollables, inputs
16 px présents dans le bloc).
- `tests/e2e/xlsx-viewer.spec.js` — test mobile réécrit : repli par défaut
(menubar/ruban cachés, formule + onglets visibles) → dépliage → ruban sans
débordement horizontal → cibles ≥ 44 px → repli ; `openXlsx()` déplie
automatiquement sous 768 px pour que les tests « desktop » restent valables
sur les deux viewports.
## 4. Limites assumées
- Le repli est piloté par la **largeur** (`max-width: 768px`), pas par
`pointer: coarse` : une tablette large en mode tactile garde la chrome
complète (elle a la hauteur pour).
- Le groupe Recherche n'est accessible sur mobile qu'avec les outils ouverts
; le reset de tri reste atteignable par la mini-barre de sélection et le
menu Données (vérifié).
- Pas de drawer latéral ni de FAB : un seul bouton rétractable suffit à
l'usage — ajouter un panneau glissant si le retour utilisateur le réclame.
+19
View File
@@ -1473,6 +1473,11 @@ const GRID_CHUNK_ROWS = 100; // rows materialised per extension step
<span class="xlsx-toolbar-actions">${actionsHtml}</span>
</div>
<div class="xlsx-sheetbar">
<button class="btn-action xlsx-tools-toggle" id="xlsx-tools-toggle" type="button"
aria-expanded="false" title="${escapeHtml(t("xlsx.tools_toggle"))}"
aria-label="${escapeHtml(t("xlsx.tools_toggle"))}">
<i data-lucide="menu" style="width:18px;height:18px" aria-hidden="true"></i>
</button>
${tabs}
<span class="xlsx-sheetbar-end">${fileHtml}</span>
</div>
@@ -1526,6 +1531,20 @@ const GRID_CHUNK_ROWS = 100; // rows materialised per extension step
// A re-render invalidates any open context menu (it targets the old DOM).
closeContextMenu();
// #189 — mobile : la barre de menus + le ruban sont repliés par défaut
// (cf. style.css ≤768px). Ce bouton, seul dans la barre des feuilles,
// déplie/replie le tout sans jamais masquer la barre de formule.
const toolsToggle = area.querySelector("#xlsx-tools-toggle");
const toolsBar = area.querySelector(".xlsx-toolbar");
if (toolsToggle && toolsBar) {
toolsToggle.addEventListener("click", () => {
const open = toolsBar.classList.toggle("xlsx-tools-open");
toolsToggle.setAttribute("aria-expanded", String(open));
toolsToggle.classList.toggle("active", open);
safeCreateIcons();
});
}
// ── #153 A17 — dashboard panel: named ranges, objects, per-sheet KPI ──
// Fetched lazily on first open of the dashboard tab; a workbook without
// anything notable hides the button entirely (no empty panel).
+1
View File
@@ -2050,6 +2050,7 @@
"xlsx.mbar_label": "Spreadsheet menus",
"xlsx.cmdbar_label": "Spreadsheet command bar",
"xlsx.tools_toggle": "Show / hide toolbars",
"xlsx.mbar_file": "File",
"xlsx.mbar_edit": "Edit",
"xlsx.mbar_view": "View",
+1
View File
@@ -2050,6 +2050,7 @@
"xlsx.mbar_label": "Menus du tableur",
"xlsx.cmdbar_label": "Barre de commandes du tableur",
"xlsx.tools_toggle": "Afficher / masquer les barres d'outils",
"xlsx.mbar_file": "Fichier",
"xlsx.mbar_edit": "Modifier",
"xlsx.mbar_view": "Affichage",
+79
View File
@@ -12172,6 +12172,85 @@ body.desktop-mode .editor-container {
max-width: 92vw;
}
}
/* #189 — mise en page mobile : par défaut seuls restent la barre des
feuilles (avec le basculeur) et la barre de formule. La barre de menus et
le ruban sont repliés derrière #xlsx-tools-toggle ; le groupe Recherche,
logé dans la barre de formule, suit le même état pour ne pas écraser le
champ de saisie. */
.xlsx-tools-toggle {
display: none;
}
@media (max-width: 768px) {
.xlsx-tools-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 44px;
height: 44px;
flex: 0 0 auto;
}
.xlsx-menubar,
.xlsx-cmdbar,
.xlsx-find-group {
display: none;
}
.xlsx-toolbar.xlsx-tools-open .xlsx-menubar {
display: flex;
}
.xlsx-toolbar.xlsx-tools-open .xlsx-cmdbar {
display: flex;
}
.xlsx-toolbar.xlsx-tools-open .xlsx-find-group {
display: flex;
}
/* La barre de formule ne déborde jamais : elle passe en 2 lignes quand le
groupe Recherche réapparaît avec les outils ouverts. */
.xlsx-toolbar.xlsx-tools-open .xlsx-formula-bar {
flex-wrap: wrap;
}
/* Une seule ligne de feuilles : les onglets défilent horizontalement au
lieu d'enrouler et de grignoter la hauteur de la grille. */
.xlsx-sheetbar {
flex-wrap: nowrap;
}
.xlsx-sheetbar .xlsx-tabs {
flex-wrap: nowrap;
overflow-x: auto;
scrollbar-width: none;
}
.xlsx-sheetbar .xlsx-tabs::-webkit-scrollbar {
display: none;
}
/* Cibles tactiles : le ruban replié n'existe que derrière le basculeur,
mais une fois ouvert chaque commande reste atteignable au doigt. */
.xlsx-toolbar .btn-action {
min-width: 44px;
height: 44px;
}
/* À 44px un groupe (police, nombre…) dépasse la largeur d'un téléphone :
il doit pouvoir se réduire ET s'enrouler plutôt que déborder. */
.xlsx-cmdbar .xlsx-cmd-group {
flex: 0 1 auto;
min-width: 0;
flex-wrap: wrap;
}
.xlsx-menubtn {
padding: 12px 14px;
min-height: 44px;
}
.xlsx-tab,
.xlsx-tab-add {
padding: 10px 14px;
min-height: 44px;
}
/* 16px minimum : en dessous iOS zoome automatiquement la page dès que le
champ reçoit le focus, ce qui fait « sauter » l'interface. */
.xlsx-active-cell,
.xlsx-formula-input,
.xlsx-find-input {
font-size: 16px;
}
}
.xlsx-context-item {
text-align: left;
border: none;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "obsigate",
"version": "2.55.0",
"version": "2.56.0",
"description": "**Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive.",
"main": "patch.js",
"directories": {
+36 -2
View File
@@ -72,6 +72,14 @@ async function openXlsx(page, file) {
}
await treeItem.dblclick({ timeout: 5000 });
await expect(page.locator('#content-area .xlsx-table')).toBeVisible({ timeout: 15000 });
// #189 — sous 768px la barre de menus et le ruban sont repliés par défaut.
// Les tests « desktop » qui les manipulent les déplient d'abord ; le test
// mobile dédié ouvre lui-même la feuille pour vérifier l'état replié.
const toggle = page.locator('#xlsx-tools-toggle');
if (await toggle.isVisible().catch(() => false)) {
await toggle.click();
await expect(page.locator('#content-area .xlsx-menubar')).toBeVisible();
}
}
test.describe('Excel viewer — garde-fous d\'écriture et valeurs calculées (#153)', () => {
@@ -513,12 +521,27 @@ test.describe('Excel viewer — menus à icônes et fermeture au focus (#179)',
await expect(page.locator('#xlsx-minibar')).toBeVisible();
});
test('mobile : ruban sans débordement et cibles tactiles 44px', async ({ page, viewport }) => {
test('mobile : barres repliées par défaut, ruban sans débordement et cibles 44px (#189)', async ({ page, viewport }) => {
test.skip((viewport?.width ?? 9999) > 768, 'Mobile viewport required');
await login(page);
await page.evaluate(() => window.TabManager.open('TestVault', FIXTURE));
await page.evaluate((f) => window.TabManager.open('TestVault', f), FIXTURE);
await expect(page.locator('#content-area .xlsx-table')).toBeVisible({ timeout: 15000 });
// #189 — par défaut la barre de menus et le ruban sont repliés : la grille
// garde la hauteur d'écran. La barre de formule, elle, reste visible.
await expect(page.locator('#content-area .xlsx-menubar')).toBeHidden();
await expect(page.locator('#content-area .xlsx-cmdbar')).toBeHidden();
await expect(page.locator('#content-area .xlsx-formula-bar')).toBeVisible();
await expect(page.locator('#content-area .xlsx-sheetbar')).toBeVisible();
const toggle = page.locator('#xlsx-tools-toggle');
await expect(toggle).toBeVisible();
// Un clic déplie menus + ruban (état annoncé par aria-expanded).
await toggle.click();
await expect(page.locator('#content-area .xlsx-menubar')).toBeVisible();
await expect(page.locator('#content-area .xlsx-cmdbar')).toBeVisible();
await expect(toggle).toHaveAttribute('aria-expanded', 'true');
// Le ruban s'enroule au lieu de déborder horizontalement.
const overflow = await page.evaluate(() => {
const bar = document.querySelector('#content-area .xlsx-cmdbar');
@@ -526,6 +549,17 @@ test.describe('Excel viewer — menus à icônes et fermeture au focus (#179)',
});
expect(overflow).toBeLessThanOrEqual(1);
// Cibles tactiles : le basculeur et chaque commande du ruban font 44px.
const toggleBox = await toggle.boundingBox();
expect(toggleBox.height).toBeGreaterThanOrEqual(44);
const ribbonBtnBox = await page.locator('#xs-b').boundingBox();
expect(ribbonBtnBox.height).toBeGreaterThanOrEqual(44);
// Repli : la grille retrouve toute sa hauteur.
await toggle.click();
await expect(page.locator('#content-area .xlsx-menubar')).toBeHidden();
await expect(toggle).toHaveAttribute('aria-expanded', 'false');
// Menu contextuel (clic droit émulé) : tient dans le viewport, entrées ≥ 44px.
await page.locator('#content-area td[data-cell="A1"]').click({ button: 'right' });
const menu = page.locator('.xlsx-context-menu');
+48
View File
@@ -2775,6 +2775,54 @@ await test("a read-only workbook keeps the view menus but drops the editing ones
assert.ok(area.querySelector('[data-xlsx-action="toggle-grid"]'), "Gridlines stay");
});
// ── #189 — mise en page mobile : barres repliées derrière un basculeur ──────
await test("the sheet strip carries the tools toggle that flips the toolbar (#189)", () => {
const area = mountGrid();
const strip = area.querySelector(".xlsx-sheetbar");
const toggle = area.querySelector("#xlsx-tools-toggle");
assert.ok(toggle, "toggle rendered");
assert.equal(toggle.closest(".xlsx-sheetbar"), strip, "it lives in the sheet strip");
assert.equal(toggle.getAttribute("aria-expanded"), "false", "starts collapsed");
const toolbar = area.querySelector(".xlsx-toolbar");
assert.ok(!toolbar.classList.contains("xlsx-tools-open"), "toolbar starts closed");
toggle.click();
assert.ok(toolbar.classList.contains("xlsx-tools-open"), "one click opens the tools");
assert.equal(toggle.getAttribute("aria-expanded"), "true");
assert.ok(toggle.classList.contains("active"), "the toggle shows its own state");
toggle.click();
assert.ok(!toolbar.classList.contains("xlsx-tools-open"), "a second click closes them");
assert.equal(toggle.getAttribute("aria-expanded"), "false");
});
await test("style.css hides menus/ribbon/find by default under 768px and reveals them on .xlsx-tools-open (#189)", () => {
const css = readFileSync(path.join(REPO_ROOT, "frontend", "style.css"), "utf8");
// The desktop default: the toggle itself is out of the way.
assert.match(css, /\.xlsx-tools-toggle\s*\{\s*display:\s*none/, "toggle hidden on desktop");
// Mobile block: collapsed by default… (CRLF-safe slice, from the #189
// comment up to the next top-level rule).
const from = css.indexOf("/* #189");
assert.ok(from > 0, "the #189 mobile block exists after the coarse-pointer rules");
const to = css.indexOf(".xlsx-context-item", from);
assert.ok(to > from, "the #189 block is followed by the next rule");
const block = css.slice(from, to);
for (const cls of [".xlsx-menubar", ".xlsx-cmdbar", ".xlsx-find-group"]) {
const hidden = new RegExp(cls.replace(".", "\\.") + "[^}]*display:\\s*none").test(block)
|| new RegExp(cls.replace(".", "\\.") + ",[\\s\\S]{0,120}?display:\\s*none").test(block);
assert.ok(hidden, `${cls} hidden by default on mobile`);
assert.ok(
block.includes(`.xlsx-toolbar.xlsx-tools-open ${cls}`),
`${cls} revealed by .xlsx-tools-open`,
);
}
// The formula bar always stays, and the open state can wrap it (find group).
assert.ok(block.includes(".xlsx-toolbar.xlsx-tools-open .xlsx-formula-bar"), "formula bar wraps when open");
// Touch: 44px targets, tabs on one scrollable row, 16px inputs (no iOS zoom).
assert.match(block, /min-width:\s*44px/, "44px touch targets");
assert.match(block, /\.xlsx-sheetbar \.xlsx-tabs\s*\{[^}]*overflow-x:\s*auto/, "tabs scroll horizontally");
assert.match(block, /font-size:\s*16px/, "inputs at 16px avoid the iOS focus zoom");
});
// ── Report ──────────────────────────────────────────────────────────────────
console.log(`\n${passCount}/${testCount} tests passed\n`);
process.exit(passCount === testCount ? 0 : 1);