From 6d70c5f8a3ed90564b08616a3fb041409916059c Mon Sep 17 00:00:00 2001
From: Clawd <ai@clawd.bot>
Date: Sat, 28 Feb 2026 07:30:40 -0800
Subject: 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
---
 renderer/src/components/ChatPane.tsx | 66 ++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 renderer/src/components/ChatPane.tsx

(limited to 'renderer/src/components/ChatPane.tsx')

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 @@
+import React, { useState, useRef, useEffect } from "react";
+import type { Message } from "../types";
+
+interface ChatPaneProps {
+  messages: Message[];
+  onSend: (message: string) => void;
+  isLoading: boolean;
+  disabled: boolean;
+  placeholder: string;
+}
+
+export function ChatPane({
+  messages,
+  onSend,
+  isLoading,
+  disabled,
+  placeholder,
+}: ChatPaneProps) {
+  const [input, setInput] = useState("");
+  const messagesEndRef = useRef<HTMLDivElement>(null);
+
+  useEffect(() => {
+    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
+  }, [messages]);
+
+  const handleSend = () => {
+    if (!input.trim() || isLoading || disabled) return;
+    onSend(input.trim());
+    setInput("");
+  };
+
+  return (
+    <div className="chat-pane">
+      <div className="chat-messages">
+        {messages.map((msg) => (
+          <div key={msg.id} className={`message ${msg.role}`}>
+            <div className="message-content">{msg.content}</div>
+          </div>
+        ))}
+        {isLoading && (
+          <div className="message assistant loading">
+            <div className="message-content">Thinking...</div>
+          </div>
+        )}
+        <div ref={messagesEndRef} />
+      </div>
+
+      <div className="chat-input">
+        <input
+          type="text"
+          value={input}
+          onChange={(e) => setInput(e.target.value)}
+          onKeyDown={(e) => e.key === "Enter" && !e.shiftKey && handleSend()}
+          placeholder={placeholder}
+          disabled={disabled || isLoading}
+        />
+        <button
+          onClick={handleSend}
+          disabled={disabled || isLoading || !input.trim()}
+        >
+          Send
+        </button>
+      </div>
+    </div>
+  );
+}
-- 
cgit v1.2.3

