File size: 3,164 Bytes
702763e
 
e4741e5
702763e
3c7c2dc
702763e
 
bab2147
702763e
bab2147
 
702763e
 
e4741e5
 
702763e
 
 
bab2147
 
 
e4741e5
702763e
 
 
 
e4741e5
702763e
 
 
 
704ade6
702763e
 
 
bab2147
 
702763e
 
e4741e5
702763e
 
e4741e5
bab2147
 
 
 
 
 
 
 
 
702763e
bab2147
702763e
56b5482
702763e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e4741e5
702763e
bab2147
 
 
 
 
 
 
 
 
 
 
 
 
 
702763e
bab2147
 
 
 
 
702763e
bab2147
e4741e5
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
"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>
      )}
    </>
  );
}