# #154 — Refonte UI/UX de la visionneuse & éditeur XLSX (ruban, grille, inspecteur) > **Item de roadmap :** [#154 — Refonte UI/UX tableur](../ROADMAP.md) > **Origine :** #152 / #153 (visionneuse XLSX fonctionnelle mais peu conviviale) > **Statut :** 🔵 **en cours** — Lot 1 livré le 2026-09-29 > **Effort estimé :** 6-9 jours (Lot 1 ✅ · Lot 2 · Lot 3 · Lot 4) > **Règle de maintenance :** la Roadmap porte les cases à cocher (suivi), cette fiche porte > l'analyse, l'architecture cible et le plan par lots. **Ne pas dupliquer le détail.** --- ## 1. Objectif Rendre la vue tableur d'ObsiGate **intuitive, moderne et hautement utilisable** en s'inspirant des standards du marché (Excel, Google Sheets, Airtable), **sans renier les contraintes du dépôt** : thème sombre, `vanilla JS`, **zéro framework, zéro build npm** ([`AGENTS.md`](../../AGENTS.md)). La refonte est **organique** : on améliore la coquille existante (`frontend/js/viewer.js::renderXlsxViewer`, `frontend/style.css`), on ne réécrit pas la grille ni le backend. ## 2. Audit UX — les 3 problèmes majeurs | # | Problème | Constat | Résolution | |---|---|---|---| | **P1** | **Aucune hiérarchie ni regroupement des commandes** | Rangée plate de boutons de poids identique (`viewer.js` toolbar historique) ; « Tableau de bord » *prependé* au runtime ; barre de formule réduite à un `input`. | **Barre de commandes groupée** (Formules · Insertion · Vue · Fichier), bouton **Enregistrer primaire**, état *dirty*. | | **P2** | **Grille sans affordances : en-têtes = cellules** | Contraste faible entre `th` et `td`, pas de zébrage, pas de survol lisible, cellule active peu marquée. | **Tokens de grille** + en-têtes plus clairs/interactifs, zébrage, survol, cellule active en bordure accent. | | **P3** | **États avancés traités comme du contenu** | Dashboard *inline* qui pousse la grille, troncature/lecture seule/formules non recalculées sans emplacement dédié, `confirm()`/`prompt()` natifs. | **Couche UI dédiée** : bandeaux d'état + **inspecteur droit** (Lot 3) + dialogues thémés (Lot 2). | ## 3. Architecture cible de l'écran ``` ┌──────────────────────────────────────────────────────────────────────────┐ │ BARRE APP (globale, existante) │ ├─────────────┬────────────────────────────────────────────────────────────┤ │ │ A. RUBAN — groupes Formules · Insertion · Vue · Fichier │ │ EXPLORATEUR│ B. BARRE DE FORMULE — [ A1 ] fx [ … ] │ │ DE FICHIERS│ C. BANDEAUX D'ÉTAT — lecture seule · formules non recalculées│ │ (sidebar) ├──────────────────────────────────────────────┬─────────────┤ │ │ D. GRILLE (en-têtes clairs, zébrage, survol) │ E. INSPECTEUR│ │ │ │ (dashboard + │ │ │ │ IA, repliable)│ │ ├───────────────────────────────────────────────┤ │ │ │ F. ONGLETS FEUILLES + « + » · 500/522 │ │ └─────────────┴───────────────────────────────────────────────┴─────────────┘ ``` - **A. Ruban** : groupes d'actions avec séparateurs ; actions de style désactivées (styles lus, pas écrits). Bouton **Enregistrer** en accent, désactivé si rien de *dirty*. - **B. Barre de formule** : zone nom + champ + badge de session `f(x)`. - **C. Bandeaux d'état** : empilables, non bloquants ; portent lecture seule et « formules non recalculées ». - **D. Grille** : rendue côté serveur (`backend/xlsx_reader.py`), habillée et câblée par le front. - **E. Inspecteur** : **à venir (Lot 3)** — Tableau de bord + Assistant IA dans un panneau droit repliable (réutilise `PaneManager` pour le détachement), au lieu du dashboard *inline* actuel. - **F. Onglets feuilles** : permanents (même à une seule feuille) + bouton « + ». ## 4. Plan par lots (incréments livrables) ### Lot 1 — Coquille : ruban groupé, onglets permanents, badges d'état ✅ *(2026-09-29)* - **A1.1** Barre de commandes groupée (`.xlsx-cmdbar`, `.xlsx-cmd-group`, `.xlsx-cmd-sep`, `.xlsx-save-primary`), IDs existants conservés (compatibilité tests JSDOM/E2E). - **A1.2** Onglets de feuilles **toujours rendus** (non-CSV) + bouton **`+`** `.xlsx-tab-add` → `sheet_add` (même pipeline `putStructure`). - **A1.3** Badges d'état : `.xlsx-status-pill` **lecture seule** (`.xls`/`.ods`) et **formules non recalculées** (non-CSV). - **A1.4** Tokens de grille (`--grid-bg`, `--grid-header-bg`, `--grid-header-text`, `--grid-border`, `--grid-zebra`) déclinés dark/light + affordances (en-têtes clairs, zébrage, survol, cellule active solide, cellule *dirty* prioritaire au survol). ### Lot 2 — Dialogues thémés & feedback (à venir) - Remplacer `confirm()`/`prompt()` par des **modales thémées** (`.obsigate-modal-*`) et des **toasts** : structure (feuille/ligne/colonne), perte (409 `xlsx_lossy_content`), conflit (409 `conflict`) en bandeau non bloquant. - Indicateur *dirty* sur l'onglet de feuille et la barre. ### Lot 3 — Inspecteur droit (à venir) - Panneau repliable hébergeant **Tableau de bord** et **Assistant IA** en onglets ; la grille reste visible. Lien **dashboard → grille** (clic sur KPI/plage = scroll + sélection). - Détachement en split via `PaneManager.splitRight()`. ### Lot 4 — Découpage & finitions (à venir) - Extraction de `renderXlsxViewer` en modules (`frontend/js/xlsx/*.js`) : `toolbar`, `formula-bar`, `grid`, `sheet-tabs`, `inspector`, `cell-editor`, `api`. - **Undo/redo** local (pile de commandes), défilement paresseux via `IntersectionObserver`, accessibilité ARIA (`role="grid"`, *roving tabindex*). ## 5. Recommandations techniques (contrainte « zéro build ») | Option Data Grid | Build | Licence | Verdict | |---|---|---|---| | AG Grid Community | npm + bundler | MIT | ❌ viole « zéro build », réécrit le DOM, casse les tests | | Handsontable | npm + bundler | **commerciale** | ❌ licence non libre | | TanStack Table | headless (importable esm.sh) | MIT | ⚠ possible sans build, mais *headless* → gain limité | | **Grille maison sur `