invite friends modal
Browse files- package-lock.json +37 -0
- package.json +1 -0
- src/components/ask-ai/ask-ai-new.tsx +3 -62
- src/components/invite-friends/invite-friends.tsx +78 -0
- src/components/ui/button.tsx +1 -0
- src/components/ui/dialog.tsx +144 -0
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
|
| 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 |
-
|
| 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 |
+
};
|