chore(ui): update input box

This commit is contained in:
Soumyadas15 2025-05-06 11:29:31 +05:30
parent d6de70878a
commit 0ec8235d5c
5 changed files with 136 additions and 88 deletions

View File

@ -205,12 +205,12 @@ function DashboardContent() {
</div>
)}
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-[560px] max-w-[90%]">
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-[650px] max-w-[90%]">
<div className="flex flex-col items-center text-center mb-2 w-full">
<h1 className={cn('tracking-tight text-4xl font-bold leading-tight')}>
Welcome to <span className={cn(secondaryGradient)}>Suna</span>
<h1 className={cn('tracking-tight text-4xl font-semibold leading-tight')}>
Hey
</h1>
<p className="tracking-tight text-3xl font-semibold text-muted-foreground/80 mt-2 flex items-center gap-2">
<p className="tracking-tight text-3xl font-normal text-muted-foreground/80 mt-2 flex items-center gap-2">
What would you like Suna to do today?
</p>
</div>

View File

@ -10,10 +10,9 @@ import React, {
import { motion } from 'framer-motion';
import { Loader2 } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { FileUploadHandler, handleFiles } from './file-upload-handler';
import { handleFiles } from './file-upload-handler';
import { MessageInput } from './message-input';
import { UploadedFilesDisplay } from './uploaded-file-display';
import { ModelSelector } from './model-selector';
import { useModelSelection } from './_use-model-selection';
export interface ChatInputHandles {
@ -167,9 +166,9 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
};
return (
<div className="mx-auto w-full max-w-3xl px-4">
<div className="mx-auto w-full max-w-4xl px-4">
<Card
className="shadow-none w-full max-w-3xl mx-auto bg-transparent border-none rounded-xl overflow-hidden"
className="shadow-none w-full max-w-4xl mx-auto bg-transparent border-none rounded-xl overflow-hidden"
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={(e) => {
@ -190,7 +189,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
}}
>
<div className="w-full bg-muted/30 text-sm flex flex-col justify-between items-start rounded-lg border-b">
<CardContent className="shadow w-full p-1.5 pb-2 pt-3 bg-background rounded-2xl border">
<CardContent className="shadow w-full p-1.5 pb-2 pt-3 bg-sidebar rounded-2xl border">
<UploadedFilesDisplay
uploadedFiles={uploadedFiles}
sandboxId={sandboxId}
@ -209,33 +208,21 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
onStopAgent={onStopAgent}
isDraggingOver={isDraggingOver}
uploadedFiles={uploadedFiles}
fileInputRef={fileInputRef}
isUploading={isUploading}
sandboxId={sandboxId}
setPendingFiles={setPendingFiles}
setUploadedFiles={setUploadedFiles}
setIsUploading={setIsUploading}
hideAttachments={hideAttachments}
selectedModel={selectedModel}
onModelChange={handleModelChange}
modelOptions={modelOptions}
currentTier={subscriptionTier}
canAccessModel={canAccessModel}
/>
<div className="flex items-center justify-start mt-3 ml-3">
<div className="flex items-center gap-3">
{!hideAttachments && (
<FileUploadHandler
ref={fileInputRef}
loading={loading}
disabled={disabled}
isAgentRunning={isAgentRunning}
isUploading={isUploading}
sandboxId={sandboxId}
setPendingFiles={setPendingFiles}
setUploadedFiles={setUploadedFiles}
setIsUploading={setIsUploading}
/>
)}
<ModelSelector
selectedModel={selectedModel}
onModelChange={handleModelChange}
modelOptions={modelOptions}
currentTier={subscriptionTier}
canAccessModel={canAccessModel}
/>
</div>
</div>
</CardContent>
</div>
</Card>
@ -257,4 +244,4 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
},
);
ChatInput.displayName = 'ChatInput';
ChatInput.displayName = 'ChatInput';

View File

@ -188,8 +188,8 @@ export const FileUploadHandler = forwardRef<
type="button"
onClick={handleFileUpload}
variant="ghost"
size="sm"
className="h-7 rounded-md text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"
size="default"
className="h-7 rounded-md text-muted-foreground"
disabled={
loading || (disabled && !isAgentRunning) || isUploading
}
@ -199,7 +199,7 @@ export const FileUploadHandler = forwardRef<
) : (
<Paperclip className="h-4 w-4" />
)}
<span className="text-xs">Attachments</span>
<span className="text-sm">Attachments</span>
</Button>
</TooltipTrigger>
<TooltipContent side="top">
@ -220,8 +220,5 @@ export const FileUploadHandler = forwardRef<
},
);
// For easier access from other components
FileUploadHandler.displayName = 'FileUploadHandler';
// Export the helper functions for use in other components
export { handleFiles, handleLocalFiles, uploadFiles };

View File

@ -1,11 +1,12 @@
'use client';
import React, { forwardRef, useEffect } from 'react';
import { Textarea } from '@/components/ui/textarea';
import { Button } from '@/components/ui/button';
import { Square, Loader2, ArrowUp } from 'lucide-react';
import { cn } from '@/lib/utils';
import { UploadedFile } from './chat-input';
import { FileUploadHandler } from './file-upload-handler';
import { ModelSelector } from './model-selector';
import { useModelSelection } from './_use-model-selection';
interface MessageInputProps {
value: string;
@ -18,6 +19,20 @@ interface MessageInputProps {
onStopAgent?: () => void;
isDraggingOver: boolean;
uploadedFiles: UploadedFile[];
fileInputRef: React.RefObject<HTMLInputElement>;
isUploading: boolean;
sandboxId?: string;
setPendingFiles: React.Dispatch<React.SetStateAction<File[]>>;
setUploadedFiles: React.Dispatch<React.SetStateAction<UploadedFile[]>>;
setIsUploading: React.Dispatch<React.SetStateAction<boolean>>;
hideAttachments?: boolean;
selectedModel: string;
onModelChange: (model: string) => void;
modelOptions: any[];
currentTier: string;
canAccessModel: (model: string) => boolean;
}
export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
@ -33,6 +48,20 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
onStopAgent,
isDraggingOver,
uploadedFiles,
fileInputRef,
isUploading,
sandboxId,
setPendingFiles,
setUploadedFiles,
setIsUploading,
hideAttachments = false,
selectedModel,
onModelChange,
modelOptions,
currentTier,
canAccessModel,
},
ref,
) => {
@ -58,6 +87,10 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
return () => window.removeEventListener('resize', adjustHeight);
}, [value, ref]);
const {
subscriptionTier,
} = useModelSelection();
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
@ -72,50 +105,81 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
};
return (
<div className="flex gap-2 px-2">
<Textarea
ref={ref}
value={value}
onChange={onChange}
onKeyDown={handleKeyDown}
placeholder={placeholder}
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',
isDraggingOver ? 'opacity-40' : '',
)}
disabled={loading || (disabled && !isAgentRunning)}
rows={2}
/>
<Button
type="submit"
onClick={isAgentRunning && onStopAgent ? onStopAgent : onSubmit}
size="icon"
className={cn(
'flex-shrink-0 self-end',
isAgentRunning ? 'bg-red-500 hover:bg-red-600' : '',
(!value.trim() && uploadedFiles.length === 0 && !isAgentRunning) ||
loading ||
(disabled && !isAgentRunning)
? 'opacity-50'
: '',
)}
disabled={
(!value.trim() && uploadedFiles.length === 0 && !isAgentRunning) ||
loading ||
(disabled && !isAgentRunning)
}
>
{loading ? (
<Loader2 className="h-5 w-5 animate-spin" />
) : isAgentRunning ? (
<Square className="h-5 w-5" />
) : (
<ArrowUp className="h-5 w-5" />
)}
</Button>
<div className="flex flex-col w-full h-auto gap-4 justify-between">
<div className="flex gap-2 items-center px-2">
<Textarea
ref={ref}
value={value}
onChange={onChange}
onKeyDown={handleKeyDown}
placeholder={placeholder}
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',
isDraggingOver ? 'opacity-40' : '',
)}
disabled={loading || (disabled && !isAgentRunning)}
rows={2}
/>
</div>
<div className="flex items-center justify-between mt-1 ml-3 mb-1 pr-2">
<div className="flex items-center gap-3">
{!hideAttachments && (
<FileUploadHandler
ref={fileInputRef}
loading={loading}
disabled={disabled}
isAgentRunning={isAgentRunning}
isUploading={isUploading}
sandboxId={sandboxId}
setPendingFiles={setPendingFiles}
setUploadedFiles={setUploadedFiles}
setIsUploading={setIsUploading}
/>
)}
</div>
<div className='flex items-center gap-2'>
<ModelSelector
selectedModel={selectedModel}
onModelChange={onModelChange}
modelOptions={modelOptions}
currentTier={subscriptionTier}
canAccessModel={canAccessModel}
/>
<Button
type="submit"
onClick={isAgentRunning && onStopAgent ? onStopAgent : onSubmit}
size="sm"
className={cn(
'w-7 h-7 flex-shrink-0 self-end',
isAgentRunning ? 'bg-red-500 hover:bg-red-600' : '',
(!value.trim() && uploadedFiles.length === 0 && !isAgentRunning) ||
loading ||
(disabled && !isAgentRunning)
? 'opacity-50'
: '',
)}
disabled={
(!value.trim() && uploadedFiles.length === 0 && !isAgentRunning) ||
loading ||
(disabled && !isAgentRunning)
}
>
{loading ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : isAgentRunning ? (
<Square className="h-4 w-4" />
) : (
<ArrowUp className="h-4 w-4" />
)}
</Button>
</div>
</div>
</div>
);
},
);
MessageInput.displayName = 'MessageInput';
MessageInput.displayName = 'MessageInput';

View File

@ -64,10 +64,10 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="sm"
size='default'
className="h-7 rounded-md text-muted-foreground shadow-none border-none focus:ring-0 w-auto px-2 py-0"
>
<div className="flex items-center gap-1 text-xs">
<div className="flex items-center gap-1 text-sm">
<span>{selectedModelLabel}</span>
<ChevronDown className="h-3 w-3 opacity-50" />
</div>