feat: document title unread count, draft persistence, search date range

E1 - Document title unread count: FaviconUpdater now also sets
     document.title to '(N) Lotus Chat' for mentions, '· Lotus Chat'
     for plain unreads, and 'Lotus Chat' when clear. Reuses the
     existing roomToUnread forEach loop.

E2 - Draft persistence across reloads: on room unmount, unsent message
     is written to localStorage as 'draft-msg-<roomId>'. On mount, if
     the Jotai atom is empty (page reload), the localStorage draft is
     restored. Cleared on send. Uses the existing Slate node JSON format.

E5 - Search date range filter: new DateRangeButton in SearchFilters
     with From/To date inputs in a PopOut. Dates stored as epoch ms in
     ?fromTs=&toTs= URL params. Passed to Matrix /search as from_ts /
     to_ts filter fields (valid spec fields, cast via 'as any' since
     SDK types don't include them yet).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-30 22:22:40 -04:00
parent 10f0093f8e
commit 582839fddb
6 changed files with 188 additions and 13 deletions
+14 -10
View File
@@ -56,22 +56,26 @@ function FaviconUpdater() {
const roomToUnread = useAtomValue(roomToUnreadAtom);
useEffect(() => {
let notification = false;
let highlight = false;
let totalNotif = 0;
let totalHighlight = 0;
roomToUnread.forEach((unread) => {
if (unread.total > 0) {
notification = true;
}
if (unread.highlight > 0) {
highlight = true;
}
totalNotif += unread.total;
totalHighlight += unread.highlight;
});
if (notification) {
setFavicon(highlight ? LogoHighlightSVG : LogoUnreadSVG);
if (totalNotif > 0) {
setFavicon(totalHighlight > 0 ? LogoHighlightSVG : LogoUnreadSVG);
} else {
setFavicon(LogoSVG);
}
if (totalHighlight > 0) {
document.title = `(${totalHighlight}) Lotus Chat`;
} else if (totalNotif > 0) {
document.title = `· Lotus Chat`;
} else {
document.title = 'Lotus Chat';
}
}, [roomToUnread]);
return null;