feat(app): daemon-sourced Event Center feed, read-model, bell badge

Source Event Center from daemon event_log (seed + live event/events_read push).
Unread/Errors tabs filter real EventRecord flags; bell shows numeric unread badge;
clicking an entry calls focusSurface + markEventsRead(ids). notify.ts param widened
to string so exit kind type-checks without breaking existing NOTIFY_STATES guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 08:23:26 +07:00
parent d08a446b6f
commit 834d61c69a
5 changed files with 113 additions and 53 deletions
+15 -2
View File
@@ -29,11 +29,12 @@ function IconBtn({ icon, onClick, active, title }: { icon: React.ReactNode; onCl
}
export function TopBar({
active, eventsOpen, onToggleEvents,
active, eventsOpen, onToggleEvents, unread,
}: {
active: WorkspaceView | null;
eventsOpen: boolean;
onToggleEvents: () => void;
unread: number;
}) {
return (
<div
@@ -68,7 +69,19 @@ export function TopBar({
<div style={{ display: "flex", alignItems: "center", gap: 6 }}>
<IconBtn icon={<PanelRight size={15} />} onClick={onToggleEvents} active={eventsOpen} title="Toggle Event Center" />
<IconBtn icon={<Search size={16} />} title="Search (mock)" />
<IconBtn icon={<Bell size={16} />} title="Notifications (mock)" />
<div style={{ position: "relative", display: "flex" }}>
<IconBtn icon={<Bell size={16} />} title="Notifications (mock)" />
{unread > 0 && (
<span style={{
position: "absolute", top: -2, right: -2, minWidth: 14, height: 14, padding: "0 3px",
borderRadius: 7, background: COLORS.stError, color: "#fff",
fontFamily: FONT.ui, fontSize: 9, fontWeight: 700,
display: "flex", alignItems: "center", justifyContent: "center", boxSizing: "border-box",
}}>
{unread > 99 ? "99+" : unread}
</span>
)}
</div>
<IconBtn icon={<Settings size={16} />} title="Settings (mock)" />
<span style={{ width: 1, height: 18, background: COLORS.borderStrong, margin: "0 2px" }} />
<button