Spaces:
Running
Running
"use client"; | |
import { useState } from "react"; | |
import Image from "next/image"; | |
import classNames from "classnames"; | |
import satori from "satori"; | |
import { roast } from "@/app/actions/roast"; | |
import { share, ShareProps } from "@/app/actions/share"; | |
import { Form, FormProps } from "@/components/form"; | |
import { CopyToClipboard } from "@/components/copy"; | |
import { Quote } from "@/components/quote"; | |
import Logo from "@/assets/logo.svg"; | |
export default function Home() { | |
const [data, setData] = useState(""); | |
const [error, setError] = useState(""); | |
const [loading, setLoading] = useState(false); | |
const [loadingShare, setLoadingShare] = useState(false); | |
const [hfUser, setHfUser] = useState<string | undefined>(undefined); | |
const [quote, setQuote] = useState<string | undefined>(undefined); | |
const handleRoast = async (form: FormProps) => { | |
setError(""); | |
setData(""); | |
setLoading(true); | |
const res: { | |
error?: string; | |
data?: any; | |
} = await roast(form); | |
if (res.error) { | |
setError(res.error); | |
} else { | |
setQuote(undefined); | |
setHfUser(form.username); | |
setData(res?.data); | |
} | |
setLoading(false); | |
}; | |
const handleShare = async (form: ShareProps) => { | |
setLoadingShare(true); | |
const res = await share({ hf_user: form.hf_user, text: form.text }); | |
if (res?.data) { | |
setQuote(res.data.id); | |
} | |
setLoadingShare(false); | |
}; | |
return ( | |
<> | |
<div className="max-w-2xl w-full border border-gray-200 bg-white rounded-3xl p-8 grid gap-8 shadow-xl shadow-black/5"> | |
<header className="flex items-start max-lg:gap-1 lg:items-center justify-between max-lg:flex-col border-b border-zinc-200 pb-5"> | |
<Image | |
src={Logo} | |
alt="logo hugging face" | |
width={100} | |
height={100} | |
className="object-contain w-36 lg:w-44" | |
/> | |
<div> | |
<p className="text-sm text-zinc-500"> | |
Roast your favorite Hugging Face user! 👹 | |
</p> | |
</div> | |
</header> | |
{error && ( | |
<div className="text-sm text-red-600 bg-red-500/10 border-[1px] border-red-500/15 px-3.5 py-2.5 rounded-xl"> | |
<p className="font-semibold text-sm">Oops!</p> | |
{error} | |
</div> | |
)} | |
<Form loading={loading} onSubmit={handleRoast} /> | |
</div> | |
{data && ( | |
<Quote data={data}> | |
{quote ? ( | |
<CopyToClipboard id={quote} /> | |
) : ( | |
<button | |
className={classNames( | |
"bg-black rounded-full mt-4 px-4 py-2.5 text-sm font-medium text-white hover:bg-zinc-800 disabled:bg-zinc-300 disabled:text-zinc-500 disabled:cursor-not-allowed", | |
{ | |
"animate-pulse": loadingShare, | |
} | |
)} | |
disabled={loadingShare} | |
onClick={() => | |
hfUser && handleShare({ hf_user: hfUser, text: data }) | |
} | |
> | |
{loadingShare ? "Creating a quote..." : "Share my roast!"} | |
</button> | |
)} | |
</Quote> | |
)} | |
</> | |
); | |
} | |