enzostvs HF Staff commited on
Commit
b95350e
·
1 Parent(s): 7aca7ce

invite friends modal

Browse files
package-lock.json CHANGED
@@ -12,6 +12,7 @@
12
  "@huggingface/inference": "^3.6.1",
13
  "@monaco-editor/react": "^4.7.0",
14
  "@radix-ui/react-avatar": "^1.1.10",
 
15
  "@radix-ui/react-dropdown-menu": "^2.1.15",
16
  "@radix-ui/react-popover": "^1.1.14",
17
  "@radix-ui/react-select": "^2.2.5",
@@ -1278,6 +1279,42 @@
1278
  }
1279
  }
1280
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1281
  "node_modules/@radix-ui/react-direction": {
1282
  "version": "1.1.1",
1283
  "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
 
12
  "@huggingface/inference": "^3.6.1",
13
  "@monaco-editor/react": "^4.7.0",
14
  "@radix-ui/react-avatar": "^1.1.10",
15
+ "@radix-ui/react-dialog": "^1.1.14",
16
  "@radix-ui/react-dropdown-menu": "^2.1.15",
17
  "@radix-ui/react-popover": "^1.1.14",
18
  "@radix-ui/react-select": "^2.2.5",
 
1279
  }
1280
  }
1281
  },
1282
+ "node_modules/@radix-ui/react-dialog": {
1283
+ "version": "1.1.14",
1284
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz",
1285
+ "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==",
1286
+ "license": "MIT",
1287
+ "dependencies": {
1288
+ "@radix-ui/primitive": "1.1.2",
1289
+ "@radix-ui/react-compose-refs": "1.1.2",
1290
+ "@radix-ui/react-context": "1.1.2",
1291
+ "@radix-ui/react-dismissable-layer": "1.1.10",
1292
+ "@radix-ui/react-focus-guards": "1.1.2",
1293
+ "@radix-ui/react-focus-scope": "1.1.7",
1294
+ "@radix-ui/react-id": "1.1.1",
1295
+ "@radix-ui/react-portal": "1.1.9",
1296
+ "@radix-ui/react-presence": "1.1.4",
1297
+ "@radix-ui/react-primitive": "2.1.3",
1298
+ "@radix-ui/react-slot": "1.2.3",
1299
+ "@radix-ui/react-use-controllable-state": "1.2.2",
1300
+ "aria-hidden": "^1.2.4",
1301
+ "react-remove-scroll": "^2.6.3"
1302
+ },
1303
+ "peerDependencies": {
1304
+ "@types/react": "*",
1305
+ "@types/react-dom": "*",
1306
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1307
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1308
+ },
1309
+ "peerDependenciesMeta": {
1310
+ "@types/react": {
1311
+ "optional": true
1312
+ },
1313
+ "@types/react-dom": {
1314
+ "optional": true
1315
+ }
1316
+ }
1317
+ },
1318
  "node_modules/@radix-ui/react-direction": {
1319
  "version": "1.1.1",
1320
  "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
package.json CHANGED
@@ -15,6 +15,7 @@
15
  "@huggingface/inference": "^3.6.1",
16
  "@monaco-editor/react": "^4.7.0",
17
  "@radix-ui/react-avatar": "^1.1.10",
 
18
  "@radix-ui/react-dropdown-menu": "^2.1.15",
19
  "@radix-ui/react-popover": "^1.1.14",
20
  "@radix-ui/react-select": "^2.2.5",
 
15
  "@huggingface/inference": "^3.6.1",
16
  "@monaco-editor/react": "^4.7.0",
17
  "@radix-ui/react-avatar": "^1.1.10",
18
+ "@radix-ui/react-dialog": "^1.1.14",
19
  "@radix-ui/react-dropdown-menu": "^2.1.15",
20
  "@radix-ui/react-popover": "^1.1.14",
21
  "@radix-ui/react-select": "^2.2.5",
src/components/ask-ai/ask-ai-new.tsx CHANGED
@@ -3,7 +3,7 @@ import { useState, useRef } from "react";
3
  import classNames from "classnames";
4
  import { toast } from "sonner";
5
  import { useLocalStorage, useUpdateEffect } from "react-use";
6
- import { ArrowUp, ChevronDown, X } from "lucide-react";
7
  import { FaStopCircle } from "react-icons/fa";
8
 
9
  import Login from "../login/login";
@@ -16,6 +16,7 @@ import { Button } from "../ui/button";
16
  import { MODELS } from "../../../utils/providers";
17
  import Loading from "../loading/loading";
18
  import { HtmlHistory } from "../../../utils/types";
 
19
 
20
  function AskAI({
21
  html,
@@ -37,7 +38,6 @@ function AskAI({
37
  onSuccess: (h: string, p: string, n?: number[][]) => void;
38
  }) {
39
  const refThink = useRef<HTMLDivElement | null>(null);
40
- // const uploadInputRef = useRef<HTMLInputElement | null>(null);
41
 
42
  const [open, setOpen] = useState(false);
43
  const [prompt, setPrompt] = useState("");
@@ -51,7 +51,6 @@ function AskAI({
51
  const [think, setThink] = useState<string | undefined>(undefined);
52
  const [openThink, setOpenThink] = useState(false);
53
  const [isThinking, setIsThinking] = useState(true);
54
- const [files, setFiles] = useState<File[]>([]);
55
  const [controller, setController] = useState<AbortController | null>(null);
56
 
57
  const audio = new Audio(SuccessSound);
@@ -252,17 +251,6 @@ function AskAI({
252
  }
253
  };
254
 
255
- // const handleUploadFile = (event: React.ChangeEvent<HTMLInputElement>) => {
256
- // const filesList = event.target.files;
257
- // if (filesList && filesList.length > 0) {
258
- // // add files to the state to show them in the UI
259
- // const newFiles = Array.from(filesList);
260
- // setFiles((prevFiles) => [...prevFiles, ...newFiles]);
261
- // // clear the input value to allow re-uploading the same file
262
- // event.target.value = "";
263
- // }
264
- // };
265
-
266
  useUpdateEffect(() => {
267
  if (refThink.current) {
268
  refThink.current.scrollTop = refThink.current.scrollHeight;
@@ -277,33 +265,6 @@ function AskAI({
277
 
278
  return (
279
  <div className="bg-neutral-800 border border-neutral-700 rounded-2xl ring-[4px] focus-within:ring-neutral-500/30 focus-within:border-neutral-600 ring-transparent z-10 absolute bottom-3 left-3 w-[calc(100%-20px)] group">
280
- {files.length > 0 && (
281
- <div className="w-full absolute top-0 left-0 -translate-y-full pb-4 flex items-center justify-start gap-4">
282
- {files.map((file, index) => (
283
- <div
284
- key={index}
285
- className="flex items-center justify-between bg-neutral-700/50 rounded-lg w-20 aspect-square relative"
286
- style={{
287
- backgroundImage: `url(${URL.createObjectURL(file)})`,
288
- backgroundSize: "cover",
289
- backgroundPosition: "center",
290
- }}
291
- >
292
- <Button
293
- size="iconXss"
294
- className="absolute -top-2 -right-2 ring-[3px] ring-neutral-900"
295
- onClick={() => {
296
- setFiles((prevFiles) =>
297
- prevFiles.filter((f) => f.name !== file.name)
298
- );
299
- }}
300
- >
301
- <X className="size-4" />
302
- </Button>
303
- </div>
304
- ))}
305
- </div>
306
- )}
307
  {think && (
308
  <div className="w-full border-b border-neutral-700 relative overflow-hidden">
309
  <header
@@ -377,27 +338,7 @@ function AskAI({
377
  </div>
378
  <div className="flex items-center justify-between gap-2 px-4 pb-3">
379
  <div className="flex-1">
380
- {/* <Button
381
- size="iconXs"
382
- variant="outline"
383
- className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
384
- onClick={() => {
385
- if (uploadInputRef.current) {
386
- uploadInputRef.current.click();
387
- }
388
- }}
389
- >
390
- <ImagePlus className="size-4" />
391
- </Button>
392
- <input
393
- ref={uploadInputRef}
394
- type="file"
395
- accept="image/*"
396
- multiple
397
- onChange={handleUploadFile}
398
- className="hidden"
399
- id="file-upload"
400
- /> */}
401
  </div>
402
  <div className="flex items-center justify-end gap-2">
403
  <Settings
 
3
  import classNames from "classnames";
4
  import { toast } from "sonner";
5
  import { useLocalStorage, useUpdateEffect } from "react-use";
6
+ import { ArrowUp, ChevronDown } from "lucide-react";
7
  import { FaStopCircle } from "react-icons/fa";
8
 
9
  import Login from "../login/login";
 
16
  import { MODELS } from "../../../utils/providers";
17
  import Loading from "../loading/loading";
18
  import { HtmlHistory } from "../../../utils/types";
19
+ import InviteFriends from "../invite-friends/invite-friends";
20
 
21
  function AskAI({
22
  html,
 
38
  onSuccess: (h: string, p: string, n?: number[][]) => void;
39
  }) {
40
  const refThink = useRef<HTMLDivElement | null>(null);
 
41
 
42
  const [open, setOpen] = useState(false);
43
  const [prompt, setPrompt] = useState("");
 
51
  const [think, setThink] = useState<string | undefined>(undefined);
52
  const [openThink, setOpenThink] = useState(false);
53
  const [isThinking, setIsThinking] = useState(true);
 
54
  const [controller, setController] = useState<AbortController | null>(null);
55
 
56
  const audio = new Audio(SuccessSound);
 
251
  }
252
  };
253
 
 
 
 
 
 
 
 
 
 
 
 
254
  useUpdateEffect(() => {
255
  if (refThink.current) {
256
  refThink.current.scrollTop = refThink.current.scrollHeight;
 
265
 
266
  return (
267
  <div className="bg-neutral-800 border border-neutral-700 rounded-2xl ring-[4px] focus-within:ring-neutral-500/30 focus-within:border-neutral-600 ring-transparent z-10 absolute bottom-3 left-3 w-[calc(100%-20px)] group">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  {think && (
269
  <div className="w-full border-b border-neutral-700 relative overflow-hidden">
270
  <header
 
338
  </div>
339
  <div className="flex items-center justify-between gap-2 px-4 pb-3">
340
  <div className="flex-1">
341
+ <InviteFriends />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  </div>
343
  <div className="flex items-center justify-end gap-2">
344
  <Settings
src/components/invite-friends/invite-friends.tsx ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { TiUserAdd } from "react-icons/ti";
2
+ import { Link } from "lucide-react";
3
+ import { FaXTwitter } from "react-icons/fa6";
4
+
5
+ import { Button } from "../ui/button";
6
+ import { Dialog, DialogContent, DialogTrigger } from "../ui/dialog";
7
+ import { useCopyToClipboard } from "react-use";
8
+ import { toast } from "sonner";
9
+ export default function InviteFriends() {
10
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
+ const [_, copyToClipboard] = useCopyToClipboard();
12
+
13
+ return (
14
+ <Dialog>
15
+ <form>
16
+ <DialogTrigger asChild>
17
+ <Button
18
+ size="iconXs"
19
+ variant="outline"
20
+ className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
21
+ >
22
+ <TiUserAdd className="size-4" />
23
+ </Button>
24
+ </DialogTrigger>
25
+ <DialogContent className="sm:max-w-lg lg:!p-8 !rounded-3xl !bg-white !border-neutral-100">
26
+ <main>
27
+ <div className="flex items-center justify-start -space-x-4 mb-5">
28
+ <div className="size-11 rounded-full bg-pink-300 shadow-2xs flex items-center justify-center text-2xl">
29
+ 😎
30
+ </div>
31
+ <div className="size-11 rounded-full bg-amber-300 shadow-2xs flex items-center justify-center text-2xl z-2">
32
+ 😇
33
+ </div>
34
+ <div className="size-11 rounded-full bg-sky-300 shadow-2xs flex items-center justify-center text-2xl">
35
+ 😜
36
+ </div>
37
+ </div>
38
+ <p className="text-xl font-semibold text-neutral-950 max-w-[200px]">
39
+ Invite your friends to join us!
40
+ </p>
41
+ <p className="text-sm text-neutral-500 mt-2 max-w-sm">
42
+ Support us and share the love and let them know about our awesome
43
+ platform.
44
+ </p>
45
+ <div className="mt-4 space-x-3.5">
46
+ <a
47
+ href="https://x.com/intent/post?url=https://enzostvs-deepsite.hf.space/&text=Checkout%20this%20awesome%20Ai%20Tool!%20Vibe%20coding%20has%20never%20been%20so%20easy✨"
48
+ target="_blank"
49
+ rel="noopener noreferrer"
50
+ >
51
+ <Button
52
+ variant="ghostWhite"
53
+ size="sm"
54
+ className="!text-neutral-700"
55
+ >
56
+ <FaXTwitter className="size-4" />
57
+ Share on
58
+ </Button>
59
+ </a>
60
+ <Button
61
+ variant="ghostWhite"
62
+ size="sm"
63
+ className="!text-neutral-700"
64
+ onClick={() => {
65
+ copyToClipboard("https://enzostvs-deepsite.hf.space/");
66
+ toast.success("Invite link copied to clipboard!");
67
+ }}
68
+ >
69
+ <Link className="size-4" />
70
+ Copy Invite Link
71
+ </Button>
72
+ </div>
73
+ </main>
74
+ </DialogContent>
75
+ </form>
76
+ </Dialog>
77
+ );
78
+ }
src/components/ui/button.tsx CHANGED
@@ -21,6 +21,7 @@ const buttonVariants = cva(
21
  link: "text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50",
22
  pink: "bg-sky-500 text-white hover:brightness-110",
23
  gray: "bg-neutral-900 text-neutral-300 hover:brightness-110",
 
24
  },
25
  size: {
26
  default: "h-9 px-4 py-2 has-[>svg]:px-3",
 
21
  link: "text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50",
22
  pink: "bg-sky-500 text-white hover:brightness-110",
23
  gray: "bg-neutral-900 text-neutral-300 hover:brightness-110",
24
+ ghostWhite: "bg-neutral-200/60 text-neutral-900 hover:bg-neutral-200",
25
  },
26
  size: {
27
  default: "h-9 px-4 py-2 has-[>svg]:px-3",
src/components/ui/dialog.tsx ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from "react";
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
3
+ import { XIcon } from "lucide-react";
4
+
5
+ import { cn } from "./../../lib/utils";
6
+
7
+ function Dialog({
8
+ ...props
9
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
10
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
11
+ }
12
+
13
+ function DialogTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
16
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
17
+ }
18
+
19
+ function DialogPortal({
20
+ ...props
21
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
22
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
23
+ }
24
+
25
+ function DialogClose({
26
+ ...props
27
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
28
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
29
+ }
30
+
31
+ function DialogOverlay({
32
+ className,
33
+ ...props
34
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
35
+ return (
36
+ <DialogPrimitive.Overlay
37
+ data-slot="dialog-overlay"
38
+ className={cn(
39
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+
47
+ function DialogContent({
48
+ className,
49
+ children,
50
+ showCloseButton = true,
51
+ ...props
52
+ }: React.ComponentProps<typeof DialogPrimitive.Content> & {
53
+ showCloseButton?: boolean;
54
+ }) {
55
+ return (
56
+ <DialogPortal data-slot="dialog-portal">
57
+ <DialogOverlay />
58
+ <DialogPrimitive.Content
59
+ data-slot="dialog-content"
60
+ className={cn(
61
+ "bg-white data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-neutral-200 p-6 shadow-lg duration-200 sm:max-w-lg dark:bg-neutral-950 dark:border-neutral-800",
62
+ className
63
+ )}
64
+ {...props}
65
+ >
66
+ {children}
67
+ {showCloseButton && (
68
+ <DialogPrimitive.Close
69
+ data-slot="dialog-close"
70
+ className="ring-offset-white focus:ring-neutral-950 data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:ring-offset-neutral-950 dark:focus:ring-neutral-300 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400"
71
+ >
72
+ <XIcon />
73
+ <span className="sr-only">Close</span>
74
+ </DialogPrimitive.Close>
75
+ )}
76
+ </DialogPrimitive.Content>
77
+ </DialogPortal>
78
+ );
79
+ }
80
+
81
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
82
+ return (
83
+ <div
84
+ data-slot="dialog-header"
85
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
86
+ {...props}
87
+ />
88
+ );
89
+ }
90
+
91
+ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
92
+ return (
93
+ <div
94
+ data-slot="dialog-footer"
95
+ className={cn(
96
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
97
+ className
98
+ )}
99
+ {...props}
100
+ />
101
+ );
102
+ }
103
+
104
+ function DialogTitle({
105
+ className,
106
+ ...props
107
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
108
+ return (
109
+ <DialogPrimitive.Title
110
+ data-slot="dialog-title"
111
+ className={cn("text-lg leading-none font-semibold", className)}
112
+ {...props}
113
+ />
114
+ );
115
+ }
116
+
117
+ function DialogDescription({
118
+ className,
119
+ ...props
120
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
121
+ return (
122
+ <DialogPrimitive.Description
123
+ data-slot="dialog-description"
124
+ className={cn(
125
+ "text-neutral-500 text-sm dark:text-neutral-400",
126
+ className
127
+ )}
128
+ {...props}
129
+ />
130
+ );
131
+ }
132
+
133
+ export {
134
+ Dialog,
135
+ DialogClose,
136
+ DialogContent,
137
+ DialogDescription,
138
+ DialogFooter,
139
+ DialogHeader,
140
+ DialogOverlay,
141
+ DialogPortal,
142
+ DialogTitle,
143
+ DialogTrigger,
144
+ };