feat(sidebar): jump-to-unread + /inbox (LC-81) [stacked] #140
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-81-jump-and-inbox"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
LC-81: two related affordances.
Jump-to-unread keybind:
Alt+Shift+ArrowDown/ArrowUpnavigates the sidebar's room and DM list, jumping to the next anchor whose unread badge is non-empty. Wraps at both ends. Pure client-side (sidebar_jump.js). The Inbox header button uses the same handler via[data-lc-jump-unread].GET /inboxview: flattens every unread message the viewer can see (per-room and DMs) into a single newest-first timeline. Uses the existingdm_read_statewatermark (room-keyed, covers both kinds). 30-item pages cursored by?before={message_id}; empty state renders an explicit "All caught up". An HTMXrevealedsentinel at the bottom auto-loads the next page; the handler returns the items fragment when?fragment=1is set.Per-message rows deep-link to
/{room|dm}/{id}#msg-{message_id}. Mark-read happens implicitly when the linked room opens (existing behaviour); per-row mark-read is out of scope.Sidebar nav gains an "Inbox" link beside "Saved".
Acceptance criteria
/inboxlists unread messages across all rooms in time order.db::chat::get_dm_peer).revealedsentinel; no large lists materialized client-side.Out of scope (open questions)
Stack
This branch is on top of LC-79 redesign + LC-79 follow-up + LC-80 stars (PRs #137, #138, #139). Merge this branch supersedes all four.
Test plan
just check(fmt + clippy across standalone + saas)../dev/cargo test -p lets-chat-server --test routes_inbox- 2/2 pass./inboxwith no unreads - "All caught up". Have peer post in #general - reload - peer's message appears. Click - lands in room scrolled to that message. PressAlt+Shift+ArrowDownrepeatedly - cycles through unread sidebar rooms.Two related affordances per LC-81: 1. Jump-to-unread (`Alt+Shift+ArrowDown`/`Up` + `[data-lc-jump-unread]` button). Pure client-side: `sidebar_jump.js` walks `#sidebar a[href^="/room/"]`/`[href^="/dm/"]`, finds the next anchor whose `unread-{kind}-{id}` badge has non-empty text, and clicks it. Wraps at both ends. The Inbox header button uses the same handler. 2. `GET /inbox` flattens every unread message the viewer can see (per-room + DMs) into a single newest-first timeline. Uses the existing `dm_read_state` watermark (room-keyed, works for both kinds). 30-item pages with a cursor (`?before={message_id}`); the empty state renders an explicit "All caught up". HTMX `revealed` sentinel at the bottom loads the next page; the handler returns the items fragment instead of the full page when `?fragment=1`. Per-message rows deep-link to `/{room|dm}/{id}#msg-{message_id}`. Mark-read happens implicitly when the user opens the linked room (existing behaviour); a separate per-row mark-read is out of scope for this PR. Sidebar nav gains an "Inbox" link next to "Saved". Skipped (open questions from the issue): - Inbox filters (mentions-only / DMs-only / per-room). - Mark-all-as-read (global or per-room). Both can land in follow-ups; minimal viable inbox first. Tests: empty-state renders "All caught up"; peer-authored message in General appears in the viewer's inbox with the expected deep-link. Stacks on the LC-79 redesign + LC-79 follow-up + LC-80 stars.