11import { useCallback , useEffect , useRef , useState } from "react" ;
2- import { BookOpenIcon , SendIcon } from "lucide-react" ;
2+ import { BookOpenIcon , ArrowUpIcon , SparklesIcon } from "lucide-react" ;
33import type { SmeConversationId , SmeMessage , SmeMessageId } from "@okcode/contracts" ;
44import { ensureNativeApi } from "~/nativeApi" ;
55import { useSmeStore } from "~/smeStore" ;
@@ -39,6 +39,14 @@ export function SmeChatWorkspace({
3939 messagesEndRef . current ?. scrollIntoView ( { behavior : "smooth" } ) ;
4040 } , [ messages , streamingText ] ) ;
4141
42+ // Auto-resize textarea
43+ useEffect ( ( ) => {
44+ const textarea = textareaRef . current ;
45+ if ( ! textarea ) return ;
46+ textarea . style . height = "auto" ;
47+ textarea . style . height = `${ Math . min ( textarea . scrollHeight , 200 ) } px` ;
48+ } , [ inputText ] ) ;
49+
4250 const handleSend = useCallback ( async ( ) => {
4351 if ( ! conversationId || ! inputText . trim ( ) || sending ) return ;
4452
@@ -106,29 +114,32 @@ export function SmeChatWorkspace({
106114
107115 if ( ! conversationId ) {
108116 return (
109- < div className = "flex h-full items-center justify-center" >
110- < div className = "space-y-3 text-center" >
111- < BookOpenIcon className = "mx-auto size-10 text-muted-foreground/20" />
112- < p className = "text-sm text-muted-foreground" >
113- Select a conversation or create a new one to start chatting
117+ < div className = "flex h-full flex-col items-center justify-center gap-4" >
118+ < div className = "flex size-14 items-center justify-center rounded-2xl bg-gradient-to-br from-primary/20 to-primary/5" >
119+ < SparklesIcon className = "size-7 text-primary/60" />
120+ </ div >
121+ < div className = "space-y-2 text-center" >
122+ < h3 className = "text-base font-medium text-foreground" > SME Chat</ h3 >
123+ < p className = "max-w-xs text-sm text-muted-foreground" >
124+ Select a conversation or create a new one to start chatting with your subject matter
125+ expert.
114126 </ p >
115127 </ div >
116128 </ div >
117129 ) ;
118130 }
119131
120132 return (
121- < div className = "flex h-full flex-col" >
122- { /* Header */ }
123- < div className = "flex items-center justify-between border-b border-border px-4 py-2" >
124- < span className = "text-sm font-medium text-foreground" > Conversation</ span >
133+ < div className = "flex h-full flex-col bg-background" >
134+ { /* Minimal Header */ }
135+ < div className = "flex items-center justify-end px-4 py-2" >
125136 < button
126137 type = "button"
127138 onClick = { onToggleKnowledge }
128- className = { `flex items-center gap-1.5 rounded-md px-2 py-1 text-xs transition-colors ${
139+ className = { `flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors ${
129140 knowledgePanelOpen
130- ? "bg-accent text-accent-foreground "
131- : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"
141+ ? "bg-primary/10 text-primary "
142+ : "text-muted-foreground hover:bg-muted hover:text-foreground"
132143 } `}
133144 >
134145 < BookOpenIcon className = "size-3.5" />
@@ -137,8 +148,8 @@ export function SmeChatWorkspace({
137148 </ div >
138149
139150 { /* Messages */ }
140- < div className = "flex-1 overflow-y-auto px-4 py-4 " >
141- < div className = "mx-auto max-w-3xl space-y-4 " >
151+ < div className = "flex-1 overflow-y-auto" >
152+ < div className = "mx-auto max-w-3xl" >
142153 { messages . map ( ( msg ) => (
143154 < SmeMessageBubble key = { msg . messageId } message = { msg } />
144155 ) ) }
@@ -158,39 +169,54 @@ export function SmeChatWorkspace({
158169 />
159170 ) : null }
160171 { sending && ! streamingText ? (
161- < div className = "flex items-center gap-2 py-2" >
162- < div className = "flex gap-1" >
163- < span className = "size-1.5 animate-bounce rounded-full bg-muted-foreground/40 [animation-delay:0ms]" />
164- < span className = "size-1.5 animate-bounce rounded-full bg-muted-foreground/40 [animation-delay:150ms]" />
165- < span className = "size-1.5 animate-bounce rounded-full bg-muted-foreground/40 [animation-delay:300ms]" />
172+ < div className = "flex items-center gap-4 px-4 py-5" >
173+ < div className = "flex size-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-primary/80 to-primary text-primary-foreground" >
174+ < SparklesIcon className = "size-4" />
175+ </ div >
176+ < div className = "space-y-1" >
177+ < p className = "text-xs font-medium text-muted-foreground" > SME Assistant</ p >
178+ < div className = "flex items-center gap-1.5" >
179+ < div className = "flex gap-1" >
180+ < span className = "size-1.5 animate-bounce rounded-full bg-muted-foreground/50 [animation-delay:0ms]" />
181+ < span className = "size-1.5 animate-bounce rounded-full bg-muted-foreground/50 [animation-delay:150ms]" />
182+ < span className = "size-1.5 animate-bounce rounded-full bg-muted-foreground/50 [animation-delay:300ms]" />
183+ </ div >
184+ < span className = "text-xs text-muted-foreground" > Thinking...</ span >
185+ </ div >
166186 </ div >
167- < span className = "text-xs text-muted-foreground" > Thinking...</ span >
168187 </ div >
169188 ) : null }
170189 < div ref = { messagesEndRef } />
171190 </ div >
172191 </ div >
173192
174- { /* Composer */ }
175- < div className = "border-t border-border px-4 py-3" >
176- < div className = "mx-auto flex max-w-3xl items-end gap-2" >
177- < textarea
178- ref = { textareaRef }
179- value = { inputText }
180- onChange = { ( e ) => setInputText ( e . target . value ) }
181- onKeyDown = { handleKeyDown }
182- placeholder = "Ask your subject matter expert..."
183- rows = { 1 }
184- className = "min-h-[36px] max-h-[200px] flex-1 resize-none rounded-lg border border-border bg-background px-3 py-2 text-sm outline-none focus:ring-1 focus:ring-ring"
185- />
186- < button
187- type = "button"
188- onClick = { ( ) => void handleSend ( ) }
189- disabled = { ! inputText . trim ( ) || sending }
190- className = "flex size-9 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
191- >
192- < SendIcon className = "size-4" />
193- </ button >
193+ { /* Modern Composer */ }
194+ < div className = "px-4 pb-4 pt-2" >
195+ < div className = "mx-auto max-w-3xl" >
196+ < div className = "relative flex items-end rounded-2xl border border-border bg-muted/30 shadow-sm transition-colors focus-within:border-ring focus-within:bg-muted/50" >
197+ < textarea
198+ ref = { textareaRef }
199+ value = { inputText }
200+ onChange = { ( e ) => setInputText ( e . target . value ) }
201+ onKeyDown = { handleKeyDown }
202+ placeholder = "Message your SME..."
203+ rows = { 1 }
204+ className = "max-h-[200px] min-h-[44px] flex-1 resize-none bg-transparent px-4 py-3 text-sm leading-relaxed outline-none placeholder:text-muted-foreground/60"
205+ />
206+ < div className = "flex items-center gap-1 p-2" >
207+ < button
208+ type = "button"
209+ onClick = { ( ) => void handleSend ( ) }
210+ disabled = { ! inputText . trim ( ) || sending }
211+ className = "flex size-8 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground transition-all hover:bg-primary/90 disabled:bg-muted-foreground/20 disabled:text-muted-foreground/40"
212+ >
213+ < ArrowUpIcon className = "size-4" />
214+ </ button >
215+ </ div >
216+ </ div >
217+ < p className = "mt-1.5 text-center text-[10px] text-muted-foreground/40" >
218+ SME can make mistakes. Verify important information.
219+ </ p >
194220 </ div >
195221 </ div >
196222 </ div >
0 commit comments