Files
test/src/components/interaction-panel/chat.tsx
2025-07-20 20:03:29 +03:00

134 lines
4.0 KiB
TypeScript

import { observer } from "mobx-react-lite";
import { useRef, useState } from "react";
import Arrow from "@/icons/arrow.svg?react";
import Paperclip from "@/icons/paperclip.svg?react";
import Clock from "@/icons/clock.svg?react";
import { cn } from "@/lib/utils";
const Chat = observer(() => {
return (
<div className="flex-1 h-full flex items-center justify-center">
<WelcomePanel />
</div>
);
});
const WelcomePanel = () => {
return (
<div className="max-w-[741px] flex flex-col gap-8">
<div className="flex flex-col gap-2 font-medium">
<span className="leading-[120%] text-black text-[24px]">
Hi!
<br /> I will help you create a crypto project on Cytonic
</span>
<span className="text-[#C0C0C0] text-[14px] flex gap-2 items-center">
<Clock />
<p>Estimated build time: 3 minutes</p>
</span>
</div>
<div className="flex flex-col gap-4">
<p className="text-[#C0C0C0] text-[14px] font-medium leading-[120%]">
Choose one of the most common prompts
<br /> below or use your own to begin
</p>
<div className="flex gap-4">
{[
{ emoji: "🐶", text: "Build a memecoin launchpad" },
{ emoji: "🏦", text: "Build a new stablecoin protocol" },
{ emoji: "🌐", text: "Create a RWA marketplace on Cytonic" },
{ emoji: "📊", text: "Ship a token dashboard" },
].map(({ emoji, text }) => (
<button
type="button"
key={emoji}
className="text-left cursor-pointer hover:bg-fill-100 transition-all w-[173px] h-[123px] p-4 rounded-[16px] border border-[#E8E8E8] flex flex-col justify-between"
>
<p className="text-[14px] font-medium leading-[120%]">{text}</p>
<div className="text-[24px] leading-[100%]">{emoji}</div>
</button>
))}
</div>
<ChatInput />
</div>
</div>
);
};
const ChatInput = () => {
const [message, setMessage] = useState("");
const [showShadow, setShowShadow] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const handleInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const el = e.target;
setMessage(el.value);
el.style.height = "auto";
el.style.height = `${Math.min(el.scrollHeight, 200)}px`;
setShowShadow(el.scrollTop + el.clientHeight < el.scrollHeight);
};
const handleScroll = () => {
const el = textareaRef.current;
if (!el) return;
setShowShadow(el.scrollTop + el.clientHeight < el.scrollHeight);
};
return (
<div
className="relative border border-[#E8E8E8] rounded-[16px] pt-4 pb-2 pl-4 pr-2 flex flex-col justify-between transition-all duration-200"
style={{
boxShadow: "0px 1px 8px 0px #00000012",
}}
>
<div className="relative">
<textarea
ref={textareaRef}
onInput={handleInput}
onScroll={handleScroll}
className="text-[14px] placeholder:text-[#818181] focus:outline-none overflow-y-auto min-h-[40px] max-h-[150px] resize-none w-full pr-4"
placeholder="Ask whatever you want..."
value={message}
rows={1}
/>
<div
className={cn(
"absolute left-0 bottom-0 w-full h-5 pointer-events-none transition-opacity duration-300",
showShadow ? "opacity-100" : "opacity-0",
)}
style={{
background:
"linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,0.95), #ffffff)",
}}
/>
</div>
<div className="flex justify-between items-center mt-2">
<div className="flex gap-6">
<span className="flex gap-2 items-center cursor-pointer">
<Paperclip />
<p className="text-[14px] text-[#C0C0C0]">Add attachment</p>
</span>
</div>
<div className="flex items-center gap-4">
<button
type="button"
disabled={message.trim() === ""}
className="w-10 h-10 rounded-[8px] flex items-center justify-center rotate-180 disabled:opacity-50 disabled:cursor-not-allowed"
style={{ backgroundColor: "#E8E8E8" }}
>
<Arrow color="white" />
</button>
</div>
</div>
</div>
);
};
export { Chat, WelcomePanel, ChatInput };