feat: Windows taskbar notification badge counter
CI / Build & Quality Checks (push) Successful in 10m31s
Trigger Desktop Build / trigger (push) Successful in 13s

Adds a Tauri command (set_badge_count) that draws a red circle badge
with a highlight count onto the Windows taskbar button overlay icon,
matching Discord's behavior. Badge shows @mention/highlight count only
(not total messages), clears to zero when all highlights are read.

Frontend: useTauriNotificationBadge hook reads roomToUnreadAtom and
calls set_badge_count via window.__TAURI_INTERNALS__.invoke whenever
the unread map changes. No-ops silently in the browser (non-Tauri).
Mounted as TauriEffects inside JotaiProvider in App.tsx.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 17:32:38 -04:00
parent fcf16fd654
commit a9787ef041
2 changed files with 32 additions and 0 deletions
@@ -0,0 +1,25 @@
import { useEffect } from 'react';
import { useAtomValue } from 'jotai';
import { roomToUnreadAtom } from '../state/room/roomToUnread';
// Tauri v2 injects __TAURI_INTERNALS__ into the webview at runtime.
// We use it directly so cinny doesn't need @tauri-apps/api as a dependency.
type TauriInternals = { invoke: (cmd: string, args?: Record<string, unknown>) => Promise<unknown> };
const tauriInvoke = (): TauriInternals['invoke'] | undefined =>
(window as unknown as { __TAURI_INTERNALS__?: TauriInternals }).__TAURI_INTERNALS__?.invoke;
export function useTauriNotificationBadge() {
const roomToUnread = useAtomValue(roomToUnreadAtom);
useEffect(() => {
const invoke = tauriInvoke();
if (!invoke) return;
let totalHighlights = 0;
roomToUnread.forEach((unread) => {
totalHighlights += unread.highlight;
});
invoke('set_badge_count', { count: totalHighlights }).catch(() => {});
}, [roomToUnread]);
}