feat(messages): standalone Messages module + floating chat dock
Move messaging out of the notification center into its own left-nav module (own page, own unread badge), so a reload returns to it and notifications stay separate. Add a Messenger-style floating dock (bottom-right): pop a conversation out from the page, keep chatting across navigation, minimise (rollup) or close. - Messages is now a routed page; NotificationsPanel reverts to inbox-only and the nav badge no longer mixes in messages. - Extract shared KeyGate + ChatThread (used by both the page and dock windows); e2ee exposes a shared unlock subscription so page and dock agree. - ChatDock (always mounted for human users) owns the app-wide live-message subscription and per-device key restore. EN/HU/DE strings.
This commit is contained in:
parent
2f0ca68e8a
commit
3fd71cd316
14 changed files with 518 additions and 347 deletions
|
|
@ -12,6 +12,7 @@ import {
|
|||
Info,
|
||||
ListVideo,
|
||||
LogOut,
|
||||
MessageSquare,
|
||||
Settings,
|
||||
Shield,
|
||||
SlidersHorizontal,
|
||||
|
|
@ -126,15 +127,14 @@ export default function NavSidebar({
|
|||
// One indicator for both layers: durable server notifications + the client-side transient
|
||||
// events (the former separate bell is now folded into the inbox page).
|
||||
const clientUnread = useSyncExternalStore(subscribe, getUnreadCount, getUnreadCount);
|
||||
// Unread direct messages also live in the notification module, so they add to the same badge.
|
||||
// The demo account can't use messaging, so don't poll it there.
|
||||
const unread = (unreadQuery.data?.count ?? 0) + clientUnread;
|
||||
// Direct messages are their own module with their own unread badge (demo can't message).
|
||||
const msgUnreadQuery = useLiveQuery(
|
||||
["message-unread"],
|
||||
api.messageUnreadCount,
|
||||
{ intervalMs: 30000, enabled: !me.is_demo }
|
||||
);
|
||||
const unread =
|
||||
(unreadQuery.data?.count ?? 0) + clientUnread + (msgUnreadQuery.data?.count ?? 0);
|
||||
const msgUnread = msgUnreadQuery.data?.count ?? 0;
|
||||
|
||||
type NavItem = { page: Page; icon: typeof Home; label: string; badge?: number };
|
||||
// User-facing content modules vs. admin/system modules, separated by a divider in the rail.
|
||||
|
|
@ -143,6 +143,10 @@ export default function NavSidebar({
|
|||
{ page: "channels", icon: Tv, label: t("header.account.channels") },
|
||||
{ page: "playlists", icon: ListVideo, label: t("header.account.playlists") },
|
||||
{ page: "notifications", icon: Bell, label: t("inbox.navLabel"), badge: unread },
|
||||
// Direct messaging — its own module; hidden for the shared demo account.
|
||||
...(me.is_demo
|
||||
? []
|
||||
: [{ page: "messages" as Page, icon: MessageSquare, label: t("messages.navLabel"), badge: msgUnread }]),
|
||||
// Per-user sync status + your own API usage (admins get an extra system-wide tab inside).
|
||||
{ page: "stats", icon: BarChart3, label: t("header.account.stats") },
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue