Buckets:
techprotrade/LuunaOS / NEXUS_AI.pro /pixel-perfect-pixels-main /src /components /chat /ChatInput.tsx
| import { useState, useRef, useEffect } from "react"; | |
| import { motion } from "framer-motion"; | |
| import { Send, Sparkles } from "lucide-react"; | |
| import { cn } from "@/lib/utils"; | |
| interface ChatInputProps { | |
| onSend: (message: string) => void; | |
| isLoading?: boolean; | |
| placeholder?: string; | |
| } | |
| export const ChatInput = ({ | |
| onSend, | |
| isLoading = false, | |
| placeholder = "Command NEXUS...", | |
| }: ChatInputProps) => { | |
| const [input, setInput] = useState(""); | |
| const textareaRef = useRef<HTMLTextAreaElement>(null); | |
| useEffect(() => { | |
| if (textareaRef.current) { | |
| textareaRef.current.style.height = "auto"; | |
| textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 200)}px`; | |
| } | |
| }, [input]); | |
| const handleSubmit = () => { | |
| if (!input.trim() || isLoading) return; | |
| onSend(input.trim()); | |
| setInput(""); | |
| if (textareaRef.current) textareaRef.current.style.height = "auto"; | |
| }; | |
| const handleKeyDown = (e: React.KeyboardEvent) => { | |
| if (e.key === "Enter" && !e.shiftKey) { | |
| e.preventDefault(); | |
| handleSubmit(); | |
| } | |
| }; | |
| return ( | |
| <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="relative"> | |
| <div className="relative bg-card border border-border rounded-xl overflow-hidden focus-within:border-primary/50 focus-within:glow-cyan transition-all duration-300"> | |
| <div className="flex items-end"> | |
| <textarea | |
| ref={textareaRef} | |
| value={input} | |
| onChange={(e) => setInput(e.target.value)} | |
| onKeyDown={handleKeyDown} | |
| placeholder={placeholder} | |
| disabled={isLoading} | |
| rows={1} | |
| className="flex-1 bg-transparent px-4 py-3.5 text-sm text-foreground placeholder:text-muted-foreground resize-none focus:outline-none min-h-[50px] max-h-[200px]" | |
| /> | |
| <div className="flex items-center gap-2 p-2"> | |
| <button | |
| onClick={handleSubmit} | |
| disabled={!input.trim() || isLoading} | |
| className={cn( | |
| "p-2.5 rounded-lg transition-all duration-300", | |
| input.trim() && !isLoading | |
| ? "bg-gradient-cyber text-primary-foreground glow-cyan hover:glow-cyan-strong" | |
| : "bg-secondary text-muted-foreground cursor-not-allowed" | |
| )} | |
| > | |
| {isLoading ? <Sparkles size={18} className="animate-pulse" /> : <Send size={18} />} | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <p className="text-center text-[10px] text-muted-foreground mt-2 font-mono tracking-wider"> | |
| NEXUS-AI • Neural Extended Universal System • ⌘K for commands | |
| </p> | |
| </motion.div> | |
| ); | |
| }; | |
Xet Storage Details
- Size:
- 2.74 kB
- Xet hash:
- 369273fae3c0aadc44727aca12e174d808f06da479919ebd79796ccb9cf28a3d
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.