From 9a4796c16707149655747a7fb1f02939fe3293d4 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Fri, 10 Jul 2026 12:34:51 -0400 Subject: [PATCH] fix(gif): still previews + a11y for recent GIFs Address findings from 2 review agents on the recent-GIFs row: - Motion/perf: the Recent row rendered up to 16 full animated GIFs at once (autoplaying). Capture a small still image at pick time (fixed_width_small_still / *_still) into RecentGif.previewUrl and render that for the thumbnail, so recents no longer autoplay. Pre-existing recents without a preview fall back to the animated url. Re-send still uses the animated url, so the sent m.image is unchanged. - a11y: the recent buttons all had the identical label "Send recent GIF". Give them positional labels ("Send recent GIF N of M") and wrap the grid in a role="group" labelled by the "Recent" section heading, so the row is a distinguishable, announced group. Correctness review found no bugs (write-before-unmount, term gating, dedupe, re-send fidelity all verified). Co-Authored-By: Claude Opus 4.8 --- src/app/components/GifPicker.tsx | 51 ++++++++++++++++++++++++-------- src/app/state/recentGifs.ts | 2 ++ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/app/components/GifPicker.tsx b/src/app/components/GifPicker.tsx index 40b3f060d..ac8a4db8a 100644 --- a/src/app/components/GifPicker.tsx +++ b/src/app/components/GifPicker.tsx @@ -19,10 +19,21 @@ type GifPickerInnerProps = { // Small monospace section header matching the picker's `// GIF_SEARCH` treatment // (lotusTerminal) / a muted label otherwise. -function SectionLabel({ text, lotusTerminal }: { text: string; lotusTerminal: boolean }) { +const RECENT_LABEL_ID = 'gif-picker-recent-label'; + +function SectionLabel({ + text, + lotusTerminal, + id, +}: { + text: string; + lotusTerminal: boolean; + id?: string; +}) { if (lotusTerminal) { return (
void; + onPick: (gif: RecentGif) => void; }) { return (
- -
- {recents.map((g) => ( + +
+ {recents.map((g, i) => (