fixed nudges design

This commit is contained in:
Lucas Oliveira 2025-10-21 18:12:43 -03:00 committed by Mike Fortman
parent 3d56fd4932
commit ba4bf9adc4
2 changed files with 144 additions and 141 deletions

View file

@ -11,7 +11,7 @@ export default function Nudges({
handleSuggestionClick: (suggestion: string) => void; handleSuggestionClick: (suggestion: string) => void;
}) { }) {
return ( return (
<div className="flex-shrink-0 h-12 w-full overflow-hidden pl-10"> <div className="flex-shrink-0 h-12 w-full overflow-hidden">
<AnimatePresence> <AnimatePresence>
{nudges.length > 0 && ( {nudges.length > 0 && (
<motion.div <motion.div

View file

@ -92,7 +92,7 @@ function ChatPage() {
onComplete: (message, responseId) => { onComplete: (message, responseId) => {
setMessages((prev) => [...prev, message]); setMessages((prev) => [...prev, message]);
setLoading(false); setLoading(false);
if (responseId) { if (responseId) {
cancelNudges(); cancelNudges();
setPreviousResponseIds((prev) => ({ setPreviousResponseIds((prev) => ({
@ -739,7 +739,7 @@ function ChatPage() {
scrollToBottom({ scrollToBottom({
animation: "smooth", animation: "smooth",
duration: 1000, duration: 1000,
}); });
}; };
const handleSendMessage = async (inputMessage: string) => { const handleSendMessage = async (inputMessage: string) => {
@ -759,7 +759,7 @@ function ChatPage() {
scrollToBottom({ scrollToBottom({
animation: "smooth", animation: "smooth",
duration: 1000, duration: 1000,
}); });
if (asyncMode) { if (asyncMode) {
await handleSSEStream(userMessage); await handleSSEStream(userMessage);
@ -1109,146 +1109,148 @@ function ChatPage() {
} }
}; };
return (<> return (
{/* Debug header - only show in debug mode */} <>
{isDebugMode && ( {/* Debug header - only show in debug mode */}
<div className="flex items-center justify-between p-6"> {isDebugMode && (
<div className="flex items-center gap-2"></div> <div className="flex items-center justify-between p-6">
<div className="flex items-center gap-4"> <div className="flex items-center gap-2"></div>
{/* Async Mode Toggle */} <div className="flex items-center gap-4">
<div className="flex items-center gap-2 bg-muted/50 rounded-lg p-1"> {/* Async Mode Toggle */}
<Button <div className="flex items-center gap-2 bg-muted/50 rounded-lg p-1">
variant={!asyncMode ? "default" : "ghost"} <Button
size="sm" variant={!asyncMode ? "default" : "ghost"}
onClick={() => setAsyncMode(false)} size="sm"
className="h-7 text-xs" onClick={() => setAsyncMode(false)}
> className="h-7 text-xs"
Streaming Off >
</Button> Streaming Off
<Button </Button>
variant={asyncMode ? "default" : "ghost"} <Button
size="sm" variant={asyncMode ? "default" : "ghost"}
onClick={() => setAsyncMode(true)} size="sm"
className="h-7 text-xs" onClick={() => setAsyncMode(true)}
> className="h-7 text-xs"
<Zap className="h-3 w-3 mr-1" /> >
Streaming On <Zap className="h-3 w-3 mr-1" />
</Button> Streaming On
</div> </Button>
{/* Endpoint Toggle */} </div>
<div className="flex items-center gap-2 bg-muted/50 rounded-lg p-1"> {/* Endpoint Toggle */}
<Button <div className="flex items-center gap-2 bg-muted/50 rounded-lg p-1">
variant={endpoint === "chat" ? "default" : "ghost"} <Button
size="sm" variant={endpoint === "chat" ? "default" : "ghost"}
onClick={() => handleEndpointChange("chat")} size="sm"
className="h-7 text-xs" onClick={() => handleEndpointChange("chat")}
> className="h-7 text-xs"
Chat >
</Button> Chat
<Button </Button>
variant={endpoint === "langflow" ? "default" : "ghost"} <Button
size="sm" variant={endpoint === "langflow" ? "default" : "ghost"}
onClick={() => handleEndpointChange("langflow")} size="sm"
className="h-7 text-xs" onClick={() => handleEndpointChange("langflow")}
> className="h-7 text-xs"
Langflow >
</Button> Langflow
</div> </Button>
</div> </div>
</div> </div>
)} </div>
)}
<StickToBottom.Content className="flex flex-col min-h-full overflow-x-hidden p-6"> <StickToBottom.Content className="flex flex-col min-h-full overflow-x-hidden p-6">
<div className="flex flex-col place-self-center space-y-6 max-w-[960px] w-full mx-auto"> <div className="flex flex-col place-self-center space-y-6 max-w-[960px] w-full mx-auto">
{messages.length === 0 && !streamingMessage ? ( {messages.length === 0 && !streamingMessage ? (
<div className="flex items-center justify-center h-full text-muted-foreground"> <div className="flex items-center justify-center h-full text-muted-foreground">
<div className="text-center"> <div className="text-center">
{isUploading ? ( {isUploading ? (
<> <>
<Loader2 className="h-12 w-12 mx-auto mb-4 animate-spin" /> <Loader2 className="h-12 w-12 mx-auto mb-4 animate-spin" />
<p>Processing your document...</p> <p>Processing your document...</p>
<p className="text-sm mt-2"> <p className="text-sm mt-2">This may take a few moments</p>
This may take a few moments </>
</p> ) : null}
</>
) : null}
</div>
</div> </div>
) : ( </div>
<> ) : (
{messages.map((message, index) => ( <>
<div {messages.map((message, index) => (
key={`${ <div
message.role key={`${
}-${index}-${message.timestamp?.getTime()}`} message.role
className="space-y-6 group" }-${index}-${message.timestamp?.getTime()}`}
> className="space-y-6 group"
{message.role === "user" && ( >
<UserMessage content={message.content} /> {message.role === "user" && (
)} <UserMessage content={message.content} />
)}
{message.role === "assistant" && ( {message.role === "assistant" && (
<AssistantMessage <AssistantMessage
content={message.content} content={message.content}
functionCalls={message.functionCalls} functionCalls={message.functionCalls}
messageIndex={index} messageIndex={index}
expandedFunctionCalls={expandedFunctionCalls} expandedFunctionCalls={expandedFunctionCalls}
onToggle={toggleFunctionCall} onToggle={toggleFunctionCall}
showForkButton={endpoint === "chat"} showForkButton={endpoint === "chat"}
onFork={(e) => handleForkConversation(index, e)} onFork={(e) => handleForkConversation(index, e)}
/> />
)} )}
</div> </div>
))} ))}
{/* Streaming Message Display */} {/* Streaming Message Display */}
{streamingMessage && ( {streamingMessage && (
<AssistantMessage <AssistantMessage
content={streamingMessage.content} content={streamingMessage.content}
functionCalls={streamingMessage.functionCalls} functionCalls={streamingMessage.functionCalls}
messageIndex={messages.length} messageIndex={messages.length}
expandedFunctionCalls={expandedFunctionCalls} expandedFunctionCalls={expandedFunctionCalls}
onToggle={toggleFunctionCall} onToggle={toggleFunctionCall}
isStreaming isStreaming
/> />
)} )}
</> </>
)} )}
{!streamingMessage && ( {!streamingMessage && (
<div className="pl-10">
<Nudges <Nudges
nudges={loading ? [] : (nudges as string[])} nudges={loading ? [] : (nudges as string[])}
handleSuggestionClick={handleSuggestionClick} handleSuggestionClick={handleSuggestionClick}
/> />
)} </div>
</div> )}
</StickToBottom.Content> </div>
</StickToBottom.Content>
{/* Input Area - Fixed at bottom */} {/* Input Area - Fixed at bottom */}
<ChatInput <ChatInput
ref={chatInputRef} ref={chatInputRef}
input={input} input={input}
loading={loading} loading={loading}
isUploading={isUploading} isUploading={isUploading}
selectedFilter={selectedFilter} selectedFilter={selectedFilter}
isFilterDropdownOpen={isFilterDropdownOpen} isFilterDropdownOpen={isFilterDropdownOpen}
availableFilters={availableFilters} availableFilters={availableFilters}
filterSearchTerm={filterSearchTerm} filterSearchTerm={filterSearchTerm}
selectedFilterIndex={selectedFilterIndex} selectedFilterIndex={selectedFilterIndex}
anchorPosition={anchorPosition} anchorPosition={anchorPosition}
textareaHeight={textareaHeight} textareaHeight={textareaHeight}
parsedFilterData={parsedFilterData} parsedFilterData={parsedFilterData}
onSubmit={handleSubmit} onSubmit={handleSubmit}
onChange={onChange} onChange={onChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
onHeightChange={(height) => setTextareaHeight(height)} onHeightChange={(height) => setTextareaHeight(height)}
onFilterSelect={handleFilterSelect} onFilterSelect={handleFilterSelect}
onAtClick={onAtClick} onAtClick={onAtClick}
onFilePickerChange={handleFilePickerChange} onFilePickerChange={handleFilePickerChange}
onFilePickerClick={handleFilePickerClick} onFilePickerClick={handleFilePickerClick}
setSelectedFilter={setSelectedFilter} setSelectedFilter={setSelectedFilter}
setIsFilterHighlighted={setIsFilterHighlighted} setIsFilterHighlighted={setIsFilterHighlighted}
setIsFilterDropdownOpen={setIsFilterDropdownOpen} setIsFilterDropdownOpen={setIsFilterDropdownOpen}
/></> />
</>
); );
} }
@ -1256,14 +1258,15 @@ export default function ProtectedChatPage() {
return ( return (
<ProtectedRoute> <ProtectedRoute>
<div className="flex w-full h-full overflow-hidden"> <div className="flex w-full h-full overflow-hidden">
<StickToBottom <StickToBottom
className="flex h-full flex-1 flex-col" className="flex h-full flex-1 flex-col"
resize="smooth" resize="smooth"
initial="instant" initial="instant"
mass={1} mass={1}
> >
<ChatPage /> <ChatPage />
</StickToBottom></div> </StickToBottom>
</div>
</ProtectedRoute> </ProtectedRoute>
); );
} }