feat(stickers): "recently used" row in the sticker picker

The emoji and GIF pickers both have a "Recent" row, but the sticker tab of the
shared EmojiBoard did not — you had to hunt through packs to re-send a sticker.
Add recent stickers, mirroring recentGifs:

- New state/recentStickers.ts (localStorage cinny_recent_stickers_v1, deduped by
  url, capped 16) + pure addRecentSticker with 4 unit tests.
- EmojiBoard: a "Recent" group in stickerGroupItems and a RecentClock sidebar
  icon in StickerSidebar, shown only when recents exist. Entries are rebuilt into
  minimal PackImageReaders (StickerItem needs only url/shortcode/body) so they
  render + re-send like pack stickers.
- Recorded on select in the shared delegated click handler, covering both the
  grouped and search paths.

Blast radius is the sticker tab only (reactions/status use the emoji tab).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 22:43:17 -04:00
co-authored by Claude Opus 4.8
parent fb8e0c6e14
commit 3a1c626bc8
4 changed files with 144 additions and 2 deletions
+11
View File
@@ -679,6 +679,17 @@ The indicator is hidden once the server confirms the event (when the internal st
- Picker UI is styled with TDS variables when the TDS theme is active
- Located at `src/app/components/GifPicker.tsx`
### Sticker Picker — Recently used
The sticker tab of the shared `EmojiBoard` now has a **"Recent" group** (a sidebar
`RecentClock` icon + top group), matching the emoji and GIF pickers — the stickers you last sent
surface for one-click re-sending instead of hunting through packs. Only shown once you've sent at
least one sticker (hidden otherwise). Persisted in localStorage (`cinny_recent_stickers_v1`),
deduped by url, most-recent-first, capped at 16, via the pure/unit-tested `addRecentSticker`
(`src/app/state/recentStickers.ts`). Recent entries are rebuilt into minimal `PackImageReader`s
(`StickerItem` only needs `url`/`shortcode`/`body`) so they render and re-send exactly like pack
stickers. Recorded on select for both the grouped and search paths (shared delegated click).
### Message Forwarding
Context menu → **Forward** allows forwarding a message to any room the user is a member of.