--- phase: 21-chat-foundation plan: "04" subsystem: ui tags: [chat, context, components, layout, tdd] dependency_graph: requires: ["21-00", "21-02"] provides: [ChatPanelContext, ChatPanel, ChatInput, ChatMessage] affects: [Layout, main.tsx] tech_stack: added: [] patterns: [Context + hook pattern with localStorage persistence, TDD with jsdom+createRoot] key_files: created: - ui/src/context/ChatPanelContext.tsx - ui/src/components/ChatPanel.tsx - ui/src/components/ChatInput.tsx - ui/src/components/ChatMessage.tsx modified: - ui/src/components/ChatInput.test.tsx - ui/src/components/Layout.tsx - ui/src/main.tsx decisions: - ChatPanelProvider inserted inside PanelProvider so ChatPanel can call setPanelVisible to close PropertiesPanel on open - Chat toggle button placed in desktop sidebar bottom controls with hidden md:inline-flex (same cluster as settings and theme) - ChatMessage uses plain text for user role (no markdown) and ChatMarkdownMessage for assistant role metrics: duration: "~4 minutes" completed: "2026-04-01" tasks_completed: 2 files_created: 4 files_modified: 3 --- # Phase 21 Plan 04: Chat Panel Shell and Context Summary **One-liner:** Chat drawer shell with ChatPanelProvider (localStorage persistence), auto-resize ChatInput (Enter/Shift+Enter/Escape), ChatMessage bubbles, and Layout integration toggling PropertiesPanel closed on open. ## Tasks Completed | Task | Name | Commit | Files | |------|------|--------|-------| | 1 | Create ChatPanelContext, ChatInput, ChatMessage (TDD) | acfe2a7a | ChatPanelContext.tsx, ChatInput.tsx, ChatMessage.tsx, ChatInput.test.tsx | | 2 | Create ChatPanel shell and wire into Layout + main.tsx | b1c9dbfb | ChatPanel.tsx, Layout.tsx, main.tsx | ## What Was Built ### ChatPanelContext (ui/src/context/ChatPanelContext.tsx) Mirrors PanelContext pattern: - `STORAGE_KEY = "nexus:chat-panel-open"` — localStorage persistence - Default state: `false` (chat starts closed, unlike PropertiesPanel which defaults to visible) - Exports `ChatPanelProvider` and `useChatPanel` - Tracks `chatOpen`, `activeConversationId`, `setChatOpen`, `toggleChat`, `setActiveConversationId` ### ChatInput (ui/src/components/ChatInput.tsx) - `