test: vitest unit + playwright e2e suites; fix a11y, contrast, no-JS reveal

- vitest: dictionary parity, slug-map bijection, content-schema validation, JSON-LD (23)
- playwright: both locales, language-switch mapping (incl. no-JS), CV downloads,
  form happy-path + honeypot, axe a11y on 5 templates x 2 themes (23)
- fix: raise ink-faint + light accent to meet WCAG AA 4.5:1 (axe-verified)
- fix: gate reveal animations behind html.js so content is visible without JS
  (progressive enhancement - was hidden at opacity 0); scan reduced-motion path
- fix: validate contact form before the anti-bot time-trap (no false success)
- chore: ESLint node globals, typed diagram props, resvg fontFiles, prettier pass

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cesnimda
2026-07-04 06:14:18 +02:00
parent 9fa16b650d
commit 033c9ec315
64 changed files with 1627 additions and 278 deletions
+16 -8
View File
@@ -25,14 +25,14 @@ const currentLabel = locale === 'en' ? d.cv.english : d.cv.norsk;
<a
href={current.path}
download
class="inline-flex items-center rounded-l-sm bg-accent px-4 py-2 text-small font-semibold text-accent-ink transition-[filter] duration-[--dur-quick] hover:brightness-105"
class="bg-accent text-small text-accent-ink inline-flex items-center rounded-l-sm px-4 py-2 font-semibold transition-[filter] duration-[--dur-quick] hover:brightness-105"
>
{d.cv.download}
{!compact && <span class="ml-2 font-mono text-mono-label opacity-70">EN/NO</span>}
{!compact && <span class="text-mono-label ml-2 font-mono opacity-70">EN/NO</span>}
</a>
<details class="cv-menu">
<summary
class="flex cursor-pointer list-none items-center rounded-r-sm border-l border-accent-ink/20 bg-accent px-2 text-accent-ink transition-[filter] duration-[--dur-quick] hover:brightness-105"
class="border-accent-ink/20 bg-accent text-accent-ink flex cursor-pointer list-none items-center rounded-r-sm border-l px-2 transition-[filter] duration-[--dur-quick] hover:brightness-105"
aria-label={d.cv.download}
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" aria-hidden="true">
@@ -40,22 +40,30 @@ const currentLabel = locale === 'en' ? d.cv.english : d.cv.norsk;
</svg>
</summary>
<div
class="absolute right-0 top-[calc(100%+8px)] z-30 w-64 overflow-hidden rounded-md border border-line-strong bg-surface-2 shadow-[var(--shadow-overlay)]"
class="border-line-strong bg-surface-2 absolute top-[calc(100%+8px)] right-0 z-30 w-64 overflow-hidden rounded-md border shadow-[var(--shadow-overlay)]"
>
<a
href={current.path}
download
class="flex items-center justify-between gap-2 px-4 py-3 text-small text-ink hover:bg-surface-1"
class="text-small text-ink hover:bg-surface-1 flex items-center justify-between gap-2 px-4 py-3"
>
<span><span class="mr-2 font-mono text-mono-label text-accent">{d.lang[locale]}</span>{currentLabel}</span>
<span
><span class="text-mono-label text-accent mr-2 font-mono">{d.lang[locale]}</span>{
currentLabel
}</span
>
<span class="mono-meta">{interpolate(d.cv.fileMeta, { size: current.sizeKb })}</span>
</a>
<a
href={other.path}
download
class="flex items-center justify-between gap-2 border-t border-line px-4 py-3 text-small text-ink-muted hover:bg-surface-1 hover:text-ink"
class="border-line text-small text-ink-muted hover:bg-surface-1 hover:text-ink flex items-center justify-between gap-2 border-t px-4 py-3"
>
<span><span class="mr-2 font-mono text-mono-label">{locale === 'en' ? 'NO' : 'EN'}</span>{otherLabel}</span>
<span
><span class="text-mono-label mr-2 font-mono">{locale === 'en' ? 'NO' : 'EN'}</span>{
otherLabel
}</span
>
<span class="mono-meta">{interpolate(d.cv.fileMeta, { size: other.sizeKb })}</span>
</a>
</div>