diff --git a/apps/web/src/components/sme/SmeChatWorkspace.tsx b/apps/web/src/components/sme/SmeChatWorkspace.tsx
index d9c57db6c..2f888e4b4 100644
--- a/apps/web/src/components/sme/SmeChatWorkspace.tsx
+++ b/apps/web/src/components/sme/SmeChatWorkspace.tsx
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useRef, useState } from "react";
-import { BookOpenIcon, SendIcon } from "lucide-react";
+import { BookOpenIcon, ArrowUpIcon, SparklesIcon } from "lucide-react";
import type { SmeConversationId, SmeMessage, SmeMessageId } from "@okcode/contracts";
import { ensureNativeApi } from "~/nativeApi";
import { useSmeStore } from "~/smeStore";
@@ -39,6 +39,14 @@ export function SmeChatWorkspace({
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages, streamingText]);
+ // Auto-resize textarea
+ useEffect(() => {
+ const textarea = textareaRef.current;
+ if (!textarea) return;
+ textarea.style.height = "auto";
+ textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
+ }, [inputText]);
+
const handleSend = useCallback(async () => {
if (!conversationId || !inputText.trim() || sending) return;
@@ -106,11 +114,15 @@ export function SmeChatWorkspace({
if (!conversationId) {
return (
-
-
-
-
- Select a conversation or create a new one to start chatting
+
+
+
+
+
+
SME Chat
+
+ Select a conversation or create a new one to start chatting with your subject matter
+ expert.
@@ -118,17 +130,16 @@ export function SmeChatWorkspace({
}
return (
-
- {/* Header */}
-
-
Conversation
+
+ {/* Minimal Header */}
+
{/* Messages */}
-
-
+
+
{messages.map((msg) => (
))}
@@ -158,39 +169,54 @@ export function SmeChatWorkspace({
/>
) : null}
{sending && !streamingText ? (
-
-
-
-
-
+
+
+
+
+
+
SME Assistant
+
+
+
+
+
+
+
Thinking...
+
-
Thinking...
) : null}
- {/* Composer */}
-
-
diff --git a/apps/web/src/components/sme/SmeConversationRail.tsx b/apps/web/src/components/sme/SmeConversationRail.tsx
index 09451785c..0a110d0af 100644
--- a/apps/web/src/components/sme/SmeConversationRail.tsx
+++ b/apps/web/src/components/sme/SmeConversationRail.tsx
@@ -1,5 +1,5 @@
import { useCallback, useState } from "react";
-import { MessageSquarePlusIcon, TrashIcon } from "lucide-react";
+import { PlusIcon, TrashIcon, MessageSquareIcon } from "lucide-react";
import type { SmeConversationId } from "@okcode/contracts";
import type { Project } from "~/types";
@@ -55,14 +55,28 @@ export function SmeConversationRail({
);
return (
-
+
+ {/* Header with new chat button */}
+
+
{/* Project selector */}
{projects.length > 1 ? (
-
+
) : null}
- {/* New conversation button */}
-
-
-
-
{/* Conversation list */}
-
+
{conversations.length === 0 ? (
-
- No conversations yet
-
+
+
+
No conversations yet
+
) : (
{conversations.map((conv) => (
@@ -100,17 +102,17 @@ export function SmeConversationRail({
type="button"
onClick={() => setActiveConversationId(conv.conversationId)}
className={cn(
- "group flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs transition-colors",
+ "group flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-left text-[13px] transition-colors",
activeConversationId === conv.conversationId
- ? "bg-accent text-accent-foreground"
- : "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
+ ? "bg-muted text-foreground"
+ : "text-muted-foreground hover:bg-muted/60 hover:text-foreground",
)}
>
{conv.title}
diff --git a/apps/web/src/components/sme/SmeKnowledgePanel.tsx b/apps/web/src/components/sme/SmeKnowledgePanel.tsx
index 9dd4ba3de..72effce92 100644
--- a/apps/web/src/components/sme/SmeKnowledgePanel.tsx
+++ b/apps/web/src/components/sme/SmeKnowledgePanel.tsx
@@ -86,21 +86,21 @@ export function SmeKnowledgePanel({ project, onClose }: SmeKnowledgePanelProps)
);
return (
-
+
{/* Header */}
-
-
Knowledge Base
+
+ Knowledge Base
{/* Upload button */}
-
+
fileInputRef.current?.click()}
disabled={uploading}
- className="flex w-full items-center justify-center gap-2 rounded-md border border-dashed border-border px-3 py-2 text-xs text-muted-foreground transition-colors hover:border-foreground/30 hover:text-foreground disabled:opacity-50"
+ className="flex w-full items-center justify-center gap-2 rounded-xl border border-dashed border-border/60 px-3 py-3 text-xs text-muted-foreground transition-colors hover:border-primary/40 hover:bg-primary/5 hover:text-foreground disabled:opacity-50"
>
-
+
{uploading ? "Uploading..." : "Upload Document"}
-
+
.txt, .md, .json, .csv, .yaml, .html, .xml
@@ -125,29 +125,32 @@ export function SmeKnowledgePanel({ project, onClose }: SmeKnowledgePanelProps)
{/* Document list */}
{documents.length === 0 ? (
-
- No documents uploaded yet.
-
- Upload reference docs to give your SME context.
-
+
+
+
+ No documents uploaded yet.
+
+ Upload reference docs to give your SME context.
+
+
) : (
-
+
{documents.map((doc) => (
-
+
-
{doc.title}
-
+
{doc.title}
+
{doc.fileName} · {formatBytes(doc.sizeBytes)}
diff --git a/apps/web/src/components/sme/SmeMessageBubble.tsx b/apps/web/src/components/sme/SmeMessageBubble.tsx
index ac1ed4551..585631a33 100644
--- a/apps/web/src/components/sme/SmeMessageBubble.tsx
+++ b/apps/web/src/components/sme/SmeMessageBubble.tsx
@@ -1,4 +1,4 @@
-import { UserIcon, BotIcon } from "lucide-react";
+import { UserIcon, SparklesIcon } from "lucide-react";
import type { SmeMessage } from "@okcode/contracts";
import { cn } from "~/lib/utils";
@@ -11,31 +11,44 @@ export function SmeMessageBubble({ message }: SmeMessageBubbleProps) {
const isUser = message.role === "user";
return (
-
+
{/* Avatar */}
- {isUser ? : }
+ {isUser ? : }
- {/* Bubble */}
-
- {/* Render text with basic whitespace preservation */}
-
{message.text}
+ {/* Content */}
+
+
+ {isUser ? "You" : "SME Assistant"}
+
+
+
{message.text}
- {/* Streaming indicator */}
- {message.isStreaming ? (
-
- ) : null}
+ {/* Streaming cursor */}
+ {message.isStreaming ? (
+
+ ) : null}
+
);