From 3e09ff66d124b769760fb065007d168e80de7759 Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 22 Apr 2026 17:00:59 +0200 Subject: [PATCH] fix(a11y): resolve 30 svelte-check warnings across 8 files svelte-check now completes clean (0 errors, 0 warnings, 0 files with problems). - profile/ContextOverview: 11 click-on-div sites made keyboard- accessible with role="button", tabindex="0", and an onActivate helper that fires the same handler on Enter/Space. Two

wrappers became

since

cannot carry role="button" per ARIA. - profile/ContextInterview: paginate dots got aria-label + aria-current. - settings/GeneralSection: toggle button got aria-label + aria-pressed. - events/RegionPicker: radius label associated with range input via for/id. - events/SourceManager: drop unused .source-item.inactive + .inactive- badge CSS selectors (dead code). - research-lab/CompareColumn: local `rating` seed from entry.userRating now uses svelte-ignore comment + $effect sync (intentional seed-only read, plus prop-update mirror). - admin/ListView: initialTab prop is deliberately read only at mount; svelte-ignore comment documents the intent. - gifts/redeem: drop unused .animate-fade-in CSS selector. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../settings/sections/GeneralSection.svelte | 2 + .../web/src/lib/modules/admin/ListView.svelte | 3 + .../events/components/RegionPicker.svelte | 4 +- .../events/components/SourceManager.svelte | 11 --- .../modules/profile/ContextInterview.svelte | 2 + .../modules/profile/ContextOverview.svelte | 81 +++++++++++++++++-- .../components/CompareColumn.svelte | 8 ++ .../(app)/gifts/redeem/[code]/+page.svelte | 3 - 8 files changed, 90 insertions(+), 24 deletions(-) diff --git a/apps/mana/apps/web/src/lib/components/settings/sections/GeneralSection.svelte b/apps/mana/apps/web/src/lib/components/settings/sections/GeneralSection.svelte index 863ad3f21..06d5feba9 100644 --- a/apps/mana/apps/web/src/lib/components/settings/sections/GeneralSection.svelte +++ b/apps/mana/apps/web/src/lib/components/settings/sections/GeneralSection.svelte @@ -135,6 +135,8 @@ class="toggle" class:on={userSettings.general?.soundsEnabled ?? true} onclick={() => setSounds(!(userSettings.general?.soundsEnabled ?? true))} + aria-label="Sounds ein- oder ausschalten" + aria-pressed={userSettings.general?.soundsEnabled ?? true} > diff --git a/apps/mana/apps/web/src/lib/modules/admin/ListView.svelte b/apps/mana/apps/web/src/lib/modules/admin/ListView.svelte index 5b85776a7..e2fd5ea8d 100644 --- a/apps/mana/apps/web/src/lib/modules/admin/ListView.svelte +++ b/apps/mana/apps/web/src/lib/modules/admin/ListView.svelte @@ -26,6 +26,9 @@ let { initialTab = 'overview' }: Props = $props(); + // initialTab is an entry-point default only — we deliberately ignore later prop + // changes because the user may have switched tabs since mount. + // svelte-ignore state_referenced_locally let activeTab = $state(initialTab); let isAdmin = $derived(authStore.user?.role === 'admin'); diff --git a/apps/mana/apps/web/src/lib/modules/events/components/RegionPicker.svelte b/apps/mana/apps/web/src/lib/modules/events/components/RegionPicker.svelte index b3bdccf6f..f182a3762 100644 --- a/apps/mana/apps/web/src/lib/modules/events/components/RegionPicker.svelte +++ b/apps/mana/apps/web/src/lib/modules/events/components/RegionPicker.svelte @@ -88,8 +88,8 @@ placeholder="Stadt oder Region suchen..." />

- - + +
{#if suggestions.length > 0}
diff --git a/apps/mana/apps/web/src/lib/modules/profile/ContextOverview.svelte b/apps/mana/apps/web/src/lib/modules/profile/ContextOverview.svelte index 8f80e9a41..c2b77d9d4 100644 --- a/apps/mana/apps/web/src/lib/modules/profile/ContextOverview.svelte +++ b/apps/mana/apps/web/src/lib/modules/profile/ContextOverview.svelte @@ -65,6 +65,18 @@ 5: 'Fr', 6: 'Sa', }; + + // Enter / Space on a non-button click-target counts as activation, same + // as a button would. Used to make the "tap a section to edit" surfaces + // keyboard-accessible without rewriting the whole card layout. + function onActivate(handler: () => void) { + return (e: KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + handler(); + } + }; + }
@@ -108,9 +120,15 @@
- {:else}

startEdit('about.bio', ctx?.about?.bio)}> + {:else}

startEdit('about.bio', ctx?.about?.bio)} + onkeydown={onActivate(() => startEdit('about.bio', ctx?.about?.bio))} + > {ctx?.about?.bio} -

{/if} +
{/if} {/if} @@ -144,7 +162,13 @@ {:else if ctx?.interests?.length} -
startEdit('interests', ctx?.interests ?? [])}> +
startEdit('interests', ctx?.interests ?? [])} + onkeydown={onActivate(() => startEdit('interests', ctx?.interests ?? []))} + > {#each ctx.interests as tag (tag)}{tag}{/each}
{:else} @@ -162,7 +186,13 @@

Tagesablauf

{#if ctx?.routine && (ctx.routine.wakeUp || ctx.routine.workStart || ctx.routine.bedtime)} -
onStartInterview()}> +
onStartInterview()} + onkeydown={onActivate(() => onStartInterview())} + > {#if ctx.routine.wakeUp}
Aufstehen{ctx.routine.wakeUp}Ernährung {#if ctx?.nutrition && (ctx.nutrition.diet || ctx.nutrition.allergies?.length)}
- {#if ctx.nutrition.diet}

onStartInterview()}> + {#if ctx.nutrition.diet}

onStartInterview()} + onkeydown={onActivate(() => onStartInterview())} + > {ctx.nutrition.diet} -

{/if} +
{/if} {#if ctx.nutrition.allergies?.length} {#if editingField === 'nutrition.allergies'}
@@ -232,7 +268,12 @@ {:else}
startEdit('nutrition.allergies', ctx?.nutrition?.allergies ?? [])} + onkeydown={onActivate(() => + startEdit('nutrition.allergies', ctx?.nutrition?.allergies ?? []) + )} > {#each ctx.nutrition.allergies as a (a)}{a}{/each}
@@ -258,7 +299,10 @@ Sport
startEdit('leisure.sports', ctx?.leisure?.sports ?? [])} + onkeydown={onActivate(() => startEdit('leisure.sports', ctx?.leisure?.sports ?? []))} > {#each ctx.leisure.sports as s (s)}{s}{/each}
@@ -269,7 +313,10 @@ Medien
startEdit('leisure.media', ctx?.leisure?.media ?? [])} + onkeydown={onActivate(() => startEdit('leisure.media', ctx?.leisure?.media ?? []))} > {#each ctx.leisure.media as m (m)}{m}{/each}
@@ -280,7 +327,10 @@ Haustiere startEdit('leisure.pets', ctx?.leisure?.pets ?? '')} + onkeydown={onActivate(() => startEdit('leisure.pets', ctx?.leisure?.pets ?? ''))} >{ctx.leisure.pets}
@@ -318,7 +368,13 @@
{:else if ctx?.goals?.length} -
startEdit('goals', ctx?.goals ?? [])}> +
startEdit('goals', ctx?.goals ?? [])} + onkeydown={onActivate(() => startEdit('goals', ctx?.goals ?? []))} + > {#each ctx.goals as goal (goal)}{goal}{/each}
{:else} @@ -336,7 +392,13 @@

Arbeitsstil

{#if ctx?.social && (ctx.social.workStyle || ctx.social.communication || ctx.social.livingSetup)} -
onStartInterview()}> +
onStartInterview()} + onkeydown={onActivate(() => onStartInterview())} + > {#if ctx.social.workStyle}
Arbeitsweise{ctx.social.workStyle} startEdit('about.languages', ctx?.about?.languages ?? [])} + onkeydown={onActivate(() => startEdit('about.languages', ctx?.about?.languages ?? []))} > {#each ctx.about.languages as lang (lang)}{lang}{/each}
diff --git a/apps/mana/apps/web/src/lib/modules/research-lab/components/CompareColumn.svelte b/apps/mana/apps/web/src/lib/modules/research-lab/components/CompareColumn.svelte index 1e924c4ae..96defe5e6 100644 --- a/apps/mana/apps/web/src/lib/modules/research-lab/components/CompareColumn.svelte +++ b/apps/mana/apps/web/src/lib/modules/research-lab/components/CompareColumn.svelte @@ -20,9 +20,17 @@ const { category, entry, runId }: Props = $props(); + // Local optimistic rating — seed from the current entry, then keep in sync + // via $effect when the parent swaps the prop. The seed-only read of + // entry.userRating is intentional; the $effect covers prop updates. + // svelte-ignore state_referenced_locally let rating = $state(entry.userRating ?? 0); let ratingError = $state(null); + $effect(() => { + rating = entry.userRating ?? 0; + }); + async function setRating(value: number) { if (!runId || !entry.resultId) return; ratingError = null; diff --git a/apps/mana/apps/web/src/routes/(app)/gifts/redeem/[code]/+page.svelte b/apps/mana/apps/web/src/routes/(app)/gifts/redeem/[code]/+page.svelte index 639cf389d..8ab37fe60 100644 --- a/apps/mana/apps/web/src/routes/(app)/gifts/redeem/[code]/+page.svelte +++ b/apps/mana/apps/web/src/routes/(app)/gifts/redeem/[code]/+page.svelte @@ -294,9 +294,6 @@ transform: translateY(0); } } - .animate-fade-in { - animation: fade-in 0.2s ease-out; - } @keyframes bounce-once { 0%, 100% {