SidebarMenuButton applies truncate via [&>span:last-child]:truncate,
so the text must be in a <span> rather than a bare text node to get
overflow-hidden + text-ellipsis + whitespace-nowrap.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Drop SidebarMenuAction (absolute positioning) in favor of a flex row:
left side (SidebarMenuButton) gets flex-1 min-w-0 for natural truncation,
right side (delete button) sits as a normal flex child with hover reveal.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cursor-not-allowed and reduced opacity to ChatInput when disabled
- Show user icon in empty state when no agent is selected
- Pass contextual placeholder text based on agent selection
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use CSS truncation for agent/hub IDs instead of JS slicing, show delete
button only on hover via showOnHover prop, and reduce contrast on status
dots, labels, and placeholder text for a more subtle appearance.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- hub-sidebar: displays Hub connection status, agent list with create/delete
- chat: sends messages via Gateway to Hub, receives agent responses, filters by active agent
- layout: passes HubSidebar as children to AppSidebar, removes static NAV_ITEMS
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
sonner is a dependency of @multica/ui, not web. Re-export toast from
the ui sonner module and update the import path in chat.tsx.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Display full UUID instead of truncated 8-char slice. Add ghost button
with copy icon that writes deviceId to clipboard, switches to checkmark
for 2s, and shows a sonner toast confirmation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move device ID logic from @multica/store (Zustand persist) into a
simple useDeviceId hook in the web app. SSR returns empty string,
client reads/writes localStorage directly — no hydration mismatch,
no suppressHydrationWarning needed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use CSS mask-image gradients to hint at scrollable overflow in the chat
area. Adds useScrollFade hook that dynamically applies top/bottom fade
based on scroll position via scroll events and ResizeObserver.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Zustand persist generates a new deviceId on the server (no localStorage),
then hydrates a different value from localStorage on the client. Add
suppressHydrationWarning to the deviceId span since this mismatch is expected.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create empty Chat component and wire it into the main page,
replacing the previous mock Markdown/ChatInput content.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>