Unified settings, Claude-style chat & instant history
Added
Unified Settings modal (components/settings/) in the Claude style:
centered dialog, left nav with General / AI Models / Connectors tabs.
General holds Profile (avatar, editable full name saved to Supabase user
metadata — the same name presence and cursors show, email), Preferences
(light/dark appearance, a new chat font choice — Sans or Serif — applied
to AI replies via lib/prefs.ts), and Sign out. AI Models and Connectors
are the old drawer contents re-homed. The modal stacks above the AI panel
and agent view (z 80), so opening settings no longer closes the chat or
agent mode; its Escape key is captured so it closes only itself. On phones
it becomes a full-screen sheet with a horizontal tab row.
Message timestamps. Chat messages now carry ts (client clock locally,
created_at from the DB for cloud threads — the /api/ai GET now returns
it as epoch ms). Threads render day dividers ("Today", "Jul 4"), small
per-message times, an "Updated 2m ago" in the agent header, and "2h ago"
recency labels on the agent sidebar's space rows.
Agent view chrome. The sidebar now leads with the ClipSpaces logo +
Agent badge and ends with an account chip (avatar initial, display name,
gear → Settings General; signed-out shows Sign in). The main header gains
the user's avatar button.
Changed
Claude-style message split. In both the compact popover and the agent
view, assistant replies are plain prose (no bubble, no border, optional
serif) and only the user's turns get a bubble — neutral elevated background
instead of the old accent-filled one.
The two right-side drawers are retired.AISettingsPanel.tsx and
IntegrationsPanel.tsx are deleted; the TopBar Connect button, the canvas
empty-state, and every AI-settings gear now open the Settings modal at the
right tab.
Fixed
Chat history no longer pops in all at once after the scan. The thread
and the board live in different stores by design (cards flow through the
canvas pipeline — IndexedDB/Realtime — while the conversation lives in
ai_messages behind auth/RLS), so history had to wait for a network fetch
that resolved behind the 2.6s minimum scan animation. Now every space
keeps a device-side thread cache (cloud spaces too): the last-known
conversation paints synchronously on open, the server copy reconciles in the
background (client-only meta like worked-for durations is preserved where
turns match), and the scan animation only plays when the board actually
changed and a fresh briefing is being generated.