a11y: viewport-fit, reduced-motion, like aria-pressed, labels, contrast (M13-M18)

M13: add viewport-fit=cover so env(safe-area-inset-*) resolves on notched phones.
M14: like buttons (list card, grid overlay, lightbox) get aria-pressed + a
descriptive aria-label so AT announces self-state, not just the shared count.
M15: a prefers-reduced-motion media query neutralizes the decorative keyframes
(Ken Burns, crossfade, HeartBurst) and snaps transitions.
M16: join/recover name + PIN inputs and the lightbox comment input get aria-labels.
M17: FeedGrid overlay like/comment buttons get aria-labels and ≥44px hit areas.
M18: bump light-mode secondary text from gray-400 to gray-500 (keeping
dark:text-gray-400) across the app for WCAG AA contrast.

Also raises the PIN inputs to 6 digits (placeholder, maxlength, slice, and the
auto-submit threshold) to match the new 6-digit generated PINs; legacy 4-digit
PINs still submit via the button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-27 16:26:21 +02:00
parent 5bd008591b
commit 0737288ed9
13 changed files with 69 additions and 40 deletions

View File

@@ -67,7 +67,9 @@
<p class="truncate text-xs font-medium text-white">{upload.uploader_name}</p>
<div class="mt-0.5 flex items-center gap-3 text-xs text-white/80">
<button
class="pointer-events-auto flex items-center gap-0.5"
class="pointer-events-auto -m-2 flex min-h-11 min-w-11 items-center justify-center gap-0.5 p-2"
aria-pressed={upload.liked_by_me}
aria-label="Gefällt mir ({upload.like_count})"
onclick={(e) => { e.stopPropagation(); onlike(upload.id); }}
>
<svg class="h-3.5 w-3.5 {upload.liked_by_me ? 'fill-red-400 text-red-400' : ''}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -76,7 +78,8 @@
{upload.like_count}
</button>
<button
class="pointer-events-auto flex items-center gap-0.5"
class="pointer-events-auto -m-2 flex min-h-11 min-w-11 items-center justify-center gap-0.5 p-2"
aria-label="Kommentare ({upload.comment_count})"
onclick={(e) => { e.stopPropagation(); oncomment(upload.id); }}
>
<svg class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">

View File

@@ -100,7 +100,7 @@
</div>
<div class="min-w-0">
<p class="truncate text-sm font-semibold text-gray-900 dark:text-gray-100">{upload.uploader_name}</p>
<p class="text-xs text-gray-400 dark:text-gray-500">{relativeTime(upload.created_at)}</p>
<p class="text-xs text-gray-500 dark:text-gray-400">{relativeTime(upload.created_at)}</p>
</div>
</div>
@@ -164,6 +164,8 @@
<div class="flex items-center gap-4 px-4 py-2">
<button
onclick={() => { vibrate(10); onlike(upload.id); }}
aria-pressed={upload.liked_by_me}
aria-label="Gefällt mir ({upload.like_count})"
class="flex items-center gap-1.5 text-sm font-medium transition-colors
{upload.liked_by_me ? 'text-red-500 dark:text-red-400' : 'text-gray-500 hover:text-red-400 active:text-red-400 dark:text-gray-400 dark:hover:text-red-400 dark:active:text-red-400'}"
>
@@ -188,7 +190,7 @@
{upload.comment_count}
</button>
{#if isOwn}
<span class="ml-auto text-xs text-gray-400 dark:text-gray-500">Eigener Beitrag</span>
<span class="ml-auto text-xs text-gray-500 dark:text-gray-400">Eigener Beitrag</span>
{/if}
</div>

View File

@@ -141,10 +141,12 @@
<div class="flex items-center justify-between">
<div>
<span id="lightbox-title" class="font-medium text-gray-900 dark:text-gray-100">{upload.uploader_name}</span>
<span class="ml-2 text-xs text-gray-400 dark:text-gray-500">{formatTime(upload.created_at)}</span>
<span class="ml-2 text-xs text-gray-500 dark:text-gray-400">{formatTime(upload.created_at)}</span>
</div>
<button
onclick={() => onlike(upload.id)}
aria-pressed={upload.liked_by_me}
aria-label="Gefällt mir ({upload.like_count})"
class="flex items-center gap-1 rounded-full px-2.5 py-1 text-sm transition {
upload.liked_by_me
? 'bg-red-50 text-red-600 dark:bg-red-950/40 dark:text-red-300'
@@ -165,7 +167,7 @@
<!-- Comments list -->
<div class="flex-1 overflow-y-auto p-3">
{#if comments.length === 0}
<p class="text-center text-sm text-gray-400 dark:text-gray-500">Noch keine Kommentare.</p>
<p class="text-center text-sm text-gray-500 dark:text-gray-400">Noch keine Kommentare.</p>
{:else}
<div class="space-y-3">
{#each comments as comment (comment.id)}
@@ -173,7 +175,7 @@
<div class="flex-1">
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{comment.uploader_name}</span>
<span class="ml-1 text-sm text-gray-700 dark:text-gray-300">{comment.body}</span>
<div class="mt-0.5 text-xs text-gray-400 dark:text-gray-500">{formatTime(comment.created_at)}</div>
<div class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">{formatTime(comment.created_at)}</div>
</div>
{#if comment.user_id === userId}
<button
@@ -201,6 +203,7 @@
<input
type="text"
bind:value={newComment}
aria-label="Kommentar schreiben"
placeholder="Kommentar schreiben..."
maxlength={COMMENT_MAX}
class="flex-1 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:outline-none dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-500"