feat: add browser notifications and tab title badge for unread messages

When the tab is not focused:
- Tab title shows unread count: (3) PinchChat
- Browser notification with message preview (if permitted)
- Notifications collapse into one via tag
- Click notification to focus tab
- All clears when tab regains focus
- Permission requested on first user interaction
This commit is contained in:
Nicolas Varrot
2026-02-11 21:45:59 +00:00
parent d02009475b
commit 473d23c140
2 changed files with 95 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
import { useState, useEffect, useCallback } from 'react';
import { useState, useEffect, useCallback, useRef } from 'react';
import { useGateway } from './hooks/useGateway';
import { useNotifications } from './hooks/useNotifications';
import { Header } from './components/Header';
import { Sidebar } from './components/Sidebar';
import { Chat } from './components/Chat';
@@ -15,6 +16,21 @@ export default function App() {
} = useGateway();
const [sidebarOpen, setSidebarOpen] = useState(false);
const [shortcutsOpen, setShortcutsOpen] = useState(false);
const { notify } = useNotifications();
const prevMessageCountRef = useRef(messages.length);
// Notify on new assistant messages when tab is not focused
useEffect(() => {
const prevCount = prevMessageCountRef.current;
prevMessageCountRef.current = messages.length;
if (messages.length > prevCount) {
const last = messages[messages.length - 1];
if (last && last.role === 'assistant' && !last.isStreaming) {
const preview = last.content?.slice(0, 100) || 'New message';
notify('PinchChat', preview);
}
}
}, [messages, notify]);
// Close sidebar on Escape key, open shortcuts on ?
const handleKeyDown = useCallback((e: KeyboardEvent) => {