Address findings from 3 review agents on the Threads list panel:
- Last-activity accuracy (SDK): sort key and the "last reply <time>"
label now use thread.replyToEvent.getTs() (server bundle latest_event)
instead of lastReply(), which returns the ROOT time until each thread's
replies lazily paginate (or permanently on fetch error). Applied to the
hook signature too.
- Live-refresh completeness (correctness): the useRoomThreads signature
now includes thread.length and the root event's replacingEventId, so a
mid-thread redaction (reply count) and a root-message edit (row snippet)
refresh the row live instead of going stale.
- a11y: the row's aria-label was the button's whole accessible name,
hiding the snippet/count/unread from screen readers. It now describes
the thread ("Open thread by <name>, unread, N replies, last reply ..").
- Unread badge: replaced the bare green dot (Success = the mention color)
with the app-wide UnreadBadge, using the Highlight count so mentions
render red and ordinary unread renders secondary, matching room-nav.
- Hover/focus affordance: the clickable row moved its inline styles to a
css class with token-based :hover / :active backgrounds.
- Participant pile now also includes the last replier from the bundle.
- Stabilized the panel's onClose/onOpenThread with useCallback so its
Escape listener isn't re-subscribed every Room render. Added
filter->sort pipeline + all/participating immutability tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
45 lines
1.0 KiB
TypeScript
45 lines
1.0 KiB
TypeScript
import { style } from '@vanilla-extract/css';
|
|
import { color, config, toRem } from 'folds';
|
|
|
|
export const ThreadsListPanel = style({
|
|
width: toRem(340),
|
|
'@media': {
|
|
'(max-width: 750px)': {
|
|
position: 'fixed',
|
|
inset: 0,
|
|
width: '100%',
|
|
zIndex: 500,
|
|
},
|
|
},
|
|
});
|
|
|
|
export const ThreadsListHeader = style({
|
|
flexShrink: 0,
|
|
padding: `0 ${config.space.S200} 0 ${config.space.S300}`,
|
|
borderBottomWidth: config.borderWidth.B300,
|
|
});
|
|
|
|
export const ThreadsListToolbar = style({
|
|
flexShrink: 0,
|
|
padding: config.space.S200,
|
|
borderBottomWidth: config.borderWidth.B300,
|
|
});
|
|
|
|
export const ThreadsListContent = style({
|
|
padding: config.space.S200,
|
|
});
|
|
|
|
export const ThreadRow = style({
|
|
width: '100%',
|
|
textAlign: 'left',
|
|
cursor: 'pointer',
|
|
border: 'none',
|
|
borderRadius: config.radii.R300,
|
|
padding: config.space.S300,
|
|
background: color.SurfaceVariant.Container,
|
|
selectors: {
|
|
'&:hover': { background: color.SurfaceVariant.ContainerHover },
|
|
'&:active': { background: color.SurfaceVariant.ContainerActive },
|
|
},
|
|
});
|