lightswind
Version:
A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.
109 lines (108 loc) • 8.37 kB
JavaScript
// @ts-nocheck
"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useRef, useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Globe, Paperclip, Plus, Send } from "lucide-react";
import { cn } from "../../lib/utils";
import { Textarea } from "./textarea";
function useAutoResizeTextarea({ minHeight, maxHeight, }) {
const textareaRef = useRef(null);
const adjustHeight = useCallback((reset) => {
const textarea = textareaRef.current;
if (!textarea)
return;
if (reset) {
textarea.style.height = `${minHeight}px`;
return;
}
textarea.style.height = `${minHeight}px`;
const newHeight = Math.max(minHeight, Math.min(textarea.scrollHeight, maxHeight ?? Number.POSITIVE_INFINITY));
textarea.style.height = `${newHeight}px`;
}, [minHeight, maxHeight]);
useEffect(() => {
const textarea = textareaRef.current;
if (textarea) {
textarea.style.height = `${minHeight}px`;
}
}, [minHeight]);
useEffect(() => {
const handleResize = () => adjustHeight();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, [adjustHeight]);
return { textareaRef, adjustHeight };
}
const MIN_HEIGHT = 48;
const MAX_HEIGHT = 164;
const AnimatedPlaceholder = ({ showSearch }) => (_jsx(AnimatePresence, { mode: "wait", children: _jsx(motion.p, { initial: { opacity: 0, y: 5 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -5 }, transition: { duration: 0.1 }, className: "pointer-events-none w-[1500px] text-sm absolute \r\n text-black/70 dark:text-white/70", children: showSearch ? "Search the web..." : "Ask Skiper Ai..." }, showSearch ? "search" : "ask") }));
export function AiInput() {
const [value, setValue] = useState("");
const { textareaRef, adjustHeight } = useAutoResizeTextarea({
minHeight: MIN_HEIGHT,
maxHeight: MAX_HEIGHT,
});
const [showSearch, setShowSearch] = useState(true);
const [imagePreview, setImagePreview] = useState(null);
const fileInputRef = useRef(null);
const handelClose = (e) => {
e.preventDefault();
e.stopPropagation();
if (fileInputRef.current) {
fileInputRef.current.value = ""; // Reset file input
}
setImagePreview(null); // Use null instead of empty string
};
const handelChange = (e) => {
const file = e.target.files ? e.target.files[0] : null;
if (file) {
setImagePreview(URL.createObjectURL(file));
}
};
const handleSubmit = () => {
setValue("");
adjustHeight(true);
};
useEffect(() => {
return () => {
if (imagePreview) {
URL.revokeObjectURL(imagePreview);
}
};
}, [imagePreview]);
return (_jsx("div", { className: "mx-auto lg:min-w-[400px] w-full py-4", children: _jsx("div", { className: "relative max-w-xl border rounded-[22px] border-black/5 p-1 w-full mx-auto", children: _jsxs("div", { className: "relative rounded-2xl border border-black/5 bg-neutral-800/5 flex flex-col", children: [_jsx("div", { style: { maxHeight: `${MAX_HEIGHT}px` }, children: _jsxs("div", { className: "relative", children: [_jsx(Textarea, { id: "ai-input-04", value: value, placeholder: "", className: "w-full rounded-2xl rounded-b-none px-4 py-3 bg-black/5 dark:bg-white/5 border-none dark:text-white resize-none focus-visible:ring-0 leading-[1.2]", ref: textareaRef, onKeyDown: (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
handleSubmit();
}
}, onChange: (e) => {
setValue(e.target.value);
adjustHeight();
} }), !value && (_jsx("div", { className: "absolute left-4 top-3", children: _jsx(AnimatedPlaceholder, { showSearch: showSearch }) }))] }) }), _jsxs("div", { className: "h-12 bg-black/5 dark:bg-white/5 rounded-b-xl", children: [_jsxs("div", { className: "absolute left-3 bottom-3 flex items-center gap-2", children: [_jsxs("label", { className: cn("cursor-pointer relative rounded-full p-2 bg-black/5 dark:bg-white/5", imagePreview
? "bg-[#ff3f17]/15 border border-[#ff3f17] text-[#ff3f17]"
: "bg-black/5 dark:bg-white/5 text-black/40 dark:text-white/40 hover:text-black dark:hover:text-white"), children: [_jsx("input", { type: "file", ref: fileInputRef, onChange: handelChange, className: "hidden" }), _jsx(Paperclip, { className: cn("w-4 h-4 text-black/40 dark:text-white/40 hover:text-black dark:hover:text-white transition-colors", imagePreview && "text-[#ff3f17]") }), imagePreview && (_jsxs("div", { className: "absolute w-[100px] h-[100px] top-14 -left-4", children: [_jsx("img", { className: "object-cover rounded-2xl", src: imagePreview || "/picture1.jpeg", height: 500, width: 500, alt: "additional image" }), _jsx("button", { onClick: handelClose, className: "bg-[#e8e8e8] text-[#464646] absolute -top-1 -left-1 shadow-3xl rounded-full rotate-45", children: _jsx(Plus, { className: "w-4 h-4" }) })] }))] }), _jsxs("button", { type: "button", onClick: () => {
setShowSearch(!showSearch);
}, className: cn("rounded-full transition-all flex items-center gap-2 px-1.5 py-1 border h-8", showSearch
? "bg-[#ff3f17]/15 border-[#ff3f17] text-[#ff3f17]"
: "bg-black/5 dark:bg-white/5 border-transparent text-black/40 dark:text-white/40 hover:text-black dark:hover:text-white"), children: [_jsx("div", { className: "w-4 h-4 flex items-center justify-center flex-shrink-0", children: _jsx(motion.div, { animate: {
rotate: showSearch ? 180 : 0,
scale: showSearch ? 1.1 : 1,
}, whileHover: {
rotate: showSearch ? 180 : 15,
scale: 1.1,
transition: {
type: "spring",
stiffness: 300,
damping: 10,
},
}, transition: {
type: "spring",
stiffness: 260,
damping: 25,
}, children: _jsx(Globe, { className: cn("w-4 h-4", showSearch ? "text-[#ff3f17]" : "text-inherit") }) }) }), _jsx(AnimatePresence, { children: showSearch && (_jsx(motion.span, { initial: { width: 0, opacity: 0 }, animate: {
width: "auto",
opacity: 1,
}, exit: { width: 0, opacity: 0 }, transition: { duration: 0.2 }, className: "text-sm overflow-hidden whitespace-nowrap text-[#ff3f17] flex-shrink-0", children: "Search" })) })] })] }), _jsx("div", { className: "absolute right-3 bottom-3", children: _jsx("button", { type: "button", onClick: handleSubmit, className: cn("rounded-full p-2 transition-colors", value
? "bg-[#ff3f17]/15 text-[#ff3f17]"
: "bg-black/5 dark:bg-white/5 text-black/40 dark:text-white/40 hover:text-black dark:hover:text-white"), children: _jsx(Send, { className: "w-4 h-4" }) }) })] })] }) }) }));
}