@klodd/ds 3.3.1 → 3.4.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/SKILL.md +56 -0
- package/bin/klodd-ds.js +25 -0
- package/bin/precache.js +43 -0
- package/bin/sync.js +33 -0
- package/bin/verify.js +66 -0
- package/css/00-primitives.css +13 -3
- package/css/base/typography.css +3 -5
- package/css/components/dropdown.css +1 -1
- package/css/components/setting-row.css +1 -1
- package/css/components/tab-bar.css +1 -1
- package/css/components/tooltip.css +1 -1
- package/css/utilities.css +101 -67
- package/js/hero-roll.js +5 -5
- package/package.json +12 -3
- package/references/01-tokens.md +182 -0
- package/references/02-components.md +260 -0
- package/references/03-quality-bar.md +238 -0
- package/references/04-locked-decisions/0001-three-layer-token-architecture.md +41 -0
- package/references/04-locked-decisions/0002-bem-naming.md +37 -0
- package/references/04-locked-decisions/0003-radix-colors-oklch.md +39 -0
- package/references/04-locked-decisions/0004-pixel-numeric-spacing.md +31 -0
- package/references/04-locked-decisions/0005-data-app-theming.md +42 -0
- package/references/04-locked-decisions/0006-mauve-neutral.md +40 -0
- package/references/04-locked-decisions/0007-font-weight-400-500.md +46 -0
- package/references/04-locked-decisions/0008-npm-package-distribution.md +40 -0
- package/references/05-open-decisions/0001-tx-row-to-list-row-migration-CLOSED.md +80 -0
- package/references/05-open-decisions/0002-parallel-classnames-cleanup-CLOSED.md +75 -0
- package/references/05-open-decisions/0003-js-duplicates-migration-CLOSED.md +79 -0
- package/references/05-open-decisions/0004-halsomentorn-legacy-css.md +51 -0
- package/references/05-open-decisions/0005-cat-class-location-CLOSED.md +37 -0
- package/references/05-open-decisions/0006-bar-kind-template-migration-CLOSED.md +75 -0
- package/references/05-open-decisions/0007-ekonom-base-import-gap-CLOSED.md +111 -0
- package/references/05-open-decisions/0008-legacy-token-migration.md +73 -0
package/SKILL.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: klodd-ds
|
|
3
|
+
description: Design memory for the @klodd/ds shared design system across all Klodd apps (Jubb, Ekonom, future apps). Use this skill whenever working on UI components, design tokens, theming, CSS class names, spacing, color, typography, accessibility, or any visual or interaction decision in an app that imports @klodd/ds. Also use when questions arise about component APIs, token architecture, BEM naming, whether to add new tokens vs reuse existing, or how to theme a new app. Contains locked architectural decisions (do not re-litigate without explicit instruction) and open migration items (still under discussion).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @klodd/ds — Design Memory
|
|
7
|
+
|
|
8
|
+
## Vad detta är
|
|
9
|
+
Gemensamt designsystem på npm (`@klodd/ds@3.x`). Tre-lagers tokens,
|
|
10
|
+
33+ komponenter, konsumeras av Jubb och Ekonom. Fler appar planerade.
|
|
11
|
+
Denna Skill fångar både reglerna ("vad") och resonemanget ("varför").
|
|
12
|
+
|
|
13
|
+
## Läs i denna ordning
|
|
14
|
+
1. `references/01-tokens.md` — token-arkitektur (primitives → semantic → per-app)
|
|
15
|
+
2. `references/02-components.md` — komponentkatalog med anti-patterns
|
|
16
|
+
3. `references/03-quality-bar.md` — icke-förhandlingsbara krav
|
|
17
|
+
|
|
18
|
+
<locked_rules>
|
|
19
|
+
- ALDRIG hårdkoda färg, spacing, radius eller font-size. Alltid semantic token.
|
|
20
|
+
- BEM-namngivning för alla CSS-klasser (.block__element--modifier).
|
|
21
|
+
- WCAG AA minimum på alla interaktiva komponenter.
|
|
22
|
+
- Spacing är pixel-numerisk: --space-N där N = exakt antal pixlar (4, 8, 12, 16...).
|
|
23
|
+
- Per-app token-lager overridar bara semantic — aldrig primitives direkt.
|
|
24
|
+
- Font-weight: bara --fw-regular (400) eller --fw-medium (500).
|
|
25
|
+
Undantag: display-siffror (hero-roll) explicit font-weight: 600.
|
|
26
|
+
- Komponenter refererar ALDRIG --gray-N, --blue-N, --plum-N direkt.
|
|
27
|
+
</locked_rules>
|
|
28
|
+
|
|
29
|
+
## Apps och theming
|
|
30
|
+
- `data-app="jubb"` → Blue accent (Radix Blue Dark), Mauve neutral
|
|
31
|
+
- `data-app="ekonom"` → Plum accent (Radix Plum Dark), Plum-tonad bakgrund
|
|
32
|
+
- Ny app: lägg till ramp i 00-primitives.css + 5-raders apps/foo.css
|
|
33
|
+
|
|
34
|
+
## Besluts-records
|
|
35
|
+
- `references/04-locked-decisions/` — låsta beslut. Förklara, ändra inte.
|
|
36
|
+
- `references/05-open-decisions/` — öppna punkter. Presentera alternativen.
|
|
37
|
+
|
|
38
|
+
## Komponent-val
|
|
39
|
+
1. Kolla `references/02-components.md` för befintlig komponent
|
|
40
|
+
2. Föredra komposition över fork
|
|
41
|
+
3. Saknas den genuint — föreslå var den passar i token-modellen FÖRST
|
|
42
|
+
|
|
43
|
+
## Uppdatera paketet
|
|
44
|
+
```bash
|
|
45
|
+
cd ~/dev/klodd-ds
|
|
46
|
+
npm version patch|minor|major
|
|
47
|
+
npm publish --access public
|
|
48
|
+
cd ~/dev/Jubb && npm install @klodd/ds@latest && npm run build:ds
|
|
49
|
+
cd ~/dev/Ekonom && npm install @klodd/ds@latest && npm run build:ds
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## När du är osäker
|
|
53
|
+
Läs relevant ADR. Täcks frågan inte av något ADR — flagga det explicit:
|
|
54
|
+
"Jag ser inget beslut på detta — ska vi skapa ett i references/05-open-decisions/?"
|
|
55
|
+
|
|
56
|
+
Updated: 2026-05-07 (matchar @klodd/ds 3.2.0)
|
package/bin/klodd-ds.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* @klodd/ds CLI-dispatcher.
|
|
3
|
+
*
|
|
4
|
+
* Anvandning fran ett app-repo (Jubb, Ekonom, framtida appar):
|
|
5
|
+
* npx @klodd/ds sync - kopiera paketets CSS/JS till app-repots ds-mapp
|
|
6
|
+
* npx @klodd/ds verify - diff:a committade DS-filer mot paketet (CI-gate)
|
|
7
|
+
* npx @klodd/ds precache - generera PRECACHE_URLS fran main.css + base.html
|
|
8
|
+
*
|
|
9
|
+
* Konfiguration: klodd-ds.json i app-repots rot.
|
|
10
|
+
* { "cssTarget": "app/static/css/ds", "jsTarget": "app/static/js/ds" } */
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const cmd = process.argv[2];
|
|
14
|
+
const valid = new Set(['sync', 'verify', 'precache']);
|
|
15
|
+
|
|
16
|
+
if (!valid.has(cmd)) {
|
|
17
|
+
console.error('Anvandning: npx @klodd/ds <sync|verify|precache>');
|
|
18
|
+
console.error('');
|
|
19
|
+
console.error(' sync Kopiera paketets CSS/JS till app-repots ds-mapp.');
|
|
20
|
+
console.error(' verify Diff:a committade DS-filer mot paketet (CI-gate).');
|
|
21
|
+
console.error(' precache Generera PRECACHE_URLS fran main.css + base.html.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
require('./' + cmd + '.js');
|
package/bin/precache.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* @klodd/ds precache - genererar PRECACHE_URLS fran main.css @imports
|
|
3
|
+
* och base.html <link>-taggar.
|
|
4
|
+
* Kor: npx @klodd/ds precache
|
|
5
|
+
* Output: lista av URL:er att klistra in i sw.js
|
|
6
|
+
*
|
|
7
|
+
* Notera: hanterar bara direkta @import i main.css (inte nested).
|
|
8
|
+
* Ekonom har bundles/ekonom.css som importerar nestat - kompletterar
|
|
9
|
+
* manuellt vid jamforelse mot befintlig PRECACHE_URLS. */
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
const cssPath = path.join(process.cwd(), 'app/static/css/main.css');
|
|
16
|
+
const htmlPath = path.join(process.cwd(), 'app/templates/base.html');
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(cssPath)) {
|
|
19
|
+
console.error(`Saknas: ${cssPath}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
if (!fs.existsSync(htmlPath)) {
|
|
23
|
+
console.error(`Saknas: ${htmlPath}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const mainCss = fs.readFileSync(cssPath, 'utf8');
|
|
28
|
+
const baseHtml = fs.readFileSync(htmlPath, 'utf8');
|
|
29
|
+
|
|
30
|
+
const cssImports = [...mainCss.matchAll(/@import url\(['"]?(.+?)['"]?\)/g)]
|
|
31
|
+
.map((m) => '/static/css/' + m[1].replace(/^\.\//, ''));
|
|
32
|
+
|
|
33
|
+
const htmlLinks = [...baseHtml.matchAll(/<link[^>]+rel=["']stylesheet["'][^>]+href=["']([^"'?]+)/g)]
|
|
34
|
+
.map((m) => m[1]);
|
|
35
|
+
|
|
36
|
+
const allUrls = [...new Set([...cssImports, ...htmlLinks])].sort();
|
|
37
|
+
|
|
38
|
+
console.log('// Auto-genererat av npx @klodd/ds precache');
|
|
39
|
+
console.log('// Kor kommandot igen om main.css eller base.html andras.');
|
|
40
|
+
console.log('// Hanterar bara direkta @imports - jamfor mot befintlig SW-lista.');
|
|
41
|
+
console.log('const PRECACHE_URLS = [');
|
|
42
|
+
allUrls.forEach((url) => console.log(` '${url}',`));
|
|
43
|
+
console.log('];');
|
package/bin/sync.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* @klodd/ds sync - kopierar paketets CSS och JS till app-repot.
|
|
3
|
+
* Kor: npx @klodd/ds sync
|
|
4
|
+
* Forutsatter att CWD ar app-repots rot.
|
|
5
|
+
* Laser cssTarget/jsTarget fran klodd-ds.json i CWD, eller anvander default.
|
|
6
|
+
*
|
|
7
|
+
* Cross-platform via fs.cpSync (Node 16.7+) - inte POSIX cp -r. */
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const pkgDir = path.dirname(require.resolve('@klodd/ds/package.json'));
|
|
14
|
+
const cssSource = path.join(pkgDir, 'css');
|
|
15
|
+
const jsSource = path.join(pkgDir, 'js');
|
|
16
|
+
|
|
17
|
+
const configPath = path.join(process.cwd(), 'klodd-ds.json');
|
|
18
|
+
const config = fs.existsSync(configPath)
|
|
19
|
+
? JSON.parse(fs.readFileSync(configPath, 'utf8'))
|
|
20
|
+
: { cssTarget: 'app/static/css/ds', jsTarget: 'app/static/js/ds' };
|
|
21
|
+
|
|
22
|
+
const cssTarget = path.join(process.cwd(), config.cssTarget);
|
|
23
|
+
const jsTarget = path.join(process.cwd(), config.jsTarget);
|
|
24
|
+
|
|
25
|
+
fs.mkdirSync(cssTarget, { recursive: true });
|
|
26
|
+
fs.mkdirSync(jsTarget, { recursive: true });
|
|
27
|
+
|
|
28
|
+
fs.cpSync(cssSource, cssTarget, { recursive: true });
|
|
29
|
+
if (fs.existsSync(jsSource)) {
|
|
30
|
+
fs.cpSync(jsSource, jsTarget, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(`OK @klodd/ds synkad till ${config.cssTarget} och ${config.jsTarget}`);
|
package/bin/verify.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* @klodd/ds verify - diff:ar committade DS-filer mot paket-kallan.
|
|
3
|
+
* Kor i CI: npx @klodd/ds verify
|
|
4
|
+
* Fail:ar med exit code 1 om drift detekteras. */
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const crypto = require('crypto');
|
|
10
|
+
|
|
11
|
+
const pkgDir = path.dirname(require.resolve('@klodd/ds/package.json'));
|
|
12
|
+
const configPath = path.join(process.cwd(), 'klodd-ds.json');
|
|
13
|
+
const config = fs.existsSync(configPath)
|
|
14
|
+
? JSON.parse(fs.readFileSync(configPath, 'utf8'))
|
|
15
|
+
: { cssTarget: 'app/static/css/ds', jsTarget: 'app/static/js/ds' };
|
|
16
|
+
|
|
17
|
+
function hashFile(filePath) {
|
|
18
|
+
return crypto.createHash('sha256')
|
|
19
|
+
.update(fs.readFileSync(filePath))
|
|
20
|
+
.digest('hex');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function listFilesRec(dir) {
|
|
24
|
+
const out = [];
|
|
25
|
+
const stack = [{ abs: dir, rel: '' }];
|
|
26
|
+
while (stack.length) {
|
|
27
|
+
const { abs, rel } = stack.pop();
|
|
28
|
+
for (const entry of fs.readdirSync(abs, { withFileTypes: true })) {
|
|
29
|
+
const childAbs = path.join(abs, entry.name);
|
|
30
|
+
const childRel = rel ? path.join(rel, entry.name) : entry.name;
|
|
31
|
+
if (entry.isDirectory()) stack.push({ abs: childAbs, rel: childRel });
|
|
32
|
+
else if (entry.isFile()) out.push(childRel);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function diffDirs(sourceDir, targetRel) {
|
|
39
|
+
const drifted = [];
|
|
40
|
+
if (!fs.existsSync(sourceDir)) return drifted;
|
|
41
|
+
const targetAbs = path.join(process.cwd(), targetRel);
|
|
42
|
+
for (const file of listFilesRec(sourceDir)) {
|
|
43
|
+
const src = path.join(sourceDir, file);
|
|
44
|
+
const tgt = path.join(targetAbs, file);
|
|
45
|
+
if (!fs.existsSync(tgt)) {
|
|
46
|
+
drifted.push(`SAKNAS: ${targetRel}/${file}`);
|
|
47
|
+
} else if (hashFile(src) !== hashFile(tgt)) {
|
|
48
|
+
drifted.push(`DRIFT: ${targetRel}/${file}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return drifted;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const cssDrift = diffDirs(path.join(pkgDir, 'css'), config.cssTarget);
|
|
55
|
+
const jsDrift = diffDirs(path.join(pkgDir, 'js'), config.jsTarget);
|
|
56
|
+
const allDrift = [...cssDrift, ...jsDrift];
|
|
57
|
+
|
|
58
|
+
if (allDrift.length > 0) {
|
|
59
|
+
console.error('FAIL: @klodd/ds drift detekterad:');
|
|
60
|
+
allDrift.forEach((d) => console.error(' ' + d));
|
|
61
|
+
console.error('\nKor `npm run build:ds` for att synka.');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log('OK: alla DS-filer matchar @klodd/ds-paketet.');
|
|
66
|
+
process.exit(0);
|
package/css/00-primitives.css
CHANGED
|
@@ -349,11 +349,21 @@
|
|
|
349
349
|
|
|
350
350
|
/* ================================================================
|
|
351
351
|
==== Z-INDEX
|
|
352
|
+
Hierarki (lagst forst):
|
|
353
|
+
- tooltip: hover-popups, ovanpa allt vanligt content
|
|
354
|
+
- dropdown: dropdown-menyer, autocomplete, kontextmenyer
|
|
355
|
+
- sticky: sticky-headers, fixed bottom-nav
|
|
356
|
+
- modal: overlays, sheets, modals
|
|
357
|
+
- spinner: upload-spinner, blockerar interaktion
|
|
352
358
|
================================================================ */
|
|
353
359
|
:root {
|
|
354
|
-
--z-
|
|
355
|
-
--z-
|
|
356
|
-
--z-
|
|
360
|
+
--z-tooltip: 50;
|
|
361
|
+
--z-dropdown: 100;
|
|
362
|
+
--z-nav: 100; /* alias for --z-dropdown - bottom-nav-niva */
|
|
363
|
+
--z-sticky: 150;
|
|
364
|
+
--z-modal: 200;
|
|
365
|
+
--z-overlay: 200; /* alias for --z-modal - bibehalls bakat-kompat */
|
|
366
|
+
--z-spinner: 9999;
|
|
357
367
|
}
|
|
358
368
|
|
|
359
369
|
|
package/css/base/typography.css
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
/* Inter
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
400 = --fw-regular, 500 = --fw-medium per font-weight-policy. */
|
|
5
|
-
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap');
|
|
1
|
+
/* Inter laddas INTE via Google Fonts (render-blocking, medvetet borttaget).
|
|
2
|
+
* Stacken faller tillbaka pa SF Pro Display pa iOS och system-ui pa ovriga.
|
|
3
|
+
* Se --font-sans i 00-primitives.css. */
|
|
6
4
|
|
|
7
5
|
|
|
8
6
|
/* ================================================================
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
background: var(--surface-page);
|
|
173
173
|
border-radius: 50%;
|
|
174
174
|
transition: transform var(--dur-medium) var(--ease-spring-snappy);
|
|
175
|
-
box-shadow:
|
|
175
|
+
box-shadow: var(--shadow-card);
|
|
176
176
|
}
|
|
177
177
|
.setting-toggle input:checked + .setting-toggle__track {
|
|
178
178
|
background: var(--accent-9);
|
package/css/utilities.css
CHANGED
|
@@ -1,81 +1,115 @@
|
|
|
1
1
|
/* ================================================================
|
|
2
|
-
utilities.css
|
|
3
|
-
Single-purpose
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Ingen styling-logik - bara en CSS-property per klass.
|
|
2
|
+
ds/utilities.css
|
|
3
|
+
Single-purpose helpers. Anvands sparsamt for layout-tweaks som
|
|
4
|
+
inte motiverar en namngiven komponentklass. Inte Tailwind-style
|
|
5
|
+
explosion, utan ett medvetet litet set.
|
|
7
6
|
================================================================ */
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
/* Display ------------------------------------------------------- */
|
|
10
|
+
.flex { display: flex; }
|
|
11
|
+
.flex-col { display: flex; flex-direction: column; }
|
|
12
|
+
.inline { display: inline; }
|
|
13
|
+
.inline-block { display: inline-block; }
|
|
14
|
+
.inline-flex { display: inline-flex; }
|
|
15
|
+
.block { display: block; }
|
|
16
|
+
.is-hidden { display: none; }
|
|
17
|
+
|
|
18
|
+
/* Text wrapping (Sprint 50/CSP A+: ersatter inline word-break-style) */
|
|
19
|
+
.break-word { word-break: break-word; }
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/* Flex --------------------------------------------------------- */
|
|
23
|
+
.items-center { align-items: center; }
|
|
24
|
+
.items-baseline { align-items: baseline; }
|
|
25
|
+
.items-start { align-items: flex-start; }
|
|
26
|
+
.items-end { align-items: flex-end; }
|
|
27
|
+
.justify-between { justify-content: space-between; }
|
|
28
|
+
.flex-wrap { flex-wrap: wrap; }
|
|
29
|
+
.flex-1 { flex: 1; }
|
|
30
|
+
.flex-2 { flex: 2; }
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
/* Gaps --------------------------------------------------------- */
|
|
34
|
+
.gap-sm { gap: var(--space-8); }
|
|
35
|
+
.gap-md { gap: var(--space-12); }
|
|
36
|
+
.gap-lg { gap: var(--space-20); }
|
|
37
|
+
.gap-14 { gap: var(--space-14); }
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
/* Margins (numerisk pixel-skala + namnvarianter) ---------------- */
|
|
10
41
|
.m-0 { margin: 0; }
|
|
11
42
|
.mt-0 { margin-top: 0; }
|
|
43
|
+
.mt-2 { margin-top: var(--space-2); }
|
|
12
44
|
.mt-4 { margin-top: var(--space-4); }
|
|
13
|
-
.mt-
|
|
45
|
+
.mt-6 { margin-top: var(--space-6); }
|
|
46
|
+
.mt-8, .mt-sm { margin-top: var(--space-8); }
|
|
14
47
|
.mt-12 { margin-top: var(--space-12); }
|
|
15
|
-
.mt-16 { margin-top: var(--space-16); }
|
|
16
|
-
.mt-
|
|
17
|
-
|
|
48
|
+
.mt-16, .mt-md { margin-top: var(--space-16); }
|
|
49
|
+
.mt-24, .mt-lg { margin-top: var(--space-24); }
|
|
50
|
+
|
|
18
51
|
.mb-0 { margin-bottom: 0; }
|
|
52
|
+
.mb-2 { margin-bottom: var(--space-2); }
|
|
19
53
|
.mb-4 { margin-bottom: var(--space-4); }
|
|
20
|
-
.mb-
|
|
54
|
+
.mb-6 { margin-bottom: var(--space-6); }
|
|
55
|
+
.mb-8, .mb-sm { margin-bottom: var(--space-8); }
|
|
56
|
+
.mb-10 { margin-bottom: var(--space-10); }
|
|
21
57
|
.mb-12 { margin-bottom: var(--space-12); }
|
|
22
|
-
.mb-
|
|
23
|
-
.mb-
|
|
24
|
-
.mb-24 { margin-bottom: var(--space-24); }
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.w-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
.gap-12 { gap: var(--space-12); }
|
|
43
|
-
.gap-16 { gap: var(--space-16); }
|
|
44
|
-
.flex-column { flex-direction: column; }
|
|
45
|
-
.align-center { align-items: center; }
|
|
46
|
-
.align-self-start { align-self: flex-start; }
|
|
47
|
-
.justify-between { justify-content: space-between; }
|
|
58
|
+
.mb-14 { margin-bottom: var(--space-14); }
|
|
59
|
+
.mb-16, .mb-md { margin-bottom: var(--space-16); }
|
|
60
|
+
.mb-24, .mb-lg { margin-bottom: var(--space-24); }
|
|
61
|
+
|
|
62
|
+
.mr-sm { margin-right: var(--space-8); }
|
|
63
|
+
.ml-auto { margin-left: auto; }
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
/* Padding ------------------------------------------------------- */
|
|
67
|
+
.py-sm { padding-top: var(--space-8); padding-bottom: var(--space-8); }
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
/* Width / max-width -------------------------------------------- */
|
|
71
|
+
.w-full { width: 100%; }
|
|
72
|
+
.w-auto { width: auto; }
|
|
73
|
+
.w-100 { width: 100px; }
|
|
74
|
+
.max-w-narrow { max-width: 120px; }
|
|
75
|
+
.max-w-200 { max-width: 200px; }
|
|
76
|
+
.max-w-medium { max-width: 220px; }
|
|
77
|
+
|
|
48
78
|
|
|
49
|
-
/*
|
|
79
|
+
/* Min-width (for flex-form-rows) ------------------------------- */
|
|
80
|
+
.min-w-140 { min-width: 140px; }
|
|
81
|
+
.min-w-180 { min-width: 180px; }
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
/* Text helpers ------------------------------------------------- */
|
|
85
|
+
.text-right { text-align: right; }
|
|
86
|
+
.text-center { text-align: center; }
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
/* Cursors ------------------------------------------------------ */
|
|
90
|
+
.cursor-pointer { cursor: pointer; }
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
/* Position (CSP-migration: ersatter style="position: ..."-attribut) */
|
|
50
94
|
.absolute { position: absolute; }
|
|
51
95
|
.absolute-fill { position: absolute; inset: 0; }
|
|
52
|
-
.relative { position: relative; }
|
|
53
96
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
.
|
|
65
|
-
.
|
|
66
|
-
.
|
|
67
|
-
.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
/*
|
|
71
|
-
.
|
|
72
|
-
|
|
73
|
-
width: 1px;
|
|
74
|
-
height: 1px;
|
|
75
|
-
padding: 0;
|
|
76
|
-
margin: -1px;
|
|
77
|
-
overflow: hidden;
|
|
78
|
-
clip: rect(0, 0, 0, 0);
|
|
79
|
-
white-space: nowrap;
|
|
80
|
-
border: 0;
|
|
81
|
-
}
|
|
97
|
+
|
|
98
|
+
/* Self-alignment (flex-children) */
|
|
99
|
+
.align-self-start { align-self: flex-start; }
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
/* Composite flex (vanlig kombination i demos och paneler) */
|
|
103
|
+
.flex-col-gap { display: flex; flex-direction: column; gap: var(--space-8); }
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
/* Status-color shortcuts (legacy aliases). */
|
|
107
|
+
.positive { color: var(--positive); }
|
|
108
|
+
.negative { color: var(--negative); }
|
|
109
|
+
.accent { color: var(--accent); }
|
|
110
|
+
.warning { color: var(--warning); }
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
/* Text-color utilities (CSP-migration: ersatter style="color: var(--text-X)") */
|
|
114
|
+
.text-subtle { color: var(--text-subtle); }
|
|
115
|
+
.text-muted { color: var(--text-muted); }
|
package/js/hero-roll.js
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
marker. Animation kor vid forsta page-load efter att PWA/tab
|
|
18
18
|
stangts helt. Sprint D3:s `body[data-first-load]` (cookie-baserad)
|
|
19
19
|
fungerar bara for helt nya anvandare; J.5-trigger fungerar for
|
|
20
|
-
return-anvandare som har
|
|
20
|
+
return-anvandare som har appens first-load-cookie (satts av servern)
|
|
21
|
+
sedan tidigare.
|
|
21
22
|
2. Manadsbyte via < / > i manads-pillen pa /avstamning
|
|
22
23
|
|
|
23
24
|
Sprint J.4 (CE-rapport: 000 kr syns lite val lange + hela processen
|
|
@@ -58,10 +59,9 @@
|
|
|
58
59
|
// Sprint J.5: sessionStorage-marker for fresh-session-detektering.
|
|
59
60
|
// sessionStorage rensas vid PWA-stangning/tab-close, persisterar
|
|
60
61
|
// mellan reloads/nav inom samma session.
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
// engang per anvandare - ny markering satts vid nasta kallstart.
|
|
62
|
+
// Nyckel: ds_hero_session (app-agnostisk). Delad mellan alla appar
|
|
63
|
+
// som anvander @klodd/ds sa samma session-marker fungerar oavsett
|
|
64
|
+
// vilken app som kor.
|
|
65
65
|
const SESSION_KEY = 'ds_hero_session';
|
|
66
66
|
|
|
67
67
|
let hasRunInitial = false;
|
package/package.json
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@klodd/ds",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Klodd Design System - shared tokens, typography, components and JS for Jubb, Ekonom, and future apps.
|
|
3
|
+
"version": "3.4.1",
|
|
4
|
+
"description": "Klodd Design System - shared tokens, typography, components and JS for Jubb, Ekonom, and future apps. v3.4 inkluderar sync/verify/precache CLI sa app-repona inte langre handhaller egna build-script. v3.4.1 tar bort Google Fonts @import + gor hero-roll-kommentarer app-agnostiska.",
|
|
5
5
|
"main": "css/index.css",
|
|
6
|
+
"bin": {
|
|
7
|
+
"klodd-ds": "./bin/klodd-ds.js"
|
|
8
|
+
},
|
|
6
9
|
"files": [
|
|
7
10
|
"css/",
|
|
8
|
-
"js/"
|
|
11
|
+
"js/",
|
|
12
|
+
"bin/",
|
|
13
|
+
"SKILL.md",
|
|
14
|
+
"references/"
|
|
9
15
|
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=16.7"
|
|
18
|
+
},
|
|
10
19
|
"keywords": [
|
|
11
20
|
"design-system",
|
|
12
21
|
"css",
|