create sig in flow LO
This commit is contained in:
@@ -1,24 +1,133 @@
|
||||
import { useAccountStore } from "@/contexts/AccountContext";
|
||||
import { Button } from "../ui/button";
|
||||
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";
|
||||
|
||||
export const Chat = observer(() => {
|
||||
const { isSandboxOpen, setIsSandboxOpen, isMainMenuOpen, setIsMainMenuOpen } =
|
||||
useAccountStore();
|
||||
|
||||
const Chat = observer(() => {
|
||||
return (
|
||||
<div className="flex-1">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setIsSandboxOpen(!isSandboxOpen);
|
||||
if (isMainMenuOpen && !isSandboxOpen) {
|
||||
setIsMainMenuOpen(false);
|
||||
}
|
||||
}}
|
||||
className="ml-10"
|
||||
>
|
||||
OPEN SANDBOX
|
||||
</Button>
|
||||
<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 };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Button } from "../ui/button";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useAccountStore } from "@/contexts/AccountContext";
|
||||
import { Button } from "./ui/button";
|
||||
|
||||
export const MainMenu = observer(() => {
|
||||
const { isMainMenuOpen, setIsMainMenuOpen } = useAccountStore();
|
||||
@@ -4,7 +4,7 @@ import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 font-medium whitespace-nowrap rounded-[8px] px-4 text-[14px] leading-[130%] tracking-[0.01em] transition-colors hover:cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:*:fill-text-secondary [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
"h-[52px] inline-flex items-center justify-center gap-2 font-medium whitespace-nowrap rounded-[8px] px-4 text-[14px] leading-[130%] tracking-[0.01em] transition-colors hover:cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:*:fill-text-secondary [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
62
src/components/ui/input.tsx
Normal file
62
src/components/ui/input.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import type { HTMLInputTypeAttribute } from "react";
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type InputProps = Omit<React.ComponentProps<"input">, "type"> & {
|
||||
type?: HTMLInputTypeAttribute | "token";
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
label?: string;
|
||||
|
||||
rightContent?: React.ReactNode;
|
||||
};
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ children, className, type, label, required, ...props }, ref) => {
|
||||
return (
|
||||
<div className="group flex w-full flex-col gap-3">
|
||||
{label && (
|
||||
<span
|
||||
data-required={required}
|
||||
className="text-text-light-500 font-[500] text-[12px] after:ml-0.5 after:text-negative-primary data-[required=true]:after:content-['*']"
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
"group flex rounded-[8px] items-center w-full border transition-colors border-fill-200 hover:border-fill-400",
|
||||
"focus-within:border-fill-400",
|
||||
"disabled:border-b-fill-secondary",
|
||||
"data-[invalid=true]:border-b-negative-primary",
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type={type}
|
||||
ref={ref}
|
||||
data-disabled={props.disabled}
|
||||
className={cn(
|
||||
"text-[14px] px-4 py-3 flex w-full border-none bg-transparent transition-colors placeholder:text-text-secondary",
|
||||
"focus:placeholder:opacity-0 disabled:cursor-not-allowed disabled:text-text-quartinary",
|
||||
"data-[disabled=true]:placeholder:text-text-quinary",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
{props.rightContent && (
|
||||
<div className="pr-2 pb-2 flex items-center gap-1 text-text-primary text-sm">
|
||||
{props.rightContent}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
Input.displayName = "Input";
|
||||
|
||||
export { Input };
|
||||
Reference in New Issue
Block a user