Commit 882876e
authored
feat(threads): thread drawer, thread browser, live reply counts, and unread badges (#564)
📝 **Docs:** Already live at [Threads — Sable
Docs](https://docs.sable.moe/new-features/threads/) — no separate docs
PR needed.
---
### Description
Expands Matrix thread support with a full thread drawer, server-side
thread browser, live reply counts, unread badges, and several UX fixes.
#### ThreadDrawer
- Slide-in drawer for reading and replying in threads without leaving
the main room
- Thread root message shown at top with full reply history below
- Up-arrow edit-last-message: pressing ↑ in the thread input edits the
user's last own message in that thread
- Reactions add/remove trigger immediate re-renders without manual
refresh (handles the fact that reaction events carry
`m.relates_to.event_id` not `threadRootId` directly — fetches target
event to check thread membership)
- Thread root message box sized to content with `maxHeight: 200px` to
avoid dead whitespace on short messages
#### ThreadBrowser
- Lists all threads in the room; calls `room.fetchRoomThreads()` on
mount to load threads beyond the local timeline window
- Load-more button when the server has additional thread pages
- Each thread preview shows sender avatar, display name, reply count,
and last message body with ellipsis truncation
- Jump button navigates to the thread root in the main timeline (via
`useRoomNavigate`) instead of re-opening the drawer
- Thread unread badges on each preview item via
`room.getThreadUnreadNotificationCount()`
#### ThreadReplyChip (main timeline)
- Shows unread badge for threads with unseen replies via
`room.getThreadUnreadNotificationCount()`
#### Thread button (RoomViewHeader)
- If a thread drawer is open, button closes the drawer and opens the
thread browser (allows going from a single thread to the full list)
- If no thread is open, button toggles the thread browser as before
- `aria-pressed` reflects both thread browser state and open thread
drawer
Fixes #
#### Type of change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update
### Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
### AI disclosure:
- [x] Partially AI assisted (clarify which code was AI assisted and
briefly explain what it does)
- [ ] Fully AI generated (explain what all the generated code does in
moderate detail)
ThreadDrawer/ThreadBrowser/thread-chip iterations were partially AI
assisted; I reviewed and adjusted logic for timeline processing, thread
loading, and event rendering behavior.11 files changed
Lines changed: 767 additions & 493 deletions
File tree
- .changeset
- src
- app
- features/room
- hooks
- timeline
- styles/overrides
- client
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| 35 | + | |
35 | 36 | | |
36 | 37 | | |
37 | 38 | | |
| |||
124 | 125 | | |
125 | 126 | | |
126 | 127 | | |
| 128 | + | |
| 129 | + | |
127 | 130 | | |
128 | 131 | | |
129 | 132 | | |
| |||
167 | 170 | | |
168 | 171 | | |
169 | 172 | | |
170 | | - | |
171 | 173 | | |
172 | 174 | | |
173 | 175 | | |
| |||
472 | 474 | | |
473 | 475 | | |
474 | 476 | | |
475 | | - | |
476 | 477 | | |
477 | 478 | | |
478 | 479 | | |
| |||
481 | 482 | | |
482 | 483 | | |
483 | 484 | | |
484 | | - | |
485 | | - | |
| 485 | + | |
486 | 486 | | |
487 | 487 | | |
488 | 488 | | |
| |||
0 commit comments