@conciso/design-system-mcp 2.4.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 +1 -0
- package/package.json +1 -1
- package/snapshot/manifests/components.json +20 -0
- package/snapshot/manifests/docs.json +1 -1
- package/snapshot/services/addon-docs/mdx/grundlagen-farben.json +18 -0
- package/snapshot/services/addon-docs/mdx/grundlagen-typografie.json +18 -0
- package/snapshot/services/addon-docs/mdx/komponenten-buttons-button.json +1 -1
- package/snapshot/services/addon-docs/mdx/komponenten-cards-teaser--verwendung.json +1 -1
- package/snapshot/services/addon-docs/mdx/komponenten-sektion--/303/274bersicht.json +1 -1
- package/snapshot/services/addon-docs/mdx/komponenten-theme-umschalter--verwendung.json +2 -2
- package/src/instructions.mjs +9 -1
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@ Beim Verbinden gibt der Server dem Assistenten außerdem feste Regeln mit:
|
|
|
33
33
|
2. Kein eigenes CSS für Design-System-Komponenten, keine erfundenen CSS-Klassen.
|
|
34
34
|
3. Nur Inputs und Outputs verwenden, die `docs-show` liefert. Vorher nachsehen, nie raten.
|
|
35
35
|
4. Bei Fragen zur Einrichtung die Storybook-Seite „Einrichtung“ lesen.
|
|
36
|
+
5. Für Auswahl- und Gestaltungsfragen zusätzlich die Verwendungsguidance der Komponente heranziehen, sonst über `docs-list` die passende „Verwendung“-Seite suchen.
|
|
36
37
|
|
|
37
38
|
Weitere Eigenschaften:
|
|
38
39
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conciso/design-system-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "MCP-Server für Consumer des Conciso Design System, beantwortet docs-list, docs-show und docs-show-story über stdio aus einem mitgelieferten Storybook-Snapshot, ohne Netzzugriff.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -28,6 +28,16 @@
|
|
|
28
28
|
"name": "grundlagen-farben",
|
|
29
29
|
"stories": {
|
|
30
30
|
"$ref": "../services/core/story-docs/grundlagen-farben.json#/components/grundlagen-farben"
|
|
31
|
+
},
|
|
32
|
+
"docs": {
|
|
33
|
+
"grundlagen-farben--verwendung": {
|
|
34
|
+
"id": "grundlagen-farben--verwendung",
|
|
35
|
+
"name": "Verwendung",
|
|
36
|
+
"mdx": {
|
|
37
|
+
"$ref": "../services/addon-docs/mdx/grundlagen-farben.json#/components/grundlagen-farben/docs/grundlagen-farben--verwendung"
|
|
38
|
+
},
|
|
39
|
+
"summary": "# Verwendung Vier Bereichspaletten (Corporate, Angewandte KI, Effektive Software, Wirksame..."
|
|
40
|
+
}
|
|
31
41
|
}
|
|
32
42
|
},
|
|
33
43
|
"grundlagen-typografie": {
|
|
@@ -35,6 +45,16 @@
|
|
|
35
45
|
"name": "grundlagen-typografie",
|
|
36
46
|
"stories": {
|
|
37
47
|
"$ref": "../services/core/story-docs/grundlagen-typografie.json#/components/grundlagen-typografie"
|
|
48
|
+
},
|
|
49
|
+
"docs": {
|
|
50
|
+
"grundlagen-typografie--verwendung": {
|
|
51
|
+
"id": "grundlagen-typografie--verwendung",
|
|
52
|
+
"name": "Verwendung",
|
|
53
|
+
"mdx": {
|
|
54
|
+
"$ref": "../services/addon-docs/mdx/grundlagen-typografie.json#/components/grundlagen-typografie/docs/grundlagen-typografie--verwendung"
|
|
55
|
+
},
|
|
56
|
+
"summary": "# Verwendung Zwei Schriften tragen zwei unterschiedliche Aufgaben. Libre Baskerville (Seri..."
|
|
57
|
+
}
|
|
38
58
|
}
|
|
39
59
|
},
|
|
40
60
|
"komponenten-buttons-button": {
|
|
@@ -215,7 +215,7 @@
|
|
|
215
215
|
"mdx": {
|
|
216
216
|
"$ref": "../services/addon-docs/mdx/komponenten-theme-umschalter--verwendung.json#/components/komponenten-theme-umschalter--verwendung/docs/komponenten-theme-umschalter--verwendung"
|
|
217
217
|
},
|
|
218
|
-
"summary": "# Theme-Umschalter · Verwendung
|
|
218
|
+
"summary": "# Theme-Umschalter · Verwendung `docs/index.html` hat für den Theme-Umschalter eine eigene..."
|
|
219
219
|
},
|
|
220
220
|
"seitenmuster-wissensbeitrag--übersicht": {
|
|
221
221
|
"id": "seitenmuster-wissensbeitrag--übersicht",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"components": {
|
|
3
|
+
"grundlagen-farben": {
|
|
4
|
+
"id": "grundlagen-farben",
|
|
5
|
+
"name": "grundlagen-farben",
|
|
6
|
+
"docs": {
|
|
7
|
+
"grundlagen-farben--verwendung": {
|
|
8
|
+
"id": "grundlagen-farben--verwendung",
|
|
9
|
+
"name": "Verwendung",
|
|
10
|
+
"path": "./src/docs/grundlagen/farben.mdx",
|
|
11
|
+
"title": "Grundlagen/Farben",
|
|
12
|
+
"content": "import { Meta } from '@storybook/addon-docs/blocks';\nimport * as FarbenStories from '../../foundations/colors.stories';\n\n<Meta of={FarbenStories} name=\"Verwendung\" />\n\n# Verwendung\n\nVier Bereichspaletten (Corporate, Angewandte KI, Effektive Software, Wirksame Organisationen) plus Rosé und die Neutrals tragen je eine Tonal-Skala von 50 bis 900 (Live-Swatches in der Story „Paletten“). Diese Seite hält fest, welche Stufe wofür steht, wie Kontrast in beiden Modi funktioniert, und wo Tönung Akzent bleibt statt Standard-Grund zu werden. Kontrast-Schwellen (auf Weiß): AA ab 4,5:1 für Fließtext, AA Large ab 3,0:1 für großen Text (ab 24 px) und UI-Komponenten, AAA ab 7,0:1.\n\n## Farbstufen, wofür?\n\n| Stufe | Verwendungszweck |\n|---|---|\n| `-50` | Tonal Overlay, Chip-Hintergrund, Badge-Hintergrund, Sub-Strip-Background, sehr helle Fläche |\n| `-100` bis `-300` | Dezente UI-Akzente, Media-Hintergründe in Cards, Hero-Gradient, Borders |\n| `-500` | Brand-Akzent: Hero-Gradient, dekorative Flächen, aktive Marker, Icon. **Kein** Button-Background, **kein** Text auf Weiß (Co, KI und WO unterschreiten den Kontrast) |\n| `-700` | Standard für farbigen Text auf Weiß (Co, ES) und Filled-Button-Background (`.btn-co`, `.btn-es`, `.btn-wo`). Erfüllt WCAG AA (≥ 4,5:1). **Ausnahme KI:** KI-700 erreicht nur 4,4:1, für Text und Filled-Button `-800` nehmen (`.btn-ki` nutzt das bereits) |\n| `-800` bis `-900` | Dunkle Kontexte, Text auf Bereichsfarbe (`-500`), Hover-Zustände, Page-End-CTA-Band-Background, KI-Text/-Button (siehe Zeile oben) |\n\n## Semantische Farben\n\n| Token | Wann einsetzen |\n|---|---|\n| `--c-success` | Erfolgreiche Aktionen, OK-Snackbar, Bestätigungs-Badge |\n| `--c-warning` | Hinweise, Beta-Zustände, nicht kritische Warnungen |\n| `--c-error` | Fehler-Snackbar, Validierungsfehler im Formular, Deprecated-Badge |\n| `--tx-primary` | Fließtext, Headlines, UI-Labels. `#333E48`, deutlich über AAA gegen Weiß |\n| `--tx-secondary` | Sekundärer Text: Lead, Sub-Titel, Captions. `var(--n-500)`, AA gegen Weiß |\n| `--tx-muted` | Inhaltlich leise Texte: Eyebrow, Meta, Counter. `#5A7171`, AA gegen Weiß, gegen `n-50` und gegen getönte Hellflächen |\n| `--co-ink` · `--ki-ink` · `--es-ink` · `--wo-ink` | Farbiger Text und farbige Icons, die in **beiden** Modi lesbar bleiben müssen: Light `-700` (KI `-800`, weil KI-700 nur 4,05:1 trägt), Dark `-200` (ES `-100`). Ein fest gesetztes `-700` trägt im Dark nur 3,17:1, ein fest gesetztes `-200` im Light umgekehrt zu wenig, darum **immer das Ink-Token**, nicht die Stufe selbst |\n| `--co-fill` · `--ki-fill` · `--es-fill` · `--wo-fill` | Füllung von Pill und Bereichs-Badge. Im Light identisch mit `--XX-50` (der ruhige Tint mit kräftiger dunkler Schrift). Im Dark eigene, gehobene Werte, weil dort helle Schrift auf dunklem Tint liegt und der Tint sich sonst nicht von der Karte löst |\n| `--co-band` · `--ki-band` · `--es-band` · `--wo-band` | Große Sektionsfläche (Hero, CTA-Band). Im Light identisch mit `--XX-50`. Im Dark ein eigener, dunklerer Wert, damit das Band unter den Karten bleibt statt die Ebenen-Ordnung umzukehren |\n\n## Vier Rollen, ein Bereichston\n\nWCAG verlangt für eine dekorative Fläche nichts, für ein textführendes Bauteil verlangt die Hausregel (CONTRIBUTING § 3) mindestens 1,3:1 gegen den Grund und 10 L\\* Helligkeitsabstand. Deshalb hat jeder Bereichston vier Rollen mit vier Namen: `--XX-50` ruhiger dekorativer Tint (Icon-Kachel, Timeline-Marker, Chip-Hover, Inline-Code), `--XX-fill` textführende Bauteil-Füllung, `--XX-band` große Sektionsfläche, `--XX-ink` farbiger Text.\n\nIm Light sind `--XX-50`, `--XX-fill` und `--XX-band` identisch, dort gibt es zwischen kleiner Füllung und großem Band keinen Konflikt. Im Dark trennen sie sich: eine kleine Füllung (Badge, Pill, Icon-Kachel) muss *heller* sein als ihr Grund, sonst liest sie nicht mehr als Fläche. Ein großes Band (Hero, CTA-Sektion) muss dagegen *dunkler* bleiben als die Karten darauf, sonst kehrt sich die Ebenen-Ordnung um. Bei einer Basisfläche von 17,5:1 gegen Weiß und reinem Schwarz bei 21:1 reicht der verbleibende Spielraum nicht, damit ein einzelner Wert beide Aufgaben trägt.\n\n## Text-Tokens vs. dekorative Neutrals\n\n`--tx-muted` ist für inhaltlich leise, aber AA-konforme Texte gedacht (Eyebrow, Counter, Meta-Angaben). Rein dekorative Elemente (Trenner, Ornament, Disabled-Hintergrund) nutzen direkt das Neutral-Token `var(--n-300)` oder heller, diese sind absichtlich unter AA, weil sie keinen Textinhalt tragen.\n\n**Faustregel:** Soll ein Screenreader den Text vorlesen, mindestens `--tx-muted` verwenden. Ist das Element rein visuell und für Screenreader ausgeblendet (`aria-hidden`, dekorative Border), darf es heller sein.\n\nFarbiger Text oder ein farbiges Icon auf einer hellen `-100`-Kachel (Chip, Häkchen-Kreis, Label-Pille) wird fest auf `--XX-800` gesetzt, **nicht** über `.t-*` beziehungsweise `--XX-ink`. Diese `-100`-Kacheln flippen im Dark nicht mit, sie bleiben hell, damit sie auf dem dunklen Grund sichtbar bleiben. `.t-*`/`--XX-ink` würde dagegen auf den hellen `-200`-Ton kippen, hell auf hell, unsichtbar. `--XX-800` ist in beiden Modi stabil. Entscheidend ist immer, ob der Hintergrund mit dem Theme mitflippt.\n\n## Hintergrundflächen & Rhythmus\n\n- Aufeinanderfolgende Sektionen wechseln im Standard zwischen Weiß (`--bg-surface`) und ruhigem Grau (`--n-50`). Kein hartes `#fff`, das schaltet im Dark Mode nicht mit.\n- **Faustregel: Tönung ist Akzent, nicht Standard-Grund.** Eine Bereichsfläche (`-50`) wirkt als Akzent, etwa als Aktions-Brücke direkt unter dem Hero, die dunkle `-800` als CTA-Band am Seitenende bildet die Gegen-Klammer. Mehrere große getönte Bänder hintereinander lassen die Seite bunt wirken und schwächen die Bereichsfarbe dort, wo sie Bedeutung trägt.\n- **Dark: nur zwei Flächen-Stufen.** Statt Weiß/Grau gibt es im Dark nur `--bg-page` (Basis) und das hellere `--bg-surface`, dazu `--bg-surface-hover` als Hover-Zustand, keine dritte statische Stufe. `n-50`-Sektionen werden im Dark ausnahmslos auf `--bg-surface` gehoben, damit die Tonfolge dieselbe bleibt wie im Light.\n- Kartentragende Sektionen sind dabei kein Sonderfall: Eine gehobene Sektion trifft zwar den Ton ihrer eigenen `bg-surface`-Karten, das passiert im Light auf weißen Sektionen mit weißen Karten genauso. Die Karte liest dort über ihren Rand (`--bd-strong-c`), im Dark deutlich kräftiger als die Haarlinie im Light.\n- Naheliegend wäre, kartentragende Sektionen auf `bg-page` zu lassen, damit die Karten die hellere Stufe bilden. Gemessen über die Beispielseiten kostet das aber den Rhythmus: deutlich mehr verschmolzene Übergänge zwischen benachbarten Sektionen als mit der gehobenen Fläche.\n- Ein heller `-100`-Rahmen auf einer getönten Fläche ist im Light ein zarter gleichfarbiger Whisper, `-100` flippt aber nicht mit dem Theme. Im Dark wird daraus eine grelle helle Linie auf dunkler Tönung. Trennlinien und Rahmen getönter Flächen im Dark deshalb auf den neutralen `var(--bd)` heben, nie eine `-100`-Stufe direkt verwenden.\n- Umgekehrt bei neutralem `--n-100`: Im Light passt `1px solid var(--n-100)` zu dem, was `--bd` auflöst. Im Dark wird `--n-100` selbst zu einer dunklen Fläche, der Rahmen verschwindet praktisch. Für Rahmen und Trennlinien deshalb ausnahmslos `var(--bd)` beziehungsweise `var(--bd-strong)` verwenden, nie eine `-100`-Stufe direkt.\n\n## Dos & Don'ts\n\n**Tun**\n\n- Bereichsfarbe `-700` für farbigen Text auf Weiß (Co, ES und WO erfüllen damit WCAG AA). **Ausnahme KI:** `-700` erreicht nur 4,4:1, für Text und Filled-Button auf Weiß `-800` verwenden\n- Stufe `-50` für Hintergründe und Tonal Overlays, sie wirkt, ohne zu dominieren\n- Semantische Tokens `--c-success`, `--c-warning`, `--c-error` konsequent für Status einsetzen\n- Jede Seite gehört zu genau einer Brand Area, deren Farbpalette durchgängig verwenden\n- Neutrals (`--tx-primary`, `--tx-secondary`) für Fließtext, Bereichsfarben nur für Akzente\n\n**Nicht tun**\n\n- Stufe `-500` als Textfarbe auf Weiß: Co-500 und KI-500 unterschreiten AA komplett, WO-500 erreicht nur AA Large. Nur ES-500 und Rosé-500 erfüllen AA\n- Paletten verschiedener Bereiche auf derselben Seite mischen, bricht die Markenzugehörigkeit\n- Bereichsfarbe für Fließtext, lange Texte in Farbe ermüden und verringern die Lesbarkeit\n- Semantische Farben zweckfremden, `--c-success` nicht für dekorative grüne Elemente\n- Hardcodierte Hex-Werte statt Tokens, verhindert Dark-Mode-Unterstützung und Theme-Wechsel\n\n## Siehe auch\n\n- CONTRIBUTING.md § 3 Farbe & Kontrast\n- `Grundlagen/Design Tokens` für das Präfix-Schema aller Tokens\n",
|
|
13
|
+
"summary": "# Verwendung Vier Bereichspaletten (Corporate, Angewandte KI, Effektive Software, Wirksame..."
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"components": {
|
|
3
|
+
"grundlagen-typografie": {
|
|
4
|
+
"id": "grundlagen-typografie",
|
|
5
|
+
"name": "grundlagen-typografie",
|
|
6
|
+
"docs": {
|
|
7
|
+
"grundlagen-typografie--verwendung": {
|
|
8
|
+
"id": "grundlagen-typografie--verwendung",
|
|
9
|
+
"name": "Verwendung",
|
|
10
|
+
"path": "./src/docs/grundlagen/typografie.mdx",
|
|
11
|
+
"title": "Grundlagen/Typografie",
|
|
12
|
+
"content": "import { Meta } from '@storybook/addon-docs/blocks';\nimport * as TypografieStories from '../../foundations/typography.stories';\n\n<Meta of={TypografieStories} name=\"Verwendung\" />\n\n# Verwendung\n\nZwei Schriften tragen zwei unterschiedliche Aufgaben. Libre Baskerville (Serifenschrift, Display und Headline) trägt Hero-Überschriften, Seitentitel, Pull Quotes und emotionale Akzente. Montserrat (Grotesk, Title, Body und Label) trägt UI-Text, Fließtext, Buttons, Navigation und Captions. Minimum-Font-Size systemweit ist 12 px, kleinere Größen werden bewusst vermieden.\n\n## Wann welche Schrift\n\n| Schrift | Tokens | Einsatz |\n|---|---|---|\n| Libre Baskerville, Serifenschrift | Display, Headline | Hero-Überschriften, Seitentitel, Pull Quotes, emotionale Akzente |\n| Montserrat, Grotesk | Title, Body, Label | UI-Text, Fließtext, Buttons, Navigation, Captions |\n\n## Token-Übersicht\n\n| Kategorie | Einsatz | Größen |\n|---|---|---|\n| Display | Hero-Texte, ep-Seiten, große Kampagnentitel | responsive (fluid), clamp 28 bis 46 px, 30 bis 40 px, 28 bis 36 px |\n| Headline | Sektions-Überschriften, Abschnittstitel | responsive (fluid), clamp 23 bis 28 px, 21 bis 24 px, 20 bis 22 px |\n| Title | Title Small für Karten-Titel und Komponenten-Header | 20 px |\n| Body | Fließtext, Card-Beschreibungen, Meta-Daten, Captions | 16, 14, 12 px |\n| Label | Buttons, Badges, UI-Beschriftungen, Eyebrows (UC-Variante) | 14, 12, 12 px UC |\n\nDie Token-Hierarchie ist verbindlich und wird nicht übersprungen: *Display → Headline → Title → Body → Label*.\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Hierarchie | Überschriften-Ebenen nie überspringen (h1 → h2 → h3), Screenreader navigieren anhand der Heading-Struktur |\n| rem statt px | Alle Typo-Tokens sind rem-basiert (1rem = 16px), damit sie die Browser-Schriftgröße respektieren, px ignoriert sie (WCAG 1.4.4) |\n| Zeilenhöhe | Body-Text mindestens `line-height: 1.5` (WCAG 1.4.8), erleichtert das Lesen bei Dyslexie und Sehschwäche |\n| Nicht nur Stil | Bedeutung nie ausschließlich durch Schriftschnitt (fett, kursiv) vermitteln, der Kontext muss auch ohne Formatierung erkennbar sein |\n\n## Dos & Don'ts\n\n**Tun**\n\n- Libre Baskerville für Überschriften und emotionale Akzente, der markentypische Kontrast zur UI\n- Display-Tokens ausschließlich auf Landing Pages und Kampagnenseiten einsetzen\n- Body Medium (16 px) als Standard für Fließtext, optimale Lesbarkeit auf allen Screens\n- Token-Hierarchie einhalten: Display → Headline → Title → Body → Label\n- Label-Tokens für alle UI-Beschriftungen: Buttons, Chips, Badges, Eyebrows\n\n**Nicht tun**\n\n- Libre Baskerville als Fließtext, Serifenschriften ermüden bei langen Texten auf Screens\n- Libre Baskerville für Navigation, Buttons oder kleine UI-Labels, falsche semantische Ebene\n- Freihand-Fontgrößen (zum Beispiel 13 px, 17 px) statt Token-Werte, bricht den visuellen Rhythmus\n- Title-Tokens für Hero-Überschriften, zu klein, nimmt der Marke den Ausdruck\n- Body-Text fett formatieren statt ein Title-Token zu wählen, falsche Hierarchiesignale\n\n## Siehe auch\n\n- CONTRIBUTING.md § 6 Typografie\n- `Grundlagen/Design Tokens` für das Präfix-Schema aller Tokens\n",
|
|
13
|
+
"summary": "# Verwendung Zwei Schriften tragen zwei unterschiedliche Aufgaben. Libre Baskerville (Seri..."
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"name": "Verwendung",
|
|
10
10
|
"path": "./src/docs/komponenten/buttons-verwendung.mdx",
|
|
11
11
|
"title": "Komponenten/Buttons/Button",
|
|
12
|
-
"content": "import { Meta, Unstyled } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from '../../lib/button/button.stories';\n\n<Meta of={ButtonStories} name=\"Verwendung\" />\n\n# Verwendung\n\nButtons sind die primäre Aktions-Komponente des Systems: fünf Stilvarianten (Filled · Tonal · Elevated · Outlined · Text), drei Größen (Standard · Small · Large), der Ton-Modifier `.btn-err` für destruktive Aktionen und der Inversions-Modifier `.btn-on-band` für Buttons auf farbigen Bereichs-Bändern. Jede Variante steht in allen vier Brand Areas zur Verfügung (Bereichsreihenfolge co · ki · es · wo), das Mindestmaß für ein Touch-Target ist 44 Pixel.\n\n## Wann welche Variante\n\nDie Hierarchie ist verbindlich: Filled vor Tonal oder Outlined vor Text. Pro Kontext höchstens ein Filled-Button, sonst ist die Hauptaktion nicht mehr eindeutig erkennbar. Elevated steht außerhalb dieser Kette und markiert eine freistehende, vom Hintergrund abgehobene Aktion.\n\nSo löst sich die Hierarchie in typischen Kontexten auf: ein Dialog mit Text- neben Filled-Button, ein Formular mit Outlined- neben Filled-Button und eine Feature-Karte mit Text- neben Tonal-Button.\n\n<Unstyled>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--s4)' }}>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderRadius: 'var(--r-lg)',\n padding: 'var(--s5)',\n background: 'var(--bg-surface)',\n }}\n >\n <div style={{ font: '500 16px/24px var(--font)', color: 'var(--tx-primary)', marginBottom: 'var(--s2)' }}>\n Aktion bestätigen\n </div>\n <div style={{ font: '400 14px/20px var(--font)', color: 'var(--tx-secondary)', marginBottom: 'var(--s5)' }}>\n Möchtest du die Änderungen wirklich speichern?\n </div>\n <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 'var(--s2)', marginBottom: 'var(--s3)' }}>\n <button className=\"btn btn-text btn-sm btn-co\">Abbrechen</button>\n <button className=\"btn btn-filled btn-sm btn-co\">Speichern</button>\n </div>\n <div style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)', textAlign: 'right' }}>\n Text → Abbrechen · Filled → Hauptaktion\n </div>\n </div>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderRadius: 'var(--r-lg)',\n padding: 'var(--s5)',\n background: 'var(--bg-surface)',\n }}\n >\n <div style={{ font: '500 16px/24px var(--font)', color: 'var(--tx-primary)', marginBottom: 'var(--s4)' }}>\n Formular einreichen\n </div>\n <div\n style={{\n height: '32px',\n background: 'var(--bg-overlay)',\n borderRadius: 'var(--r-sm)',\n border: 'var(--bd-strong)',\n marginBottom: 'var(--s5)',\n }}\n ></div>\n <div style={{ display: 'flex', gap: 'var(--s2)', marginBottom: 'var(--s3)' }}>\n <button className=\"btn btn-outlined btn-sm btn-co\">Vorschau</button>\n <button className=\"btn btn-filled btn-sm btn-co\">Absenden</button>\n </div>\n <div style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n Outlined → Alternativaktion · Filled → Primäraktion\n </div>\n </div>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderRadius: 'var(--r-lg)',\n padding: 'var(--s5)',\n background: 'var(--bg-surface)',\n }}\n >\n <div style={{ font: '500 16px/24px var(--font)', color: 'var(--tx-primary)', marginBottom: 'var(--s2)' }}>\n Feature entdecken\n </div>\n <div style={{ font: '400 14px/20px var(--font)', color: 'var(--tx-secondary)', marginBottom: 'var(--s5)' }}>\n Drei Bereiche, ein Ziel, Gelassenheit durch klare Struktur.\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--s2)', marginBottom: 'var(--s3)' }}>\n <button className=\"btn btn-text btn-sm btn-co\">Mehr erfahren</button>\n <button className=\"btn btn-tonal btn-sm btn-co\">Jetzt starten</button>\n </div>\n <div style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n Text → Nebenaktion · Tonal → unterstützende Aktion\n </div>\n </div>\n </div>\n</Unstyled>\n\n| Variante | Rolle in der Hierarchie | Einsatz | Beispiele |\n|---|---|---|---|\n| Filled | 1. Primäre Hauptaktion | Max. 1 bis 2 pro Kontext | Speichern, Absenden, Starten |\n| Tonal | 2. Sekundäre Bestätigung | Neben Filled oder eigenständig | Weiter, Übernehmen |\n| Outlined | 2. Gleichwertige Alternative | Ohne Primärfokus | Vorschau, Exportieren |\n| Text | 3. Nebenaktion | Niedrigste Priorität, link-ähnliche Funktion | Abbrechen, Mehr erfahren |\n| Elevated | Außerhalb der Hierarchie | Freistehende Aktion, visuell vom Hintergrund getrennt | Schwebende Elemente, FAB |\n\n## Destruktive Aktionen\n\n`.btn-err` (Angular: `tone=\"err\"`) markiert eine Aktion, die sich nicht rückgängig machen lässt: Löschen, Verwerfen, Entfernen. Der Modifier **ersetzt** die Bereichsfarbe, er wird statt `.btn-co` gesetzt, nicht zusätzlich. Gedacht für Filled, Outlined und Text.\n\n<Unstyled>\n <div style={{ display: 'flex', gap: 'var(--s4)', flexWrap: 'wrap', alignItems: 'center', marginBottom: 'var(--s5)' }}>\n <button className=\"btn btn-filled btn-err\">Löschen</button>\n <button className=\"btn btn-outlined btn-err\">Verwerfen</button>\n <button className=\"btn btn-text btn-err\">Entfernen</button>\n </div>\n</Unstyled>\n\nWelcher Button gefüllt ist, entscheidet der Kontext:\n\n| Kontext | Beispiel | Hauptaktion (Filled) | Nebenaktion |\n|---|---|---|---|\n| Selbst ausgelöst | Klick auf „Löschen“, danach eine Rückfrage | „Löschen“ mit `.btn-err` | „Abbrechen“ als Text |\n| Unterbrechung | Ungespeicherte Änderungen beim Verlassen | „Weiter bearbeiten“ in der Bereichsfarbe | „Verwerfen“ als Outlined mit `.btn-err` |\n\nBei einer Unterbrechung wollte die Person etwas anderes, das Verwerfen ist Nebenwirkung. Deshalb bekommt dort der sichere Weg das Gewicht. Die Farbe ist nie der einzige Hinweis, das Label nennt immer die Folge.\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Icon-only | Buttons ohne sichtbaren Text benötigen `aria-label`, der SVG-Inhalt allein reicht für Screenreader nicht aus |\n| Disabled | `aria-disabled=\"true\"` statt HTML `disabled`, wenn der Button im Fokus-Flow bleiben soll, `disabled` entfernt das Element aus der Tastaturreihenfolge |\n| Touch-Target | Mindestgröße 44 mal 44 Pixel für alle Button-Varianten (WCAG 2.5.5), `btn-sm` bei Bedarf mit zusätzlichem Padding kompensieren |\n| Focus-Ring | Nie `outline: none` ohne sichtbaren Ersatz, der Design-System-Focus-Ring (`--focus-aa`) muss für alle Buttons erhalten bleiben |\n| Filled auf Bereichs-Section | Filled-Buttons auf hellen Bereichs-Hintergründen (`--co-50`, `--ki-50`, `--wo-50`, `--es-50`) brauchen eine ausreichend dunkle Variante mit weißer Schrift, sonst fehlt der UI-Komponenten-Kontrast (WCAG 1.4.11, mindestens 3 zu 1) zwischen Button-Fläche und Section |\n\nDrei der vier Bereiche sind über die Modifier-Klasse bereits korrekt abgedeckt: `.btn-co` auf `--co-700`, `.btn-ki` auf `--ki-800`, `.btn-es` auf `--es-700`. Die Default-Farbe von `.btn-wo` (`--wo-700`) ist im Allgemeinen passend, verfehlt aber auf `--wo-50`-Sub-Streifen den Kontrast. Dort die Bereichs-Klasse mit einem minimalen Inline-Override kombinieren:\n\n```html\n<button class=\"btn btn-filled btn-wo\" style=\"--c500:var(--wo-600)\">\n```\n\n`--c50` erbt korrekt von `.btn-wo`, ein `color`-Override entfällt, weil der Default aus `.btn-filled` (Weiß) bereits greift.\n\n## Dos & Don'ts\n\n**Tun**\n\n- Pro Kontext maximal ein Filled Button, klare Priorisierung der Hauptaktion für die Nutzerin.\n- Verb-Labels: konkret und handlungsorientiert, „Starten“, „Speichern“, „Anfragen“, „Absenden“.\n- Hierarchie konsequent einhalten: Filled vor Tonal oder Outlined vor Text.\n- Bereichsklasse passend zum Seitenkontext: `.btn-co`, `.btn-ki`, `.btn-es`, `.btn-wo`.\n- Touch-Target mindestens 44 Pixel einhalten, auch im Small-Modus ausreichend groß für sichere Bedienung.\n- `.btn-err` nur für Aktionen, die sich nicht rückgängig machen lassen, höchstens einer pro Ansicht, mit einem Label, das die Folge nennt: „Löschen“, „Verwerfen“.\n\n**Nicht tun**\n\n- Mehrere Filled Buttons nebeneinander, das lässt keine klare Primäraktion erkennen.\n- Substantive oder lange Phrasen als Labels, „Antragsformular einreichen“ statt lieber „Absenden“.\n- Disabled-State ohne sichtbare Begründung, Helper-Text oder Tooltip nutzen, um zu erklären warum.\n- Bereichsfarbe willkürlich tauschen, Corporate-Kontext immer `.btn-co`, nie `.btn-ki`.\n- Filled-Button mit `--area-500` auf hellem Bereichs-Hintergrund (`--area-50`), stattdessen die dunklere Bereichs-Variante nutzen (siehe Barrierefreiheits-Tabelle oben).\n- `.btn-err` als Blickfang oder für umkehrbare Aktionen („Abmelden“, „Filter zurücksetzen“), und nie neben einer Bereichsklasse am selben Button.\n\n## Verwandte Seiten\n\n- Buttons (`Komponenten/Buttons/Button`), alle Stilvarianten, Größen und Zustände als Stories.\n",
|
|
12
|
+
"content": "import { Meta, Unstyled } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from '../../lib/button/button.stories';\n\n<Meta of={ButtonStories} name=\"Verwendung\" />\n\n# Verwendung\n\nButtons sind die primäre Aktions-Komponente des Systems: fünf Stilvarianten (Filled · Tonal · Elevated · Outlined · Text), drei Größen (Standard · Small · Large), der Ton-Modifier `.btn-err` für destruktive Aktionen und der Inversions-Modifier `.btn-on-band` für Buttons auf farbigen Bereichs-Bändern. Jede Variante steht in allen vier Brand Areas zur Verfügung (Bereichsreihenfolge co · ki · es · wo), das Mindestmaß für ein Touch-Target ist 44 Pixel.\n\n## Wann welche Variante\n\nDie Hierarchie ist verbindlich: Filled vor Tonal oder Outlined vor Text. Pro Kontext höchstens ein Filled-Button, sonst ist die Hauptaktion nicht mehr eindeutig erkennbar. Elevated steht außerhalb dieser Kette und markiert eine freistehende, vom Hintergrund abgehobene Aktion.\n\nSo löst sich die Hierarchie in typischen Kontexten auf: ein Dialog mit Text- neben Filled-Button, ein Formular mit Outlined- neben Filled-Button und eine Feature-Karte mit Text- neben Tonal-Button.\n\n<Unstyled>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--s4)' }}>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderRadius: 'var(--r-lg)',\n padding: 'var(--s5)',\n background: 'var(--bg-surface)',\n }}\n >\n <div style={{ font: '500 16px/24px var(--font)', color: 'var(--tx-primary)', marginBottom: 'var(--s2)' }}>\n Aktion bestätigen\n </div>\n <div style={{ font: '400 14px/20px var(--font)', color: 'var(--tx-secondary)', marginBottom: 'var(--s5)' }}>\n Möchtest du die Änderungen wirklich speichern?\n </div>\n <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 'var(--s2)', marginBottom: 'var(--s3)' }}>\n <button className=\"btn btn-text btn-sm btn-co\">Abbrechen</button>\n <button className=\"btn btn-filled btn-sm btn-co\">Speichern</button>\n </div>\n <div style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)', textAlign: 'right' }}>\n Text → Abbrechen · Filled → Hauptaktion\n </div>\n </div>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderRadius: 'var(--r-lg)',\n padding: 'var(--s5)',\n background: 'var(--bg-surface)',\n }}\n >\n <div style={{ font: '500 16px/24px var(--font)', color: 'var(--tx-primary)', marginBottom: 'var(--s4)' }}>\n Formular einreichen\n </div>\n <div\n style={{\n height: '32px',\n background: 'var(--bg-overlay)',\n borderRadius: 'var(--r-sm)',\n border: 'var(--bd-strong)',\n marginBottom: 'var(--s5)',\n }}\n ></div>\n <div style={{ display: 'flex', gap: 'var(--s2)', marginBottom: 'var(--s3)' }}>\n <button className=\"btn btn-outlined btn-sm btn-co\">Vorschau</button>\n <button className=\"btn btn-filled btn-sm btn-co\">Absenden</button>\n </div>\n <div style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n Outlined → Alternativaktion · Filled → Primäraktion\n </div>\n </div>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderRadius: 'var(--r-lg)',\n padding: 'var(--s5)',\n background: 'var(--bg-surface)',\n }}\n >\n <div style={{ font: '500 16px/24px var(--font)', color: 'var(--tx-primary)', marginBottom: 'var(--s2)' }}>\n Feature entdecken\n </div>\n <div style={{ font: '400 14px/20px var(--font)', color: 'var(--tx-secondary)', marginBottom: 'var(--s5)' }}>\n Drei Bereiche, ein Ziel, Gelassenheit durch klare Struktur.\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--s2)', marginBottom: 'var(--s3)' }}>\n <button className=\"btn btn-text btn-sm btn-co\">Mehr erfahren</button>\n <button className=\"btn btn-tonal btn-sm btn-co\">Jetzt starten</button>\n </div>\n <div style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n Text → Nebenaktion · Tonal → unterstützende Aktion\n </div>\n </div>\n </div>\n</Unstyled>\n\n| Variante | Rolle in der Hierarchie | Einsatz | Beispiele |\n|---|---|---|---|\n| Filled | 1. Primäre Hauptaktion | Max. 1 bis 2 pro Kontext | Speichern, Absenden, Starten |\n| Tonal | 2. Sekundäre Bestätigung | Neben Filled oder eigenständig | Weiter, Übernehmen |\n| Outlined | 2. Gleichwertige Alternative | Ohne Primärfokus | Vorschau, Exportieren |\n| Text | 3. Nebenaktion | Niedrigste Priorität, link-ähnliche Funktion | Abbrechen, Mehr erfahren |\n| Elevated | Außerhalb der Hierarchie | Freistehende Aktion, visuell vom Hintergrund getrennt | Schwebende Elemente, FAB |\n\n## Destruktive Aktionen\n\n`.btn-err` (Angular: `tone=\"err\"`) markiert eine Aktion, die sich nicht rückgängig machen lässt: Löschen, Verwerfen, Entfernen. Der Modifier **ersetzt** die Bereichsfarbe, er wird statt `.btn-co` gesetzt, nicht zusätzlich. Gedacht für Filled, Outlined und Text.\n\n<Unstyled>\n <div style={{ display: 'flex', gap: 'var(--s4)', flexWrap: 'wrap', alignItems: 'center', marginBottom: 'var(--s5)' }}>\n <button className=\"btn btn-filled btn-err\">Löschen</button>\n <button className=\"btn btn-outlined btn-err\">Verwerfen</button>\n <button className=\"btn btn-text btn-err\">Entfernen</button>\n </div>\n</Unstyled>\n\nWelcher Button gefüllt ist, entscheidet der Kontext:\n\n| Kontext | Beispiel | Hauptaktion (Filled) | Nebenaktion |\n|---|---|---|---|\n| Selbst ausgelöst | Klick auf „Löschen“, danach eine Rückfrage | „Löschen“ mit `.btn-err` | „Abbrechen“ als Text |\n| Unterbrechung | Ungespeicherte Änderungen beim Verlassen | „Weiter bearbeiten“ in der Bereichsfarbe | „Verwerfen“ als Outlined mit `.btn-err` |\n\nBei einer Unterbrechung wollte die Person etwas anderes, das Verwerfen ist Nebenwirkung. Deshalb bekommt dort der sichere Weg das Gewicht. Die Farbe ist nie der einzige Hinweis, das Label nennt immer die Folge.\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Icon-only | Buttons ohne sichtbaren Text benötigen `aria-label`, der SVG-Inhalt allein reicht für Screenreader nicht aus |\n| Disabled | `aria-disabled=\"true\"` statt HTML `disabled`, wenn der Button im Fokus-Flow bleiben soll, `disabled` entfernt das Element aus der Tastaturreihenfolge |\n| Touch-Target | Mindestgröße 44 mal 44 Pixel für alle Button-Varianten (WCAG 2.5.5), `btn-sm` bei Bedarf mit zusätzlichem Padding kompensieren |\n| Focus-Ring | Nie `outline: none` ohne sichtbaren Ersatz, der Design-System-Focus-Ring (`--focus-aa`) muss für alle Buttons erhalten bleiben |\n| Filled auf Bereichs-Section | Filled-Buttons auf hellen Bereichs-Hintergründen (`--co-50`, `--ki-50`, `--wo-50`, `--es-50`) brauchen eine ausreichend dunkle Variante mit weißer Schrift, sonst fehlt der UI-Komponenten-Kontrast (WCAG 1.4.11, mindestens 3 zu 1) zwischen Button-Fläche und Section |\n\nDrei der vier Bereiche sind über die Modifier-Klasse bereits korrekt abgedeckt: `.btn-co` auf `--co-700`, `.btn-ki` auf `--ki-800`, `.btn-es` auf `--es-700`. Die Default-Farbe von `.btn-wo` (`--wo-700`) ist im Allgemeinen passend, verfehlt aber auf `--wo-50`-Sub-Streifen den Kontrast. Dort die Bereichs-Klasse mit einem minimalen Inline-Override kombinieren:\n\n```html\n<button class=\"btn btn-filled btn-wo\" style=\"--c500:var(--wo-600)\">\n```\n\n`--c50` erbt korrekt von `.btn-wo`, ein `color`-Override entfällt, weil der Default aus `.btn-filled` (Weiß) bereits greift.\n\n**Anti-Pattern:** Inline-Style verwenden, der nur die Token-Werte einer Modifier-Klasse dupliziert (etwa `style=\"--c500:var(--co-700);--c50:var(--co-50)\"` statt `.btn-co`). Macht das Markup laut, das Refactoring teuer und verlangsamt das Lesen. Wenn eine Wiederholung auftaucht, lieber einen neuen Modifier definieren (wie `.btn-on-band`) statt das Pattern an mehreren Stellen inline zu kopieren.\n\n## Dos & Don'ts\n\n**Tun**\n\n- Pro Kontext maximal ein Filled Button, klare Priorisierung der Hauptaktion für die Nutzerin.\n- Verb-Labels: konkret und handlungsorientiert, „Starten“, „Speichern“, „Anfragen“, „Absenden“.\n- Hierarchie konsequent einhalten: Filled vor Tonal oder Outlined vor Text.\n- Bereichsklasse passend zum Seitenkontext: `.btn-co`, `.btn-ki`, `.btn-es`, `.btn-wo`.\n- Touch-Target mindestens 44 Pixel einhalten, auch im Small-Modus ausreichend groß für sichere Bedienung.\n- `.btn-err` nur für Aktionen, die sich nicht rückgängig machen lassen, höchstens einer pro Ansicht, mit einem Label, das die Folge nennt: „Löschen“, „Verwerfen“.\n\n**Nicht tun**\n\n- Mehrere Filled Buttons nebeneinander, das lässt keine klare Primäraktion erkennen.\n- Substantive oder lange Phrasen als Labels, „Antragsformular einreichen“ statt lieber „Absenden“.\n- Disabled-State ohne sichtbare Begründung, Helper-Text oder Tooltip nutzen, um zu erklären warum.\n- Bereichsfarbe willkürlich tauschen, Corporate-Kontext immer `.btn-co`, nie `.btn-ki`.\n- Filled-Button mit `--area-500` auf hellem Bereichs-Hintergrund (`--area-50`), stattdessen die dunklere Bereichs-Variante nutzen (siehe Barrierefreiheits-Tabelle oben).\n- `.btn-err` als Blickfang oder für umkehrbare Aktionen („Abmelden“, „Filter zurücksetzen“), und nie neben einer Bereichsklasse am selben Button.\n\n## Verwandte Seiten\n\n- Buttons (`Komponenten/Buttons/Button`), alle Stilvarianten, Größen und Zustände als Stories.\n",
|
|
13
13
|
"summary": "# Verwendung Buttons sind die primäre Aktions-Komponente des Systems: fünf Stilvarianten (..."
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"name": "Verwendung",
|
|
10
10
|
"path": "./src/docs/komponenten/cards-verwendung.mdx",
|
|
11
11
|
"title": "Komponenten/Cards & Teaser",
|
|
12
|
-
"content": "import { Meta, Unstyled } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Cards & Teaser\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nGenerische Karten (statisch, Link-Karte) und Inhaltskarten (Stat), alle Brand Areas, barrierefrei. Der Abschnitt deckt mehr ab, als es eigene Bauteile gibt: die editoriale Kennzahl-Zeile ist ein reines CSS-Rezept ohne eigene Komponente. Klickbare Karte, Featured-Karte, Icon-Karte, offene Feature-Liste und Tier-Trenner haben jeweils ein eigenes Angular-Bauteil (siehe „Verwandte Seiten“).\n\n## Anatomie\n\nDie folgende Anatomie zeigt die fünf Bausteine einer generischen Karte: Media-Bereich, Eyebrow, Title, Text und Footer. Die Ziffern korrespondieren mit den Begriffen, die in den übrigen Abschnitten dieser Seite verwendet werden.\n\n<Unstyled>\n <div style={{ border: 'var(--bd-strong)', borderRadius: 'var(--r-lg)', overflow: 'hidden' }}>\n <div\n style={{\n height: 60,\n background: 'var(--co-50)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderBottom: 'var(--bd)',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n ① Media, Bereichsfarbe <code className=\"token\">-50</code>\n </span>\n </div>\n <div style={{ padding: 'var(--s4)' }}>\n <div\n className=\"t-co\"\n style={{\n font: '500 12px/16px var(--font)',\n letterSpacing: '.08em',\n textTransform: 'uppercase',\n marginBottom: 'var(--s1)',\n }}\n >\n ② Eyebrow, Bereichsname\n </div>\n <div\n style={{\n font: '500 16px/24px var(--font)',\n color: 'var(--tx-primary)',\n marginBottom: 'var(--s1)',\n }}\n >\n ③ Title, Kernaussage\n </div>\n <div style={{ font: 'var(--ty-body-md)', color: 'var(--tx-secondary)', marginBottom: 'var(--s4)' }}>\n ④ Text, max. 2 Sätze, konkret\n </div>\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 'var(--s2)',\n borderTop: 'var(--bd)',\n paddingTop: 'var(--s3)',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-muted)' }}>\n ⑤ Footer, max. 2 Aktionen\n </span>\n </div>\n </div>\n </div>\n</Unstyled>\n\n## Wann welche Variante\n\n| Variante | Klasse | Wann einsetzen | Elevation |\n|---|---|---|---|\n| Statisch | `.card` | Der Standard, Karten deren Aktionen in Footer-Buttons liegen, dazu Listen- und Tabellen-Kontexte ohne visuelle Schwere | `--e0` + Rahmen |\n| Link-Karte | `a.card.card-elevated` | Wenn die ganze Karte zu einem Ziel führt: Listing-Teaser, Beitrags-, Job- und Veranstaltungs-Karten | `--e1`, Hover `--e2` + Lift |\n\n**Klickbare Karte als Modus.** Wenn die ganze Karte zu einem Ziel führen soll, gibt es zwei Patterns, je nach Karten-Typ und Inhaltsdichte:\n\n| Pattern | Wrapping | Wann einsetzen |\n|---|---|---|\n| `.ep-card.ep-card-link` | `<a class=\"ep-card ep-card-link\">` | Kompakte Teaser-Kacheln mit Icon, Eyebrow, Titel, kurzem Text und CTA-Pfeil-Zeile, ohne Card-Footer-Buttons |\n| `a.card.card-elevated` | `<a class=\"card card-elevated\">` | Textreiche Listing-Cards mit Card-Media, Card-Body (Pill, Titel, Text, Meta-Zeile) und implizitem „Beitrag lesen →“-Anker am Ende |\n| `a.card.card-elevated.card-featured` | `<a class=\"card card-elevated card-featured\">` | Horizontale Großkarte für genau einen hervorgehobenen Beitrag oder Termin, Bild links im 16:9, Content rechts |\n\nIn Angular deckt jedes der drei Patterns ein eigenes Bauteil ab: `<a cdsIconCard>` (Icon-Karte), `cds-link-card` (Klickbare Karte) und `cds-featured-card` (Featured-Karte).\n\n**Weitere CSS-Rezepte ohne eigenes Bauteil**, sinnvoll dort, wo ein weiteres Karten-Grid die Seite überladen würde:\n\n| Muster | Rolle | Wann statt Karte |\n|---|---|---|\n| Stat-Karte (`.card-stat`) | Eigenständige KPI-Kachel mit Rahmen | Kennzahlen auf Landingpages, Jahresberichten, Dashboards |\n| Bandstreifen (`.card-stat-strip` / `.card-stat-flat`) | Flache Variante ohne Rahmen und Schatten | Kompakte KPI-Bänder, Footer-Stats, Hero-Anschluss-Sektionen |\n| Editoriale Kennzahl-Zeile | Redaktioneller Fließinhalt, nur durch Haarlinien getrennt, kein Karten-Chrome | Case-, Projekt- und Leistungslisten, wenn auf der Seite bereits Karten-Grids stehen |\n| Offene Feature-Liste (`.ep-feature`, in Angular `<div cdsFeature>`) | Icon-geführte Aufzählung ohne Rahmen, Schatten oder Media-Fläche | Vollständiger Funktionsumfang, wenn ein weiteres Karten-Grid überladen würde |\n\nKarten sind für Angebots-Menüs und Teaser da: Lösungs- und Leistungskacheln, Artikel-Vorschauen, Elemente, die zu einem Ziel führen und als abgeschlossene, klickbare Einheit funktionieren. Für Stimmen, Funktions- und Case-Listen ist meist eine offene, redaktionelle Darstellung die bessere Wahl: direkt auf der Fläche, durch Haarlinien getrennt. Das hält inhaltsdichte Abschnitte luftig und vermeidet den Eindruck einer Kachelwand, wenn mehrere Karten-Grids aufeinanderfolgen.\n\n**Testimonial-Karte**: wohnt unter `Komponenten/Zitate & Testimonials/Testimonial`, hier nur der Querverweis. Zitat mit Quellenangabe, farbiger Top-Border signalisiert die Brand Area, Auszeichnung über `<figure>` + `<blockquote>` für korrekte Semantik.\n\n<Unstyled>\n <div className=\"layout-grid\">\n <div className=\"col-4\">\n <div\n style={{\n font: '500 12px/16px var(--font)',\n color: 'var(--tx-muted)',\n marginBottom: 'var(--s2)',\n }}\n >\n Mit Media-Bereich → keine Linie\n </div>\n <div style={{ border: 'var(--bd-strong)', borderRadius: 'var(--r-lg)', overflow: 'hidden' }}>\n <div\n style={{\n height: 40,\n background: 'var(--co-50)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n Media\n </span>\n </div>\n <div style={{ padding: 'var(--s3) var(--s4)' }}>\n <div\n style={{\n height: 6,\n borderRadius: 3,\n background: 'var(--n-200)',\n marginBottom: 6,\n width: '55%',\n }}\n />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', marginBottom: 4 }} />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', width: '80%' }} />\n </div>\n </div>\n </div>\n <div className=\"col-4\">\n <div\n style={{\n font: '500 12px/16px var(--font)',\n color: 'var(--tx-muted)',\n marginBottom: 'var(--s2)',\n }}\n >\n Ohne Media-Bereich → Linie oben\n </div>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderTop: '4px solid var(--co-500)',\n borderRadius: 'var(--r-lg)',\n overflow: 'hidden',\n }}\n >\n <div style={{ padding: 'var(--s3) var(--s4)' }}>\n <div\n style={{\n height: 6,\n borderRadius: 3,\n background: 'var(--n-200)',\n marginBottom: 6,\n width: '55%',\n }}\n />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', marginBottom: 4 }} />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', width: '80%' }} />\n </div>\n </div>\n </div>\n </div>\n</Unstyled>\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Semantik | `<article>` für eigenständige Cards, Screenreader listen Artikel als navigierbare Landmark, Überschriften-Hierarchie einhalten (Card-Titel als `h3` unter einer Section-`h2`) |\n| Klickbereich | Wenn die ganze Karte zu einem Ziel führt: das umschließende Element auf `<a>` oder `<button>` umstellen, nie `<div>` mit `onclick`. Pfeil-Suffix in `<span aria-hidden=\"true\">` hüllen, Focus-Ring sichtbar lassen. Trägt die Karte nur passive Information, gehören Interaktionselemente ausschließlich in den Card-Footer |\n| Bilder & Icons | Card-Media-Bilder mit beschreibendem `alt`-Text versehen, dekorative SVGs mit `aria-hidden=\"true\"` + `focusable=\"false\"` ausblenden |\n\n**Bildslots sind 16/9 und kommen aus `.card-media`.** Listing-Grid und Featured-Card teilen sich das Verhältnis, damit Redaktion pro Beitrag ein Bild in einem Zuschnitt pflegt statt einen je Slot. Den Bildausschnitt setzt `object-position` am `<img>`, nicht `background-position` an einem Container, sonst gilt der Zuschnitt nur in einem Slot. Eigene Verhältnisse haben nur Hero und Slider (21/9) sowie Avatare (1/1). Reicht die Höhe nicht, wird Text gekappt, nicht das Verhältnis gedehnt.\n\n**Der Abstand gehört dem Container, nicht dem Kind.** `.card-body` ist eine Flex-Spalte mit `gap: var(--s3)`, das ist der einzige vertikale Rhythmus der Karte. `.card-eyebrow`, `.card-cta-link` und die Pill setzen im Card-Body keine eigene Marge, sonst addiert sie sich zum `gap`, statt zu kollabieren, denn im Flex-Layout kollabieren Margen nicht. Braucht eine Karte mehr Luft, wird nur der `gap` überschrieben, nicht eine Marge nachgeschoben.\n\n## Dos & Don'ts\n\n**Tun**\n\n- Eyebrow und Media konsequent in der Bereichsfarbe halten, die Karte ist immer einem Bereich zugehörig.\n- Schatten nur auf Link-Karten (`a.card.card-elevated`), Karten mit Aktionen im Footer ruhen flach mit Rahmen.\n- Max. 2 Aktionen im Card-Footer: Text-Button (sekundär) plus Filled-Button (primär).\n- Card-Text auf max. 2 Sätze begrenzen, prägnant und scanbar, kein Fließtext.\n- Gleichartige Karten in einem Grid konsistent halten, gleiche Variante, gleiche Breite.\n\n**Nicht tun**\n\n- Statische und Link-Karten in derselben Reihe mischen, der Schatten liest sich dann als Zufall statt als Klick-Angebot.\n- Mehr als 2 Filled Buttons im Footer, die Hierarchie wird unklar, eine Hauptaktion reicht.\n- Bereichsfarben einer Karte und ihrer Nachbarkarte mischen, jede Karte gehört zu einem Bereich.\n- Eine Karte erhöhen, deren Fläche nirgendwohin führt, das verspricht Klickbarkeit, die es nicht gibt.\n- Langen Fließtext in Card-Body, stattdessen einen Teaser formulieren und auf eine Detailseite verlinken.\n\n## Verwandte Seiten\n\n- Card (`Komponenten/Cards & Teaser/Card`)\n- Klickbare Karte (`Komponenten/Cards & Teaser/Klickbare Karte`), `cds-link-card`\n- Featured-Karte (`Komponenten/Cards & Teaser/Featured-Karte`), `cds-featured-card`\n- Icon-Karte (`Komponenten/Cards & Teaser/Icon-Karte`), `[cdsIconCard]`\n- Feature-Liste (`Komponenten/Cards & Teaser/Feature-Liste`), `[cdsFeature]`\n- Tier-Trenner (`Komponenten/Cards & Teaser/Tier-Trenner`), `cds-tier`\n- StatCard (`Komponenten/Cards & Teaser/StatCard`)\n- StatStrip (`Komponenten/Cards & Teaser/StatStrip`)\n- Testimonial (`Komponenten/Zitate & Testimonials/Testimonial`), Zitat-Karte mit Quellenangabe, hier nur verlinkt\n",
|
|
12
|
+
"content": "import { Meta, Unstyled } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Cards & Teaser\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nGenerische Karten (statisch, Link-Karte) und Inhaltskarten (Stat), alle Brand Areas, barrierefrei. Der Abschnitt deckt mehr ab, als es eigene Bauteile gibt: die editoriale Kennzahl-Zeile ist ein reines CSS-Rezept ohne eigene Komponente. Klickbare Karte, Featured-Karte, Icon-Karte, offene Feature-Liste und Tier-Trenner haben jeweils ein eigenes Angular-Bauteil (siehe „Verwandte Seiten“).\n\n## Anatomie\n\nDie folgende Anatomie zeigt die fünf Bausteine einer generischen Karte: Media-Bereich, Eyebrow, Title, Text und Footer. Die Ziffern korrespondieren mit den Begriffen, die in den übrigen Abschnitten dieser Seite verwendet werden.\n\n<Unstyled>\n <div style={{ border: 'var(--bd-strong)', borderRadius: 'var(--r-lg)', overflow: 'hidden' }}>\n <div\n style={{\n height: 60,\n background: 'var(--co-50)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderBottom: 'var(--bd)',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n ① Media, Bereichsfarbe <code className=\"token\">-50</code>\n </span>\n </div>\n <div style={{ padding: 'var(--s4)' }}>\n <div\n className=\"t-co\"\n style={{\n font: '500 12px/16px var(--font)',\n letterSpacing: '.08em',\n textTransform: 'uppercase',\n marginBottom: 'var(--s1)',\n }}\n >\n ② Eyebrow, Bereichsname\n </div>\n <div\n style={{\n font: '500 16px/24px var(--font)',\n color: 'var(--tx-primary)',\n marginBottom: 'var(--s1)',\n }}\n >\n ③ Title, Kernaussage\n </div>\n <div style={{ font: 'var(--ty-body-md)', color: 'var(--tx-secondary)', marginBottom: 'var(--s4)' }}>\n ④ Text, max. 2 Sätze, konkret\n </div>\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 'var(--s2)',\n borderTop: 'var(--bd)',\n paddingTop: 'var(--s3)',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-muted)' }}>\n ⑤ Footer, max. 2 Aktionen\n </span>\n </div>\n </div>\n </div>\n</Unstyled>\n\n## Wann welche Variante\n\n| Variante | Klasse | Wann einsetzen | Elevation |\n|---|---|---|---|\n| Statisch | `.card` | Der Standard, Karten deren Aktionen in Footer-Buttons liegen, dazu Listen- und Tabellen-Kontexte ohne visuelle Schwere | `--e0` + Rahmen |\n| Link-Karte | `a.card.card-elevated` | Wenn die ganze Karte zu einem Ziel führt: Listing-Teaser, Beitrags-, Job- und Veranstaltungs-Karten | `--e1`, Hover `--e2` + Lift |\n\n**Klickbare Karte als Modus.** Wenn die ganze Karte zu einem Ziel führen soll, gibt es zwei Patterns, je nach Karten-Typ und Inhaltsdichte:\n\n| Pattern | Wrapping | Wann einsetzen |\n|---|---|---|\n| `.ep-card.ep-card-link` | `<a class=\"ep-card ep-card-link\">` | Kompakte Teaser-Kacheln mit Icon, Eyebrow, Titel, kurzem Text und CTA-Pfeil-Zeile, ohne Card-Footer-Buttons |\n| `a.card.card-elevated` | `<a class=\"card card-elevated\">` | Textreiche Listing-Cards mit Card-Media, Card-Body (Pill, Titel, Text, Meta-Zeile) und implizitem „Beitrag lesen →“-Anker am Ende |\n| `a.card.card-elevated.card-featured` | `<a class=\"card card-elevated card-featured\">` | Horizontale Großkarte für genau einen hervorgehobenen Beitrag oder Termin, Bild links im 16:9, Content rechts |\n\nIn Angular deckt jedes der drei Patterns ein eigenes Bauteil ab: `<a cdsIconCard>` (Icon-Karte), `cds-link-card` (Klickbare Karte) und `cds-featured-card` (Featured-Karte).\n\n**Weitere CSS-Rezepte ohne eigenes Bauteil**, sinnvoll dort, wo ein weiteres Karten-Grid die Seite überladen würde:\n\n| Muster | Rolle | Wann statt Karte |\n|---|---|---|\n| Stat-Karte (`.card-stat`) | Eigenständige KPI-Kachel mit Rahmen | Kennzahlen auf Landingpages, Jahresberichten, Dashboards |\n| Bandstreifen (`.card-stat-strip` / `.card-stat-flat`) | Flache Variante ohne Rahmen und Schatten | Kompakte KPI-Bänder, Footer-Stats, Hero-Anschluss-Sektionen |\n| Editoriale Kennzahl-Zeile | Redaktioneller Fließinhalt, nur durch Haarlinien getrennt, kein Karten-Chrome | Case-, Projekt- und Leistungslisten, wenn auf der Seite bereits Karten-Grids stehen |\n| Offene Feature-Liste (`.ep-feature`, in Angular `<div cdsFeature>`) | Icon-geführte Aufzählung ohne Rahmen, Schatten oder Media-Fläche | Vollständiger Funktionsumfang, wenn ein weiteres Karten-Grid überladen würde |\n\nKarten sind für Angebots-Menüs und Teaser da: Lösungs- und Leistungskacheln, Artikel-Vorschauen, Elemente, die zu einem Ziel führen und als abgeschlossene, klickbare Einheit funktionieren. Für Stimmen, Funktions- und Case-Listen ist meist eine offene, redaktionelle Darstellung die bessere Wahl: direkt auf der Fläche, durch Haarlinien getrennt. Das hält inhaltsdichte Abschnitte luftig und vermeidet den Eindruck einer Kachelwand, wenn mehrere Karten-Grids aufeinanderfolgen.\n\n**Testimonial-Karte**: wohnt unter `Komponenten/Zitate & Testimonials/Testimonial`, hier nur der Querverweis. Zitat mit Quellenangabe, farbiger Top-Border signalisiert die Brand Area, Auszeichnung über `<figure>` + `<blockquote>` für korrekte Semantik.\n\n**Warum oben und nicht links?** Die Leserichtung ist von links nach rechts, von oben nach unten, der oberste Kartenrand ist der erste Fixpunkt beim Scannen einer Seite. Die Linie links eignet sich für redaktionellen Fließinhalt (Blockquote), weil der Text direkt daneben beginnt und die Linie als Begleiter wirkt. Bei einer abgeschlossenen Karte würde ein linker Rand mit dem Layout-Raster kollidieren und die Außenkante der Karte unruhig machen.\n\n<Unstyled>\n <div className=\"layout-grid\">\n <div className=\"col-4\">\n <div\n style={{\n font: '500 12px/16px var(--font)',\n color: 'var(--tx-muted)',\n marginBottom: 'var(--s2)',\n }}\n >\n Mit Media-Bereich → keine Linie\n </div>\n <div style={{ border: 'var(--bd-strong)', borderRadius: 'var(--r-lg)', overflow: 'hidden' }}>\n <div\n style={{\n height: 40,\n background: 'var(--co-50)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n Media\n </span>\n </div>\n <div style={{ padding: 'var(--s3) var(--s4)' }}>\n <div\n style={{\n height: 6,\n borderRadius: 3,\n background: 'var(--n-200)',\n marginBottom: 6,\n width: '55%',\n }}\n />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', marginBottom: 4 }} />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', width: '80%' }} />\n </div>\n </div>\n </div>\n <div className=\"col-4\">\n <div\n style={{\n font: '500 12px/16px var(--font)',\n color: 'var(--tx-muted)',\n marginBottom: 'var(--s2)',\n }}\n >\n Ohne Media-Bereich → Linie oben\n </div>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderTop: '4px solid var(--co-500)',\n borderRadius: 'var(--r-lg)',\n overflow: 'hidden',\n }}\n >\n <div style={{ padding: 'var(--s3) var(--s4)' }}>\n <div\n style={{\n height: 6,\n borderRadius: 3,\n background: 'var(--n-200)',\n marginBottom: 6,\n width: '55%',\n }}\n />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', marginBottom: 4 }} />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', width: '80%' }} />\n </div>\n </div>\n </div>\n </div>\n</Unstyled>\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Semantik | `<article>` für eigenständige Cards, Screenreader listen Artikel als navigierbare Landmark, Überschriften-Hierarchie einhalten (Card-Titel als `h3` unter einer Section-`h2`) |\n| Klickbereich | Wenn die ganze Karte zu einem Ziel führt: das umschließende Element auf `<a>` oder `<button>` umstellen, nie `<div>` mit `onclick`. Pfeil-Suffix in `<span aria-hidden=\"true\">` hüllen, Focus-Ring sichtbar lassen. Trägt die Karte nur passive Information, gehören Interaktionselemente ausschließlich in den Card-Footer |\n| Bilder & Icons | Card-Media-Bilder mit beschreibendem `alt`-Text versehen, dekorative SVGs mit `aria-hidden=\"true\"` + `focusable=\"false\"` ausblenden |\n\n**Bildslots sind 16/9 und kommen aus `.card-media`.** Listing-Grid und Featured-Card teilen sich das Verhältnis, damit Redaktion pro Beitrag ein Bild in einem Zuschnitt pflegt statt einen je Slot. Den Bildausschnitt setzt `object-position` am `<img>`, nicht `background-position` an einem Container, sonst gilt der Zuschnitt nur in einem Slot. Eigene Verhältnisse haben nur Hero und Slider (21/9) sowie Avatare (1/1). Reicht die Höhe nicht, wird Text gekappt, nicht das Verhältnis gedehnt.\n\n**Der Abstand gehört dem Container, nicht dem Kind.** `.card-body` ist eine Flex-Spalte mit `gap: var(--s3)`, das ist der einzige vertikale Rhythmus der Karte. `.card-eyebrow`, `.card-cta-link` und die Pill setzen im Card-Body keine eigene Marge, sonst addiert sie sich zum `gap`, statt zu kollabieren, denn im Flex-Layout kollabieren Margen nicht. Braucht eine Karte mehr Luft, wird nur der `gap` überschrieben, nicht eine Marge nachgeschoben.\n\n## Dos & Don'ts\n\n**Tun**\n\n- Eyebrow und Media konsequent in der Bereichsfarbe halten, die Karte ist immer einem Bereich zugehörig.\n- Schatten nur auf Link-Karten (`a.card.card-elevated`), Karten mit Aktionen im Footer ruhen flach mit Rahmen.\n- Max. 2 Aktionen im Card-Footer: Text-Button (sekundär) plus Filled-Button (primär).\n- Card-Text auf max. 2 Sätze begrenzen, prägnant und scanbar, kein Fließtext.\n- Gleichartige Karten in einem Grid konsistent halten, gleiche Variante, gleiche Breite.\n\n**Nicht tun**\n\n- Statische und Link-Karten in derselben Reihe mischen, der Schatten liest sich dann als Zufall statt als Klick-Angebot.\n- Mehr als 2 Filled Buttons im Footer, die Hierarchie wird unklar, eine Hauptaktion reicht.\n- Bereichsfarben einer Karte und ihrer Nachbarkarte mischen, jede Karte gehört zu einem Bereich.\n- Eine Karte erhöhen, deren Fläche nirgendwohin führt, das verspricht Klickbarkeit, die es nicht gibt.\n- Langen Fließtext in Card-Body, stattdessen einen Teaser formulieren und auf eine Detailseite verlinken.\n\n## Verwandte Seiten\n\n- Card (`Komponenten/Cards & Teaser/Card`)\n- Klickbare Karte (`Komponenten/Cards & Teaser/Klickbare Karte`), `cds-link-card`\n- Featured-Karte (`Komponenten/Cards & Teaser/Featured-Karte`), `cds-featured-card`\n- Icon-Karte (`Komponenten/Cards & Teaser/Icon-Karte`), `[cdsIconCard]`\n- Feature-Liste (`Komponenten/Cards & Teaser/Feature-Liste`), `[cdsFeature]`\n- Tier-Trenner (`Komponenten/Cards & Teaser/Tier-Trenner`), `cds-tier`\n- StatCard (`Komponenten/Cards & Teaser/StatCard`)\n- StatStrip (`Komponenten/Cards & Teaser/StatStrip`)\n- Testimonial (`Komponenten/Zitate & Testimonials/Testimonial`), Zitat-Karte mit Quellenangabe, hier nur verlinkt\n",
|
|
13
13
|
"summary": "# Verwendung Generische Karten (statisch, Link-Karte) und Inhaltskarten (Stat), alle Brand..."
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"name": "Übersicht",
|
|
10
10
|
"path": "./src/docs/komponenten/sektion.mdx",
|
|
11
11
|
"title": "Komponenten/Sektion",
|
|
12
|
-
"content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Sektion\" name=\"Übersicht\" />\n\n# Sektion\n\nDas strukturelle Gerüst, in dem auf den Beispielseiten praktisch jeder andere\nBaustein sitzt: `.ep-section` mit dem optionalen Kopf-Trio aus Kicker, Überschrift\nund Lead. 133 Vorkommen in den Beispielseiten, 85 davon mit Kopfzeile. Das\nAngular-Bauteil ist `Komponenten/Sektion/Sektion` (`[cdsSection]`).\n\nQuelle: `docs/index.html#sec-section`.\n\n## Aufbau\n\nDrei Klassen bilden den Kopf: `.ep-section-label` (Kicker, bereichsfärbbar über\n`.t-co` / `.t-ki` / `.t-es` / `.t-wo`), `.ep-section-h2` (Überschrift) und\n`.ep-section-sub` (Lead). Alle drei sind Beiwerk: Eine Sektion besteht auch ganz\nohne Kopf, nur aus ihrem Inhalt darunter.\n\n```html\n<div class=\"ep-section\" style=\"background:var(--n-50)\">\n <div class=\"ep-section-label t-co\">Was wir tun</div>\n <h2 class=\"ep-section-h2\">So ist eine Sektion aufgebaut.</h2>\n <p class=\"ep-section-sub\">Kicker, Überschrift und Lead sind Beiwerk, der Inhalt darunter ist frei.</p>\n <!-- beliebiger Inhalt -->\n</div>\n```\n\n## Angular-Wrapper\n\n`[cdsSection]` ist ein Attributselektor statt eines eigenen Elements\n(`docs/adr/0008-selektortyp-der-wrapper-komponenten.md`). Der\nKonsument wählt das Tag: `<section cdsSection>` oder `<div cdsSection>`. Die\nKomponente setzt `aria-labelledby`, wenn ein zugänglicher Name verfügbar ist:\nentweder die eigene Überschrift oder eine per `labelledBy` übergebene id einer\nÜberschrift außerhalb der Komponente. Fehlt beides, setzt sie kein\n`aria-labelledby`.\n\n## Verwendung\n\nDie Fläche gehört der Seite, nicht dem Bauteil. Sektionen wechseln im Rhythmus\nzwischen `--bg-surface` und `--n-50`, auf einzelnen Sektionsflächen kommt\nzusätzlich eine Bereichstönung als Akzent vor. Welche Fläche eine Sektion trägt,\nhängt von ihren Nachbarn ab, und nur die Seite kennt diese Nachbarn. Deshalb setzt\n`.ep-section` selbst keinen Hintergrund, und `[cdsSection]` hat keinen\n`background`-Input: Die Fläche kommt per Klasse oder Inline-Style direkt an das\nElement, das `cdsSection` trägt (`<section cdsSection style=\"background:…\">`).\n",
|
|
12
|
+
"content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Sektion\" name=\"Übersicht\" />\n\n# Sektion\n\nDas strukturelle Gerüst, in dem auf den Beispielseiten praktisch jeder andere\nBaustein sitzt: `.ep-section` mit dem optionalen Kopf-Trio aus Kicker, Überschrift\nund Lead. 133 Vorkommen in den Beispielseiten, 85 davon mit Kopfzeile. Das\nAngular-Bauteil ist `Komponenten/Sektion/Sektion` (`[cdsSection]`).\n\nQuelle: `docs/index.html#sec-section`.\n\n## Aufbau\n\nDrei Klassen bilden den Kopf: `.ep-section-label` (Kicker, bereichsfärbbar über\n`.t-co` / `.t-ki` / `.t-es` / `.t-wo`), `.ep-section-h2` (Überschrift) und\n`.ep-section-sub` (Lead). Alle drei sind Beiwerk: Eine Sektion besteht auch ganz\nohne Kopf, nur aus ihrem Inhalt darunter.\n\n```html\n<div class=\"ep-section\" style=\"background:var(--n-50)\">\n <div class=\"ep-section-label t-co\">Was wir tun</div>\n <h2 class=\"ep-section-h2\">So ist eine Sektion aufgebaut.</h2>\n <p class=\"ep-section-sub\">Kicker, Überschrift und Lead sind Beiwerk, der Inhalt darunter ist frei.</p>\n <!-- beliebiger Inhalt -->\n</div>\n```\n\n## Angular-Wrapper\n\n`[cdsSection]` ist ein Attributselektor statt eines eigenen Elements\n(`docs/adr/0008-selektortyp-der-wrapper-komponenten.md`). Der\nKonsument wählt das Tag: `<section cdsSection>` oder `<div cdsSection>`. Die\nKomponente setzt `aria-labelledby`, wenn ein zugänglicher Name verfügbar ist:\nentweder die eigene Überschrift oder eine per `labelledBy` übergebene id einer\nÜberschrift außerhalb der Komponente. Fehlt beides, setzt sie kein\n`aria-labelledby`.\n\n## Verwendung\n\nDie Fläche gehört der Seite, nicht dem Bauteil. Sektionen wechseln im Rhythmus\nzwischen `--bg-surface` und `--n-50`, auf einzelnen Sektionsflächen kommt\nzusätzlich eine Bereichstönung als Akzent vor. Welche Fläche eine Sektion trägt,\nhängt von ihren Nachbarn ab, und nur die Seite kennt diese Nachbarn. Deshalb setzt\n`.ep-section` selbst keinen Hintergrund, und `[cdsSection]` hat keinen\n`background`-Input: Die Fläche kommt per Klasse oder Inline-Style direkt an das\nElement, das `cdsSection` trägt (`<section cdsSection style=\"background:…\">`).\n\n## Dos & Don'ts\n\n**Tun**\n\n- Die Hintergrundfläche als Klasse oder Style auf dem Element setzen, das `cdsSection` trägt, im Wechsel mit den Nachbar-Sektionen.\n- Kicker, Überschrift und Lead weglassen, wenn eine Sektion keinen eigenen Kopf braucht.\n- Ohne eigene Überschrift `labelledBy` auf eine vorhandene Überschrift setzen, damit die Sektion einen zugänglichen Namen behält.\n\n**Nicht tun**\n\n- Eine Hintergrundfarbe fest in die Komponente einbauen, sie kennt ihre Nachbar-Sektionen nicht.\n- Mehrere getönte Sektionen direkt hintereinander setzen, das wirkt schnell bunt statt ruhig.\n- Im Angular-Wrapper `<section cdsSection>` ohne Überschrift und ohne `labelledBy` schreiben, wenn `<div cdsSection>` genügt: die Sektion bliebe für Screenreader ohnehin namenlos, das Tag verspricht aber eine Landmark, die nie entsteht.\n",
|
|
13
13
|
"summary": "# Sektion Das strukturelle Gerüst, in dem auf den Beispielseiten praktisch jeder andere Ba..."
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"name": "Verwendung",
|
|
10
10
|
"path": "./src/docs/komponenten/theme-umschalter.mdx",
|
|
11
11
|
"title": "Komponenten/Theme-Umschalter",
|
|
12
|
-
"content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Theme-Umschalter\" name=\"Verwendung\" tags={['angular']} />\n\n# Theme-Umschalter · Verwendung\n\
|
|
13
|
-
"summary": "# Theme-Umschalter · Verwendung
|
|
12
|
+
"content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Theme-Umschalter\" name=\"Verwendung\" tags={['angular']} />\n\n# Theme-Umschalter · Verwendung\n\n`docs/index.html` hat für den Theme-Umschalter eine eigene Sektion (`sec-theme`,\nÜberschrift „Theme-Umschalter“) mit einem `gt-theme-verwendung`-Block. Deren\nPlatzierungsregeln (welches der drei Bauteile wo eingesetzt wird) folgen hier\nnoch. Diese Seite beschreibt deshalb vor allem das Bauteil aus dem Repo selbst:\nder Angular-Lib\n(`angular-lib/projects/design-system-angular/src/lib/theme-switch/`) und der\nStorybook-Konfiguration (`.storybook/preview.ts`).\n\n## Dreistufiger Modus\n\n`CdsThemeMode` kennt drei Werte: `light`, `dark`, `system`. `system` folgt der\nBetriebssystem-Einstellung (`prefers-color-scheme`). Die Reihenfolge, in der alle\ndrei Umschalter zyklen beziehungsweise Optionen anbieten, ist fest:\n`CDS_THEME_ORDER = ['light', 'dark', 'system']`.\n\n| Modus | Label | Icon-Key |\n|---|---|---|\n| `light` | Hell | `heroSun` |\n| `dark` | Dunkel | `heroMoon` |\n| `system` | System | `heroComputerDesktop` |\n\nAlle drei Umschalter teilen denselben `showSystem`-Parameter: `true` zeigt alle drei\nModi (tri), `false` blendet „System“ aus und zyklt nur zwischen Hell und Dunkel\n(binär). Die Auswahl trifft `cdsThemeModes(showSystem)` in `theme-mode.ts`.\n\n## `themeStore` als einziger Schreiber von `data-theme`\n\nAlle drei Komponenten und die Storybook-Toolbar lesen und schreiben über\n`themeStore` (`theme-mode.ts`), eine modul-globale Quelle, kein Angular-Service:\nJede Story hat ihre eigene App-Instanz mit eigenem Root-Injector, Angular-DI allein\nwürde den Zustand also nicht über alle Stories hinweg teilen. `ThemeModeService` ist\nnur ein dünner Injectable-Wrapper darüber für `inject(ThemeModeService)` im\ngewohnten Muster.\n\n`themeStore` ist die **einzige** Stelle im System, die das Attribut `data-theme` am\n`<html>`-Element setzt oder entfernt:\n\n- `dark` gesetzt → `data-theme=\"dark\"`.\n- `light` → Attribut entfernt (Light ist der Default ohne Attribut).\n- `system` → koppelt live an `window.matchMedia('(prefers-color-scheme: dark)')`\n und reflektiert dessen `matches`-Wert als `dark` oder `light`; ein\n `change`-Listener hält das synchron, solange der Modus `system` bleibt.\n\nEin `document`/`window`-Guard schützt SSR und Prerendering: Ohne `document` wird\ndas Attribut übersprungen, der Modus bleibt im Signal erhalten und greift, sobald im\nBrowser das nächste `apply()` läuft. Die Lib fasst den globalen Cascade sonst nicht\nan (siehe `docs/adr/0001`).\n\n## Synchronisation mit der Storybook-Toolbar\n\n`.storybook/preview.ts` verdrahtet zwei Richtungen:\n\n1. **Store → Toolbar.** `themeStore.subscribe(...)` emittiert bei jeder Änderung\n `UPDATE_GLOBALS` an den Storybook-Channel, damit der globale\n Theme-Toolbar-Schalter mitwandert, wenn eine Story-Komponente den Modus ändert.\n2. **Toolbar → Store.** Ein Decorator ruft bei jedem Kontextwechsel\n `themeStore.setSilent(context.globals['theme'])` auf: `setSilent` wendet den\n Modus an, **ohne** erneut zu emittieren, sonst entstünde eine Rückkopplungs-\n schleife zwischen Toolbar und Store.\n\nDamit bleiben Toolbar, Docs-Vorschau und alle drei Switcher-Komponenten immer\ndenselben Modus zeigen. Das Docs-Chrome selbst (Überschriften, Tabellen) bleibt\ndavon unabhängig immer im Light-Theme (`concisoLight`), weil Storybook Toolbar- und\nDocs-Theme nicht koppelt.\n\n## Dark Mode: der Unterbau aus der CSS-Schicht\n\nDer CSS-Schicht-Vertrag (`docs/GETTING-STARTED.md` § 3) kennt nur ein Attribut:\n\n```js\ndocument.documentElement.setAttribute('data-theme', 'dark'); // dunkel\ndocument.documentElement.removeAttribute('data-theme'); // hell (Default)\n```\n\n**Genau zwei Modi in der ausgelieferten CSS.** Das System kennt Light und Dark,\nkeinen dritten Modus, der der Betriebssystem-Präferenz folgt: `prefers-color-scheme`\nwird im ausgelieferten CSS nicht ausgewertet, Default ist Light. Der dritte,\nUI-seitige Modus „System“ der drei Theme-Umschalter-Komponenten liegt deshalb eine\nEbene **über** der CSS-Schicht: `themeStore` löst `system` selbst über\n`matchMedia` auf und schreibt der CSS-Schicht am Ende immer nur einen der zwei\nZustände, die sie kennt (`data-theme=\"dark\"` gesetzt oder entfernt). Ein Consumer,\nder die Betriebssystem-Präferenz ohne diese Komponenten übernehmen will, wertet sie\nim eigenen Produkt genauso aus:\n\n```js\nif (matchMedia('(prefers-color-scheme: dark)').matches)\n document.documentElement.setAttribute('data-theme', 'dark');\n```\n\n**Anti-Flash-Snippet.** Als erstes Skript im `<head>`, vor dem CSS-Paint, damit beim\nReload nicht kurz Light aufblitzt. Liest die gespeicherte Präferenz aus\n`localStorage`:\n\n```html\n<script>\n (function(){\n try {\n var t = localStorage.getItem('ds-theme');\n if (t && t !== 'light') document.documentElement.setAttribute('data-theme', t);\n } catch(e) {}\n })();\n</script>\n```\n\nPersistenz beim Umschalten: `localStorage.setItem('ds-theme', 'dark' | 'light')`.\nDie drei Angular-Umschalter selbst persistieren nicht; das bleibt Aufgabe des\nConsumers, der `themeStore.subscribe(...)` an die eigene Persistenz anschließt.\n\n**Warum das für jede Komponente gilt (CONTRIBUTING § 5).** `data-theme` ist der\neinzige Schalter im System: Alle Token flippen darüber, keine Komponente wertet\n`prefers-color-scheme` selbst aus oder führt eine eigene dritte Flächen-Stufe ein.\nWeil `themeStore` der einzige Schreiber dieses Attributs ist, bleibt diese Garantie\nauch mit drei unterschiedlichen Umschalter-Bauteilen (Cycle-Button, Segment,\nDropdown) und der Storybook-Toolbar intakt: Es gibt genau eine Quelle der Wahrheit\nfür den Modus, unabhängig davon, über welchen Umschalter er gesetzt wurde.\n\n## Verwandte Seiten\n\n- `Komponenten/Theme-Umschalter/Cycle-Button` (Icon-Button, ein Klick zyklt durch die Modi, vorgesehen für den Header)\n- `Komponenten/Theme-Umschalter/Segment` (Segment-Leiste zum Hovern, immer responsiv und animiert)\n- `Komponenten/Theme-Umschalter/Dropdown` (Custom Select, vorgesehen nur in den Einstellungen, nicht als persistentes Element)\n",
|
|
13
|
+
"summary": "# Theme-Umschalter · Verwendung `docs/index.html` hat für den Theme-Umschalter eine eigene..."
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
}
|
package/src/instructions.mjs
CHANGED
|
@@ -20,7 +20,15 @@ Feste Regeln für die Angular-Lib „@conciso/design-system-angular“:
|
|
|
20
20
|
1. CSS-Schicht und Fonts global einbinden, nicht pro Komponente. Ohne diesen Schritt bleiben die Wrapper-Komponenten ungestylt.
|
|
21
21
|
2. Kein eigenes CSS für DS-Komponenten schreiben und keine CSS-Klassen erfinden.
|
|
22
22
|
3. Nur Inputs und Outputs verwenden, die docs-show für die jeweilige Komponente liefert. Vorher nachsehen, nie raten.
|
|
23
|
-
4. Bei Fragen zur Einrichtung docs-show mit der ID „${EINRICHTUNG_DOC_ID}“ aufrufen (Storybook-Seite „Einrichtung“)
|
|
23
|
+
4. Bei Fragen zur Einrichtung docs-show mit der ID „${EINRICHTUNG_DOC_ID}“ aufrufen (Storybook-Seite „Einrichtung“).
|
|
24
|
+
5. Für Auswahl- und Gestaltungsfragen (welche Komponente, welche Variante, wo platzieren) zusätzlich die Verwendungsguidance heranziehen: Sie steht, wenn vorhanden, in der docs-show-Antwort der Komponente im Abschnitt „Docs“. Fehlt dieser Abschnitt, über docs-list nach einer Seite „Verwendung“ der Komponentengruppe suchen und sie mit docs-show laden.`;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Anzahl der oben nummerierten Regeln in OWN_INSTRUCTIONS. Exportiert, damit ein Test sie gegen
|
|
28
|
+
* die Regel-Liste in der Paket-README (mcp-server/README.md, Abschnitt „Was er kann“) absichern
|
|
29
|
+
* kann, ohne die Regeln selbst dafür zu duplizieren.
|
|
30
|
+
*/
|
|
31
|
+
export const OWN_RULE_COUNT = (OWN_INSTRUCTIONS.match(/^\d+\.\s/gm) ?? []).length;
|
|
24
32
|
|
|
25
33
|
/**
|
|
26
34
|
* Baut den vollständigen `instructions`-Text: eigene Regeln, optional die Versions-Notiz aus
|