@klodd/ds 3.16.0 → 3.17.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/css/components/nav.css +34 -13
- package/css/components/pwa-avatar.css +51 -0
- package/css/index.css +1 -0
- package/js/hard-refresh.js +45 -0
- package/package.json +1 -1
- package/references/02-components.md +18 -2
- package/references/DESIGN-LANGUAGE.md +43 -29
package/css/components/nav.css
CHANGED
|
@@ -112,18 +112,23 @@
|
|
|
112
112
|
|
|
113
113
|
/* ================================================================
|
|
114
114
|
==== TOPBAR (in-flow header)
|
|
115
|
-
Tre slots:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
Tre slots: pwa-avatar/back (vanster) / titel-eller-month-pill
|
|
116
|
+
(center) / user-avatar (hoger). Display grid med 3 kolumner.
|
|
117
|
+
|
|
118
|
+
Layout-doktrin (2026-05-13):
|
|
119
|
+
- Kolumn 1 (vanster, auto): .pwa-avatar ELLER .topbar__back
|
|
120
|
+
- Kolumn 2 (center, 1fr): .topbar__title ELLER .month-pill
|
|
121
|
+
- Kolumn 3 (hoger, auto): .avatar (ev. wrappad i <a>)
|
|
122
|
+
|
|
123
|
+
Grid-positioning sker via explicit grid-column-rules nedan -
|
|
124
|
+
HTML-ordning paverkar inte visual position.
|
|
125
|
+
|
|
126
|
+
Doktrin gemensam for alla Klodd-appar (Ekonom, Jubb, framtida).
|
|
127
|
+
Se DESIGN-LANGUAGE.md sektion 13.
|
|
124
128
|
================================================================ */
|
|
125
129
|
.topbar {
|
|
126
|
-
display:
|
|
130
|
+
display: grid;
|
|
131
|
+
grid-template-columns: auto 1fr auto;
|
|
127
132
|
align-items: center;
|
|
128
133
|
gap: var(--space-12);
|
|
129
134
|
min-height: var(--touch-min);
|
|
@@ -131,11 +136,27 @@
|
|
|
131
136
|
margin-bottom: var(--space-16);
|
|
132
137
|
}
|
|
133
138
|
|
|
134
|
-
/*
|
|
135
|
-
|
|
139
|
+
/* Vanster kolumn: pwa-avatar eller back-knapp */
|
|
140
|
+
.topbar > .pwa-avatar,
|
|
141
|
+
.topbar > .topbar__back {
|
|
142
|
+
grid-column: 1;
|
|
143
|
+
justify-self: start;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Center kolumn: titel eller month-pill */
|
|
147
|
+
.topbar > .topbar__title,
|
|
148
|
+
.topbar > .topbar__logo,
|
|
149
|
+
.topbar > .month-pill,
|
|
150
|
+
.topbar > .brand-pill {
|
|
151
|
+
grid-column: 2;
|
|
152
|
+
justify-self: center;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Hoger kolumn: user-avatar (direkt eller wrappad i <a>) */
|
|
136
156
|
.topbar > .avatar,
|
|
137
157
|
.topbar > a:has(> .avatar) {
|
|
138
|
-
|
|
158
|
+
grid-column: 3;
|
|
159
|
+
justify-self: end;
|
|
139
160
|
}
|
|
140
161
|
|
|
141
162
|
.topbar__back {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* ================================================================
|
|
2
|
+
components/pwa-avatar.css
|
|
3
|
+
PWA-identifierande avatar i topbar (vansterstalld).
|
|
4
|
+
Skiljer sig fran .avatar (user-profile, hogerstalld) genom:
|
|
5
|
+
- Anvands for app-brand-identifiering (Jubb-J, Ekonom-E)
|
|
6
|
+
- Hard-refresh-trigger via klick (se hard-refresh.js)
|
|
7
|
+
- Subtle accent-soft-bg + accent-text istallet for accent-9-gradient
|
|
8
|
+
|
|
9
|
+
Storlek 36x36 matchar .avatar default + .month-pill for visuell
|
|
10
|
+
harmoni i topbar.
|
|
11
|
+
|
|
12
|
+
Blocks:
|
|
13
|
+
.pwa-avatar - klickbar app-brand-avatar (button-element)
|
|
14
|
+
================================================================ */
|
|
15
|
+
.pwa-avatar {
|
|
16
|
+
display: inline-flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
width: 36px;
|
|
20
|
+
height: 36px;
|
|
21
|
+
padding: 0;
|
|
22
|
+
background: var(--accent-soft);
|
|
23
|
+
color: var(--accent-text);
|
|
24
|
+
border: 1px solid var(--accent-a6);
|
|
25
|
+
border-radius: var(--radius-full);
|
|
26
|
+
font-family: inherit;
|
|
27
|
+
font-size: var(--fs-15);
|
|
28
|
+
font-weight: var(--fw-medium);
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
flex-shrink: 0;
|
|
31
|
+
-webkit-tap-highlight-color: transparent;
|
|
32
|
+
touch-action: manipulation;
|
|
33
|
+
transition:
|
|
34
|
+
background var(--dur-fast) var(--ease-spring-snappy),
|
|
35
|
+
transform var(--dur-fast) var(--ease-spring-snappy);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@media (hover: hover) and (pointer: fine) {
|
|
39
|
+
.pwa-avatar:hover {
|
|
40
|
+
background: var(--accent-moderate);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.pwa-avatar:active {
|
|
45
|
+
transform: scale(0.95);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.pwa-avatar:focus-visible {
|
|
49
|
+
outline: 2px solid var(--border-focus);
|
|
50
|
+
outline-offset: 2px;
|
|
51
|
+
}
|
package/css/index.css
CHANGED
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
@import './components/upload-spinner.css';
|
|
60
60
|
@import './components/tab-bar.css';
|
|
61
61
|
@import './components/pill-nav.css';
|
|
62
|
+
@import './components/pwa-avatar.css';
|
|
62
63
|
|
|
63
64
|
/* v3.1.0 - generic kategori-monster (token-binding via app-domain-CSS) */
|
|
64
65
|
@import './components/colored-row.css';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* ================================================================
|
|
2
|
+
hard-refresh.js
|
|
3
|
+
PWA hard-refresh: rensa Cache Storage + unregister Service Worker
|
|
4
|
+
+ reload. Motsvarar webbläsarens Cmd+Shift+R men funkar inom PWA
|
|
5
|
+
(installerad standalone-mode dar tangentbordsgenvagen inte finns).
|
|
6
|
+
|
|
7
|
+
Auto-bind: alla .pwa-avatar-element + [data-pwa-refresh]-element
|
|
8
|
+
triggar hardRefresh() pa klick med confirm-dialog.
|
|
9
|
+
|
|
10
|
+
Aktivera genom att inkludera i base.html:
|
|
11
|
+
<script defer src="/static/js/hard-refresh.js"></script>
|
|
12
|
+
================================================================ */
|
|
13
|
+
(function() {
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
async function hardRefresh() {
|
|
17
|
+
try {
|
|
18
|
+
if ('caches' in window) {
|
|
19
|
+
const keys = await caches.keys();
|
|
20
|
+
await Promise.all(keys.map(k => caches.delete(k)));
|
|
21
|
+
}
|
|
22
|
+
if ('serviceWorker' in navigator) {
|
|
23
|
+
const regs = await navigator.serviceWorker.getRegistrations();
|
|
24
|
+
await Promise.all(regs.map(r => r.unregister()));
|
|
25
|
+
}
|
|
26
|
+
} catch (err) {
|
|
27
|
+
console.error('hard-refresh: cleanup-fel', err);
|
|
28
|
+
} finally {
|
|
29
|
+
location.reload();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
document.addEventListener('click', (e) => {
|
|
34
|
+
const target = e.target.closest('.pwa-avatar, [data-pwa-refresh]');
|
|
35
|
+
if (!target) return;
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
const proceed = confirm('Hard refresh: rensar cache och laddar om PWA-en. Forsatta?');
|
|
38
|
+
if (proceed) {
|
|
39
|
+
hardRefresh();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Exponera for programmatic-anvandning
|
|
44
|
+
window.kloddHardRefresh = hardRefresh;
|
|
45
|
+
})();
|
package/package.json
CHANGED
|
@@ -200,8 +200,24 @@ För varje entry gäller:
|
|
|
200
200
|
### avatar (`avatar.css`)
|
|
201
201
|
- **Blocks:** `.avatar`
|
|
202
202
|
- **Modifiers:** `.avatar--sm`, `.avatar--lg`
|
|
203
|
-
- **Anvand:** Cirkular initial-avatar med accent-gradient
|
|
204
|
-
|
|
203
|
+
- **Anvand:** Cirkular initial-avatar med accent-gradient. ALLTID
|
|
204
|
+
hogerstalld i topbar (kolumn 3) per DESIGN-LANGUAGE sektion 13.
|
|
205
|
+
- **INTE:** Foto-avatar (overlapp via custom regel). Vansterstalld
|
|
206
|
+
i topbar (anvand `.pwa-avatar` istallet).
|
|
207
|
+
|
|
208
|
+
### pwa-avatar (`pwa-avatar.css`) - v3.17.0
|
|
209
|
+
- **Blocks:** `.pwa-avatar`
|
|
210
|
+
- **Anvand:** App-brand-identifierare i topbar kolumn 1 (vansterstalld).
|
|
211
|
+
Klick triggar hard-refresh av PWA (rensar Cache Storage + unregister
|
|
212
|
+
SW + reload) via `js/hard-refresh.js`-auto-bind. Storlek 36x36
|
|
213
|
+
matchar `.avatar` for visuell harmoni.
|
|
214
|
+
- **INTE:** User-profile-avatar (anvand `.avatar` i kolumn 3). Anvandning
|
|
215
|
+
utanfor topbar.
|
|
216
|
+
- **Tokens:** `--accent-soft` (bg), `--accent-text` (color), `--accent-a6`
|
|
217
|
+
(border), `--accent-moderate` (hover-bg). Storlek 36x36, BR full.
|
|
218
|
+
- **JS:** `hard-refresh.js` lyssnar pa klick. Confirm-dialog innan
|
|
219
|
+
destruktiv cache-cleanup + reload. Activated via base.html-include:
|
|
220
|
+
`<script defer src="/static/js/hard-refresh.js"></script>`
|
|
205
221
|
|
|
206
222
|
### list-row (`list-row.css`)
|
|
207
223
|
- **Blocks:** `.list` (sibling-wrapper, `<ul>`-reset), `.list-row` (huvud-block med BEM-element)
|
|
@@ -294,62 +294,76 @@ Future custom stylelint-plugin kan enforce:
|
|
|
294
294
|
Tills sådan plugin finns: visual-coherence är CC-disciplin baserat
|
|
295
295
|
på denna fil.
|
|
296
296
|
|
|
297
|
-
## 13. Topbar-layout-doktrin (
|
|
297
|
+
## 13. Topbar-layout-doktrin (3-column grid)
|
|
298
298
|
|
|
299
|
-
**Regel:** topbar-
|
|
299
|
+
**Regel:** topbar är 3-column grid med strikt slot-positioning:
|
|
300
300
|
|
|
301
|
-
|
|
|
302
|
-
|
|
303
|
-
|
|
|
304
|
-
|
|
|
301
|
+
| Kolumn | Bredd | Element | Användning |
|
|
302
|
+
|---|---|---|---|
|
|
303
|
+
| 1 (vänster) | auto | `.pwa-avatar` ELLER `.topbar__back` | App-brand-identifierare med hard-refresh-trigger ELLER back-navigation |
|
|
304
|
+
| 2 (center) | 1fr | `.topbar__title`, `.topbar__logo`, `.month-pill` ELLER `.brand-pill` | View-namn ELLER månadsväljare ELLER app-namn-text |
|
|
305
|
+
| 3 (höger) | auto | `.avatar` (ev. wrappad i `<a href="/jag">`) | Persistent user-profile-länk |
|
|
305
306
|
|
|
306
307
|
**CSS-implementation** (paketets `nav.css`):
|
|
307
308
|
|
|
308
309
|
```css
|
|
309
|
-
.topbar
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
.topbar {
|
|
311
|
+
display: grid;
|
|
312
|
+
grid-template-columns: auto 1fr auto;
|
|
313
|
+
align-items: center;
|
|
314
|
+
gap: var(--space-12);
|
|
312
315
|
}
|
|
316
|
+
|
|
317
|
+
.topbar > .pwa-avatar, .topbar > .topbar__back { grid-column: 1; justify-self: start; }
|
|
318
|
+
.topbar > .topbar__title, .topbar > .topbar__logo,
|
|
319
|
+
.topbar > .month-pill, .topbar > .brand-pill { grid-column: 2; justify-self: center; }
|
|
320
|
+
.topbar > .avatar, .topbar > a:has(> .avatar) { grid-column: 3; justify-self: end; }
|
|
313
321
|
```
|
|
314
322
|
|
|
315
|
-
|
|
316
|
-
vänster med `gap: var(--space-12)`.
|
|
323
|
+
Elementen positioneras automatiskt baserat på klass, inte HTML-ordning.
|
|
317
324
|
|
|
318
325
|
**HTML-pattern:**
|
|
319
326
|
|
|
320
327
|
```html
|
|
321
|
-
<!-- Standard topbar
|
|
328
|
+
<!-- Standard topbar: pwa-avatar + titel + user-avatar -->
|
|
322
329
|
<div class="topbar">
|
|
323
|
-
<
|
|
324
|
-
<
|
|
330
|
+
<button class="pwa-avatar" data-pwa-refresh aria-label="Refresh PWA">J</button>
|
|
331
|
+
<span class="topbar__title">Jobb</span>
|
|
332
|
+
<a href="/jag"><span class="avatar">CE</span></a>
|
|
325
333
|
</div>
|
|
326
334
|
|
|
327
|
-
<!-- Topbar med back-knapp
|
|
335
|
+
<!-- Topbar med back-knapp -->
|
|
328
336
|
<div class="topbar">
|
|
329
|
-
<a href="/jobb" class="topbar__back"
|
|
330
|
-
<span class="
|
|
331
|
-
<a href="/jag"><span class="avatar">CE</span></a>
|
|
337
|
+
<a href="/jobb" class="topbar__back" aria-label="Tillbaka"><svg.../></a>
|
|
338
|
+
<span class="topbar__title">Jobbdetalj</span>
|
|
339
|
+
<a href="/jag"><span class="avatar">CE</span></a>
|
|
332
340
|
</div>
|
|
333
341
|
|
|
334
|
-
<!-- Topbar
|
|
342
|
+
<!-- Topbar med month-pill (Ekonom dashboards) -->
|
|
335
343
|
<div class="topbar">
|
|
336
|
-
<
|
|
337
|
-
<span class="
|
|
344
|
+
<button class="pwa-avatar" data-pwa-refresh aria-label="Refresh PWA">E</button>
|
|
345
|
+
<span class="month-pill">[‹] Maj 2026 [›]</span>
|
|
346
|
+
<a href="/jag"><span class="avatar">CE</span></a>
|
|
338
347
|
</div>
|
|
339
348
|
```
|
|
340
349
|
|
|
350
|
+
**PWA-avatar = hard-refresh-trigger:**
|
|
351
|
+
- Klick → confirm-dialog → rensa Cache Storage + unregister SW + reload
|
|
352
|
+
- Auto-bind via `hard-refresh.js` (inkluderas i `base.html`)
|
|
353
|
+
- Konfigurerbart via `<button class="pwa-avatar" data-pwa-refresh>` eller bara `<button class="pwa-avatar">`
|
|
354
|
+
- Bg: `--accent-soft`, color: `--accent-text`, height 36px (matchar user-avatar)
|
|
355
|
+
|
|
341
356
|
**Förbjudet:**
|
|
342
|
-
- Avatar någon annanstans än i topbar
|
|
343
|
-
- Två avatar-element i samma topbar
|
|
344
|
-
- Manual
|
|
345
|
-
-
|
|
346
|
-
hanterar det)
|
|
357
|
+
- Avatar någon annanstans än i topbar kolumn 3
|
|
358
|
+
- Två user-avatar-element i samma topbar (en pwa-avatar i kolumn 1 + en user-avatar i kolumn 3 är OK)
|
|
359
|
+
- Manual `margin-left: auto` / `justify-self` på topbar-children i app-domain-CSS (paketet hanterar via grid)
|
|
360
|
+
- Användning av `.pwa-avatar` utanför topbar
|
|
347
361
|
|
|
348
362
|
**Konsekvens:** alla Klodd-appar (Ekonom, Jubb, framtida) får identisk
|
|
349
|
-
topbar-layout
|
|
350
|
-
|
|
363
|
+
topbar-layout: PWA-brand vänster, kontext center, user höger. Plus
|
|
364
|
+
universell PWA-refresh-action via tap på vänster avatar.
|
|
351
365
|
|
|
352
|
-
**Etablerad 2026-05-
|
|
366
|
+
**Etablerad 2026-05-13.** Refaktor från flex till grid samma datum.
|
|
353
367
|
|
|
354
368
|
## 12. När ändra regler
|
|
355
369
|
|