Use the theme's cards, buttons, inputs and filter buttons everywhere
Build & Deploy / deploy (push) Successful in 2m48s

Every hand-written card, button, input, the profiler's filter buttons, the
upload area, the chat bubbles, the nav links and the shortcut key now use
Weircon-wind components. The theme is imported into Tailwind's components
layer so utilities on the same element still apply.

Claude-Session: https://claude.ai/code/session_012LCTmU2ewo8tnM1dByYAoG
This commit is contained in:
Asger Geel Weirsøe
2026-10-29 18:52:00 +01:00
parent a352b32fac
commit 490835e6ae
21 changed files with 77 additions and 96 deletions
+3 -4
View File
@@ -19,8 +19,8 @@ const t = lang === 'en' ? {
<form id="chat-form" class="mt-6 flex gap-3" data-thinking={t.thinking} data-offline={t.offline} data-unreachable={t.unreachable}> <form id="chat-form" class="mt-6 flex gap-3" data-thinking={t.thinking} data-offline={t.offline} data-unreachable={t.unreachable}>
<input id="chat-input" type="text" required maxlength="500" autocomplete="off" <input id="chat-input" type="text" required maxlength="500" autocomplete="off"
placeholder={t.placeholder} placeholder={t.placeholder}
class="flex-1 rounded-xl border border-border bg-surface/60 px-4 py-2.5 outline-none focus:border-accent" /> class="flex-1 wt-input wt-input--lg" />
<button type="submit" class="rounded-xl bg-accent px-5 py-2.5 font-medium text-bg transition-transform hover:-translate-y-0.5">Send</button> <button type="submit" class="wt-btn wt-btn--primary wt-btn--lg">Send</button>
</form> </form>
<p class="mt-3 text-xs text-muted/80">{t.disclaimer}</p> <p class="mt-3 text-xs text-muted/80">{t.disclaimer}</p>
@@ -49,8 +49,7 @@ const t = lang === 'en' ? {
function bubble(role, text) { function bubble(role, text) {
var log = document.getElementById('chat-log'); var log = document.getElementById('chat-log');
var d = document.createElement('div'); var d = document.createElement('div');
d.className = 'rounded-2xl border border-border p-4 text-sm whitespace-pre-wrap ' + d.className = 'wt-card text-sm whitespace-pre-wrap ' + (role === 'user' ? 'wt-card--alt ml-8' : 'mr-8');
(role === 'user' ? 'bg-surface-2 ml-8' : 'bg-surface/60 mr-8');
if (role === 'user') d.textContent = text; else d.innerHTML = linkify(text); if (role === 'user') d.textContent = text; else d.innerHTML = linkify(text);
log.appendChild(d); log.appendChild(d);
d.scrollIntoView({ behavior: 'smooth', block: 'end' }); d.scrollIntoView({ behavior: 'smooth', block: 'end' });
+2 -2
View File
@@ -12,14 +12,14 @@ const en = lang === 'en';
aria-live="polite" aria-live="polite"
aria-label={en ? 'Cookie notice' : 'Cookie-besked'} aria-label={en ? 'Cookie notice' : 'Cookie-besked'}
> >
<div class="mx-auto flex max-w-3xl flex-col gap-3 rounded-2xl border border-border bg-surface/95 p-4 shadow-xl backdrop-blur sm:flex-row sm:items-center sm:justify-between"> <div class="mx-auto flex max-w-3xl flex-col gap-3 wt-card wt-card--raised sm:flex-row sm:items-center sm:justify-between">
<p class="text-sm text-muted"> <p class="text-sm text-muted">
{en ? 'This site uses cookies to improve your experience and keep anonymous visitor statistics. By using the site you accept this.' : 'Denne side bruger cookies til at forbedre din oplevelse og lave anonym statistik over besøg. Ved at bruge siden accepterer du det.'} {en ? 'This site uses cookies to improve your experience and keep anonymous visitor statistics. By using the site you accept this.' : 'Denne side bruger cookies til at forbedre din oplevelse og lave anonym statistik over besøg. Ved at bruge siden accepterer du det.'}
<a href="/cookies" class="text-accent underline">{en ? 'Read more (Danish)' : 'Læs mere'}</a>. <a href="/cookies" class="text-accent underline">{en ? 'Read more (Danish)' : 'Læs mere'}</a>.
</p> </p>
<button <button
id="cookie-ok" id="cookie-ok"
class="shrink-0 self-start rounded-xl bg-accent px-5 py-2 text-sm font-medium text-bg transition-transform hover:-translate-y-0.5 sm:self-auto" class="shrink-0 self-start wt-btn wt-btn--primary sm:self-auto"
>OK</button> >OK</button>
</div> </div>
</div> </div>
+2 -4
View File
@@ -17,10 +17,8 @@ const isActive = (href: string) => (href === '/' || href === '/en' ? path === hr
<li> <li>
<a <a
href={item.href} href={item.href}
class:list={[ class="wt-nav-link"
'rounded-lg px-3 py-1.5 transition-colors hover:text-text', aria-current={isActive(item.href) ? 'page' : undefined}
isActive(item.href) ? 'text-text bg-surface-2' : 'text-muted',
]}
>{item.label}</a> >{item.label}</a>
</li> </li>
))} ))}
+1 -1
View File
@@ -3,7 +3,7 @@ interface Props { href: string; title: string; date: Date; description?: string;
const { href, title, date, description, tags = [] } = Astro.props; const { href, title, date, description, tags = [] } = Astro.props;
const d = date.toLocaleDateString('da-DK', { year: 'numeric', month: 'long', day: 'numeric' }); const d = date.toLocaleDateString('da-DK', { year: 'numeric', month: 'long', day: 'numeric' });
--- ---
<article class="group rounded-2xl border border-border bg-surface/60 p-5 transition-colors hover:border-accent/50"> <article class="group wt-card wt-card--hover">
<a href={href} class="block"> <a href={href} class="block">
<div class="text-xs text-muted">{d}</div> <div class="text-xs text-muted">{d}</div>
<h3 class="mt-1 text-lg font-semibold tracking-tight group-hover:text-accent">{title}</h3> <h3 class="mt-1 text-lg font-semibold tracking-tight group-hover:text-accent">{title}</h3>
+1 -1
View File
@@ -5,6 +5,6 @@ import Base from '../layouts/Base.astro';
<div class="py-20 text-center"> <div class="py-20 text-center">
<h1 class="text-6xl font-bold tracking-tight">404</h1> <h1 class="text-6xl font-bold tracking-tight">404</h1>
<p class="mt-4 text-muted">Siden findes ikke.</p> <p class="mt-4 text-muted">Siden findes ikke.</p>
<a href="/" class="mt-8 inline-block rounded-xl bg-accent px-5 py-2.5 font-medium text-bg">Til forsiden</a> <a href="/" class="mt-8 wt-btn wt-btn--primary wt-btn--lg">Til forsiden</a>
</div> </div>
</Base> </Base>
+1 -1
View File
@@ -22,7 +22,7 @@ const stack = [
ingen tredjeparts-fonts, ingen eksterne trackere.. bare en statisk side der gør hvad den får besked på. ingen tredjeparts-fonts, ingen eksterne trackere.. bare en statisk side der gør hvad den får besked på.
</p> </p>
<div class="mt-8 overflow-hidden rounded-2xl border border-border"> <div class="mt-8 wt-card wt-card--flush">
<table class="w-full text-sm"> <table class="w-full text-sm">
<tbody> <tbody>
{stack.map((row) => ( {stack.map((row) => (
+2 -2
View File
@@ -11,7 +11,7 @@ import Base from '../layouts/Base.astro';
<h2 class="mt-10 text-2xl font-bold tracking-tight">Hvad bruger vi dem til?</h2> <h2 class="mt-10 text-2xl font-bold tracking-tight">Hvad bruger vi dem til?</h2>
<div class="mt-5 grid gap-4"> <div class="mt-5 grid gap-4">
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<h3 class="font-semibold tracking-tight">Statistik &amp; analyse</h3> <h3 class="font-semibold tracking-tight">Statistik &amp; analyse</h3>
<p class="mt-2 text-sm text-muted"> <p class="mt-2 text-sm text-muted">
Jeg bruger <strong class="text-text">Matomo</strong> til at se hvor mange der besøger siden, Jeg bruger <strong class="text-text">Matomo</strong> til at se hvor mange der besøger siden,
@@ -25,7 +25,7 @@ import Base from '../layouts/Base.astro';
</ul> </ul>
</div> </div>
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<h3 class="font-semibold tracking-tight">Funktionelt</h3> <h3 class="font-semibold tracking-tight">Funktionelt</h3>
<p class="mt-2 text-sm text-muted"> <p class="mt-2 text-sm text-muted">
Husker dine valg på siden. Det er ikke sporing, og det forlader aldrig din browser. Husker dine valg på siden. Det er ikke sporing, og det forlader aldrig din browser.
+7 -7
View File
@@ -126,7 +126,7 @@ const sprog = ['Dansk (modersmål)', 'Engelsk (flydende i tale og skrift)'];
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Erhvervserfaring</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Erhvervserfaring</h2>
<div class="mt-4 space-y-4"> <div class="mt-4 space-y-4">
{erhverv.map((e) => ( {erhverv.map((e) => (
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<h3 class="font-semibold">{e.org} <span class="font-normal text-muted">· {e.sted}</span></h3> <h3 class="font-semibold">{e.org} <span class="font-normal text-muted">· {e.sted}</span></h3>
<div class="mt-3 space-y-3"> <div class="mt-3 space-y-3">
{e.roller.map((r) => ( {e.roller.map((r) => (
@@ -150,7 +150,7 @@ const sprog = ['Dansk (modersmål)', 'Engelsk (flydende i tale og skrift)'];
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Uddannelse</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Uddannelse</h2>
<div class="mt-4 space-y-4"> <div class="mt-4 space-y-4">
{uddannelse.map((u) => ( {uddannelse.map((u) => (
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<div class="flex flex-wrap items-baseline justify-between gap-2"> <div class="flex flex-wrap items-baseline justify-between gap-2">
<h3 class="font-semibold">{u.hvad}</h3><span class="text-xs text-muted">{u.naar}</span> <h3 class="font-semibold">{u.hvad}</h3><span class="text-xs text-muted">{u.naar}</span>
</div> </div>
@@ -165,7 +165,7 @@ const sprog = ['Dansk (modersmål)', 'Engelsk (flydende i tale og skrift)'];
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Licenser</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Licenser</h2>
<div class="mt-4 space-y-4"> <div class="mt-4 space-y-4">
{licenser.map((l) => ( {licenser.map((l) => (
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<div class="flex flex-wrap items-baseline justify-between gap-2"> <div class="flex flex-wrap items-baseline justify-between gap-2">
<h3 class="font-semibold">{l.hvad}</h3><span class="text-xs text-muted">{l.naar}</span> <h3 class="font-semibold">{l.hvad}</h3><span class="text-xs text-muted">{l.naar}</span>
</div> </div>
@@ -178,7 +178,7 @@ const sprog = ['Dansk (modersmål)', 'Engelsk (flydende i tale og skrift)'];
<section class="mt-10"> <section class="mt-10">
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Publikationer</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Publikationer</h2>
<div class="mt-4 rounded-2xl border border-border bg-surface/60 p-5"> <div class="mt-4 wt-card">
<a href="https://arxiv.org/abs/2310.00999" target="_blank" rel="noopener" class="font-medium hover:text-accent"> <a href="https://arxiv.org/abs/2310.00999" target="_blank" rel="noopener" class="font-medium hover:text-accent">
CGAAL: Distributed On-The-Fly ATL Model Checker with Heuristics CGAAL: Distributed On-The-Fly ATL Model Checker with Heuristics
</a> </a>
@@ -193,7 +193,7 @@ const sprog = ['Dansk (modersmål)', 'Engelsk (flydende i tale og skrift)'];
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Frivilligt arbejde</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Frivilligt arbejde</h2>
<div class="mt-4 space-y-4"> <div class="mt-4 space-y-4">
{frivilligt.map((f) => ( {frivilligt.map((f) => (
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<div class="flex flex-wrap items-baseline justify-between gap-2"> <div class="flex flex-wrap items-baseline justify-between gap-2">
<h3 class="font-semibold">{f.hvad}</h3><span class="text-xs text-muted">{f.naar}</span> <h3 class="font-semibold">{f.hvad}</h3><span class="text-xs text-muted">{f.naar}</span>
</div> </div>
@@ -217,7 +217,7 @@ const sprog = ['Dansk (modersmål)', 'Engelsk (flydende i tale og skrift)'];
<div> <div>
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Sprog</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Sprog</h2>
<ul class="mt-4 space-y-2 text-sm"> <ul class="mt-4 space-y-2 text-sm">
{sprog.map((s) => <li class="rounded-xl border border-border bg-surface/60 px-3 py-2">{s}</li>)} {sprog.map((s) => <li class="wt-card wt-card--compact">{s}</li>)}
</ul> </ul>
<h2 class="mt-8 text-sm font-semibold uppercase tracking-widest text-accent">Interesser</h2> <h2 class="mt-8 text-sm font-semibold uppercase tracking-widest text-accent">Interesser</h2>
<p class="mt-4 text-sm text-muted"> <p class="mt-4 text-sm text-muted">
@@ -236,7 +236,7 @@ const sprog = ['Dansk (modersmål)', 'Engelsk (flydende i tale og skrift)'];
<section class="mt-10"> <section class="mt-10">
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Natur og jagt</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Natur og jagt</h2>
<div class="mt-4 rounded-2xl border border-border bg-surface/60 p-5"> <div class="mt-4 wt-card">
<p class="text-muted"> <p class="text-muted">
Jeg har jagttegn, men jagten er mest anledningen. Det jeg tager ud efter, er at stå op Jeg har jagttegn, men jagten er mest anledningen. Det jeg tager ud efter, er at stå op
længe før resten af landet og træde ud i den stilhed, der kun findes tidligt om morgenen, længe før resten af landet og træde ud i den stilhed, der kun findes tidligt om morgenen,
+5 -5
View File
@@ -98,7 +98,7 @@ const skills = [
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Experience</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Experience</h2>
<div class="mt-4 space-y-4"> <div class="mt-4 space-y-4">
{work.map((e) => ( {work.map((e) => (
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<h3 class="font-semibold">{e.org} <span class="font-normal text-muted">· {e.place}</span></h3> <h3 class="font-semibold">{e.org} <span class="font-normal text-muted">· {e.place}</span></h3>
<div class="mt-3 space-y-3"> <div class="mt-3 space-y-3">
{e.roles.map((r) => ( {e.roles.map((r) => (
@@ -122,7 +122,7 @@ const skills = [
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Education</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Education</h2>
<div class="mt-4 space-y-4"> <div class="mt-4 space-y-4">
{education.map((u) => ( {education.map((u) => (
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<div class="flex flex-wrap items-baseline justify-between gap-2"> <div class="flex flex-wrap items-baseline justify-between gap-2">
<h3 class="font-semibold">{u.what}</h3><span class="text-xs text-muted">{u.when}</span> <h3 class="font-semibold">{u.what}</h3><span class="text-xs text-muted">{u.when}</span>
</div> </div>
@@ -135,7 +135,7 @@ const skills = [
<section class="mt-10"> <section class="mt-10">
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Publication</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Publication</h2>
<div class="mt-4 rounded-2xl border border-border bg-surface/60 p-5"> <div class="mt-4 wt-card">
<a href="https://arxiv.org/abs/2310.00999" target="_blank" rel="noopener" class="font-medium hover:text-accent"> <a href="https://arxiv.org/abs/2310.00999" target="_blank" rel="noopener" class="font-medium hover:text-accent">
CGAAL: Distributed On-The-Fly ATL Model Checker with Heuristics CGAAL: Distributed On-The-Fly ATL Model Checker with Heuristics
</a> </a>
@@ -164,8 +164,8 @@ const skills = [
<div> <div>
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Languages</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Languages</h2>
<ul class="mt-4 space-y-2 text-sm"> <ul class="mt-4 space-y-2 text-sm">
<li class="rounded-xl border border-border bg-surface/60 px-3 py-2">Danish (native)</li> <li class="wt-card wt-card--compact">Danish (native)</li>
<li class="rounded-xl border border-border bg-surface/60 px-3 py-2">English (fluent, spoken and written)</li> <li class="wt-card wt-card--compact">English (fluent, spoken and written)</li>
</ul> </ul>
</div> </div>
<div> <div>
+7 -7
View File
@@ -43,9 +43,9 @@ const faqs = [
the air as a radio amateur (OZ0AGW). the air as a radio amateur (OZ0AGW).
</p> </p>
<div class="mt-7 flex flex-wrap gap-3"> <div class="mt-7 flex flex-wrap gap-3">
<a href="/en/cv" class="rounded-xl bg-accent px-5 py-2.5 font-medium text-bg transition-transform hover:-translate-y-0.5">See my CV</a> <a href="/en/cv" class="wt-btn wt-btn--primary wt-btn--lg">See my CV</a>
<a href="/en/chat" class="rounded-xl border border-border px-5 py-2.5 font-medium transition-colors hover:border-accent">Ask my CV</a> <a href="/en/chat" class="wt-btn wt-btn--lg">Ask my CV</a>
<a href="/en/projects" class="rounded-xl border border-border px-5 py-2.5 font-medium transition-colors hover:border-accent">Projects</a> <a href="/en/projects" class="wt-btn wt-btn--lg">Projects</a>
</div> </div>
</div> </div>
<Image <Image
@@ -60,7 +60,7 @@ const faqs = [
<section class="mt-14 grid gap-4 sm:grid-cols-3"> <section class="mt-14 grid gap-4 sm:grid-cols-3">
{highlights.map((h) => ( {highlights.map((h) => (
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<h2 class="font-semibold tracking-tight">{h.title}</h2> <h2 class="font-semibold tracking-tight">{h.title}</h2>
<p class="mt-2 text-sm text-muted">{h.body}</p> <p class="mt-2 text-sm text-muted">{h.body}</p>
</div> </div>
@@ -76,20 +76,20 @@ const faqs = [
{ href: '/ubl', title: 'UBL check (Danish)', desc: 'Drop in an e-invoice and get its profile, syntax and EN 16931 status decoded. It all runs in the browser, the file never leaves your machine.' }, { href: '/ubl', title: 'UBL check (Danish)', desc: 'Drop in an e-invoice and get its profile, syntax and EN 16931 status decoded. It all runs in the browser, the file never leaves your machine.' },
{ href: '/en/projects', title: 'Projects', desc: 'Tools I maintain and publish on the AUR, Homebrew and Scoop.' }, { href: '/en/projects', title: 'Projects', desc: 'Tools I maintain and publish on the AUR, Homebrew and Scoop.' },
].map((c) => ( ].map((c) => (
<a href={c.href} class="group rounded-2xl border border-border bg-surface/60 p-5 transition-colors hover:border-accent"> <a href={c.href} class="group wt-card wt-card--hover">
<h3 class="font-semibold tracking-tight group-hover:text-accent">{c.title} →</h3> <h3 class="font-semibold tracking-tight group-hover:text-accent">{c.title} →</h3>
<p class="mt-2 text-sm text-muted">{c.desc}</p> <p class="mt-2 text-sm text-muted">{c.desc}</p>
</a> </a>
))} ))}
</div> </div>
<p class="mt-3 text-xs text-muted/80">Pro tip: press <kbd class="rounded border border-border bg-surface-2 px-1.5 py-0.5 font-mono text-[0.7rem]">Ctrl/⌘ K</kbd> to jump anywhere, or run <code class="rounded bg-surface-2 px-1.5 py-0.5">curl asger.weirsøe.dk</code> in a terminal.</p> <p class="mt-3 text-xs text-muted/80">Pro tip: press <kbd class="wt-kbd">Ctrl/⌘ K</kbd> to jump anywhere, or run <code class="rounded bg-surface-2 px-1.5 py-0.5">curl asger.weirsøe.dk</code> in a terminal.</p>
</section> </section>
<section class="mt-16"> <section class="mt-16">
<h2 class="text-2xl font-bold tracking-tight">Frequently asked questions</h2> <h2 class="text-2xl font-bold tracking-tight">Frequently asked questions</h2>
<div class="mt-5 grid gap-3"> <div class="mt-5 grid gap-3">
{faqs.map((f) => ( {faqs.map((f) => (
<details class="group rounded-2xl border border-border bg-surface/60 p-5"> <details class="group wt-card">
<summary class="cursor-pointer list-none font-semibold tracking-tight marker:hidden">{f.q}</summary> <summary class="cursor-pointer list-none font-semibold tracking-tight marker:hidden">{f.q}</summary>
<p class="mt-3 text-sm text-muted">{f.a}</p> <p class="mt-3 text-sm text-muted">{f.a}</p>
</details> </details>
+1 -1
View File
@@ -18,7 +18,7 @@ const ld = collectionPage({
<div class="mt-8 grid gap-4 sm:grid-cols-2"> <div class="mt-8 grid gap-4 sm:grid-cols-2">
{sider.map((p) => ( {sider.map((p) => (
<a href={`/en/projects/${p.id.replace(/^en\//, '')}`} <a href={`/en/projects/${p.id.replace(/^en\//, '')}`}
class="group rounded-2xl border border-border bg-surface/60 p-5 transition-colors hover:border-accent/50"> class="group wt-card wt-card--hover">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<h3 class="font-semibold tracking-tight group-hover:text-accent">{p.data.title}</h3> <h3 class="font-semibold tracking-tight group-hover:text-accent">{p.data.title}</h3>
{p.data.aur.length > 0 && <span class="text-xs text-muted">AUR</span>} {p.data.aur.length > 0 && <span class="text-xs text-muted">AUR</span>}
+7 -7
View File
@@ -56,9 +56,9 @@ const jsonLd = [profilePage, faqPage(faqs)];
Proxmox-homelab, roder med AI-projekter og går på luften som radioamatør (OZ0AGW). Proxmox-homelab, roder med AI-projekter og går på luften som radioamatør (OZ0AGW).
</p> </p>
<div class="mt-7 flex flex-wrap gap-3"> <div class="mt-7 flex flex-wrap gap-3">
<a href="/cv" class="rounded-xl bg-accent px-5 py-2.5 font-medium text-bg transition-transform hover:-translate-y-0.5">Se mit CV</a> <a href="/cv" class="wt-btn wt-btn--primary wt-btn--lg">Se mit CV</a>
<a href="/projekter" class="rounded-xl border border-border px-5 py-2.5 font-medium transition-colors hover:border-accent">Projekter</a> <a href="/projekter" class="wt-btn wt-btn--lg">Projekter</a>
<a href="/blog" class="rounded-xl border border-border px-5 py-2.5 font-medium transition-colors hover:border-accent">Blog</a> <a href="/blog" class="wt-btn wt-btn--lg">Blog</a>
</div> </div>
</div> </div>
<Image <Image
@@ -73,7 +73,7 @@ const jsonLd = [profilePage, faqPage(faqs)];
<section class="mt-14 grid gap-4 sm:grid-cols-3"> <section class="mt-14 grid gap-4 sm:grid-cols-3">
{highlights.map((h) => ( {highlights.map((h) => (
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<h2 class="font-semibold tracking-tight">{h.title}</h2> <h2 class="font-semibold tracking-tight">{h.title}</h2>
<p class="mt-2 text-sm text-muted">{h.body}</p> <p class="mt-2 text-sm text-muted">{h.body}</p>
</div> </div>
@@ -91,20 +91,20 @@ const jsonLd = [profilePage, faqPage(faqs)];
{ href: '/profiler', title: 'Profil-opslag', desc: 'Søgbart opslag over Nemhandel OIOUBL- og Peppol BIS/PINT-profiler: id\'er, dokumenter og typisk brug.' }, { href: '/profiler', title: 'Profil-opslag', desc: 'Søgbart opslag over Nemhandel OIOUBL- og Peppol BIS/PINT-profiler: id\'er, dokumenter og typisk brug.' },
{ href: '/ubl', title: 'UBL-tjek', desc: 'Træk en faktura ind og få profil, syntaks og EN 16931-status afkodet. Alt sker i browseren, filen forlader aldrig din maskine.' }, { href: '/ubl', title: 'UBL-tjek', desc: 'Træk en faktura ind og få profil, syntaks og EN 16931-status afkodet. Alt sker i browseren, filen forlader aldrig din maskine.' },
].map((c) => ( ].map((c) => (
<a href={c.href} class="group rounded-2xl border border-border bg-surface/60 p-5 transition-colors hover:border-accent"> <a href={c.href} class="group wt-card wt-card--hover">
<h3 class="font-semibold tracking-tight group-hover:text-accent">{c.title} →</h3> <h3 class="font-semibold tracking-tight group-hover:text-accent">{c.title} →</h3>
<p class="mt-2 text-sm text-muted">{c.desc}</p> <p class="mt-2 text-sm text-muted">{c.desc}</p>
</a> </a>
))} ))}
</div> </div>
<p class="mt-3 text-xs text-muted/80">Pro-tip: tryk <kbd class="rounded border border-border bg-surface-2 px-1.5 py-0.5 font-mono text-[0.7rem]">Ctrl/⌘ K</kbd> og hop direkte til alt, eller <code class="rounded bg-surface-2 px-1.5 py-0.5">curl asger.weirsøe.dk</code> i en terminal.</p> <p class="mt-3 text-xs text-muted/80">Pro-tip: tryk <kbd class="wt-kbd">Ctrl/⌘ K</kbd> og hop direkte til alt, eller <code class="rounded bg-surface-2 px-1.5 py-0.5">curl asger.weirsøe.dk</code> i en terminal.</p>
</section> </section>
<section class="mt-16"> <section class="mt-16">
<h2 class="text-2xl font-bold tracking-tight">Ofte stillede spørgsmål</h2> <h2 class="text-2xl font-bold tracking-tight">Ofte stillede spørgsmål</h2>
<div class="mt-5 grid gap-3"> <div class="mt-5 grid gap-3">
{faqs.map((f) => ( {faqs.map((f) => (
<details class="group rounded-2xl border border-border bg-surface/60 p-5"> <details class="group wt-card">
<summary class="cursor-pointer list-none font-semibold tracking-tight marker:hidden"> <summary class="cursor-pointer list-none font-semibold tracking-tight marker:hidden">
{f.q} {f.q}
</summary> </summary>
+11 -12
View File
@@ -12,15 +12,15 @@ import Base from '../layouts/Base.astro';
<form id="pep-form" class="mt-8 flex gap-3"> <form id="pep-form" class="mt-8 flex gap-3">
<input id="pep-cvr" type="text" inputmode="numeric" pattern="[0-9]{8}" maxlength="8" required <input id="pep-cvr" type="text" inputmode="numeric" pattern="[0-9]{8}" maxlength="8" required
placeholder="CVR (8 cifre)" autocomplete="off" placeholder="CVR (8 cifre)" autocomplete="off"
class="w-44 rounded-xl border border-border bg-surface/60 px-4 py-2.5 outline-none focus:border-accent" /> class="w-44 wt-input wt-input--lg" />
<button type="submit" class="rounded-xl bg-accent px-5 py-2.5 font-medium text-bg transition-transform hover:-translate-y-0.5">Slå op</button> <button type="submit" class="wt-btn wt-btn--primary wt-btn--lg">Slå op</button>
</form> </form>
<div id="pep-result" class="mt-8" hidden> <div id="pep-result" class="mt-8" hidden>
<div class="rounded-2xl border border-border bg-surface/60 p-5"> <div class="wt-card">
<div class="flex flex-wrap items-baseline justify-between gap-2"> <div class="flex flex-wrap items-baseline justify-between gap-2">
<h2 id="pep-name" class="text-xl font-semibold tracking-tight"></h2> <h2 id="pep-name" class="text-xl font-semibold tracking-tight"></h2>
<span id="pep-badge" class="rounded-full px-3 py-1 text-sm font-medium"></span> <span id="pep-badge" class="wt-tag"></span>
</div> </div>
<p id="pep-cvr-line" class="mt-1 text-sm text-muted"></p> <p id="pep-cvr-line" class="mt-1 text-sm text-muted"></p>
<div id="pep-caps" class="mt-4"></div> <div id="pep-caps" class="mt-4"></div>
@@ -46,29 +46,29 @@ import Base from '../layouts/Base.astro';
}; };
async function loadPeppol(cvr) { async function loadPeppol(cvr) {
var box = document.getElementById('peppol-net'); box.hidden = false; var box = document.getElementById('peppol-net'); box.hidden = false;
box.innerHTML = '<div class="rounded-2xl border border-border bg-surface/60 p-5"><p class="text-sm text-muted">Slår op i Peppol-netværket…</p></div>'; box.innerHTML = '<div class="wt-card"><p class="text-sm text-muted">Slår op i Peppol-netværket…</p></div>';
try { try {
var r = await fetch('/api/peppol/smp/' + encodeURIComponent(cvr)); var r = await fetch('/api/peppol/smp/' + encodeURIComponent(cvr));
var d = await r.json(); var d = await r.json();
if (!r.ok) { box.innerHTML = '<div class="rounded-2xl border border-border bg-surface/60 p-5"><p class="text-sm text-muted">Peppol-opslag ikke tilgængeligt lige nu.</p></div>'; return; } if (!r.ok) { box.innerHTML = '<div class="wt-card"><p class="text-sm text-muted">Peppol-opslag ikke tilgængeligt lige nu.</p></div>'; return; }
if (!d.on_peppol) { if (!d.on_peppol) {
box.innerHTML = '<div class="rounded-2xl border border-border bg-surface/60 p-5"><div class="flex items-baseline justify-between gap-2"><h2 class="text-xl font-semibold tracking-tight">Peppol-netværk</h2><span class="wt-tag wt-muted">Ikke fundet</span></div><p class="mt-2 text-sm text-muted">Virksomheden blev ikke fundet i Peppol Directory via CVR-opslag (kan stadig være på Peppol under et andet identifikator-scheme).</p></div>'; box.innerHTML = '<div class="wt-card"><div class="flex items-baseline justify-between gap-2"><h2 class="text-xl font-semibold tracking-tight">Peppol-netværk</h2><span class="wt-tag wt-muted">Ikke fundet</span></div><p class="mt-2 text-sm text-muted">Virksomheden blev ikke fundet i Peppol Directory via CVR-opslag (kan stadig være på Peppol under et andet identifikator-scheme).</p></div>';
return; return;
} }
var docs = (d.doctypes || []).map(function (dt) { var docs = (d.doctypes || []).map(function (dt) {
var label = PROF[dt.customization] || dt.customization; var label = PROF[dt.customization] || dt.customization;
return '<span class="wt-tag">' + esc(dt.document) + ' · ' + esc(label) + '</span>'; return '<span class="wt-tag">' + esc(dt.document) + ' · ' + esc(label) + '</span>';
}).join(''); }).join('');
box.innerHTML = '<div class="rounded-2xl border border-border bg-surface/60 p-5">' + box.innerHTML = '<div class="wt-card">' +
'<div class="flex flex-wrap items-baseline justify-between gap-2"><h2 class="text-xl font-semibold tracking-tight">Peppol-netværk</h2>' + '<div class="flex flex-wrap items-baseline justify-between gap-2"><h2 class="text-xl font-semibold tracking-tight">Peppol-netværk</h2>' +
'<span class="rounded-full bg-accent/15 px-3 py-1 text-sm font-medium text-accent">På Peppol</span></div>' + '<span class="wt-tag wt-tag--accent">På Peppol</span></div>' +
'<p class="mt-1 text-sm text-muted">' + esc(d.name || '') + (d.country ? ' · ' + esc(d.country) : '') + '<p class="mt-1 text-sm text-muted">' + esc(d.name || '') + (d.country ? ' · ' + esc(d.country) : '') +
' · <span class="font-mono text-xs">' + esc(d.participant_id || '') + '</span>' + (d.reg_date ? ' · reg. ' + esc(d.reg_date) : '') + '</p>' + ' · <span class="font-mono text-xs">' + esc(d.participant_id || '') + '</span>' + (d.reg_date ? ' · reg. ' + esc(d.reg_date) : '') + '</p>' +
'<p class="mt-4 text-xs font-semibold uppercase tracking-widest text-accent">Kan modtage</p>' + '<p class="mt-4 text-xs font-semibold uppercase tracking-widest text-accent">Kan modtage</p>' +
'<div class="mt-2 flex flex-wrap gap-2">' + (docs || '<span class="text-sm text-muted">ingen dokumenttyper</span>') + '</div>' + '<div class="mt-2 flex flex-wrap gap-2">' + (docs || '<span class="text-sm text-muted">ingen dokumenttyper</span>') + '</div>' +
'<p class="mt-3 text-xs text-muted/80">Live fra Peppol Directory via egen proxy, intet gemt.</p></div>'; '<p class="mt-3 text-xs text-muted/80">Live fra Peppol Directory via egen proxy, intet gemt.</p></div>';
} catch (_) { } catch (_) {
box.innerHTML = '<div class="rounded-2xl border border-border bg-surface/60 p-5"><p class="text-sm text-muted">Kunne ikke nå Peppol-opslaget.</p></div>'; box.innerHTML = '<div class="wt-card"><p class="text-sm text-muted">Kunne ikke nå Peppol-opslaget.</p></div>';
} }
} }
form.addEventListener('submit', async function (e) { form.addEventListener('submit', async function (e) {
@@ -86,8 +86,7 @@ import Base from '../layouts/Base.astro';
document.getElementById('pep-cvr-line').textContent = 'CVR ' + data.cvr; document.getElementById('pep-cvr-line').textContent = 'CVR ' + data.cvr;
var badge = document.getElementById('pep-badge'); var badge = document.getElementById('pep-badge');
badge.textContent = data.registered ? 'Registreret i NemHandel' : 'Ikke registreret'; badge.textContent = data.registered ? 'Registreret i NemHandel' : 'Ikke registreret';
badge.className = 'rounded-full px-3 py-1 text-sm font-medium ' + badge.className = 'wt-tag ' + (data.registered ? 'wt-tag--accent' : 'wt-muted');
(data.registered ? 'bg-accent/15 text-accent' : 'border border-border text-muted');
var caps = document.getElementById('pep-caps'); var caps = document.getElementById('pep-caps');
if (data.registered && (data.profiles.length || data.networks.length)) { if (data.registered && (data.profiles.length || data.networks.length)) {
caps.innerHTML = caps.innerHTML =
+2 -2
View File
@@ -48,7 +48,7 @@ const updated = today.toLocaleDateString('da-DK', { year: 'numeric', month: 'lon
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Lige nu</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Lige nu</h2>
<ul class="mt-4 space-y-3"> <ul class="mt-4 space-y-3">
{focus.map((f) => ( {focus.map((f) => (
<li class="rounded-2xl border border-border bg-surface/60 p-4 text-sm">{f}</li> <li class="wt-card text-sm">{f}</li>
))} ))}
</ul> </ul>
</section> </section>
@@ -57,7 +57,7 @@ const updated = today.toLocaleDateString('da-DK', { year: 'numeric', month: 'lon
<section class="mt-10"> <section class="mt-10">
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Git-aktivitet</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">Git-aktivitet</h2>
<p class="mt-2 text-sm text-muted">{total} bidrag i mit eget Gitea det seneste år, de seneste {WEEKS} uger:</p> <p class="mt-2 text-sm text-muted">{total} bidrag i mit eget Gitea det seneste år, de seneste {WEEKS} uger:</p>
<div class="mt-4 overflow-x-auto rounded-2xl border border-border bg-surface/60 p-4"> <div class="mt-4 overflow-x-auto wt-card">
<div class="heatmap" role="img" aria-label="Aktivitets-heatmap over git-bidrag"> <div class="heatmap" role="img" aria-label="Aktivitets-heatmap over git-bidrag">
{weeks.map((w) => ( {weeks.map((w) => (
<div class="hm-col"> <div class="hm-col">
+8 -24
View File
@@ -51,22 +51,22 @@ const kilde = (p: (typeof profiles)[number]) => {
placeholder="Søg profil, id, dokument…" placeholder="Søg profil, id, dokument…"
autocomplete="off" autocomplete="off"
aria-label="Søg profiler" aria-label="Søg profiler"
class="w-full rounded-xl border border-border bg-surface/60 py-2.5 pl-9 pr-4 outline-none focus:border-accent" class="w-full wt-input wt-input--lg pl-9"
/> />
</div> </div>
<span id="p-count" class="text-sm text-muted">{profiles.length} profiler</span> <span id="p-count" class="text-sm text-muted">{profiles.length} profiler</span>
</div> </div>
<div class="mt-3 flex flex-wrap gap-2"> <div class="mt-3 flex flex-wrap gap-2">
<button type="button" class="p-chip" data-std="" aria-pressed="true">Alle</button> <button type="button" class="wt-btn wt-btn--ghost wt-btn--sm" data-std="" aria-pressed="true">Alle</button>
{standarder.map((s) => <button type="button" class="p-chip" data-std={s} aria-pressed="false">{s}</button>)} {standarder.map((s) => <button type="button" class="wt-btn wt-btn--ghost wt-btn--sm" data-std={s} aria-pressed="false">{s}</button>)}
</div> </div>
<div class="mt-3"> <div class="mt-3">
<span class="mr-2 text-xs text-muted">Nemhandelsregistrets kategori:</span> <span class="mr-2 text-xs text-muted">Nemhandelsregistrets kategori:</span>
<span class="mt-1 inline-flex flex-wrap gap-2 align-middle"> <span class="mt-1 inline-flex flex-wrap gap-2 align-middle">
<button type="button" class="p-chip" data-kat="" aria-pressed="true">Alle</button> <button type="button" class="wt-btn wt-btn--ghost wt-btn--sm" data-kat="" aria-pressed="true">Alle</button>
{kategorier.map((k) => <button type="button" class="p-chip" data-kat={k} aria-pressed="false">{k}</button>)} {kategorier.map((k) => <button type="button" class="wt-btn wt-btn--ghost wt-btn--sm" data-kat={k} aria-pressed="false">{k}</button>)}
</span> </span>
</div> </div>
@@ -78,7 +78,7 @@ const kilde = (p: (typeof profiles)[number]) => {
data-standard={p.standard} data-standard={p.standard}
data-kategori={p.kategori ?? ''} data-kategori={p.kategori ?? ''}
data-search={searchString(p)} data-search={searchString(p)}
class="rounded-2xl border border-border bg-surface/60 p-5 transition-colors hover:border-accent/50" class="wt-card wt-card--hover"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<span class="wt-tag wt-tag--accent"> <span class="wt-tag wt-tag--accent">
@@ -136,22 +136,6 @@ const kilde = (p: (typeof profiles)[number]) => {
</p> </p>
<style is:inline> <style is:inline>
.p-chip {
border: 1px solid var(--color-border);
color: var(--color-muted);
border-radius: 0.6rem;
padding: 0.35rem 0.8rem;
font-size: 0.85rem;
cursor: pointer;
background: transparent;
transition: color 0.15s, background-color 0.15s, border-color 0.15s;
}
.p-chip:hover { color: var(--color-text); }
.p-chip[aria-pressed="true"] {
background: var(--color-surface-2);
color: var(--color-text);
border-color: color-mix(in srgb, var(--color-accent) 40%, var(--color-border));
}
.copy { transition: color 0.15s; } .copy { transition: color 0.15s; }
.copy:hover { color: var(--color-accent); text-decoration: underline; text-underline-offset: 3px; } .copy:hover { color: var(--color-accent); text-decoration: underline; text-underline-offset: 3px; }
</style> </style>
@@ -160,8 +144,8 @@ const kilde = (p: (typeof profiles)[number]) => {
(function () { (function () {
var cards = [].slice.call(document.querySelectorAll('[data-profile]')); var cards = [].slice.call(document.querySelectorAll('[data-profile]'));
var search = document.getElementById('p-search'); var search = document.getElementById('p-search');
var stdChips = [].slice.call(document.querySelectorAll('.p-chip[data-std]')); var stdChips = [].slice.call(document.querySelectorAll('button[data-std]'));
var katChips = [].slice.call(document.querySelectorAll('.p-chip[data-kat]')); var katChips = [].slice.call(document.querySelectorAll('button[data-kat]'));
var count = document.getElementById('p-count'); var count = document.getElementById('p-count');
var none = document.getElementById('p-none'); var none = document.getElementById('p-none');
var q = '', std = '', kat = ''; var q = '', std = '', kat = '';
+3 -3
View File
@@ -38,14 +38,14 @@ try {
<h1 class="text-4xl font-bold tracking-tight">Projekter</h1> <h1 class="text-4xl font-bold tracking-tight">Projekter</h1>
<p class="mt-3 text-muted">Hentet live fra min <a class="text-accent hover:underline" href={`${SITE.giteaBase}/${SITE.giteaUser}`}>Gitea</a>.</p> <p class="mt-3 text-muted">Hentet live fra min <a class="text-accent hover:underline" href={`${SITE.giteaBase}/${SITE.giteaUser}`}>Gitea</a>.</p>
{error && <p class="mt-8 rounded-xl border border-border bg-surface/60 p-5 text-muted">Kunne ikke hente repositories lige nu.</p>} {error && <p class="mt-8 wt-card text-muted">Kunne ikke hente repositories lige nu.</p>}
<div class="mt-8 grid gap-4 sm:grid-cols-2"> <div class="mt-8 grid gap-4 sm:grid-cols-2">
{repos.map((r) => { {repos.map((r) => {
const side = sider.get(r.name.toLowerCase()); const side = sider.get(r.name.toLowerCase());
return side ? ( return side ? (
<a href={`/projekter/${side.id}`} <a href={`/projekter/${side.id}`}
class="group rounded-2xl border border-border bg-surface/60 p-5 transition-colors hover:border-accent/50"> class="group wt-card wt-card--hover">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<h3 class="font-semibold tracking-tight group-hover:text-accent">{side.data.title}</h3> <h3 class="font-semibold tracking-tight group-hover:text-accent">{side.data.title}</h3>
{side.data.aur.length > 0 && <span class="text-xs text-muted">AUR</span>} {side.data.aur.length > 0 && <span class="text-xs text-muted">AUR</span>}
@@ -55,7 +55,7 @@ try {
</a> </a>
) : ( ) : (
<a href={r.html_url} target="_blank" rel="noopener" <a href={r.html_url} target="_blank" rel="noopener"
class="group rounded-2xl border border-border bg-surface/60 p-5 transition-colors hover:border-accent/50"> class="group wt-card wt-card--hover">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<h3 class="font-semibold tracking-tight group-hover:text-accent">{r.name}</h3> <h3 class="font-semibold tracking-tight group-hover:text-accent">{r.name}</h3>
{r.stars_count > 0 && <span class="text-xs text-muted">★ {r.stars_count}</span>} {r.stars_count > 0 && <span class="text-xs text-muted">★ {r.stars_count}</span>}
+1 -1
View File
@@ -10,7 +10,7 @@ const STATUS_URL = 'https://status.weircon.dk/status/weircon';
Når man drifter ~50 containere selv, er det rart at vide hvornår man har smadret noget. Når man drifter ~50 containere selv, er det rart at vide hvornår man har smadret noget.
</p> </p>
<div class="mt-8 overflow-hidden rounded-2xl border border-border bg-surface/60"> <div class="mt-8 wt-card wt-card--flush">
<iframe src={STATUS_URL} title="Uptime Kuma statusside" loading="lazy" <iframe src={STATUS_URL} title="Uptime Kuma statusside" loading="lazy"
class="h-[70vh] w-full" style="border:0"></iframe> class="h-[70vh] w-full" style="border:0"></iframe>
</div> </div>
+7 -7
View File
@@ -28,7 +28,7 @@ const idx = profiles.map((p) => ({
også på Windows og macOS. også på Windows og macOS.
</p> </p>
<div id="drop" class="mt-8 rounded-2xl border border-dashed border-border bg-surface/40 p-8 text-center transition-colors"> <div id="drop" class="mt-8 wt-dropzone">
<p class="text-muted">Træk en <code class="rounded bg-surface-2 px-1.5 py-0.5">.xml</code>-fil hertil, eller <p class="text-muted">Træk en <code class="rounded bg-surface-2 px-1.5 py-0.5">.xml</code>-fil hertil, eller
<label class="cursor-pointer text-accent hover:underline">vælg en fil<input id="file" type="file" accept=".xml,text/xml,application/xml" class="hidden" /></label>. <label class="cursor-pointer text-accent hover:underline">vælg en fil<input id="file" type="file" accept=".xml,text/xml,application/xml" class="hidden" /></label>.
</p> </p>
@@ -37,8 +37,8 @@ const idx = profiles.map((p) => ({
<details class="mt-3"> <details class="mt-3">
<summary class="cursor-pointer text-sm text-muted">…eller indsæt XML / en identifikator manuelt</summary> <summary class="cursor-pointer text-sm text-muted">…eller indsæt XML / en identifikator manuelt</summary>
<textarea id="paste" rows="6" placeholder="Indsæt UBL-XML, eller bare en CustomizationID/ProfileID…" <textarea id="paste" rows="6" placeholder="Indsæt UBL-XML, eller bare en CustomizationID/ProfileID…"
class="mt-2 w-full rounded-xl border border-border bg-surface/60 px-4 py-3 font-mono text-xs outline-none focus:border-accent"></textarea> class="mt-2 w-full wt-input wt-input--lg font-mono text-xs"></textarea>
<p class="mt-2"><button id="analyze" type="button" class="rounded-xl bg-accent px-4 py-2 text-sm font-medium text-bg">Afkod</button></p> <p class="mt-2"><button id="analyze" type="button" class="wt-btn wt-btn--primary">Afkod</button></p>
</details> </details>
<div id="result" class="mt-6" hidden></div> <div id="result" class="mt-6" hidden></div>
@@ -140,7 +140,7 @@ const idx = profiles.map((p) => ({
(dec.standard ? ' <span class="text-muted text-base font-normal">· ' + esc(dec.standard) + '</span>' : '') + '</h2>'; (dec.standard ? ' <span class="text-muted text-base font-normal">· ' + esc(dec.standard) + '</span>' : '') + '</h2>';
result.innerHTML = result.innerHTML =
'<div class="rounded-2xl border border-border bg-surface/60 p-5">' + head + '<div class="wt-card">' + head +
'<dl class="mt-3 space-y-1 text-xs">' + '<dl class="mt-3 space-y-1 text-xs">' +
row('Dokumenttype', '<span class="font-semibold">' + esc(docType) + '</span> (UBL ' + (esc(ublv) || '2.x') + ')') + row('Dokumenttype', '<span class="font-semibold">' + esc(docType) + '</span> (UBL ' + (esc(ublv) || '2.x') + ')') +
row('ID', esc(id)) + row('ID', esc(id)) +
@@ -157,7 +157,7 @@ const idx = profiles.map((p) => ({
function renderId(s) { function renderId(s) {
var dec = decode(s, s); var dec = decode(s, s);
result.innerHTML = '<div class="rounded-2xl border border-border bg-surface/60 p-5">' + result.innerHTML = '<div class="wt-card">' +
(dec.match ? '<div class="flex flex-wrap items-center gap-2">' + badge(dec.match.standard, 'ok') + (dec.match ? '<div class="flex flex-wrap items-center gap-2">' + badge(dec.match.standard, 'ok') +
'</div><h2 class="mt-2 text-xl font-semibold tracking-tight">' + esc(dec.match.navn) + '</h2>' '</div><h2 class="mt-2 text-xl font-semibold tracking-tight">' + esc(dec.match.navn) + '</h2>'
: '<h2 class="text-xl font-semibold tracking-tight">Identifikator</h2>') + : '<h2 class="text-xl font-semibold tracking-tight">Identifikator</h2>') +
@@ -187,9 +187,9 @@ const idx = profiles.map((p) => ({
function readFile(f) { var r = new FileReader(); r.onload = function () { analyze(String(r.result)); }; r.readAsText(f); } function readFile(f) { var r = new FileReader(); r.onload = function () { analyze(String(r.result)); }; r.readAsText(f); }
fileInput.addEventListener('change', function () { if (fileInput.files[0]) readFile(fileInput.files[0]); }); fileInput.addEventListener('change', function () { if (fileInput.files[0]) readFile(fileInput.files[0]); });
['dragenter', 'dragover'].forEach(function (ev) { drop.addEventListener(ev, function (e) { ['dragenter', 'dragover'].forEach(function (ev) { drop.addEventListener(ev, function (e) {
e.preventDefault(); drop.classList.add('border-accent'); }); }); e.preventDefault(); drop.classList.add('is-over'); }); });
['dragleave', 'drop'].forEach(function (ev) { drop.addEventListener(ev, function (e) { ['dragleave', 'drop'].forEach(function (ev) { drop.addEventListener(ev, function (e) {
e.preventDefault(); drop.classList.remove('border-accent'); }); }); e.preventDefault(); drop.classList.remove('is-over'); }); });
drop.addEventListener('drop', function (e) { var f = e.dataTransfer && e.dataTransfer.files[0]; if (f) readFile(f); }); drop.addEventListener('drop', function (e) { var f = e.dataTransfer && e.dataTransfer.files[0]; if (f) readFile(f); });
document.getElementById('analyze').addEventListener('click', function () { analyze(paste.value); }); document.getElementById('analyze').addEventListener('click', function () { analyze(paste.value); });
paste.addEventListener('keydown', function (e) { if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') analyze(paste.value); }); paste.addEventListener('keydown', function (e) { if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') analyze(paste.value); });
+1 -1
View File
@@ -43,7 +43,7 @@ const sections = [
<h2 class="text-sm font-semibold uppercase tracking-widest text-accent">{s.title}</h2> <h2 class="text-sm font-semibold uppercase tracking-widest text-accent">{s.title}</h2>
<div class="mt-4 space-y-3"> <div class="mt-4 space-y-3">
{s.items.map((it) => ( {s.items.map((it) => (
<div class="rounded-2xl border border-border bg-surface/60 p-4"> <div class="wt-card">
<span class="font-semibold">{it.name}</span> <span class="font-semibold">{it.name}</span>
<p class="mt-1 text-sm text-muted">{it.note}</p> <p class="mt-1 text-sm text-muted">{it.note}</p>
</div> </div>
+4 -3
View File
@@ -5,10 +5,11 @@
adapters/tailwind.css feeds the colour tokens into Tailwind's @theme so the adapters/tailwind.css feeds the colour tokens into Tailwind's @theme so the
bg-surface / text-muted / border-border / text-accent utilities are generated bg-surface / text-muted / border-border / text-accent utilities are generated
from the shared palette; weirsoe-theme.css adds the base glow, the sun⇄moon from the shared palette; weirsoe-theme.css adds the base glow, the sun⇄moon
toggle, .prose and the .wt-* components. Replaces the tokens/toggle/prose/glow toggle, .prose and the .wt-* components, in Tailwind's components layer so a
utility on the same element (pl-9, font-mono) still wins. Replaces the tokens/toggle/prose/glow
that used to live here by hand. */ that used to live here by hand. */
@import "../../vendor/weirsoe-theme/adapters/tailwind.css"; @import "../../vendor/weirsoe-theme/adapters/tailwind.css";
@import "../../vendor/weirsoe-theme/weirsoe-theme.css"; @import "../../vendor/weirsoe-theme/weirsoe-theme.css" layer(components);
/* asger keeps Inter as its UI font (the theme defaults to a system stack). */ /* asger keeps Inter as its UI font (the theme defaults to a system stack). */
@theme { @theme {
@@ -19,4 +20,4 @@ html[data-theme="terminal"] {
} }
/* make the theme's body font follow asger's --font-sans (Inter / mono) */ /* make the theme's body font follow asger's --font-sans (Inter / mono) */
:root { --wt-font-sans: var(--font-sans); } :root { --wt-font-sans: var(--font-sans); }
a { color: inherit; } @layer base { a { color: inherit; } }