@klodd/ds 3.14.14 → 3.15.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/SKILL.md +76 -1
- package/css/base/typography.css +1 -0
- package/css/components/banner.css +1 -1
- package/css/components/collapsible.css +1 -1
- package/css/components/dropdown.css +3 -1
- package/css/components/feedback.css +6 -3
- package/css/components/form.css +1 -1
- package/css/components/hero.css +3 -1
- package/css/components/hub-card.css +1 -1
- package/css/components/inline-edit.css +1 -1
- package/css/components/list-row.css +1 -1
- package/css/components/nav.css +8 -5
- package/css/components/offline.css +1 -1
- package/css/components/overlay.css +10 -5
- package/css/components/panel.css +1 -1
- package/css/components/setting-row.css +1 -1
- package/css/components/sheet-content.css +2 -2
- package/css/components/stat.css +1 -1
- package/css/components/swipe-stack.css +1 -1
- package/css/components/tab-bar.css +2 -2
- package/css/components/tooltip.css +1 -1
- package/package.json +9 -2
- package/references/02-components.md +137 -0
- package/references/03-quality-bar.md +26 -3
- package/references/04-locked-decisions/0011-strikt-bem-elementsyntax.md +133 -0
- package/references/04-locked-decisions/0012-stylelint-bem-enforcement.md +117 -0
- package/references/AUDIT-VISUAL-COHERENCE-2026-05-12.md +216 -0
- package/references/DESIGN-LANGUAGE.md +305 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Klodd Design Language
|
|
2
|
+
|
|
3
|
+
Konkreta regler för **visuell koherens** över Klodd-ekosystemet. Token-
|
|
4
|
+
arkitekturen (`01-tokens.md`) och komponent-API (`02-components.md`)
|
|
5
|
+
specificerar **vad** som finns; denna fil specificerar **hur** komponenter
|
|
6
|
+
ska användas tillsammans för homogen design-uttryck.
|
|
7
|
+
|
|
8
|
+
**Grundprincip:** rytm > flexibilitet. Begränsade val ger visuell
|
|
9
|
+
koherens. Varje element i samma kategori ska kunna bytas ut mot ett
|
|
10
|
+
annat utan att layout-rytm bryts.
|
|
11
|
+
|
|
12
|
+
Etablerad 2026-05-12 baserat på audit av 17 vyer (se
|
|
13
|
+
`AUDIT-VISUAL-COHERENCE-2026-05-12.md`).
|
|
14
|
+
|
|
15
|
+
## 1. Border-radius-skala (fem värden)
|
|
16
|
+
|
|
17
|
+
**Regel:** all border-radius i komponent-CSS ska vara EN av:
|
|
18
|
+
|
|
19
|
+
| Värde | Token | Användning |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| 4px | `--radius-4` | Thin-bars: progress, skeleton-line, split-bar-segment |
|
|
22
|
+
| 10px | `--radius-10` | Button, inputs, tab-bar__item, small-action-button |
|
|
23
|
+
| 14px | `--radius-14` | All cards/containers: card, panel, hub-card, job-card, swipe-card, banner, form-card, stat-card, list-row, setting-row, toast, dialog, sheet, collapsible, offline-wrap, sheet-content fields |
|
|
24
|
+
| 50% | (calculated) | Avatars, icon-circles, toggle-thumb |
|
|
25
|
+
| 9999px | `--radius-full` | Pills: badge, chip, status-pill, dot-separator, score-pill |
|
|
26
|
+
|
|
27
|
+
**Förbjudet:** 2px, 6px, 8px, 12px, 16px, 18px, 20px, 22px, 24px på
|
|
28
|
+
komponent-element. (Existerar som tokens men ska inte appliceras
|
|
29
|
+
direkt på BR i komponent-CSS efter denna konsolidering.)
|
|
30
|
+
|
|
31
|
+
**Rationale:** ögat skiljer på fem kategorier: thin-bar, button,
|
|
32
|
+
container, circle, pill. 11+ värden ger visuell brus utan
|
|
33
|
+
informations-värde. Calle's audit-observation "olika former" var
|
|
34
|
+
denna BR-spridning.
|
|
35
|
+
|
|
36
|
+
**Migration-not:** existerande paket-komponenter med BR=6/8/12/16/20/24
|
|
37
|
+
flyttas till närmaste av de fem. Sprint 3b 2026-05-12 genomförde
|
|
38
|
+
migrationen i paketet. App-domain-CSS följer samma regel.
|
|
39
|
+
|
|
40
|
+
## 2. Shadow-policy (restriktiv)
|
|
41
|
+
|
|
42
|
+
**Regel:** shadow används i tre exakt-definierade kontexter:
|
|
43
|
+
|
|
44
|
+
| Kontext | Värde | Rationale |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| Modaler, sheets, dropdowns (overlay-elementer) | `box-shadow: none` | Dark-mode: surface-overlay + border ger djup. Shadow på mörk bg ger inverterad djupkänsla. |
|
|
47
|
+
| iOS-style active-state-indikatorer (toggle-thumb, active-tab-pill) | `var(--shadow-card)` | Fysisk thumb-feel. Motiverat per regel 10. |
|
|
48
|
+
| Allt annat | `box-shadow: none` | Default. |
|
|
49
|
+
|
|
50
|
+
**Förbjudet:**
|
|
51
|
+
- `--shadow-float`, `--shadow-resting`, `--shadow-raised`-tokens
|
|
52
|
+
utöver `--shadow-card`. (Existerar som alias - candidate för
|
|
53
|
+
borttagning i Sprint 3b.)
|
|
54
|
+
- Hardkodade `box-shadow` med oklch eller rgba
|
|
55
|
+
- Shadow på panel, card, hub-card, stat-card, banner, form-card
|
|
56
|
+
(de är inom-flow-element, hierarki via surface-tokens)
|
|
57
|
+
- Shadow på bottom-nav, toast (inom-flow + backdrop-filter räcker)
|
|
58
|
+
|
|
59
|
+
**Dark-mode-rationale:** ljus shadow på mörk bg ger inverterad
|
|
60
|
+
djupkänsla (ljust = lyft, inte sänkt). Använd surface-color-hierarki
|
|
61
|
+
istället: `--surface-page < default < raised < overlay`.
|
|
62
|
+
|
|
63
|
+
## 3. Page-toppar: två separata patterns
|
|
64
|
+
|
|
65
|
+
**Regel:** två väldefinierade patterns för page-toppar - hero och
|
|
66
|
+
page-header. Välj baserat på purpose, inte preferens.
|
|
67
|
+
|
|
68
|
+
### Pattern A: `.hero` (dashboard med metric)
|
|
69
|
+
|
|
70
|
+
För dashboards där primär-data är en STOR siffer-display.
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<section class="hero">
|
|
74
|
+
<p class="hero__label">SEKTION-LABEL</p>
|
|
75
|
+
<p class="hero__amount">{stort-värde}</p>
|
|
76
|
+
<p class="hero__meta">{kontextuell-info}</p>
|
|
77
|
+
<div class="hero__actions">
|
|
78
|
+
<button class="btn btn--primary">{primär-action}</button>
|
|
79
|
+
</div>
|
|
80
|
+
</section>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`.hero__amount` är fs-80 (siffer-display). `.hero__amount--card`
|
|
84
|
+
(fs-40) för hero inom panel. `.hero__amount--fluid` (clamp 40-80vw)
|
|
85
|
+
för responsiv siffer-display.
|
|
86
|
+
|
|
87
|
+
Hero har `padding: 20px 0 24px` (alignment med övriga container-element).
|
|
88
|
+
|
|
89
|
+
### Pattern B: `.page-header` (utility-page med titel)
|
|
90
|
+
|
|
91
|
+
För pages utan primär-metric, bara navigation-kontext.
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<div class="page-header">
|
|
95
|
+
<h1 class="page-title">{Titel}</h1>
|
|
96
|
+
<p class="page-subtitle">{Beskrivning}</p>
|
|
97
|
+
</div>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`.page-title` är fs-22 (heading-size). `.page-subtitle` är fs-13
|
|
101
|
+
muted. Page-header har `display: flex` med space-between för
|
|
102
|
+
sidoplacerade actions vid behov.
|
|
103
|
+
|
|
104
|
+
### När använda vilken
|
|
105
|
+
|
|
106
|
+
| Vy-typ | Pattern |
|
|
107
|
+
|---|---|
|
|
108
|
+
| Dashboard med primär-metric | `.hero` |
|
|
109
|
+
| Lista-vy med titel | `.page-header` |
|
|
110
|
+
| Settings-hub | `.page-header` |
|
|
111
|
+
| Detalj-vy med metric | `.hero` (inom panel: `.hero--card`) |
|
|
112
|
+
| Form-page | `.page-header` |
|
|
113
|
+
|
|
114
|
+
### Konkret per app
|
|
115
|
+
|
|
116
|
+
- **Jubb /, /installera**: `.hero` (job-count är primär-metric)
|
|
117
|
+
- **Jubb /jobb, /korningar, /insikter**: `.page-header` (list-vyer)
|
|
118
|
+
- **Jubb /triage**: ingen page-topp (swipe-stack är huvudobjekt)
|
|
119
|
+
- **Ekonom /avstamning, /privat, /bolanet, /kategorier**: `.hero`
|
|
120
|
+
(saldo/utgifter/equity är primär-metric)
|
|
121
|
+
- **Ekonom /jag**: `.page-header` (profil-vy, ingen metric)
|
|
122
|
+
- **Ekonom /installningar, /granskning, /import**: `.page-header`
|
|
123
|
+
- **Ekonom /jag/abonnemang**: `.page-header`
|
|
124
|
+
|
|
125
|
+
### Gemensam spacing-doktrin
|
|
126
|
+
|
|
127
|
+
Båda patterns följer alignment-regel sektion 8: content på `x = 14`
|
|
128
|
+
(main-padding-left). Ingen inner horizontal padding på top-level
|
|
129
|
+
container (hero, page-header).
|
|
130
|
+
|
|
131
|
+
### Förbjudet
|
|
132
|
+
|
|
133
|
+
- Blanda `.hero` och `.page-header` i samma vy
|
|
134
|
+
- Använda `<div>` med ad-hoc styling istället för en av de två
|
|
135
|
+
patterns
|
|
136
|
+
- Hardkodad font-size för titel-element (använd `.hero__amount`
|
|
137
|
+
eller `.page-title`)
|
|
138
|
+
|
|
139
|
+
## 4. Padding-rytm (sex värden)
|
|
140
|
+
|
|
141
|
+
**Regel:** all padding i komponent-CSS ska vara EN av:
|
|
142
|
+
|
|
143
|
+
| Värde | Token | Användning |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| 4px | `--space-4` | Mini-gaps, badge inner, tab-spacing |
|
|
146
|
+
| 8px | `--space-8` | Standard gap, icon-margin |
|
|
147
|
+
| 12px | `--space-12` | List-row vertical, button-internal |
|
|
148
|
+
| 16px | `--space-16` | Card internal, panel internal, hero |
|
|
149
|
+
| 20px | `--space-20` | Section gap, hero-internal vertical |
|
|
150
|
+
| 24px | `--space-24` | Major section break |
|
|
151
|
+
|
|
152
|
+
**Förbjudet i komponent-CSS:** 2, 6, 10, 14, 18, 22, 28, 32-värden
|
|
153
|
+
direkt. (Finns som tokens men reserverat för layout-grid och spacing
|
|
154
|
+
mellan section-block, inte inom komponenter.)
|
|
155
|
+
|
|
156
|
+
**Sammansatta padding (TRBL)**:
|
|
157
|
+
- Symmetric preferred: `padding: 16px` ✓
|
|
158
|
+
- Vertical-horizontal: `padding: 12px 16px` ✓
|
|
159
|
+
- Asymmetric only with rationale: `padding: 20px 0 24px` (hero) -
|
|
160
|
+
kommentar med motivering krävs
|
|
161
|
+
|
|
162
|
+
## 5. Font-size-skala (åtta värden)
|
|
163
|
+
|
|
164
|
+
**Regel:** font-size i komponent-CSS ska vara EN av token-skalan:
|
|
165
|
+
|
|
166
|
+
| Token | Användning |
|
|
167
|
+
|---|---|
|
|
168
|
+
| --fs-11 | Meta-text, time-stamps |
|
|
169
|
+
| --fs-12 | Default body, list-row-text |
|
|
170
|
+
| --fs-13 | Card-body, secondary |
|
|
171
|
+
| --fs-14 | Primary body, button-text |
|
|
172
|
+
| --fs-17 | Subtitle, panel-title |
|
|
173
|
+
| --fs-22 | Heading, section-title |
|
|
174
|
+
| --fs-32 | Large-display, card-hero |
|
|
175
|
+
| --fs-80 | Page-hero amount |
|
|
176
|
+
|
|
177
|
+
**Förbjudet:** 15px, 18px, 20px, 24px, 40px, 64px på text-content.
|
|
178
|
+
(Token-värden finns men ska användas selektivt och inom
|
|
179
|
+
specifika komponenter.)
|
|
180
|
+
|
|
181
|
+
**Förbjudet i app-domain-CSS:**
|
|
182
|
+
- `clamp()`-baserade font-sizes som ger non-integer rendering
|
|
183
|
+
- `font-size: 13.3333px` (browser sub-pixel av %-baserat värde)
|
|
184
|
+
- Hardkodade `font-size: 14px` utan token
|
|
185
|
+
- `font-size: 51.6px` (Bolanet) - off-token värde
|
|
186
|
+
|
|
187
|
+
## 6. Container-klassifikation (vilket är vad)
|
|
188
|
+
|
|
189
|
+
**Regel:** välj rätt container baserat på funktion:
|
|
190
|
+
|
|
191
|
+
| Komponent | När använda | Inte använda för |
|
|
192
|
+
|---|---|---|
|
|
193
|
+
| `.card` | Klickbar enhet med titel + body | Statisk info-panel |
|
|
194
|
+
| `.card--interactive` | Card med hover/press-feedback | Static-card |
|
|
195
|
+
| `.panel` | Ramad sektion med titel, statisk innehåll | Klickbar |
|
|
196
|
+
| `.hub-card` | Settings-hub navigation-target | Generic listrad |
|
|
197
|
+
| `.job-card` (Jubb) | Job-listing enhet | Generic card |
|
|
198
|
+
| `.swipe-card` | Tinder-stil swipeable card | Static info |
|
|
199
|
+
| `.stat-card` | Single-metric display (siffra + label) | Multi-content |
|
|
200
|
+
| `.banner` | Bred info-rad i flow | Action card |
|
|
201
|
+
| `.form-card` | Form-wrapper | Generic content |
|
|
202
|
+
| `.list-row` | Generic list-rad med ikon + body + amount | Settings-rad |
|
|
203
|
+
| `.setting-row` | Tap-to-edit settings-rad | Klickbart kort |
|
|
204
|
+
|
|
205
|
+
**Bias-toward-panel:** vid osäkerhet, använd `.panel`. Det är default-
|
|
206
|
+
container.
|
|
207
|
+
|
|
208
|
+
## 7. Spacing-rytm mellan block
|
|
209
|
+
|
|
210
|
+
**Regel:** vertikalt spacing mellan distinkta block:
|
|
211
|
+
|
|
212
|
+
- Mellan topbar och första block: `margin-bottom: 16` på topbar
|
|
213
|
+
- Mellan section-block (panel, hero, section): `margin-bottom: 14`
|
|
214
|
+
- Mellan list-row (samma list): `margin: 0` (border-top för separator)
|
|
215
|
+
- Mellan hub-card-list-items: `margin-bottom: 12`
|
|
216
|
+
- Mellan section och footer-text: `margin-top: 16` på footer
|
|
217
|
+
|
|
218
|
+
**Förbjudet:** beroende på `gap`-property på parent när siblings har
|
|
219
|
+
egna `margin-bottom`. Välj en mekanism per kontext.
|
|
220
|
+
|
|
221
|
+
## 8. Alignment-regler
|
|
222
|
+
|
|
223
|
+
**Regel:** alla primära block-content sitter på samma horizontal-x.
|
|
224
|
+
|
|
225
|
+
- Main har `padding: 16px 14px 84px` (top-right-bottom-left). Content
|
|
226
|
+
startar på `x = 14`.
|
|
227
|
+
- Container-block (panel, card, hero, hub-card) sitter på `x = 14`
|
|
228
|
+
(no extra margin).
|
|
229
|
+
- Inom container, text-content sitter på `x = 14 + container-inner-padding`.
|
|
230
|
+
- Hero ska INTE ha asymmetrisk horizontal padding (förbjudet:
|
|
231
|
+
`padding: 20px 4px 24px`). Tillåtet: `padding: 20px 0 24px` eller
|
|
232
|
+
`padding: 20px`.
|
|
233
|
+
|
|
234
|
+
## 9. PWA-specifika konventioner
|
|
235
|
+
|
|
236
|
+
### Tap-targets
|
|
237
|
+
|
|
238
|
+
- Alla interaktiva element MÅSTE vara minst 44x44px (WCAG 2.5.5).
|
|
239
|
+
- Buttons: `min-height: var(--touch-min)` (= 44).
|
|
240
|
+
- List-rows: `padding: 14px 0` minimum (= 50px height med text-line).
|
|
241
|
+
- Icon-buttons: `width: 44px; height: 44px`.
|
|
242
|
+
|
|
243
|
+
### Mobile-first
|
|
244
|
+
|
|
245
|
+
- Default-styles är mobile (375-430 viewport).
|
|
246
|
+
- Tablet (768+) och desktop (1024+) är progressive enhancements.
|
|
247
|
+
- Test alltid på iPhone 14 Pro Max (430x932) som baseline.
|
|
248
|
+
|
|
249
|
+
### Safe areas
|
|
250
|
+
|
|
251
|
+
- `padding-top: calc(var(--safe-top) + 16px)` på main för iOS-notch.
|
|
252
|
+
- `padding-bottom: var(--bottom-nav-clearance)` (= 84px) för fixed
|
|
253
|
+
bottom-nav.
|
|
254
|
+
|
|
255
|
+
### iOS-specifika
|
|
256
|
+
|
|
257
|
+
- Inputs: `font-size: 17px` minimum (anti auto-zoom).
|
|
258
|
+
- Touch-feedback: `:active` med `transform: scale(0.97)` + spring-easing.
|
|
259
|
+
- Hover wrappas i `@media (hover: hover) and (pointer: fine)`.
|
|
260
|
+
|
|
261
|
+
## 10. Färg-konvention
|
|
262
|
+
|
|
263
|
+
**Regel:** alla bakgrundsfärger via semantic surface-tokens:
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
--surface-page (sidens bg, lägst)
|
|
267
|
+
--surface-default (sektioner, list-rows)
|
|
268
|
+
--surface-raised (kort, paneler - en steg upp)
|
|
269
|
+
--surface-overlay (modaler, popovers)
|
|
270
|
+
--surface-hover (:hover bg)
|
|
271
|
+
--surface-active (:active bg)
|
|
272
|
+
--surface-sunken (inputs - LÄGRE än page för iOS-stil)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Förbjudet i komponent-CSS:**
|
|
276
|
+
- Hardkodade hex/rgb-värden
|
|
277
|
+
- `var(--gray-N)`, `var(--blue-N)`, `var(--plum-N)` direkt (bara i
|
|
278
|
+
primitives + apps/-filer)
|
|
279
|
+
- `rgba()` med alpha - använd `color-mix(in oklch, ...)` eller
|
|
280
|
+
`--accent-aN`-tokens
|
|
281
|
+
|
|
282
|
+
## 11. Enforcement-status
|
|
283
|
+
|
|
284
|
+
Mekanisk enforcement via stylelint (Sprint 10-1) fångar BEM-syntax-
|
|
285
|
+
brott men INTE design-rule-brott. Visuell coherence är fortfarande
|
|
286
|
+
human-disciplin + framtida custom plugin.
|
|
287
|
+
|
|
288
|
+
Future custom stylelint-plugin kan enforce:
|
|
289
|
+
- BR-value är en av {10, 14, 9999}
|
|
290
|
+
- Font-size är en av token-skalan
|
|
291
|
+
- Padding-värden begränsade till de 6 listade
|
|
292
|
+
- Shadow forbidden utöver `--shadow-card`
|
|
293
|
+
|
|
294
|
+
Tills sådan plugin finns: visual-coherence är CC-disciplin baserat
|
|
295
|
+
på denna fil.
|
|
296
|
+
|
|
297
|
+
## 12. När ändra regler
|
|
298
|
+
|
|
299
|
+
Denna fil är **locked**. Ändringar kräver:
|
|
300
|
+
1. ADR i `references/04-locked-decisions/` med rationale
|
|
301
|
+
2. Audit-pass av berörda vyer
|
|
302
|
+
3. Migration av befintliga komponenter till nya regeln
|
|
303
|
+
4. Update av ADR 0013 (visual-coherence-doctrine)
|
|
304
|
+
|
|
305
|
+
Inga ad-hoc-ändringar utan ADR-process.
|