@conciso/design-system 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +5 -3
- package/CHANGELOG.md +0 -1786
package/CHANGELOG.md
DELETED
|
@@ -1,1786 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
Alle nennenswerten Änderungen am Conciso Design System. Format nach
|
|
4
|
-
[Keep a Changelog](https://keepachangelog.com/de/1.1.0/), Versionierung nach
|
|
5
|
-
[SemVer](https://semver.org/lang/de/).
|
|
6
|
-
|
|
7
|
-
Versionspolitik:
|
|
8
|
-
- **MAJOR** — Breaking Changes an der öffentlichen API (umbenannte/entfernte
|
|
9
|
-
Klassen oder Tokens, geänderte Ladereihenfolge).
|
|
10
|
-
- **MINOR** — neue Komponenten/Tokens, abwärtskompatibel.
|
|
11
|
-
- **PATCH** — Bugfixes, Kontrast-/Dark-Mode-Korrekturen, Doku.
|
|
12
|
-
|
|
13
|
-
Releases werden als Git-Tags `vX.Y.Z` markiert.
|
|
14
|
-
|
|
15
|
-
> **Eingefroren ab Version 2.0.0.** Ab hier entsteht ein Release automatisch aus
|
|
16
|
-
> Conventional Commits (siehe
|
|
17
|
-
> [ADR-0010](docs/adr/0010-release-ausloesung-und-versionsquelle.md)); die Notizen dazu
|
|
18
|
-
> stehen im jeweiligen GitHub-Release, nicht mehr in dieser Datei. Die
|
|
19
|
-
> Abschnitte unterhalb dieser Zeile sind der letzte handgeschriebene Stand.
|
|
20
|
-
|
|
21
|
-
## [2.0.0] - 2026-09-23
|
|
22
|
-
|
|
23
|
-
### Breaking
|
|
24
|
-
- **`@conciso/design-system-angular` verlangt jetzt Angular 22.** Die peerDependencies
|
|
25
|
-
`@angular/common`, `@angular/core`, `@angular/forms` und `@angular/platform-browser`
|
|
26
|
-
stehen auf `^22.0.0` statt `^21.2.0`; die Lib wird mit dem Angular-22-Compiler gebaut.
|
|
27
|
-
Konsumenten auf Angular 21 bleiben auf 1.x, bis sie selbst auf 22 gehen. Mit Angular 22
|
|
28
|
-
kommt TypeScript 6.0 als Pflicht für den Build des Konsumenten (`>=6.0 <6.1`). Die
|
|
29
|
-
mitgelieferten Icons (`@ng-icons/core`, `@ng-icons/heroicons`) springen von 33 auf 36;
|
|
30
|
-
der Konsument fasst sie nicht direkt an (siehe ADR-0004), bekommt sie aber als
|
|
31
|
-
`dependency` mit. Die Consumer-Fixture baut gegen Angular 22.
|
|
32
|
-
- **Inhalts-Inputs von 16 Komponenten sind jetzt `input.required()`.** Betroffen:
|
|
33
|
-
`BlockquoteComponent` (`quote`, `name`), `TestimonialComponent` (`quote`, `name`),
|
|
34
|
-
`TeamVoiceComponent` (`quote`, `name`), `StatCardComponent` (`value`, `label`),
|
|
35
|
-
`StatStripComponent` (`stats`), `DownloadCtaComponent` (`title`, `primaryLabel`),
|
|
36
|
-
`FaqComponent` (`items`), `CarouselComponent` (`slides`), `LogoCarouselComponent`
|
|
37
|
-
(`sets`), `CardComponent` (`title`, `text`), `AreaBadgeComponent` (`label`),
|
|
38
|
-
`StatusBadgeComponent` (`label`), `ChipComponent` (`label`), `PillComponent`
|
|
39
|
-
(`label`), `CodeBlockComponent` (`code`) und `SnackbarComponent` (`message`). Diese
|
|
40
|
-
Inputs trugen bisher erfundenen Conciso-Beispieltext als Default (Namen, Zitate,
|
|
41
|
-
Kennzahlen, FAQ-Einträge, Slide-Inhalte …) — ein vergessenes Binding lieferte damit
|
|
42
|
-
unbemerkt Marketingtext statt eines auffälligen Fehlers aus. Fehlt der Wert jetzt,
|
|
43
|
-
wirft Angular zur Laufzeit `NG0950`; ein vergessenes Binding fällt damit sofort auf,
|
|
44
|
-
statt still Demo-Inhalt auszuliefern. Reines Beiwerk (`roleLabel`, `trendText`,
|
|
45
|
-
`eyebrow`/`desc`/`meta`/`secondaryLabel` bei DownloadCta, `actionLabel` bei Card und
|
|
46
|
-
Snackbar) bleibt optional, defaultet aber jetzt auf `''` statt auf erfundenen Text.
|
|
47
|
-
Die bisherigen Default-Texte sind nicht verloren — sie stehen jetzt als explizite
|
|
48
|
-
`args` in den jeweiligen Stories (`storybook-angular/src/lib/**/*.stories.ts`) und
|
|
49
|
-
rendern dort weiterhin unverändert.
|
|
50
|
-
- **`FieldShellComponent` ist kein Export der öffentlichen API mehr.** Die Komponente war nie als
|
|
51
|
-
öffentliche API gedacht — ihre Klassendoku bezeichnet sie seit jeher als intern
|
|
52
|
-
(„Präsentations-Hülle für alle Field-Komponenten“), es gab weder eine eigene Story noch JSDoc
|
|
53
|
-
dafür. Textfeld, Textbereich und Auswahlfeld beziehen sie weiterhin über den relativen Import
|
|
54
|
-
(`./field-shell.component`), nur der Re-Export aus `public-api.ts` entfällt. Wer eigene Feldtypen
|
|
55
|
-
baut, setzt die Klassen der CSS-Schicht (`.field`, `.helper`, `.error-msg`, …) direkt zusammen,
|
|
56
|
-
statt sich an eine interne Hilfskomponente zu binden.
|
|
57
|
-
- **97 interne Member sind von `public` auf `protected` gewechselt, darunter 35 Methoden.**
|
|
58
|
-
Betroffen sind Template-Handler und internes Zustandsgerüst, etwa `ChipComponent.toggle`,
|
|
59
|
-
`SelectComponent.open`/`close`/`select`, `CarouselComponent.next`/`goTo` und die
|
|
60
|
-
`handleInput`/`handleBlur` der Feld-Basis. Sie waren nie als API gedacht, standen aber in der
|
|
61
|
-
generierten TypeScript-Oberfläche und seit dem Docgen-Server aus
|
|
62
|
-
[ADR-0006](docs/adr/0006-storybook-10-6-docgen-server-mcp-und-theming.md) auch in Props-Tabelle
|
|
63
|
-
und Manifest. Wer eine dieser Methoden von außen aufgerufen hat, kompiliert nicht mehr; der
|
|
64
|
-
vorgesehene Weg führt über Inputs und Outputs. Die Regel dahinter steht in
|
|
65
|
-
[ADR-0007](docs/adr/0007-api-konventionen-der-angular-komponenten.md): Interfaces wie
|
|
66
|
-
`ControlValueAccessor` bleiben notwendigerweise `public` und tragen nur `@internal`.
|
|
67
|
-
|
|
68
|
-
### Added
|
|
69
|
-
- **`SectionComponent` (`[cdsSection]`), erste Angular-Wrapper-Komponente für die
|
|
70
|
-
Seitenbausteine der Beispielseiten — und wie `cds-icon-card` (Ticket 05) auf
|
|
71
|
-
Attributselektor umgestellt.** Wrapper um `.ep-section` samt dem optionalen
|
|
72
|
-
Kopf-Trio `.ep-section-label`/`-h2`/`-sub` (`label`, `heading`, `sub`, alle
|
|
73
|
-
Beiwerk), dazu `area` (`.t-{area}` auf dem Label) und `labelledBy`. Erste Fassung
|
|
74
|
-
war `cds-section` als eigenes Element, das selbst zwischen `<section
|
|
75
|
-
aria-labelledby="…">` (mit zugänglichem Namen) und einem namenlosen `<div>` wählte.
|
|
76
|
-
Eine Sektionsfläche musste dabei auf einem UMSCHLIESSENDEN Element sitzen, nicht auf
|
|
77
|
-
dem `<cds-section>`-Host — gemessen im laufenden Storybook (Details in
|
|
78
|
-
`docs/adr/0008-selektortyp-der-wrapper-komponenten.md`, „Fall 2“): Host-`background`
|
|
79
|
-
wurde von `getComputedStyle` und `getBoundingClientRect()` beide als korrekt gemeldet,
|
|
80
|
-
der Screenshot zeigte trotzdem keinen einzigen gemalten Pixel — ein unbekanntes
|
|
81
|
-
Custom Element ohne eigenen Inline-Inhalt, dessen Block-Kind herausgebrochen wird,
|
|
82
|
-
hat keine eigene Box zu füllen. Jetzt `section[cdsSection], div[cdsSection]`: der
|
|
83
|
-
Konsument wählt das Tag (und damit, ob überhaupt eine `<section>`-Landmark möglich
|
|
84
|
-
ist), die Komponente setzt nur noch `aria-labelledby`, wenn ein Name verfügbar ist.
|
|
85
|
-
Die Fläche sitzt jetzt direkt am Host (`<section cdsSection
|
|
86
|
-
style="background:…">`), kein umschließendes Element mehr nötig — bewusst weiterhin
|
|
87
|
-
**kein** `background`-Input, die Sektionsfläche bleibt eine Entscheidung der Seite,
|
|
88
|
-
nicht des Bauteils. `@if`/`@else`, `<ng-template>` und `NgTemplateOutlet` entfallen,
|
|
89
|
-
das Template ist jetzt linear. Neue Story `Fläche am Host`, `Interaktiv`/`Ohne
|
|
90
|
-
Kopf`/`Benannt von außen`/`Nur Überschrift`/`Bereichsgefärbtes Label` auf
|
|
91
|
-
`<section cdsSection>`/`<div cdsSection>` umgestellt. Doku-Sektion „Sektion“
|
|
92
|
-
(`docs/index.html#sec-section`) entsprechend nachgezogen. Erstes Ticket der
|
|
93
|
-
Seitenbausteine-Serie (`.scratch/angular-seitenbausteine/spec.md`); die
|
|
94
|
-
Kopf-Trio-Struktur trägt 133 der Beispielseiten-Sektionen, 85 davon mit Kopfzeile.
|
|
95
|
-
- **`HeroImageComponent` (`cds-hero-image`), zweites Ticket der Seitenbausteine-Serie.**
|
|
96
|
-
Wrapper um `.hero-image` (`css/components.css:851–878`) samt optionaler Caption als
|
|
97
|
-
Gradient-Overlay (`-caption`, `-caption-eyebrow`, `-caption-title`, `-caption-text`):
|
|
98
|
-
vollbreites, randloses `<figure>` im 21:9-Format, Standard-Hero auf allen
|
|
99
|
-
Customer-Pages (17 Vorkommen in den Beispielseiten). `src`/`alt` sind
|
|
100
|
-
`input.required()`, `eyebrow`/`heading`/`text` Beiwerk. Bleiben alle drei Textteile
|
|
101
|
-
leer, entfällt das `<figcaption>` vollständig statt leer zu rendern. Neuer Input
|
|
102
|
-
`headingLevel` (`1` Default, `2`) macht die Heading-Ebene des Caption-Titels
|
|
103
|
-
explizit, für Beitrags-Heros, die unter einem eigenen `<h1>` (Article-Header)
|
|
104
|
-
sitzen und sonst eine zweite Top-Überschrift bekämen. `objectPosition` als
|
|
105
|
-
Style-Binding direkt am `<img>` (nicht als Klasse, die CSS-Schicht hat dafür keinen
|
|
106
|
-
Modifier) — die eine bewusste Ausnahme von der Regel, dass Inline-Styles aus dem
|
|
107
|
-
Mockup nicht in die Komponente wandern, weil der Bildausschnitt eine Eigenschaft
|
|
108
|
-
des konkreten Bildes ist, nicht der Seite. `eager` (Default `true`) steuert
|
|
109
|
-
`loading="eager"`/`"lazy"`. Bewusst **kein** `tabindex`/`id`-Handling: Das
|
|
110
|
-
Sprungziel des Skip-Links ist eine Entscheidung der Seite, der Konsument setzt
|
|
111
|
-
beides am `<cds-hero-image>`-Host. Neue Bauteil-Ebene `Komponenten/Hero/Hero-Bild`
|
|
112
|
-
unter der bestehenden Doku-Sektion „Hero“ (bisher nur MDX-Übersicht) mit vier
|
|
113
|
-
Stories (`Interaktiv`, `Ohne Caption`, `Beitrags-Hero (h2)`, `Bildausschnitt`);
|
|
114
|
-
Icon `ui-computer-desktop` in `SECTION_ICON_KEYS` von der bisher verschmolzenen
|
|
115
|
-
Ein-Kind-ID (`komponenten-hero--übersicht`) auf die jetzt eigenständige
|
|
116
|
-
Sektions-ID (`komponenten-hero`) umgehängt.
|
|
117
|
-
- **`StoererComponent` (`cds-stoerer`) und `StoererSetComponent` (`cds-stoerer-set`),
|
|
118
|
-
drittes Ticket der Seitenbausteine-Serie.** Wrapper um `.stoerer`/`-set`/`-list`
|
|
119
|
-
(`css/components.css:926–974`): das Verweiskachel-Set, das ausschließlich auf der
|
|
120
|
-
Startseite oben rechts über dem Hero-Bild liegt. `cds-stoerer` ist eine vollständig
|
|
121
|
-
klickbare `<a class="stoerer">` mit Pflicht-Inputs `topic`/`title`/`href` und
|
|
122
|
-
Beiwerk `meta`/`date` (ISO, formatiert als deutsches Langdatum); bleiben `meta` und
|
|
123
|
-
`date` beide leer, entfällt die Meta-Zeile vollständig statt leer zu rendern. Der
|
|
124
|
-
`sr-only`-Trenner zwischen Datum und Ort/Lesezeit bleibt erhalten, wenn beide
|
|
125
|
-
gesetzt sind. Das Icon ist wie bei `cds-icon-card` (Ticket 05) projizierter Inhalt
|
|
126
|
-
(`<ng-content select="[cdsIcon]">`, nicht ein `icon`-Input), weil die
|
|
127
|
-
Störer-Icons wechselnde Heroicons sind, keine DS-Bereichsglyphen; abweichend von
|
|
128
|
-
Ticket 05 trägt das projizierte `<svg>` die Klasse `stoerer-icon` selbst, weil
|
|
129
|
-
`.stoerer-icon` (anders als `.ep-card-icon`) direkt auf dem SVG sitzt, ohne
|
|
130
|
-
Container, der die Größe per Nachfahren-Selektor durchreichen könnte. **Die
|
|
131
|
-
`<li>`-Frage:** `.stoerer-list` ist ein `<ul>`, seine Kacheln müssen echte `<li>`
|
|
132
|
-
sein, sonst bekommen sie laut HTML-AAM keine `listitem`-Rolle. Ein `display:
|
|
133
|
-
contents`-Wrapper hätte neues CSS gebraucht (ADR-0001 verbietet das); gelöst über
|
|
134
|
-
dasselbe `TemplateRef`/`ngTemplateOutlet`-Muster, das `cds-area-tabs`/`cds-area-tab`
|
|
135
|
-
bereits etabliert: `cds-stoerer` rendert in ein internes `<ng-template>`,
|
|
136
|
-
`cds-stoerer-set` liest die projizierten Kacheln per `contentChildren()` und setzt
|
|
137
|
-
ihr Markup direkt in ein selbst gerendertes `<li>` — im laufenden Storybook geprüft,
|
|
138
|
-
`<cds-stoerer>` taucht im gerenderten DOM nirgends auf, `<ul class="stoerer-list">`
|
|
139
|
-
hat ausschließlich `<li>` als direkte Kinder. Der Positionsrahmen `.stoerer-hero`
|
|
140
|
-
(umschließt Hero-Bild UND Set) bleibt bewusst beim Konsumenten. Neue Bauteil-Ebene
|
|
141
|
-
`Komponenten/Hero/Störer` (Stories `Interaktiv`, `Zwei Kacheln über dem Hero`,
|
|
142
|
-
`Ohne Meta`), `storySort.order` der Sektion „Hero“ um `Störer` ergänzt.
|
|
143
|
-
- **`LinkCardComponent` (`cds-link-card`) und `FeaturedCardComponent`
|
|
144
|
-
(`cds-featured-card`), viertes Ticket der Seitenbausteine-Serie: die beiden
|
|
145
|
-
klickbaren Kartenvarianten, die `CardComponent` laut eigener Klassendoku bewusst
|
|
146
|
-
nicht abdeckt.** `cds-link-card` ist ein echtes `<a class="card card-elevated">`
|
|
147
|
-
(css/components.css:147–154) — die ganze Fläche ist der Link und trägt deshalb
|
|
148
|
-
nach `CONTRIBUTING.md` §4 den Schatten, den `cds-card` nicht trägt; Struktur wie
|
|
149
|
-
`cds-card` (optionale bereichsgefärbte `.card-media`, `.card-eyebrow`/`.card-title`/
|
|
150
|
-
`.card-text`), dazu ein optionaler Fuß `.card-cta-link` (`ctaLabel`, leer = kein
|
|
151
|
-
Fuß) mit `ctaPinned` (`--pinned`, unten angeheftet für gleich hohe Karten im
|
|
152
|
-
Raster) — als `<span>`, nicht als zweites `<a>`, weil die Karte selbst schon `<a>`
|
|
153
|
-
ist. `cds-featured-card` bildet `.card-featured` ab (css/components.css:230–249):
|
|
154
|
-
Bild links 60 %, Textspalte rechts 40 % als absolut positioniertes Overlay, mit
|
|
155
|
-
`.card-title-hero` (Serif-Editorial-Titel) und optionaler `.pill`; mit gesetztem
|
|
156
|
-
`href` ein `<a class="card card-elevated card-featured">`, sonst ein `<article
|
|
157
|
-
class="card card-featured">` ohne `.card-elevated` (die Klasse wirkt laut §4
|
|
158
|
-
ohnehin nur auf `a.card-elevated`, eine `<article>` bekäme den Schatten auch mit
|
|
159
|
-
gesetzter Klasse nicht). Media und Body stehen dafür einmal in einem gemeinsamen
|
|
160
|
-
`<ng-template>` und werden in beiden Zweigen (`<a>`/`<article>`) per
|
|
161
|
-
`<ng-container [ngTemplateOutlet]>` eingesetzt — dasselbe Muster wie
|
|
162
|
-
`SectionComponent`; `<ng-container>` rendert selbst kein Element, die
|
|
163
|
-
Kindselektoren bleiben unberührt. **Die Pill ist direkt komponiertes Markup, kein
|
|
164
|
-
`<cds-pill>`:** `.card-featured` arbeitet mit direkten Kindselektoren
|
|
165
|
-
(`.card-featured>.card-media`, `.card-featured-body>.pill`/`-.card-text`/
|
|
166
|
-
`-.card-title-hero`); `<cds-pill>` rendert sein `.pill`-Element eine Ebene unter
|
|
167
|
-
dem eigenen Host, ein projiziertes `<cds-pill>` stünde also zwischen
|
|
168
|
-
`.card-featured-body` und `.pill` und die Kindselektoren griffen still nicht mehr
|
|
169
|
-
(Layout bricht, kein Fehler). Dieselbe Abwägung wie in `download-cta.component.ts`
|
|
170
|
-
(Kommentar über den Buttons): Klassen direkt komponieren statt eine
|
|
171
|
-
Wrapper-Komponente dazwischenzusetzen. Weil die Pille direkt komponiert wird,
|
|
172
|
-
übernimmt `cds-featured-card` auch die `aria-label`-Regel von `PillComponent` von
|
|
173
|
-
Hand: `pillAriaLabel` überschreibt den Default „Bereich `<pill>`“ für Fälle, in
|
|
174
|
-
denen die Pille keinen Bereich benennt (z. B. „12 min Lesezeit“ →
|
|
175
|
-
`aria-label="Lesezeit 12 Minuten"`). Im laufenden Storybook geprüft: die
|
|
176
|
-
gerenderte Kette hat exakt die Kindselektoren, auf die das CSS zielt, kein
|
|
177
|
-
zusätzliches Element dazwischen, kein `<cds-pill>`-Tag im DOM — erneut gemessen
|
|
178
|
-
nach der Umstellung auf `ngTemplateOutlet`, unverändertes Ergebnis. Neue
|
|
179
|
-
Bauteil-Ebenen `Komponenten/Cards & Teaser/Klickbare Karte` (Stories `Interaktiv`,
|
|
180
|
-
`Pro Bereich`, `Im Raster`) und `Komponenten/Cards & Teaser/Featured-Karte`
|
|
181
|
-
(Stories `Interaktiv`, `Pro Bereich`, `Pille als Lesezeit`, `Ohne Pill`,
|
|
182
|
-
`Ohne Link`; bewusst **kein** Grid-Beispiel — die Doku verlangt „genau einer auf
|
|
183
|
-
der Bühne“), `storySort.order` der Sektion „Cards & Teaser“ entsprechend ergänzt.
|
|
184
|
-
- **`IconCardComponent` (`[cdsIconCard]`), fünftes Ticket der Seitenbausteine-Serie:
|
|
185
|
-
die Icon-Teaser-Kachel der Beispielseiten (81 Vorkommen) — UND erste Komponente mit
|
|
186
|
-
Attributselektor statt eigenem Element.** Bildet `.ep-card` ab
|
|
187
|
-
(css/components.css:1298–1340): farbige Icon-Kachel, Eyebrow, Titel, Text, optionale
|
|
188
|
-
Pfeil-CTA-Zeile. Erste Fassung war `cds-icon-card` als eigenes Element mit
|
|
189
|
-
`href`-Input (`<a>`/`<div>` per `@if`/`@else`). Gemessen im laufenden Storybook: zwei
|
|
190
|
-
Karten mit unterschiedlich langem Text ergaben im `.ep-cards`-Grid ungleiche
|
|
191
|
-
`.ep-card`-Höhen (174px/270px), weil `align-items:stretch` nur den unsichtbaren
|
|
192
|
-
`<cds-icon-card>`-Host streckt, nicht das `.ep-card`-Element eine Ebene darunter.
|
|
193
|
-
Dieselbe Messung ohne Host-Wrapper (rohes Markup direkt in `.ep-cards`) ergab
|
|
194
|
-
306px/306px, CTA-Unterkanten auf identischer Y-Koordinate — die CSS-Schicht gleicht
|
|
195
|
-
Kartenhöhen also korrekt aus, der Fehler saß im Wrapper-Element. Konsequenz, analog
|
|
196
|
-
zu Angular Materials `a[mat-button], button[mat-button]`: Die Komponente ist jetzt
|
|
197
|
-
`a[cdsIconCard], div[cdsIconCard]`, hängt sich also als Attribut an ein vom
|
|
198
|
-
Konsumenten geschriebenes `<a>`/`<div>`, statt ein eigenes Host-Element zu sein.
|
|
199
|
-
`href` ist damit kein Input mehr (natives Attribut am `<a>`). `.ep-card-link` hängt
|
|
200
|
-
bewusst an „ist `<a>` UND hat `href`“, nicht am Tag allein: Ein `<a cdsIconCard>`
|
|
201
|
-
ohne `href` ist weder fokussierbar noch hat es eine Link-Rolle, hätte mit dem Tag
|
|
202
|
-
allein aber trotzdem den Link-Look (Schatten, Hover) bekommen — genau die Garantie,
|
|
203
|
-
die die frühere `href`-Input-Fassung strukturell hatte (leerer String → zwingend der
|
|
204
|
-
`<div>`-Zweig). Die Prüfung sitzt als **Methode im Host-Binding**
|
|
205
|
-
(`'[class.ep-card-link]': 'isLink()'`), nicht als einmalig berechnetes Feld, weil
|
|
206
|
-
`href` zur Laufzeit gesetzt werden kann: Host-Bindings werden bei jedem Refresh der
|
|
207
|
-
ELTERN-Ansicht neu ausgewertet, unabhängig vom OnPush-Status der Komponente selbst
|
|
208
|
-
— kein Sonderfall des in ADR-0007 §3 verworfenen Getter-Musters (das betraf
|
|
209
|
-
Getter in der eigenen Kindvorlage). Empirisch mit einem Signal-getriebenen
|
|
210
|
-
`[attr.href]`-Toggle zur Laufzeit geprüft (Spike, seither gelöscht): kein `effect()`
|
|
211
|
-
nötig. Neue Story „Anker ohne Href“ pinnt den Fall. Erneut gemessen: alle Karten
|
|
212
|
-
306px, CTA-Unterkanten deckungsgleich — als Regressionsschutz jetzt eine
|
|
213
|
-
Play-Funktion in der Story „Im Raster“ mit bewusst unterschiedlich langen Texten
|
|
214
|
-
(vorher unauffällig gleich lang). `@angular-eslint/component-selector` erlaubt dafür
|
|
215
|
-
jetzt zusätzlich zum Element-Standard (`kebab-case`, weiterhin für alle anderen
|
|
216
|
-
Komponenten) einen `cds`-Attributselektor (`camelCase`) als benannte Ausnahme
|
|
217
|
-
([ADR-0008](docs/adr/0008-selektortyp-der-wrapper-komponenten.md)).
|
|
218
|
-
Das Icon kommt als projizierter Inhalt (`<ng-content select="[cdsIcon]">`), anders
|
|
219
|
-
als bei `cds-stoerer` aber OHNE dass das SVG eine eigene Größenklasse tragen muss:
|
|
220
|
-
`.ep-card-icon` ist ein echter Container und reicht Maße/Stroke über den
|
|
221
|
-
Nachfahren-Selektor `.ep-card-icon svg` durch. `data-area` sitzt auf Karte (Host),
|
|
222
|
-
Icon-Kachel und Eyebrow, wie im Mockup; die CTA-Farbe braucht kein eigenes
|
|
223
|
-
`data-area`, sie kommt über `.ep-card[data-area] .ep-card-cta`. **Kein
|
|
224
|
-
`cdsIconCards`-Raster:** `.ep-cards` ist ein reines `display:grid` ohne Struktur
|
|
225
|
-
oder Verhalten (dieselbe Begründung wie beim Verzicht auf einen
|
|
226
|
-
`layout-grid`-Wrapper, siehe `spec.md`) — Konsumenten schreiben `<div
|
|
227
|
-
class="ep-cards">` von Hand. Neue Bauteil-Ebene `Komponenten/Cards & Teaser/
|
|
228
|
-
Icon-Karte` (Stories `Interaktiv`, `Als Link`, `Anker ohne Href`, `Pro Bereich`,
|
|
229
|
-
`Im Raster`, `Ohne CTA`), `storySort.order` der Sektion „Cards & Teaser“
|
|
230
|
-
entsprechend ergänzt.
|
|
231
|
-
- **`FeatureComponent` (`[cdsFeature]`), sechstes Ticket der Seitenbausteine-Serie:
|
|
232
|
-
die offene Feature-Zeile ohne Box und ohne Schatten (40 Vorkommen auf den
|
|
233
|
-
Beispielseiten).** Bildet `.ep-feature` ab (css/components.css:1363–1379):
|
|
234
|
-
Icon-Kachel links, Titel und Text rechts. Attributselektor von Anfang an
|
|
235
|
-
(`div[cdsFeature]`), nicht erst nach einem Fehlversuch: das Mockup setzt die
|
|
236
|
-
Spaltenklasse konsequent am selben Element wie `.ep-feature`
|
|
237
|
-
(`class="ep-feature col-4"`), das Bauteil ist damit selbst Grid-Kind UND Ziel
|
|
238
|
-
einer Layout-Klasse des Konsumenten — exakt das Kriterium aus
|
|
239
|
-
[ADR-0008](docs/adr/0008-selektortyp-der-wrapper-komponenten.md), hier vorab
|
|
240
|
-
angewandt statt nachträglich gemessen. Gemessen wurde trotzdem: die Story
|
|
241
|
-
„Dreispalter“ setzt drei `.ep-feature` mit stark unterschiedlich langem Text als
|
|
242
|
-
`col-4`-Geschwister in ein `.layout-grid` — alle drei 128px hoch, alle drei
|
|
243
|
-
Unterkanten bei y=128, der Grid-Zeilenausgleich greift direkt auf `.ep-feature`,
|
|
244
|
-
ohne Host-Element dazwischen. Das Icon kommt als projizierter Inhalt
|
|
245
|
-
(`<ng-content select="[cdsIcon]">`); `.ep-feature-icon` ist wie `.ep-card-icon`
|
|
246
|
-
ein Container, der Maße über den Nachfahren-Selektor `.ep-feature-icon svg`
|
|
247
|
-
durchreicht, geht darin aber weiter als die Icon-Karte: es setzt zusätzlich
|
|
248
|
-
`color` auf dem Container (`.ep-card-icon` tut das nicht), die vier
|
|
249
|
-
`[data-area]`-Varianten liefern also nicht nur die Kachelfarbe, sondern auch den
|
|
250
|
-
passenden Icon-Ton — ein projiziertes `<svg stroke="currentColor">` erbt ihn ohne
|
|
251
|
-
eigenes Zutun, das Mockup nutzt genau das (`docs/index.html:10406` u. a.). Der
|
|
252
|
-
optionale CTA (`.card-cta-link`), direktes Kind von `.ep-feature-body`, ist ein
|
|
253
|
-
echter `<a href>`, wenn `ctaHref` gesetzt ist, sonst ein `<span>` mit identischer
|
|
254
|
-
Optik — nie ein `<a>` ohne `href`. Ausgezählt in `docs/index.html`: alle 13
|
|
255
|
-
`.card-cta-link`-Vorkommen in `.ep-feature-body` sind entweder ein `<a href="…">`
|
|
256
|
-
(12×) oder ein `<span>` (1×, Platzhalter „Landingpage folgt“ ohne Ziel), niemals
|
|
257
|
-
ein `<a>` ohne `href` — dieselbe Falle, die `cds-icon-card` über `isLink()`
|
|
258
|
-
schließt, hier aber strukturell im `@if`/`@else`-Zweig statt am Host-Tag gelöst,
|
|
259
|
-
weil der Host bei `cdsFeature` immer `<div>` ist. Ein `<a>` ohne `href` wäre weder
|
|
260
|
-
fokussierbar noch hätte es eine Link-Rolle, sähe mit der `.card-cta-link`-Optik
|
|
261
|
-
aber trotzdem bedienbar aus; erster Entwurf hatte das nur über `[attr.href]="…||
|
|
262
|
-
null"` abgefedert, nicht ausgeschlossen. Zweite Korrektur an derselben Stelle:
|
|
263
|
-
der neue `ctaAriaLabel`-Input. Erster Entwurf ging davon aus, das Mockup verzichte
|
|
264
|
-
meist auf einen zusätzlichen `aria-label` — ausgezählt war das Gegenteil richtig:
|
|
265
|
-
von den 12 `<a class="card-cta-link">` tragen 11 einen `aria-label`, weil sich nur
|
|
266
|
-
3 verschiedene sichtbare Texte auf diese 12 Links verteilen (`„Zur Landingpage“`
|
|
267
|
-
allein zehnmal) und eine Screenreader-Linkliste sonst zehnmal denselben Namen
|
|
268
|
-
hörte. Das Mockup disambiguiert durchgängig mit `<sichtbarer Text>: <Ziel>`
|
|
269
|
-
(`aria-label="Zur Landingpage: KI Kickstart Workshops"`) — `ctaAriaLabel` bildet
|
|
270
|
-
genau das nach, Default `''` (sichtbarer `ctaLabel`-Text bleibt zugänglicher
|
|
271
|
-
Name), wirkt nur am `<a>`-Zweig. Neue Bauteil-Ebene
|
|
272
|
-
`Komponenten/Cards & Teaser/Feature-Liste` (Stories `Interaktiv`, `Dreispalter`,
|
|
273
|
-
`Mit CTA`, `Ohne Href`, `Pro Bereich`), `storySort.order` der Sektion
|
|
274
|
-
„Cards & Teaser“ entsprechend ergänzt.
|
|
275
|
-
- **`CtaBandComponent` (`[cdsCtaBand]`), siebtes Ticket der Seitenbausteine-Serie: das
|
|
276
|
-
bereichsgefärbte Page-End-CTA-Band am Ende jeder Customer-Page.** Bildet
|
|
277
|
-
`.ep-cta-band` samt Kopf-Duo `.ep-cta-h2`/`.ep-cta-sub` und einer Aktion ab
|
|
278
|
-
(css/components.css:1456; 22 Vorkommen auf den Beispielseiten, ausnahmslos genau
|
|
279
|
-
eine Aktion). Vier Entscheidungen, alle gemessen statt hergeleitet: **(1)**
|
|
280
|
-
Attributselektor (`div[cdsCtaBand]`), derselbe „Fläche am Host“-Fall wie
|
|
281
|
-
`cds-section` ([ADR-0008](docs/adr/0008-selektortyp-der-wrapper-komponenten.md)) —
|
|
282
|
-
`.ep-cta-band` trägt kein `[data-area]` (per Grep geprüft), die Bandfläche kommt in
|
|
283
|
-
allen 22 Vorkommen als Inline-Style direkt am Element; ein Element-Selektor hätte
|
|
284
|
-
denselben ungemalten Hintergrund reproduziert, den ADR-0008 „Fall 2“ für
|
|
285
|
-
`cds-section` maß. Nur `<div>`, kein `<section>`-Zwilling: keines der 22 Vorkommen
|
|
286
|
-
variiert das Tag. **(2)** `area` färbt nur `.btn-{area}` auf der Aktion, nicht die
|
|
287
|
-
Bandfläche — dieselbe Konsumenten-Zuständigkeit wie bei `cds-section`, hier
|
|
288
|
-
zusätzlich erzwungen, weil das CSS an dieser Klasse ohnehin keinen
|
|
289
|
-
`[data-area]`-Haken kennt. **(3)** Die `.btn-filled`+`.btn-on-band`-Klassen sind
|
|
290
|
-
direkt komponiert, nicht über `cds-button` projiziert (Präzedenzfall
|
|
291
|
-
`download-cta.component.ts`) — härterer Grund als dort: `cds-button` kennt zwar
|
|
292
|
-
`.btn-on-band` (`variant="filled-on-band"`, geprüft über `npx storybook tools docs
|
|
293
|
-
show --id komponenten-buttons-button`, Story „Auf Bereichs-Band“), rendert aber
|
|
294
|
-
IMMER ein `<button>` und kann die geforderte `primaryHref`-gesetzt-→-`<a>`-
|
|
295
|
-
Verzweigung strukturell nicht erfüllen. **(4)** Bewusst nur EINE Aktion, kein
|
|
296
|
-
`secondaryLabel`. Ein erster Entwurf bot eine zweite Aktion an, ungeprüft gegen das
|
|
297
|
-
Mockup — die Korrektur kam aus zwei Gegenproben: keines der 22 Vorkommen zeigt eine
|
|
298
|
-
zweite Aktion, und `.btn-{area}.btn-on-band{color:…}`
|
|
299
|
-
(css/components.css:47–51) überschreibt die Textfarbe JEDER Variante auf denselben
|
|
300
|
-
Ton, den die Doku als Bandhintergrund nennt — nur `.btn-filled` tauscht zusätzlich
|
|
301
|
-
die Füllung gegen Weiß, jede andere Variante wäre Text in Bandfarbe auf Bandfarbe.
|
|
302
|
-
Eine zweite Aktion hätte also zwangsläufig dieselbe Optik wie die erste getragen,
|
|
303
|
-
keine Hierarchie. Diese CSS-Lücke ist jetzt
|
|
304
|
-
`.scratch/angular-seitenbausteine/issues/16-css-luecke-zweite-aktion-auf-band.md`;
|
|
305
|
-
die Komponente trägt bis zu ihrer Klärung nur eine Aktion, ohne eigenes
|
|
306
|
-
Flex-Layout dafür (das hätte eine Darstellung erfunden, die die CSS-Schicht unter
|
|
307
|
-
diesem Namen nicht kennt — `display:flex;gap:var(--s3);flex-wrap:wrap` existiert
|
|
308
|
-
bereits identisch als `.ep-hero-ctas`, css/components.css:1222, für einen anderen
|
|
309
|
-
Bauteiltyp). Eine einzelne Aktion zentriert sich stattdessen über das ererbte
|
|
310
|
-
`.ep-cta-band{text-align:center}` von selbst, genau wie in allen 22
|
|
311
|
-
Mockup-Vorkommen. Kein `aria-label`-Input: anders als bei `cds-feature` (11 von 12
|
|
312
|
-
mit `aria-label`) trägt keines der 22 Band-Vorkommen einen `aria-label` auf seiner
|
|
313
|
-
Aktion, ausgezählt statt geschätzt. Die Aktion folgt demselben Muster wie bei
|
|
314
|
-
`cds-feature`: gesetztes Href → echter `<a href>`, sonst `<button>` mit feuerndem
|
|
315
|
-
Output, nie ein `<a>` ohne Ziel. Neue Bauteil-Ebene
|
|
316
|
-
`Komponenten/Call to Action/CTA-Band` (Stories `Interaktiv`, `Pro Bereich`, `Als
|
|
317
|
-
Links`), `storySort.order` der Sektion „Call to Action“ entsprechend ergänzt.
|
|
318
|
-
**Nebenbefunde (CSS-/Gate-Kern, nicht in diesem Ticket behoben, jetzt eigene
|
|
319
|
-
Tickets 15–17):** `.ep-cta-sub` (`opacity:.85`) unterschreitet auf `--co-700` den
|
|
320
|
-
AA-Textkontrast (4,46:1 statt 4,5:1, WCAG-Formel gegen die Token-Werte gerechnet;
|
|
321
|
-
axe meldet dasselbe in den Storybook-Interaktionstests) — auf
|
|
322
|
-
`--ki-800`/`--es-700`/`--wo-700` liegt derselbe Text bei 6,1–7,4:1, „co“ ist der
|
|
323
|
-
systematische Ausreißer, wie schon beim bekannten `.cta-dl-eyebrow`-Befund in
|
|
324
|
-
`download-cta.stories.ts` (Ticket 15). Identisches rohes HTML (docs/index.html:6304
|
|
325
|
-
ff.) hat denselben Fehler, kein Wrapper-Artefakt. Die betroffenen Stories setzen
|
|
326
|
-
lokal `a11y: { test: 'todo' }` (dieselbe Ausnahme, die `preview.ts` für bekannte
|
|
327
|
-
CSS-Kern-Befunde vorsieht). Zusätzlich: `check:contrast`
|
|
328
|
-
(`scripts/check-contrast.mjs`) übersieht diesen Fall, weil es `opacity` nur als
|
|
329
|
-
Ein/Aus-Schalter behandelt (Zeile 181) und nicht in die Farbmischung mit dem
|
|
330
|
-
Hintergrund einrechnet — ein blinder Fleck des Gates (Ticket 17), kein Beleg dafür,
|
|
331
|
-
dass der Befund neu wäre.
|
|
332
|
-
- **`TierComponent` (`cds-tier`) und `FactsComponent` (`cds-facts`), achtes Ticket der
|
|
333
|
-
Seitenbausteine-Serie: die Angebots-Bausteine (`cds-award-list` zurückgestellt,
|
|
334
|
-
siehe unten).** `cds-tier` bildet `.ep-tier` ab (css/components.css:1381–1384):
|
|
335
|
-
Label + Haarlinie, die eine Offene Feature-Liste in Pakete gliedert (z. B. „In
|
|
336
|
-
jedem Paket enthalten“ vor „Zusätzlich mit Pro“). Element-Selektor, der
|
|
337
|
-
ADR-0008-Standardfall — ausgezählt: keines der 4 `.ep-tier`-Vorkommen in
|
|
338
|
-
`docs/index.html` sitzt in einem Grid/Flex, das seine Kinder streckt, keines
|
|
339
|
-
trägt eine `col-*`-Klasse, das Tag variiert nicht. `area` ist auf `'ki'` typisiert,
|
|
340
|
-
nicht auf die vollen vier Markenbereiche: `css/components.css` kennt
|
|
341
|
-
ausschließlich `.ep-tier-label[data-area="ki"]` (Dark-Override
|
|
342
|
-
`css/dark-mode.css:476`), für `co`/`es`/`wo` existiert keine einzige Regel —
|
|
343
|
-
ausgezählt: 3 von 4 `.ep-tier-label`-Vorkommen setzen `ki`, eines gar kein
|
|
344
|
-
`data-area`, keines einen anderen Bereich. Ein `CdsArea`-Input hätte für drei von
|
|
345
|
-
vier gültigen Werten ein wirkungsloses `data-area`-Attribut geschrieben; der
|
|
346
|
-
eingeschränkte Typ macht das strukturell unmöglich, statt es nur im JSDoc zu
|
|
347
|
-
behaupten. `.ep-tier-rule` ist rein dekorativ und trägt `aria-hidden="true"`. Neue
|
|
348
|
-
Bauteil-Ebene `Komponenten/Cards & Teaser/Tier-Trenner` (Stories `Interaktiv`,
|
|
349
|
-
`Pro Bereich`), `storySort.order` der Sektion „Cards & Teaser“ entsprechend ergänzt.
|
|
350
|
-
`cds-facts` bildet `.ep-facts` ab (css/components.css:1261–1272): die
|
|
351
|
-
Definitionsliste für Angebots-Eckdaten (Termin, Dauer, Ort, Preis), einspaltig mit
|
|
352
|
-
Haarlinie zwischen den Paaren oder als `.is-grid` zweispaltig für Kästen neben
|
|
353
|
-
Inhalt. Ebenfalls Element-Selektor: analog zu `cds-faq` trägt die INNERE `<dl
|
|
354
|
-
class="ep-facts">` die CSS-Klasse, nicht der Host — die Semantik einer
|
|
355
|
-
Definitionsliste hängt am `<dl>`-Tag selbst, ein Custom-Element kann es nicht
|
|
356
|
-
annehmen; da `.ep-facts > div + div` nur Nachfahren der eigenen Vorlage anspricht,
|
|
357
|
-
bricht die zusätzliche Host-Ebene nichts (kein „Fläche am Host“-Fall wie bei
|
|
358
|
-
`cds-section`). Jedes Fakten-Paar rendert deshalb exakt als `<div><dt>…</dt>
|
|
359
|
-
<dd>…</dd></div>`, weil genau dieser Selektor den Trenner ab dem zweiten Paar
|
|
360
|
-
setzt. Über die Ticket-Skizze hinaus ergänzt: ein `area`-Input, der `.t-{area}`
|
|
361
|
-
auf jedes `<dt>` anwendet — der CSS-Kommentar zu dieser Klasse
|
|
362
|
-
(css/components.css:1259) nennt `.t-XX` ausdrücklich als sanktionierten Weg für
|
|
363
|
-
den Bereichston der Labels, und alle 3 realen `.ep-facts`-Vorkommen in
|
|
364
|
-
`docs/index.html` setzen ihn einheitlich (`.t-wo`) auf jedem `<dt>` derselben
|
|
365
|
-
Liste; ohne den Input hätte sich keines originalgetreu nachbauen lassen. Neue
|
|
366
|
-
Bauteil-Ebene `Seitenmuster/Seminar · Training/Fakten-Liste` (Stories
|
|
367
|
-
`Interaktiv`, `Als Raster`), `storySort.order` entsprechend ergänzt — die Sektion
|
|
368
|
-
„Seminar · Training“ wechselt dabei von einer flachen Doku-Seite zu einer Sektion
|
|
369
|
-
mit Bauteil-Ebene, `Übersicht` bleibt per `CONTRIBUTING.md` §12 das erste Kind.
|
|
370
|
-
**`cds-award-list` zurückgestellt:** `.ep-award-list` (css/components.css:
|
|
371
|
-
1242–1245) kommt in `docs/index.html` außerhalb der Beispielseiten nicht vor — die
|
|
372
|
-
einzige Erwähnung außerhalb ist eine Zeile der Responsive-Verhaltenstabelle
|
|
373
|
-
(`docs/index.html:1963`), kein eigener Doku-Abschnitt mit Verwendung und
|
|
374
|
-
Code-Beispiel nach `CONTRIBUTING.md` §10.4. Statt einen neuen Produktions-Doku-
|
|
375
|
-
Abschnitt ungeprüft anzulegen, ist das Bauteil aus diesem Ticket herausgelöst;
|
|
376
|
-
Entscheidung und nächster Schritt stehen in
|
|
377
|
-
`.scratch/angular-seitenbausteine/issues/18-doku-luecke-ep-award-list.md`.
|
|
378
|
-
- **Interaktions- und Tastaturtests für die bisher ungeprüften Komponenten.** Der Button, die drei
|
|
379
|
-
Theme-Umschalter, die Footer-Aktion der Card, der Aktionsknopf der Snackbar und der Kopier-Button
|
|
380
|
-
des CodeBlocks hatten keinen einzigen Interaktionstest, obwohl Stories laut
|
|
381
|
-
[ADR-0005](docs/adr/0005-testebene-der-angular-lib.md) die einzige Testebene der Lib sind.
|
|
382
|
-
Ebenso ungeprüft waren die Tastaturpfade von AreaTabs, Carousel und Select sowie der
|
|
383
|
-
deaktivierte Zustand aller sieben Formularkomponenten. 110 Tests statt 89.
|
|
384
|
-
- **`--font-mono` als dritte Schriftrolle des Systems.** Das System hatte Tokens für Grotesk
|
|
385
|
-
(`--font`) und Serife (`--font-display`), aber keines für die dicktengleiche Schrift — die stand
|
|
386
|
-
stattdessen zehnmal hart in `css/base.css` und `css/components.css` und weitere zehnmal in
|
|
387
|
-
Inline-Styles von `docs/index.html`. Der Wert bleibt unverändert `'Courier New',monospace`, es
|
|
388
|
-
ändert sich kein gerendertes Pixel; der Schritt ist rein strukturell. Sein Zweck: die Frage, ob
|
|
389
|
-
Courier New die richtige Bildschirmschrift für Code ist, fällt ab jetzt an einer Stelle statt an
|
|
390
|
-
zwanzig. Storybooks Doku- und Manager-Chrome (`fontCode` in `.storybook/theme.ts`) zeigt auf
|
|
391
|
-
denselben Stack, damit Doku-Site und Storybook denselben Code-Satz rendern.
|
|
392
|
-
- **`TableComponent` (`cds-table`), neuntes Ticket der Seitenbausteine-Serie.** Wrapper um
|
|
393
|
-
`.tbl`/`.tbl-wrap` (css/components.css:1462–1480): die Datentabelle mit horizontalem
|
|
394
|
-
Scroll-Container. Ausgezählt: außerhalb der Doku-Sektion `sec-table` selbst kommt
|
|
395
|
-
`.tbl-wrap` nur zweimal vor, beide auf Beitragsseiten (`docs/index.html:8622`, `15080`).
|
|
396
|
-
**Kein Daten-Input** —
|
|
397
|
-
eine `columns`/`rows`-API hätte Zellinhalte auf Strings festgelegt, die Beispielseiten setzen
|
|
398
|
-
darin Badges, Links und `data-num`; der Konsument projiziert `<thead>`/`<tbody>`/`<tfoot>`
|
|
399
|
-
unverändert per `<ng-content>`, die Komponente liefert nur `.tbl-wrap`, `.tbl`, `<caption>` und
|
|
400
|
-
`.tbl--striped`. Element-Selektor, ADR-0008-Standardfall wie `cds-facts`/`cds-faq`: ausgezählt,
|
|
401
|
-
keines der 5 `.tbl-wrap`-Vorkommen in `docs/index.html` (Zeilen 5061, 5116, 5236, 8622, 15080)
|
|
402
|
-
ist selbst ein direktes Grid-/Flex-Kind, keines variiert das Tag — `.tbl-wrap`/`.tbl` sitzen
|
|
403
|
-
deshalb im eigenen Template der Komponente, nicht am Host. Im laufenden Storybook geprüft: die
|
|
404
|
-
gerenderte Kette hat `<table class="tbl">` direkt unter `<div class="tbl-wrap">`, `<caption>`
|
|
405
|
-
als erstes Kind, danach ohne zusätzlichen Knoten die projizierten `<thead>`/`<tbody>`-Elemente —
|
|
406
|
-
`<ng-content>` fügt selbst kein DOM-Element ein. `caption` ist `input.required<string>()`,
|
|
407
|
-
abweichend von der ursprünglichen Ticket-Skizze (dort optional mit Default `''`): die eigene
|
|
408
|
-
Doku (`tabelle.mdx:137`) nennt `<caption>` „Pflicht, Screenreader lesen den Titel vor, bevor
|
|
409
|
-
die Zellen vorgelesen werden“, und alle 5 realen `.tbl`-Vorkommen in `docs/index.html` haben
|
|
410
|
-
eine — nach ADR-0007 §2 ist `caption` damit Inhalt, nicht Beiwerk. `.tbl-wrap` ist deshalb
|
|
411
|
-
immer per Tastatur erreichbar (`tabindex="0"`, eigener `:focus-visible`-Ring) UND immer
|
|
412
|
-
benannt (`role="region"` + `aria-label`, `scrollLabel` hat Vorrang, sonst `caption`, kann dank
|
|
413
|
-
Pflicht-`caption` nie leer werden). **`.tbl-sort` bleibt außen vor:** die Klasse liefert nur den
|
|
414
|
-
Button-Look, es gibt keine zugehörige Sortierlogik in `docs/main.js` — ein Wrapper, der sie
|
|
415
|
-
anböte, täuschte Funktion vor, die nicht existiert. Neuer Befund
|
|
416
|
-
`.scratch/angular-seitenbausteine/issues/19-fehlende-sortierlogik-tbl-sort.md`. Neue
|
|
417
|
-
Bauteil-Ebene `Komponenten/Tabelle/Tabelle` (Stories `Interaktiv`, `Gestreift`,
|
|
418
|
-
`Mit Zahlenspalte`, `Mit Fußzeile`, `Schmaler Viewport`), `storySort.order` und
|
|
419
|
-
`SECTION_ICON_KEYS` entsprechend ergänzt — die Sektion „Tabelle“ wechselt dabei von einer
|
|
420
|
-
flachen Doku-Seite zu einer Sektion mit Bauteil-Ebene, `Übersicht` bleibt per
|
|
421
|
-
`CONTRIBUTING.md` §12 das erste Kind. `storybook-angular/src/docs/komponenten/tabelle.mdx`
|
|
422
|
-
entsprechend nachgezogen (die veraltete Aussage „kein eigenes Angular-Bauteil“ galt nur noch
|
|
423
|
-
für die separat zu bauende Vergleichstabelle, `.ep-compare*`, Ticket 10).
|
|
424
|
-
- **`CompareComponent` (`cds-compare`), zehntes Ticket der Seitenbausteine-Serie.** Wrapper um
|
|
425
|
-
`.ep-compare*` (css/components.css:1275–1294): die aufklappbare Vergleichstabelle für den
|
|
426
|
-
zeilenweisen Direktvergleich mehrerer Pakete/Tarife hinter nativem `<details>`/`<summary>`.
|
|
427
|
-
**Mit Daten-Input, anders als `cds-table`:** ausgezählt sind alle 22 Datenzellen des einzigen
|
|
428
|
-
realen Vorkommens (`docs/index.html:11970–12038`, 11 Zeilen × 2 Spalten) entweder ein
|
|
429
|
-
Ja/Nein-Marker (18×) oder eine kurze Angabe (4×), nie ein Badge oder Link — `columns`/`rows`
|
|
430
|
-
statt `<ng-content>`, weil die Zell-Typisierung
|
|
431
|
-
(`boolean | string`) dem Konsumenten ohnehin keine zusätzliche Freiheit ließe. Ja/Nein-Zellen
|
|
432
|
-
tragen fest verdrahteten `.sr-only`-Text (`Enthalten`/`Nicht enthalten`, exakt aus dem Mockup
|
|
433
|
-
übernommen, nicht erfunden, Glyphen „✓“/„−“ U+2212), weil Farbe und Glyphe allein keine
|
|
434
|
-
Bedeutung tragen (WCAG 1.4.1). `caption` ist `input.required<string>()`, dieselbe Begründung
|
|
435
|
-
wie bei `cds-table`: die eigene Doku (`tabelle.mdx:91`) nennt `<caption class="sr-only">`
|
|
436
|
-
ausdrücklich als Teil des Bauteils. Anders als bei `cds-table` ist sie hier `.sr-only`, weil der
|
|
437
|
-
Klartext schon im `<summary>` steht. `rowsLabel` (erste Kopfzelle, „Funktion“ im Mockup) ist
|
|
438
|
-
dagegen Beiwerk mit Default `''`: ein leeres `<th scope="col">` bleibt eine gültige, in
|
|
439
|
-
Vergleichsmatrizen verbreitete Ecke, das Beispielwort steht deshalb in der Story statt in der
|
|
440
|
-
Klasse. Natives `<details>`/`<summary>` bleibt erhalten (Tastaturbedienung und Toggle kommen
|
|
441
|
-
vom Browser, das CSS hängt an `[open]`), `<details class="ep-compare">` sitzt deshalb im
|
|
442
|
-
Template, nicht am Host — ein `<cds-compare>`-Host ist ein unbekanntes Custom Element und kann
|
|
443
|
-
echte `<details>`-Semantik nicht annehmen (derselbe Grund wie bei `cds-table`s `.tbl-wrap`).
|
|
444
|
-
Element-Selektor, ADR-0008-Standardfall: `.ep-compare` ist im einzigen realen Vorkommen ein
|
|
445
|
-
gewöhnlicher Block-Nachfahre in `.ep-section`, kein Grid-/Flex-Kind, kein Tag-Wechsel. `open`
|
|
446
|
-
ist reiner Anfangszustand über `[attr.open]="open() ? '' : null"`, keine Zwei-Wege-Bindung —
|
|
447
|
-
Angular schreibt das Attribut nur bei einer Werteänderung des geprüften Ausdrucks, ein
|
|
448
|
-
nachfolgender nativer Toggle bleibt deshalb unangetastet (in der Story „Interaktiv“ per
|
|
449
|
-
Play-Funktion geprüft, nicht nur angenommen). `toggled` feuert bei jedem Auf-/Zuklappen mit dem
|
|
450
|
-
neuen Zustand. Neue Bauteil-Ebene `Komponenten/Tabelle/Vergleichstabelle` (Stories `Interaktiv`,
|
|
451
|
-
`Bereits offen`, `Mit Text-Zellen`, `Hervorgehobene Spalte`), `storySort.order` der Sektion
|
|
452
|
-
„Tabelle“ entsprechend ergänzt (`['Übersicht', 'Tabelle', 'Vergleichstabelle']`),
|
|
453
|
-
`storybook-angular/src/docs/komponenten/tabelle.mdx` nachgezogen. Befund zur Zeilenangabe im
|
|
454
|
-
Ticket: `.scratch/angular-seitenbausteine/issues/20-ticket-10-falsche-zeilenangabe-doku-vorlage.md`.
|
|
455
|
-
- **`ArticleHeaderComponent` (`cds-article-header`), `AvatarComponent` (`div[cdsAvatar]`) und
|
|
456
|
-
`AvatarStackComponent` (`cds-avatar-stack`), elftes Ticket der Seitenbausteine-Serie.** Wrapper
|
|
457
|
-
um `.article-header`/`-breadcrumb*`/`-title`/`-lead`/`-meta*` (css/components.css:1486–1519) und
|
|
458
|
-
`.article-avatar*` (css/components.css:1520–1545): der zentrierte Kopf eines Wissensbeitrags samt
|
|
459
|
-
Avatar-Stapel für mehrere Autor:innen. Hauptvorlage war
|
|
460
|
-
`storybook-angular/src/docs/seitenmuster/wissensbeitrag.mdx` (Abschnitt „Article Header“), nicht
|
|
461
|
-
nur das Mockup. **Avatar bekommt einen Attributselektor** (`div[cdsAvatar]`, ADR-0008): ausgezählt
|
|
462
|
-
sitzen 8 der 11 Grundgrößen-Instanzen in `docs/index.html` als direkte Geschwister in einer von
|
|
463
|
-
3 `.article-avatar-stack`-Kacheln (Zeilen 8343–8344, 8373–8375, 8404–8406), wo der
|
|
464
|
-
CSS-Geschwister-Selektor
|
|
465
|
-
`.article-avatar-stack .article-avatar + .article-avatar` (css/components.css:1540) einen echten,
|
|
466
|
-
gemeinsamen Elternknoten braucht — ein Element-Selektor, der `.article-avatar` auf ein inneres
|
|
467
|
-
Element legt (wie `cds-facts` es mit `<dl>` tut), würde die Kette brechen. Gemessen per
|
|
468
|
-
`getBoundingClientRect()` in der Story „Avatar-Stapel“ (28 statt 40 px Abstand der linken Kanten
|
|
469
|
-
bei 40-px-Kacheln und `margin-left:-12px`) UND per Screenshot-Baseline
|
|
470
|
-
(`visual-snapshots/…avatar-stapel.png`, Kreise überlappen sichtbar mit weißem Halo-Rand) — nicht
|
|
471
|
-
nur an Computed Styles (ADR-0008, Fall 2). Zweiter, unabhängiger Grund für den Attributselektor:
|
|
472
|
-
`cds-article-header` projiziert den Avatar über `<ng-content select="[cdsAvatar], cds-avatar-stack">`,
|
|
473
|
-
dasselbe Attribut dient also zugleich als Host-Selektor UND als Projektions-Marker. `cds-pill`
|
|
474
|
-
bleibt dagegen eine echte Komponente (kein direkt komponiertes `<span class="pill">`): geprüft per
|
|
475
|
-
`docs show --id komponenten-chips-badges-pills-pill`, `PillComponent`s `.pill` sitzt zwar eine
|
|
476
|
-
Ebene unter seinem Host, `.article-header`/`.pill` haben aber (anders als `FeaturedCardComponent`s
|
|
477
|
-
`.card-featured-body>.pill`) keinen Kindselektor, der das verhindern würde — per Screenshot
|
|
478
|
-
bestätigt (`visual-snapshots/…interaktiv.png`). Neuer Input `pillAriaLabel` (wie bei
|
|
479
|
-
`FeaturedCardComponent`), weil `PillComponent`s eigener Default („Bereich `<label>`“) für die
|
|
480
|
-
Lesezeit-Pille des Wissensbeitrags nicht passt (`wissensbeitrag.mdx`: `aria-label="Lesezeit 8
|
|
481
|
-
Minuten"`) und aus einem freien `pill`-String nicht zuverlässig herleitbar ist. **Die Pille
|
|
482
|
-
rendert nur, wenn `area` UND `pill` gesetzt sind** — ausgezählt trägt jedes der 9 realen
|
|
483
|
-
`.pill`-Vorkommen im Article-Header-Kontext ein `data-area`, ein Fall ohne Bereich kommt im
|
|
484
|
-
Mockup nicht vor; statt einen Default zu erfinden (etwa `PillComponent`s eigenen, per
|
|
485
|
-
`strictTemplates`-Typüberbrückung durchgereichten), narrowt `@if (area(); as pillArea)`
|
|
486
|
-
`CdsArea | undefined` sauber auf `CdsArea`, ohne Typ-Cast, und ohne `area` bleibt die Pille
|
|
487
|
-
schlicht weg (Story „Pille ohne Bereich“). **Initialen werden
|
|
488
|
-
aus `name` abgeleitet** (`computed()`, erstes Zeichen von erstem und letztem Wort), kein eigener
|
|
489
|
-
Input. **`date`/`dateLabel` bleiben getrennt, anders als `cds-stoerer`**: `cds-stoerer` formatiert
|
|
490
|
-
ein ISO-Datum selbst nach `de-DE` (inkl. Umgehung des UTC-Mitternacht-Fallstricks bei
|
|
491
|
-
`new Date(iso)`); diese Komponente konstruiert dagegen nie ein `Date`-Objekt aus `date()` —
|
|
492
|
-
`dateLabel` liefert die sichtbare Schreibweise, ohne `dateLabel` steht `date` unverändert als
|
|
493
|
-
ISO-Text sichtbar (in der Story „Interaktiv“ als Warnfall demonstriert), der Zeitzonen-Fallstrick
|
|
494
|
-
kann so gar nicht erst auftreten. `aria-hidden="true"` ist an beiden Avatar-Komponenten fest
|
|
495
|
-
verdrahtet (kein Input): ausgezählt tragen 45 von 53 `.article-avatar`-Instanzen es direkt, die
|
|
496
|
-
restlichen 8 sitzen in einem bereits `aria-hidden`-tragenden Stapel (redundant, aber unschädlich).
|
|
497
|
-
Breadcrumb: letzter Eintrag rendert immer ohne Link mit `aria-current="page"`
|
|
498
|
-
(Akzeptanzkriterium), unabhängig von den beiden unvollständigen Wissensbeitrag-Inline-Beispielen,
|
|
499
|
-
die dafür keine Vorlage sind (siehe Befund unten). Meta-Strip rendert nur, wenn `authorName`
|
|
500
|
-
und/oder `date` etwas liefern (eine Stellenanzeige nutzt `.article-header` komplett ohne
|
|
501
|
-
`.article-meta`, das Ticket sieht dafür keine API vor). Neue Bauteil-Ebenen
|
|
502
|
-
`Seitenmuster/Wissensbeitrag/Article-Header` (Stories `Interaktiv`, `Ohne Breadcrumb`, `Mehrere
|
|
503
|
-
Autor:innen`) und `Seitenmuster/Wissensbeitrag/Avatar` (Stories `Avatar-Größen`,
|
|
504
|
-
`Avatar ohne Bild`, `Avatar mit Bild`, `Avatar-Stapel`), `storySort.order` der Sektion
|
|
505
|
-
„Wissensbeitrag“ entsprechend ergänzt (`['Übersicht', 'Article-Header', 'Avatar', 'FAQ']`),
|
|
506
|
-
Doku-Seite bleibt erstes Kind. Befunde:
|
|
507
|
-
`.scratch/angular-seitenbausteine/issues/20-breadcrumb-in-oder-vor-article-header.md`
|
|
508
|
-
(`docs/index.html:2423`, wörtlich: „Den Breadcrumb nicht in einen zentrierten `.article-header`
|
|
509
|
-
einbetten…“ — beide echten Beispielseiten folgen dem, 6 isolierte Doku-Demos inkl.
|
|
510
|
-
`wissensbeitrag.mdx` widersprechen dem ausdrücklich — die Komponente folgt der Ticket-Vorlage) und
|
|
511
|
-
`.scratch/angular-seitenbausteine/issues/21-pill-default-area-dokumentation-vs-code.md`
|
|
512
|
-
(`PillComponent.area` dokumentiert einen Corporate-Default, der Code liefert `'ki'`).
|
|
513
|
-
- **`ArticleTocComponent` (`cds-article-toc`), `ArticleCalloutComponent` (`cds-article-callout`),
|
|
514
|
-
`ArticleFigureComponent` (`cds-article-figure`) und `ArticlePullquoteComponent`
|
|
515
|
-
(`cds-article-pullquote`), zwölftes Ticket der Seitenbausteine-Serie („Artikel-Körper“).**
|
|
516
|
-
Wrapper um `.article-toc*` (css/components.css:1577–1589), `.article-callout*`
|
|
517
|
-
(css/components.css:1591–1600), `.article-figure`/`.article-figcaption`
|
|
518
|
-
(css/components.css:1573–1575) und `.article-pullquote` (css/components.css:1608–1612): die
|
|
519
|
-
vier Bausteine im Lauftext eines Wissensbeitrags. `.article-body` selbst bekommt bewusst
|
|
520
|
-
**keine** Komponente — reiner Typografie-Kontext, dessen Kindselektor (`.article-body > p`)
|
|
521
|
-
eine Zwischenebene stören würde; der Konsument schreibt weiterhin `<div class="article-body">`
|
|
522
|
-
selbst (neue Story „Im Artikel-Body“ in `Seitenmuster/Wissensbeitrag/Inhaltsverzeichnis`, zeigt
|
|
523
|
-
alle vier Bausteine im rohen Kontext). Alle vier bleiben Element-Selektoren
|
|
524
|
-
(ADR-0008-Standardfall): ausgezählt sitzt keines der insgesamt 12 realen Vorkommen als
|
|
525
|
-
Grid-/Flex-Kind, keines trägt eine `col-*`-Klasse, keines steht in einem
|
|
526
|
-
Geschwister-Kombinator, kein Tag variiert (immer `<details>`/`<aside>`/`<figure>`/
|
|
527
|
-
`<blockquote>`) — je eigens geprüft, nicht pauschal übernommen. **`cds-article-toc` ist das
|
|
528
|
-
zweite Vorkommen des `<details>`-mit-drehendem-Caret-Musters neben `cds-compare` (Ticket 10),
|
|
529
|
-
bewusst NICHT zusammengezogen (ADR-0007 §5):** natives `<details>`/`<summary>`, `aria-label`
|
|
530
|
-
am `<summary>` fest verdrahtet (wortgleich in beiden realen Vorkommen), kein `toggled`-Output
|
|
531
|
-
(anders als `cds-compare`, weil die Ticket-API keinen vorsieht). **`cds-article-callout`
|
|
532
|
-
projiziert Absätze als direkte Kinder** (`.article-callout > p`, Ticket-Vorgabe): `<ng-content>`
|
|
533
|
-
fügt kein eigenes Element ein, geprüft per `:scope > p` in der Story „Interaktiv“. Dabei ein
|
|
534
|
-
bekannter, vorbestehender CSS-Befund entdeckt und NICHT im Wrapper geflickt (ADR-0001):
|
|
535
|
-
`.article-callout-eyebrow` (Spezifität 0,1,0) verliert gegen `.article-callout > p`
|
|
536
|
-
(Spezifität 0,1,1) bei Schriftgröße, -gewicht und Randabstand, in jedem Bereich, weil die
|
|
537
|
-
Eyebrow selbst ein `<p>` UND ein direktes Kind ist — gemessen in rohem Markup ohne Angular
|
|
538
|
-
(Playwright/Chromium), siehe
|
|
539
|
-
`.scratch/angular-seitenbausteine/issues/22-css-luecke-callout-eyebrow-spezifitaet.md`.
|
|
540
|
-
Zusätzlich trägt `<aside>` jetzt `aria-labelledby` auf die Eyebrow, sobald eine gesetzt ist
|
|
541
|
-
(ARIA-Zusatz, keine CSS-Änderung): mehrere `.article-callout` auf derselben Seite wären sonst
|
|
542
|
-
gleichnamige, ununterscheidbare `complementary`-Landmarks (axe `landmark-unique`, gemessen auch
|
|
543
|
-
in rohem Markup ohne Angular, siehe
|
|
544
|
-
`.scratch/angular-seitenbausteine/issues/23-doku-luecke-callout-landmark-label.md`).
|
|
545
|
-
**`cds-article-pullquote` grenzt sich wechselseitig von `cds-blockquote` ab** (Ticket-Vorgabe):
|
|
546
|
-
Pull-Quote zitiert den eigenen Lauftext ohne Attribution, Box oder Icon, Blockquote zitiert eine
|
|
547
|
-
benannte dritte Person mit getönter Box und Quote-Icon — beide Klassendocs verweisen
|
|
548
|
-
aufeinander. `quote` enthält die deutschen Anführungszeichen bereits als Teil des Texts
|
|
549
|
-
(`quotes:none`, keine CSS-generierten Marken in der gesamten Zitat-Familie), die Komponente
|
|
550
|
-
ergänzt keine eigenen. `area` (Callout und Pull-Quote) hat den verteidigbaren Default `'co'`:
|
|
551
|
-
die Basisregel ohne `[data-area]` rendert bereits identisch zu `[data-area="co"]`. `loading="lazy"`
|
|
552
|
-
ist an `cds-article-figure` fest verdrahtet (2 von 3 realen Vorkommen, der dritte ist ein
|
|
553
|
-
captionsloses Lead-Bild außerhalb von `.article-body` mit `eager`/`fetchpriority`, für das die
|
|
554
|
-
Ticket-API kein Input vorsieht). Neue Bauteil-Ebenen `Seitenmuster/Wissensbeitrag/
|
|
555
|
-
Inhaltsverzeichnis` (Stories `Interaktiv`, `Bereits offen`, `Im Artikel-Body`), `…/Callout`
|
|
556
|
-
(`Interaktiv`, `Pro Bereich`, `Ohne Eyebrow`), `…/Figure` (`Interaktiv`, `Ohne Caption`) und
|
|
557
|
-
`…/Pull-Quote` (`Interaktiv`, `Pro Bereich`), `storySort.order` der Sektion „Wissensbeitrag“
|
|
558
|
-
entsprechend ergänzt (`['Übersicht', 'Article-Header', 'Avatar', 'Inhaltsverzeichnis',
|
|
559
|
-
'Callout', 'Figure', 'Pull-Quote', 'FAQ']`), Doku-Seite bleibt erstes Kind.
|
|
560
|
-
- **`AuthorCardComponent` (`div[cdsAuthorCard]`) und `AuthorCardGroupComponent`
|
|
561
|
-
(`cds-author-card-group`), dreizehntes und letztes Ticket der Seitenbausteine-Serie.**
|
|
562
|
-
Wrapper um `.author-card*` (css/components.css:1602–1606) und `.author-card-group*`
|
|
563
|
-
(css/components.css:1547–1563): der Avatar-plus-Bio-Strip am Ende eines
|
|
564
|
-
Wissensbeitrags, einzeln oder als gestapelte/`is-grid`-Gruppe. **`cds-author-card`
|
|
565
|
-
bekommt einen Attributselektor** (ADR-0008), gemessen statt nur hergeleitet: eine
|
|
566
|
-
Spike-Story hat den Element-Selektor- und den Attributselektor-Aufbau nebeneinander
|
|
567
|
-
im `.is-grid`-Fall gebaut und mit `getBoundingClientRect()` verglichen — Element-
|
|
568
|
-
Selektor liefert `.author-card`-Höhen von 84/204 px bei ungleich langen Bios (der
|
|
569
|
-
unsichtbare Host wird auf 204 px gestreckt, die sichtbare Box eine Ebene darunter
|
|
570
|
-
bleibt bei ihrer Inhaltshöhe), Attributselektor liefert 204/204 px. **Ehrlicher
|
|
571
|
-
Unterschied zu `cds-icon-card`:** die Baseline-Screenshots beider Spike-Varianten
|
|
572
|
-
waren byte-identisch (sha1 gleich) — `.author-card` hat anders als `.ep-card` weder
|
|
573
|
-
Hintergrund noch Rahmen noch Schatten, der Fehler ist heute rein strukturell
|
|
574
|
-
(falsches Boxmodell), nicht optisch sichtbar, wird aber real, sobald die Karte
|
|
575
|
-
künftig Rahmen/Hintergrund/Hover bekommt, und verfälscht schon heute jede Messung
|
|
576
|
-
auf die tatsächliche Kartenhöhe. `cds-author-card-group` bleibt Element-Selektor
|
|
577
|
-
(ADR-0008-Standardfall für die Gruppe selbst), setzt `.author-card-group` aber auf
|
|
578
|
-
ein INNERES `<div>` statt auf den Host: `.author-card-group-eyebrow:has(+
|
|
579
|
-
.author-card-group.is-grid)` (css/components.css:1563) verlangt, dass die
|
|
580
|
-
Gruppen-Eyebrow ein unmittelbares Geschwister von `.author-card-group` bleibt, was
|
|
581
|
-
mit der Klasse auf dem Host (Eyebrow müsste dann als Kind darin stehen und würde im
|
|
582
|
-
Raster zur eigenen Grid-Zelle) nicht ginge. **`area` ist bewusst KEIN Input von
|
|
583
|
-
`cds-author-card`** — ausgezählt tragen alle 17 realen `.author-card`-Vorkommen
|
|
584
|
-
`data-area`, und sowohl `docs/index.html:8185` als auch `wissensbeitrag.mdx:199`
|
|
585
|
-
behaupten wörtlich, das färbe „nur den Avatar“; tatsächlich hat `css/components.css`
|
|
586
|
-
(Light UND Dark) keine einzige `.author-card[data-area]`-Regel, die Bereichsfarbe
|
|
587
|
-
kommt ausschließlich vom `area`-Input des projizierten `[cdsAvatar]` (Ticket 11) —
|
|
588
|
-
ein Input, der hier nur ein wirkungsloses Attribut setzt, wäre eine erfundene
|
|
589
|
-
Konfiguration ohne Gegenwert (Befund, nicht im Wrapper geflickt:
|
|
590
|
-
`.scratch/angular-seitenbausteine/issues/24-css-luecke-author-card-data-area.md`).
|
|
591
|
-
**`roleLabel`, nicht `role` wie im Ticket-Text** (gemessene Abweichung): ein erster
|
|
592
|
-
Entwurf mit `role`-Input ließ axe bei jeder Story mit echtem Rollentext auf
|
|
593
|
-
`aria-roles` fehlschlagen, weil ein ungebundenes `role="…"`-Attribut zusätzlich als
|
|
594
|
-
natives ARIA-`role` im DOM stehen bleibt — dieselbe Kollision, die
|
|
595
|
-
`BlockquoteComponent`/`TestimonialComponent`/`TeamVoiceComponent` bereits mit
|
|
596
|
-
`roleLabel` umgehen; diese Komponente folgt demselben, etablierten Muster. Avatar
|
|
597
|
-
projiziert über `[cdsAvatar]`, wie bei `cds-article-header`: Größe/Bereich setzt der
|
|
598
|
-
Konsument direkt am Avatar. Eyebrow rendert als `<h3>`, nur wenn gesetzt — sowohl
|
|
599
|
-
an der Einzelkarte (`.author-card-eyebrow`) als auch an der Gruppe
|
|
600
|
-
(`.author-card-group-eyebrow`), deckungsgleich mit den realen, vollständigen
|
|
601
|
-
Mockup-Seiten (die isolierte `<p>`-Variante einer Doku-Illustration ohne eigene
|
|
602
|
-
`<h2>`-Hierarchie bleibt außen vor). Neue Bauteil-Ebene
|
|
603
|
-
`Seitenmuster/Wissensbeitrag/Author-Card` (Stories `Interaktiv`, `Zwei Autor:innen`,
|
|
604
|
-
`Als Raster`, `Ohne Bio` — „Als Raster“ mit bewusst ungleich langen Bios, pinnt
|
|
605
|
-
gleiche Kartenhöhen per `getBoundingClientRect()`), `storySort.order` der Sektion
|
|
606
|
-
„Wissensbeitrag“ entsprechend ergänzt (`['Übersicht', 'Article-Header', 'Avatar',
|
|
607
|
-
'Inhaltsverzeichnis', 'Callout', 'Figure', 'Pull-Quote', 'FAQ', 'Author-Card']`),
|
|
608
|
-
Doku-Seite bleibt erstes Kind.
|
|
609
|
-
|
|
610
|
-
### Changed
|
|
611
|
-
- **`npm run test` und `npm run playwright:install` laufen auch unter Windows.** Beide Skripte
|
|
612
|
-
setzten `PLAYWRIGHT_BROWSERS_PATH=0` in Unix-Syntax, an der `cmd.exe` scheiterte; sie gehen
|
|
613
|
-
jetzt über `cross-env` (neue devDependency in `storybook-angular`).
|
|
614
|
-
- **`storybook-angular/vitest.config.ts` und `visual-baseline-guard.ts` heißen jetzt `.mts`.** Vite
|
|
615
|
-
warnte, beide nutzten ESM-Syntax, würden aber als CommonJS geladen, und ein Import ohne
|
|
616
|
-
Dateiendung vertrage sich nicht mit dem nativen Config-Loader, den Vite künftig zum Default
|
|
617
|
-
machen will. `"type": "module"` für den ganzen Workspace kam nicht infrage, weil
|
|
618
|
-
`eslint.config.js` dort CommonJS ist. Den Import mit `.mts`-Endung akzeptiert TypeScript nur mit
|
|
619
|
-
`allowImportingTsExtensions`; die beiden Dateien bekommen dafür eine eigene
|
|
620
|
-
`tsconfig.node.json`, auf die `tsconfig.json` per `references` verweist, damit Editoren sie
|
|
621
|
-
ohne Fehlermeldung prüfen.
|
|
622
|
-
- **Storybook-Workspace führt `@angular/animations` und `@angular/platform-browser-dynamic`
|
|
623
|
-
nicht mehr als eigene Abhängigkeiten.** Beide sind seit Angular 22 als veraltet markiert, und
|
|
624
|
-
weder die Stories noch das Framework importieren sie. `@angular/animations` bleibt im Baum,
|
|
625
|
-
weil `@storybook/angular-vite` es als Pflicht-Peer verlangt; npm installiert es darüber mit.
|
|
626
|
-
Betrifft nur das interne Storybook, nicht die ausgelieferten Pakete.
|
|
627
|
-
- **Visual-Regression von Storybook-Test-Runner (Jest) nach Vitest verschoben, eine Testschiene
|
|
628
|
-
statt zwei.** `npm run test:vitest` deckte bereits Smoke-Rendering, `play`-Funktionen und die
|
|
629
|
-
a11y-Prüfung ab; der zweite Lauf über `@storybook/test-runner` (`test-storybook:ci`) fuhr
|
|
630
|
-
dieselben 110 Tests redundant noch einmal und trug nur die Visual-Regression bei
|
|
631
|
-
(`jest-image-snapshot` in `.storybook/test-runner.ts`). Diese Logik steckt jetzt in einem
|
|
632
|
-
`afterEach`-Hook in `.storybook/vitest.setup.ts` (`expect(document.body).toMatchScreenshot(...)`,
|
|
633
|
-
nur mit `VISUAL=1`, Baselines weiterhin unter `visual-snapshots/<story-id>.png`,
|
|
634
|
-
`parameters.snapshot.skip` als Opt-out). `test-storybook`, `test-storybook:ci`,
|
|
635
|
-
`test-storybook:visual` sowie die Root-Skripte `test:storybook`, `test:storybook:ci`,
|
|
636
|
-
`test:visual` und die Pakete `@storybook/test-runner`, `jest-image-snapshot`,
|
|
637
|
-
`@types/jest-image-snapshot`, `http-server`, `wait-on`, `concurrently` sind entfernt. Grund: der
|
|
638
|
-
ESM-Loader-Hook, den Jest beim Laden von `test-runner.ts` registriert, bricht unter Angular 22 in
|
|
639
|
-
allen Stories ab (unter Angular 21 nur eine Deprecation-Warnung) — Vitest ist der von Angular
|
|
640
|
-
vorgesehene Testrunner, die zweite Schiene abzulösen entfernt den Blocker, statt ihn zu reparieren.
|
|
641
|
-
`.github/workflows/visual.yml` (kein `http-server`/`wait-on` mehr, Vitest startet seinen Server
|
|
642
|
-
selbst) und `.github/workflows/storybook-angular.yml` (Schritt „Storybook-Tests“ läuft jetzt über
|
|
643
|
-
`test:vitest`) sind entsprechend angepasst. Details und die Arbeitsteilung, die damit endet, in
|
|
644
|
-
[ADR-0005](docs/adr/0005-testebene-der-angular-lib.md).
|
|
645
|
-
- **Storybook auf 10.6.0, Docgen-Server statt Compodoc.** Alle Storybook-Familienpakete
|
|
646
|
-
in `storybook-angular/` sind auf `^10.6.0`, `@storybook/test-runner` auf `^0.24.5`.
|
|
647
|
-
Der seit 10.6 in `@storybook/angular-vite` default gesetzte In-Process-Docgen-Server
|
|
648
|
-
liest Inputs, Outputs und JSDoc direkt aus der TypeScript-Quelle der Angular-Lib und
|
|
649
|
-
speist damit Controls, Docs-Seiten und das Komponenten-Manifest (siehe nächster
|
|
650
|
-
Punkt). Die nie produktiv genutzte Compodoc-Pipeline ist entfernt (`compodoc`/
|
|
651
|
-
`compodocArgs` raus aus `main.ts` und den `angular.json`-Builder-Optionen). Details
|
|
652
|
-
und verworfene Alternativen in
|
|
653
|
-
[ADR-0006](docs/adr/0006-storybook-10-6-docgen-server-mcp-und-theming.md).
|
|
654
|
-
- **`@storybook/addon-mcp` aktiv: Komponenten-Manifest und CI-Gate dafür.**
|
|
655
|
-
`npm run build-storybook` schreibt jetzt `storybook-static/manifests/components.json`
|
|
656
|
-
(`meta.docgen: "angular-component-meta"`), der Dev-Server beantwortet unter `/mcp`
|
|
657
|
-
JSON-RPC für Agenten (u. a. `stories-preview`, `docs-show`, `test-run`). Die CI prüft
|
|
658
|
-
nach dem Build, dass dieses Manifest existiert und die erwartete Kennung trägt — ein
|
|
659
|
-
künftiges Update kann das Manifest damit nicht mehr stillschweigend abschalten.
|
|
660
|
-
- **JSDoc `@internal` in der Angular-Lib gegen Interna in Props-Tabellen und Manifest.**
|
|
661
|
-
Der Docgen-Server dokumentiert grundsätzlich jedes öffentliche Member einer
|
|
662
|
-
Komponentenklasse; ohne Filter erschienen Template-Getter,
|
|
663
|
-
ControlValueAccessor-Methoden und Event-Handler in Docs-Props-Tabelle und Manifest.
|
|
664
|
-
Alle Nicht-API-Member der Lib tragen jetzt `@internal` und bleiben damit aus beiden
|
|
665
|
-
heraus — Agenten sehen über den MCP-Endpunkt dieselbe bereinigte API wie
|
|
666
|
-
Entwickler:innen im Docs-Panel.
|
|
667
|
-
- **Storybook-Manager und Docs-Chrome im Conciso-Look.** Sidebar, Toolbar und
|
|
668
|
-
Docs-Seiten tragen jetzt Montserrat, die Conciso-Wortmarke und Corporate-Teal als
|
|
669
|
-
Akzent (`.storybook/theme.ts`, `manager.ts`, `manager-head.html`). Der Manager folgt
|
|
670
|
-
`prefers-color-scheme`, die Docs-Chrome bleibt fest im Light-Theme — beide sind
|
|
671
|
-
bewusst vom Toolbar-Theme-Schalter der Preview entkoppelt, der weiterhin nur die
|
|
672
|
-
Story-Vorschau steuert.
|
|
673
|
-
- **Alle Komponenten laufen mit `OnPush` und leiten Werte über `computed()` ab.** Abgeleitete
|
|
674
|
-
Werte steckten bisher in Gettern, die bei jedem Change-Detection-Lauf neu rechneten; das
|
|
675
|
-
explizite `standalone: true` war seit Angular 19 Rauschen. Template-Handler und interne
|
|
676
|
-
Zustandssignale sind jetzt `protected`, Legacy-Decorators sind den heutigen APIs gewichen. Die
|
|
677
|
-
Regeln dahinter stehen in [ADR-0007](docs/adr/0007-api-konventionen-der-angular-komponenten.md).
|
|
678
|
-
Für Konsumenten ändert sich am Verhalten nichts.
|
|
679
|
-
- **Barrierefreiheits- und Verhaltenskorrekturen.** Die Dots des LogoCarousel waren als Tab-Leiste
|
|
680
|
-
ausgezeichnet, ohne auf Pfeiltasten zu reagieren. Die Topnav gab beim Schließen per Escape den
|
|
681
|
-
Fokus nicht an den öffnenden Knopf zurück, obwohl das CSS das Menü ausblendet — der Fokus fiel
|
|
682
|
-
ins Nichts. Die Combobox öffnete nicht auf Pfeil nach oben, kannte kein Pos1 und Ende und ließ im
|
|
683
|
-
Mehrfachmodus losen Filtertext stehen. Der DownloadCta hatte überhaupt keinen Output, ein Klick
|
|
684
|
-
auf seine Hauptaktion verpuffte.
|
|
685
|
-
- **Doku-Darstellung in Sidebar und Doku-Seiten aufgeräumt, vier kleine Korrekturen.** Das
|
|
686
|
-
Inhaltsverzeichnis der Doku-Seiten (`docs.toc` in `preview.ts`) erfasste per Default nur
|
|
687
|
-
`h3`, die 34 MDX-Seiten gliedern aber mit `##` (h2) — ganze Seiten ohne h3 hatten dadurch
|
|
688
|
-
gar kein Inhaltsverzeichnis; jetzt `h2, h3`. Der Autodocs-Eintrag jeder Komponente hieß
|
|
689
|
-
„Docs“, die einzige englische Zeile in einer durchgehend deutschen Navigation — jetzt
|
|
690
|
-
„Übersicht“ (`docs.defaultName` in `main.ts`), das Wort, das die eigenständigen MDX-Seiten
|
|
691
|
-
schon tragen. „Beispielseiten“ stand als einziges Wurzel-Blatt ohne Ordner ganz oben in der
|
|
692
|
-
Sidebar vor „Marke“, weil Storybook Blätter vor Ordnern sortiert — jetzt ein Ordner mit dem
|
|
693
|
-
Kind „Übersicht“ (`beispielseiten.mdx`), analog zu „Referenzen/Quellen“. Und die drei am
|
|
694
|
-
wenigsten befüllten Wurzeln (Seitenmuster, Beispielseiten, Referenzen) starten zugeklappt
|
|
695
|
-
(`collapsedRoots` in `manager.tsx`) — 149 der 181 Sidebar-Einträge hängen unter
|
|
696
|
-
„Komponenten“, das bleibt wie Marke und Grundlagen offen.
|
|
697
|
-
- **Doku-Seiten von Storybook an die Typografie der Doku-Site angeglichen.** Die Doku-Chrome
|
|
698
|
-
brachte ihre eigene Emotion-Typografie mit: Überschriften in Montserrat 700 (32/24/20 px),
|
|
699
|
-
Fließtext 14 px — also weder die Display-Schrift der Marke noch die eigene Body-Größe. Maßstab
|
|
700
|
-
ist jetzt `docs/index.html`, die gebaute Referenz, die ihr Aussehen aus denselben CSS-Dateien
|
|
701
|
-
zieht: h1 wie `.sec-title` (Libre Baskerville 400, 2rem/2.5rem), h2 wie `.group-title`
|
|
702
|
-
(1.5rem/2rem plus Haarlinie, 40 px darüber, 24 px Polster, 16 px darunter), ab h3 bewusst
|
|
703
|
-
Grotesk (`--ty-title-sm`), Fließtext und Tabellenzellen 16 px mit `line-height:1.7` wie am
|
|
704
|
-
`body` in `base.css`, Tabellenköpfe und die kräftige Kopf-Trennlinie wie `.doc-table`
|
|
705
|
-
(`preview-head.html`). Feste Größen statt der fluiden `--ty-display-*`/`--ty-headline-*`-Tokens:
|
|
706
|
-
die sind für Seiten gedacht, deren Breite mit dem Viewport wächst, eine Doku-Spalte ist
|
|
707
|
-
breitenbegrenzt. Die Haarlinie über h2 ist dabei der eigentliche Abstandsgeber — die Doku-Site
|
|
708
|
-
gliedert nicht mit Luft allein. Die Regeln sparen `.docs-story` und `.sbdocs-preview` aus: dort
|
|
709
|
-
stehen gerenderte Komponenten, deren Darstellung ausschließlich aus der CSS-Schicht kommen darf.
|
|
710
|
-
Storybooks eigene Sektionsüberschrift „Stories“ bleibt ebenfalls unangetastet.
|
|
711
|
-
- **`<Unstyled>` schaltet die Doku-Typografie jetzt tatsächlich ab.** Die Typografie-Regeln der
|
|
712
|
-
Doku-Seiten sparten bisher nur die Story-Vorschauen aus. Rohes Demo-Markup, das MDX-Seiten
|
|
713
|
-
direkt einbetten, fiel weiter darunter: gemessen rendert ein
|
|
714
|
-
`<h1 class="hero-image-caption-title">` als Doku-Überschrift (Libre Baskerville 32 px, dunkel)
|
|
715
|
-
statt als Bauteil (`--ty-serif-md`, weiß, `line-height:1.25`) — die Doku-Regel gewinnt mit
|
|
716
|
-
Spezifität (0,3,1) gegen die Bauteil-Klasse mit (0,1,0). Storybooks eigener Block `<Unstyled>`
|
|
717
|
-
half nicht, weil er nur `<div class="sb-unstyled">` rendert und kein CSS mitbringt. Alle sieben
|
|
718
|
-
Regeln sparen `.sb-unstyled` jetzt aus — dieselbe Konvention, die Storybooks eigenes Stylesheet
|
|
719
|
-
dafür benutzt. Damit können Doku-Seiten echte Live-Beispiele einbetten, die aussehen wie auf
|
|
720
|
-
der Site, statt sie in Code-Blöcken zu beschreiben.
|
|
721
|
-
- **Theme-Umschalter wirkt jetzt auch auf Doku-Seiten ohne eingebettete Story.**
|
|
722
|
-
`themeStore.setSilent()` stand ausschließlich im Story-Decorator, der pro Story-Render läuft.
|
|
723
|
-
Auf den 34 eigenständigen MDX-Seiten (Icons, Hero, Tabelle, Buchungsformular, alle
|
|
724
|
-
Seitenmuster, alle „Verwendung“-Seiten) rendert keine Story — dort schrieb niemand
|
|
725
|
-
`data-theme` ans `<html>` des Preview-Frames, gemessen blieb es `null`, der Umschalter war
|
|
726
|
-
wirkungslos. Ein Listener auf Modulebene hört jetzt zusätzlich auf `setGlobals` (Erst-Load)
|
|
727
|
-
und `globalsUpdated` (jede Änderung) und setzt den Store direkt; beide Ereignisnamen und ihre
|
|
728
|
-
Nutzlast wurden gegen den installierten Dist geprüft. `setSilent` benachrichtigt keine
|
|
729
|
-
Abonnenten, deshalb entsteht keine Rückkopplung mit der Gegenrichtung Store→Toolbar — je
|
|
730
|
-
Umschaltvorgang gezählt: genau ein `updateGlobals`, ein `globalsUpdated`. Der Decorator bleibt
|
|
731
|
-
daneben stehen. Damit rendern Live-Beispiele auf Doku-Seiten im Dark Mode korrekt; die
|
|
732
|
-
Doku-Chrome selbst bleibt weiterhin hell (bekannter Follow-up aus ADR-0006).
|
|
733
|
-
- **Seitenleiste entrümpelt.** Storybooks Typ-Icons und das rote „A“-Badge sind weg: das Badge
|
|
734
|
-
hängte an einem Tag, das 158 von 181 Einträgen tragen, und markierte damit nichts. Die Zeilen
|
|
735
|
-
stehen auf 32 px statt 28, zwischen den Wurzelgruppen liegt Luft, und Ordner wie Blätter
|
|
736
|
-
derselben Ebene beginnen auf derselben Textkante — vorher standen Blätter 14 px weiter rechts,
|
|
737
|
-
was vom Icon verdeckt war und sie fälschlich als Kinder des Ordners darüber lesen ließ. Der
|
|
738
|
-
Aufklapp-Chevron bleibt erhalten: er sitzt im selben Wrapper wie das Typ-Icon, weshalb die
|
|
739
|
-
Regel das Icon selbst trifft und nicht den Wrapper. Mit dem Badge entfallen auch die
|
|
740
|
-
Umbenennung von `manager.ts` zu `.tsx` und die `jsx`-Option in der `tsconfig.json`, die es
|
|
741
|
-
allein nötig gemacht hatte. Wirkt erst nach einem Neustart — der Manager liest
|
|
742
|
-
`manager-head.html` und `manager.ts` nur beim Prozessstart.
|
|
743
|
-
- **Icons-Seite zeigt jetzt Icons.** Die Seite erklärte Icons auf 105 Zeilen, ohne ein einziges zu
|
|
744
|
-
zeigen. Alle 74 Glyphen aus `icons/icons.json` rendern jetzt live, getrennt nach den fünf
|
|
745
|
-
Bereichs-Glyphen in ihrer Bereichsfarbe und den 69 bereichsneutralen UI-Icons, jeweils mit dem
|
|
746
|
-
Schlüssel, den ein Entwickler importiert. Dabei fielen drei Aussagen der Seite als falsch auf
|
|
747
|
-
und wurden korrigiert: die Registry hält je Schlüssel genau eine Variante, nicht fünf Größen;
|
|
748
|
-
die Größe wird über `width`/`height` oder CSS gesetzt, nicht durch Wahl einer Variante; und die
|
|
749
|
-
Farbe ist nicht eingebrannt, sondern kommt über `currentColor` vom Consumer. Die fünf
|
|
750
|
-
handoptimierten Größenvarianten existieren nur als Inline-SVG in `docs/index.html`, nicht im
|
|
751
|
-
veröffentlichten Paket.
|
|
752
|
-
- Git LFS für `docs/assets/images/` + History-Bereinigung (entfernt die ~159 MB
|
|
753
|
-
Bilder aus dem Git-Verlauf). Erfordert `git lfs` (noch nicht installiert) und
|
|
754
|
-
`git lfs migrate` bzw. `git filter-repo` — schreibt die History um (Force-Push,
|
|
755
|
-
Team-Koordination), daher bewusst als separater Schritt.
|
|
756
|
-
- Optionales schlankes `behaviors.js` (Theme/Nav/Back-to-Top) fürs Paket.
|
|
757
|
-
|
|
758
|
-
### Fixed
|
|
759
|
-
- **Listen in `CarouselComponent`, `FaqComponent`, `FooterBottomComponent` und
|
|
760
|
-
`TopnavComponent` brechen bei doppelten Beschriftungen nicht mehr ab.** Die `@for`-Schleifen
|
|
761
|
-
trackten per Titel, Frage bzw. Label, obwohl die Inputs keine Eindeutigkeit verlangen. Zwei
|
|
762
|
-
gleich beschriftete Einträge lösten Angulars NG0955 aus und stoppten das Rendern. Carousel,
|
|
763
|
-
Footer und Topnav tracken jetzt per `$index` (ihr Zustand hängt ohnehin am Index), das FAQ
|
|
764
|
-
per Eintragsobjekt, damit der native `open`-Zustand eines `<details>` beim Umsortieren an
|
|
765
|
-
seiner Frage bleibt. Je Komponente pinnt eine Story mit doppelten Beschriftungen das ab.
|
|
766
|
-
|
|
767
|
-
## [1.0.0] - 2026-08-21
|
|
768
|
-
|
|
769
|
-
### Fixed
|
|
770
|
-
- **Das Card-Layout stand im `style`-Attribut, nicht in der Klasse.** `.card-body` dokumentiert
|
|
771
|
-
`.card-cta-link--pinned`, und dessen `margin-top:auto` funktioniert ausschließlich im
|
|
772
|
-
Flex-Container. Die Klasse war aber nur `padding:var(--s5)`. Ergebnis: in den Doku-Mockups stand
|
|
773
|
-
die Flex-Spalte 43-mal im `style`-Attribut des Bodys, 41-mal zusätzlich an `.card` selbst (ohne
|
|
774
|
-
Flex-Spalte an der Karte greift `flex:1` am Body ins Leere), dazu 41-mal `flex:1` und 39-mal ein
|
|
775
|
-
`margin-bottom:0` an der Pill. Wer das dokumentierte Rezept ohne diese Inline-Styles übernahm,
|
|
776
|
-
bekam ein anderes Layout als die Doku zeigt: keine Abstände zwischen den Body-Kindern und einen
|
|
777
|
-
CTA, der nicht an der Unterkante sitzt.
|
|
778
|
-
Jetzt tragen die Klassen das Layout: `.card` ist `display:flex;flex-direction:column`,
|
|
779
|
-
`.card-body` eine Flex-Spalte mit `gap:var(--s3)` und `flex:1`. Der `gap` ist damit der einzige
|
|
780
|
-
vertikale Rhythmus der Karte, und die Kinder geben ihre Außenmargen ab (`.card-eyebrow`,
|
|
781
|
-
`.card-cta-link`; `.card-body > .pill` nimmt die Eigenmarge der Pill zurück wie im
|
|
782
|
-
Featured-Body). Das ist der Punkt: eine Außenmarge am Kind addiert sich im Flex-Layout zum
|
|
783
|
-
`gap`, statt zu kollabieren, und muss dann in jedem Kontext einzeln zurückgenommen werden.
|
|
784
|
-
`.card-featured` bleibt `display:block`, dort liegt der Body absolut.
|
|
785
|
-
**Sichtbar ändert sich zweierlei, im Browser nachgemessen.** In der Featured-Card rückt der CTA
|
|
786
|
-
von 24 px auf 16 px an die Zeile darüber und liegt damit im selben Rhythmus wie der übrige Body
|
|
787
|
-
(`gap:var(--s4)`); vorher kamen 8 px Marge dazu. Und in den sieben Anatomie-Demo-Karten, die
|
|
788
|
-
ihren Body nie inline geflext hatten, stehen Eyebrow, Titel und Text jetzt mit 12/12 px statt
|
|
789
|
-
8/0 px, die Karte wächst dadurch von 404 px auf 420 px. Alles andere bleibt gleich: die
|
|
790
|
-
Listing-Cards, deren Body vorher inline geflext war, rendern unverändert (12 px zwischen den
|
|
791
|
-
Kindern, gepinnte CTAs mit 20 px Padding-Luft an der Unterkante), das Bildverhältnis der
|
|
792
|
-
Featured-Card bleibt 1,778, kein horizontaler Overflow.
|
|
793
|
-
**Eine Ausnahme gehört zur Regel:** `.ep-feature-body` hat mit Absicht nur `gap:var(--s1)`, damit
|
|
794
|
-
Titel und Text als Einheit gelesen werden. Für den CTA ist das zu eng, deshalb trägt der
|
|
795
|
-
Container die Ausnahme (`.ep-feature-body > .card-cta-link{margin-top:var(--s2)}`) und die 13
|
|
796
|
-
Feature-CTAs stehen unverändert bei 12 px. Genau so gehört es: nicht das Kind bringt die Marge
|
|
797
|
-
überall mit, sondern der Container, der sie braucht, gibt sie seinem Kind.
|
|
798
|
-
In den Mockups sind alle 43 + 41 + 41 + 39 Inline-Deklarationen entfernt; geblieben sind vier
|
|
799
|
-
reine `gap`-Overrides (`--s4`, `--s6`), also Abstands-Entscheidungen, kein neu deklariertes
|
|
800
|
-
Layout.
|
|
801
|
-
`CONTRIBUTING.md` § 7 hält beide Regeln fest, an denen das hing: der Abstand gehört dem
|
|
802
|
-
Container, nicht dem Kind, und eine Klasse trägt das Layout, das ihr eigenes Rezept voraussetzt.
|
|
803
|
-
Prüfstein für künftige Bauteile: das Rezept aus der Doku muss allein mit seinen Klassen so
|
|
804
|
-
aussehen, wie die Doku es zeigt.
|
|
805
|
-
- **Die Pill wurde in Flex-Spalten zum Balken.** `.pill` ist `inline-block`, wird als Flex-Item
|
|
806
|
-
aber zu `block` blockifiziert, und ein Item mit auto-Cross-Size zieht `align-items:stretch` auf
|
|
807
|
-
die volle Spaltenbreite. Im `.card-featured-body` (Flex-Spalte, `gap:var(--s4)`) heißt das:
|
|
808
|
-
gemessen bei 1280 px Kartenbreite 448 px Pill-Breite statt 146 px, also exakt die Inhaltsbreite
|
|
809
|
-
des Bodys (40 % von 1280 px minus zweimal `--s8`). Dazu addierte sich die Eigenmarge der Pill
|
|
810
|
-
(`margin-bottom:var(--s5)`, gedacht für den normalen Fluss über einer Überschrift) zum `gap` des
|
|
811
|
-
Bodys, statt zu kollabieren: 36 px unter der Pill statt 16 px, wodurch sich der Meta-Block vom
|
|
812
|
-
Bereichs-Signal löste, mit dem er als Meta-Header zusammengehört.
|
|
813
|
-
Die Doku-Mockups zeigten den Fehler nicht, weil an jeder der 46 Pill-Instanzen
|
|
814
|
-
`style="width:fit-content;margin-bottom:0"` stand. Im Copy-Paste-Rezept der Featured-Card fehlte
|
|
815
|
-
dieser Override. Wer das Rezept übernahm, bekam den Balken.
|
|
816
|
-
Jetzt bringt `.pill` selbst `width:fit-content` mit (im normalen Fluss ein No-Op, ein
|
|
817
|
-
`inline-block` schrumpft dort ohnehin auf seinen Inhalt; deckt Flex und Grid in einem ab, weil
|
|
818
|
-
eine definierte Cross-Size `stretch` in beiden schlägt), und `.card-featured-body > .pill` nimmt
|
|
819
|
-
die Eigenmarge dort zurück, wo der Body den Abstand als `gap` selbst trägt. In den Mockups sind
|
|
820
|
-
alle 46 `width:fit-content` entfernt, die 7 Featured-Pills brauchen gar kein `style`-Attribut
|
|
821
|
-
mehr. Auch die 39 Pills in einem `.card-body` sind ihren Override los, seit `.card-body` seine
|
|
822
|
-
Flex-Spalte selbst trägt (siehe den Eintrag darüber). Doku: die Pill-Sektion, das
|
|
823
|
-
Featured-Rezept und die technischen Regeln der Veranstaltungs-Card nennen jetzt, was die Klasse
|
|
824
|
-
leistet und was im Markup nichts zu suchen hat.
|
|
825
|
-
- **Kartenraender waren im Light praktisch unsichtbar und untereinander uneinheitlich.** Die
|
|
826
|
-
generische `.card` trug `--bd` (n-100), Testimonial- und Stat-Karte `--bd-strong` (n-200) plus
|
|
827
|
-
einen 4-px-Bereichsakzent. Gemessen im Light: 1,18:1 gegen Weiss und 1,10:1 gegen eine
|
|
828
|
-
`n-50`-Sektion, gegenueber 1,53:1 bei den anderen. Alle Karten haben 1 px, der Unterschied kam
|
|
829
|
-
also aus Farbe und Akzent, nicht aus der Strichstaerke. Im Dark war beides nie ein Problem
|
|
830
|
-
(2,99:1 und 4,21:1). Zwei Ursachen: es gab keine Regel, wann welches Token gilt (§4 nannte
|
|
831
|
-
beide ohne Kriterium), und `.ep-card`, die Karte der Beispielseiten, nutzte laengst
|
|
832
|
-
`--bd-strong`, waehrend die dokumentierte `.card` bei `--bd` blieb.
|
|
833
|
-
Jetzt sind es **zwei Rollen statt zwei Staerken**: `--bd` ist die Trennlinie **innerhalb** eines
|
|
834
|
-
Bauteils (Card-Footer, Caption-Kante, Tabellenzeile), `--bd-strong` die **Aussenkante** einer
|
|
835
|
-
Flaeche. 18 Aussenkanten in `components.css`/`base.css` und 61 Demo-Kaesten in der Doku sind
|
|
836
|
-
umgestellt; Beispielcode blieb unberuehrt. Ausgenommen bleiben Bedienelemente: Formularfelder
|
|
837
|
-
und Buttons haben `--field-border` (4,13:1, WCAG 1.4.11), Pills und Chips ihren eigenen Rand,
|
|
838
|
-
deshalb behalten `.a11y-mode` und `.logo-carousel-pause` ihr `--bd`.
|
|
839
|
-
Dazu traegt `--bd-strong-c` im Light jetzt `n-300` statt `n-200`: **2,25:1** gegen Weiss und
|
|
840
|
-
**2,09:1** gegen eine `n-50`-Sektion. Der Dark-Wert bleibt unangetastet. Damit stimmt auch eine
|
|
841
|
-
Begruendung wieder, die das System schon fuehrte: §5 leitet den Sektions-Rhythmus daraus ab,
|
|
842
|
-
dass die weisse Karte auf weisser Sektion "ueber ihren Rand" liest, nannte im selben Satz aber
|
|
843
|
-
1,10:1 fuer Light. Die drei Kommentare in `dark-mode.css`, die 1,10:1 als ausreichend
|
|
844
|
-
bezeichneten, und der Wert in der Stoerer-Tabelle sind mitgezogen. Der 4-px-Bereichsakzent
|
|
845
|
-
bleibt Unterschied: die generische Karte zeigt ihren Bereich ueber die getoente Medienflaeche,
|
|
846
|
-
Testimonial und Stat-Karte haben keine, dort traegt die Oberkante die Bereichsfarbe.
|
|
847
|
-
|
|
848
|
-
- **Zwei tote Nav-Links in der Barrierefreiheits-Sektion.** „Tastaturnavigation“
|
|
849
|
-
(`#gt-a11y-keyboard`) und „Touch Targets“ (`#gt-a11y-touch`) standen in der Sub-Navigation,
|
|
850
|
-
ohne dass es die Ziele gab, während die Einleitung derselben Sektion beide Themen ankündigt.
|
|
851
|
-
Beide Blöcke sind jetzt geschrieben, siehe „Added“.
|
|
852
|
-
- **Fünf Überschriften waren über die Sidebar nicht erreichbar.** „Editoriale Kennzahl-Zeile“,
|
|
853
|
-
„Kontrastverhältnisse · Dark Mode“ und die beiden Verwendungs-Blöcke in Slider & Carousel
|
|
854
|
-
hatten keinen Nav-Eintrag. Weil diese Sektion zwei Bauteile dokumentiert, heißen ihre
|
|
855
|
-
Verwendungs-Blöcke jetzt „Bild-Carousel · Verwendung“ und „Kundenlogo-Karussell · Verwendung“,
|
|
856
|
-
nach dem schon beim Störer verwendeten Muster. `gt-colors-semantik` war dagegen kein
|
|
857
|
-
Gruppen-Titel, sondern das Label einer Spalte im Verwendungs-Block, angesprungen von einem
|
|
858
|
-
Querverweis; es heißt jetzt `colors-semantik`, damit `gt-` genau die Überschriften mit
|
|
859
|
-
Nav-Eintrag bezeichnet.
|
|
860
|
-
- **Übersprungene Heading-Ebene in der Token-Sektion (WCAG 1.3.1).** `sec-tokens` ging von
|
|
861
|
-
`h1.sec-title` direkt auf nackte `h3` und war deshalb die einzige Grundlagen-Sektion ohne
|
|
862
|
-
Sub-Navigation, zwei Symptome derselben Ursache. Die fünf Token-Blöcke tragen ihre Überschrift
|
|
863
|
-
jetzt als `h2.group-title` und erscheinen in der Sidebar; `.token-section h3` entfällt.
|
|
864
|
-
- **Fünf Anker trugen das Präfix einer fremden Sektion.** Reste früherer Umzüge:
|
|
865
|
-
`gt-nav-hero-image`, `gt-nav-hero-substrip` und `gt-carousel-hero` lagen in `sec-hero`,
|
|
866
|
-
`gt-logo-carousel*` in `sec-slider`. Alle sieben IDs der beiden Sektionen folgen jetzt ihrer
|
|
867
|
-
eigenen Sektion, samt der Querverweise im Fließtext.
|
|
868
|
-
- **Inhaltsverzeichnis von `docs/GETTING-STARTED.md` unvollständig.** Es listete 8 Kapitel bei 9
|
|
869
|
-
vorhandenen: „Einheiten & medienübergreifende Nutzung“ war als §7 eingeschoben worden, ohne das
|
|
870
|
-
Verzeichnis nachzuziehen, wodurch die letzten zwei Einträge auf `#7-icons-nutzen` und
|
|
871
|
-
`#8-frameworks` zeigten statt auf `#8-…` und `#9-…`. Alle 9 Anker lösen wieder auf.
|
|
872
|
-
- **`README.md` beschrieb eine Gliederung, die es nicht mehr gibt.** Statt „32 Sektionen:
|
|
873
|
-
Foundations (…)“ jetzt 35 Sektionen in den sechs aktuellen Gruppen.
|
|
874
|
-
- **Störer bei 200 % Textgröße: Maße von px auf rem (WCAG 1.4.4).** Die Container-Query-Schwelle
|
|
875
|
-
stand als `1025px` da und skalierte damit nicht mit der Browser-Standardschriftgröße. Bei
|
|
876
|
-
verdoppelter Wurzel-Schrift wuchs die Kachel von 126 auf 290 px, das Overlay blieb aber an und
|
|
877
|
-
ragte gemessen 96 px in die Sub-Sektion. Jetzt `64.0625rem`: bei 150 % und 200 % verlangt die
|
|
878
|
-
Schwelle mehr Hero-Breite als vorhanden, das Set fällt also in den Block-Zweig unter dem Hero,
|
|
879
|
-
statt zu überlappen. Ebenso Kachelbreite (`22.5rem`) und Grid-Minimum (`16.25rem`).
|
|
880
|
-
Nebenbefund, der **nicht** vom Störer kommt: bei 200 % läuft die Doku-Seite horizontal über
|
|
881
|
-
(1498 statt 1440 px). Mit und ohne Störer identisch gemessen, kein Element der Beispielseite ragt
|
|
882
|
-
über den Viewport; das ist die Doku-Shell (252-px-Sidebar plus Content).
|
|
883
|
-
- **Reflow bei 320 px strukturell abgesichert (WCAG 1.4.10).** Das Auto-Fit-Grid hatte einen
|
|
884
|
-
starren Boden von `16.25rem`; bei 320 px Viewport ist der Grund nur 256 px breit, die Spalte ragte
|
|
885
|
-
also 4 px in die Polsterung. Es entstand kein horizontaler Überlauf, weil das Padding es auffing —
|
|
886
|
-
das hielt aber nur zufällig. Jetzt `minmax(min(16.25rem,100%),1fr)`, die Spalte weicht auf 100 %
|
|
887
|
-
aus statt den Grund zu sprengen. Dazu mobil (≤ 768 px) derselbe Innenabstand wie `.ep-section`
|
|
888
|
-
(`--s6` statt `--s8`): im Block-Zweig steht das Set in der Sektionslogik der Seite und folgt deren
|
|
889
|
-
Rhythmus. Gemessen bei 320/360/400/768 px: kein Überlauf, ein bzw. zwei Spalten.
|
|
890
|
-
- **`.stoerer` in die `forced-colors`-Rahmenliste aufgenommen.** Im Windows-Kontrastmodus entfernt
|
|
891
|
-
das OS `box-shadow`; `base.css` stellt für `.card` und `.card-elevated` deshalb `2px solid
|
|
892
|
-
CanvasText` her. Der Störer fehlte in der Liste und behielt nur seinen 1-px-Rand — genau im
|
|
893
|
-
schwierigsten Fall, nämlich über einem Foto und ohne den `--e1`, auf den er sich sonst stützt.
|
|
894
|
-
Der Fokus-Ring war nicht betroffen, die globale `:focus-visible`-Regel ersetzt ihn dort schon
|
|
895
|
-
durch `outline: 3px solid Highlight` (in beiden Modi nachgemessen).
|
|
896
|
-
|
|
897
|
-
### Added
|
|
898
|
-
- **Die Brand-Logos werden jetzt ausgeliefert: `assets/brand/`.** Wer das Paket eingebunden hat,
|
|
899
|
-
bekam kein Logo. Die drei Wortmarken lagen unter `docs/assets/images/`, und `docs/` steht nicht in
|
|
900
|
-
`package.json` → `files`; einen `exports`-Eintrag für Assets gab es ebenfalls nicht. Dokumentiert
|
|
901
|
-
war das Logo dagegen vollständig (Doku-Sektion **Marke → Logo**), es fehlte allein der Weg zum
|
|
902
|
-
Developer. Zwei Nebenfolgen derselben Ablage: die Doku nannte in der Prosa den Pfad
|
|
903
|
-
`images/logo-conciso{,-light,-dark}.svg`, real war es `assets/images/…`, und Storybook mountete
|
|
904
|
-
für **9,7 KB** Logo den kompletten **164 MB** großen Demo-Bilderordner nach `/conciso/images`.
|
|
905
|
-
Die drei SVGs liegen jetzt unter `assets/brand/` und sind über `files` und
|
|
906
|
-
`exports["./assets/brand/*"]` Teil des Pakets, ansprechbar als
|
|
907
|
-
`@conciso/design-system/assets/brand/logo-conciso.svg`. Umgestellt sind 59 `src`-Attribute in
|
|
908
|
-
`docs/index.html` (Sektionen Logo, Navigation, Beispielseiten) auf `../assets/brand/`, die falsche
|
|
909
|
-
Prosa-Angabe, der Storybook-Mount (jetzt `assets/brand` → `/conciso/brand`, 164 MB auf 9,7 KB) samt
|
|
910
|
-
acht Story-Referenzen und das Vorschau-Skript, das die Root-Assets mitkopiert und `../assets/` wie
|
|
911
|
-
bisher `../css/` auf Geschwister-Ebene umschreibt. `assets/brand/README.md` beschreibt den Einbau,
|
|
912
|
-
verbindlich für Größen, Schutzraum und Verwendung bleibt die Doku-Sektion.
|
|
913
|
-
`logo-conciso.svg` trug noch XML-Prolog, `DOCTYPE` und drei ungenutzte Namespaces des Export-Tools,
|
|
914
|
-
die beiden anderen Varianten nicht. Sie sind entfernt, die Pfaddaten sind byte-identisch geblieben
|
|
915
|
-
(3609 auf 3355 Byte). Zwei der Dateien hatten fälschlich das Executable-Bit, jetzt `644`.
|
|
916
|
-
`width` und `height` bleiben an allen drei SVGs, anders als es CONTRIBUTING § 10 für
|
|
917
|
-
`icons/source/` vorschreibt: Icons werden inline eingebettet, Logos per `<img>`, und dort liefern
|
|
918
|
-
genau diese Attribute das intrinsische Seitenverhältnis und verhindern Layout-Shift. Die Begründung
|
|
919
|
-
steht in `assets/brand/README.md`, damit sie niemand gegen die Icon-Regel wegräumt.
|
|
920
|
-
Bewusst **nicht** Teil davon: ein Favicon- oder App-Icon-Set (die Wortmarke ist bei 7,6 zu 1 als
|
|
921
|
-
Favicon unbrauchbar, Quelle wäre `icons/source/co-mark.svg`), eine `currentColor`-Variante (der
|
|
922
|
-
CSS-Swap über `.logo-themed-default`/`-light` bleibt der Weg) und die Auslagerung der Demo-Fotos,
|
|
923
|
-
die weiter unter **Geplant** steht. Die Fremdmarken `logo-youtube-light.svg` und
|
|
924
|
-
`logo-linkedin-light.png` bleiben bei den Demo-Bildern, sie sind keine Conciso-Assets.
|
|
925
|
-
- **`.card-featured`: Featured-Card mit dem Bildverhältnis der Listing-Cards.** Die Featured-Card
|
|
926
|
-
hatte kein definiertes Bildverhältnis. Die Bildspalte war ein `<div>` mit `min-height` und einem
|
|
927
|
-
CSS-`background-image`, ihre Höhe ergab sich aus dem Text daneben. Gemessen bei 1440 px Viewport:
|
|
928
|
-
**1,62**, während `.card-media` im Listing-Grid **1,778** (16/9) liefert. Redaktion musste damit
|
|
929
|
-
pro Beitrag zwei Zuschnitte pflegen, einen fürs Featured und einen fürs Grid.
|
|
930
|
-
Die Bildspalte trägt jetzt `.card-media` und damit dasselbe `aspect-ratio`, der Bildausschnitt
|
|
931
|
-
sitzt als `object-position` am `<img>` statt als `background-position` am Container. Ein Bild in
|
|
932
|
-
einem Zuschnitt passt damit in beide Slots.
|
|
933
|
-
Damit das Verhältnis unabhängig von der Textlänge hält, bestimmt das **Bild** die Kartenhöhe:
|
|
934
|
-
`.card-featured-body` liegt absolut und trägt nichts zur Zeilenhöhe bei. Als normale Spalte zieht
|
|
935
|
-
seine Inhaltshöhe die Zeile auf und streckt das Bild mit. Ein `aspect-ratio` auf der Karte genügt
|
|
936
|
-
dafür nicht, es ist eine Wunschgröße und verliert gegen die Inhaltshöhe (gemessen 1,50).
|
|
937
|
-
Spaltenteilung 60/40 statt 50/50, weil ein 16/9-Bild auf halber Kartenbreite zu flach für den
|
|
938
|
-
Content-Block ist: bei 50 % schrumpfte der Lead auf null Zeilen.
|
|
939
|
-
- **Drei Stufen der Featured-Card, an der Kartenbreite statt am Viewport.** Alle Stufen hängen per
|
|
940
|
-
`@container` an der Karte (CONTRIBUTING § 7). Im Doku-Mockup ist die Karte bei 1180 px Viewport nur
|
|
941
|
-
814 px breit, bei 1024 px dagegen 958 px, weil die Doku-Sidebar unterschiedlich greift. Eine
|
|
942
|
-
Viewport-Regel träfe dort das Falsche.
|
|
943
|
-
Über **1000 px** Kartenbreite: Bild 60 %, Padding `s6 s8`, Lead drei Zeilen.
|
|
944
|
-
**900 bis 1000 px** (Tablet-Landscape): nebeneinander bleiben, aber verdichtet. Bild 65 %, Padding
|
|
945
|
-
`s4 s6`, Lead zwei Zeilen. Bei 16/9 heißt breiteres Bild auch höheres Bild, und diese Höhe
|
|
946
|
-
braucht der Content-Block. Vorher wurde hier gestapelt: das Bild wurde full width und 539 px hoch,
|
|
947
|
-
die Karte 807 px, auf einem 1024×768-iPad also höher als der Bildschirm. Jetzt 350 px.
|
|
948
|
-
Unter **900 px**: gestapelt wie die Grid-Cards, und das Lead-Kürzen wird zurückgenommen, weil
|
|
949
|
-
ohne feste Höhe kein Grund besteht, eine Zeile zu opfern. Tiefer nebeneinander zu bleiben lohnt
|
|
950
|
-
nicht, die Textspalte fiele unter 250 px, rund 30 Zeichen pro Zeile.
|
|
951
|
-
- **Kürzen statt Verhältnis brechen: der Vorrang steht fest.** `.card-text` bringt sein `line-clamp`
|
|
952
|
-
mit und gibt als schrumpfendes Flex-Item zuerst nach, bevor Pill, Meta-Strip, Titel oder CTA
|
|
953
|
-
wegfallen. Dazu kappt `.card-title-hero` **innerhalb** der Featured-Card auf drei Zeilen: ohne
|
|
954
|
-
diesen Riegel frisst ein langer Titel die Höhe, die der Lead braucht, und schiebt danach Pill und
|
|
955
|
-
CTA aus der Karte (gemessen mit einem 18-Wort-Titel). Global bleibt `.card-title-hero`
|
|
956
|
-
unbeschnitten. Rest-Fall, bewusst so gelassen: schöpft ein Titel den Riegel voll aus, wird die
|
|
957
|
-
letzte Lead-Zeile angeschnitten statt mit Auslassungspunkten zu enden. Dann muss etwas nachgeben,
|
|
958
|
-
und eine halbe Lead-Zeile ist der geringste Schaden; die Karte bleibt in jedem Fall geschlossen.
|
|
959
|
-
Ein kleinerer `gap` verschiebt den Fall nur (1,98 statt 1,76 Zeilen) und löst ihn nicht.
|
|
960
|
-
- **Tastaturnavigation und Touch Targets dokumentiert.** Beide Blöcke fehlten in einem System mit
|
|
961
|
-
AA-Ziel. Tastaturnavigation behandelt Fokusreihenfolge aus dem Markup (keine positiven
|
|
962
|
-
`tabindex`), Sprungziele mit `tabindex="-1"`, den Skip-Link, die Tastaturfalle, verdeckten Fokus
|
|
963
|
-
und ein gemeinsames Tastenset für neue Bauteile (2.1.1, 2.1.2, 2.4.3, 2.4.7, 2.4.11), dazu eine
|
|
964
|
-
Tabelle mit der tatsächlichen Belegung aller Bauteile aus `main.js`. Bei den Zielgrößen sind die
|
|
965
|
-
zwei Kriterien getrennt benannt, weil sie nicht dasselbe verlangen: 2.5.8 fordert auf AA 24 px,
|
|
966
|
-
2.5.5 auf AAA 44 px, und das System zielt auf 44 px. Die zwei Bauteile darunter (Segmented
|
|
967
|
-
Control, Area Tabs, je 40 px) stehen als bewusste Abweichung dabei, statt unerwähnt zu bleiben.
|
|
968
|
-
2.4.11 und 2.5.8 sind als Kriterien aus WCAG 2.2 gekennzeichnet, da die Sektion 2.1 nennt und es
|
|
969
|
-
dort auf AA keine Zielgrößen-Anforderung gibt.
|
|
970
|
-
- **Sub-Navigation für Design Tokens und Beispielseiten.** Beide Sektionen waren in der Sidebar
|
|
971
|
-
ohne Tiefe. Die Beispielseiten sind der größte Teil der Doku, ihre Gliederung lag allein in der
|
|
972
|
-
Tab-Leiste. Die sechs Gruppen stehen jetzt in der Sidebar und ein Eintrag **öffnet** die erste
|
|
973
|
-
Beispielseite seiner Gruppe: gemessen bei 1440 px liegen fünf der sechs Gruppen-Labels in
|
|
974
|
-
derselben Grid-Zeile von `.ep-tabs` und die Leiste ist 328 px hoch, ein reiner Anker führte also
|
|
975
|
-
fünfmal an dieselbe Stelle. Umgesetzt über das vorhandene `activateExamplePage`; der `href` zeigt
|
|
976
|
-
auf den ersten Tab der Gruppe und bleibt ohne JS ein gültiges Sprungziel.
|
|
977
|
-
- **`CONTRIBUTING.md` §11 „Doku-Struktur“.** Für die Gliederung der Doku-Site gab es keine
|
|
978
|
-
geschriebene Regel, nur einen Halbsatz in §10 Schritt 4, der drei Inhaltsblöcke nennt. Der neue
|
|
979
|
-
Abschnitt hält fest: die sechs Gruppen und was hineingehört, Nav-Eintrag als Pflicht, das
|
|
980
|
-
Anker-Schema `gt-<sektion>-<thema>` und wofür das Präfix reserviert ist, „Aufbau“ zuerst und
|
|
981
|
-
„Verwendung“ zuletzt samt der Form `<Bauteil> · Verwendung`, die Bereichsreihenfolge, Nav-Label
|
|
982
|
-
gleich Überschrift oder deren Anfang, ein Trennzeichen pro Aufgabe, die Sprachregel und die
|
|
983
|
-
Heading-Ebenen samt der einen dokumentierten Ausnahme. Dazu zwei Einzeiler zum Selbstprüfen und
|
|
984
|
-
eine Zeile in der PR-Checkliste.
|
|
985
|
-
|
|
986
|
-
### Changed
|
|
987
|
-
- **Alle sieben Featured-Cards auf `.card-featured` umgestellt.** Wissen-Übersicht (drei
|
|
988
|
-
bereichsspezifische Varianten), Veranstaltungs-Übersicht (drei) und das Featured auf der Landing.
|
|
989
|
-
Damit liegt Layout, Spaltenteilung und das Kürzen in der Klasse statt im `style`-Attribut, und
|
|
990
|
-
die alte `min-height`-Konstruktion mit `background-image` ist restlos aus dem Repo. Geprüft über
|
|
991
|
-
alle drei Beispielseiten bei zehn Kartenbreiten von 1200 bis 375 px, Light und Dark: 16/9 hält
|
|
992
|
-
durchgängig, Pill und CTA bleiben sichtbar, der Lead endet auf Zeilenkante.
|
|
993
|
-
- **Doku der Featured-Card beschrieb das Bild als 1:1 und die Geometrie als `min-height`-Spalte.**
|
|
994
|
-
Beides traf schon vor dieser Änderung nicht zu, gemessen waren es 1,62 und eine Spalte ohne
|
|
995
|
-
definiertes Verhältnis. Prosa, Vergleichstabelle und Code-Block sind auf 16:9, `.card-media` und
|
|
996
|
-
die drei Container-Stufen gezogen. In der Vergleichstabelle stand für den Lead außerdem noch
|
|
997
|
-
14 px, `.card-text` trägt Body-md mit 16 px.
|
|
998
|
-
- **Reihenfolge und Benennung der Doku-Navigation.** „Verwendung“ schließt eine Sektion ab, bei
|
|
999
|
-
Elevation und Tabelle stand danach noch ein Block. Icons listete die Bereiche als co/ki/wo/es,
|
|
1000
|
-
kanonisch und wie bei Buttons ist co/ki/es/wo. Der Eintrag Design Tokens sitzt jetzt hinter
|
|
1001
|
-
Elevation statt zwischen Icons und Barrierefreiheit, also hinter den vier Themen, deren Werte er
|
|
1002
|
-
festhält. Bei diesen Umzügen ist die Zeilenmenge der Datei unverändert, nur die Reihenfolge.
|
|
1003
|
-
Benennung: Gruppen- und Konzeptnamen deutsch (Foundations → Grundlagen, Components →
|
|
1004
|
-
Komponenten, Page-Patterns → Seitenmuster, Colors → Farben, Typography → Typografie, CSS Design
|
|
1005
|
-
Tokens → Design Tokens, WCAG 2.1 AA & Accessibility → Barrierefreiheit, Hero-Patterns → Hero),
|
|
1006
|
-
etablierte Bauteil- und Token-Namen unverändert. „Brand Areas“ bleibt: der Begriff steht 34 Mal
|
|
1007
|
-
in der Doku-Prosa und je zwei Mal in CONTRIBUTING und CHANGELOG, nur die Sektion umzubenennen
|
|
1008
|
-
hieße ein Ding, zwei Wörter. Nav-Label ist jetzt überall die Überschrift oder ihr Anfang
|
|
1009
|
-
(vorher wichen 10 von 165 ab, am weitesten „Verschachtelung“ für „Optional: Sub-Hierarchie per
|
|
1010
|
-
`.footer-subtitle`“, ohne ein gemeinsames Wort). Für „Name plus Zusatz“ gilt ein Trennzeichen:
|
|
1011
|
-
`·` bestimmt näher, `:` steht vor einem Satz, Klammern tragen einen kurzen Einschub.
|
|
1012
|
-
- **Domänenwort für Veranstaltungen systemweit vereinheitlicht.** Das Sektions-Label „Treffen“ auf
|
|
1013
|
-
der Startseite und der Topnav-Eintrag „Events“ heißen jetzt beide „Veranstaltungen“. Für dieselbe Domäne
|
|
1014
|
-
standen auf einer Seite drei Wörter: „Events“ (Topnav), „Treffen“ (Sektions-Label) und „Alle
|
|
1015
|
-
Veranstaltungen ansehen“ (Link am Sektionsende); dazu kommt die Übersichtsseite, die von
|
|
1016
|
-
Veranstaltungen spricht. Mit dem Störer verlinken zwei Elemente derselben Seite auf dasselbe Ziel,
|
|
1017
|
-
und dann sind zwei verschiedene Namen nicht mehr nur uneinheitlich: für Screenreader liest sich das
|
|
1018
|
-
wie zwei verschiedene Inhalte. „Veranstaltungen“ ist das Wort, das Übersichtsseite, Detailseite und
|
|
1019
|
-
der Link am Sektionsende schon tragen. Angeglichen sind 27 Topnav-Einträge über alle
|
|
1020
|
-
Beispielseiten, das Sektions-Label, die Karte und der CTA auf der Unternehmens-Übersicht, die
|
|
1021
|
-
Anmeldungs-Einwilligung, der Hero-Eyebrow „Fokusevent“ (jetzt „Fokusveranstaltung“) sowie die
|
|
1022
|
-
Doku-Prosa inklusive des Komponenten-Namens „Event-Card“ (jetzt „Veranstaltungs-Card“). Im Wort
|
|
1023
|
-
„Event“ verbleiben nur technische Bezeichner (`gt-event-*`, `sec-events`, `pointer-events`,
|
|
1024
|
-
`data-event-meta`, Bild-Dateinamen) und die internen Team-Aktivitäten auf der Arbeitgeber-Seite
|
|
1025
|
-
(„Teamevents“, „Kochevents“): das sind andere Dinge, und zwei Dinge dürfen zwei Wörter haben.
|
|
1026
|
-
Kontrolliert: 0 Textüberläufe in vier Breiten, das Wort ist mehr als doppelt so lang wie „Events“
|
|
1027
|
-
und passt in das 240 px breite Dropdown-Panel.
|
|
1028
|
-
CONTRIBUTING § 6 hält die Regel fest: ein Domänenwort pro Domäne über Nav, Sektions-Label und
|
|
1029
|
-
Verweis-Komponenten. Dazu die Notiz, dass die Eyebrow-Form (`--ty-label-xs` + uppercase +
|
|
1030
|
-
`--co-ink`) mit vier Rollen voll belegt ist und keine fünfte Bedeutung mehr tragen soll.
|
|
1031
|
-
- **Paletten-Beschriftung auf einen neutralen Streifen unter dem Farbfeld.** Sie saß auf der Farbe,
|
|
1032
|
-
und dort ist der Kontrast nicht garantierbar: bei **7 von 100** Stufen liegt die Leuchtdichte so
|
|
1033
|
-
in der Mitte, dass weder weiße noch dunkle Schrift 4,5:1 erreicht (auf `ki-700` schafft selbst
|
|
1034
|
-
reines Schwarz nur 4,82:1). Die Zwischenlösung war eine Plakette auf genau diesen sieben, was als
|
|
1035
|
-
Ungleichheit auffiel und wie ein Fehler las. Jetzt tragen alle Beschriftungen `--tx-secondary` auf
|
|
1036
|
-
`--bg-surface`: **6,28:1 in beiden Modi**, das Farbfeld bleibt unverdeckt, und die 100 inline
|
|
1037
|
-
gesetzten Label-Farben im Markup sind überflüssig geworden und entfernt. Der abzulesende Hexwert
|
|
1038
|
-
ist Information, nicht Dekoration, und hat jetzt einen Grund, auf dem er trägt.
|
|
1039
|
-
Layout dazu: die Rundung sitzt an den Farbfeldern statt an der Reihe (die Reihe klippte sonst den
|
|
1040
|
-
Streifen an den Außenkanten ab), der Streifen hat Luft nach oben statt am Farbfeld zu kleben, die
|
|
1041
|
-
Beschriftung bricht nicht mehr um (ein Umbruch bei „800 T“ schob das Farbfeld dieser Spalte nach
|
|
1042
|
-
oben und ergab eine Stufe in der Reihe), und das Farbfeld behält seine 60 px Höhe. Unter 1024 px
|
|
1043
|
-
entfällt der Hexwert, dort ist eine Spalte zu schmal; er bleibt im `title` und per Klick kopierbar.
|
|
1044
|
-
Und die Reihe ist jetzt eine Karte mit Haarlinie: ohne Rahmen verlor sie im Light ihre Kante, weil
|
|
1045
|
-
die hellen Stufen und der weiße Beschriftungs-Streifen beide fast die Farbe der Seite haben
|
|
1046
|
-
(`#E0F7F7` gegen Weiß sind 1,12:1). Dazu eine Linie zwischen Farbfeld und Beschriftung, aus
|
|
1047
|
-
demselben Grund. Im Dark trennte sich der Streifen schon vorher von der Seite, dort ist beides
|
|
1048
|
-
nur konsequent.
|
|
1049
|
-
- **Pill und Bereichs-Badge folgen im Light dem Kachel-Rezept.** Zarter `--XX-50`-Tint mit
|
|
1050
|
-
kräftiger dunkler Schrift (7,5 bis 12,3:1) statt kräftiger Füllung. Begründung wie bei den
|
|
1051
|
-
Kacheln: WCAG verlangt für diese Fläche nichts, die Aussage steht im Label, und darüber
|
|
1052
|
-
entscheidet das Markenrad. Auf dem zarten Grund wirkt die Schrift kräftiger, weil sie nicht mit
|
|
1053
|
-
der Fläche konkurriert. **Im Dark bleibt die gehobene Füllung**, weil sich dort das Verhältnis
|
|
1054
|
-
umdreht: helle Schrift auf dunklem Tint, und bei fast gleicher Helligkeit wie die Karte hält
|
|
1055
|
-
nichts mehr die Fläche zusammen (1,54 bis 1,55:1 zur Karte, 12,5 bis 12,7 L*). Gleiche Rolle,
|
|
1056
|
-
zwei Werte, wie bei `--XX-band`.
|
|
1057
|
-
Das Gate prüft die 1,3:1-und-10-L*-Regel damit nur noch für **Status**-Füllungen, bei denen die
|
|
1058
|
-
Farbfläche in dichten Kontexten der schnelle Hinweis ist, bevor das Label gelesen wird. Für
|
|
1059
|
-
Label- und Dekor-Flächen bleibt es beim Text, und der wird ohnehin geprüft.
|
|
1060
|
-
- **Dekorative Flächen dürfen ruhig bleiben: Icon-Kacheln zurück auf den zarten Tint.** Beim
|
|
1061
|
-
Anheben der Füllungen waren die 48-px-Kacheln mitgelaufen, obwohl für sie nichts davon gilt: WCAG
|
|
1062
|
-
verlangt für eine dekorative Fläche keinen Kontrast (kein Bedienelement, kein bedeutungstragendes
|
|
1063
|
-
Grafikobjekt, das Glyph ist `aria-hidden` und wiederholt das Eyebrow daneben), und großflächig
|
|
1064
|
-
gesättigte Farbe widerspricht dem Markenwert „Ruhig“. Kacheln und Timeline-Marker tragen jetzt
|
|
1065
|
-
wieder `--XX-50`, ohne Rand; die Erkennbarkeit trägt das Glyph mit 7,5 bis 11,4:1 im Light und
|
|
1066
|
-
6,9 bis 8,6:1 im Dark, also mehr als auf der kräftigen Füllung (dort 4,7 bis 7,5:1).
|
|
1067
|
-
Dazu die Rollen sauber getrennt, damit die Entscheidung am Token-Namen hängt: **`--XX-50`** ruhige
|
|
1068
|
-
dekorative Fläche (in beiden Modi dasselbe Versprechen; im Dark stehen dort wieder die ruhigen
|
|
1069
|
-
Werte) · **`--XX-fill`** textführendes Bauteil, muss lesen (im Dark eigene, gehobene Werte statt
|
|
1070
|
-
einer Referenz auf `-50`) · **`--XX-band`** Sektionsfläche · **`--XX-ink`** farbiger Text.
|
|
1071
|
-
Das Gate prüft die Hausregel entsprechend nur für textführende Füllungen; warum die Kacheln nicht
|
|
1072
|
-
drin sind, steht im Skript.
|
|
1073
|
-
CONTRIBUTING § 3 führt die Entscheidung jetzt zweistufig: WCAG ist Pflicht und gilt für den
|
|
1074
|
-
Inhalt, darüber hinaus entscheidet das Markenrad und nicht der Kontrastrechner.
|
|
1075
|
-
- **Getönte Füllungen im Dark um 4 L\*-Punkte gehoben, und das Gate prüft jetzt zwei Werte.** Die
|
|
1076
|
-
vier Bereichs-Füllungen erfüllten mit 1,33:1 den 1,3:1-Faustwert, hatten aber nur **8,3 L\***
|
|
1077
|
-
Helligkeitsabstand zur Karte: der Unterschied lag fast vollständig in Farbton und Sättigung, und
|
|
1078
|
-
eine satte Fläche auf gleicher Helligkeit liest als dunkler Fleck statt als hellere Stufe. Am
|
|
1079
|
-
deutlichsten bei ES, weil Blau bei gleichem L\* am dunkelsten wirkt; genau dort ist es aufgefallen
|
|
1080
|
-
(Pill der Veranstaltungskarte). Neu in Lab gerechnet, nur L angehoben, Farbton und Sättigung
|
|
1081
|
-
unverändert: `--co-50` `#1F5651`, `--ki-50` `#43531C`, `--wo-50` `#205828`, `--es-50` `#34469D`.
|
|
1082
|
-
Fläche jetzt 1,54 bis 1,55:1 zur Karte und 2,07 bis 2,09:1 zur Seite, ΔL\* 12,5 bis 12,7.
|
|
1083
|
-
Dasselbe für die Status-Füllungen, die das neue Kriterium mit aufdeckte (ΔL\* 8,2 bis 8,4):
|
|
1084
|
-
`--c-success-bg` `#1F573B`, `--c-warning-bg` `#5F4B1E`, `--c-error-bg` `#882725`,
|
|
1085
|
-
`--badge-neu-bg` `#404F5D`. Beim Fehlerton bewusst bei ΔL\* 11 gestoppt, weil der Text darauf
|
|
1086
|
-
sonst unter AA fällt (jetzt 4,74:1).
|
|
1087
|
-
**Das Gate prüft Füllungen ab jetzt gegen 1,3:1 UND 10 L\***, sonst wäre genau dieser Fall wieder
|
|
1088
|
-
durchgerutscht. Es hat dabei drei Folgefehler gefunden: Inline-Code (`.token`) trug im Dark
|
|
1089
|
-
`co-300` und fiel auf der helleren Füllung auf 4,48:1, ebenso die Grid-Spalten-Labels; beide
|
|
1090
|
-
laufen jetzt über `--co-ink`. Vier Code-Chips trugen zusätzlich eine semantische Inline-Farbe
|
|
1091
|
-
(`--c-error` und Verwandte) und lagen bei 4,46:1; die Farbe ist raus, den Zweck erklärt die Zeile
|
|
1092
|
-
daneben. Und ein CSS-Kommentar mit `a*/b*` hat beim Schreiben den Kommentar vorzeitig beendet und
|
|
1093
|
-
den halben Dark-Token-Block gekippt: 1.705 gemeldete Verstöße, in einem Lauf gefunden.
|
|
1094
|
-
- **Alle Kontrast-Verstöße der Doku behoben: 183 auf 0, in beiden Modi.** Ausgangsstand nach dem
|
|
1095
|
-
Bau des Gates: Light 49 Text / 101 Füllungen / 6 Rahmen, Dark 20 / 0 / 0. Neun Gruppen, jede mit
|
|
1096
|
-
einer Ursache:
|
|
1097
|
-
- **Farbiger Text ohne Theme-Wechsel (17 Stellen).** `co-600` als Textfarbe trug auf Weiß nur
|
|
1098
|
-
3,29:1. Dabei fiel auf, dass das System `--XX-ink` (Light `-700`/`-800`, Dark `-200`/`-100`)
|
|
1099
|
-
nur für KI hatte. Die Familie ist jetzt vollständig: **`--co-ink`, `--es-ink`, `--wo-ink`**.
|
|
1100
|
-
Ohne sie erzeugt jede Light-Korrektur einen Dark-Verstoß, was beim ersten Anlauf genau so
|
|
1101
|
-
passiert ist (16 neue Dark-Befunde durch ein fest gesetztes `co-700`).
|
|
1102
|
-
- **Getönte Füllungen (101).** 76 Icon-Kacheln, 13 Status- und neutrale Badges, 8 Timeline-Icons,
|
|
1103
|
-
4 Trend-Chips lagen zwischen 1,02 und 1,16:1 gegen ihren Grund. Kacheln und Timeline-Icons
|
|
1104
|
-
nutzen jetzt `--XX-fill`, die Status-Tints sind auf Flächenwirkung angehoben
|
|
1105
|
-
(`--c-success-bg` `#A9E5C8`, `--c-warning-bg` `#F5D08C`, `--c-error-bg` `#F5BFBF`, Fläche 1,43
|
|
1106
|
-
bis 1,60:1), der neutrale Badge auf `n-200`. Die Tint-Texte wandern mit: `--c-warning` auf
|
|
1107
|
-
`#785008` und `--c-error` auf `#9B2020`, damit sie auf der kräftigeren Füllung 4,84 bzw. 4,99:1
|
|
1108
|
-
tragen; `--badge-*-text` verweist jetzt auf dieselben Token statt eigene Werte zu führen.
|
|
1109
|
-
- **60 inline gesetzte Kachel-Tints** sind aus dem Markup in die Komponente gewandert
|
|
1110
|
-
(`.ep-card-icon[data-area]`).
|
|
1111
|
-
- **`--tx-muted` auf `#5A7171`** (vorher `#5E7676`): auf Weiß 4,85:1 ✓, aber auf `n-50` und
|
|
1112
|
-
getönten Gründen nur 4,35 bis 4,51:1, also genau dort unter AA, wo leiser Text meist sitzt.
|
|
1113
|
-
Jetzt 4,66 bis 5,20:1 und weiter klar heller als `--tx-secondary`.
|
|
1114
|
-
- **Paletten-Beschriftungen (11).** Die Labels trugen `opacity:.75` auf der Swatch-Farbe, 2,53
|
|
1115
|
-
bis 4,36:1, und genau dort steht der Hexwert zum Ablesen. Deckkraft raus; für die
|
|
1116
|
-
Mittelton-Stufen, auf denen weder weißer noch dunkler Text 4,5:1 erreicht (auf `ki-700`
|
|
1117
|
-
schafft selbst Schwarz nur 4,82:1), gibt es `.swatch.is-midtone` mit einer Plakette.
|
|
1118
|
-
- **Halbtransparentes Weiß auf Bereichsbändern (4).** `.7` bis `.85` trugen 3,54 bis 4,46:1.
|
|
1119
|
-
Jetzt deckend; die dokumentierte Konvention nannte `.85` und ist mit korrigiert.
|
|
1120
|
-
- **Bedienelement-Rahmen (6).** Segmented Control und vier inline gestylte Suchfelder nutzten
|
|
1121
|
-
`n-200` (1,53:1) statt `--field-border` (3,92:1), also unter der 3:1-Schwelle aus WCAG 1.4.11.
|
|
1122
|
-
- **Terminal-Variante des Code-Blocks (3).** Kopier-Button und Ausgabe-Zeilen trugen 3,09 bzw.
|
|
1123
|
-
4,20:1 auf dem dunklen Grund.
|
|
1124
|
-
- **Slider ohne Bereichsklasse (1).** Fiel im Dark auf den `co-700`-Fallback und stand mit
|
|
1125
|
-
2,36:1 dunkel auf dunkel; die vier Bereichsvarianten waren gesetzt, der Grundfall nicht.
|
|
1126
|
-
- **Kontrast-Gate `npm run check:contrast`.** Rendert `docs/index.html` in beiden Modi in Chromium,
|
|
1127
|
-
löst für jeden Textknoten den effektiven Grund über die Elternkette auf (halbtransparente
|
|
1128
|
-
Schichten werden aufeinander komponiert) und prüft Text (4,5:1 bzw. 3:1), getönte
|
|
1129
|
-
Bauteil-Füllungen (Hausregel 1,3:1) und Bedienelement-Rahmen (3:1). Es misst die **fertige Kette**
|
|
1130
|
-
statt des CSS und findet damit auch inline gesetzte Farben, die kein Token-Check sieht. Läuft in
|
|
1131
|
-
`storybook-angular.yml`, weil es einen Browser braucht; das Wurzelprojekt bleibt ohne
|
|
1132
|
-
Dependencies. Genau **eine** dokumentierte Ausnahme: Swatches, die ein Farbpaar als Inhalt zeigen.
|
|
1133
|
-
Text über Fotos und Verläufen wird gezählt, nicht gewertet (braucht Pixelmessung).
|
|
1134
|
-
Absicherung als **Ratsche**: eine Zahl pro Kategorie im Skript, Fehlschlag wenn sie steigt und
|
|
1135
|
-
ebenso wenn sie sinkt, ohne nachgezogen zu werden. Erster Stand, Light/Dark:
|
|
1136
|
-
**56/20** Text, **101/0** Füllungen, **6/0** Rahmen. Ziel überall 0.
|
|
1137
|
-
Nebenbefund beim Bau: die ersten Messläufe lasen Zwischenwerte der Theme-Animation, die Zahlen
|
|
1138
|
-
wanderten je nach Wartezeit. Das Gate schaltet Übergänge vor der Messung ab, zwei Läufe
|
|
1139
|
-
hintereinander liefern jetzt identische Zahlen.
|
|
1140
|
-
- **Pill- und Badge-Füllungen lesen im Light wieder als Fläche.** Beide füllten mit `--XX-50`, das
|
|
1141
|
-
im Light gleichzeitig der zarte Sektions-Tint ist. Als Bauteil-Füllung trug es gegen seinen Grund
|
|
1142
|
-
nur **1,06:1** (ki) bis **1,14:1** (es), ein Fall auf einer `wo-50`-Sektion sogar 1,00:1: das
|
|
1143
|
-
Element las nur noch als farbiger Text und verfehlte den Faustwert von 1,3:1 aus CONTRIBUTING § 5.
|
|
1144
|
-
Gemessen über alle 64 Pills und 39 Bereichs-Badges der Doku, in beiden Modi.
|
|
1145
|
-
Neu dafür **`--co-fill` / `--ki-fill` / `--es-fill` / `--wo-fill`** (Light `-200`, ki `-400`, weil
|
|
1146
|
-
der Ton so hell ist, dass `-200` nur 1,27:1 trägt; im Dark identisch mit `--XX-50`, das dort schon
|
|
1147
|
-
auf genau diese Aufgabe kalibriert ist). Nachgemessen: Light 1,42 bis 2,03:1 gegen beide Gründe,
|
|
1148
|
-
Dark unverändert 1,32 bis 1,79:1, Text überall über 5,6:1. Die ES-Pill nimmt dabei `--es-800`
|
|
1149
|
-
statt `--es-700`, wie das ES-Badge, weil `-700` auf der kräftigeren Füllung nur 4,74:1 trüge.
|
|
1150
|
-
WCAG war in beiden Modi schon vorher erfüllt, der Text trug 4,7 bis 11,4:1; verfehlt war die
|
|
1151
|
-
Flächenwirkung. Kein `--ro-fill`: Rosé ist Akzent- und Statusfarbe ohne Pill und Badge.
|
|
1152
|
-
- **Bereichs-Rahmen der Team-Stimme erfüllt die 3:1-Schwelle.** `.team-voice[data-area]` tönt seinen
|
|
1153
|
-
Rahmen in der Bereichsfarbe, und der Rahmen ist dort das tragende Farbsignal, weil das Quote-Icon
|
|
1154
|
-
daneben dekorativ ist (`opacity` .25 im Light, .6 im Dark). Er trug im Light auf `-200` nur
|
|
1155
|
-
**1,27:1** (ki) bis **2,03:1** (es) und im Dark auf `-800` nur **1,07:1** (wo) bis **1,63:1** (ki),
|
|
1156
|
-
war also in beiden Modi als Signal nicht wahrnehmbar. Jetzt dieselben Stufen wie beim
|
|
1157
|
-
Bereichs-Chip, die dort schon auf die 3:1-Schwelle für grafische Objekte ausgelegt sind: Light
|
|
1158
|
-
`-600`/`-700`/`-500`/`-500` (3,29 bis 5,66:1), Dark `-300` (4,25 bis 9,48:1).
|
|
1159
|
-
- **Sektions-Rhythmus im Dark auf Light-Parität, Karten grenzen sich per Rand ab.** Im Dark werden
|
|
1160
|
-
`n-50`-Sektionen auf `bg-surface` gehoben, damit die Tonfolge dieselbe ist wie im Light. Für
|
|
1161
|
-
kartentragende Sektionen gab es dafür eine Ausnahme (`.ep-section-cards`), die die Hebung
|
|
1162
|
-
zurücknahm, damit die Karten die hellere Stufe bilden. Die Ausnahme kostet aber genau den
|
|
1163
|
-
Rhythmus: die Sektion sitzt dann auf dem Ton ihrer Nachbarn. Im Browser über die 24 Beispielseiten
|
|
1164
|
-
gemessen (133 Abschnitte, Chrome, `data-theme="dark"`): **63** verschmolzene Sektionsübergänge mit
|
|
1165
|
-
Rücknahme, **20** ohne, **17** im Light. Auf der Beispiel-Startseite: 1 gegen 0.
|
|
1166
|
-
Die Ausnahme entfällt daher komplett, samt Klasse und ihren 9 Vorkommen im Markup. Stattdessen
|
|
1167
|
-
tragen Karten im Dark einen Rand aus `--bd-strong-c` (**4,21:1** gegen die Kartenfläche):
|
|
1168
|
-
`.card`, `.ep-card` und `.ep-card-link`, letztere auch dann, wenn sie im Light `border:none`
|
|
1169
|
-
setzen und sich auf `--e1` verlassen. Das ist kein Notbehelf, sondern dasselbe Mittel, mit dem im
|
|
1170
|
-
Light die weiße Karte auf der weißen Sektion liest, dort mit 1,10:1. Auf `bg-page`-Sektionen
|
|
1171
|
-
kommt die Tonstufe dazu. Gegenprobe im Browser: keine Kartenfläche ohne Rand.
|
|
1172
|
-
- **Schatten nur noch auf Karten, deren Fläche selbst klickbar ist.** `.card-elevated` setzte den
|
|
1173
|
-
Ruhe-Schatten `--e1` auf jeder Karte, auch auf `<article>`/`<div>`-Karten mit Buttons im Footer.
|
|
1174
|
-
Nach der Konvention „Elevation = Interaktivität“ ist so eine Karte statisch: die Buttons sind die
|
|
1175
|
-
Interaktion, die Fläche führt nirgendwohin, und ein Ruhe-Schatten verspricht Klickbarkeit, die es
|
|
1176
|
-
nicht gibt. Der Hover-Lift war bereits auf `a.card-elevated` begrenzt, der Ruhe-Schatten nicht.
|
|
1177
|
-
Die Variante hängt jetzt komplett an `a.card-elevated`; eine statische Karte fällt damit auf
|
|
1178
|
-
`.card` zurück (flach, `--bd`-Rahmen) und kann den Schatten auch mit gesetzter Klasse nicht
|
|
1179
|
-
bekommen. Betroffen waren 9 statische `.card-elevated`-Karten (generische Karten, Referenz- und
|
|
1180
|
-
Themen-Karten der Beispielseiten), 6 Blöcke mit Inline-`box-shadow` (AI.Box-Preiskarten,
|
|
1181
|
-
Agenda-Karten, zwei Newsletter-Widgets) sowie `.cta-dl` und `.cta-visual`, die den Schatten aus
|
|
1182
|
-
dem CSS trugen. Alle behalten ihren Rahmen, die Kartenform bleibt. Die 44 Link-Karten
|
|
1183
|
-
(`<a class="card card-elevated">`) sind unverändert. In der Doku ersetzt die Zeile „Link-Karte“
|
|
1184
|
-
die bisherige Zeile „Elevation-Opt-in“, die genau diesen Fall legitimiert hatte.
|
|
1185
|
-
- **Angular-Card rendert flach.** `CardComponent` gab per Default `card card-elevated` auf einem
|
|
1186
|
-
`<article>` mit Footer-Button aus, also genau dieses Muster. Der `elevated`-Input entfällt (er
|
|
1187
|
-
wäre nach der CSS-Änderung wirkungslos), die Komponente rendert `<article class="card">`. Eine
|
|
1188
|
-
Link-Karten-Variante (`<a>` mit Ziel statt `<article>` mit Button) bleibt offen.
|
|
1189
|
-
- **Bereichs-Chips waren im Dark dunkel-auf-dunkel.** `.chip[data-area]` setzte Rahmen und Text auf
|
|
1190
|
-
die dunklen Stufen (`-500`/`-600`/`-700` Rahmen, `-700`/`-800` Text), die im Dark nicht flippen:
|
|
1191
|
-
der Text stand zwischen **1,35:1** (es) und **2,36:1** (co) auf einer Karte, der es-Rahmen mit
|
|
1192
|
-
2,30:1 unter der 3:1-Schwelle für die Bedienelement-Grenze. Nur der *gedrückte* Zustand hatte
|
|
1193
|
-
Dark-Regeln. Jetzt wie überall im Dark die hellen Pendants: Text `-200` (es `-100`) mit 7,66 bis
|
|
1194
|
-
10,25:1, Rahmen `-300` mit 4,25 bis 9,48:1, Hover eine Stufe kräftiger. Betrifft 35 Chips in der
|
|
1195
|
-
Doku. `check:dark-states` sah das nicht, weil es Zustands-Regeln prüft, nicht Ruhezustände.
|
|
1196
|
-
- **Karten-Varianten „Filled“ und „Outlined“ aus der Doku entfernt.** `.card-filled` und
|
|
1197
|
-
`.card-outlined` existierten nie, weder im CSS noch im Markup noch in der Angular-Lib. Die
|
|
1198
|
-
Varianten-Tabelle führt jetzt die zwei Zustände, die es gibt: statisch (`.card`) und Link-Karte
|
|
1199
|
-
(`a.card.card-elevated`). Die Do/Don't-Liste und der Abschnitts-Untertitel sind nachgezogen,
|
|
1200
|
-
ebenso zwei Aussagen zu einem „Tonal Overlay“, das Karten nie gesetzt haben.
|
|
1201
|
-
- **Drei rohe Bereichston-Rahmen ersetzt.** Die Pro-Preiskarte trug `1px solid var(--ki-200)`
|
|
1202
|
-
(im Light 1,27:1 gegen Weiß, im Dark eine leuchtende Haarlinie mit 10,25:1), jetzt `--bd`; die
|
|
1203
|
-
4-px-Oberkante und die „Empfohlen“-Pill tragen die Hervorhebung weiter. Die zwei
|
|
1204
|
-
Font-Specimen-Links nutzen jetzt die vorhandene `.chip`-Komponente mit `data-area` statt
|
|
1205
|
-
Inline-Rahmen, Inline-Radius und zwei `onmouseover`/`onmouseout`-Handlern für den Hover.
|
|
1206
|
-
`.chip` bekommt dafür `text-decoration:none`, damit es auch als `<a>` trägt.
|
|
1207
|
-
- **Dark-Mode-Flächen neu aufgesetzt.** `--bg-page` trug mit `#333E48` nur **10,92:1** gegen Weiß.
|
|
1208
|
-
Die Material-Dark-Theme-Guidance fordert für die Basisfläche mindestens **15,8:1**; der Wert ist
|
|
1209
|
-
kein Stilmittel, sondern der Puffer, der Fließtext auch auf der höchsten Elevationsstufe noch
|
|
1210
|
-
4,5:1 sichert. Ursache war strukturell: `#333E48` ist `--tx-brand` aus dem Light Mode, also eine
|
|
1211
|
-
gegen Weiß optimierte **Textfarbe als Fläche**. Neu `#151A1F` (17,51:1), Farbwinkel 209 wie bisher,
|
|
1212
|
-
der Marken-Slate bleibt erhalten. `--bg-surface` `#3F4B56` → `#28323D`; die Stufe zwischen Seite
|
|
1213
|
-
und Karte wächst dabei von 1,223:1 auf **1,346:1**, weil mehr Kopfraum nach unten mehr Spielraum
|
|
1214
|
-
nach oben schafft. Gemessen über alle 24 Beispielseiten im Dark: **117 → 24 Kontrast-Verstöße**,
|
|
1215
|
-
die verbleibenden 24 sind ein vorbestehender, themeunabhängiger Befund am `.skip-link`
|
|
1216
|
-
(weiß auf `--co-500` = 2,31:1, in Light identisch, separat zu beheben). Der größte Block waren
|
|
1217
|
-
`--tx-muted` und Bereichstexte auf Karten, die mit 4,08:1 knapp unter AA lagen und jetzt bei
|
|
1218
|
-
5,95:1 liegen.
|
|
1219
|
-
- **Getönte Flächen im Dark: `--XX-50` zerfällt in zwei Token.** Ein Wert kann zwei gegensätzliche
|
|
1220
|
-
Aufgaben nicht mehr tragen. Ein **großes Band** muss dunkler bleiben als die Karten darauf, eine
|
|
1221
|
-
**kleine Füllung** (Badge, Pill, Icon-Kachel) muss heller sein als ihr Grund, sonst liest sie
|
|
1222
|
-
nicht mehr als Fläche. Bei `bg-page` auf 17,5:1 und Schwarz bei 21:1 reicht der Spielraum für
|
|
1223
|
-
beides zusammen nicht. `--XX-50` ist jetzt die kleine Füllung (9,8:1, also 1,78:1 gegen die Seite
|
|
1224
|
-
und 1,32:1 gegen Karten), das neue `--XX-band` die Sektionsfläche (16,5:1, 1,06:1 gegen die Seite
|
|
1225
|
-
mit der Trennung über den Farbton, Karten darauf 1,27:1). Im Light sind beide identisch.
|
|
1226
|
-
Gemessen über 199 Badge- und Pill-Instanzen: die Fläche gegen ihren Grund stand nach der ersten
|
|
1227
|
-
Fassung bei **1,06:1** und damit praktisch nicht mehr da, jetzt bei 1,32 bis 1,79:1. Zum Vergleich
|
|
1228
|
-
der Stand vor dem gesamten Umbau: 1,29:1 im schlechtesten Fall. Sättigung auf 0,60 begrenzt, weil
|
|
1229
|
-
kräftig gesättigte Farbe großflächig auf dunklem Grund optisch vibriert.
|
|
1230
|
-
- **Acht Inline-Rahmen nutzten rohes `--n-100` statt `--bd`.** Das verstößt gegen die eigene Regel in
|
|
1231
|
-
`CONTRIBUTING.md` § 5. Im Light sind beide Werte identisch, im Dark wird `--n-100` dunkel und der
|
|
1232
|
-
Rahmen stand mit **1,18:1** gegen die Kartenfläche, war also praktisch unsichtbar. Jetzt `var(--bd)`
|
|
1233
|
-
(2,99:1). Betraf `.card`-Elemente in der Doku, Light bleibt unverändert.
|
|
1234
|
-
- **Snackbar-Flächen im Dark waren hartkodierte Kopien.** `.snack-ok` und `.snack-err` trugen
|
|
1235
|
-
`#052415` und `#220808`, also die alten Werte von `--c-success-bg` und `--c-error-bg`. Als die
|
|
1236
|
-
Status-Tints angehoben wurden, blieben die Kopien zurück und standen nur noch **1,06:1** bzw.
|
|
1237
|
-
**1,08:1** gegen die Seite, die Snackbar war als Fläche praktisch weg. Jetzt über die Token
|
|
1238
|
-
(1,78 und 1,79:1). Zusätzlich zählt die Snackbar zu den schwebenden Panels und bekommt im Dark
|
|
1239
|
-
denselben `--bd-strong-c`-Rand wie Menüs (5,66:1 gegen den Grund); das deckt auch die
|
|
1240
|
-
Default-Variante ab, die mit `--n-700` nicht mitflippt und bei 1,23:1 lag.
|
|
1241
|
-
- **Schwebende Panels bekommen im Dark einen stärkeren Rand.** Menüs und Popover grenzen sich im
|
|
1242
|
-
Light über `--e3` ab. Auf der tiefen Basisfläche trägt ein schwarzer Schatten das nicht mehr: ein
|
|
1243
|
-
geöffnetes Topnav-Menü stand über dem Hero-Foto nur noch **1,34:1** gegen die hellste Stelle
|
|
1244
|
-
daneben (vorher 1,92:1), weil die Panel-Fläche mitgesunken ist, das Foto darunter aber nicht.
|
|
1245
|
-
Eine dritte statische Flächen-Stufe wäre der Material-Weg, würde aber die Zwei-Stufen-Konvention
|
|
1246
|
-
brechen und einem Menü über einer Karte nur 1,13:1 bringen. Stattdessen übernimmt der Rand:
|
|
1247
|
-
`--bd-strong-c` statt `--bd-c` für `.ep-nav-sub`, `.ep-select-menu`, `.ep-combobox-menu` und das
|
|
1248
|
-
Suchpanel. Panel-Rand gegen den Untergrund 3,51 auf **4,95:1**, damit über dem Ausgangsstand
|
|
1249
|
-
(4,15:1). Neu dafür `--bd-c` / `--bd-strong-c`, die reinen Rahmenfarben: `--bd` und `--bd-strong`
|
|
1250
|
-
sind Shorthands und funktionieren in `border-color` nicht.
|
|
1251
|
-
- **Platzhalter in Formularfeldern erfüllen AA.** `.field` hatte keine `::placeholder`-Regel, es griff
|
|
1252
|
-
Chromes Default `rgb(117,117,117)`: im Dark **2,82:1** und damit ein Verstoß, im Light 4,61:1 und
|
|
1253
|
-
damit knapp bestanden, aber ohne Reserve und vom Browser abhängig. Jetzt `--tx-secondary` wie bei
|
|
1254
|
-
Suchfeld, Footer-Newsletter, Combobox und Nav-Suche, die das längst taten; die Standard-Felder
|
|
1255
|
-
waren der Ausreißer. Gemessen über 22 Felder: Dark 7,13:1, Light 6,29:1.
|
|
1256
|
-
- **Zwei Download-Buttons trugen im Dark dunklen Text auf dunkler Fläche** (3,51:1). Sie setzten die
|
|
1257
|
-
Bereichsfarbe inline (`--c500:var(--co-700)`) statt über `.btn-co`. Die Dark-Regel für die Fläche
|
|
1258
|
-
hängt an der Bereichsklasse, die für die Textfarbe an `.btn-filled`; ohne Klasse greift nur die
|
|
1259
|
-
zweite. Jetzt `class="btn btn-filled btn-co"`, die inline gesetzten `--c600`/`--c700`/`--c900`
|
|
1260
|
-
waren ohnehin tot (nirgends in `css/` referenziert). Vorbestehend, Light war nicht betroffen.
|
|
1261
|
-
- **Fehler-Badge-Text im Dark auf `#FFA5A5`.** `#F08080` trug auf der aufgehellten Fehler-Füllung
|
|
1262
|
-
nur 3,78:1. Damit nutzen `--badge-err-text`, `--cbadge-fail-text` und `--c-error` denselben Ton,
|
|
1263
|
-
eine Fehlerfarbe weniger im System.
|
|
1264
|
-
- **`--c-warning-bg` war im Dark unsichtbar.** `#231800` stand mit 1,00:1 gegen die neue Seite. Alle
|
|
1265
|
-
drei Status-Tints und die drei Kontrast-Badge-Flächen auf die Tint-Stufe gehoben.
|
|
1266
|
-
- **Ränder im Dark nachgezogen.** Auf der tieferen Seite sprang `--bd` von 3,19:1 auf 5,12:1 und
|
|
1267
|
-
wirkte drahtig, jetzt `#6F7A89`. `--field-border` von `--n-200` (11,46:1) auf `#869C9C`; als
|
|
1268
|
-
einzige Grenze, die WCAG 1.4.11 zwingend braucht, liegt es mit 4,49:1 auf der Karte sicher über 3:1.
|
|
1269
|
-
- **Logo-Platte im Dark gedämpft.** Eine reinweiße Fläche dieser Größe stand mit 17,51:1 gegen die
|
|
1270
|
-
Seite. Über das neue `--bg-plate` im Dark auf `#E8EDED`; dunkle Kundenlogos darauf 14,73:1.
|
|
1271
|
-
- **Fotos im Dark leicht gedämpft** (`filter: brightness(.92)` auf `.hero-image-media`,
|
|
1272
|
-
`.ep-media-band`, `.article-figure`). Nicht zu verwechseln mit dem verworfenen
|
|
1273
|
-
`brightness(.75)` auf Icon-Glyphen: das betraf Strichgrafik auf getönten Kacheln.
|
|
1274
|
-
- **Fokusringe folgen jetzt `var(--bg-page)`** statt einem hartkodierten `#333E48` und laufen bei
|
|
1275
|
-
künftigen Flächen-Änderungen automatisch mit.
|
|
1276
|
-
- **Drei hartkodierte Kopien im Dark auf ihre Token gezogen.** Sie hielten Werte, die die
|
|
1277
|
-
Flächen-Umstellung ersetzt hat, und liefen dadurch aus der Familie:
|
|
1278
|
-
`.a11y-rule-icon` trug die Kreisflächen als `#052415` / `#220808` und stand damit bei 1,06:1 bzw.
|
|
1279
|
-
1,08:1 gegen die Seite, der Kreis war keine Fläche mehr (jetzt `--c-success-bg` / `--c-error-bg`,
|
|
1280
|
-
1,78 und 1,79:1; der Fehler-Glyph geht mit auf `--c-error`, 5,21:1 statt 3,78:1).
|
|
1281
|
-
Der Chip-Rahmen hielt den alten `--bd`-Wert `#818C99` (jetzt `--bd-strong-c`, 4,21:1 gegen die
|
|
1282
|
-
Chip-Fläche; `--bd-c` wäre mit 2,99:1 unter der 3:1-Schwelle, die die Bedienelement-Grenze nach
|
|
1283
|
-
WCAG 1.4.11 braucht). Der Tonal-Button-Rahmen hielt den alten `--bd-strong`-Wert `#9DA8B6`
|
|
1284
|
-
(jetzt `--bd-strong-c`, 3,64:1 bis 4,87:1 auf den vier Tonal-Füllungen).
|
|
1285
|
-
|
|
1286
|
-
- **Skip-Link erfüllt AA.** Weiß auf `--co-500` `#00BEBE` trug **2,31:1**. In Ruhe ist der Link
|
|
1287
|
-
geclippt, beim Fokus springt er sichtbar herein, also genau dann kaputt, wenn Tastaturnutzende ihn
|
|
1288
|
-
brauchen. Jetzt `--co-700` (5,52:1), dieselbe Füllfarbe, die `.btn-filled.btn-co` verwendet.
|
|
1289
|
-
Betraf beide Modi, `--co-*` flippt nicht.
|
|
1290
|
-
- **Hero-Scrim verdichtet.** Der Text liegt zwischen 23 % und 77 % der Caption-Höhe, der Eyebrow als
|
|
1291
|
-
erstes Kind damit im obersten, schwächsten Abschnitt des Verlaufs. Dort stand er auf Alpha 0,30,
|
|
1292
|
-
über einem ausgebrannt hellen Foto sind das 1,90:1; gemessen lagen bis zu **63 % der
|
|
1293
|
-
Eyebrow-Fläche** unter 4,5:1. Der `text-shadow` hilft optisch, zählt für WCAG nicht. Die
|
|
1294
|
-
Unterkante bleibt unverändert bei `.85`, verdichtet wird nur der obere Teil
|
|
1295
|
-
(`.72` bei 60 %, `.66` bei 80 %). Bei 77 % jetzt Alpha 0,67 = 6,0:1 gegen ein weißes Foto.
|
|
1296
|
-
Pixelgemessen über 51 Textblöcke auf 17 Seiten: Blöcke mit über 10 % Fläche unter 4,5:1 gehen von
|
|
1297
|
-
**17 auf 0** (Light) und von 13 auf 0 (Dark).
|
|
1298
|
-
Der erste Anlauf dafür erfüllte zwar alle Kontrastwerte, zeichnete aber eine sichtbare Linie quer
|
|
1299
|
-
durchs Bild: er baute die Deckkraft auf zu kurzer Strecke auf. Gemessen an der zweiten Ableitung
|
|
1300
|
-
der Zeilenhelligkeit lag er bei 21 bis 25 gegenüber 7,9 beim vorherigen Verlauf. **Mehr
|
|
1301
|
-
Stützstellen halfen nicht** (eine weiche Kurve mit neun Stops maß 22,4). Gelöst über eine längere
|
|
1302
|
-
Auslaufstrecke: die Caption bekommt oben eine fluide Polsterung bis 96 px, der Verlauf läuft mit
|
|
1303
|
-
0,0066 Deckkraft pro Pixel aus und misst 9,2. Der Faustwert dazu steht jetzt in der Bildsprache.
|
|
1304
|
-
- **Code-Kommentare erfüllen AA.** `.cb-body .c` stand mit `--n-400` auf dem `--n-50`-Grund bei
|
|
1305
|
-
3,65:1, jetzt `--tx-muted` (Light 4,51:1, Dark 8,9:1). Die Terminal-Variante hat einen fest
|
|
1306
|
-
dunklen Grund in beiden Modi und behält deshalb `--n-400` (4,87:1) über eine eigene Regel.
|
|
1307
|
-
- **Scrim-Empfehlung in der Bildsprache korrigiert.** Die Doku nannte `rgba(0,0,0,.45)` und
|
|
1308
|
-
widersprach damit ihrer eigenen Regel darüber: über einer ausgebrannten Bildstelle trägt das nur
|
|
1309
|
-
rund 3:1. Neu mindestens `.60` für weiße Schrift, gerechnet gegen die **hellste** Stelle unter dem
|
|
1310
|
-
Text statt gegen den Bilddurchschnitt, und bei Verläufen an der Position des Textes statt am
|
|
1311
|
-
dichten Ende. Genau diese Lücke hatte den Hero-Befund erzeugt.
|
|
1312
|
-
|
|
1313
|
-
### Documentation
|
|
1314
|
-
- **Die Rollen-Token sind jetzt dort dokumentiert, wo man sie sucht.** `--co-ink`, `--es-ink` und
|
|
1315
|
-
`--wo-ink` standen in keiner Doku, die Token-Tabelle der Doku-Seite führte nur `--ki-ink` (die
|
|
1316
|
-
anderen drei gab es bis vor Kurzem nicht), und `--XX-fill` stand nur in Prosa und in
|
|
1317
|
-
CSS-Kommentaren. Auch die Consumer-Tabelle in `docs/GETTING-STARTED.md`, also die Tabelle, die
|
|
1318
|
-
eine Anwendung liest, kannte beide Rollen nicht. Ergänzt: Familien-Zeilen in der Doku-Tabelle mit
|
|
1319
|
-
Messwerten, dieselben zwei Rollen in der Consumer-Tabelle samt Leitsatz („nach der Rolle greifen,
|
|
1320
|
-
nicht nach der Stufe“), die Rollen-Zuordnung als ersten Schritt in CONTRIBUTING § 10, beide
|
|
1321
|
-
Prüfbefehle im Schritt „Prüfen“ und in der PR-Checkliste, und ein Abschnitt „Prüfungen“ im README:
|
|
1322
|
-
dass es ein Kontrast-Gate gibt und was es garantiert, stand dort gar nicht.
|
|
1323
|
-
- **In die PR-Checkliste aufgenommen, was in dieser Runde zweimal gefehlt hat:** nach
|
|
1324
|
-
Layout-Änderungen den geänderten Bereich in beiden Modi **und zwei Breiten** ansehen, also Kanten
|
|
1325
|
-
und Umbrüche, nicht nur Farbwerte.
|
|
1326
|
-
|
|
1327
|
-
### Added
|
|
1328
|
-
- **Angular-Komponenten-Bibliothek `@conciso/design-system-angular`.** Die 37 Angular-Wrapper
|
|
1329
|
-
sind aus dem Storybook in eine eigene, publizierbare Lib extrahiert (Angular Package Format
|
|
1330
|
-
via ng-packagr, ein einziger Einstiegspunkt `public-api.ts`, Angular 21). Die Wrapper sind
|
|
1331
|
-
dünne Hüllen über der CSS-Schicht und liefern **kein eigenes CSS**: Konsumenten binden
|
|
1332
|
-
`@conciso/design-system` (peerDependency, Lockstep-Version) samt Fonts global ein — der
|
|
1333
|
-
copy-paste-fertige `angular.json`-Schnipsel steht im README der Lib. `storybook-angular`
|
|
1334
|
-
enthält nur noch Stories und konsumiert die Lib. Architektur-Entscheidungen in
|
|
1335
|
-
`docs/adr/0001`–`0005`, `CONTEXT.md` führt das Glossar.
|
|
1336
|
-
- **Distribution über GitHub Packages** (privat, org-scoped) für beide Pakete — kehrt die
|
|
1337
|
-
0.1.0-Entscheidung „intern/proprietär statt Registry-Publish“ um, weil eine Angular-Lib als
|
|
1338
|
-
gebautes Artefakt ausgeliefert werden muss und ein Git-Tarball dafür nicht genügt.
|
|
1339
|
-
`publishConfig` auf beiden `package.json`, dazu ein Publish-Workflow, der auf eine
|
|
1340
|
-
Versionsänderung auf `main` reagiert: Er prüft pro Paket, ob die Lockstep-Version schon in der
|
|
1341
|
-
Registry liegt, veröffentlicht nur was fehlt, und legt Tag plus GitHub-Release selbst an
|
|
1342
|
-
(Release-Text ist der CHANGELOG-Abschnitt der Version). Version anheben und mergen ist damit
|
|
1343
|
-
das Release.
|
|
1344
|
-
- **Consumer-Smoke-Test als CI-Gate.** Eine committete Minimal-Konsumenten-App
|
|
1345
|
-
(`examples/consumer-fixture`) installiert die per `npm pack` gebauten Tarballs beider Pakete
|
|
1346
|
-
und fährt einen produktiven AOT-Build — außerhalb des Repos, damit die Modul-Auflösung nicht
|
|
1347
|
-
über das Wurzel-`node_modules` leckt. Fängt, was Lint und Storybook strukturell nicht sehen:
|
|
1348
|
-
unvollständige APF-Metadaten, fehlende Re-Exports, nicht deklarierte Abhängigkeiten,
|
|
1349
|
-
AOT-Template-Typfehler. Ist harte Vorbedingung des Publish-Jobs.
|
|
1350
|
-
- **Störer (`.stoerer`), Verweiskacheln über dem Hero, nur auf der Startseite.** Ein bis drei
|
|
1351
|
-
Kacheln als Set oben rechts über dem Hero-Bild, je auf einen aktuellen Inhalt: nächste
|
|
1352
|
-
Veranstaltung, neuer Wissensbeitrag, Pressemitteilung, Info. Default sind zwei, drei sind das
|
|
1353
|
-
Maximum. Aufbau je Kachel: Typ-Glyph und Thema-Label in einer Zeile (Eyebrow, `--co-ink`), Titel
|
|
1354
|
-
über zwei Zeilen, Meta-Zeile. Die ganze Kachel ist der Link, ein Tab-Stop, mit Hover und
|
|
1355
|
-
Fokus. Klassen `.stoerer-hero` (Wrapper um Hero und Set) · `.stoerer-set` · `.stoerer-list` ·
|
|
1356
|
-
`.stoerer` · `.stoerer-topic` · `.stoerer-title` · `.stoerer-meta` ·
|
|
1357
|
-
`.stoerer-icon`. `.hero-image` bleibt unverändert und funktioniert weiter ohne Störer.
|
|
1358
|
-
Die Entscheidungen, die das Bauteil tragen:
|
|
1359
|
-
- **Typ-Glyph als Leading-Element im Thema-Label**, nicht rechts hinter einem Trenner. Material
|
|
1360
|
-
trennt die Slots einer Listenzeile nach Aufgabe: das Leading-Element „represents the item's
|
|
1361
|
-
subject or category“, das Trailing-Element trägt „secondary information, actions, or status
|
|
1362
|
-
indicators“. Das Glyph ist ein reiner Typ-Marker, also eine Kategorie. Rechts stand es im Slot
|
|
1363
|
-
für Aktionen und Status und konnte auf einer vollständig klickbaren Kachel als Button lesen.
|
|
1364
|
-
NN/g ergänzt die andere Richtung („a text label must be present alongside an icon to clarify
|
|
1365
|
-
its meaning“): die Bedeutung trägt das Label, das Glyph ist Wiedererkennungshilfe und wirkt
|
|
1366
|
-
direkt neben dem Wort, das es doppelt. Gemessener Nebengewinn: ohne Icon-Spalte (57 px aus
|
|
1367
|
-
Glyph, Polsterung, Trenner und Spaltenabstand) wächst die Textspalte von 269 auf 326 px, also
|
|
1368
|
-
um 21 %, und die realistischen Titel der Startseite klammern nicht mehr. Kachelhöhe unverändert
|
|
1369
|
-
126 px, weil das 16-px-Glyph in die 16 px hohe Label-Zeile passt. Preis ist die Salienz: 16 px
|
|
1370
|
-
mit `--icon-stroke-micro` statt 24 px mit `-sm`, vertretbar weil das Glyph `aria-hidden` ist.
|
|
1371
|
-
Damit entfällt `.stoerer-body`, dessen einziger Zweck der durchgehende Trenner war.
|
|
1372
|
-
- **Eine Farbgebung für alle vier Typen**, der Inhaltstyp steht in Label und Icon. Vier
|
|
1373
|
-
Bereichsfarben nebeneinander arbeiten gegeneinander und gegen die Hero-Headline, und das Set
|
|
1374
|
-
liest dann als vier lose Kacheln statt als eines. Akzent ist durchgehend Corporate
|
|
1375
|
-
(`--co-ink`), aus demselben Grund wie bei der Topnav: der Störer ist Chrome über dem Bild, kein
|
|
1376
|
-
Bereichsinhalt. Kein `data-area`.
|
|
1377
|
-
- **Deckende Fläche, kein Glas.** Über einem Foto ist der Grund unbekannt, eine halbtransparente
|
|
1378
|
-
Kachel trägt je nach Bildstelle 2:1 oder 12:1, und `check:contrast` kann das nicht werten, weil
|
|
1379
|
-
der Grund nicht in der Elternkette steht. Auf `--bg-surface` ist der Text messbar: Light 5,52
|
|
1380
|
-
bis 10,92:1, Dark 8,32 bis 10,48:1. Das Bild bleibt sichtbar, weil die Kacheln klein sind, nicht
|
|
1381
|
-
weil sie durchscheinen. Dazu ein `--bd-strong`-Rahmen schon im Light, abweichend von den
|
|
1382
|
-
übrigen Karten: auf einer ausgebrannt hellen Bildstelle leistet der schwarze `--e1`-Schatten
|
|
1383
|
-
keine Kante mehr.
|
|
1384
|
-
- **Gleiche Höhe unabhängig von der Titellänge.** `min-height:2lh` außen reserviert zwei Zeilen,
|
|
1385
|
-
das innere Element kappt per `line-clamp` mit Auslassungszeichen. Ein einzeiliger Titel lässt
|
|
1386
|
-
dadurch sichtbar Luft zur Meta-Zeile, und das ist der gewollte Tausch: sonst springen die
|
|
1387
|
-
Kacheln, sobald das CMS einen längeren Titel liefert. Der vollständige Titel bleibt im
|
|
1388
|
-
zugänglichen Namen des Links, das Kappen ist rein visuell.
|
|
1389
|
-
- **Overlay nach Hero-Breite, nicht nach Fensterbreite.** Bei 21:9 ist die Hero-Höhe die Breite ×
|
|
1390
|
-
9/21; drei Kacheln brauchen 426 px Höhe und damit 994 px Hero-Breite. Eine Media Query auf
|
|
1391
|
-
1025 px ließ ein Dreier-Set in der Doku-Vorschau (Hero 898 px im 1200-px-Fenster) 41 px in die
|
|
1392
|
-
Sub-Sektion ragen. Die Entscheidung hängt deshalb an einer **Container-Query** auf
|
|
1393
|
-
`.stoerer-hero` (Schwelle 1025 px, das Desktop-Tier der Responsive-Strategie), der ersten im
|
|
1394
|
-
System. Ist der Hero schmaler, steht das Set als Block darunter; dasselbe passiert ohne
|
|
1395
|
-
Container-Query-Support, dort greift die Regel nie und der funktionierende Fall bleibt stehen.
|
|
1396
|
-
Barrierefreiheit: `<aside aria-label="Aktuelles">` als benannte Landmark, `<ul>`/`<li>` damit
|
|
1397
|
-
Screenreader die Anzahl melden, Icon `aria-hidden` (es wiederholt das Label). Der Trennpunkt der
|
|
1398
|
-
Meta-Zeile ist `aria-hidden` mit einem `.sr-only`-Komma daneben, sonst wird er verschluckt oder
|
|
1399
|
-
als „Punkt“ gelesen und Datum und Ort verschmelzen; im AX-Tree geprüft. Der Hover unterstreicht
|
|
1400
|
-
zusätzlich den Titel (WCAG 1.4.1): über einem Foto ist ein Schatten- oder Flächen-Zuwachs je nach
|
|
1401
|
-
Bildstelle kaum sichtbar, die Unterstreichung immer.
|
|
1402
|
-
Ziel jeder Kachel ist die **eigene Seite des Inhalts** (Veranstaltungs-Detailseite,
|
|
1403
|
-
Wissensbeitrag, Pressemeldung, Seminar-Landingpage), nie ein Anker der Startseite und kein
|
|
1404
|
-
`target="_blank"`. Ein Anker wäre ein Versprechen, das die Kachel nicht hält: ihr zugänglicher
|
|
1405
|
-
Name kündigt einen konkreten Inhalt an, geliefert würde eine Scroll-Position (WCAG 2.4.4).
|
|
1406
|
-
Existiert für einen Anlass keine eigene Seite, ist er kein Störer-Kandidat.
|
|
1407
|
-
Rolle gegenüber den Vorschau-Sektionen: der Störer ist eine **Abkürzung zum Inhalt**, dasselbe
|
|
1408
|
-
Ziel wie eine Sektion weiter unten ist erlaubt und beabsichtigt. Die Sektion bleibt der kanonische Ort mit Bild
|
|
1409
|
-
und Anreißer. Bedingung ist ein **Domänenwort pro Domäne**: sonst steht derselbe Inhalt zweimal
|
|
1410
|
-
als Link mit verschiedenen Namen auf der Seite, und für Screenreader sind das zwei verschiedene
|
|
1411
|
-
Dinge. Der Titel muss dafür im zugänglichen Namen der Kachel stehen, was der Aufbau von selbst
|
|
1412
|
-
leistet.
|
|
1413
|
-
- **Icon `ui-megaphone`** (outline, `--icon-stroke-sm`) für den Störer-Typ Pressemitteilung.
|
|
1414
|
-
`ui-newspaper` heißt im DS „Zeitung / Artikel“ und bleibt das Artikel-Glyph für den
|
|
1415
|
-
Wissensbeitrag; eine Verlautbarung braucht ein eigenes Zeichen, sonst ist das Icon zwischen den
|
|
1416
|
-
beiden Typen kein Unterscheidungsmerkmal mehr. Veranstaltung nutzt `ui-calendar-days`, Info
|
|
1417
|
-
`ui-information-circle`, beide bereits vorhanden.
|
|
1418
|
-
- **`--bg-surface-hover`** (Light `var(--bg-surface)`, Dark `#2E3B46`): Auf der tieferen Basisfläche
|
|
1419
|
-
tragen die schwarzen `--e*`-Schatten weniger, deshalb hebt der Hover interaktiver Karten
|
|
1420
|
-
zusätzlich die Fläche. Ein Zustand, keine dritte statische Flächen-Stufe.
|
|
1421
|
-
- **`--bg-plate`** (Light `#FFFFFF`, Dark `#E8EDED`): helle Platte unter Fremd-Assets, die nur in
|
|
1422
|
-
einer dunklen Fassung vorliegen (Kundenlogos).
|
|
1423
|
-
- **Druckausgabe:** `dark-mode.css` steht jetzt komplett in `@media screen`, Token-Block und
|
|
1424
|
-
Komponenten-Regeln. Eine Seite mit `data-theme="dark"` druckte bisher die volle dunkle Fläche;
|
|
1425
|
-
jetzt greifen die Light-Werte aus `tokens.css`, ohne dass sie ein zweites Mal gepflegt werden.
|
|
1426
|
-
Die Komponenten-Regeln müssen mit hinein: 183 von ihnen setzen eine helle Tint- oder Festfarbe
|
|
1427
|
-
(`co-200`, `ki-200`, `es-100`, heller `tx-primary`), die auf dem hellen Druckgrund 1,2 bis 1,9:1
|
|
1428
|
-
trägt; ein geschützter Token-Block allein hätte den Text genau dort verloren, wo eine eigene
|
|
1429
|
-
Dark-Regel greift. Neue Dark-Regeln gehören innerhalb des Blocks, sonst drucken sie dunkel mit.
|
|
1430
|
-
- **CI-Gate gegen dunkel-auf-dunkel-Zustände** (`npm run check:dark-states`, in `css-core.yml`):
|
|
1431
|
-
Prüft jede `:hover`/`:focus`/`:active`-Regel in `components.css` darauf, ob sie einen nicht
|
|
1432
|
-
theme-awaren Ton setzt, dessen Kontrast gegen die dunklen Grundflächen unter der WCAG-Schwelle
|
|
1433
|
-
liegt (4,5:1 für Text, 3:1 für Ränder), ohne dass `dark-mode.css` nachzieht. Gerechnet wird echter
|
|
1434
|
-
Kontrast, nicht die Stufennummer: `--co-500` ist `#00BEBE` und trägt im Dark, `--wo-800` ist
|
|
1435
|
-
`#183A0E` und nicht. Auf dem Stand vor diesem Commit hätte der Check **acht** Verstöße gemeldet.
|
|
1436
|
-
Bewusste Ausnahmen stehen mit Begründung im Skript, aktuell keine.
|
|
1437
|
-
Dazu ein zweiter Check gegen **zerrissene Füllung/Text-Paare**: Eine Regel, die Hintergrund und
|
|
1438
|
-
Textfarbe gemeinsam setzt, trägt ihren Kontrast selbst, aber nur solange das Paar zusammenbleibt.
|
|
1439
|
-
Überschreibt eine andere Regel nur eine Hälfte, entsteht genau der Fehler, den der erste Check nicht
|
|
1440
|
-
sieht. Der zweite bildet dafür die Kaskade je (Element, Theme, Zustand) nach und prüft die
|
|
1441
|
-
tatsächlich gewinnende Kombination — paarweises Vergleichen reichte nicht, weil im Dark oft eine
|
|
1442
|
-
spezifischere Regel den Text längst überschrieben hat.
|
|
1443
|
-
Er hat sofort zwei Fehler gefunden, die von Hand durchgerutscht waren: die zu breite Chip-Inversion
|
|
1444
|
-
und einen Icon-Hover auf `var(--n-100)`. Letzterer entlarvte eine falsche Annahme im ersten Check:
|
|
1445
|
-
Tokens aus dem Dark-Block galten als „theme-aware und damit unkritisch“, aber die Neutrals kippen
|
|
1446
|
-
dort auf **dunkle** Werte (`--n-100` = `#1C2E2E`). Der Check wertet Tokens jetzt mit dem Wert aus,
|
|
1447
|
-
den sie im Dark tatsächlich annehmen.
|
|
1448
|
-
- **Personengruppe mit Bio** (`.author-card-group.is-grid`): Zweispaltige Variante der bestehenden
|
|
1449
|
-
Author-Card-Gruppe für zwei bis vier Personen mit Kurz-Bio, gedacht für die Trainer:innen einer
|
|
1450
|
-
Seminar- oder Training-Landing. Die Karten selbst bleiben unverändert; die Variante setzt nur das
|
|
1451
|
-
Raster (960 px Container, `minmax(0,1fr)` gegen Grid-Blowout, mobil einspaltig ab 768 px) und zieht
|
|
1452
|
-
die gemeinsame `.author-card-group-eyebrow` per `:has()` auf dieselbe Breite. Dokumentiert mit einer
|
|
1453
|
-
Regel an der Personenzahl: 1 Person groß mit 4:3-Bild, 2 bis 4 im Raster, darüber das
|
|
1454
|
-
Team-Tile-Grid ohne Bio. Dokumentiert unter *Seminar & Training · Trainer:innen*, nicht bei der
|
|
1455
|
-
Author Card: Trainer:innen kommen nur auf Seminar- und Training-Landings vor. Live auf der Beispielseite *Scrum Trainings*, deren Trainer:innen-Sektion
|
|
1456
|
-
bisher nur einen Platzhaltertext ohne Personen trug.
|
|
1457
|
-
- **Komponente „Buchungsformular“** (`#sec-booking`, Klassen `.bk-*`): verbindliche Terminbuchung als
|
|
1458
|
-
Komposition aus `.field`-Feldern, am Beispiel eines Seminars. Erste Formular-Komponente mit
|
|
1459
|
-
**bedingten Feldblöcken** (Firma vs. Privatperson, abweichende Rechnungsadresse: `hidden` statt
|
|
1460
|
-
`disabled`, `required` wird über `data-required` mitgeschaltet) und einem **Teilnehmenden-Repeater**
|
|
1461
|
-
(Anzahl als führendes Feld, Namensblöcke folgen, Schutz vor stillem Datenverlust beim Verringern,
|
|
1462
|
-
„Ich nehme selbst teil“ belegt Block 1 vor). Live-Preiszeile und Anzahl als `role="status"`, Fehlerübersicht `.bk-errors` mit Sprunglisten,
|
|
1463
|
-
`autocomplete`-Sections je Block, feldspezifische Fehlermeldungen über `data-err`.
|
|
1464
|
-
Informationshierarchie in drei Stufen: Gruppe `--ty-title-sm` (20 px) mit Haarlinie, Untergruppe
|
|
1465
|
-
(`.bk-subgroup`/`.bk-sublegend`) `--ty-name` (14 px), Feldlabel 12 px Versalien. Eine Gruppe ist
|
|
1466
|
-
eine Entscheidung samt ihrer Folgen, bedingte Blöcke liegen als Untergruppe **in** der Gruppe
|
|
1467
|
-
ihres Auslösers statt daneben. Preiszeile zweimal (bei der Anzahl mit `role="status"`, stumm über
|
|
1468
|
-
dem Submit); nur Pflichtsternchen ohne zusätzliche „(optional)“-Marker; freiwilliges
|
|
1469
|
-
Contentletter-Häkchen von den Pflicht-Bestätigungen abgesetzt.
|
|
1470
|
-
**Bestellübersicht** (`.bk-order`) unmittelbar vor dem zahlungspflichtigen Button: Leistung,
|
|
1471
|
-
Termin, Auftraggeber, Plätze und Gesamtbetrag, live aus dem Formular. Noch leere Zeilen bleiben
|
|
1472
|
-
stehen und tragen `data-empty`, damit sichtbar ist, was fehlt, statt dass die Übersicht springt.
|
|
1473
|
-
Dazu der Abschnitt **„Für die Umsetzung“**: Anforderungen an die Produktivfassung, allen voran
|
|
1474
|
-
ein Zwischenspeicher gegen Datenverlust (Schlüssel, Speicherort, Wiederherstellungsreihenfolge,
|
|
1475
|
-
`beforeunload`-Regel), sowie serverseitige Validierung, Platzkontingent, Doppel-Submit und Spam.
|
|
1476
|
-
Dazu ein Entscheidungs-Abschnitt „Anfrage oder Direktbuchung“, der das Formular gegen die adaptive
|
|
1477
|
-
Kontaktseite abgrenzt; die Beispielseite Seminar bleibt bewusst beim Anfrage-Flow.
|
|
1478
|
-
|
|
1479
|
-
- **Bereichs-Varianten für das Segmented Control** (`.seg-ki`, `.seg-es`, `.seg-wo`): Die Füllung des
|
|
1480
|
-
gewählten Segments läuft jetzt über `--seg-fill`/`--seg-on` statt fest über `--co-700`, analog zum
|
|
1481
|
-
`--c500`-Muster der Buttons. Default bleibt Corporate, bestehende Verwendungen ändern sich nicht.
|
|
1482
|
-
Im Dark Mode kippt jede Variante auf ihren `-300`-Ton mit `-900`-Text.
|
|
1483
|
-
|
|
1484
|
-
- **Doku · Abschnitt „Responsive“** (`#sec-responsive`): Übergabe-Spezifikation der Responsive-Strategie
|
|
1485
|
-
als eigener Foundations-Abschnitt (bisher nur implizit im CSS + verstreut). Verbindliche 3-Stufen-Breakpoints
|
|
1486
|
-
(Phone ≤ 520 · Mobile ≤ 768 · Tablet 769 bis 1024 · Desktop > 1024), Begründungen der nicht offensichtlichen
|
|
1487
|
-
Bruchpunkte (520 vs. 768 bei Hero-CTAs, auto-fit vs. fix-spaltig, Hamburger ≤ 760, Doku-Sidebar ≤ 1024),
|
|
1488
|
-
fluide Typo-Tokens (clamp, min ≥ 20 px, unitless Ratio) und vollständiges Komponenten-Inventar mit CSS-Quelle.
|
|
1489
|
-
Plus Hinweise, was auf der echten Site übernommen werden muss vs. was mockup-gebunden ist.
|
|
1490
|
-
- **Angebots-Detailseiten (Beispielseiten)**: Fünf neue Landingpages für einzelne Angebote unterhalb der
|
|
1491
|
-
Bereiche, jeweils an den Bereich gebunden. Wirksame Organisationen: „Erste Hilfe bei Meetingflut“
|
|
1492
|
-
(Festpreis 3.600 €), „Scrum Trainings“ (Preiskarten Scrum.org/TÜV SÜD), „Lean Portfolio Management“
|
|
1493
|
-
(Beratung ohne Festpreis). Effektive Software: „Identity mit Keycloak“ (mit YouTube-Embeds) und
|
|
1494
|
-
„Keycloak-Erweiterungen“ (Festpreis 9.900 €). Die Bereichs-Tabs (ES, WO) sind dafür zu aufklappbaren
|
|
1495
|
-
Baum-Tabs geworden; die „Konkrete Themen“-Einträge der Bereichsübersichten verlinken jetzt auf die Seiten.
|
|
1496
|
-
- **Video-Embed (Beispielseite Identity mit Keycloak)**: Zwei responsive YouTube-Embeds
|
|
1497
|
-
(`youtube-nocookie.com`, 16:9 via `aspect-ratio`, `title`, kein Autoplay, `loading="lazy"`). Referenzen
|
|
1498
|
-
(Social Proof) direkt nach der Lösung plus Mid-Page-CTA; Abschnitts-Hintergründe neu alterniert.
|
|
1499
|
-
- **Doku · Page-Pattern „Angebots-Detailseite“** (`#sec-leistung-detail`): Aufbau (Sektionsreihenfolge nach
|
|
1500
|
-
Funnel-Logik), Angebots-Box (Festpreis-Box + „Für wen“), Preismodelle (Festpreis / mehrere Pakete /
|
|
1501
|
-
Beratung ohne Festpreis), Cross-Links und Verwendung (Do/Don't).
|
|
1502
|
-
- **Doku · Barrierefreiheit „Video-Embed“** (`#gt-a11y-video`): `title`, Untertitel (WCAG 1.2.2),
|
|
1503
|
-
Transkript/Audiodeskription, kein Autoplay, responsiv, Datenschutz, Sprach-Kennzeichnung, Tastatur;
|
|
1504
|
-
inklusive Abgrenzung, was das DS liefert vs. was die Videoquelle liefern muss.
|
|
1505
|
-
- **KI-Wissensbeitrag (Beispielseite): Contentletter- + LinkedIn-CTA**: Nach „Weiterlesen“ und vor dem
|
|
1506
|
-
finalen CTA-Band ein „Dranbleiben“-Block als offene Feature-Liste (`.ep-feature`, zwei `col-6`): „Food
|
|
1507
|
-
for your brain!“ (Contentletter-Anmeldung) und „Stay connected!“ (LinkedIn-Folgen, externer Link mit
|
|
1508
|
-
`target="_blank"`/`aria-label`). Bewusst als flache Feature-Liste statt Karte/Band, um sich vom Download-
|
|
1509
|
-
`.cta-dl` darüber abzuheben, ohne die Seite weiter zu verkasten. Corporate-Akzent (unternehmensweit).
|
|
1510
|
-
- **`.card-cta-link` als echter Link nutzbar**: `a.card-cta-link` ohne Default-Underline (Underline erst
|
|
1511
|
-
bei Hover), sichtbarer Fokus-Ring; gescoped auf `a[…]`, damit die `<span>`-Nutzung in klickbaren
|
|
1512
|
-
`.ep-card-link`-Karten unberührt bleibt.
|
|
1513
|
-
- **Farb-Swatches: Hex-Anzeige + Klick-zum-Kopieren** (Doku): In der Tonal-Palette (`#sec-colors`)
|
|
1514
|
-
zeigt jeder Swatch zusätzlich zum Stufen-Label seinen Hex-Code (kontrastgleich zur Stufen-Schrift,
|
|
1515
|
-
für die Nutzung in anderen Gestaltungsmitteln). Jeder Swatch und jede Farb-Clip-Card kopiert per
|
|
1516
|
-
Klick oder Tastatur (Enter/Space) den Hex in die Zwischenablage (`navigator.clipboard`, Fallback
|
|
1517
|
-
`execCommand`). Barrierefrei: `role="button"`, `tabindex`, `aria-label`, sichtbarer Inset-Fokus-Ring
|
|
1518
|
-
(nicht vom `overflow:hidden` der `.pal-row` abgeschnitten), `aria-live`-Bestätigung + „✓“-Overlay.
|
|
1519
|
-
In den schmalen Bereichs-Übersichtskarten (`#sec-areas`) bleibt der Hex aus Platzgründen im
|
|
1520
|
-
title-Tooltip, Kopieren funktioniert dort ebenso.
|
|
1521
|
-
- **Icon-Bibliothek** als maschinenlesbarer Export: `icons/icons.json` · `icons.js`
|
|
1522
|
-
(kompletter `<svg>`-Body pro Key, `currentColor`, Stil-Markierung `solid`/`outline`,
|
|
1523
|
-
`viewBox`, Verwendungskontext) + kuratierte Quelle `icons/source/*.svg`, generiert via
|
|
1524
|
-
`scripts/build-icons.mjs` (`npm run build:icons`, jetzt Teil von `npm run build`).
|
|
1525
|
-
Neue Exports `@conciso/design-system/icons` · `/icons.json`; Mapping/Consumption in
|
|
1526
|
-
`icons/README.md`. Vier Solid-Bereichs-Glyphen (`ki-bot`, `es-window-check`,
|
|
1527
|
-
`wo-network`, `co-building`) + generische Outline-UI-Icons.
|
|
1528
|
-
- **Dropdown-Komponenten**: `.ep-select` (Custom Select mit Listbox-A11y, Bereichs-Akzent)
|
|
1529
|
-
und `.ep-combobox` (Tipp-Filter über langen Listen; `.is-multi` für Multi-Select mit
|
|
1530
|
-
entfernbaren Chips), inkl. Lösch-Button und Filter-Reset beim Schließen.
|
|
1531
|
-
- **Topnav-Aktionen**: Such-Popover (Disclosure, A11y) + Light/Dark-Umschalter
|
|
1532
|
-
(`aria-pressed`, synchron mit dem Sidebar-Switch), per JS in jede `.ep-topnav` injiziert.
|
|
1533
|
-
- **Responsive Grid-Marker** für gezielt mehrspaltige Mobile/Tablet-Layouts (statt der
|
|
1534
|
-
einspaltigen Default-Kollabierung): `data-team-tiles` (2×2), `data-team-roster` (2 Spalten
|
|
1535
|
-
≤ 520 px / 3 Spalten 521–768 px), `data-benefits` und `data-event-meta` (2×2 auf Tablet /
|
|
1536
|
-
1-spaltig ≤ 520 px). Alle auf `.layout-grid` gesetzt.
|
|
1537
|
-
|
|
1538
|
-
- **Editoriale „Im Detail“-Sektion** auf der Beispielseite Wirksame Organisationen: offene
|
|
1539
|
-
Feature-Liste (`.ep-feature`, Alternative zu Karten) mit bis zu 8 Themen-Landingpages, Status
|
|
1540
|
-
über die Aktionszeile (Link „Zur Landingpage“ bei verfügbaren, „Landingpage folgt“ bei in-Aufbau,
|
|
1541
|
-
ohne toten Link), plus content-breites Akzentbild als Sektions-Auftakt.
|
|
1542
|
-
- **Bereichsvariante `.card-cta-link[data-area="co|ki|es|wo"]`**: färbt den Text-CTA-Link in der
|
|
1543
|
-
Akzentfarbe statt Corporate-Teal (Shades wie `.ep-card-cta`), inkl. Dark-Overrides (`-200/-100`).
|
|
1544
|
-
|
|
1545
|
-
### Changed
|
|
1546
|
-
- **Preis und Rahmendaten stehen jetzt direkt nach dem Hero** (Beispielseite Seminar): Die
|
|
1547
|
-
Lernziele-Sektion ist zweispaltig geworden, links die Bullet-Liste (`.col-8`), rechts der
|
|
1548
|
-
Angebots-Kasten (`.col-4`, sticky). Gemessen rückt der Preis von **45 % auf 10 %** der Seitenhöhe.
|
|
1549
|
-
Bewusst kein neuer Streifen unter dem Header, sondern der vorhandene Kasten neben dem ersten Inhalt.
|
|
1550
|
-
Das Kontaktformular bleibt, wo es war, bei „Inhalte & Voraussetzungen“; beide Kästen tragen dadurch
|
|
1551
|
-
je eine Aufgabe. Dazu eine Zwei-Spalten-Variante der Rahmendaten (`.ep-facts.is-grid`): Einspaltig
|
|
1552
|
-
war der Kasten 470 px hoch gegen 256 px Inhalt daneben, also 214 px Leerraum. Zweispaltig sind es
|
|
1553
|
-
299 px und 43 px Leerraum. Die Variante verzichtet auf die Haarlinien und wird über `auto-fit` in
|
|
1554
|
-
schmalen Kästen von selbst wieder einspaltig.
|
|
1555
|
-
- **Fakten-Streifen aufgelöst, Angaben ziehen in den vorhandenen Kasten** (`.ep-facts`): Der flache
|
|
1556
|
-
Key-Facts-Streifen unter dem Hero entfällt auf allen vier Angebots-/Seminar-Landings. Die Angaben
|
|
1557
|
-
bleiben vollständig erhalten und stehen jetzt dort, wo über das Angebot entschieden wird, statt an
|
|
1558
|
-
zwei Stellen. Neu ist dafür `.ep-facts`, eine einspaltige `<dl>` aus Label/Wert-Paaren
|
|
1559
|
-
mit Haarlinie dazwischen, **ohne eigenen Rahmen**: sie zieht in einen Container ein, den die Seite
|
|
1560
|
-
schon hat (Angebots-Box, Sticky-Sidebar), sonst entstünde Kasten im Kasten. Damit verschwinden auch
|
|
1561
|
-
die viermal kopierten Inline-Styles des alten Streifens.
|
|
1562
|
-
Pro Seite: *Seminar* → Dauer, Format, Gruppe und Sprache in die Sticky-Sidebar (der dortige separate
|
|
1563
|
-
Sprache-Block entfällt, die Dublette zum Streifen ist damit weg). *Meetingflut* und
|
|
1564
|
-
*Keycloak-Erweiterungen* → **keine** Liste, ihre Angebots-Box nannte Laufzeit, Leistung, Ergebnis und
|
|
1565
|
-
Preis bereits vollständig, der Streifen war dort reine Dopplung. *Scrum Trainings* → eigener Kasten
|
|
1566
|
-
einmal über den vier Preiskarten, weil die Angaben für alle vier gelten und die Seite keine
|
|
1567
|
-
Angebots-Box hat.
|
|
1568
|
-
- **`data-accent` ist nicht mehr an `.ep-page` gebunden**: Die Akzent-Regeln für `.t-co` und
|
|
1569
|
-
`.body-link` sowie die Chrome-Resets für Footer und Topnav laufen jetzt über `[data-accent="…"]`
|
|
1570
|
-
statt `.ep-page[data-accent="…"]` (Light und Dark). Damit kann auch ein einzelner Block einen
|
|
1571
|
-
Bereichs-Scope aufspannen, etwa ein Buchungsformular, eine Anmeldesektion oder ein
|
|
1572
|
-
Bereichsformular in einer sonst corporate Seite, ohne Inline-Bereichsfarben an den Links (die im
|
|
1573
|
-
Dark-Mode brechen würden). Abwärtskompatibel: die bestehenden `.ep-page[data-accent]`-Seiten
|
|
1574
|
-
treffen den neuen Selektor unverändert.
|
|
1575
|
-
- **Topnav: Submenüs öffnen zusätzlich per Hover**: Auf Geräten mit echtem Hover (`pointer:fine`) klappt
|
|
1576
|
-
das Submenü jetzt auch beim Überfahren des Top-Items auf (JS-gesteuert, kurzer Intent-Delay beim Öffnen,
|
|
1577
|
-
verzögertes Schließen + unsichtbare Brücke über den Gap → WCAG 1.4.13 „hoverable/dismissible/persistent“).
|
|
1578
|
-
Klick/Tap, Tastatur und Touch bleiben unverändert; der Label-Klick navigiert weiterhin direkt zur
|
|
1579
|
-
Übersicht (kein erzwungener 2-Klick). Der Reveal hängt weiter an `.is-open` (kein reines CSS-`:hover`),
|
|
1580
|
-
`aria-expanded` läuft mit, `closeAllNavItems` verhindert zwei gleichzeitig offene Menüs. Escape schließt
|
|
1581
|
-
jetzt auch ein rein per Hover geöffnetes Menü.
|
|
1582
|
-
- **Topnav: Top-Level-Parents als Link zur Übersicht (Split „Link + Caret-Disclosure“)**: „Angewandte KI“,
|
|
1583
|
-
„Leistungen“ und „Unternehmen“ sind jetzt echte `<a>`-Links auf ihre Übersichtsseite (`data-ep` = erstes
|
|
1584
|
-
Submenü-Ziel), statt reiner Aufklapp-Buttons. Ein **separater Caret-`<button>`** (`.ep-nav-item-toggle`,
|
|
1585
|
-
`aria-expanded`/`aria-controls`) öffnet das Submenü per Klick/Tastatur. UX: 1 Klick zur Übersicht statt
|
|
1586
|
-
Umweg über den „Übersicht“-Dropdown-Eintrag; A11y: eigene Caret-Hit-Area ≥ 24 px (WCAG 2.5.8) + Fokus-Ring,
|
|
1587
|
-
mobil Link + Caret in einer Zeile mit ≥ 44 px Tap-Fläche. Der nicht-farbige Aktiv-Unterstrich (WCAG 1.4.1)
|
|
1588
|
-
sitzt jetzt am Parent-Link. Über alle Beispielseiten + Doku (`#gt-nav-topnav`) konsistent umgesetzt.
|
|
1589
|
-
- **KI-Wissensbeitrag „Weiterlesen“: aktuelle Artikel-Cards** statt der alten `.ep-card`-Textkarten:
|
|
1590
|
-
jetzt `.card.card-elevated` mit 16:9-Bild, `.pill`-Bereichslabel, `.card-title` und gepinntem
|
|
1591
|
-
`.card-cta-link`, im `.layout-grid` (col-4) — identisch zur Beitragsübersicht (`ep-wb-uebersicht`).
|
|
1592
|
-
- Topnav-Icon-Buttons und Hamburger auf 48 × 48 px (Touch-Target AAA, WCAG 2.5.5).
|
|
1593
|
-
- Icon-Doku (`#sec-icons`): Solid-Bereichs-Glyphen vs. Outline-UI-Icons klargestellt
|
|
1594
|
-
(vorherige „nur Outline“-Aussage war unzutreffend); Verweis auf die Icon-Bibliothek.
|
|
1595
|
-
- **Headline/Display-Tokens fluid**: `--ty-headline-xs/sm/md` und `--ty-display-sm/md` nutzen
|
|
1596
|
-
jetzt `clamp()` mit unitless Ratio-Zeilenhöhe (Mirror von `--ty-display-lg`). Desktop-Maxima
|
|
1597
|
-
unverändert, Minima ≥ 20 px greifen am Phone. Typografie-Doku entsprechend aktualisiert.
|
|
1598
|
-
- **Responsive-Überarbeitung der Beispielseiten** (3 Stufen: ≤ 520 px Phone · 521–768 px Tablet ·
|
|
1599
|
-
> 768 px Desktop):
|
|
1600
|
-
- Section-Innenabstand mobil 32 → 24 px (`--s6`); Hero-CTAs stapeln full-width erst ≤ 520 px
|
|
1601
|
-
(vorher 768 px, lief auf Phablet zu breit).
|
|
1602
|
-
- `.layout-grid` setzt beim Kollabieren die `col-N`-Spannweiten zurück, sodass ungleiche Splits
|
|
1603
|
-
(z. B. `col-7`/`col-5`) gleich breit stapeln (vorher wurde das Bild schmaler).
|
|
1604
|
-
- Mobile-Topnav: Burger als äußerstes rechtes Element (kein Positionssprung beim Öffnen).
|
|
1605
|
-
- `.team-voice` mobil als Pull-Quote (Quote-Icon im linken Gutter statt eigener Zeile);
|
|
1606
|
-
`.card`-`min-height` (2lh/3lh, nur für Grid-Gleichhöhe) entfällt einspaltig; `.ep-award-list`
|
|
1607
|
-
als 2×2 statt versetztem Flex-Wrap; `.article-avatar-xl` mobil spaltenrelativ (max. 112 px).
|
|
1608
|
-
- **Doku-Shell**: `.ds-sidebar` wird ≤ 1024 px ausgeblendet (Content full-width), damit die
|
|
1609
|
-
Beispielseiten die echte Fensterbreite einnehmen und ihre viewport-`@media`-Queries korrekt
|
|
1610
|
-
greifen — Voraussetzung für faithful Mobile/Tablet-Vorschau.
|
|
1611
|
-
- **Effektive-Software-Hero**: neues, thematisch passenderes Motiv (Entwickler, Laptop-Sticker
|
|
1612
|
-
Clean Code / Keycloak / Jakarta EE / Docker); web-optimiert (5000 px/5,1 MB → 2000 px/411 KB).
|
|
1613
|
-
- **Typografie durchgängig rem-basiert (WCAG 1.4.4 „Resize Text“)**: Alle `--ty-*`-Tokens, die
|
|
1614
|
-
15 `.type-*`-Utilities und die hartcodierten Schriftgrößen in `base.css`/`components.css` von
|
|
1615
|
-
`px` auf `rem` umgestellt (Basis `1rem = 16px`). Die fluiden `clamp()`-Tokens nutzen jetzt
|
|
1616
|
-
`rem`-Min/Max und einen `rem + vw`-Mittel-Term (Zwei-Anker-Fluid-Kurve), sodass Schrift auch
|
|
1617
|
-
auf die Browser-Standardschriftgröße reagiert, nicht nur auf Seiten-Zoom. `body` von `16px`
|
|
1618
|
-
auf `1rem`. Desktop-Rendering pixelidentisch (Maxima unverändert). Ausnahme: SVG-Text
|
|
1619
|
-
(`.bw-label-*`) bleibt px (skaliert übers `viewBox`). Token-Exporte via `npm run build:tokens`
|
|
1620
|
-
regeneriert. Neuer Doku-Abschnitt zur medienübergreifenden Nutzung (Web/Print/PowerPoint, px↔pt).
|
|
1621
|
-
|
|
1622
|
-
### Fixed
|
|
1623
|
-
- **Seminar-Sidebar in zwei Kästen geteilt**: Seit dem Umzug der Rahmendaten trug der eine Kasten zwei
|
|
1624
|
-
Aufgaben, Nachschlage-Information und Kontaktformular, und die Formular-Überschrift saß als gefüllter
|
|
1625
|
-
Bereichsbalken mitten im Element. Das las sich wie zwei zusammengeklebte Karten. Jetzt zwei Kästen mit
|
|
1626
|
-
Abstand: oben Angebot und Rahmendaten, darunter das Formular mit seinem Balken dort, wo eine
|
|
1627
|
-
Kartenüberschrift hingehört. Sticky-Verhalten und Formular unverändert.
|
|
1628
|
-
- **Rohe `var(--n-200)`-Rahmen auf `var(--bd-strong)` umgestellt** (Seminar-Sidebar, adaptive
|
|
1629
|
-
Kontaktseite, vier Stellen): `--n-200` flippt im Dark nicht und ergab dort einen grellen `#C9D3D3`-Rahmen.
|
|
1630
|
-
`--bd-strong` ist im Light derselbe Ton, im Dark `#9DA8B6`. Entspricht der Konvention „nie rohes
|
|
1631
|
-
`-100`/`-200` als Border“.
|
|
1632
|
-
- **Falsches Bereichs-Icon auf fünf Verweiskarten**: Karten, die auf eine Bereichs-Übersicht
|
|
1633
|
-
verlinken, tragen das Marken-Glyph des Bereichs (`ki-bot`, `es-window-check`, `wo-network`,
|
|
1634
|
-
solid, eingefärbt über `.ep-card-icon.t-XX`). Zehn Karten hielten sich daran, fünf nicht: die
|
|
1635
|
-
„Weiter im Thema“-Blöcke der Angebots-Detailseiten (Meetingflut, Scrum, LPM, Keycloak,
|
|
1636
|
-
Keycloak-Erweiterungen) zeigten ein generisches Heroicon mit inline gesetztem
|
|
1637
|
-
`stroke="var(--XX-700)"` statt des Glyphs. `icons/README.md` hatte die Regel nur für
|
|
1638
|
-
`/leistungen` und die Landingpage notiert; sie hängt jetzt am Anlass statt an einzelnen Seiten,
|
|
1639
|
-
mit ausdrücklicher Abgrenzung zu den thematischen Outline-Icons inhaltlicher Karten.
|
|
1640
|
-
- **Hover bereichsgetönter Body-Links war im Dark Mode unlesbar**: In einem `data-accent`-Container
|
|
1641
|
-
sprang `.body-link:hover` auch im Dark auf den `-800`-Ton, also dunkel auf dunkel. Gemessen:
|
|
1642
|
-
`wo-800` auf `bg-page` = **1,17:1**, `es-800` = 1,29:1, weit unter der AA-Schwelle von 4,5:1. Der
|
|
1643
|
-
Link verschwand beim Überfahren praktisch. Ursache: Die Light-Regel `[data-accent="wo"]
|
|
1644
|
-
.body-link:hover` hat dieselbe Spezifität wie die Dark-Grundregel, und `components.css` wird nach
|
|
1645
|
-
`dark-mode.css` geladen. Für den generischen `.body-link:hover` gab es den Dark-Override bereits,
|
|
1646
|
-
für die drei Bereichsvarianten fehlte er. Jetzt ergänzt (`-100`, also heller statt dunkler, analog
|
|
1647
|
-
zur bestehenden Regel): `wo-100` = 8,4:1, `es-100` = 7,6:1, `ki-100` entsprechend.
|
|
1648
|
-
Ein systematischer Durchgang durch **alle** `:hover`-Regeln mit dunklen Tokens fand denselben Fehler
|
|
1649
|
-
ein zweites Mal: der Chrome-Reset `[data-accent] .footer .body-link:hover` sprang im Dark auf
|
|
1650
|
-
`co-800`, **1,97:1** → jetzt `co-100` = 14,3:1.
|
|
1651
|
-
- **Chip-Hover lief im Dark Mode rückwärts**: Der Rand nutzt beim Überfahren die kräftigeren
|
|
1652
|
-
`-500`/`-600`/`-700`-Töne. Im Dark sind das die dunkleren, der Rand wurde also schwächer statt
|
|
1653
|
-
kräftiger und die Affordanz kehrte sich um (`ki` ruhend `-400` #BEE82D → hover `-700` #6B8208).
|
|
1654
|
-
Kein AA-Verstoß (alle Werte blieben über der 3:1-Schwelle für Nicht-Text), aber falsch herum.
|
|
1655
|
-
Dark-Overrides ergänzt, jeweils eine Stufe heller als der Ruhezustand: co `-200`, ki `-300`,
|
|
1656
|
-
es `-200`, wo `-200`.
|
|
1657
|
-
- **Gedrückter Chip war im Dark Mode kaum vom Grund zu unterscheiden**: Die Füllung `n-700` ergab
|
|
1658
|
-
gegen `bg-page` nur **1,60:1**, der ausgewählte Zustand war praktisch nur am weißen Text erkennbar.
|
|
1659
|
-
Er invertiert jetzt wie das Segmented Control, das dieses Muster im System bereits vorgibt
|
|
1660
|
-
(`--seg-fill` `-300` mit `--seg-on` `-900`): helle Füllung `n-300` mit dunklem Text `n-900`,
|
|
1661
|
-
Hover eine Stufe heller statt dunkler. Gemessen: Text auf Füllung 8,62:1, Füllung gegen Seite
|
|
1662
|
-
4,85:1. Light bleibt unverändert bei `n-700` mit weißem Text.
|
|
1663
|
-
- **Drei weitere dunkel-auf-dunkel-Zustände**, gefunden durch den neuen Check statt durch Zufall:
|
|
1664
|
-
der Hover-Rand des neutralen Chips (`n-400`, 2,79:1 und dunkler als der Ruhe-Rand → `n-200`) und
|
|
1665
|
-
der Pause-Knopf im Logo-Karussell (`n-700`, **1,60:1** → `n-100`). Offen bleibt der gedrückte Chip:
|
|
1666
|
-
seine Füllung ist im Dark eine sehr dunkle Fläche auf dunklem Grund. Der Zustand ist über den
|
|
1667
|
-
weißen Text erkennbar, die sauberere Lösung wäre eine helle Füllung im Dark — das ist aber eine
|
|
1668
|
-
Gestaltungsentscheidung und steht als dokumentierte Ausnahme im Check.
|
|
1669
|
-
- **Vergleichstabelle (`.ep-compare-*`) Dark-Mode-Kontrast**: Summary, ✓-Glyph (`.ep-compare-yes`) und
|
|
1670
|
-
- **Segmented Control trug in Bereichsformularen Corporate**: `.seg-option input:checked + label` war
|
|
1671
|
-
fest auf `--co-700` verdrahtet. Ein KI-, ES- oder WO-Formular bekam dadurch mitten zwischen seinen
|
|
1672
|
-
Feldern einen Corporate-Akzent und trug zwei Brand Areas gleichzeitig, entgegen der eigenen Regel
|
|
1673
|
-
„ein Formular gehört zu genau einer Brand Area“.
|
|
1674
|
-
- **Links im Buchungsformular blieben Corporate**: Die Inhouse-Anfrage im Helper und die beiden
|
|
1675
|
-
Consent-Links standen auf `--co-700`, obwohl der Abschnitt genau zwei bewusste Corporate-Reste
|
|
1676
|
-
ausweist (Fokusring, Feldrahmen im Fokus). Ursache war der fehlende Akzent-Scope: die Demo hängt
|
|
1677
|
-
in einer Doku-Karte, nicht in einer `.ep-page`. Der Wrapper trägt jetzt `data-accent="ki"`.
|
|
1678
|
-
- **Consent-Links waren `<span>` statt Anker**: Die verlinkten Datenschutz- und Bedingungs-Hinweise in
|
|
1679
|
-
den Einwilligungs-Checkboxen waren nicht per Tab erreichbar und wurden von Screenreadern nicht als
|
|
1680
|
-
Link angesagt, obwohl genau dieser Text die Grundlage der Einwilligung ist. Jetzt durchgehend echte
|
|
1681
|
-
`<a class="body-link">`: Buchungsformular (2×), beide Newsletter-Varianten und die Event-Anmeldung,
|
|
1682
|
-
die als dritte Variante ein `<span class="t-es">` mit `text-decoration:underline` trug. Als
|
|
1683
|
-
**systemweite Regel** dokumentiert (Inputs & Forms, Zeile „Link im Label“, plus Do/Don't-Paar und
|
|
1684
|
-
CONTRIBUTING § 8); die A11y-Zeile des Buchungsformulars verweist darauf. Die Übergabe-Tabelle
|
|
1685
|
-
„Für die Umsetzung“ fordert zusätzlich echte Ziele für die Rechtstexte (die Demos tragen `href="#"`)
|
|
1686
|
-
und ein Öffnen ohne Formularverlust.
|
|
1687
|
-
- **Bereichsformulare tönten ihren Consent-Link nicht**: Neben dem Buchungsformular betraf das die
|
|
1688
|
-
Event-Anmeldung (Sektion `#ev-anmeldung` trägt jetzt `data-accent="es"`) und die adaptive
|
|
1689
|
-
Kontaktseite, wo `applyKontaktContext()` Header, Button und Häkchen umtönte, den Datenschutz-Link
|
|
1690
|
-
im Consent-Label aber corporate ließ. Das Attribut sitzt dort am `<form>`, nicht an der Karte:
|
|
1691
|
-
Telefon, E-Mail und Maps-Link daneben sind Unternehmens-Kontaktdaten und bleiben Corporate.
|
|
1692
|
-
Bei `co` wird es entfernt, Corporate ist der Default.
|
|
1693
|
-
- **Bereichs-CTAs aus der Doku verloren ihren Kontext**: Der globale Anker-Handler rief
|
|
1694
|
-
`activateExamplePage(epKey)` ohne Kontext-Objekt, anders als der `ep-page`-Handler. Ein Link mit
|
|
1695
|
-
`data-k-bereich`/`data-k-anliegen` außerhalb einer Beispielseite (etwa „Inhouse-Termin anfragen“
|
|
1696
|
-
im Buchungsformular) landete deshalb auf der neutralen Kontaktseite: keine Tönung, kein
|
|
1697
|
-
vorbelegtes Thema, kein Anliegen. Beide Pfade geben den Kontext jetzt gleich weiter.
|
|
1698
|
-
- **`.helper` verfehlte AA im Dark Mode**: Hilfetexte unter Feldern nutzten `--tx-muted`, das auf
|
|
1699
|
-
`--bg-surface` nur 4,1:1 erreicht (die Kontrast-Tabelle dokumentiert das dort ausdrücklich als
|
|
1700
|
-
„Large Text / Non-Text“). Umgestellt auf `--tx-secondary`: 6,3:1 Light, 4,9:1 Dark. Betrifft alle
|
|
1701
|
-
Formulare mit Hilfetext.
|
|
1702
|
-
- **Fehlerrahmen an Select und Textarea**: `.field.has-error` färbte nur `input` rot, ein fehlerhaftes
|
|
1703
|
-
Pflicht-Select blieb optisch unmarkiert. Regel um `select` und `textarea` erweitert.
|
|
1704
|
-
- **`--c-error` verfehlte AA im Dark Mode auf `bg-surface`**: `#FF8E8E` war nur gegen `--bg-page`
|
|
1705
|
-
geprüft (4,9:1). Inline-Fehlertext sitzt aber fast immer in einer Formularkarte auf `--bg-surface`,
|
|
1706
|
-
dort waren es 4,0:1 bei 12 px. Angehoben auf `#FFA5A5`: 5,9:1 auf bg-page, 4,75:1 auf bg-surface.
|
|
1707
|
-
Betrifft alle Fehlermeldungen, Required-Sternchen und ✕-Marker im Dark Mode.
|
|
1708
|
-
|
|
1709
|
-
der „Pro“-Header (`thead .ep-compare-pro`) nutzten rohes `co`/`ki`-`800` (`--ki-800` #475705), das im
|
|
1710
|
-
Dark nicht mitflippt → dunkel-auf-dunkel (Core-Spalte auf `bg-page`, Pro-Spalte auf `--ki-50` #2A3411,
|
|
1711
|
-
Häkchen faktisch unsichtbar). Dark-Override ergänzt: ✓ und Pro-Header auf `--ki-100`, Summary auf
|
|
1712
|
-
`--ki-200` (Hover `--ki-100`), analog zum bestehenden `.ep-feature-icon`/`.ep-tier-label`-Muster.
|
|
1713
|
-
Light-Mode unverändert.
|
|
1714
|
-
- **Hover-Farben auf `--tx-primary`-Text im Dark (`.footer-link`, `.article-toc`)**: Der Hover sprang auf
|
|
1715
|
-
`--co-700`, das im Dark nicht flippt → der Link wurde beim Hovern dunkler statt heller (dunkel-auf-dunkel).
|
|
1716
|
-
Dark-Override auf `--co-200` ergänzt (`.footer-link:hover`, `.article-toc-summary:hover`,
|
|
1717
|
-
`.article-toc-list a:hover`), konsistent mit `.body-link:hover`. Light-Mode unverändert.
|
|
1718
|
-
- **`.cta-dl[data-area="co"]` Eyebrow-Kontrast (Light)**: `co-600` (#009E9E, 3,28:1, Uppercase-Label < AA)
|
|
1719
|
-
auf `co-700` (5,5:1) → jetzt konsistent mit ki-800/es-700/wo-700. Dark-Override (`co-200`) unverändert.
|
|
1720
|
-
- **Fokus-Ring global kontraststark (`--focus-ring` / `--focus-aa`)**: sichtbarer Ring im Light-Mode
|
|
1721
|
-
von `co-500` (#00BEBE, nur 2,3:1 auf Weiß) auf `co-700` (#007575, 5,5:1) → erfüllt die 3:1-Schwelle
|
|
1722
|
-
für Fokus-Indikatoren (WCAG 2.4.11). Gilt systemweit, da alle `:focus-visible`-Ringe diese zwei Tokens
|
|
1723
|
-
nutzen. Dark-Mode unverändert `co-500` (dort 4,7:1 auf dunklem Grund; `co-700` wäre dunkel-auf-dunkel).
|
|
1724
|
-
- **Doku-Sidebar Struktur-Semantik**: Gruppen-Labels (`.nav-section`) sind jetzt `<h2>` (Screenreader-
|
|
1725
|
-
Outline der Navigation), und die Einträge jeder Gruppe liegen in `<ul class="nav-list">` mit
|
|
1726
|
-
`aria-labelledby` auf das Gruppen-Heading (Ansage „Gruppe, Liste, N Einträge“). Reine Semantik-/
|
|
1727
|
-
Markup-Änderung, Optik und JS unverändert.
|
|
1728
|
-
- **Doku-Sidebar (`.nav-item`) barrierefrei**: (1) aktiver Eintrag-Text von `co-500` (#00BEBE auf
|
|
1729
|
-
`co-50` nur 2,07:1) auf `co-700` (4,95:1) → WCAG 1.4.3; Akzentbalken auf `co-600` (3,28:1, WCAG 1.4.11).
|
|
1730
|
-
(2) `aria-current="page"` am aktiven Eintrag (statisches Markup + synchron in `activateSection`),
|
|
1731
|
-
sodass der aktive Bereich nicht mehr nur farblich, sondern programmatisch erkennbar ist (4.1.2).
|
|
1732
|
-
Zustand zusätzlich über `font-weight` (nicht nur Farbe, WCAG 1.4.1). Dark-Mode: aktiver Text/Balken
|
|
1733
|
-
auf `co-200`/`co-300` (auf dem dort fast schwarzen `co-50`).
|
|
1734
|
-
- **Bereichs-Chips (`.chip[data-area="co"]`) Rahmenkontrast**: Corporate-Rahmen von `co-500`
|
|
1735
|
-
(#00BEBE, nur 2,3:1 auf Weiß) auf `co-600` (#009E9E = 3,28:1) angehoben → erfüllt die
|
|
1736
|
-
Nicht-Text-Schwelle WCAG 1.4.11 (Default + Hover). Bleibt heller als der `co-700`-Text, das
|
|
1737
|
-
Zwei-Ton-Prinzip (Rahmen 3:1 / Text 4,5:1) bleibt erhalten. ki/es/wo lagen bereits ≥ 3:1;
|
|
1738
|
-
Dark-Mode (`co-300`, 4,8:1) unverändert.
|
|
1739
|
-
- **Light/Dark-Umschalter (`.theme-bar`) barrierefrei & konsistent**: (1) aktive Fläche von
|
|
1740
|
-
`co-500` auf `co-700` umgestellt, weißer Text erreicht AA (2,3:1 → 5,5:1); (2) Unicode-Glyphen
|
|
1741
|
-
(☀ / ◑) durch dieselben Heroicons-SVGs (Sonne / Sichelmond) wie der Topnav-Umschalter ersetzt,
|
|
1742
|
-
je `aria-hidden="true"`; (3) `aria-pressed` ins statische Markup (vorher nur per JS).
|
|
1743
|
-
- **Slider-Wertanzeige (`.field-slider-output`) barrierefrei**: (1) Textfarbe von der hellen
|
|
1744
|
-
Thumb-Farbe (`--sl-color`) entkoppelt (neues `--sl-text`), Wert nutzt jetzt dunklere Töne
|
|
1745
|
-
`co-700`/`ki-800`/`es-700`/`wo-700` → AA im Light-Mode (co 2,3:1, wo 3,3:1, ki 4,35:1 → 5,5–9,6:1),
|
|
1746
|
-
Thumb bleibt in Markenfarbe; (2) `aria-valuetext` an allen Slidern (initial + im `oninput`
|
|
1747
|
-
synchronisiert), damit Screenreader „50.000 €“ / „60 %“ statt der Rohzahl ansagen.
|
|
1748
|
-
- **Beispielseiten-Chips (`.ep-tab`) barrierefrei**: (1) aktiver Chip von `co-500` auf `co-700`
|
|
1749
|
-
umgestellt, weißer Text erreicht damit AA (2,3:1 → 5,5:1); (2) Touch-Target auf `min-height:44px`
|
|
1750
|
-
bzw. 44 × 44 px beim Aufklapp-Toggle (WCAG 2.5.5, analog `.btn`); (3) Rahmen von `--n-200` auf
|
|
1751
|
-
das modusabhängige `--field-border` (WCAG 1.4.11: Light-Mode 1,5:1 → 3,9:1, Dark unverändert 5,8:1).
|
|
1752
|
-
|
|
1753
|
-
## [0.1.0] - 2026-06-25
|
|
1754
|
-
|
|
1755
|
-
### Added
|
|
1756
|
-
- Onboarding-/Governance-Doku: `README.md`, `CONTRIBUTING.md` (Konventionen),
|
|
1757
|
-
`LICENSE`, dieses `CHANGELOG.md`, `docs/GETTING-STARTED.md`.
|
|
1758
|
-
- npm-Paketierung (`@conciso/design-system`, `package.json` mit `exports`/`files`).
|
|
1759
|
-
- Token-Export `tokens/tokens.json` · `.scss` · `.js` (generiert aus `tokens.css`
|
|
1760
|
-
+ Dark-Overrides, `var(...)` aufgelöst) via `scripts/build-tokens.mjs`.
|
|
1761
|
-
- Gebündeltes `dist/conciso-ds.css` (korrekte Ladereihenfolge) via
|
|
1762
|
-
`scripts/bundle-css.mjs`. `npm run build` erzeugt beides.
|
|
1763
|
-
- **Self-Host-Fonts** (DSGVO): `fonts/` (Montserrat + Libre Baskerville, woff2,
|
|
1764
|
-
Subsets latin + latin-ext) + `css/fonts.css` (`@font-face`, `font-display:swap`),
|
|
1765
|
-
inkl. OFL-Lizenztexte. Doku-Site und Bundle nutzen jetzt lokale Fonts statt
|
|
1766
|
-
Google-CDN — verifiziert: 0 Anfragen an googleapis/gstatic.
|
|
1767
|
-
|
|
1768
|
-
### Changed
|
|
1769
|
-
- Repo-Hygiene: Doku-Site vom konsumierbaren Kern getrennt. `index.html`,
|
|
1770
|
-
`main.js` und Bilder liegen jetzt unter `docs/` (Bilder in `docs/assets/images/`);
|
|
1771
|
-
Pfade in `docs/index.html` entsprechend angepasst. Der Kern (`css/`, `dist/`,
|
|
1772
|
-
`tokens/`) bleibt im Root.
|
|
1773
|
-
- Distribution: **intern/proprietär** statt Registry-Publish. `package.json`
|
|
1774
|
-
`license: "UNLICENSED"` + `private: true`; `publishConfig` und der
|
|
1775
|
-
Release-Workflow (`.github/workflows/release.yml`) entfernt. Nutzung über
|
|
1776
|
-
eingebundenes/kopiertes `dist/conciso-ds.css` oder gepinnte Git-Tags
|
|
1777
|
-
(`npm install github:conciso/conciso-design-system#vX.Y.Z`). `LICENSE` auf
|
|
1778
|
-
einen kurzen internen Hinweis eingedampft (Font-OFL-Verweise bleiben).
|
|
1779
|
-
|
|
1780
|
-
---
|
|
1781
|
-
|
|
1782
|
-
Frühere Arbeit (vor formaler Versionierung) ist in der Git-Historie
|
|
1783
|
-
dokumentiert: Aufbau der Foundations (Tokens, Typografie 16/14/12, Spacing,
|
|
1784
|
-
Elevation), Komponentenbibliothek, vollständiger Light/Dark-Mode mit
|
|
1785
|
-
WCAG-AA-Kontrasten, Beispielseiten und die navigierbare Doku-Site.
|
|
1786
|
-
Die erste getaggte Version markiert den Start der paketierten Distribution.
|