fix(bookmarks): harden sort/group after review
Address findings from 2 review agents on the bookmark sort/group feature:
- Flash on open: the persisted-sort atom now uses getOnInit so the saved
sort applies on the first render instead of briefly showing Newest and
reordering after mount.
- Stale collapse state: prune collapsed roomIds that no longer have any
bookmark, so a room re-saved later doesn't reappear pre-collapsed and
the Set can't grow unbounded across a session.
- Corrupt persisted value: validate the stored sort with a new
isBookmarkSort type guard, normalizing anything unexpected to Newest so
exactly one sort button is always active.
- a11y: room group headers now expose an explicit aria-label
("<room>, N saved messages") instead of announcing the avatar alt and
the visible name twice with a bare count, plus aria-controls linking the
header to its collapsible content region.
- Layout: move the sort control to its own toolbar row so the three
buttons don't crowd the count text in the narrow (266px) panel.
- Memoize filtered/sortedItems/groups for consistency with renderItem.
Adds unit tests for isBookmarkSort, group-order tie-break, and
groupBookmarksByRoom immutability.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,13 @@ import { Bookmark } from '../hooks/useBookmarks';
|
||||
|
||||
export type BookmarkSort = 'newest' | 'oldest' | 'room';
|
||||
|
||||
const BOOKMARK_SORTS: readonly BookmarkSort[] = ['newest', 'oldest', 'room'];
|
||||
|
||||
/** Type guard for persisted/untrusted sort values (localStorage can hold stale/corrupt data). */
|
||||
export function isBookmarkSort(value: unknown): value is BookmarkSort {
|
||||
return typeof value === 'string' && (BOOKMARK_SORTS as readonly string[]).includes(value);
|
||||
}
|
||||
|
||||
export type BookmarkRoomGroup = {
|
||||
roomId: string;
|
||||
roomName: string;
|
||||
|
||||
Reference in New Issue
Block a user