Offer 98 icons in a dialog and style a button icon under Design
The icon set grows from 33 to 98 drawings in seven categories (arrows, contact, commerce, files and media, people and security, house and trade, general), including truck, cart, euro, camera, tools and solar. icons.js is the single source; npm run build:icons writes the Twig drawings and the validator list, and a test keeps them equal. Choosing an icon no longer fills the panel with tiles: the panel shows the current icon with "Change", which opens a modal with category tabs and named tiles, keyboard navigable, closing with Escape. Button, icon and icon card share it. A new style group "Symbol" targets the icon inside a button per device and on hover: colour, background, size, padding, radius, rotation, plus the gap to the text. Schema v26 adds hover motion (slide, reveal) and an icon-only button whose label stays as the accessible name and keeps the line height. ADR 109. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6af2e2aead
commit
08998de533
20 files changed
+658
-228
No files matched your search
+11
-11
@@ -1,29 +1,29 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { ICON_PATHS, ICON_LABELS, BUTTON_ICON_GROUPS, ALL_ICON_GROUPS } from '../public/assets/icons.js';
|
||||
import { ICON_PATHS, ICON_LABELS, ICON_GROUPS } from '../public/assets/icons.js';
|
||||
|
||||
const read = path => readFileSync(new URL(path, import.meta.url), 'utf8');
|
||||
|
||||
test('the editor draws the same icons the website renders and the server allows', () => {
|
||||
// Drei Listen, ein Satz: die Zeichnungen der Website (Twig), die Vorschau im Editor und die
|
||||
// erlaubten Namen im Validator. Weicht eine ab, zeigt die Auswahl ein anderes Symbol als die
|
||||
// Seite - oder bietet eins an, das der Server beim Speichern ablehnt.
|
||||
// Seite - oder bietet eins an, das der Server beim Speichern ablehnt. Abhilfe: node scripts/build-icons.mjs
|
||||
const twig = read('../templates/blocks/icon.html.twig');
|
||||
const website = Object.fromEntries([...twig.matchAll(/^\s{4}'?([a-z-]+)'?: '([^']+)',?$/gm)].map(([, name, path]) => [name, path]));
|
||||
assert.deepEqual(ICON_PATHS, website);
|
||||
const validator = read('../src/Content/DocumentValidator.php');
|
||||
const allowed = [...validator.match(/public const ICONS = \[([^\]]+)\]/)[1].matchAll(/'([a-z-]+)'/g)].map(([, name]) => name);
|
||||
assert.deepEqual(Object.keys(ICON_PATHS).sort(), [...allowed].sort());
|
||||
assert.deepEqual(Object.keys(ICON_PATHS), allowed);
|
||||
});
|
||||
|
||||
test('every icon has a German name and the pickers offer each icon exactly once', () => {
|
||||
test('every icon has a German name and sits in exactly one category of the dialog', () => {
|
||||
assert.deepEqual(Object.keys(ICON_LABELS).sort(), Object.keys(ICON_PATHS).sort());
|
||||
const button = BUTTON_ICON_GROUPS.flatMap(([, names]) => names);
|
||||
assert.equal(new Set(button).size, button.length, 'Ein Symbol steht doppelt in der Button-Auswahl.');
|
||||
for (const name of button) assert.ok(ICON_PATHS[name], `${name} hat keine Zeichnung.`);
|
||||
// Der bisherige Pfeil steht vorn: er ist das, was ein Button ohne eigene Wahl trägt.
|
||||
assert.equal(button[0], 'arrow-up-right');
|
||||
const all = ALL_ICON_GROUPS.flatMap(([, names]) => names);
|
||||
assert.deepEqual([...all].sort(), Object.keys(ICON_PATHS).sort(), 'Symbol und Symbolkarte bieten jedes Symbol genau einmal an.');
|
||||
const listed = ICON_GROUPS.flatMap(([, names]) => names);
|
||||
assert.equal(new Set(listed).size, listed.length, 'Ein Symbol steht in zwei Kategorien.');
|
||||
assert.deepEqual([...listed].sort(), Object.keys(ICON_PATHS).sort(), 'Jedes Symbol steht in einer Kategorie.');
|
||||
// Der bisherige Pfeil steht vorn: ihn trägt ein Button ohne eigene Wahl.
|
||||
assert.equal(ICON_GROUPS[0][1][0], 'arrow-up-right');
|
||||
assert.ok(listed.length >= 90, `Nur ${listed.length} Symbole.`);
|
||||
for (const path of Object.values(ICON_PATHS)) assert.match(path, /^[Mm][0-9MmLlHhVvCcSsQqTtAaZz .,-]+$/, 'Ein Pfad enthält Zeichen, die keine Zeichnung sind.');
|
||||
});
|
||||
Reference in new issue
Block a user