diff --git a/README.md b/README.md index 7eb5394..8d1b567 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,18 @@ survol de la ligne, sur son bord droit : Il n'y a pas de commande séparée pour créer un **jalon** ni pour marquer une **date imposée** : ce sont deux cases du panneau de la phase, indépendantes l'une de l'autre comme du statut. Cocher -« Jalon » ramène la fin sur le début. Les deux bascules jouent dans les deux sens à tout moment. +« Jalon » ramène la fin sur le début, cocher « Date imposée » encadre les deux champs de date d'un +trait tireté — le même qu'on verra sur la barre. Les deux bascules jouent dans les deux sens à tout +moment. + +Le **statut** se choisit sur quatre boutons, chacun peint de la texture qu'il donne à la barre. Deux +traits suffisent à les lire : c'est **plein** quand rien ne bouge et **rayé** quand quelque chose se +passe ; c'est la **couleur pleine** du projet dès qu'une phase a commencé, et une teinte **diluée** +tant qu'elle n'a pas commencé. D'où : à venir pâle et bordé, en cours plein et rayé, terminé plein et +nu, bloqué rayé de rouge — seule teinte étrangère, parce que c'est la seule chose qui ne parle pas +d'avancement. La couleur reste celle du projet : elle distingue les couloirs, jamais l'avancement. Le +panneau sert ainsi de légende — il n'y en a pas d'autre, et il n'y a rien à apprendre avant de s'en +servir. La colonne se **redimensionne** en glissant la ligne qui la sépare de la frise, en haut à gauche : un double-clic revient à la largeur d'origine. Cette largeur est propre au navigateur, @@ -138,8 +149,10 @@ va. Un projet dont tout est terminé n'offre aucune prise, et son infobulle le d **Ce dont on ne décide pas non plus.** Une phase peut porter une **date imposée** : elle est déléguée à quelqu'un d'autre, ou tenue par un contrat, un créneau, une échéance réglementaire. La -case se coche dans son panneau, sous « Jalon », et la barre reçoit alors deux petits taquets à ses -extrémités — un cercle pour un jalon. Repousser le projet ne la repousse pas : si tout le reste +case se coche dans son panneau, sous « Jalon », et sa forme se cerne alors d'un **trait tireté** — +une barre comme un losange, et jusqu'aux deux champs de date du panneau. À ne pas confondre avec le +contour plein de la phase sélectionnée : celui-ci est dedans et discontinu, celui-là dehors et +franc. Repousser le projet ne la repousse pas : si tout le reste glisse, c'est le créneau qu'on rate, et le chevauchement qui apparaît est justement ce qu'on voulait voir. Elle reste glissable seule, elle : « imposée » veut dire *indépendante du projet*, pas *immuable*. @@ -297,6 +310,10 @@ mois —, chez qui — le projet et ses tags —, puis quoi — l'intitulé de l enfin son statut. Une phase longue n'est **pas** répétée dans les mois qu'elle traverse : elle n'apparaît qu'à son mois de départ, avec sa date de fin écrite en clair. +La petite marque en tête de ligne reprend les formes de la frise — barre pour une tâche, losange pour +un jalon, texture du statut, cadre tireté pour une **date imposée**. C'est ici qu'elle compte le +plus : une liste d'échéances doit dire lesquelles ne vous appartiennent pas. + Les phases qui portent des **notes** le signalent par un triangle en tête de ligne, le même que celui qui plie un projet sur la frise. Un clic **n'importe où sur la ligne** déplie la note en dessous, un second la referme. Elle s'y affiche rendue, comme dans le panneau. Rien n'est affiché diff --git a/css/style.css b/css/style.css index 1b0942b..e698aac 100644 --- a/css/style.css +++ b/css/style.css @@ -804,19 +804,52 @@ button[aria-pressed="true"] { } /* Le statut se lit à la texture de la barre, pas à sa couleur : la couleur - appartient au projet, elle sert à distinguer les couloirs entre eux. */ + appartient au projet, elle sert à distinguer les couloirs entre eux. + + Une seule grammaire pour les quatre, et elle tient en deux traits : + + - **plein** pour un état stable, **rayé** pour ce qui bouge ou coince ; + - la couleur du projet **pleine** dès qu'une phase a commencé, **diluée** tant + qu'elle n'a pas commencé. + + D'où : à venir dilué et bordé, en cours plein et rayé, terminé plein et nu, + bloqué rayé de rouge — seule teinte étrangère, parce que c'est la seule chose + qui ne parle pas d'avancement. + + « Terminé » a longtemps été assourdi, d'abord d'un gris fixe puis d'une + dilution. Les deux disaient « c'est derrière nous » en donnant une frise + morte, où la majorité des barres d'un projet avancé sont éteintes. C'est la + rayure d'« en cours » qui a permis de le rendre vif : la trame distingue + désormais ces deux-là, la teinte n'a plus à s'en charger. */ .barre--todo { background: color-mix(in srgb, var(--couleur-projet) 28%, var(--surface)); color: var(--texte); border: 1px solid var(--couleur-projet); } +/* Rayée, et non pleine : posée à côté d'une barre terminée — un aplat de la même + teinte —, une couleur pleine ne se distinguait pas assez pour qu'on lise + l'avancement d'un couloir en diagonale. La rayure lui donne ce que les trois + autres textures ont déjà : une trame, et pas seulement une nuance. Elle mêle + la couleur du projet à elle-même diluée, là où celle d'une phase bloquée y + mêle du rouge : le motif est le même, la teinte dit lequel des deux on + regarde. */ .barre--doing { - background: var(--couleur-projet); + background: repeating-linear-gradient( + 45deg, + var(--couleur-projet), + var(--couleur-projet) 6px, + color-mix(in srgb, var(--couleur-projet) 50%, var(--surface)) 6px, + color-mix(in srgb, var(--couleur-projet) 50%, var(--surface)) 12px + ); } +/* La couleur du projet, pleine et nue — c'est la seule des quatre à n'avoir + aucune marque, et c'est bien ce qu'on veut dire : il n'y a plus rien à en + suivre. Déclarée quand même, et pas laissée au fond de `.barre` : ce qui vaut + pour un statut doit se lire à l'endroit où on lit les statuts. */ .barre--done { - background: color-mix(in srgb, var(--couleur-projet) 55%, #64748b); + background: var(--couleur-projet); } .barre--blocked { @@ -832,19 +865,37 @@ button[aria-pressed="true"] { /* Une phase dont la date ne nous appartient pas — déléguée, contractuelle, réglementaire (docs/decisions.md, section 28). - Deux **taquets** verticaux à ses extrémités, comme les butées d'une pièce - qu'on ne peut plus faire coulisser. La marque se cumule avec les quatre - textures de statut au lieu de leur disputer la place : c'est bien une phase à - venir, en cours ou bloquée, qui se trouve en plus tenue par le dehors. + La forme est **cerclée**, tout entière : c'est tenu de partout, et le trait + suit le contour quel qu'il soit — une barre, un losange. Deux taquets aux + extrémités disaient la même chose et le disaient mal : sur une barre de deux + jours ils l'avalaient, sur une barre à venir ils se lisaient comme une bordure + épaissie, et ils occupaient la place où le survol révèle les poignées de + redimensionnement — le signe « cette date ne vous appartient pas » tombait + exactement là où l'outil dit « tirez ici pour la changer ». - En `inset`, donc sans toucher à la géométrie : la barre garde exactement la - largeur de ses dates, et l'ombre portée reste déclarée à côté — un - `box-shadow` ne se cumule pas d'une règle à l'autre, il se remplace. */ -.barre--imposee { - box-shadow: - var(--ombre), - inset 3px 0 0 var(--texte), - inset -3px 0 0 var(--texte); + La marque se cumule avec les quatre textures de statut au lieu de leur + disputer la place : c'est bien une phase à venir, en cours ou bloquée, qui se + trouve en plus tenue par le dehors. + + Le trait est **tireté**, et c'est ce qui le sépare du contour de la sélection, + plein. Un cerclage plein avait été essayé d'abord : à la taille réelle des + barres, on ne le distinguait pas d'une phase simplement sélectionnée. Le tiret + dit d'ailleurs ce qu'il faut — ce n'est pas nous qui traçons cette ligne. + + Il vit sur un `::after` plutôt que sur la barre : un élément n'a qu'un + `outline`, et c'est la sélection qui le prend. Les deux marques se superposent + donc sans se gêner sur une phase imposée qu'on vient de sélectionner — un + cadre tireté dedans, un contour plein dehors. */ +.barre--imposee::after, +.jalon--imposee::after { + content: ''; + position: absolute; + inset: 0; + border: 2px dashed var(--texte); + border-radius: inherit; + /* Le losange tourne, son cadre avec lui : le pseudo-élément hérite de la + rotation du jalon, et n'a donc rien à en savoir. */ + pointer-events: none; } /* Poignées de redimensionnement, révélées au survol de la barre. */ @@ -894,23 +945,35 @@ button[aria-pressed="true"] { box-shadow: var(--ombre); } +/* Mêmes textures que les barres, hachures resserrées : le losange fait 14px de + côté, une rayure de 6px n'y tiendrait pas deux fois. */ +.jalon--doing { + background: repeating-linear-gradient( + 45deg, + var(--couleur-projet), + var(--couleur-projet) 3px, + color-mix(in srgb, var(--couleur-projet) 50%, var(--surface)) 3px, + color-mix(in srgb, var(--couleur-projet) 50%, var(--surface)) 6px + ); +} + .jalon--done { - background: color-mix(in srgb, var(--couleur-projet) 55%, #64748b); + background: var(--couleur-projet); } .jalon--blocked { background: var(--danger); } -/* Un losange n'a pas d'extrémités où poser les taquets d'une barre imposée : il - se cercle. Déclarée après `.jalon`, dont elle partage la spécificité — c'est - l'ordre qui la fait gagner, un `box-shadow` se remplaçant en bloc. */ -.jalon--impose { - box-shadow: - var(--ombre), - inset 0 0 0 2px var(--texte); -} +/* Rien ici pour `.jalon--imposee` : son cadre tireté est déclaré avec celui des + barres, plus haut, à la même épaisseur. C'est la même marque, et un losange + n'est qu'une autre forme à cerner — son `::after` s'appuie sur le + `position: absolute` que `.jalon` porte déjà, et tourne avec lui. + Le trait avait été affiné à 1px, au motif que la longueur des tirets suit + l'épaisseur et qu'un losange de 14px n'en porte que quelques-uns. Mais c'est + la lisibilité qui tranche : à 1px sur une forme de cette taille, la marque + s'efface. Mieux vaut peu de tirets qu'on voit que beaucoup qu'on devine. */ .jalon--selectionne { outline: 2px solid var(--texte); outline-offset: 1px; @@ -1167,7 +1230,14 @@ button[aria-pressed="true"] { et le second garde le droit de rétrécir sous la taille de son contenu — sans lui, un flex item refuse de descendre sous sa hauteur intrinsèque et c'est la page entière qui déborderait au lieu du corps qui défile. */ +/* `--couleur-projet` se déclare ici, sur l'élément même que detail.js peint en + style inline à l'ouverture : le style inline l'emporte sur cette règle, et + l'accent ne sert que de repli tant qu'aucune phase n'est ouverte — sans quoi + les `color-mix` des textures de statut se peindraient dans le vide. La + déclarer plus bas, sur le groupe de boutons, ferait l'inverse : une valeur + posée sur un descendant gagne toujours contre celle dont il hérite. */ .panneau__corps { + --couleur-projet: var(--accent); flex: 1; min-height: 0; padding: 16px; @@ -1188,7 +1258,6 @@ button[aria-pressed="true"] { .panneau__corps input[type="text"], .panneau__corps input[type="date"], -.panneau__corps select, .panneau__corps textarea { font: inherit; padding: 6px 8px; @@ -1209,6 +1278,122 @@ button[aria-pressed="true"] { gap: 10px; } +/* Le cerclage de la barre imposée, reporté sur les deux champs que la case + qualifie : cocher « date imposée » n'avait jusque-là aucun effet visible dans + le panneau, alors que la conséquence porte précisément sur ces dates-là. + + Le padding est repris par une marge négative de même valeur : les champs ne + bougent pas d'un pixel quand la case change d'état, seul le contour apparaît. + Il déborde de 8px dans les 16px de padding du corps, donc sans jamais sortir + du panneau. */ +.champ-double--imposee { + padding: 6px 8px; + margin: -6px -8px; + border-radius: var(--rayon); + outline: 2px dashed var(--texte); + outline-offset: -2px; +} + +/* --- statut, en quatre boutons ------------------------------------------- */ + +/* Chacun peint de la texture qu'il donne à la barre sur la frise : voir + index.html pour le pourquoi. La couleur, elle, vient du formulaire — cf. le + repli déclaré sur `.panneau__corps`. */ +.statuts { + margin: 0; + padding: 0; + border: 0; +} + +.statuts legend { + padding: 0 0 4px; + font-size: 12px; + font-weight: 500; + color: var(--texte-doux); +} + +.statuts__choix { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; +} + +/* Le label *est* le bouton. Le radio natif s'efface sans quitter le DOM : c'est + lui qui porte la valeur, réunit le groupe et répond aux flèches. */ +.panneau__corps .statut { + flex-direction: row; + align-items: center; + gap: 8px; + padding: 6px 8px; + border: 1px solid var(--bordure-forte); + border-radius: var(--rayon); + font-weight: 400; + color: var(--texte); + cursor: pointer; +} + +.statut input { + position: absolute; + opacity: 0; + pointer-events: none; +} + +.statut:hover { + background: color-mix(in srgb, var(--accent) 6%, transparent); +} + +.statut:has(input:checked) { + border-color: var(--accent); + background: color-mix(in srgb, var(--accent) 12%, transparent); + font-weight: 600; +} + +/* Le focus se pose sur un radio devenu invisible : c'est au bouton de le + montrer, sans quoi la navigation aux flèches se ferait à l'aveugle. */ +.statut:has(input:focus-visible) { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +/* Les quatre textures, reprises telles quelles des barres — hachures resserrées + à l'échelle de la marque, comme celles de la vue par mois. */ +.statut__marque { + flex: none; + width: 18px; + height: 9px; + border-radius: 2px; + background: var(--couleur-projet); +} + +.statut--todo .statut__marque { + background: color-mix(in srgb, var(--couleur-projet) 28%, var(--surface)); + border: 1px solid var(--couleur-projet); +} + +.statut--doing .statut__marque { + background: repeating-linear-gradient( + 45deg, + var(--couleur-projet), + var(--couleur-projet) 3px, + color-mix(in srgb, var(--couleur-projet) 50%, var(--surface)) 3px, + color-mix(in srgb, var(--couleur-projet) 50%, var(--surface)) 6px + ); +} + +.statut--done .statut__marque { + background: var(--couleur-projet); +} + +.statut--blocked .statut__marque { + background: repeating-linear-gradient( + 45deg, + var(--couleur-projet), + var(--couleur-projet) 3px, + color-mix(in srgb, var(--danger) 75%, var(--couleur-projet)) 3px, + color-mix(in srgb, var(--danger) 75%, var(--couleur-projet)) 6px + ); +} + .case { flex-direction: row !important; align-items: center; @@ -1964,8 +2149,18 @@ kbd { border: 1px solid var(--couleur-projet); } +.mois-entree--doing .mois-entree__marque { + background: repeating-linear-gradient( + 45deg, + var(--couleur-projet), + var(--couleur-projet) 3px, + color-mix(in srgb, var(--couleur-projet) 50%, var(--surface)) 3px, + color-mix(in srgb, var(--couleur-projet) 50%, var(--surface)) 6px + ); +} + .mois-entree--done .mois-entree__marque { - background: color-mix(in srgb, var(--couleur-projet) 55%, #64748b); + background: var(--couleur-projet); } .mois-entree--blocked .mois-entree__marque { @@ -1990,6 +2185,16 @@ kbd { background: var(--danger); } +/* Le même cadre tireté que sur la frise, à l'échelle de la marque : 1px sur huit + de haut plutôt que 2 sur vingt-six. En `border` et non sur un `::after` — la + marque n'a pas de sélection à qui laisser la place, et `border-box` lui garde + sa taille. Déclaré après les quatre textures de statut, dont il ne prend pas + la place : c'est une phase à venir, en cours ou bloquée qui se trouve en plus + tenue par le dehors. */ +.mois-entree--imposee .mois-entree__marque { + border: 1px dashed var(--texte); +} + /* Chiffres tabulaires : les quantièmes s'alignent d'une ligne à l'autre, ce qui fait de la colonne une échelle lisible plutôt qu'une pile de textes. */ .mois-entree__dates { diff --git a/docs/decisions.md b/docs/decisions.md index ac86fab..b8ee542 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -1150,15 +1150,14 @@ entièrement clos ; il n'a pas eu à changer, seule la liste des phases emporté ### Ce que ça donne à l'œil -Deux **taquets** verticaux aux extrémités de la barre, comme les butées d'une pièce qui ne coulisse -plus ; un **cercle** pour un jalon, qui n'a pas d'extrémités où en poser. La marque se cumule avec -les quatre textures de statut au lieu de leur disputer la place — c'est bien une phase à venir, en -cours ou bloquée, qui se trouve en plus tenue par le dehors. +> Deux **taquets** verticaux aux extrémités de la barre, comme les butées d'une pièce qui ne coulisse +> plus ; un **cercle** pour un jalon, qui n'a pas d'extrémités où en poser. -Elle se pose en `box-shadow` interne, donc sans toucher à la géométrie : la barre garde exactement la -largeur de ses dates. Sur une phase de deux jours, les taquets occupent presque toute la barre et la -texture de statut disparaît ; c'est accepté, une fenêtre de maintenance de deux jours se lit de toute -façon à son infobulle. +C'est ce qui avait été retenu ici, et c'est ce que la section 29 a défait : la marque était trop +faible et mal placée. Elle est aujourd'hui un **cadre tireté** qui cerne la forme entière, barre ou +losange. Le reste du raisonnement tient toujours — elle se cumule avec les quatre textures de statut +au lieu de leur disputer la place, et ne touche pas à la géométrie : la barre garde exactement la +largeur de ses dates. ### Le format passe en version 6 @@ -1176,3 +1175,115 @@ comprenne pourquoi. Au passage, `donneesInitiales` dans `main.go` a été remis d'aplomb : le serveur écrivait encore `version 4` pour un planning vide, deux versions en retard. Sans conséquence — le validateur accepte un fichier plus ancien et le remonte — mais un fichier neuf se déclarait d'avant le cycle de vie. + +## 29. Rendre lisibles le statut et la date imposée + +La section 28 a posé la date imposée ; l'usage a montré que ni elle ni le statut ne se lisaient bien +là où on les cherche. Quatre corrections, de la plus factuelle à la plus discutable. + +### Le libellé d'une phase vit dans le modèle + +« En cours — date imposée, non emportée par un décalage du projet » se recomposait sur quatre sites : +les trois infobulles de la frise, et celle de la vue par mois. La quatrième avait oublié la mention, +si bien que la vue des échéances — celle où une date déléguée compte le plus — taisait ce que la +frise annonçait sur chaque barre. + +D'où `libelleStatut(phase)` dans `model.js`, à côté de la table dont il se sert. Le mettre dans une +vue aurait reposé la même question à la suivante ; le modèle est le seul endroit que les deux vues +connaissent déjà. La vue par mois a reçu du même coup la marque d'une date imposée sur sa puce de +ligne, qui reprend déjà les formes de la frise : le vocabulaire visuel est le même des deux côtés, on +ne l'apprend qu'une fois. + +### Le statut passe de la liste déroulante à quatre boutons + +Une liste déroulante montre une valeur sur quatre, n'en dessine aucune, et demande deux clics. Les +quatre boutons montrent les quatre, chacun peint de la **texture qu'il donne à la barre**, et le +panneau devient ainsi la légende que l'outil n'avait nulle part — au seul moment où on en a besoin, +celui du choix, et sans coûter d'espace permanent au planning. + +Une légende posée sur la frise avait été envisagée d'abord. Elle occupe de la place en permanence +pour une chose qui s'apprend une fois, et elle se lit loin de l'objet qu'elle explique. + +Les textures se peignent dans la **couleur du projet qu'on édite** : `detail.js` pose +`--couleur-projet` sur le formulaire à l'ouverture. Le repli se déclare sur `.panneau__corps`, donc +sur l'élément même que le style inline surcharge — le déclarer sur le groupe de boutons faisait +l'inverse, une valeur posée sur un descendant gagnant toujours contre celle dont il hérite. C'est le +genre de détail qui se paie en minutes de recherche : la teinte du repli est une couleur plausible, +et rien ne signale qu'elle n'est pas celle du projet. + +### Les quatre textures sur une seule échelle + +`doing` était un aplat de la couleur du projet, `done` le même aplat assourdi d'un gris fixe. Deux +nuances de la même teinte, qu'on ne distinguait pas en parcourant un couloir en diagonale — alors que +*ce qui avance / ce qui est fait* est la distinction qu'on lit le plus souvent. + +Deux corrections, et la seconde n'a été possible que grâce à la première. + +**`doing` reçoit une rayure**, comme `blocked` en a une : le motif est le même, la teinte dit lequel +des deux on regarde — du rouge pour une phase bloquée, la couleur du projet mêlée à elle-même diluée +pour une phase qui avance. + +**`done` redevient vif.** Le gris qui l'assourdissait n'était là que pour le séparer de `doing` ; la +rayure s'en charge désormais, et la teinte n'a plus à s'en mêler. C'est un gain net : sur un projet +avancé, la majorité des barres sont terminées, et les éteindre toutes donnait une frise morte où le +travail accompli avait l'air d'un brouillon. Une dilution à mi-chemin avait été essayée d'abord — +même famille de couleur, mais toujours délavée, donc toujours le même reproche. + +La grammaire tient maintenant en deux traits, et c'est cette économie qui la rend lisible : + +- **plein** pour un état stable, **rayé** pour ce qui bouge ou coince ; +- la couleur du projet **pleine** dès qu'une phase a commencé, **diluée** tant qu'elle n'a pas + commencé. + +D'où : à venir dilué et bordé, en cours plein et rayé, terminé plein et nu, bloqué rayé de rouge — +seule teinte étrangère, parce que c'est la seule chose qui ne parle pas d'avancement. Aucune des +quatre ne se lit à une nuance qu'il faudrait comparer à une autre pour la reconnaître. + +Le contraste de la rayure a été resserré au passage — la bande claire descend à 50% de dilution +plutôt que 65% : face à un `done` désormais plein, une rayure trop douce se serait lue comme un aplat +légèrement texturé. + +La barre cumulative garde ses opacités : elle fait neuf pixels de haut, une rayure y serait du bruit, +et elle dit la forme d'ensemble d'un projet, pas le détail d'une phase. + +### La date imposée se marque d'un cadre tireté + +Les deux taquets de la section 28 ne tenaient pas leurs promesses, pour trois raisons qui se +cumulaient : + +- sur une barre de deux jours, ils l'avalaient — la section 28 l'avait prévu et accepté ; à l'usage + ce n'est pas acceptable, une fenêtre de maintenance est *typiquement* courte, c'est le cas central + et non le cas limite ; +- sur une barre à venir, qui porte déjà une bordure, ils se lisaient comme une bordure épaissie aux + bouts, c'est-à-dire comme rien ; +- surtout, ils occupaient exactement la place où le survol révèle les **poignées de + redimensionnement**. Le signe « cette date ne vous appartient pas » tombait là où l'outil dit + « tirez ici pour la changer ». + +La forme se cerne donc maintenant tout entière, d'un trait **tireté** — une barre, un losange, et +jusqu'au bloc des deux champs de date dans le panneau, qui ne montrait rien quand on cochait la case +alors que la conséquence porte précisément sur ces dates-là. Un seul signe partout, là où le losange +se cerclait et la barre se taquetait : c'était deux signes pour une même chose. + +Le tiret n'est pas décoratif. Un cerclage **plein** a été essayé d'abord, et à la taille réelle des +barres on ne le distinguait pas d'une phase simplement sélectionnée. Discontinu, il ne se confond +plus avec rien — et il dit ce qu'il faut : ce n'est pas nous qui traçons cette ligne. + +Sur la frise, le cadre vit sur un `::after` : un élément n'a qu'un `outline`, et c'est la sélection +qui le prend. Les deux marques se superposent donc sans se gêner sur une phase imposée qu'on vient de +sélectionner — un cadre tireté dedans, un contour plein dehors. Le losange l'affine à 1px : la +longueur des tirets suit l'épaisseur du trait, et 2px en posait de trop longs pour 14px de côté. + +Dans le panneau, le padding qui porte le cadre est repris par une marge négative de même valeur : les +champs ne bougent pas d'un pixel quand la case change d'état, seul le trait apparaît. + +### Ce que `detail.js` a appris de la section 28 + +Ajouter `fixed` y avait demandé quatre retouches dispersées — remplissage, application, rafraîchissement, +comparaison — qu'on ne savait liées qu'en les cherchant. Les champs sont maintenant une liste unique +que ces fonctions parcourent. `notes` en reste dehors : son contrôle est bâti par `notes.js` et se +remplit par lui, jamais en écrivant dans le `textarea`, sans quoi l'aperçu markdown ne suivrait pas. + +Le groupe de radios a demandé un détour : `formulaire.status` n'est plus un contrôle mais la liste des +quatre, et n'est donc jamais l'élément focalisé. Sans `aLeFocus()`, le panneau réécrirait le statut +sous les flèches de qui est en train de le choisir. diff --git a/index.html b/index.html index 2ffa064..24e5566 100644 --- a/index.html +++ b/index.html @@ -177,7 +177,13 @@ Jalon (une seule date, affichée en losange) -