Two changes in one commit because they were prepared together and the component demos depend on the new self-hosted fonts.css. Tier 3 wave 2 — 12 new components --------------------------------- Adds components-tier3-supplement.css (886 lines) and 12 isolated demo HTML pages under shared/playground-examples/components/: toxic-flow chain, fleet-overview, kanban Keep/Review/Remove, maturity-ladder, classify-and-transform, cycle-ribbon, persistent-antipattern, suppressed-signals, ExpansionCard, ReadMore, FormProgress, Aspirational-vs-Committed. Reuses existing tokens — no new CSS custom properties. Honors the Phase 1 feedback rules: no large pink areas for body text, severity-red distinct from failure-red, dark mode via existing [data-theme="dark"]. Provenance: components-tier3-supplement.css and the 12 demo bodies were authored by claude.ai/design (separate Anthropic instance) on 2026-05-03. This commit only integrates them — path rewrites, font swap, generic name substitution in fleet-overview demo data, README updates. base.css from the export was deliberately NOT taken in because it reverted the inline-message contrast fix from v0.1. Self-hosted fonts (Inter, JetBrains Mono, Source Serif 4) --------------------------------------------------------- Replaces all fonts.googleapis.com / fonts.gstatic.com requests with .woff2 files bundled at shared/playground-design-system/fonts/. Why: - No data leaked to Google about end-user IPs and User-Agents. - GDPR-safe for Norwegian public-sector deployments. - Works offline / behind air-gapped firewalls. - Forkers downloading the marketplace get a complete bundle. All three families are SIL Open Font License 1.1 — license texts included alongside the woff2 files. Source Serif 4 woff2 generated locally from the upstream OTF release using fonttools ttLib.woff2 compress; Inter and JetBrains Mono are unmodified upstream webfont releases. Total bundle: 9 woff2 files, ~940 KB. New fonts.css declares all @font-face rules with font-display: swap. All 6 example HTMLs and 12 new component demos load it via a single relative path. Verified -------- - Privacy grep returns empty across plugins/ and shared/ - Google Fonts grep returns empty across shared/*.html - Smoke test via python -m http.server: HTML + 7 stylesheets + Inter-Regular.woff2 all return 200 Doc updates ----------- - shared/playground-design-system/README.md: file tree updated, Quick start snippet shows fonts.css link, "Self-hosted fonts" section added - shared/playground-design-system/fonts/LICENSES.md: combined attribution - README.md (root): Tier 3 wave 1+2 component list, Privacy-first bullet - CLAUDE.md (root): tree entry expanded for new components + fonts Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
86 lines
4.4 KiB
HTML
86 lines
4.4 KiB
HTML
<!doctype html>
|
|
<html lang="nb">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Classify & Transform · Tier 3 supp</title>
|
|
<link rel="stylesheet" href="../../playground-design-system/tokens.css" />
|
|
<link rel="stylesheet" href="../../playground-design-system/base.css" />
|
|
<link rel="stylesheet" href="../../playground-design-system/components.css" />
|
|
<link rel="stylesheet" href="../../playground-design-system/components-tier2.css" />
|
|
<link rel="stylesheet" href="../../playground-design-system/components-tier3-supplement.css" />
|
|
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
|
</head>
|
|
<body>
|
|
<header class="app-header">
|
|
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
|
<span class="app-header__breadcrumb">/ Komponenter / Classify-and-Transform</span>
|
|
</header>
|
|
|
|
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
|
<div style="margin-bottom: var(--space-6);">
|
|
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold);">OKR · /okr:skriv strategi-til-OKR</span>
|
|
<h1 style="margin: 4px 0 6px;">5-bucket-sorter</h1>
|
|
<p class="text-secondary" style="max-width: 65ch;">Lim inn tildelingsbrev øverst — hver krav-setning klassifiseres etter OKR-egnethet (lav, medium, høy).</p>
|
|
</div>
|
|
|
|
<div class="cls-sorter">
|
|
<div class="cls-input">
|
|
<textarea id="inputText">Bærum kommune skal redusere ventetid på saksbehandling med 30 % innen utgangen av 2026. Innbyggerportalen skal være tilgjengelig 99,5 % av tiden. Andelen selvbetjente saker skal øke fra 42 % til 65 %. Vi skal modernisere innbyggerportalen med AI-assistert chat. Det skal leveres kvartalsrapport til kommunestyret om digitaliseringsfremgang. Copilot for saksbehandlere skal piloteres før Q3.</textarea>
|
|
<div style="margin-top: var(--space-3); display: flex; gap: 8px;">
|
|
<button class="btn btn--primary btn--sm" onclick="alert('Mock: 6 setninger klassifisert.')">Klassifiser</button>
|
|
<span class="text-tertiary" style="font-size: 12px; align-self: center;">6 setninger funnet</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="cls-buckets" id="buckets"></div>
|
|
</div>
|
|
</main>
|
|
|
|
<script>
|
|
const buckets = {
|
|
drift: { name: "Driftskrav", egnethet: "lav",
|
|
items: [{text: "Sikre at innbyggerportalen er tilgjengelig 99,5 % av tiden", action: "→ KPI"}],
|
|
cta: "Generer KPI-katalog" },
|
|
resultat: { name: "Resultatmål", egnethet: "hoy",
|
|
items: [
|
|
{text: "Redusere ventetid på saksbehandling med 30 %", action: "→ KR-kandidat"},
|
|
{text: "Øke andel selvbetjente saker fra 42 % til 65 %", action: "→ KR-kandidat"},
|
|
],
|
|
cta: "Generer KR-utkast" },
|
|
satsing: { name: "Strategiske satsinger", egnethet: "hoy",
|
|
items: [{text: "Modernisere innbyggerportalen med AI-assistert chat", action: "→ Objective-kandidat"}],
|
|
cta: "Generer Objective-utkast" },
|
|
rapportering: { name: "Rapportering", egnethet: "lav",
|
|
items: [{text: "Kvartalsrapport til kommunestyret om digitaliseringsfremgang", action: "→ Rapporteringsrutine"}],
|
|
cta: "Skriv rapportmal" },
|
|
oppdrag: { name: "Særskilte oppdrag", egnethet: "medium",
|
|
items: [{text: "Pilotere Copilot for saksbehandlere før Q3", action: "→ Case by case"}],
|
|
cta: "Vurder OKR vs prosjekt" },
|
|
};
|
|
|
|
function egnethetLabel(e) { return e === 'hoy' ? 'Høy egnethet' : e === 'medium' ? 'Medium egnethet' : 'Lav egnethet'; }
|
|
|
|
function render() {
|
|
document.getElementById('buckets').innerHTML = Object.entries(buckets).map(([key, b]) => `
|
|
<div class="cls-bucket" data-egnethet="${b.egnethet}" data-key="${key}">
|
|
<div class="cls-bucket__head">
|
|
<span class="cls-bucket__title">${b.name}</span>
|
|
<span class="cls-bucket__egnethet">${egnethetLabel(b.egnethet)}</span>
|
|
</div>
|
|
${b.items.length ? b.items.map(i => `
|
|
<div class="cls-item">
|
|
<span>${i.text}</span>
|
|
<span class="cls-item__action">${i.action}</span>
|
|
</div>
|
|
`).join('') : `<div class="cls-bucket__empty">Ingen setninger her.</div>`}
|
|
<div class="cls-bucket__action">
|
|
<button class="btn btn--secondary btn--sm" style="width:100%;" onclick="alert('Mock: ${b.cta}')">${b.cta}</button>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
render();
|
|
</script>
|
|
</body>
|
|
</html>
|