Revoir l'ergonomie des panneaux et de la colonne des projets

Les panneaux d'édition étaient modaux et la colonne de gauche tronquait
tout ce qu'elle portait. Sept corrections, mesurées sur data/exemple.json.

Panneaux
- Le voile qui recouvrait la page disparaît : la frise reste manipulable
  pendant l'édition, et cliquer une autre barre y bascule la sélection.
  Il rendait aussi le raccourci flèches inatteignable, le focus partant
  dans le champ « Nom » sans qu'on puisse cliquer ailleurs pour en sortir.
- Un clic dans une zone inerte referme le panneau : ce que rendait le
  voile, sans le calque qui figeait la frise.
- Les paramètres d'un projet quittent le <dialog> modal pour le même
  panneau qu'une phase, avec la même édition au fil de la saisie.
  « Nouveau projet » crée donc le projet aussitôt, comme le fait déjà
  l'ajout d'une phase : plus aucune création ne passe par un formulaire.

Colonne des projets
- Le nom ne disposait que de 56 px sur 250, et « client » s'affichait
  « c. ». Les commandes passent en surimpression au survol, les tags
  cèdent en bloc derrière un compteur, et le nom cède en dernier.
- La colonne se redimensionne, largeur conservée dans localStorage.
- L'œil disparaît : il faisait doublon avec l'entrée « Masquer » du menu.
  Un « + » le remplace, l'ajout d'une phase étant l'action la plus
  fréquente, et le nom du projet devient cliquable — il portait déjà un
  curseur « main » sans aucune action derrière.
- Plus de commande « Ajouter un jalon » : un jalon est une phase dont on
  coche la case, pas un autre objet.

Frise
- Le nom d'une phase reste accroché au bord visible quand sa barre
  s'enfonce sous la colonne.
- Cliquer un nom de phase hors écran ramène la frise sur elle.
- La barre cumulative d'un projet s'affiche aussi quand il est déplié,
  amincie pour ne pas se faire passer pour une barre de phase.

Arbitrages consignés dans docs/decisions.md, sections 8 et 17 à 21.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-01 10:42:35 +02:00
parent a2a5c5cb9c
commit eaca2f7813
9 changed files with 1032 additions and 333 deletions

View File

@@ -8,12 +8,15 @@
* C'est aussi ici qu'on saisit une date exacte : le glisser sur la frise
* s'accroche au lundi, ce panneau est le recours quand une phase doit démarrer
* un jeudi précis.
*
* Le panneau n'est **pas modal** : rien ne recouvre la frise pendant qu'il est
* ouvert. Voir docs/decisions.md, section 17.
*/
import { STATUTS, dateValide, modifierPhase } from './model.js';
export function creerPanneau(refs, rappels) {
const { panneau, voile, formulaire, titre, erreur, champFin, supprimer, fermer } = refs;
const { panneau, formulaire, titre, erreur, champFin, supprimer, fermer } = refs;
let selection = null; // { projet, phase }
let phaseCourante = null;
@@ -106,7 +109,6 @@ export function creerPanneau(refs, rappels) {
});
fermer.addEventListener('click', () => api.fermer());
voile.addEventListener('click', () => api.fermer());
document.addEventListener('keydown', (evenement) => {
// Échap ferme le panneau, sauf pendant une saisie où il annule d'abord la
@@ -117,14 +119,29 @@ export function creerPanneau(refs, rappels) {
});
const api = {
ouvrir(projet, phase) {
/**
* @param {object} options
* - nomAEcraser : place le curseur dans le champ « Nom », texte
* présélectionné. Réservé à une phase qui vient d'être créée, dont le
* nom provisoire est justement là pour être remplacé.
*
* Hors de ce cas, le focus se pose sur le panneau lui-même et non dans un
* champ : `app.js` ignore les flèches quand la frappe part dans un `input`,
* et le raccourci le plus utile de l'outil — décaler la phase d'un jour —
* serait inaccessible juste après l'avoir sélectionnée.
*/
ouvrir(projet, phase, { nomAEcraser = false } = {}) {
selection = { projet: projet.id, phase: phase.id };
phaseCourante = phase;
remplir(projet, phase);
panneau.hidden = false;
voile.hidden = false;
formulaire.name.focus();
formulaire.name.select();
if (nomAEcraser) {
formulaire.name.focus();
formulaire.name.select();
} else {
panneau.focus();
}
},
/** Recharge le contenu après une modification venue de la frise. */
@@ -143,10 +160,12 @@ export function creerPanneau(refs, rappels) {
},
fermer() {
// Sans cette garde, fermer un panneau déjà fermé relancerait un rendu
// complet de la frise — ce qui arriverait à chaque clic dans le vide.
if (panneau.hidden) return;
selection = null;
phaseCourante = null;
panneau.hidden = true;
voile.hidden = true;
rappels.surFermeture();
},