feat: implement new chat design

This commit is contained in:
Vukasin 2025-07-05 21:26:25 +02:00
parent b61620c6ca
commit f7fb080145
5 changed files with 52 additions and 43 deletions

View File

@ -329,21 +329,28 @@ export function HeroSection() {
<div className='flex items-center gap-2'> <div className='flex items-center gap-2'>
<ChatDropdown /> <ChatDropdown />
<Button <Tooltip>
type="submit" <TooltipTrigger asChild>
size="sm" <Button
className={cn( type="submit"
'w-8 h-8 flex-shrink-0 self-end rounded-xl', size="sm"
(!inputValue.trim() || isSubmitting) ? 'opacity-50' : '', className={cn(
)} 'w-8 h-8 flex-shrink-0 self-end rounded-xl',
disabled={!inputValue.trim() || isSubmitting} (!inputValue.trim() || isSubmitting) ? 'opacity-50' : '',
> )}
{isSubmitting ? ( disabled={!inputValue.trim() || isSubmitting}
<Square className="h-5 w-5" /> >
) : ( {isSubmitting ? (
<ArrowUp className="h-5 w-5" /> <Square className="h-5 w-5" />
)} ) : (
</Button> <ArrowUp className="h-5 w-5" />
)}
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Send message</p>
</TooltipContent>
</Tooltip>
</div> </div>
</div> </div>
</div> </div>

View File

@ -83,7 +83,7 @@ export function AttachmentGroup({
initial={{ opacity: 0, height: 0 }} initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }} animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }} exit={{ opacity: 0, height: 0 }}
className={layout === 'inline' ? "mb-3 py-1 px-0.5" : "mt-4"} className={layout === 'inline' ? "" : "mt-4"}
/> />
); );
} }
@ -277,9 +277,9 @@ export function AttachmentGroup({
} else { } else {
// For inline layout with pre-computed data // For inline layout with pre-computed data
return ( return (
<div className={cn("flex flex-wrap gap-3", className)} style={{ maxHeight }}> <div className={cn("flex flex-wrap gap-3", className)}>
{visibleFilesWithMeta.map((item, index) => ( {visibleFilesWithMeta.map((item, index) => (
<div key={index} className={cn("relative group", item.wrapperClassName)}> <div key={index} className={cn("relative group h-[54px]", item.wrapperClassName)}>
<FileAttachment <FileAttachment
filepath={item.path} filepath={item.path}
onClick={handleFileClick} onClick={handleFileClick}
@ -346,16 +346,18 @@ export function AttachmentGroup({
<AnimatePresence> <AnimatePresence>
<motion.div <motion.div
initial={{ opacity: 0, height: 0 }} initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }} animate={{
opacity: 1, height: 'auto'
}}
exit={{ opacity: 0, height: 0 }} exit={{ opacity: 0, height: 0 }}
className={layout === 'inline' ? "mb-3 py-1 px-0.5" : "mt-4"} className={layout === 'inline' ? "pt-1.5 px-1.5 pb-0" : "mt-4"}
> >
{renderContent()} {renderContent()}
</motion.div> </motion.div>
</AnimatePresence> </AnimatePresence >
{/* Modal dialog to show all files - conditionally rendered based on isModalOpen state */} {/* Modal dialog to show all files - conditionally rendered based on isModalOpen state */}
<Dialog open={isModalOpen} onOpenChange={setIsModalOpen}> < Dialog open={isModalOpen} onOpenChange={setIsModalOpen} >
<DialogContent className="max-w-3xl max-h-[80vh] overflow-y-auto"> <DialogContent className="max-w-3xl max-h-[80vh] overflow-y-auto">
<DialogHeader className="mb-1"> <DialogHeader className="mb-1">
<DialogTitle> <DialogTitle>
@ -481,7 +483,7 @@ export function AttachmentGroup({
})()} })()}
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog >
</> </>
); );
} }

View File

@ -238,12 +238,12 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
<FloatingToolPreview <FloatingToolPreview
toolCalls={toolCalls} toolCalls={toolCalls}
currentIndex={toolCallIndex} currentIndex={toolCallIndex}
onExpand={onExpandToolPreview || (() => {})} onExpand={onExpandToolPreview || (() => { })}
agentName={agentName} agentName={agentName}
isVisible={showToolPreview} isVisible={showToolPreview}
/> />
<Card <Card
className="-mb-2 bg-red-400 shadow-none w-full max-w-4xl mx-auto bg-transparent border-none rounded-xl overflow-hidden" className="-mb-2 bg-red-400 shadow-none w-full max-w-4xl mx-auto bg-transparent border-none rounded-3xl overflow-hidden"
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDragLeave={handleDragLeave} onDragLeave={handleDragLeave}
onDrop={(e) => { onDrop={(e) => {
@ -265,7 +265,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
}} }}
> >
<div className="w-full text-sm flex flex-col justify-between items-start rounded-lg"> <div className="w-full text-sm flex flex-col justify-between items-start rounded-lg">
<CardContent className={`w-full p-1.5 pb-2 ${bgColor} rounded-2xl border`}> <CardContent className={`w-full p-1.5 pb-2 ${bgColor} rounded-3xl border`}>
<AttachmentGroup <AttachmentGroup
files={uploadedFiles || []} files={uploadedFiles || []}
sandboxId={sandboxId} sandboxId={sandboxId}

View File

@ -249,9 +249,9 @@ export const FileUploadHandler = forwardRef<
<Button <Button
type="button" type="button"
onClick={handleFileUpload} onClick={handleFileUpload}
variant="ghost" variant="outline"
size="default" size="sm"
className="h-7 rounded-md text-muted-foreground" className="h-8 px-3 py-2 bg-transparent border border-border rounded-xl text-muted-foreground hover:text-foreground hover:bg-accent/50 flex items-center gap-2"
disabled={ disabled={
loading || (disabled && !isAgentRunning) || isUploading loading || (disabled && !isAgentRunning) || isUploading
} }
@ -261,6 +261,7 @@ export const FileUploadHandler = forwardRef<
) : ( ) : (
<Paperclip className="h-4 w-4" /> <Paperclip className="h-4 w-4" />
)} )}
<span className="text-sm">Attach</span>
</Button> </Button>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="top"> <TooltipContent side="top">

View File

@ -123,9 +123,9 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
}; };
return ( return (
<div className="relative flex flex-col w-full h-auto gap-4 justify-between"> <div className="relative flex flex-col w-full h-full gap-2 justify-between">
<div className="flex flex-col gap-2 items-center px-2"> <div className="flex flex-col gap-1 px-2">
<Textarea <Textarea
ref={ref} ref={ref}
value={value} value={value}
@ -133,16 +133,16 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder={placeholder} placeholder={placeholder}
className={cn( className={cn(
'w-full bg-transparent dark:bg-transparent border-none shadow-none focus-visible:ring-0 px-2 py-1 text-base min-h-[40px] max-h-[200px] overflow-y-auto resize-none', 'w-full bg-transparent dark:bg-transparent border-none shadow-none focus-visible:ring-0 px-0.5 pb-6 pt-4 !text-[15px] min-h-[36px] max-h-[200px] overflow-y-auto resize-none',
isDraggingOver ? 'opacity-40' : '', isDraggingOver ? 'opacity-40' : '',
)} )}
disabled={loading || (disabled && !isAgentRunning)} disabled={loading || (disabled && !isAgentRunning)}
rows={2} rows={1}
/> />
</div> </div>
<div className="flex items-center justify-between mt-1 ml-3 mb-1 pr-2"> <div className="flex items-center justify-between mt-0 mb-1 px-2">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
{!hideAttachments && ( {!hideAttachments && (
<FileUploadHandler <FileUploadHandler
@ -218,8 +218,7 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
onClick={isAgentRunning && onStopAgent ? onStopAgent : onSubmit} onClick={isAgentRunning && onStopAgent ? onStopAgent : onSubmit}
size="sm" size="sm"
className={cn( className={cn(
'w-7 h-7 flex-shrink-0 self-end', 'w-8 h-8 flex-shrink-0 self-end rounded-xl',
isAgentRunning ? 'bg-red-500 hover:bg-red-600' : '',
(!value.trim() && uploadedFiles.length === 0 && !isAgentRunning) || (!value.trim() && uploadedFiles.length === 0 && !isAgentRunning) ||
loading || loading ||
(disabled && !isAgentRunning) (disabled && !isAgentRunning)
@ -233,11 +232,11 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
} }
> >
{loading ? ( {loading ? (
<Loader2 className="h-4 w-4 animate-spin" /> <Loader2 className="h-5 w-5 animate-spin" />
) : isAgentRunning ? ( ) : isAgentRunning ? (
<Square className="h-4 w-4" /> <div className="min-h-[14px] min-w-[14px] w-[14px] h-[14px] rounded-sm bg-current" />
) : ( ) : (
<ArrowUp className="h-4 w-4" /> <ArrowUp className="h-5 w-5" />
)} )}
</Button> </Button>
</div> </div>