@klodd/ds 3.20.1 → 3.21.1
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 +33 -0
- package/css/components/button.css +12 -0
- package/css/components/profile-panel.css +57 -0
- package/css/index.css +1 -0
- package/css/utilities.css +65 -0
- package/package.json +1 -1
- package/references/02-components.md +13 -3
- package/references/04-locked-decisions/0014-css-specificity-doctrine.md +147 -0
- package/references/04-locked-decisions/0015-panel-title-tag-doctrine.md +122 -0
- package/references/04-locked-decisions/0016-mina-sidor-doctrine.md +147 -0
- package/references/DESIGN-LANGUAGE.md +154 -0
package/css/components/badge.css
CHANGED
|
@@ -98,3 +98,36 @@
|
|
|
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
|
+
}
|
|
@@ -122,6 +122,18 @@
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/* --logout: subtil ghost-variant for "Logga ut"-knapp. Opacity 0.7
|
|
126
|
+
gor knappen visuellt mindre framtradande an primar-actions men
|
|
127
|
+
fortfarande klickbar. Lyft fran Ekonoms .logout-btn (v3.21.0).
|
|
128
|
+
Anvands som modifier ovanpa .btn--ghost --sm:
|
|
129
|
+
<button class="btn btn--ghost btn--sm btn--logout" data-action="logout">Logga ut</button> */
|
|
130
|
+
.btn--logout {
|
|
131
|
+
opacity: 0.7;
|
|
132
|
+
}
|
|
133
|
+
@media (hover: hover) and (pointer: fine) {
|
|
134
|
+
.btn--logout:hover { opacity: 1; }
|
|
135
|
+
}
|
|
136
|
+
|
|
125
137
|
/* --positive: transparent + positive-border. Bekraftande action
|
|
126
138
|
(t.ex. "Gemensam"-flagga i review_queue). Lyft fran Ekonom v3.9.0. */
|
|
127
139
|
.btn--positive {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* ================================================================
|
|
2
|
+
components/profile-panel.css
|
|
3
|
+
Centrerad profilkort: avatar (lg) + namn + email.
|
|
4
|
+
Anvands pa /jag (Ekonom) och /min-sida (Jubb).
|
|
5
|
+
|
|
6
|
+
Blocks:
|
|
7
|
+
.profile-panel - centrerad flex-column med komposit-children
|
|
8
|
+
|
|
9
|
+
Inga BEM-element - children ar paketets atomer (.avatar, .heading,
|
|
10
|
+
.inline-edit, .text-caption, .text-meta). Descendant-overrides
|
|
11
|
+
kalibrerar margin/layout for child-positions inom kortet.
|
|
12
|
+
|
|
13
|
+
Anvandning:
|
|
14
|
+
<div class="panel profile-panel">
|
|
15
|
+
<span class="avatar avatar--lg">CE</span>
|
|
16
|
+
<p class="text-meta">calle@klodd.io</p>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
Med inline-edit (Ekonoms /jag-mönster):
|
|
20
|
+
<div class="panel profile-panel" data-profile-panel>
|
|
21
|
+
<span class="avatar avatar--lg">CE</span>
|
|
22
|
+
<p class="heading inline-edit">
|
|
23
|
+
<span class="inline-edit__text">Calle</span>
|
|
24
|
+
<button class="inline-edit__btn">...</button>
|
|
25
|
+
</p>
|
|
26
|
+
<p class="text-caption">calle@klodd.io</p>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
Lyft fran Ekonoms .profile-panel-centered + Jubbs .profile-panel
|
|
30
|
+
(v3.21.0, 2026-05-13). Single source of truth ersatter app-domain-
|
|
31
|
+
kopior i ekonom.css + jubb.css.
|
|
32
|
+
================================================================ */
|
|
33
|
+
.profile-panel {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
align-items: center;
|
|
37
|
+
text-align: center;
|
|
38
|
+
gap: var(--space-8);
|
|
39
|
+
padding: var(--space-20) var(--space-16);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.profile-panel .avatar--lg {
|
|
43
|
+
margin-bottom: var(--space-4);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.profile-panel .inline-edit {
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: var(--space-6);
|
|
50
|
+
justify-content: center;
|
|
51
|
+
margin: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.profile-panel .text-caption,
|
|
55
|
+
.profile-panel .text-meta {
|
|
56
|
+
margin: 0;
|
|
57
|
+
}
|
package/css/index.css
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
/* v2.0.0 - flyttade fran app-repona */
|
|
42
42
|
@import './components/banner.css';
|
|
43
43
|
@import './components/panel.css';
|
|
44
|
+
@import './components/profile-panel.css';
|
|
44
45
|
@import './components/hub-card.css';
|
|
45
46
|
@import './components/stat.css';
|
|
46
47
|
@import './components/form.css';
|
package/css/utilities.css
CHANGED
|
@@ -113,3 +113,68 @@
|
|
|
113
113
|
/* Text-color utilities (CSP-migration: ersatter style="color: var(--text-X)") */
|
|
114
114
|
.text-subtle { color: var(--text-subtle); }
|
|
115
115
|
.text-muted { color: var(--text-muted); }
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
/* ================================================================
|
|
119
|
+
Layout-utilities (v3.21.0 lyft fran Jubb-domain)
|
|
120
|
+
================================================================ */
|
|
121
|
+
|
|
122
|
+
/* Logout-rad: centrerad btn-wrapper. Anvands pa /jag (Ekonom) och
|
|
123
|
+
/min-sida (Jubb) som container for "Logga ut"-knappen. */
|
|
124
|
+
.logout-row {
|
|
125
|
+
display: flex;
|
|
126
|
+
justify-content: center;
|
|
127
|
+
margin-top: var(--space-24);
|
|
128
|
+
margin-bottom: var(--space-16);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
/* ================================================================
|
|
133
|
+
Text-utilities (v3.21.0 lyft fran Jubb-domain)
|
|
134
|
+
================================================================ */
|
|
135
|
+
|
|
136
|
+
/* Inline-separator "·" mellan meta-text-items. Disabled-fargad
|
|
137
|
+
sa den fungerar som tyst avgransning utan att dra blicken. */
|
|
138
|
+
.dot-sep {
|
|
139
|
+
margin: 0 var(--space-6);
|
|
140
|
+
color: var(--text-disabled);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Pre-formatted code/text. Sunken bakgrund, monospace, pre-wrap
|
|
144
|
+
for line-break-preservering med word-wrap pa lang text. */
|
|
145
|
+
.code-block {
|
|
146
|
+
margin: 0;
|
|
147
|
+
padding: var(--space-12);
|
|
148
|
+
background: var(--surface-sunken);
|
|
149
|
+
border-radius: var(--radius-14);
|
|
150
|
+
font-family: var(--font-mono);
|
|
151
|
+
font-size: var(--fs-12);
|
|
152
|
+
color: var(--text-subtle);
|
|
153
|
+
white-space: pre-wrap;
|
|
154
|
+
overflow-wrap: break-word;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* Pre-formatted long-text (job-descriptions, multi-line content).
|
|
158
|
+
Likt .code-block men sans-font + default-fargad text. */
|
|
159
|
+
.description-block {
|
|
160
|
+
margin: 0;
|
|
161
|
+
font-family: var(--font-sans);
|
|
162
|
+
font-size: var(--fs-13);
|
|
163
|
+
color: var(--text-default);
|
|
164
|
+
white-space: pre-wrap;
|
|
165
|
+
overflow-wrap: break-word;
|
|
166
|
+
line-height: var(--lh-base);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* ul med default discs + standardspacing. Plain bullet-lista. */
|
|
170
|
+
.bullet-list {
|
|
171
|
+
margin: 0;
|
|
172
|
+
padding-left: var(--space-20);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.bullet-list > li {
|
|
176
|
+
margin-bottom: var(--space-4);
|
|
177
|
+
font-size: var(--fs-13);
|
|
178
|
+
color: var(--text-default);
|
|
179
|
+
line-height: var(--lh-base);
|
|
180
|
+
}
|
package/package.json
CHANGED
|
@@ -34,10 +34,11 @@ För varje entry gäller:
|
|
|
34
34
|
|
|
35
35
|
### badge (`badge.css`)
|
|
36
36
|
- **Blocks:** `.badge`, `.score-pill` (sibling, kanonisk definition)
|
|
37
|
-
- **Modifiers:** `.badge--neutral/-success/-warning/-danger/-accent`, `.score-pill--strong/-medium/-low`
|
|
38
|
-
- **
|
|
37
|
+
- **Modifiers:** `.badge--neutral/-success/-warning/-danger/-accent`, `.score-pill--strong/-medium/-low`, `.score-pill--na` (v3.21.1 - klickbar N/A för rescore-trigger)
|
|
38
|
+
- **States på `.score-pill--na`:** `.is-loading`, `[aria-disabled="true"]`, `:disabled` (cursor: progress)
|
|
39
|
+
- **Anvand:** Status-pills (statiska) + score-pill--na som klickbar rescore-trigger (vanligtvis som `<button>`-element med `data-action="rescore"`)
|
|
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`, `--surface-default/-hover/-active`, `--border-default/-focus/-subtle`
|
|
41
42
|
|
|
42
43
|
### card (`card.css`)
|
|
43
44
|
- **Blocks:** `.card`
|
|
@@ -133,6 +134,15 @@ För varje entry gäller:
|
|
|
133
134
|
- **Modifiers:** `.panel--info`, `.panel--info-warning`, `.panel--danger`, `.panel--attention`
|
|
134
135
|
- **Anvand:** Sektion med ramad styling och titel
|
|
135
136
|
- **INTE:** Klickbart kort (anvand `.card--interactive`)
|
|
137
|
+
- **HTML-tag for `.panel__title`:** `<h3>` default. Specialfall: `<span>` inom `.panel__step-row` (compound badge+title), `<summary>` inom `<details>`-element. Se ADR 0015 (panel-title-tag-doctrine).
|
|
138
|
+
|
|
139
|
+
### profile-panel (`profile-panel.css`) - v3.21.0
|
|
140
|
+
- **Blocks:** `.profile-panel`
|
|
141
|
+
- **Anvand:** Centrerad profilkort med avatar + namn + email/meta. Pa /jag (Ekonom) och /min-sida (Jubb).
|
|
142
|
+
- **INTE:** Allmant kort med titel (anvand `.panel` med `.panel__title`)
|
|
143
|
+
- **Tokens:** `--space-8/-16/-20`, `--space-4` (avatar margin), `--space-6` (inline-edit gap)
|
|
144
|
+
- **Composition:** Inga egna BEM-element. Children ar paketets atomer (`.avatar--lg`, `.heading`, `.inline-edit`, `.text-caption`, `.text-meta`). Descendant-overrides for child-positions inom kortet.
|
|
145
|
+
- **Lyft fran:** Ekonoms `.profile-panel-centered` + Jubbs `.profile-panel` (v3.21.0).
|
|
136
146
|
|
|
137
147
|
### hub-card (`hub-card.css`)
|
|
138
148
|
- **Blocks:** `.hub-card`, `.hub-list` (sibling-wrapper for kort-lista), `.hub-category` (sibling-rubrik over hub-list)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# 0014 - CSS Specificity Doctrine
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Locked.
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Sprint 2026-05-13 avslöjade en tyst CSS-specificity-bugg i kv-list.css.
|
|
9
|
+
Default-regeln var skriven som:
|
|
10
|
+
|
|
11
|
+
```css
|
|
12
|
+
.kv-list > li:not(.kv-list__item--budget):not(.kv-list__item--divider) {
|
|
13
|
+
color: var(--text-subtle);
|
|
14
|
+
font-size: var(--fs-13);
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Specificity blev 0,3,1 (3 klasser via .kv-list + 2x :not()-arg, plus 1
|
|
19
|
+
li element). Modifier-reglerna `.kv-list__item--strong` (color: text-
|
|
20
|
+
default + medium weight) och `.kv-list__item--sub` (font-size: fs-11)
|
|
21
|
+
hade specificity 0,1,0 - kunde inte vinna mot 0,3,1.
|
|
22
|
+
|
|
23
|
+
Symptom: Calle/Lisa/Totalt-rader förblev text-subtle istället för
|
|
24
|
+
text-default (font-weight: medium tillämpades dock - delvis vinst gav
|
|
25
|
+
intryck att modifier "fungerade"). Verklig kostnad förblev fs-13
|
|
26
|
+
istället för fs-11.
|
|
27
|
+
|
|
28
|
+
Tyst bugg eftersom font-weight på --strong och font-size på --sub
|
|
29
|
+
INTE konflikterade med default-regeln, så modifier-classes såg ut att
|
|
30
|
+
fungera. Visuell skillnad förlorades men ingen runtime-error.
|
|
31
|
+
|
|
32
|
+
Felmönstret: `:not()`-filter på default-regeln drog upp specificity
|
|
33
|
+
till en nivå där flat modifier-classes inte kunde override:a.
|
|
34
|
+
|
|
35
|
+
## Decision
|
|
36
|
+
|
|
37
|
+
**Locked regel:** default/base-regler för rad-layout, list-items,
|
|
38
|
+
comp-bas-styling **får inte** sätta `color`, `font-size`, `font-weight`,
|
|
39
|
+
`background`, `border`, `text-transform`, `letter-spacing` när
|
|
40
|
+
modifier-classes existerar för samma property.
|
|
41
|
+
|
|
42
|
+
Tre alternativ för att undvika konflikt:
|
|
43
|
+
|
|
44
|
+
### Alternativ 1: Inheritance från block-parent (rekommenderat)
|
|
45
|
+
|
|
46
|
+
Sätt default-properties på **block-roten** (`.X`), inte på item-rule
|
|
47
|
+
(`.X__item` eller `.X > li`).
|
|
48
|
+
|
|
49
|
+
```css
|
|
50
|
+
/* RÄTT */
|
|
51
|
+
.kv-list {
|
|
52
|
+
color: var(--text-subtle);
|
|
53
|
+
font-size: var(--fs-13);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.kv-list > li:not(--budget):not(--divider) {
|
|
57
|
+
display: flex;
|
|
58
|
+
padding: var(--space-8) 0;
|
|
59
|
+
/* INGEN color/font-size */
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.kv-list__item--strong { /* specificity 0,1,0 - vinner via cascade */
|
|
63
|
+
color: var(--text-default);
|
|
64
|
+
font-weight: var(--fw-medium);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Alla item-rader **ärver** color/font-size från `.kv-list`. Modifier-
|
|
69
|
+
classes (0,1,0) override:ar via inheritance utan specificity-konflikt.
|
|
70
|
+
|
|
71
|
+
### Alternativ 2: Höj modifier-specificity
|
|
72
|
+
|
|
73
|
+
Om Alternativ 1 inte funkar (t.ex. parent har inte naturlig
|
|
74
|
+
inheritance-relation), matcha modifier-specificity till default-rule:
|
|
75
|
+
|
|
76
|
+
```css
|
|
77
|
+
.X > li.X--strong:not(.X--budget):not(.X--divider) { color: ...; }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Brus och svårläsligt - undvik om möjligt.
|
|
81
|
+
|
|
82
|
+
### Alternativ 3: :where() runt default-rule
|
|
83
|
+
|
|
84
|
+
```css
|
|
85
|
+
:where(.X > li:not(.X--budget):not(.X--divider)) {
|
|
86
|
+
color: var(--text-subtle); /* specificity 0,0,0 */
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`:where()` nollställer specificity. Modifiers vinner trivialt. Modernt
|
|
91
|
+
CSS (alla browsers sedan 2021). Använd när inheritance inte fungerar
|
|
92
|
+
och Alternativ 2 är för fult.
|
|
93
|
+
|
|
94
|
+
## Konsekvenser
|
|
95
|
+
|
|
96
|
+
**Bra:**
|
|
97
|
+
- Modifier-classes vinner förutsägbart utan specificity-hack
|
|
98
|
+
- Default-rules kan ha `:not()`-filter för layout-undantag utan att
|
|
99
|
+
förstöra modifier-override
|
|
100
|
+
- Inheritance-based design ger renare CSS (mindre upprepning)
|
|
101
|
+
|
|
102
|
+
**Trade-offs:**
|
|
103
|
+
- Kräver att block-parent (.X) finns och har naturlig
|
|
104
|
+
inheritance-relation
|
|
105
|
+
- Inheritance fungerar inte för layout-properties (display, padding,
|
|
106
|
+
gap) - dessa måste fortfarande sättas på item-rule
|
|
107
|
+
- Lite mer tankearbete vid komponent-design (vad är "default" och vad
|
|
108
|
+
är "modifier-overridable")
|
|
109
|
+
|
|
110
|
+
## Migration: kv-list 3.19.0 → 3.19.3
|
|
111
|
+
|
|
112
|
+
3.19.1 introducerade `:not()`-filter på default-rule (för --budget +
|
|
113
|
+
--divider exclusion) som gav specificity 0,3,1. Modifier-reglerna
|
|
114
|
+
tappade tyst. Tre patches behövdes:
|
|
115
|
+
|
|
116
|
+
- 3.19.1: layout-fix för bare LI (introducerade buggen)
|
|
117
|
+
- 3.19.2: fix layout för --budget (lade till :not()-filter)
|
|
118
|
+
- 3.19.3: flyttade color/font-size från item-rule till .kv-list-
|
|
119
|
+
parent (löste specificity-konflikten)
|
|
120
|
+
|
|
121
|
+
## Audit över paketet
|
|
122
|
+
|
|
123
|
+
Sprint 2026-05-13 audit över alla 39 paket-CSS-filer hittade INGEN
|
|
124
|
+
liknande bugg utöver kv-list. Övriga komponenter har:
|
|
125
|
+
- Default-rules på 0,1,0 (.X { ... }) - matchas av modifier 0,1,0 via
|
|
126
|
+
cascade-order
|
|
127
|
+
- Context-overrides på 0,2,0 (.X--mod .X__element) - intentional för
|
|
128
|
+
cross-element-styling, inte konflikt mot self-modifier
|
|
129
|
+
|
|
130
|
+
Mönstret som triggade kv-list-buggen var unikt: `:not()`-filter på
|
|
131
|
+
en default-rule som också konkurrerade om color/font-size med
|
|
132
|
+
modifiers på samma block. Det mönstret ska undvikas framöver.
|
|
133
|
+
|
|
134
|
+
## Future work
|
|
135
|
+
|
|
136
|
+
1. **Stylelint-plugin** för att varna när default-rules sätter samma
|
|
137
|
+
property som modifier-rules i samma fil.
|
|
138
|
+
2. **Custom selector-specificity-linting**: flagga rules med
|
|
139
|
+
specificity > 0,2,0 som inte är context-overrides.
|
|
140
|
+
|
|
141
|
+
## References
|
|
142
|
+
|
|
143
|
+
- klodd-ds commit 9854004 (3.19.3 fix)
|
|
144
|
+
- kv-list.css JSDoc-header rad 24-35
|
|
145
|
+
- DESIGN-LANGUAGE.md sektion 14 (CSS-specificity-disciplin)
|
|
146
|
+
- ADR 0011-strikt-bem-elementsyntax.md (besläktad)
|
|
147
|
+
- ADR 0013-visual-coherence-doctrine.md (besläktad)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# 0015 - Panel-title-tag-doctrine
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Locked.
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Audit 2026-05-13 kvällsessionen avslöjade två problem med
|
|
9
|
+
`.panel__title`-användning över Klodd-ekosystemet:
|
|
10
|
+
|
|
11
|
+
**Problem 1: Inkonsekvent HTML-tagg i Ekonom.**
|
|
12
|
+
- 35 platser använder `<div class="panel__title">` (94%)
|
|
13
|
+
- 2 platser använder `<span class="panel__title">` (auto_kategorisering.html)
|
|
14
|
+
- 1 plats använder `<summary class="panel__title">` (bolan.html)
|
|
15
|
+
|
|
16
|
+
`<div>` saknar heading-semantik. Screen readers kan inte navigera
|
|
17
|
+
mellan paneler via heading-nav. Sökmotorer ser ingen rubrik-hierarki.
|
|
18
|
+
|
|
19
|
+
**Problem 2: Jubb använder `.hero__label` som panel-rubrik.**
|
|
20
|
+
- 25 platser har `<p class="hero__label">` som rubrik för en panel som
|
|
21
|
+
innehåller list/text/textarea - INTE följd av `.hero__amount`.
|
|
22
|
+
- Bara 1 plats är legitim hero-kontext (dashboard.html med pending_count
|
|
23
|
+
som hero-amount).
|
|
24
|
+
|
|
25
|
+
Felanvändningen uppstod eftersom `.hero__label` och `.panel__title`
|
|
26
|
+
visuellt liknar varandra (12px vs 11px, samma color/weight/letter-
|
|
27
|
+
spacing). Felet kostade inget visuellt, men semantiskt är klassen
|
|
28
|
+
"label OVAN en hero-amount" - inte en generisk paneltitel.
|
|
29
|
+
|
|
30
|
+
## Decision
|
|
31
|
+
|
|
32
|
+
**Locked regel:** panel-rubriker använder `<h3 class="panel__title">`
|
|
33
|
+
som default-tagg.
|
|
34
|
+
|
|
35
|
+
### Specialfall (två dokumenterade undantag)
|
|
36
|
+
|
|
37
|
+
**1. Inline i `.panel__step-row` eller `.panel__title-row`:**
|
|
38
|
+
|
|
39
|
+
Använd `<span class="panel__title">` när rubriken sitter inline i en
|
|
40
|
+
flex-rad med andra element (step-badge, meta, link). Block-element
|
|
41
|
+
(h3) bryter flex-layouten.
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<div class="panel__step-row">
|
|
45
|
+
<span class="panel__step-badge">Steg 1</span>
|
|
46
|
+
<span class="panel__title">Bankavi-matchning</span>
|
|
47
|
+
</div>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**2. Inom `<details>`-element:**
|
|
51
|
+
|
|
52
|
+
Använd `<summary class="panel__title">` eftersom native HTML kräver
|
|
53
|
+
`<summary>` som första child av `<details>`. Summary fungerar
|
|
54
|
+
analogt med en heading - aria-tree exponerar den som klickbar
|
|
55
|
+
expander.
|
|
56
|
+
|
|
57
|
+
```html
|
|
58
|
+
<details class="panel">
|
|
59
|
+
<summary class="panel__title">Värderingshistorik (3)</summary>
|
|
60
|
+
<ul class="list mt-12">...</ul>
|
|
61
|
+
</details>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `.hero__label` vs `.panel__title` - definition
|
|
65
|
+
|
|
66
|
+
- `<p class="hero__label">` används ENDAST om följt av `<p class="hero-amount">`
|
|
67
|
+
eller `<p class="hero__amount--card">`. Klassen är "labeltext OVANFÖR
|
|
68
|
+
en stor siffer-display".
|
|
69
|
+
- Allt annat (rubrik för list, table, form, text-content) ska vara
|
|
70
|
+
`<h3 class="panel__title">`.
|
|
71
|
+
|
|
72
|
+
Card-hero-pattern (panel som innehåller hero-mönster) är legitimt:
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
<div class="panel collapsible">
|
|
76
|
+
<p class="hero__label">Gemensamma utgifter</p>
|
|
77
|
+
<p class="hero__amount--card">12 500 kr</p>
|
|
78
|
+
</div>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Här är `.hero__label` korrekt eftersom `.hero__amount--card` följer.
|
|
82
|
+
|
|
83
|
+
## Konsekvenser
|
|
84
|
+
|
|
85
|
+
**Bra:**
|
|
86
|
+
- A11y-semantik korrekt: screen readers exponerar paneler som
|
|
87
|
+
navigerbara rubriker
|
|
88
|
+
- Industri-praxis (Radix UI, Material UI, Chakra renderar card-title
|
|
89
|
+
som h3 default)
|
|
90
|
+
- CSS oförändrad - `.panel__title`-stylling targetar klassen, inte
|
|
91
|
+
taggen
|
|
92
|
+
- Konsekvens över Klodd-ekosystemet (Jubb + Ekonom + framtida appar)
|
|
93
|
+
|
|
94
|
+
**Trade-offs:**
|
|
95
|
+
- Heading-hierarki är inte alltid h1→h2→h3 över hela sajten. Vyer utan
|
|
96
|
+
`<h1 class="heading-1">` får h3 som top-level (icke-ideal men inte
|
|
97
|
+
brott - browser-tree är OK med "skipping levels").
|
|
98
|
+
- Future custom stylelint-plugin kan enforce: `<h3 class="panel__title">`
|
|
99
|
+
default + dokumenterade specialfall. Tills dess är det human-disciplin.
|
|
100
|
+
|
|
101
|
+
## Migration 2026-05-13
|
|
102
|
+
|
|
103
|
+
**Klodd-ds:** denna ADR + 02-components.md panel-entry uppdaterad +
|
|
104
|
+
DESIGN-LANGUAGE.md ny sektion 16 (HTML-tagg-konvention).
|
|
105
|
+
|
|
106
|
+
**Ekonom:** 35 `<div class="panel__title">` → `<h3 class="panel__title">`.
|
|
107
|
+
Specialfall (2 span + 1 summary) behålls med kommentar i template.
|
|
108
|
+
|
|
109
|
+
**Jubb:** 25 `<p class="hero__label">` (icke-hero-kontext) →
|
|
110
|
+
`<h3 class="panel__title">`. Legitim hero-användning (dashboard.html
|
|
111
|
+
rad 16) oförändrad.
|
|
112
|
+
|
|
113
|
+
Inga CSS-ändringar, ingen npm publish behövs. Bara templates +
|
|
114
|
+
dokumentation.
|
|
115
|
+
|
|
116
|
+
## References
|
|
117
|
+
|
|
118
|
+
- DESIGN-LANGUAGE.md sektion 3 (hero vs page-header patterns)
|
|
119
|
+
- 02-components.md panel-entry
|
|
120
|
+
- 02-components.md hero-entry
|
|
121
|
+
- ADR 0011-strikt-bem-elementsyntax.md (besläktad - BEM-disciplin)
|
|
122
|
+
- ADR 0013-visual-coherence-doctrine.md (besläktad - visuell rytm)
|
|
@@ -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)
|
|
@@ -376,6 +376,160 @@ universell PWA-refresh-action via tap på vänster avatar.
|
|
|
376
376
|
|
|
377
377
|
**Etablerad 2026-05-13.** Refaktor från flex till grid samma datum.
|
|
378
378
|
|
|
379
|
+
## 14. CSS Specificity-disciplin (modifier-vinst)
|
|
380
|
+
|
|
381
|
+
**Regel:** default/base-regler för komponenter får INTE sätta `color`,
|
|
382
|
+
`font-size`, `font-weight`, `background`, `border`, `text-transform`
|
|
383
|
+
eller `letter-spacing` på item-level när modifier-classes existerar
|
|
384
|
+
för samma property.
|
|
385
|
+
|
|
386
|
+
**Default-properties ska sättas på block-roten** (`.X`), inte på
|
|
387
|
+
item-rule. Item-rader ärver via cascade, modifier-classes (0,1,0)
|
|
388
|
+
override:ar utan specificity-konflikt.
|
|
389
|
+
|
|
390
|
+
**RÄTT (kv-list 3.19.3):**
|
|
391
|
+
```css
|
|
392
|
+
.kv-list {
|
|
393
|
+
color: var(--text-subtle); /* default på block-root */
|
|
394
|
+
font-size: var(--fs-13);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.kv-list > li:not(--budget):not(--divider) {
|
|
398
|
+
display: flex;
|
|
399
|
+
/* INGEN color/font-size här */
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.kv-list__item--strong { /* 0,1,0 vinner via cascade */
|
|
403
|
+
color: var(--text-default);
|
|
404
|
+
font-weight: var(--fw-medium);
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**FEL (kv-list 3.19.1-3.19.2 - tyst bugg):**
|
|
409
|
+
```css
|
|
410
|
+
.kv-list > li:not(--budget):not(--divider) {
|
|
411
|
+
color: var(--text-subtle); /* 0,3,1 - för hög! */
|
|
412
|
+
font-size: var(--fs-13);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.kv-list__item--strong { /* 0,1,0 - vinner inte mot 0,3,1 */
|
|
416
|
+
color: var(--text-default); /* förlorar */
|
|
417
|
+
font-weight: var(--fw-medium); /* OK - ingen konflikt */
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Tyst bugg: modifier-classes vinner DELVIS (font-weight) men förlorar
|
|
422
|
+
på color/font-size. Visuell skillnad försvinner. Ingen runtime-error.
|
|
423
|
+
|
|
424
|
+
Se ADR 0014 för fullständig analys + alternativa lösningar (`:where()`,
|
|
425
|
+
modifier-specificity-boost).
|
|
426
|
+
|
|
427
|
+
**Etablerad 2026-05-13** efter kv-list-specificity-incidenten.
|
|
428
|
+
|
|
429
|
+
## 15. Sentence-case för labels (svenska)
|
|
430
|
+
|
|
431
|
+
**Regel:** label- och header-style text använder sentence-case
|
|
432
|
+
("Din dagsbudget"), inte uppercase ("DIN DAGSBUDGET"). Visuell
|
|
433
|
+
hierarki kommer från font-size + weight + color, inte caps.
|
|
434
|
+
|
|
435
|
+
**Sentence-case (default):**
|
|
436
|
+
- `.hero__label`, `.panel__title`, `.form-section__title`
|
|
437
|
+
- `.sheet__title`, `.hub-category`, `.sub-section-header`
|
|
438
|
+
- Banner-headings, empty-state titlar, card-rubriker
|
|
439
|
+
|
|
440
|
+
**Uppercase behålls (etablerad konvention):**
|
|
441
|
+
- `.heading-4`, `.text-tiny` (semantiska typo-klasser, dokumenterade
|
|
442
|
+
som "micro-tracker")
|
|
443
|
+
- `.table th` (tabellhuvuden)
|
|
444
|
+
- `.swipe-decision-overlay` (action-overlays SPARA/FÖRVISA)
|
|
445
|
+
- `.avatar` (initialer "CE")
|
|
446
|
+
- `.panel__step-badge`, `.sheet__field-label--upper` (explicit modifier)
|
|
447
|
+
- Styleguide-element i `/design` (visuell hierarki via caps)
|
|
448
|
+
|
|
449
|
+
**Rationale:** svensk grafisk konvention. Calle 2026-05-13: "bara
|
|
450
|
+
capital letter och sen gemener, som vanligt." Matchar iOS Settings,
|
|
451
|
+
Apple HIG, modern app-design. Caps reserveras för badges/actions/
|
|
452
|
+
metadata där tighet + kort längd gör det läsbart.
|
|
453
|
+
|
|
454
|
+
**Letter-spacing:** sentence-case-text använder `var(--ls-tight)`,
|
|
455
|
+
inte `--ls-wider` eller hårdkodad 0.04-0.12em (det är designat för
|
|
456
|
+
uppercase-tracking och ser sträckt ut i sentence-case).
|
|
457
|
+
|
|
458
|
+
**Etablerad 2026-05-13** efter uppercase-audit över paketet.
|
|
459
|
+
|
|
460
|
+
## 16. HTML-tagg för `.panel__title`
|
|
461
|
+
|
|
462
|
+
**Regel:** panel-rubriker använder `<h3 class="panel__title">` som
|
|
463
|
+
default-tagg. Två specialfall behålls:
|
|
464
|
+
|
|
465
|
+
| Kontext | Tagg | Skäl |
|
|
466
|
+
|---|---|---|
|
|
467
|
+
| Default | `<h3>` | A11y-semantik, screen-reader-navigerbar |
|
|
468
|
+
| Inom `.panel__step-row` | `<span>` | Compound badge+title som en konceptuell rubrik (Steg 1: X) |
|
|
469
|
+
| Inom `<details>` | `<summary>` | Native HTML-krav (summary måste vara första child) |
|
|
470
|
+
|
|
471
|
+
**Definition av `.hero__label` vs `.panel__title`:**
|
|
472
|
+
- `<p class="hero__label">` ENDAST om följt av `<p class="hero-amount">`
|
|
473
|
+
eller `<p class="hero__amount--card">`. Klassen är "labeltext OVANFÖR
|
|
474
|
+
en stor siffer-display".
|
|
475
|
+
- Allt annat (rubrik för list, table, form, text-content, knapp) ska
|
|
476
|
+
vara `<h3 class="panel__title">`.
|
|
477
|
+
|
|
478
|
+
**Förbjudet:**
|
|
479
|
+
- `<div class="panel__title">` (saknar heading-semantik)
|
|
480
|
+
- `<p class="panel__title">` (paragraph är fel semantik för rubrik)
|
|
481
|
+
- `<h3 class="hero__label">` (mismatch klass/tagg)
|
|
482
|
+
|
|
483
|
+
**Rationale:** `<div>` är aria-tree-osynligt - screen readers kan inte
|
|
484
|
+
navigera mellan paneler via heading-shortcut. `<h3>` är industri-praxis
|
|
485
|
+
för card-titles (Radix UI, Material UI, Chakra). CSS oförändrad
|
|
486
|
+
eftersom `.panel__title`-stylling targetar klassen, inte taggen.
|
|
487
|
+
|
|
488
|
+
**Heading-hierarki:** vyer med `<h1 class="heading-1">` får h1→h3
|
|
489
|
+
(legitimt skip). Vyer utan h1 får h3 som top-level (icke-ideal men
|
|
490
|
+
inte brott - browser-tree accepterar skipping levels).
|
|
491
|
+
|
|
492
|
+
**Etablerad 2026-05-13** efter panel__title-audit över Jubb + Ekonom.
|
|
493
|
+
Se ADR 0015 (panel-title-tag-doctrine).
|
|
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
|
+
|
|
379
533
|
## 12. När ändra regler
|
|
380
534
|
|
|
381
535
|
Denna fil är **locked**. Ändringar kräver:
|