feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
import { useState, useRef } from "react";
|
|
|
|
|
import { Send, Paperclip, X, FileText, Image, File } from "lucide-react";
|
2026-02-01 21:32:06 +07:00
|
|
|
import { Button } from "@/routes/ui/button";
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
import { cn } from "~/lib/utils";
|
|
|
|
|
|
|
|
|
|
export interface AttachedFile {
|
|
|
|
|
/** File ID */
|
|
|
|
|
id: string;
|
|
|
|
|
/** File name */
|
|
|
|
|
name: string;
|
|
|
|
|
/** File type */
|
|
|
|
|
type: string;
|
|
|
|
|
/** File size in bytes */
|
|
|
|
|
size: number;
|
|
|
|
|
/** File object */
|
|
|
|
|
file: File;
|
|
|
|
|
}
|
2026-02-01 21:32:06 +07:00
|
|
|
|
|
|
|
|
interface ChatInputProps {
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
/** Callback when message is sent */
|
|
|
|
|
onSend: (content: string, attachments?: AttachedFile[]) => void;
|
|
|
|
|
/** Whether input is disabled */
|
2026-02-01 21:32:06 +07:00
|
|
|
disabled?: boolean;
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
/** Placeholder text */
|
2026-02-01 21:32:06 +07:00
|
|
|
placeholder?: string;
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
/** Whether to show attachment button */
|
|
|
|
|
showAttachment?: boolean;
|
|
|
|
|
/** Accepted file types */
|
|
|
|
|
acceptedFileTypes?: string;
|
|
|
|
|
/** Max file size in bytes (default 10MB) */
|
|
|
|
|
maxFileSize?: number;
|
|
|
|
|
/** Quick action suggestions */
|
|
|
|
|
suggestions?: string[];
|
|
|
|
|
/** Callback when suggestion is clicked */
|
|
|
|
|
onSuggestionClick?: (suggestion: string) => void;
|
2026-02-01 21:32:06 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
* Enhanced chat input with attachment support and suggestions
|
|
|
|
|
*
|
|
|
|
|
* Features:
|
|
|
|
|
* - Text input with send button
|
|
|
|
|
* - File attachment button
|
|
|
|
|
* - Attached files preview
|
|
|
|
|
* - Quick action suggestions
|
|
|
|
|
* - Keyboard shortcuts (Enter to send)
|
2026-02-01 21:32:06 +07:00
|
|
|
*/
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
export function ChatInput({
|
|
|
|
|
onSend,
|
|
|
|
|
disabled,
|
|
|
|
|
placeholder,
|
|
|
|
|
showAttachment = true,
|
|
|
|
|
acceptedFileTypes = ".pdf,.txt,.md,.json,.csv,image/*",
|
|
|
|
|
maxFileSize = 10 * 1024 * 1024, // 10MB
|
|
|
|
|
suggestions = [],
|
|
|
|
|
onSuggestionClick,
|
|
|
|
|
}: ChatInputProps) {
|
2026-02-01 21:32:06 +07:00
|
|
|
const [input, setInput] = useState("");
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
const [attachments, setAttachments] = useState<AttachedFile[]>([]);
|
|
|
|
|
const [dragOver, setDragOver] = useState(false);
|
|
|
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
2026-02-01 21:32:06 +07:00
|
|
|
|
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
|
|
|
e.preventDefault();
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
if ((input.trim() || attachments.length > 0) && !disabled) {
|
|
|
|
|
onSend(input.trim(), attachments.length > 0 ? attachments : undefined);
|
2026-02-01 21:32:06 +07:00
|
|
|
setInput("");
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
setAttachments([]);
|
2026-02-01 21:32:06 +07:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
const handleFileSelect = (files: FileList | null) => {
|
|
|
|
|
if (!files) return;
|
|
|
|
|
|
|
|
|
|
const newAttachments: AttachedFile[] = [];
|
|
|
|
|
|
|
|
|
|
Array.from(files).forEach(file => {
|
|
|
|
|
// Check file size
|
|
|
|
|
if (file.size > maxFileSize) {
|
|
|
|
|
console.warn(`File ${file.name} exceeds max size of ${maxFileSize / 1024 / 1024}MB`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newAttachments.push({
|
|
|
|
|
id: `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
|
|
|
name: file.name,
|
|
|
|
|
type: file.type,
|
|
|
|
|
size: file.size,
|
|
|
|
|
file,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setAttachments(prev => [...prev, ...newAttachments]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleRemoveAttachment = (id: string) => {
|
|
|
|
|
setAttachments(prev => prev.filter(a => a.id !== id));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDragOver = (e: React.DragEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setDragOver(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDragLeave = (e: React.DragEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setDragOver(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDrop = (e: React.DragEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setDragOver(false);
|
|
|
|
|
handleFileSelect(e.dataTransfer.files);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getFileIcon = (type: string) => {
|
|
|
|
|
if (type.startsWith("image/")) return Image;
|
|
|
|
|
if (type.includes("pdf") || type.includes("text")) return FileText;
|
|
|
|
|
return File;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const formatFileSize = (bytes: number) => {
|
|
|
|
|
if (bytes < 1024) return `${bytes} B`;
|
|
|
|
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
|
|
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-01 21:32:06 +07:00
|
|
|
return (
|
feat(crypto): add SurfSense 2.0 Crypto Co-Pilot UI components
Frontend - Web Dashboard:
- Add crypto dashboard page with Watchlist, Alerts, Market, Profile tabs
- Add 11 tool-ui components for inline chat display
- Add crypto components (ChainIcon, SafetyBadge, PriceDisplay, etc.)
- Add modals (AddTokenModal, CreateAlertModal)
- Add mock data for development
Frontend - Browser Extension:
- Add shared components (ChainIcon, RiskBadge, PriceDisplay, SuggestionCard)
- Add crypto components (SafetyScoreDisplay, WatchlistPanel, AlertConfigModal)
- Add chat enhancements (WelcomeScreen, ThinkingStepsDisplay)
- Add widget components for inline display
- Enhance TokenInfoCard, ChatHeader, ChatInput, ChatInterface
Documentation:
- Add conversational UX specification
- Add UX analysis report
- Update extension UX design
This implements the Conversational UX paradigm where crypto features
are AI-callable tools that render inline in the chat interface.
2026-02-04 02:19:57 +07:00
|
|
|
<div className="border-t">
|
|
|
|
|
{/* Quick suggestions */}
|
|
|
|
|
{suggestions.length > 0 && input.length === 0 && attachments.length === 0 && (
|
|
|
|
|
<div className="px-3 pt-2 flex gap-2 flex-wrap">
|
|
|
|
|
{suggestions.slice(0, 3).map((suggestion, index) => (
|
|
|
|
|
<button
|
|
|
|
|
key={index}
|
|
|
|
|
className="text-xs px-2 py-1 rounded-full bg-muted hover:bg-muted/80 text-muted-foreground transition-colors"
|
|
|
|
|
onClick={() => onSuggestionClick?.(suggestion)}
|
|
|
|
|
>
|
|
|
|
|
{suggestion}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Attached files preview */}
|
|
|
|
|
{attachments.length > 0 && (
|
|
|
|
|
<div className="px-3 pt-2 flex gap-2 flex-wrap">
|
|
|
|
|
{attachments.map((attachment) => {
|
|
|
|
|
const FileIcon = getFileIcon(attachment.type);
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
key={attachment.id}
|
|
|
|
|
className="flex items-center gap-1.5 px-2 py-1 rounded-md bg-muted text-sm group"
|
|
|
|
|
>
|
|
|
|
|
<FileIcon className="h-3.5 w-3.5 text-muted-foreground" />
|
|
|
|
|
<span className="max-w-[100px] truncate">{attachment.name}</span>
|
|
|
|
|
<span className="text-xs text-muted-foreground">
|
|
|
|
|
({formatFileSize(attachment.size)})
|
|
|
|
|
</span>
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => handleRemoveAttachment(attachment.id)}
|
|
|
|
|
className="ml-1 p-0.5 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<X className="h-3 w-3" />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Input form */}
|
|
|
|
|
<form
|
|
|
|
|
onSubmit={handleSubmit}
|
|
|
|
|
className={cn(
|
|
|
|
|
"p-3 transition-colors",
|
|
|
|
|
dragOver && "bg-primary/5"
|
|
|
|
|
)}
|
|
|
|
|
onDragOver={handleDragOver}
|
|
|
|
|
onDragLeave={handleDragLeave}
|
|
|
|
|
onDrop={handleDrop}
|
|
|
|
|
>
|
|
|
|
|
<div className="flex items-end gap-2">
|
|
|
|
|
{/* Attachment button */}
|
|
|
|
|
{showAttachment && (
|
|
|
|
|
<>
|
|
|
|
|
<input
|
|
|
|
|
ref={fileInputRef}
|
|
|
|
|
type="file"
|
|
|
|
|
multiple
|
|
|
|
|
accept={acceptedFileTypes}
|
|
|
|
|
onChange={(e) => handleFileSelect(e.target.files)}
|
|
|
|
|
className="hidden"
|
|
|
|
|
/>
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon"
|
|
|
|
|
className="h-9 w-9 flex-shrink-0"
|
|
|
|
|
onClick={() => fileInputRef.current?.click()}
|
|
|
|
|
disabled={disabled}
|
|
|
|
|
title="Attach files"
|
|
|
|
|
>
|
|
|
|
|
<Paperclip className="h-4 w-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Text input */}
|
|
|
|
|
<div className="flex-1 relative">
|
|
|
|
|
<textarea
|
|
|
|
|
value={input}
|
|
|
|
|
onChange={(e) => setInput(e.target.value)}
|
|
|
|
|
onKeyDown={(e) => {
|
|
|
|
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
handleSubmit(e);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
placeholder={placeholder || "Type a message..."}
|
|
|
|
|
disabled={disabled}
|
|
|
|
|
rows={1}
|
|
|
|
|
className={cn(
|
|
|
|
|
"w-full px-3 py-2 border rounded-md bg-background text-sm",
|
|
|
|
|
"focus:outline-none focus:ring-2 focus:ring-primary",
|
|
|
|
|
"resize-none min-h-[38px] max-h-[120px]",
|
|
|
|
|
"scrollbar-thin scrollbar-thumb-muted"
|
|
|
|
|
)}
|
|
|
|
|
style={{
|
|
|
|
|
height: "auto",
|
|
|
|
|
minHeight: "38px",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Send button */}
|
|
|
|
|
<Button
|
|
|
|
|
type="submit"
|
|
|
|
|
size="icon"
|
|
|
|
|
className="h-9 w-9 flex-shrink-0"
|
|
|
|
|
disabled={disabled || (!input.trim() && attachments.length === 0)}
|
|
|
|
|
>
|
|
|
|
|
<Send className="h-4 w-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Drag hint */}
|
|
|
|
|
{dragOver && (
|
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center bg-primary/10 rounded-md border-2 border-dashed border-primary pointer-events-none">
|
|
|
|
|
<p className="text-sm text-primary font-medium">Drop files here</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
2026-02-01 21:32:06 +07:00
|
|
|
);
|
|
|
|
|
}
|