@klodd/ds 3.21.0 → 3.21.2
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/css/components/badge.css
CHANGED
|
@@ -98,3 +98,142 @@
|
|
|
98
98
|
background: var(--surface-default);
|
|
99
99
|
border-color: var(--border-subtle);
|
|
100
100
|
}
|
|
101
|
+
|
|
102
|
+
/* --na: AI har inte bedömt (relevance_score IS NULL). Klickbar för att
|
|
103
|
+
trigga rescore. Dashed border signalerar "bedömning saknas, klicka för
|
|
104
|
+
att försöka". Lyft från Jubb-domain v3.21.1 (2026-05-13).
|
|
105
|
+
Användning: <button class="score-pill score-pill--na" data-action="rescore" data-job-id="X">N/A</button> */
|
|
106
|
+
.score-pill--na {
|
|
107
|
+
color: var(--text-muted);
|
|
108
|
+
background: var(--surface-default);
|
|
109
|
+
border: 1px dashed var(--border-default);
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
font-family: inherit;
|
|
112
|
+
transition: background var(--dur-fast) var(--ease-default),
|
|
113
|
+
color var(--dur-fast) var(--ease-default);
|
|
114
|
+
}
|
|
115
|
+
@media (hover: hover) and (pointer: fine) {
|
|
116
|
+
.score-pill--na:hover {
|
|
117
|
+
background: var(--surface-hover);
|
|
118
|
+
color: var(--text-default);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
.score-pill--na:active { transform: scale(0.96); }
|
|
122
|
+
.score-pill--na:focus-visible {
|
|
123
|
+
outline: 2px solid var(--border-focus);
|
|
124
|
+
outline-offset: 2px;
|
|
125
|
+
}
|
|
126
|
+
.score-pill--na:disabled,
|
|
127
|
+
.score-pill--na[aria-disabled="true"] {
|
|
128
|
+
opacity: 0.5;
|
|
129
|
+
cursor: progress;
|
|
130
|
+
}
|
|
131
|
+
.score-pill--na.is-loading {
|
|
132
|
+
background: var(--surface-active);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
/* ================================================================
|
|
137
|
+
.score-circle - cirkulär relevance-score-display (v3.21.2)
|
|
138
|
+
Standardstorlek 36x36 matchar .avatar default. Tabular-nums för
|
|
139
|
+
visuellt-jämn siffer-rendering. Klickbart fall (--na) triggar
|
|
140
|
+
rescore med is-loading spinning animation.
|
|
141
|
+
|
|
142
|
+
Modifiers: --strong (grön), --medium (gul), --low (grå), --na (klickbar)
|
|
143
|
+
States på --na: :hover, :active, :focus-visible, :disabled, .is-loading
|
|
144
|
+
|
|
145
|
+
Användning:
|
|
146
|
+
<span class="score-circle score-circle--strong">8.4</span>
|
|
147
|
+
<button class="score-circle score-circle--na" data-action="rescore"
|
|
148
|
+
data-job-id="X" aria-label="Bedöm jobbet">N/A</button>
|
|
149
|
+
================================================================ */
|
|
150
|
+
.score-circle {
|
|
151
|
+
display: inline-flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: center;
|
|
154
|
+
flex-shrink: 0;
|
|
155
|
+
width: 36px;
|
|
156
|
+
height: 36px;
|
|
157
|
+
font-size: var(--fs-13);
|
|
158
|
+
font-weight: var(--fw-medium);
|
|
159
|
+
font-variant-numeric: tabular-nums;
|
|
160
|
+
line-height: 1;
|
|
161
|
+
border: 1px solid transparent;
|
|
162
|
+
border-radius: 50%;
|
|
163
|
+
white-space: nowrap;
|
|
164
|
+
position: relative;
|
|
165
|
+
overflow: hidden;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.score-circle--strong {
|
|
169
|
+
color: var(--positive);
|
|
170
|
+
background: var(--positive-dim);
|
|
171
|
+
border-color: var(--positive-border);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.score-circle--medium {
|
|
175
|
+
color: var(--warning);
|
|
176
|
+
background: var(--warning-dim);
|
|
177
|
+
border-color: var(--warning-border);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.score-circle--low {
|
|
181
|
+
color: var(--text-muted);
|
|
182
|
+
background: var(--surface-default);
|
|
183
|
+
border-color: var(--border-subtle);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* --na: klickbar (button-element) som triggar rescore via JS. Dashed
|
|
187
|
+
border signalerar "bedömning saknas, klicka för att försöka". */
|
|
188
|
+
.score-circle--na {
|
|
189
|
+
color: var(--text-muted);
|
|
190
|
+
background: var(--surface-default);
|
|
191
|
+
border: 1px dashed var(--border-default);
|
|
192
|
+
cursor: pointer;
|
|
193
|
+
font-size: var(--fs-11);
|
|
194
|
+
font-family: inherit;
|
|
195
|
+
transition: background var(--dur-fast) var(--ease-default),
|
|
196
|
+
color var(--dur-fast) var(--ease-default);
|
|
197
|
+
}
|
|
198
|
+
@media (hover: hover) and (pointer: fine) {
|
|
199
|
+
.score-circle--na:hover {
|
|
200
|
+
background: var(--surface-hover);
|
|
201
|
+
color: var(--text-default);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
.score-circle--na:active { transform: scale(0.96); }
|
|
205
|
+
.score-circle--na:focus-visible {
|
|
206
|
+
outline: 2px solid var(--border-focus);
|
|
207
|
+
outline-offset: 2px;
|
|
208
|
+
}
|
|
209
|
+
.score-circle--na:disabled,
|
|
210
|
+
.score-circle--na[aria-disabled="true"] {
|
|
211
|
+
cursor: progress;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* is-loading: spinning border-segment medan AI bedömer. Texten döljs
|
|
215
|
+
visuellt (transparent) men ::after-pseudo ritar en roterande ring.
|
|
216
|
+
prefers-reduced-motion slowar ner animationen markant. */
|
|
217
|
+
.score-circle--na.is-loading {
|
|
218
|
+
color: transparent;
|
|
219
|
+
background: var(--surface-default);
|
|
220
|
+
border-color: var(--border-default);
|
|
221
|
+
border-style: solid;
|
|
222
|
+
}
|
|
223
|
+
.score-circle--na.is-loading::after {
|
|
224
|
+
content: '';
|
|
225
|
+
position: absolute;
|
|
226
|
+
inset: 2px;
|
|
227
|
+
border-radius: 50%;
|
|
228
|
+
border: 2px solid transparent;
|
|
229
|
+
border-top-color: var(--accent-9);
|
|
230
|
+
animation: score-circle-spin 0.8s linear infinite;
|
|
231
|
+
}
|
|
232
|
+
@media (prefers-reduced-motion: reduce) {
|
|
233
|
+
.score-circle--na.is-loading::after {
|
|
234
|
+
animation-duration: 2s;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
@keyframes score-circle-spin {
|
|
238
|
+
to { transform: rotate(360deg); }
|
|
239
|
+
}
|
package/package.json
CHANGED
|
@@ -33,11 +33,12 @@ För varje entry gäller:
|
|
|
33
33
|
- **Tokens:** `--surface-sunken/-default`, `--accent-9`, `--accent-a3` (focus-ring), `--bg-danger` (error-state)
|
|
34
34
|
|
|
35
35
|
### badge (`badge.css`)
|
|
36
|
-
- **Blocks:** `.badge`, `.score-pill` (
|
|
37
|
-
- **Modifiers:** `.badge--neutral/-success/-warning/-danger/-accent`, `.score-pill--strong/-medium/-low`
|
|
38
|
-
- **
|
|
36
|
+
- **Blocks:** `.badge`, `.score-pill` (legacy rectangular form, behålls för bakåtkompat), `.score-circle` (v3.21.2 - cirkulär form, ersätter score-pill för relevance-displays)
|
|
37
|
+
- **Modifiers:** `.badge--neutral/-success/-warning/-danger/-accent`, `.score-pill--strong/-medium/-low/-na`, `.score-circle--strong/-medium/-low/-na`
|
|
38
|
+
- **States på `.score-pill--na` + `.score-circle--na`:** `.is-loading` (spinning animation), `[aria-disabled="true"]`, `:disabled` (cursor: progress)
|
|
39
|
+
- **Anvand:** Status-pills (statiska) + score-circle--na som klickbar rescore-trigger med spinning loading-animation. Standardstorlek 36x36 matchar .avatar default.
|
|
39
40
|
- **INTE:** Klickbara chips (anvand `.chip`)
|
|
40
|
-
- **Tokens:** `--positive/-dim/-border`, `--warning/-dim/-border`, `--bg-danger`, `--accent-text/-a2/-a6`
|
|
41
|
+
- **Tokens:** `--positive/-dim/-border`, `--warning/-dim/-border`, `--bg-danger`, `--accent-text/-a2/-a6/--accent-9`, `--surface-default/-hover/-active`, `--border-default/-focus/-subtle`, `--dur-fast`, `--ease-default`
|
|
41
42
|
|
|
42
43
|
### card (`card.css`)
|
|
43
44
|
- **Blocks:** `.card`
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# 0016 - "Mina sidor"-doctrine
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Locked.
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Audit 2026-05-13 jämförde Ekonoms `/jag` (sprint 66b-doktrinen) mot
|
|
9
|
+
Jubbs `/min-sida` (just byggd från grund). Båda är settings-hubbar -
|
|
10
|
+
samma roll men olika UI-disciplin.
|
|
11
|
+
|
|
12
|
+
Ekonom hade etablerat ett moget mönster (profilkort med inline-edit,
|
|
13
|
+
logisk sektion-gruppering, "Att åtgärda"-conditional, field_sheet-
|
|
14
|
+
macros för editing, LEAF-topbar). Jubb hade snabbt byggts utan motsvarande
|
|
15
|
+
struktur (profilkort utan namn, blandning av setting-rows och inline-knappar,
|
|
16
|
+
ingen actionable-conditional).
|
|
17
|
+
|
|
18
|
+
Per Calle's princip "alla appar ska ha samma namn och komponentstruktur"
|
|
19
|
+
behöver ett gemensamt locked pattern etableras för "Mina sidor" som
|
|
20
|
+
används av alla nuvarande och framtida Klodd-appar.
|
|
21
|
+
|
|
22
|
+
## Decision
|
|
23
|
+
|
|
24
|
+
**Locked template-struktur för "Mina sidor"** (kanonisk ordning):
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
┌────────────────────────────────────────────┐
|
|
28
|
+
│ Topbar (3-kol grid, LEAF-anpassad) │
|
|
29
|
+
│ col 1: pwa-avatar │
|
|
30
|
+
│ col 2: topbar__logo "Min sida" │
|
|
31
|
+
│ col 3: <span class="avatar"> utan link │ ← LEAF
|
|
32
|
+
├────────────────────────────────────────────┤
|
|
33
|
+
│ Profilkort (.profile-panel) │
|
|
34
|
+
│ · avatar--lg │
|
|
35
|
+
│ · display-name med inline-edit (om │
|
|
36
|
+
│ multi-user) eller skippa (single-user) │
|
|
37
|
+
│ · email (.text-caption eller .text-meta) │
|
|
38
|
+
├────────────────────────────────────────────┤
|
|
39
|
+
│ Panel "Att åtgärda" CONDITIONAL │ ← Alerts först
|
|
40
|
+
│ panel--attention │
|
|
41
|
+
│ setting-rows med .panel__pill (count) │
|
|
42
|
+
├────────────────────────────────────────────┤
|
|
43
|
+
│ Panel "Min [domän]" OPTIONAL │ ← om domän-data finns
|
|
44
|
+
│ setting-rows som öppnar field_sheet │
|
|
45
|
+
├────────────────────────────────────────────┤
|
|
46
|
+
│ Panel "Mina inställningar" │
|
|
47
|
+
│ setting-rows + toggles + sheets │
|
|
48
|
+
├────────────────────────────────────────────┤
|
|
49
|
+
│ Panel "Mina vyer" │
|
|
50
|
+
│ setting-rows som länk-rows │
|
|
51
|
+
├────────────────────────────────────────────┤
|
|
52
|
+
│ Panel "Installera [app]" CONDITIONAL │ ← om !standalone PWA
|
|
53
|
+
│ iOS Safari-instruktioner (iPhone-only) │
|
|
54
|
+
├────────────────────────────────────────────┤
|
|
55
|
+
│ Logout-row │
|
|
56
|
+
│ .btn--logout (paketet) │
|
|
57
|
+
└────────────────────────────────────────────┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Regler
|
|
61
|
+
|
|
62
|
+
1. **Topbar är 3-kol-grid, LEAF-anpassad.** Avatar i kolumn 3 finns
|
|
63
|
+
visuellt för layout-konsekvens men är `<span class="avatar">` utan
|
|
64
|
+
`<a>`-wrapper. Inte klickbar (användaren är redan på destinationen).
|
|
65
|
+
Topbar__logo blir korrekt centrerat av grid `auto 1fr auto`.
|
|
66
|
+
|
|
67
|
+
2. **Topbar-text "Min sida"** (svenska). Kort, idiomatisk, konsekvent
|
|
68
|
+
över alla Klodd-appar.
|
|
69
|
+
|
|
70
|
+
3. **Profilkort är obligatoriskt.** `.profile-panel` (lyft till paketet
|
|
71
|
+
v3.21.0). Avatar--lg + email som minimum. Display-name med inline-edit
|
|
72
|
+
OBLIGATORISKT för multi-user-appar (Ekonom), OPTIONAL för single-user-
|
|
73
|
+
appar (Jubb). Single-user-app utan tydligt display-name-bruk får skippa.
|
|
74
|
+
|
|
75
|
+
4. **Sektion-ordning är "alerts first".** "Att åtgärda" placeras FÖRE
|
|
76
|
+
"Min [domän]" och övriga settings så användaren direkt ser pending
|
|
77
|
+
tasks vid sidladdning.
|
|
78
|
+
|
|
79
|
+
5. **"Min [domän]"-panel är OPTIONAL.** Bara om appen har domän-
|
|
80
|
+
specifika personliga värden separat från preferences (Ekonom:
|
|
81
|
+
inkomst + saldo). Single-purpose-appar (Jubb) slår ihop allt till
|
|
82
|
+
"Mina inställningar".
|
|
83
|
+
|
|
84
|
+
6. **Alla settings använder setting-row + sheet.** Inga inline-knappar
|
|
85
|
+
för actions som ändrar state. Detta inkluderar:
|
|
86
|
+
- Choice-actions: `.sheet__item-grid` med `.sheet__item--primary`
|
|
87
|
+
- Field-editing: `field_sheet` macro
|
|
88
|
+
- Multi-field-editing: `multi_field_sheet` macro
|
|
89
|
+
- Toggles: `setting-toggle` inom setting-row
|
|
90
|
+
|
|
91
|
+
7. **Conditional panels visas via JS eller Jinja-conditional.** Inte
|
|
92
|
+
alltid synliga, inte alltid dolda. Aktivering-villkor i ADR/template-
|
|
93
|
+
kommentar.
|
|
94
|
+
|
|
95
|
+
8. **PWA-install-panel är iPhone-only.** Klodd-appar utvecklas för iOS
|
|
96
|
+
PWA + dev-desktop. Android Chrome-instruktioner inkluderas inte
|
|
97
|
+
(skulle ge falskt-positiva intryck att Android stöds). Detection
|
|
98
|
+
via `window.matchMedia('(display-mode: standalone)').matches`.
|
|
99
|
+
|
|
100
|
+
9. **Logout är paketet `.btn--logout` i `.logout-row`** (v3.21.0).
|
|
101
|
+
|
|
102
|
+
### Domain-naming-konvention per app
|
|
103
|
+
|
|
104
|
+
| App | "Min [domän]" eller "Mina inställningar" |
|
|
105
|
+
|---|---|
|
|
106
|
+
| Ekonom | Min ekonomi (inkomst, saldo) + Mina inställningar (toggles, abonnemang) |
|
|
107
|
+
| Jubb | Skip "Min [domän]" → Mina inställningar (Sökläge, Notiser, AI-profil) |
|
|
108
|
+
| Future-app | "Min [domän]" om personliga värden finns separat |
|
|
109
|
+
|
|
110
|
+
## Konsekvenser
|
|
111
|
+
|
|
112
|
+
**Bra:**
|
|
113
|
+
- Single source of truth för settings-hubbar
|
|
114
|
+
- Future-Margevo + framtida appar får gratis-pattern
|
|
115
|
+
- A11y + iOS-konvention: heading-hierarki + setting-row-rytm
|
|
116
|
+
- Komposit av befintliga paket-komponenter (ingen ny CSS behövs)
|
|
117
|
+
|
|
118
|
+
**Trade-offs:**
|
|
119
|
+
- Single-user-appar tappar ett potentiellt personlighet-element (display-
|
|
120
|
+
name) - acceptabelt eftersom inline-edit av single-user-namn är
|
|
121
|
+
cosmetic, inte funktionellt.
|
|
122
|
+
- "Min sida" är längre än iOS-konvention "Mitt" - men matchar Calle's
|
|
123
|
+
preferens (mer explicit).
|
|
124
|
+
|
|
125
|
+
## Migration 2026-05-13
|
|
126
|
+
|
|
127
|
+
**Jubb:**
|
|
128
|
+
- /min-sida-template omskriven enligt doktrinen
|
|
129
|
+
- Topbar: lägg avatar i kolumn 3 (`<span class="avatar">` utan link)
|
|
130
|
+
- "Att åtgärda" CONDITIONAL panel: pending triage-jobb med relevance >= 7.0
|
|
131
|
+
- Slå ihop "Sökläge" + "Notiser" + "AI-profil-förslag" till "Mina
|
|
132
|
+
inställningar"-panel
|
|
133
|
+
- "Installera Jubb": bara iOS Safari-instruktioner
|
|
134
|
+
|
|
135
|
+
**Ekonom:**
|
|
136
|
+
- /jag topbar: byt "Mitt" → "Min sida"
|
|
137
|
+
- Topbar: lägg `<span class="avatar">` i kolumn 3 (visuell paritet)
|
|
138
|
+
- Flytta "Att åtgärda" till FÖRE "Min ekonomi" (alerts first)
|
|
139
|
+
- Lägg "Installera Ekonom" CONDITIONAL panel (paritet, iOS-only)
|
|
140
|
+
|
|
141
|
+
## References
|
|
142
|
+
|
|
143
|
+
- ADR 0011-strikt-bem-elementsyntax.md (besläktad - BEM-disciplin)
|
|
144
|
+
- ADR 0013-visual-coherence-doctrine.md (besläktad - visuell rytm)
|
|
145
|
+
- ADR 0015-panel-title-tag-doctrine.md (besläktad - heading-semantik)
|
|
146
|
+
- 02-components.md profile-panel-entry (v3.21.0)
|
|
147
|
+
- DESIGN-LANGUAGE.md sektion 13 (topbar-layout) + sektion 17 (Mina sidor)
|
|
@@ -492,6 +492,44 @@ inte brott - browser-tree accepterar skipping levels).
|
|
|
492
492
|
**Etablerad 2026-05-13** efter panel__title-audit över Jubb + Ekonom.
|
|
493
493
|
Se ADR 0015 (panel-title-tag-doctrine).
|
|
494
494
|
|
|
495
|
+
## 17. "Mina sidor"-doktrin (settings-hub-pattern)
|
|
496
|
+
|
|
497
|
+
**Regel:** alla Klodd-appar har en gemensam "Mina sidor"-route med
|
|
498
|
+
locked template-struktur. Route-URL kan variera per app (`/jag` i
|
|
499
|
+
Ekonom, `/min-sida` i Jubb) men UI-pattern är konsekvent.
|
|
500
|
+
|
|
501
|
+
### Template-struktur (kanonisk ordning)
|
|
502
|
+
|
|
503
|
+
1. **Topbar** - 3-kol-grid med LEAF-anpassning: pwa-avatar + "Min sida" + `<span class="avatar">` utan link
|
|
504
|
+
2. **Profilkort** - `.profile-panel` med avatar--lg + ev. display-name med inline-edit + email
|
|
505
|
+
3. **"Att åtgärda"** CONDITIONAL - `panel--attention` med setting-rows + `.panel__pill`
|
|
506
|
+
4. **"Min [domän]"** OPTIONAL - app-specifika personliga värden
|
|
507
|
+
5. **"Mina inställningar"** - app-agnostiska preferences via setting-rows + sheets
|
|
508
|
+
6. **"Mina vyer"** - navigation till sub-vyer
|
|
509
|
+
7. **"Installera [app]"** CONDITIONAL - iPhone-only PWA-instruktioner
|
|
510
|
+
8. **Logout-row** - `.btn--logout`
|
|
511
|
+
|
|
512
|
+
### Kritiska regler
|
|
513
|
+
|
|
514
|
+
- Topbar avatar i kolumn 3 är `<span class="avatar">` UTAN `<a>`-wrapper på Min sida (LEAF-pattern - användaren är redan på destinationen, men element kvar för layout-konsekvens)
|
|
515
|
+
- Topbar-text alltid **"Min sida"** över alla appar (svenska, kort)
|
|
516
|
+
- Alla settings använder **setting-row + sheet** - inga inline-knappar för state-changes
|
|
517
|
+
- "Att åtgärda" placeras **FÖRE** "Min [domän]" så alerts visas direkt
|
|
518
|
+
- Display-name **obligatoriskt** för multi-user-appar (Ekonom), **optional** för single-user (Jubb)
|
|
519
|
+
- "Min [domän]" är **OPTIONAL** panel - bara om appen har domän-specifika personliga värden
|
|
520
|
+
- PWA-install-panel **bara iOS Safari**-instruktioner (Klodd-appar är iPhone-targeted)
|
|
521
|
+
|
|
522
|
+
### Förbjudet
|
|
523
|
+
|
|
524
|
+
- Inline-knapp för push-aktivering (måste vara setting-row)
|
|
525
|
+
- Topbar utan kolumn 3-avatar på Min sida (bryter grid-centrering)
|
|
526
|
+
- Topbar utan LEAF-anpassning (avatar måste vara `<span>`, inte `<a>` på destinationen)
|
|
527
|
+
- Android Chrome-instruktioner i PWA-install-panel (klodd-appar är iPhone-only)
|
|
528
|
+
|
|
529
|
+
**Etablerad 2026-05-13** efter audit-jämförelse mellan Ekonoms `/jag`
|
|
530
|
+
och Jubbs `/min-sida`. Se ADR 0016 (mina-sidor-doctrine) för fullständig
|
|
531
|
+
specifikation + locked rationale.
|
|
532
|
+
|
|
495
533
|
## 12. När ändra regler
|
|
496
534
|
|
|
497
535
|
Denna fil är **locked**. Ändringar kräver:
|