Une phase avait quatre lignes de texte brut ; un projet n'avait rien. Les deux
manques se tiennent : la frise ne dit pas qui pilote ni sur quel budget, et ce
contexte finissait dans les notes de la première phase venue, où il ne survit
pas à sa suppression.
Le bloc de notes est le même dans les deux panneaux et prend toute la hauteur
restante : les autres champs ont une taille dictée par leur contenu, une note
fait ce qu'on a à dire. Il s'ouvre sur l'aperçu quand la note existe, sur la
saisie quand elle est vide.
Les cases à cocher se cliquent dans l'aperçu — seul geste de l'aperçu qui touche
aux données. La bascule réécrit la seule ligne visée plutôt que de régénérer la
note, qui verrait sinon sa mise en forme normalisée. Inertes dans la vue par
mois, en lecture seule (décision 24).
La barre d'outils écrit par `document.execCommand('insertText')` et non en
affectant `value`, qui viderait la pile d'annulation du navigateur : `Ctrl+Z`
doit continuer de marcher. Le DOM est bâti nœud par nœud, sans un `innerHTML`.
Les infobulles aplatissent le markdown — `title` ne connaît que le texte —, et
celles d'un jalon et d'un libellé de projet les affichent désormais.
Le format passe en version 4 : le validateur reconstruit chaque projet champ par
champ, un binaire antérieur effacerait les notes de projet à la première
sauvegarde.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Elles n'étaient accessibles que dans l'infobulle de la ligne, où l'on ne pense
pas à aller les chercher et d'où l'on ne peut rien copier. Or une note est
précisément ce qu'on va lire quand on fait le point — « pourquoi cette phase
est-elle bloquée ».
Un triangle en tête de ligne les déplie en dessous, sur les phases qui en
portent. C'est celui qui plie un projet sur la frise, au même endroit et avec
la même rotation : ce qui s'apprend d'un côté vaut de l'autre. La gouttière se
lit ainsi d'un coup d'œil comme la liste de ce qui a quelque chose à dire.
Toute la ligne déplie, pas seulement le triangle. Une première version faisait
de l'intitulé lui-même le bouton, avec un chevron à sa suite : la cible était
trop petite pour un geste aussi banal, et rien ne justifiait cette parcimonie
dans une vue où le clic n'a aucun autre effet. Le triangle reste comme
indicateur plutôt que comme cible, le curseur et le fond au survol disent que
la ligne réagit. Les lignes sans notes, elles, ne réagissent pas : promettre un
geste qui ne fait rien est pire que ne rien promettre.
Il n'en reste pas moins un vrai button : la ligne n'est pas focusable, c'est
donc le seul chemin clavier vers les notes.
Les notes restent repliées par défaut pour deux raisons. La densité d'abord :
trois lignes sous chaque intitulé étalent un mois sur deux écrans et ruinent la
lecture en diagonale. Et parce qu'une phase sur trois seulement en porte, les
afficher d'office donnerait des lignes de hauteurs inégales, ce qui casse
l'alignement des colonnes sur lequel repose tout le balayage du regard.
L'état déplié vit dans le DOM et nulle part ailleurs : il ne survit pas à un
changement de filtre, qui reconstruit la liste. Le remonter dans l'état de
l'application achèterait cher une continuité que personne ne réclame — quand la
liste change, on la relit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La frise répond mal à « qu'est-ce qui arrive le mois prochain » : la question
traverse les projets, alors que la frise les range précisément en couloirs
séparés. Il fallait balayer une colonne de dates à travers tous les couloirs
en gardant en tête ce qu'on avait vu plus haut — d'où le tableur ressorti à
côté.
Deux boutons dans la barre d'outils basculent vers une liste qui déroule
toutes les phases, projets mêlés, dans l'ordre du calendrier. Chaque ligne se
lit quand, chez qui, puis quoi : période, projet et ses tags, intitulé,
statut.
Une phase est rattachée au seul mois de son début. La répéter dans chaque mois
traversé aurait donné un tableau de charge — utile, mais c'est une autre vue,
et le doublon coûte la lecture en diagonale qui fait tout l'intérêt de
celle-ci. Sa fin est écrite sur la ligne, ce qui suffit à voir qu'elle
déborde. Les mois sans rien ne sont pas représentés : l'absence se lit déjà
dans le saut d'un titre au suivant.
La liste ne s'édite pas, et ce n'est pas une lacune à combler : déplacer une
phase demande de voir ce qu'elle chevauche et ce qu'elle repousse, or c'est
justement ce voisinage que l'ordre chronologique dissout. Seules les pastilles
de tags restent cliquables — filtrer ne change pas les données.
Le filtre par tags vaut pour les deux vues, sans rien changer à sa mécanique,
si bien qu'on ne se demande jamais si l'une montre plus que l'autre. L'œil
(hidden) écarte un projet de la liste comme il écarte ses barres.
La vue choisie n'est pas enregistrée, contrairement à la largeur de la colonne
des libellés : cette largeur est un réglage d'écran, la vue est un geste de
consultation. L'outil s'ouvre donc sur la frise, celle où l'on modifie. Le
défilement horizontal de la frise, lui, est mémorisé le temps de
l'aller-retour, puisque masquer un élément lui fait perdre son scrollLeft.
Deux extractions au passage, chacune parce que deux vues sœurs en ont besoin
et qu'aucune n'a à importer l'autre : les noms de mois et le formatage des
dates rejoignent model.js, les pastilles de tags un module tags.js.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'interface enregistre après une seconde d'inactivité, et le serveur copiait
le planning avant chaque écriture : une après-midi d'édition produisait des
dizaines de fichiers quasi identiques.
Le problème n'est pas la place occupée mais ce que la rotation en faisait —
les cinquante emplacements se remplissaient en quelques heures et chassaient
les états anciens, les seuls qu'on cherche à retrouver. Un filet qui ne
remonte pas au-delà de la dernière demi-heure ne protège pas de la bêtise
qu'on découvre le lendemain.
La copie est désormais prise à l'ouverture, quand le planning est encore dans
l'état d'avant la séance. Deux garde-fous : au plus une par jour si le serveur
reste allumé longtemps, et rien du tout si le contenu n'a pas bougé depuis la
dernière copie. Les cinquante conservées couvrent maintenant des mois.
La copie et le remplacement partagent un état — la date de la dernière
sauvegarde — donc un verrou les sérialise, ce qui protège au passage du cas
où deux onglets enregistrent simultanément.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
serve.py supposait Python installé et une commande tapée dans un terminal
depuis le dossier du dépôt. L'objectif ici : poser l'exécutable et son
planning dans un dossier synchronisé, et les retrouver sur n'importe quelle
machine sans rien installer.
Le binaire embarque l'interface, expose les mêmes routes sur le même format,
et cherche son projets.json à côté de lui. Compilé avec CGO_ENABLED=0, il ne
dépend d'aucune bibliothèque système, pas même de la glibc ; build.sh produit
les cinq plateformes depuis une seule machine.
Le front est inchangé : les modules ES sont embarqués et servis tels quels,
et --dev les sert depuis le disque pour développer sans recompiler.
Deux ajustements dictés par le double-clic, où aucun drapeau ne peut être
passé : le port se cherche à partir de 8000 s'il est occupé, et le fichier de
données est résolu depuis l'exécutable et non depuis le répertoire courant.
La décision 3 est rectifiée au passage : elle affirmait à tort que la File
System Access API ne fonctionne pas depuis file://. Vérification faite, c'est
CORS sur les modules ES qui ferme cette voie, pas la sécurité de l'API.
serve.py est supprimé, le binaire l'ayant remplacé en usage réel.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Elle s'épaississait en mode plié, au motif qu'elle y était seule sur sa
ligne. Mais plier un couloir ne change rien à ce que cette barre
représente : la voir changer d'aspect au pli laissait croire à deux
objets différents.
Elle garde donc partout la hauteur de sa version dépliée, plus mince
qu'une barre de phase — puisqu'elle voisine avec elles dès que le projet
est déplié, et qu'elle ne se glisse pas.
`--hauteur-cumulative` remonte dans `:root` : la barre et le fantôme qui
la double sont frères et non imbriqués, la variable doit donc vivre
au-dessus des deux.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Section 16 de decisions.md : pourquoi des étiquettes libres plutôt qu'un
référentiel, pourquoi un filtre conjonctif plutôt que disjonctif, pourquoi il
n'est pas enregistré alors que le masquage par l'œil l'est — avec un tableau qui
oppose les deux —, pourquoi la couleur d'un tag est calculée et non choisie, et
pourquoi un tag trop long est tronqué là où une date invalide bloque tout.
Le README décrit l'usage : saisie des tags, filtre cumulatif, portée limitée à la
session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Une frise chronologique unique où plusieurs projets s'empilent en couloirs
pliables, pour voir d'un coup d'œil où en est chacun et comment ils se situent
les uns par rapport aux autres. Ce n'est pas un outil de suivi quotidien : une
phase se compte en semaines, et il n'y a ni sous-tâches, ni tickets, ni
dépendances entre phases.
- Manipulation directe des barres (glisser, redimensionner), accrochées au lundi
- Couloirs pliables : plié, un projet devient une barre segmentée par phase
- Planning de référence figeable, avec barre fantôme et calcul de dérive
- En-tête à trois bandes : année, mois, numéro de semaine ISO 8601
- Frise qui s'élargit au défilement, pour planifier dans un futur encore vide
- Micro-serveur Python (bibliothèque standard) exposant GET/PUT sur /api/data,
avec sauvegarde horodatée avant chaque écriture
- Zéro build : modules ES natifs, aucune dépendance à installer
50 tests unitaires sur la logique métier (node --test, sans dépendance).
Vérifié dans Chromium et Firefox.
Les arbitrages de conception et surtout leurs raisons sont consignés dans
docs/decisions.md — notamment l'abandon des dépendances entre phases, de la
File System Access API, du SVG et des niveaux de zoom.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>