feat(ui): recently-used emoji row in the reaction picker (LC-288) #322

Merged
longjacksonle merged 1 commit from feat/lc-288-recent-emoji into main 2026-06-14 20:21:04 +02:00

What

The reaction picker now opens with a "Recent" row of the emojis you react with most, for one-click reuse (LC-288). Builds on the LC-274 picker.

How

  • get_picker renders an empty data-lc-emoji-recent placeholder (hidden, with a localized label data-attr) above the grid.
  • A persistent-shell IIFE in layout.html:
    • Records on click: a delegated listener on [hx-post*="/reactions/"] parses the emoji from the URL and, for unicode emoji only (custom :shortcode: skipped - enclave-scoped, not reusable across rooms; the cancel/open controls use hx-get so never match), pushes it to localStorage['lc-recent-emoji'] (MRU, cap 12, deduped).
    • Fills on open: on htmx:afterSettle, builds real htmx-wired reaction buttons for the recents (targeting that message's #reactions-{id}), runs htmx.process, and reveals the row. Empty history leaves it hidden, so the picker looks exactly as before for new users.

Recents are an ephemeral per-device convenience (localStorage, like theme/density/sidebar) - no schema, query, or route. Label localized in en + es. Not operator-visible. No LC-77 fixture impact (the picker isn't rendered in any fixture).

Tests

routes_reactions_authz: the picker ships the data-lc-emoji-recent placeholder. just test and just test-saas pass; no fixture changes.

QA note

JS + localStorage, so worth a manual pass: react with a few unicode emojis, reopen the picker (a "Recent" row shows them, newest first), click a recent one (it reacts), react with more and confirm MRU ordering/dedup and the cap; confirm a custom :emoji: reaction does NOT appear in Recent; confirm a brand-new browser (no history) shows no Recent row; reload and confirm recents persist.

## What The reaction picker now opens with a "Recent" row of the emojis you react with most, for one-click reuse (LC-288). Builds on the LC-274 picker. ## How - `get_picker` renders an empty `data-lc-emoji-recent` placeholder (hidden, with a localized label data-attr) above the grid. - A persistent-shell IIFE in `layout.html`: - Records on click: a delegated listener on `[hx-post*="/reactions/"]` parses the emoji from the URL and, for unicode emoji only (custom `:shortcode:` skipped - enclave-scoped, not reusable across rooms; the cancel/open controls use `hx-get` so never match), pushes it to `localStorage['lc-recent-emoji']` (MRU, cap 12, deduped). - Fills on open: on `htmx:afterSettle`, builds real htmx-wired reaction buttons for the recents (targeting that message's `#reactions-{id}`), runs `htmx.process`, and reveals the row. Empty history leaves it hidden, so the picker looks exactly as before for new users. Recents are an ephemeral per-device convenience (localStorage, like theme/density/sidebar) - no schema, query, or route. Label localized in en + es. Not operator-visible. No LC-77 fixture impact (the picker isn't rendered in any fixture). ## Tests `routes_reactions_authz`: the picker ships the `data-lc-emoji-recent` placeholder. `just test` and `just test-saas` pass; no fixture changes. ## QA note JS + localStorage, so worth a manual pass: react with a few unicode emojis, reopen the picker (a "Recent" row shows them, newest first), click a recent one (it reacts), react with more and confirm MRU ordering/dedup and the cap; confirm a custom `:emoji:` reaction does NOT appear in Recent; confirm a brand-new browser (no history) shows no Recent row; reload and confirm recents persist.
feat(ui): recently-used emoji row in the reaction picker (LC-288)
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 3m43s
check-secrets / Nosey parker (pull_request) Successful in 5s
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 4s
check-secrets / Kingfisher (push) Successful in 6s
check-secrets / TruffleHog (pull_request) Successful in 5s
check-secrets / Kingfisher (pull_request) Successful in 5s
Create release / Create release from merged PR (pull_request) Has been skipped
c973ef3a0a
The reaction picker now shows a "Recent" row of the emojis you react with most, for one-click reuse. Recents are per-device (localStorage, MRU, capped at 12).

get_picker renders an empty data-lc-emoji-recent placeholder above the grid; a persistent-shell IIFE records the unicode emoji of any reaction POST (picker buttons, existing pills, recent buttons) - skipping custom :shortcode: reactions (enclave-scoped, not reusable across rooms) and the hx-get cancel/open controls - and fills the row on picker open, building real htmx-wired reaction buttons (htmx.process) that target the message's reactions endpoint. Empty history leaves the row hidden, so with no recents the picker looks exactly as before.

Recents are an ephemeral per-device convenience (localStorage, like theme/density), so no schema or query. Label localized in en + es. Test asserts the picker ships the placeholder. No LC-77 fixture impact (the picker is not in any fixture).

#LC-288
#LC-289

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-288-recent-emoji 2026-06-14 20:21:04 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!322
No description provided.