diff options
| author | Clawd <ai@clawd.bot> | 2026-02-28 07:30:40 -0800 |
|---|---|---|
| committer | Clawd <ai@clawd.bot> | 2026-02-28 07:30:40 -0800 |
| commit | 6d70c5f8a3ed90564b08616a3fb041409916059c (patch) | |
| tree | 4c6480c5a606ab0a178dca72efa93c60ebe70c34 /renderer/src/components/ChatPane.tsx | |
| parent | 66f66d1c17213f55aa56d69c0cccc309b16f3362 (diff) | |
Phase 4: React UI
- Add renderer/src/types.ts with Project, Session, Message, Phase types
- Add renderer/src/styles/globals.css with full styling
- Dark theme with accent colors
- Header, document pane, chat pane, action bar layouts
- Phase indicator, token usage bar, buttons
- Add renderer/src/components/Header.tsx
- Project/session dropdowns with create buttons
- Phase indicator showing current workflow state
- Add renderer/src/components/DocumentPane.tsx
- Markdown viewer/editor with toggle
- Syntax highlighting for review comments
- Task checkbox rendering
- Add renderer/src/components/ChatPane.tsx
- Message list with auto-scroll
- Input field with Enter to send
- Loading state indicator
- Add renderer/src/components/ActionBar.tsx
- Token usage bar with color coding
- Review/Submit buttons for workflow
- Permission mode toggle for implement phase
- Add renderer/src/App.tsx
- Full state management for projects, sessions, messages
- Claude message subscription
- Workflow handlers (review, submit, phase advance)
- Update renderer/src/main.tsx to render App
Diffstat (limited to 'renderer/src/components/ChatPane.tsx')
| -rw-r--r-- | renderer/src/components/ChatPane.tsx | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/renderer/src/components/ChatPane.tsx b/renderer/src/components/ChatPane.tsx new file mode 100644 index 0000000..917d462 --- /dev/null +++ b/renderer/src/components/ChatPane.tsx | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | import React, { useState, useRef, useEffect } from "react"; | ||
| 2 | import type { Message } from "../types"; | ||
| 3 | |||
| 4 | interface ChatPaneProps { | ||
| 5 | messages: Message[]; | ||
| 6 | onSend: (message: string) => void; | ||
| 7 | isLoading: boolean; | ||
| 8 | disabled: boolean; | ||
| 9 | placeholder: string; | ||
| 10 | } | ||
| 11 | |||
| 12 | export function ChatPane({ | ||
| 13 | messages, | ||
| 14 | onSend, | ||
| 15 | isLoading, | ||
| 16 | disabled, | ||
| 17 | placeholder, | ||
| 18 | }: ChatPaneProps) { | ||
| 19 | const [input, setInput] = useState(""); | ||
| 20 | const messagesEndRef = useRef<HTMLDivElement>(null); | ||
| 21 | |||
| 22 | useEffect(() => { | ||
| 23 | messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); | ||
| 24 | }, [messages]); | ||
| 25 | |||
| 26 | const handleSend = () => { | ||
| 27 | if (!input.trim() || isLoading || disabled) return; | ||
| 28 | onSend(input.trim()); | ||
| 29 | setInput(""); | ||
| 30 | }; | ||
| 31 | |||
| 32 | return ( | ||
| 33 | <div className="chat-pane"> | ||
| 34 | <div className="chat-messages"> | ||
| 35 | {messages.map((msg) => ( | ||
| 36 | <div key={msg.id} className={`message ${msg.role}`}> | ||
| 37 | <div className="message-content">{msg.content}</div> | ||
| 38 | </div> | ||
| 39 | ))} | ||
| 40 | {isLoading && ( | ||
| 41 | <div className="message assistant loading"> | ||
| 42 | <div className="message-content">Thinking...</div> | ||
| 43 | </div> | ||
| 44 | )} | ||
| 45 | <div ref={messagesEndRef} /> | ||
| 46 | </div> | ||
| 47 | |||
| 48 | <div className="chat-input"> | ||
| 49 | <input | ||
| 50 | type="text" | ||
| 51 | value={input} | ||
| 52 | onChange={(e) => setInput(e.target.value)} | ||
| 53 | onKeyDown={(e) => e.key === "Enter" && !e.shiftKey && handleSend()} | ||
| 54 | placeholder={placeholder} | ||
| 55 | disabled={disabled || isLoading} | ||
| 56 | /> | ||
| 57 | <button | ||
| 58 | onClick={handleSend} | ||
| 59 | disabled={disabled || isLoading || !input.trim()} | ||
| 60 | > | ||
| 61 | Send | ||
| 62 | </button> | ||
| 63 | </div> | ||
| 64 | </div> | ||
| 65 | ); | ||
| 66 | } | ||
