diff --git a/DESIGN_SYSTEM.md b/DESIGN_SYSTEM.md index e5261e2..bcc2c05 100644 --- a/DESIGN_SYSTEM.md +++ b/DESIGN_SYSTEM.md @@ -179,8 +179,49 @@ Alertes timer : - le garde-fou bloque uniquement les comptes a rebours recurrents (`Pattern horaire`, `Intervalle`) si la repetition est inferieure a 5 minutes ; - un `Pattern horaire` comme `X:24:X` cible `hh:24:00` et se repete toutes les heures. +### Bloc Notes Riche + +Le bloc notes utilise une edition directe en `contentEditable`, sans mode preview separe. + +Regles UI : + +- toolbar compacte en haut de l'outil ; +- boutons courts pour gras, italique, souligne, paragraphes, titres et listes ; +- couleurs texte et surlignage regroupees dans un dropdown unique avec icone arc-en-ciel et libelles de categories ; +- date de derniere modification affichee en pied d'outil, sans prendre le dessus sur le contenu ; +- switch de stockage des dessins en pied d'outil, avec icone sauvegarde et etat actif ; +- placeholder integre dans la surface d'edition quand la note est vide ; +- le HTML persiste doit rester nettoye via allowlist, jamais via HTML libre. + +### Calque De Dessin + +Les annotations dessinees utilisent un canvas transparent superpose au contenu annote. + +Regles UI : + +- le calque est inactif par defaut pour laisser le contenu editable ; +- en mode dessin, les interactions pointer sont capturees par le canvas ; +- les controles de dessin sont regroupes dans un panneau reutilisable vertical, colle a droite de la surface annotee ; +- seuls les controles directement lies au dessin sont affiches quand le mode dessin est actif ; +- les controles restent compacts : gommer, annuler, effacer, couleur et epaisseur via dropdowns ; +- le mode temporaire privilegie le griffonnage de session et utilise `sessionStorage` ; +- le mode permanent suit le stockage IndexedDB de l'outil ; +- pour les surfaces scrollables, le canvas suit le contenu complet plutot que le viewport visible. +- sur les annotations d'images, les traits utilisent des coordonnees en pourcentage et restent visibles dans l'aperçu reduit ; l'edition se fait uniquement en plein ecran et le switch de sauvegarde reste disponible dans la barre de dessin. + ## 8. Tabs Et Switchs +### Dropdowns Compacts + +Les menus flottants compacts d'icones, couleurs, epaisseurs ou actions rapides doivent reutiliser `CompactDropdown`. + +Regles : + +- conserver un trigger compact, idealement icone seule avec tooltip ; +- fermer au clic exterieur, a `Escape`, a la selection et quand le focus sort du menu ; +- garder le contenu interne libre pour supporter grilles d'icones, swatches, libelles de categories ou choix d'epaisseur ; +- reutiliser les classes visuelles existantes du contexte quand le menu appartient a un outil precis. + Tabs : - utiliser le composant commun quand un outil doit alterner entre plusieurs modes ; diff --git a/docs/STORAGE_SCHEMA.md b/docs/STORAGE_SCHEMA.md index 7d4522a..b6fccfb 100644 --- a/docs/STORAGE_SCHEMA.md +++ b/docs/STORAGE_SCHEMA.md @@ -79,13 +79,36 @@ Type : `notepad` ```json { - "text": "Notes rapides..." + "html": "

Notes rapides...

", + "text": "Notes rapides...", + "updatedAt": "2026-07-29T12:00:00.000Z", + "drawingMode": "permanent", + "drawings": { + "strokes": [ + { + "id": "stroke1", + "color": "#f6c453", + "width": 4, + "points": [ + { "x": 12.5, "y": 48 }, + { "x": 24, "y": 52.5 } + ] + } + ] + } } ``` Stockage compact : -- si `text` est vide, l'entrée de module peut être supprimée. +- l'ancien format `{ "text": "..." }` reste accepté et est converti en HTML riche au prochain enregistrement ; +- `html` est nettoyé avec une allowlist de balises et de couleurs ; +- `text` conserve une version texte pour les exports et les fallbacks ; +- `updatedAt` est omis si vide ou invalide ; +- `drawingMode` vaut `temporary` par défaut et est omis dans ce cas ; +- `drawings` est stocké uniquement si `drawingMode` vaut `permanent` et qu'au moins un trait valide existe ; +- les dessins temporaires du bloc-notes sont conservés dans `sessionStorage`, pas dans IndexedDB ; +- si le texte, la date et les dessins permanents sont vides, l'entrée de module peut être supprimée. ## Outil Checklist @@ -178,7 +201,20 @@ Type : `imageAnnotation` "y": 68, "label": "Entrée" } - ] + ], + "drawings": { + "strokes": [ + { + "id": "stroke1", + "color": "#f6c453", + "width": 4, + "points": [ + { "x": 18.5, "y": 32 }, + { "x": 24, "y": 40.5 } + ] + } + ] + } } ``` @@ -188,6 +224,10 @@ Stockage compact : - `x` et `y` sont des pourcentages entre `0` et `100`. - `label` est facultatif. - `label` est omis si vide. +- `drawings` est facultatif et omis si aucun trait valide n'existe. +- les points des dessins sont stockés en pourcentages entre `0` et `100` pour rester alignés en aperçu réduit et en plein écran. +- les dessins sont éditables uniquement depuis la modale plein écran ; l'aperçu réduit les affiche en lecture seule. +- le mode temporaire des dessins d'image utilise `sessionStorage` et ne modifie pas `drawings` dans IndexedDB tant que l'utilisateur ne repasse pas en stockage permanent. ## Outil Timer diff --git a/tests/helpers/data-validation.mjs b/tests/helpers/data-validation.mjs index d934b0a..9b37e35 100644 --- a/tests/helpers/data-validation.mjs +++ b/tests/helpers/data-validation.mjs @@ -87,6 +87,31 @@ export function validateSiteContent(site) { "toolboxes.storageHelp.title", "toolboxes.storageHelp.text", "toolboxes.modules.notepad.placeholder", + "toolboxes.modules.notepad.toolbarLabel", + "toolboxes.modules.notepad.textFormatLabel", + "toolboxes.modules.notepad.boldTitle", + "toolboxes.modules.notepad.italicTitle", + "toolboxes.modules.notepad.underlineTitle", + "toolboxes.modules.notepad.paragraphTitle", + "toolboxes.modules.notepad.headingTitle", + "toolboxes.modules.notepad.bulletListTitle", + "toolboxes.modules.notepad.numberListTitle", + "toolboxes.modules.notepad.colorGroupLabel", + "toolboxes.modules.notepad.textColorLabel", + "toolboxes.modules.notepad.highlightColorLabel", + "toolboxes.modules.notepad.drawingLabel", + "toolboxes.modules.notepad.drawTitle", + "toolboxes.modules.notepad.eraseTitle", + "toolboxes.modules.notepad.temporaryTitle", + "toolboxes.modules.notepad.permanentTitle", + "toolboxes.modules.notepad.undoDrawingTitle", + "toolboxes.modules.notepad.clearDrawingTitle", + "toolboxes.modules.notepad.drawingColorLabel", + "toolboxes.modules.notepad.drawingWidthLabel", + "toolboxes.modules.notepad.temporaryStatus", + "toolboxes.modules.notepad.permanentStatus", + "toolboxes.modules.notepad.updatedAtPrefix", + "toolboxes.modules.notepad.sessionStorageError", "toolboxes.modules.checklist.itemPlaceholder", "toolboxes.modules.checklist.sectionPlaceholder", "toolboxes.modules.checklist.quantityLabel", @@ -246,6 +271,16 @@ export function validateSiteContent(site) { "toolboxes.modules.imageAnnotation.emptyMarkers", "toolboxes.modules.imageAnnotation.deleteImageTitle", "toolboxes.modules.imageAnnotation.deleteMarkerTitle", + "toolboxes.modules.imageAnnotation.drawingLabel", + "toolboxes.modules.imageAnnotation.drawTitle", + "toolboxes.modules.imageAnnotation.eraseTitle", + "toolboxes.modules.imageAnnotation.undoDrawingTitle", + "toolboxes.modules.imageAnnotation.clearDrawingTitle", + "toolboxes.modules.imageAnnotation.drawingColorLabel", + "toolboxes.modules.imageAnnotation.drawingWidthLabel", + "toolboxes.modules.imageAnnotation.temporaryTitle", + "toolboxes.modules.imageAnnotation.permanentTitle", + "toolboxes.modules.imageAnnotation.sessionStorageError", "toolboxes.emptyTitle", "toolboxes.emptyText" ].forEach((path) => assertNonEmptyString(site, path)); diff --git a/tests/static-toolboxes.test.mjs b/tests/static-toolboxes.test.mjs index 5bf232b..6299796 100644 --- a/tests/static-toolboxes.test.mjs +++ b/tests/static-toolboxes.test.mjs @@ -114,7 +114,7 @@ test("toolbox module registry and modules expose expected behavior", async () => assert.match(moduleRegistry, /module-content/); assert.match(moduleRegistry, /module-scroll-button/); assert.match(moduleRegistry, /Icon name="dropdown"/); - assert.match(moduleRegistry, /aria-expanded=\{quickOpen\}/); + assert.match(moduleRegistry, /CompactDropdown/); assert.doesNotMatch(source, /