Spaces:
Running
Running
LocalPullAT
#142
by
RandySm
- opened
- .gitattributes +0 -1
- README.md +1 -4
- components.json +0 -23
- index.html +0 -23
- package-lock.json +23 -1181
- package.json +1 -20
- public/banner.png +0 -3
- public/providers/together.svg +0 -10
- server.js +56 -346
- src/assets/index.css +0 -133
- src/assets/linux.png +0 -0
- src/{views → components}/App.tsx +136 -185
- src/components/ask-ai/ask-ai.tsx +119 -264
- src/components/deploy-button/deploy-button.tsx +156 -91
- src/components/footer/footer.tsx +0 -177
- src/components/header/header.tsx +19 -48
- src/components/history/history.tsx +0 -138
- src/components/invite-friends/invite-friends.tsx +0 -78
- src/components/load-button/load-button.tsx +51 -43
- src/components/loading/loading.tsx +3 -16
- src/components/login/login.tsx +4 -4
- src/components/magicui/grid-pattern.tsx +0 -69
- src/components/preview/preview.tsx +52 -46
- src/components/pro-modal/pro-modal.tsx +40 -64
- src/components/re-imagine/re-imagine.tsx +0 -136
- src/components/settings/settings.tsx +95 -154
- src/components/tabs/tabs.tsx +120 -0
- src/components/theme/mode-toggle.tsx +0 -37
- src/components/theme/theme-provider.tsx +0 -75
- src/components/ui/avatar.tsx +0 -51
- src/components/ui/button.tsx +0 -64
- src/components/ui/dialog.tsx +0 -144
- src/components/ui/dropdown-menu.tsx +0 -258
- src/components/ui/input.tsx +0 -21
- src/components/ui/popover.tsx +0 -46
- src/components/ui/select.tsx +0 -189
- src/components/ui/sonner.tsx +0 -23
- src/components/ui/tabs.tsx +0 -64
- src/components/ui/toggle-group.tsx +0 -71
- src/components/ui/toggle.tsx +0 -47
- src/components/ui/tooltip.tsx +0 -59
- src/lib/utils.ts +0 -6
- src/main.tsx +3 -1
- tsconfig.app.json +0 -1
- tsconfig.json +3 -7
- utils/consts.ts +31 -10
- utils/providers.js +6 -35
- utils/types.ts +0 -6
- vite.config.ts +3 -6
.gitattributes
DELETED
@@ -1 +0,0 @@
|
|
1 |
-
public/banner.png filter=lfs diff=lfs merge=lfs -text
|
|
|
|
README.md
CHANGED
@@ -10,13 +10,10 @@ license: mit
|
|
10 |
short_description: Generate any application with DeepSeek
|
11 |
models:
|
12 |
- deepseek-ai/DeepSeek-V3-0324
|
13 |
-
- deepseek-ai/DeepSeek-R1-0528
|
14 |
---
|
15 |
|
16 |
# DeepSite 🐳
|
17 |
-
|
18 |
DeepSite is a coding platform powered by DeepSeek AI, designed to make coding smarter and more efficient. Tailored for developers, data scientists, and AI engineers, it integrates generative AI into your coding projects to enhance creativity and productivity.
|
19 |
|
20 |
## How to use it locally
|
21 |
-
|
22 |
-
Follow [this discussion](https://huggingface.co/spaces/enzostvs/deepsite/discussions/74)
|
|
|
10 |
short_description: Generate any application with DeepSeek
|
11 |
models:
|
12 |
- deepseek-ai/DeepSeek-V3-0324
|
|
|
13 |
---
|
14 |
|
15 |
# DeepSite 🐳
|
|
|
16 |
DeepSite is a coding platform powered by DeepSeek AI, designed to make coding smarter and more efficient. Tailored for developers, data scientists, and AI engineers, it integrates generative AI into your coding projects to enhance creativity and productivity.
|
17 |
|
18 |
## How to use it locally
|
19 |
+
Follow [this discussion](https://huggingface.co/spaces/enzostvs/deepsite/discussions/74)
|
|
components.json
DELETED
@@ -1,23 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"$schema": "https://ui.shadcn.com/schema.json",
|
3 |
-
"style": "new-york",
|
4 |
-
"rsc": false,
|
5 |
-
"tsx": true,
|
6 |
-
"tailwind": {
|
7 |
-
"config": "",
|
8 |
-
"css": "src/assets/index.css",
|
9 |
-
"baseColor": "neutral",
|
10 |
-
"baseColorLight": "slate",
|
11 |
-
"baseColorDark": "neutral",
|
12 |
-
"cssVariables": false,
|
13 |
-
"prefix": ""
|
14 |
-
},
|
15 |
-
"aliases": {
|
16 |
-
"components": "@/components",
|
17 |
-
"utils": "@/lib/utils",
|
18 |
-
"ui": "@/components/ui",
|
19 |
-
"lib": "@/lib",
|
20 |
-
"hooks": "@/hooks"
|
21 |
-
},
|
22 |
-
"iconLibrary": "lucide"
|
23 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
index.html
CHANGED
@@ -11,29 +11,6 @@
|
|
11 |
helps you build websites with AI, no code required. Let's deploy your
|
12 |
website with DeepSite and enjoy the magic of AI."
|
13 |
/>
|
14 |
-
<meta name="theme-color" content="#000000" />
|
15 |
-
<meta name="apple-mobile-web-app-capable" content="yes" />
|
16 |
-
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
17 |
-
<meta name="apple-mobile-web-app-title" content="DeepSite" />
|
18 |
-
<meta name="msapplication-TileColor" content="#000000" />
|
19 |
-
<meta name="twitter:card" content="summary_large_image" />
|
20 |
-
<meta name="twitter:title" content="DeepSite | Build with AI ✨" />
|
21 |
-
<meta
|
22 |
-
name="twitter:description"
|
23 |
-
content="DeepSite is a web development tool that
|
24 |
-
helps you build websites with AI, no code required. Let's deploy your
|
25 |
-
website with DeepSite and enjoy the magic of AI."
|
26 |
-
/>
|
27 |
-
<meta name="twitter:image" content="/banner.png" />
|
28 |
-
<meta property="og:type" content="website" />
|
29 |
-
<meta property="og:title" content="DeepSite | Build with AI ✨" />
|
30 |
-
<meta
|
31 |
-
property="og:description"
|
32 |
-
content="DeepSite is a web development tool that
|
33 |
-
helps you build websites with AI, no code required. Let's deploy your
|
34 |
-
website with DeepSite and enjoy the magic of AI."
|
35 |
-
/>
|
36 |
-
<meta property="og:image" content="/banner.png" />
|
37 |
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
38 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
39 |
<link
|
|
|
11 |
helps you build websites with AI, no code required. Let's deploy your
|
12 |
website with DeepSite and enjoy the magic of AI."
|
13 |
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
15 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
16 |
<link
|
package-lock.json
CHANGED
@@ -9,30 +9,15 @@
|
|
9 |
"version": "0.0.0",
|
10 |
"dependencies": {
|
11 |
"@huggingface/hub": "^1.1.1",
|
12 |
-
"@huggingface/inference": "^
|
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",
|
19 |
-
"@radix-ui/react-slot": "^1.2.3",
|
20 |
-
"@radix-ui/react-switch": "^1.2.5",
|
21 |
-
"@radix-ui/react-tabs": "^1.1.12",
|
22 |
-
"@radix-ui/react-toggle": "^1.1.9",
|
23 |
-
"@radix-ui/react-toggle-group": "^1.1.10",
|
24 |
-
"@radix-ui/react-tooltip": "^1.2.7",
|
25 |
"@tailwindcss/vite": "^4.0.15",
|
26 |
"@xenova/transformers": "^2.17.2",
|
27 |
"body-parser": "^1.20.3",
|
28 |
-
"class-variance-authority": "^0.7.1",
|
29 |
"classnames": "^2.5.1",
|
30 |
-
"clsx": "^2.1.1",
|
31 |
"cookie-parser": "^1.4.7",
|
32 |
"dotenv": "^16.4.7",
|
33 |
"express": "^4.21.2",
|
34 |
-
"lucide-react": "^0.511.0",
|
35 |
-
"next-themes": "^0.4.6",
|
36 |
"react": "^19.0.0",
|
37 |
"react-dom": "^19.0.0",
|
38 |
"react-icons": "^5.5.0",
|
@@ -40,14 +25,11 @@
|
|
40 |
"react-speech-recognition": "^4.0.0",
|
41 |
"react-toastify": "^11.0.5",
|
42 |
"react-use": "^17.6.0",
|
43 |
-
"sonner": "^2.0.3",
|
44 |
-
"tailwind-merge": "^3.3.0",
|
45 |
"tailwindcss": "^4.0.15"
|
46 |
},
|
47 |
"devDependencies": {
|
48 |
"@eslint/js": "^9.21.0",
|
49 |
"@types/express": "^5.0.1",
|
50 |
-
"@types/node": "^22.15.21",
|
51 |
"@types/react": "^19.0.10",
|
52 |
"@types/react-dom": "^19.0.4",
|
53 |
"@types/react-speech-recognition": "^3.9.6",
|
@@ -56,7 +38,6 @@
|
|
56 |
"eslint-plugin-react-hooks": "^5.1.0",
|
57 |
"eslint-plugin-react-refresh": "^0.4.19",
|
58 |
"globals": "^15.15.0",
|
59 |
-
"tw-animate-css": "^1.3.0",
|
60 |
"typescript": "~5.7.2",
|
61 |
"typescript-eslint": "^8.24.1",
|
62 |
"vite": "^6.2.0"
|
@@ -191,11 +172,10 @@
|
|
191 |
}
|
192 |
},
|
193 |
"node_modules/@babel/helper-plugin-utils": {
|
194 |
-
"version": "7.
|
195 |
-
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.
|
196 |
-
"integrity": "sha512-
|
197 |
"dev": true,
|
198 |
-
"license": "MIT",
|
199 |
"engines": {
|
200 |
"node": ">=6.9.0"
|
201 |
}
|
@@ -865,44 +845,6 @@
|
|
865 |
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
866 |
}
|
867 |
},
|
868 |
-
"node_modules/@floating-ui/core": {
|
869 |
-
"version": "1.7.0",
|
870 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz",
|
871 |
-
"integrity": "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==",
|
872 |
-
"license": "MIT",
|
873 |
-
"dependencies": {
|
874 |
-
"@floating-ui/utils": "^0.2.9"
|
875 |
-
}
|
876 |
-
},
|
877 |
-
"node_modules/@floating-ui/dom": {
|
878 |
-
"version": "1.7.0",
|
879 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz",
|
880 |
-
"integrity": "sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==",
|
881 |
-
"license": "MIT",
|
882 |
-
"dependencies": {
|
883 |
-
"@floating-ui/core": "^1.7.0",
|
884 |
-
"@floating-ui/utils": "^0.2.9"
|
885 |
-
}
|
886 |
-
},
|
887 |
-
"node_modules/@floating-ui/react-dom": {
|
888 |
-
"version": "2.1.2",
|
889 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
|
890 |
-
"integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
|
891 |
-
"license": "MIT",
|
892 |
-
"dependencies": {
|
893 |
-
"@floating-ui/dom": "^1.0.0"
|
894 |
-
},
|
895 |
-
"peerDependencies": {
|
896 |
-
"react": ">=16.8.0",
|
897 |
-
"react-dom": ">=16.8.0"
|
898 |
-
}
|
899 |
-
},
|
900 |
-
"node_modules/@floating-ui/utils": {
|
901 |
-
"version": "0.2.9",
|
902 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz",
|
903 |
-
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
|
904 |
-
"license": "MIT"
|
905 |
-
},
|
906 |
"node_modules/@huggingface/hub": {
|
907 |
"version": "1.1.1",
|
908 |
"resolved": "https://registry.npmjs.org/@huggingface/hub/-/hub-1.1.1.tgz",
|
@@ -920,32 +862,29 @@
|
|
920 |
"integrity": "sha512-HK6JTVB/nrgjOnbe77HFSENftfAp67AI4mHMR2x64Os1hvchuTT88M8fKEiyESSvqKFKwW4lQKkHva07p05AXw=="
|
921 |
},
|
922 |
"node_modules/@huggingface/inference": {
|
923 |
-
"version": "
|
924 |
-
"resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-
|
925 |
-
"integrity": "sha512-
|
926 |
-
"license": "MIT",
|
927 |
"dependencies": {
|
928 |
-
"@huggingface/jinja": "^0.
|
929 |
-
"@huggingface/tasks": "^0.
|
930 |
},
|
931 |
"engines": {
|
932 |
"node": ">=18"
|
933 |
}
|
934 |
},
|
935 |
"node_modules/@huggingface/jinja": {
|
936 |
-
"version": "0.
|
937 |
-
"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.
|
938 |
-
"integrity": "sha512-
|
939 |
-
"license": "MIT",
|
940 |
"engines": {
|
941 |
"node": ">=18"
|
942 |
}
|
943 |
},
|
944 |
"node_modules/@huggingface/tasks": {
|
945 |
-
"version": "0.
|
946 |
-
"resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.
|
947 |
-
"integrity": "sha512-
|
948 |
-
"license": "MIT"
|
949 |
},
|
950 |
"node_modules/@humanfs/core": {
|
951 |
"version": "0.19.1",
|
@@ -1165,891 +1104,6 @@
|
|
1165 |
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
1166 |
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
1167 |
},
|
1168 |
-
"node_modules/@radix-ui/number": {
|
1169 |
-
"version": "1.1.1",
|
1170 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
|
1171 |
-
"integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==",
|
1172 |
-
"license": "MIT"
|
1173 |
-
},
|
1174 |
-
"node_modules/@radix-ui/primitive": {
|
1175 |
-
"version": "1.1.2",
|
1176 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
|
1177 |
-
"integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==",
|
1178 |
-
"license": "MIT"
|
1179 |
-
},
|
1180 |
-
"node_modules/@radix-ui/react-arrow": {
|
1181 |
-
"version": "1.1.7",
|
1182 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
1183 |
-
"integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
|
1184 |
-
"license": "MIT",
|
1185 |
-
"dependencies": {
|
1186 |
-
"@radix-ui/react-primitive": "2.1.3"
|
1187 |
-
},
|
1188 |
-
"peerDependencies": {
|
1189 |
-
"@types/react": "*",
|
1190 |
-
"@types/react-dom": "*",
|
1191 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1192 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1193 |
-
},
|
1194 |
-
"peerDependenciesMeta": {
|
1195 |
-
"@types/react": {
|
1196 |
-
"optional": true
|
1197 |
-
},
|
1198 |
-
"@types/react-dom": {
|
1199 |
-
"optional": true
|
1200 |
-
}
|
1201 |
-
}
|
1202 |
-
},
|
1203 |
-
"node_modules/@radix-ui/react-avatar": {
|
1204 |
-
"version": "1.1.10",
|
1205 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz",
|
1206 |
-
"integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==",
|
1207 |
-
"license": "MIT",
|
1208 |
-
"dependencies": {
|
1209 |
-
"@radix-ui/react-context": "1.1.2",
|
1210 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1211 |
-
"@radix-ui/react-use-callback-ref": "1.1.1",
|
1212 |
-
"@radix-ui/react-use-is-hydrated": "0.1.0",
|
1213 |
-
"@radix-ui/react-use-layout-effect": "1.1.1"
|
1214 |
-
},
|
1215 |
-
"peerDependencies": {
|
1216 |
-
"@types/react": "*",
|
1217 |
-
"@types/react-dom": "*",
|
1218 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1219 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1220 |
-
},
|
1221 |
-
"peerDependenciesMeta": {
|
1222 |
-
"@types/react": {
|
1223 |
-
"optional": true
|
1224 |
-
},
|
1225 |
-
"@types/react-dom": {
|
1226 |
-
"optional": true
|
1227 |
-
}
|
1228 |
-
}
|
1229 |
-
},
|
1230 |
-
"node_modules/@radix-ui/react-collection": {
|
1231 |
-
"version": "1.1.7",
|
1232 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
|
1233 |
-
"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
|
1234 |
-
"license": "MIT",
|
1235 |
-
"dependencies": {
|
1236 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1237 |
-
"@radix-ui/react-context": "1.1.2",
|
1238 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1239 |
-
"@radix-ui/react-slot": "1.2.3"
|
1240 |
-
},
|
1241 |
-
"peerDependencies": {
|
1242 |
-
"@types/react": "*",
|
1243 |
-
"@types/react-dom": "*",
|
1244 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1245 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1246 |
-
},
|
1247 |
-
"peerDependenciesMeta": {
|
1248 |
-
"@types/react": {
|
1249 |
-
"optional": true
|
1250 |
-
},
|
1251 |
-
"@types/react-dom": {
|
1252 |
-
"optional": true
|
1253 |
-
}
|
1254 |
-
}
|
1255 |
-
},
|
1256 |
-
"node_modules/@radix-ui/react-compose-refs": {
|
1257 |
-
"version": "1.1.2",
|
1258 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
1259 |
-
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
1260 |
-
"license": "MIT",
|
1261 |
-
"peerDependencies": {
|
1262 |
-
"@types/react": "*",
|
1263 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1264 |
-
},
|
1265 |
-
"peerDependenciesMeta": {
|
1266 |
-
"@types/react": {
|
1267 |
-
"optional": true
|
1268 |
-
}
|
1269 |
-
}
|
1270 |
-
},
|
1271 |
-
"node_modules/@radix-ui/react-context": {
|
1272 |
-
"version": "1.1.2",
|
1273 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
|
1274 |
-
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
|
1275 |
-
"license": "MIT",
|
1276 |
-
"peerDependencies": {
|
1277 |
-
"@types/react": "*",
|
1278 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1279 |
-
},
|
1280 |
-
"peerDependenciesMeta": {
|
1281 |
-
"@types/react": {
|
1282 |
-
"optional": true
|
1283 |
-
}
|
1284 |
-
}
|
1285 |
-
},
|
1286 |
-
"node_modules/@radix-ui/react-dialog": {
|
1287 |
-
"version": "1.1.14",
|
1288 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz",
|
1289 |
-
"integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==",
|
1290 |
-
"license": "MIT",
|
1291 |
-
"dependencies": {
|
1292 |
-
"@radix-ui/primitive": "1.1.2",
|
1293 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1294 |
-
"@radix-ui/react-context": "1.1.2",
|
1295 |
-
"@radix-ui/react-dismissable-layer": "1.1.10",
|
1296 |
-
"@radix-ui/react-focus-guards": "1.1.2",
|
1297 |
-
"@radix-ui/react-focus-scope": "1.1.7",
|
1298 |
-
"@radix-ui/react-id": "1.1.1",
|
1299 |
-
"@radix-ui/react-portal": "1.1.9",
|
1300 |
-
"@radix-ui/react-presence": "1.1.4",
|
1301 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1302 |
-
"@radix-ui/react-slot": "1.2.3",
|
1303 |
-
"@radix-ui/react-use-controllable-state": "1.2.2",
|
1304 |
-
"aria-hidden": "^1.2.4",
|
1305 |
-
"react-remove-scroll": "^2.6.3"
|
1306 |
-
},
|
1307 |
-
"peerDependencies": {
|
1308 |
-
"@types/react": "*",
|
1309 |
-
"@types/react-dom": "*",
|
1310 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1311 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1312 |
-
},
|
1313 |
-
"peerDependenciesMeta": {
|
1314 |
-
"@types/react": {
|
1315 |
-
"optional": true
|
1316 |
-
},
|
1317 |
-
"@types/react-dom": {
|
1318 |
-
"optional": true
|
1319 |
-
}
|
1320 |
-
}
|
1321 |
-
},
|
1322 |
-
"node_modules/@radix-ui/react-direction": {
|
1323 |
-
"version": "1.1.1",
|
1324 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
|
1325 |
-
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
|
1326 |
-
"license": "MIT",
|
1327 |
-
"peerDependencies": {
|
1328 |
-
"@types/react": "*",
|
1329 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1330 |
-
},
|
1331 |
-
"peerDependenciesMeta": {
|
1332 |
-
"@types/react": {
|
1333 |
-
"optional": true
|
1334 |
-
}
|
1335 |
-
}
|
1336 |
-
},
|
1337 |
-
"node_modules/@radix-ui/react-dismissable-layer": {
|
1338 |
-
"version": "1.1.10",
|
1339 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
|
1340 |
-
"integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==",
|
1341 |
-
"license": "MIT",
|
1342 |
-
"dependencies": {
|
1343 |
-
"@radix-ui/primitive": "1.1.2",
|
1344 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1345 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1346 |
-
"@radix-ui/react-use-callback-ref": "1.1.1",
|
1347 |
-
"@radix-ui/react-use-escape-keydown": "1.1.1"
|
1348 |
-
},
|
1349 |
-
"peerDependencies": {
|
1350 |
-
"@types/react": "*",
|
1351 |
-
"@types/react-dom": "*",
|
1352 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1353 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1354 |
-
},
|
1355 |
-
"peerDependenciesMeta": {
|
1356 |
-
"@types/react": {
|
1357 |
-
"optional": true
|
1358 |
-
},
|
1359 |
-
"@types/react-dom": {
|
1360 |
-
"optional": true
|
1361 |
-
}
|
1362 |
-
}
|
1363 |
-
},
|
1364 |
-
"node_modules/@radix-ui/react-dropdown-menu": {
|
1365 |
-
"version": "2.1.15",
|
1366 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz",
|
1367 |
-
"integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==",
|
1368 |
-
"license": "MIT",
|
1369 |
-
"dependencies": {
|
1370 |
-
"@radix-ui/primitive": "1.1.2",
|
1371 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1372 |
-
"@radix-ui/react-context": "1.1.2",
|
1373 |
-
"@radix-ui/react-id": "1.1.1",
|
1374 |
-
"@radix-ui/react-menu": "2.1.15",
|
1375 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1376 |
-
"@radix-ui/react-use-controllable-state": "1.2.2"
|
1377 |
-
},
|
1378 |
-
"peerDependencies": {
|
1379 |
-
"@types/react": "*",
|
1380 |
-
"@types/react-dom": "*",
|
1381 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1382 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1383 |
-
},
|
1384 |
-
"peerDependenciesMeta": {
|
1385 |
-
"@types/react": {
|
1386 |
-
"optional": true
|
1387 |
-
},
|
1388 |
-
"@types/react-dom": {
|
1389 |
-
"optional": true
|
1390 |
-
}
|
1391 |
-
}
|
1392 |
-
},
|
1393 |
-
"node_modules/@radix-ui/react-focus-guards": {
|
1394 |
-
"version": "1.1.2",
|
1395 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz",
|
1396 |
-
"integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==",
|
1397 |
-
"license": "MIT",
|
1398 |
-
"peerDependencies": {
|
1399 |
-
"@types/react": "*",
|
1400 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1401 |
-
},
|
1402 |
-
"peerDependenciesMeta": {
|
1403 |
-
"@types/react": {
|
1404 |
-
"optional": true
|
1405 |
-
}
|
1406 |
-
}
|
1407 |
-
},
|
1408 |
-
"node_modules/@radix-ui/react-focus-scope": {
|
1409 |
-
"version": "1.1.7",
|
1410 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
|
1411 |
-
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
|
1412 |
-
"license": "MIT",
|
1413 |
-
"dependencies": {
|
1414 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1415 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1416 |
-
"@radix-ui/react-use-callback-ref": "1.1.1"
|
1417 |
-
},
|
1418 |
-
"peerDependencies": {
|
1419 |
-
"@types/react": "*",
|
1420 |
-
"@types/react-dom": "*",
|
1421 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1422 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1423 |
-
},
|
1424 |
-
"peerDependenciesMeta": {
|
1425 |
-
"@types/react": {
|
1426 |
-
"optional": true
|
1427 |
-
},
|
1428 |
-
"@types/react-dom": {
|
1429 |
-
"optional": true
|
1430 |
-
}
|
1431 |
-
}
|
1432 |
-
},
|
1433 |
-
"node_modules/@radix-ui/react-id": {
|
1434 |
-
"version": "1.1.1",
|
1435 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
|
1436 |
-
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
|
1437 |
-
"license": "MIT",
|
1438 |
-
"dependencies": {
|
1439 |
-
"@radix-ui/react-use-layout-effect": "1.1.1"
|
1440 |
-
},
|
1441 |
-
"peerDependencies": {
|
1442 |
-
"@types/react": "*",
|
1443 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1444 |
-
},
|
1445 |
-
"peerDependenciesMeta": {
|
1446 |
-
"@types/react": {
|
1447 |
-
"optional": true
|
1448 |
-
}
|
1449 |
-
}
|
1450 |
-
},
|
1451 |
-
"node_modules/@radix-ui/react-menu": {
|
1452 |
-
"version": "2.1.15",
|
1453 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz",
|
1454 |
-
"integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==",
|
1455 |
-
"license": "MIT",
|
1456 |
-
"dependencies": {
|
1457 |
-
"@radix-ui/primitive": "1.1.2",
|
1458 |
-
"@radix-ui/react-collection": "1.1.7",
|
1459 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1460 |
-
"@radix-ui/react-context": "1.1.2",
|
1461 |
-
"@radix-ui/react-direction": "1.1.1",
|
1462 |
-
"@radix-ui/react-dismissable-layer": "1.1.10",
|
1463 |
-
"@radix-ui/react-focus-guards": "1.1.2",
|
1464 |
-
"@radix-ui/react-focus-scope": "1.1.7",
|
1465 |
-
"@radix-ui/react-id": "1.1.1",
|
1466 |
-
"@radix-ui/react-popper": "1.2.7",
|
1467 |
-
"@radix-ui/react-portal": "1.1.9",
|
1468 |
-
"@radix-ui/react-presence": "1.1.4",
|
1469 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1470 |
-
"@radix-ui/react-roving-focus": "1.1.10",
|
1471 |
-
"@radix-ui/react-slot": "1.2.3",
|
1472 |
-
"@radix-ui/react-use-callback-ref": "1.1.1",
|
1473 |
-
"aria-hidden": "^1.2.4",
|
1474 |
-
"react-remove-scroll": "^2.6.3"
|
1475 |
-
},
|
1476 |
-
"peerDependencies": {
|
1477 |
-
"@types/react": "*",
|
1478 |
-
"@types/react-dom": "*",
|
1479 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1480 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1481 |
-
},
|
1482 |
-
"peerDependenciesMeta": {
|
1483 |
-
"@types/react": {
|
1484 |
-
"optional": true
|
1485 |
-
},
|
1486 |
-
"@types/react-dom": {
|
1487 |
-
"optional": true
|
1488 |
-
}
|
1489 |
-
}
|
1490 |
-
},
|
1491 |
-
"node_modules/@radix-ui/react-popover": {
|
1492 |
-
"version": "1.1.14",
|
1493 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz",
|
1494 |
-
"integrity": "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==",
|
1495 |
-
"license": "MIT",
|
1496 |
-
"dependencies": {
|
1497 |
-
"@radix-ui/primitive": "1.1.2",
|
1498 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1499 |
-
"@radix-ui/react-context": "1.1.2",
|
1500 |
-
"@radix-ui/react-dismissable-layer": "1.1.10",
|
1501 |
-
"@radix-ui/react-focus-guards": "1.1.2",
|
1502 |
-
"@radix-ui/react-focus-scope": "1.1.7",
|
1503 |
-
"@radix-ui/react-id": "1.1.1",
|
1504 |
-
"@radix-ui/react-popper": "1.2.7",
|
1505 |
-
"@radix-ui/react-portal": "1.1.9",
|
1506 |
-
"@radix-ui/react-presence": "1.1.4",
|
1507 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1508 |
-
"@radix-ui/react-slot": "1.2.3",
|
1509 |
-
"@radix-ui/react-use-controllable-state": "1.2.2",
|
1510 |
-
"aria-hidden": "^1.2.4",
|
1511 |
-
"react-remove-scroll": "^2.6.3"
|
1512 |
-
},
|
1513 |
-
"peerDependencies": {
|
1514 |
-
"@types/react": "*",
|
1515 |
-
"@types/react-dom": "*",
|
1516 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1517 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1518 |
-
},
|
1519 |
-
"peerDependenciesMeta": {
|
1520 |
-
"@types/react": {
|
1521 |
-
"optional": true
|
1522 |
-
},
|
1523 |
-
"@types/react-dom": {
|
1524 |
-
"optional": true
|
1525 |
-
}
|
1526 |
-
}
|
1527 |
-
},
|
1528 |
-
"node_modules/@radix-ui/react-popper": {
|
1529 |
-
"version": "1.2.7",
|
1530 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz",
|
1531 |
-
"integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==",
|
1532 |
-
"license": "MIT",
|
1533 |
-
"dependencies": {
|
1534 |
-
"@floating-ui/react-dom": "^2.0.0",
|
1535 |
-
"@radix-ui/react-arrow": "1.1.7",
|
1536 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1537 |
-
"@radix-ui/react-context": "1.1.2",
|
1538 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1539 |
-
"@radix-ui/react-use-callback-ref": "1.1.1",
|
1540 |
-
"@radix-ui/react-use-layout-effect": "1.1.1",
|
1541 |
-
"@radix-ui/react-use-rect": "1.1.1",
|
1542 |
-
"@radix-ui/react-use-size": "1.1.1",
|
1543 |
-
"@radix-ui/rect": "1.1.1"
|
1544 |
-
},
|
1545 |
-
"peerDependencies": {
|
1546 |
-
"@types/react": "*",
|
1547 |
-
"@types/react-dom": "*",
|
1548 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1549 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1550 |
-
},
|
1551 |
-
"peerDependenciesMeta": {
|
1552 |
-
"@types/react": {
|
1553 |
-
"optional": true
|
1554 |
-
},
|
1555 |
-
"@types/react-dom": {
|
1556 |
-
"optional": true
|
1557 |
-
}
|
1558 |
-
}
|
1559 |
-
},
|
1560 |
-
"node_modules/@radix-ui/react-portal": {
|
1561 |
-
"version": "1.1.9",
|
1562 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
|
1563 |
-
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
|
1564 |
-
"license": "MIT",
|
1565 |
-
"dependencies": {
|
1566 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1567 |
-
"@radix-ui/react-use-layout-effect": "1.1.1"
|
1568 |
-
},
|
1569 |
-
"peerDependencies": {
|
1570 |
-
"@types/react": "*",
|
1571 |
-
"@types/react-dom": "*",
|
1572 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1573 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1574 |
-
},
|
1575 |
-
"peerDependenciesMeta": {
|
1576 |
-
"@types/react": {
|
1577 |
-
"optional": true
|
1578 |
-
},
|
1579 |
-
"@types/react-dom": {
|
1580 |
-
"optional": true
|
1581 |
-
}
|
1582 |
-
}
|
1583 |
-
},
|
1584 |
-
"node_modules/@radix-ui/react-presence": {
|
1585 |
-
"version": "1.1.4",
|
1586 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
|
1587 |
-
"integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
|
1588 |
-
"license": "MIT",
|
1589 |
-
"dependencies": {
|
1590 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1591 |
-
"@radix-ui/react-use-layout-effect": "1.1.1"
|
1592 |
-
},
|
1593 |
-
"peerDependencies": {
|
1594 |
-
"@types/react": "*",
|
1595 |
-
"@types/react-dom": "*",
|
1596 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1597 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1598 |
-
},
|
1599 |
-
"peerDependenciesMeta": {
|
1600 |
-
"@types/react": {
|
1601 |
-
"optional": true
|
1602 |
-
},
|
1603 |
-
"@types/react-dom": {
|
1604 |
-
"optional": true
|
1605 |
-
}
|
1606 |
-
}
|
1607 |
-
},
|
1608 |
-
"node_modules/@radix-ui/react-primitive": {
|
1609 |
-
"version": "2.1.3",
|
1610 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
1611 |
-
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
1612 |
-
"license": "MIT",
|
1613 |
-
"dependencies": {
|
1614 |
-
"@radix-ui/react-slot": "1.2.3"
|
1615 |
-
},
|
1616 |
-
"peerDependencies": {
|
1617 |
-
"@types/react": "*",
|
1618 |
-
"@types/react-dom": "*",
|
1619 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1620 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1621 |
-
},
|
1622 |
-
"peerDependenciesMeta": {
|
1623 |
-
"@types/react": {
|
1624 |
-
"optional": true
|
1625 |
-
},
|
1626 |
-
"@types/react-dom": {
|
1627 |
-
"optional": true
|
1628 |
-
}
|
1629 |
-
}
|
1630 |
-
},
|
1631 |
-
"node_modules/@radix-ui/react-roving-focus": {
|
1632 |
-
"version": "1.1.10",
|
1633 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz",
|
1634 |
-
"integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==",
|
1635 |
-
"license": "MIT",
|
1636 |
-
"dependencies": {
|
1637 |
-
"@radix-ui/primitive": "1.1.2",
|
1638 |
-
"@radix-ui/react-collection": "1.1.7",
|
1639 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1640 |
-
"@radix-ui/react-context": "1.1.2",
|
1641 |
-
"@radix-ui/react-direction": "1.1.1",
|
1642 |
-
"@radix-ui/react-id": "1.1.1",
|
1643 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1644 |
-
"@radix-ui/react-use-callback-ref": "1.1.1",
|
1645 |
-
"@radix-ui/react-use-controllable-state": "1.2.2"
|
1646 |
-
},
|
1647 |
-
"peerDependencies": {
|
1648 |
-
"@types/react": "*",
|
1649 |
-
"@types/react-dom": "*",
|
1650 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1651 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1652 |
-
},
|
1653 |
-
"peerDependenciesMeta": {
|
1654 |
-
"@types/react": {
|
1655 |
-
"optional": true
|
1656 |
-
},
|
1657 |
-
"@types/react-dom": {
|
1658 |
-
"optional": true
|
1659 |
-
}
|
1660 |
-
}
|
1661 |
-
},
|
1662 |
-
"node_modules/@radix-ui/react-select": {
|
1663 |
-
"version": "2.2.5",
|
1664 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz",
|
1665 |
-
"integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==",
|
1666 |
-
"license": "MIT",
|
1667 |
-
"dependencies": {
|
1668 |
-
"@radix-ui/number": "1.1.1",
|
1669 |
-
"@radix-ui/primitive": "1.1.2",
|
1670 |
-
"@radix-ui/react-collection": "1.1.7",
|
1671 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1672 |
-
"@radix-ui/react-context": "1.1.2",
|
1673 |
-
"@radix-ui/react-direction": "1.1.1",
|
1674 |
-
"@radix-ui/react-dismissable-layer": "1.1.10",
|
1675 |
-
"@radix-ui/react-focus-guards": "1.1.2",
|
1676 |
-
"@radix-ui/react-focus-scope": "1.1.7",
|
1677 |
-
"@radix-ui/react-id": "1.1.1",
|
1678 |
-
"@radix-ui/react-popper": "1.2.7",
|
1679 |
-
"@radix-ui/react-portal": "1.1.9",
|
1680 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1681 |
-
"@radix-ui/react-slot": "1.2.3",
|
1682 |
-
"@radix-ui/react-use-callback-ref": "1.1.1",
|
1683 |
-
"@radix-ui/react-use-controllable-state": "1.2.2",
|
1684 |
-
"@radix-ui/react-use-layout-effect": "1.1.1",
|
1685 |
-
"@radix-ui/react-use-previous": "1.1.1",
|
1686 |
-
"@radix-ui/react-visually-hidden": "1.2.3",
|
1687 |
-
"aria-hidden": "^1.2.4",
|
1688 |
-
"react-remove-scroll": "^2.6.3"
|
1689 |
-
},
|
1690 |
-
"peerDependencies": {
|
1691 |
-
"@types/react": "*",
|
1692 |
-
"@types/react-dom": "*",
|
1693 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1694 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1695 |
-
},
|
1696 |
-
"peerDependenciesMeta": {
|
1697 |
-
"@types/react": {
|
1698 |
-
"optional": true
|
1699 |
-
},
|
1700 |
-
"@types/react-dom": {
|
1701 |
-
"optional": true
|
1702 |
-
}
|
1703 |
-
}
|
1704 |
-
},
|
1705 |
-
"node_modules/@radix-ui/react-slot": {
|
1706 |
-
"version": "1.2.3",
|
1707 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
1708 |
-
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
1709 |
-
"license": "MIT",
|
1710 |
-
"dependencies": {
|
1711 |
-
"@radix-ui/react-compose-refs": "1.1.2"
|
1712 |
-
},
|
1713 |
-
"peerDependencies": {
|
1714 |
-
"@types/react": "*",
|
1715 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1716 |
-
},
|
1717 |
-
"peerDependenciesMeta": {
|
1718 |
-
"@types/react": {
|
1719 |
-
"optional": true
|
1720 |
-
}
|
1721 |
-
}
|
1722 |
-
},
|
1723 |
-
"node_modules/@radix-ui/react-switch": {
|
1724 |
-
"version": "1.2.5",
|
1725 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.5.tgz",
|
1726 |
-
"integrity": "sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==",
|
1727 |
-
"license": "MIT",
|
1728 |
-
"dependencies": {
|
1729 |
-
"@radix-ui/primitive": "1.1.2",
|
1730 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1731 |
-
"@radix-ui/react-context": "1.1.2",
|
1732 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1733 |
-
"@radix-ui/react-use-controllable-state": "1.2.2",
|
1734 |
-
"@radix-ui/react-use-previous": "1.1.1",
|
1735 |
-
"@radix-ui/react-use-size": "1.1.1"
|
1736 |
-
},
|
1737 |
-
"peerDependencies": {
|
1738 |
-
"@types/react": "*",
|
1739 |
-
"@types/react-dom": "*",
|
1740 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1741 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1742 |
-
},
|
1743 |
-
"peerDependenciesMeta": {
|
1744 |
-
"@types/react": {
|
1745 |
-
"optional": true
|
1746 |
-
},
|
1747 |
-
"@types/react-dom": {
|
1748 |
-
"optional": true
|
1749 |
-
}
|
1750 |
-
}
|
1751 |
-
},
|
1752 |
-
"node_modules/@radix-ui/react-tabs": {
|
1753 |
-
"version": "1.1.12",
|
1754 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.12.tgz",
|
1755 |
-
"integrity": "sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==",
|
1756 |
-
"license": "MIT",
|
1757 |
-
"dependencies": {
|
1758 |
-
"@radix-ui/primitive": "1.1.2",
|
1759 |
-
"@radix-ui/react-context": "1.1.2",
|
1760 |
-
"@radix-ui/react-direction": "1.1.1",
|
1761 |
-
"@radix-ui/react-id": "1.1.1",
|
1762 |
-
"@radix-ui/react-presence": "1.1.4",
|
1763 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1764 |
-
"@radix-ui/react-roving-focus": "1.1.10",
|
1765 |
-
"@radix-ui/react-use-controllable-state": "1.2.2"
|
1766 |
-
},
|
1767 |
-
"peerDependencies": {
|
1768 |
-
"@types/react": "*",
|
1769 |
-
"@types/react-dom": "*",
|
1770 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1771 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1772 |
-
},
|
1773 |
-
"peerDependenciesMeta": {
|
1774 |
-
"@types/react": {
|
1775 |
-
"optional": true
|
1776 |
-
},
|
1777 |
-
"@types/react-dom": {
|
1778 |
-
"optional": true
|
1779 |
-
}
|
1780 |
-
}
|
1781 |
-
},
|
1782 |
-
"node_modules/@radix-ui/react-toggle": {
|
1783 |
-
"version": "1.1.9",
|
1784 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.9.tgz",
|
1785 |
-
"integrity": "sha512-ZoFkBBz9zv9GWer7wIjvdRxmh2wyc2oKWw6C6CseWd6/yq1DK/l5lJ+wnsmFwJZbBYqr02mrf8A2q/CVCuM3ZA==",
|
1786 |
-
"license": "MIT",
|
1787 |
-
"dependencies": {
|
1788 |
-
"@radix-ui/primitive": "1.1.2",
|
1789 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1790 |
-
"@radix-ui/react-use-controllable-state": "1.2.2"
|
1791 |
-
},
|
1792 |
-
"peerDependencies": {
|
1793 |
-
"@types/react": "*",
|
1794 |
-
"@types/react-dom": "*",
|
1795 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1796 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1797 |
-
},
|
1798 |
-
"peerDependenciesMeta": {
|
1799 |
-
"@types/react": {
|
1800 |
-
"optional": true
|
1801 |
-
},
|
1802 |
-
"@types/react-dom": {
|
1803 |
-
"optional": true
|
1804 |
-
}
|
1805 |
-
}
|
1806 |
-
},
|
1807 |
-
"node_modules/@radix-ui/react-toggle-group": {
|
1808 |
-
"version": "1.1.10",
|
1809 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.10.tgz",
|
1810 |
-
"integrity": "sha512-kiU694Km3WFLTC75DdqgM/3Jauf3rD9wxeS9XtyWFKsBUeZA337lC+6uUazT7I1DhanZ5gyD5Stf8uf2dbQxOQ==",
|
1811 |
-
"license": "MIT",
|
1812 |
-
"dependencies": {
|
1813 |
-
"@radix-ui/primitive": "1.1.2",
|
1814 |
-
"@radix-ui/react-context": "1.1.2",
|
1815 |
-
"@radix-ui/react-direction": "1.1.1",
|
1816 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1817 |
-
"@radix-ui/react-roving-focus": "1.1.10",
|
1818 |
-
"@radix-ui/react-toggle": "1.1.9",
|
1819 |
-
"@radix-ui/react-use-controllable-state": "1.2.2"
|
1820 |
-
},
|
1821 |
-
"peerDependencies": {
|
1822 |
-
"@types/react": "*",
|
1823 |
-
"@types/react-dom": "*",
|
1824 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1825 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1826 |
-
},
|
1827 |
-
"peerDependenciesMeta": {
|
1828 |
-
"@types/react": {
|
1829 |
-
"optional": true
|
1830 |
-
},
|
1831 |
-
"@types/react-dom": {
|
1832 |
-
"optional": true
|
1833 |
-
}
|
1834 |
-
}
|
1835 |
-
},
|
1836 |
-
"node_modules/@radix-ui/react-tooltip": {
|
1837 |
-
"version": "1.2.7",
|
1838 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz",
|
1839 |
-
"integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==",
|
1840 |
-
"license": "MIT",
|
1841 |
-
"dependencies": {
|
1842 |
-
"@radix-ui/primitive": "1.1.2",
|
1843 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1844 |
-
"@radix-ui/react-context": "1.1.2",
|
1845 |
-
"@radix-ui/react-dismissable-layer": "1.1.10",
|
1846 |
-
"@radix-ui/react-id": "1.1.1",
|
1847 |
-
"@radix-ui/react-popper": "1.2.7",
|
1848 |
-
"@radix-ui/react-portal": "1.1.9",
|
1849 |
-
"@radix-ui/react-presence": "1.1.4",
|
1850 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1851 |
-
"@radix-ui/react-slot": "1.2.3",
|
1852 |
-
"@radix-ui/react-use-controllable-state": "1.2.2",
|
1853 |
-
"@radix-ui/react-visually-hidden": "1.2.3"
|
1854 |
-
},
|
1855 |
-
"peerDependencies": {
|
1856 |
-
"@types/react": "*",
|
1857 |
-
"@types/react-dom": "*",
|
1858 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1859 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1860 |
-
},
|
1861 |
-
"peerDependenciesMeta": {
|
1862 |
-
"@types/react": {
|
1863 |
-
"optional": true
|
1864 |
-
},
|
1865 |
-
"@types/react-dom": {
|
1866 |
-
"optional": true
|
1867 |
-
}
|
1868 |
-
}
|
1869 |
-
},
|
1870 |
-
"node_modules/@radix-ui/react-use-callback-ref": {
|
1871 |
-
"version": "1.1.1",
|
1872 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
1873 |
-
"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
|
1874 |
-
"license": "MIT",
|
1875 |
-
"peerDependencies": {
|
1876 |
-
"@types/react": "*",
|
1877 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1878 |
-
},
|
1879 |
-
"peerDependenciesMeta": {
|
1880 |
-
"@types/react": {
|
1881 |
-
"optional": true
|
1882 |
-
}
|
1883 |
-
}
|
1884 |
-
},
|
1885 |
-
"node_modules/@radix-ui/react-use-controllable-state": {
|
1886 |
-
"version": "1.2.2",
|
1887 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
|
1888 |
-
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
|
1889 |
-
"license": "MIT",
|
1890 |
-
"dependencies": {
|
1891 |
-
"@radix-ui/react-use-effect-event": "0.0.2",
|
1892 |
-
"@radix-ui/react-use-layout-effect": "1.1.1"
|
1893 |
-
},
|
1894 |
-
"peerDependencies": {
|
1895 |
-
"@types/react": "*",
|
1896 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1897 |
-
},
|
1898 |
-
"peerDependenciesMeta": {
|
1899 |
-
"@types/react": {
|
1900 |
-
"optional": true
|
1901 |
-
}
|
1902 |
-
}
|
1903 |
-
},
|
1904 |
-
"node_modules/@radix-ui/react-use-effect-event": {
|
1905 |
-
"version": "0.0.2",
|
1906 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
|
1907 |
-
"integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
|
1908 |
-
"license": "MIT",
|
1909 |
-
"dependencies": {
|
1910 |
-
"@radix-ui/react-use-layout-effect": "1.1.1"
|
1911 |
-
},
|
1912 |
-
"peerDependencies": {
|
1913 |
-
"@types/react": "*",
|
1914 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1915 |
-
},
|
1916 |
-
"peerDependenciesMeta": {
|
1917 |
-
"@types/react": {
|
1918 |
-
"optional": true
|
1919 |
-
}
|
1920 |
-
}
|
1921 |
-
},
|
1922 |
-
"node_modules/@radix-ui/react-use-escape-keydown": {
|
1923 |
-
"version": "1.1.1",
|
1924 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
|
1925 |
-
"integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
|
1926 |
-
"license": "MIT",
|
1927 |
-
"dependencies": {
|
1928 |
-
"@radix-ui/react-use-callback-ref": "1.1.1"
|
1929 |
-
},
|
1930 |
-
"peerDependencies": {
|
1931 |
-
"@types/react": "*",
|
1932 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1933 |
-
},
|
1934 |
-
"peerDependenciesMeta": {
|
1935 |
-
"@types/react": {
|
1936 |
-
"optional": true
|
1937 |
-
}
|
1938 |
-
}
|
1939 |
-
},
|
1940 |
-
"node_modules/@radix-ui/react-use-is-hydrated": {
|
1941 |
-
"version": "0.1.0",
|
1942 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz",
|
1943 |
-
"integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==",
|
1944 |
-
"license": "MIT",
|
1945 |
-
"dependencies": {
|
1946 |
-
"use-sync-external-store": "^1.5.0"
|
1947 |
-
},
|
1948 |
-
"peerDependencies": {
|
1949 |
-
"@types/react": "*",
|
1950 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1951 |
-
},
|
1952 |
-
"peerDependenciesMeta": {
|
1953 |
-
"@types/react": {
|
1954 |
-
"optional": true
|
1955 |
-
}
|
1956 |
-
}
|
1957 |
-
},
|
1958 |
-
"node_modules/@radix-ui/react-use-layout-effect": {
|
1959 |
-
"version": "1.1.1",
|
1960 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
|
1961 |
-
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
|
1962 |
-
"license": "MIT",
|
1963 |
-
"peerDependencies": {
|
1964 |
-
"@types/react": "*",
|
1965 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1966 |
-
},
|
1967 |
-
"peerDependenciesMeta": {
|
1968 |
-
"@types/react": {
|
1969 |
-
"optional": true
|
1970 |
-
}
|
1971 |
-
}
|
1972 |
-
},
|
1973 |
-
"node_modules/@radix-ui/react-use-previous": {
|
1974 |
-
"version": "1.1.1",
|
1975 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
|
1976 |
-
"integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
|
1977 |
-
"license": "MIT",
|
1978 |
-
"peerDependencies": {
|
1979 |
-
"@types/react": "*",
|
1980 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1981 |
-
},
|
1982 |
-
"peerDependenciesMeta": {
|
1983 |
-
"@types/react": {
|
1984 |
-
"optional": true
|
1985 |
-
}
|
1986 |
-
}
|
1987 |
-
},
|
1988 |
-
"node_modules/@radix-ui/react-use-rect": {
|
1989 |
-
"version": "1.1.1",
|
1990 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
|
1991 |
-
"integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
|
1992 |
-
"license": "MIT",
|
1993 |
-
"dependencies": {
|
1994 |
-
"@radix-ui/rect": "1.1.1"
|
1995 |
-
},
|
1996 |
-
"peerDependencies": {
|
1997 |
-
"@types/react": "*",
|
1998 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1999 |
-
},
|
2000 |
-
"peerDependenciesMeta": {
|
2001 |
-
"@types/react": {
|
2002 |
-
"optional": true
|
2003 |
-
}
|
2004 |
-
}
|
2005 |
-
},
|
2006 |
-
"node_modules/@radix-ui/react-use-size": {
|
2007 |
-
"version": "1.1.1",
|
2008 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
|
2009 |
-
"integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
|
2010 |
-
"license": "MIT",
|
2011 |
-
"dependencies": {
|
2012 |
-
"@radix-ui/react-use-layout-effect": "1.1.1"
|
2013 |
-
},
|
2014 |
-
"peerDependencies": {
|
2015 |
-
"@types/react": "*",
|
2016 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
2017 |
-
},
|
2018 |
-
"peerDependenciesMeta": {
|
2019 |
-
"@types/react": {
|
2020 |
-
"optional": true
|
2021 |
-
}
|
2022 |
-
}
|
2023 |
-
},
|
2024 |
-
"node_modules/@radix-ui/react-visually-hidden": {
|
2025 |
-
"version": "1.2.3",
|
2026 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
|
2027 |
-
"integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
|
2028 |
-
"license": "MIT",
|
2029 |
-
"dependencies": {
|
2030 |
-
"@radix-ui/react-primitive": "2.1.3"
|
2031 |
-
},
|
2032 |
-
"peerDependencies": {
|
2033 |
-
"@types/react": "*",
|
2034 |
-
"@types/react-dom": "*",
|
2035 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
2036 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
2037 |
-
},
|
2038 |
-
"peerDependenciesMeta": {
|
2039 |
-
"@types/react": {
|
2040 |
-
"optional": true
|
2041 |
-
},
|
2042 |
-
"@types/react-dom": {
|
2043 |
-
"optional": true
|
2044 |
-
}
|
2045 |
-
}
|
2046 |
-
},
|
2047 |
-
"node_modules/@radix-ui/rect": {
|
2048 |
-
"version": "1.1.1",
|
2049 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
|
2050 |
-
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
2051 |
-
"license": "MIT"
|
2052 |
-
},
|
2053 |
"node_modules/@rollup/rollup-android-arm-eabi": {
|
2054 |
"version": "4.36.0",
|
2055 |
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.36.0.tgz",
|
@@ -2648,12 +1702,11 @@
|
|
2648 |
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="
|
2649 |
},
|
2650 |
"node_modules/@types/node": {
|
2651 |
-
"version": "22.
|
2652 |
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.
|
2653 |
-
"integrity": "sha512-
|
2654 |
-
"license": "MIT",
|
2655 |
"dependencies": {
|
2656 |
-
"undici-types": "~6.
|
2657 |
}
|
2658 |
},
|
2659 |
"node_modules/@types/qs": {
|
@@ -2680,7 +1733,7 @@
|
|
2680 |
"version": "19.0.4",
|
2681 |
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz",
|
2682 |
"integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==",
|
2683 |
-
"
|
2684 |
"peerDependencies": {
|
2685 |
"@types/react": "^19.0.0"
|
2686 |
}
|
@@ -3048,18 +2101,6 @@
|
|
3048 |
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
3049 |
"dev": true
|
3050 |
},
|
3051 |
-
"node_modules/aria-hidden": {
|
3052 |
-
"version": "1.2.6",
|
3053 |
-
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
3054 |
-
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
|
3055 |
-
"license": "MIT",
|
3056 |
-
"dependencies": {
|
3057 |
-
"tslib": "^2.0.0"
|
3058 |
-
},
|
3059 |
-
"engines": {
|
3060 |
-
"node": ">=10"
|
3061 |
-
}
|
3062 |
-
},
|
3063 |
"node_modules/array-flatten": {
|
3064 |
"version": "1.1.1",
|
3065 |
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
@@ -3424,18 +2465,6 @@
|
|
3424 |
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
3425 |
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
3426 |
},
|
3427 |
-
"node_modules/class-variance-authority": {
|
3428 |
-
"version": "0.7.1",
|
3429 |
-
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
3430 |
-
"integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
|
3431 |
-
"license": "Apache-2.0",
|
3432 |
-
"dependencies": {
|
3433 |
-
"clsx": "^2.1.1"
|
3434 |
-
},
|
3435 |
-
"funding": {
|
3436 |
-
"url": "https://polar.sh/cva"
|
3437 |
-
}
|
3438 |
-
},
|
3439 |
"node_modules/classnames": {
|
3440 |
"version": "2.5.1",
|
3441 |
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
@@ -3445,7 +2474,6 @@
|
|
3445 |
"version": "2.1.1",
|
3446 |
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
3447 |
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
3448 |
-
"license": "MIT",
|
3449 |
"engines": {
|
3450 |
"node": ">=6"
|
3451 |
}
|
@@ -3696,12 +2724,6 @@
|
|
3696 |
"node": ">=8"
|
3697 |
}
|
3698 |
},
|
3699 |
-
"node_modules/detect-node-es": {
|
3700 |
-
"version": "1.1.0",
|
3701 |
-
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
3702 |
-
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
|
3703 |
-
"license": "MIT"
|
3704 |
-
},
|
3705 |
"node_modules/devlop": {
|
3706 |
"version": "1.1.0",
|
3707 |
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
|
@@ -4370,15 +3392,6 @@
|
|
4370 |
"url": "https://github.com/sponsors/ljharb"
|
4371 |
}
|
4372 |
},
|
4373 |
-
"node_modules/get-nonce": {
|
4374 |
-
"version": "1.0.1",
|
4375 |
-
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
4376 |
-
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
|
4377 |
-
"license": "MIT",
|
4378 |
-
"engines": {
|
4379 |
-
"node": ">=6"
|
4380 |
-
}
|
4381 |
-
},
|
4382 |
"node_modules/get-proto": {
|
4383 |
"version": "1.0.1",
|
4384 |
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
@@ -5088,15 +4101,6 @@
|
|
5088 |
"yallist": "^3.0.2"
|
5089 |
}
|
5090 |
},
|
5091 |
-
"node_modules/lucide-react": {
|
5092 |
-
"version": "0.511.0",
|
5093 |
-
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.511.0.tgz",
|
5094 |
-
"integrity": "sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==",
|
5095 |
-
"license": "ISC",
|
5096 |
-
"peerDependencies": {
|
5097 |
-
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
5098 |
-
}
|
5099 |
-
},
|
5100 |
"node_modules/math-intrinsics": {
|
5101 |
"version": "1.1.0",
|
5102 |
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
@@ -5854,16 +4858,6 @@
|
|
5854 |
"node": ">= 0.6"
|
5855 |
}
|
5856 |
},
|
5857 |
-
"node_modules/next-themes": {
|
5858 |
-
"version": "0.4.6",
|
5859 |
-
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
|
5860 |
-
"integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
|
5861 |
-
"license": "MIT",
|
5862 |
-
"peerDependencies": {
|
5863 |
-
"react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
|
5864 |
-
"react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
|
5865 |
-
}
|
5866 |
-
},
|
5867 |
"node_modules/node-abi": {
|
5868 |
"version": "3.74.0",
|
5869 |
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz",
|
@@ -6393,53 +5387,6 @@
|
|
6393 |
"node": ">=0.10.0"
|
6394 |
}
|
6395 |
},
|
6396 |
-
"node_modules/react-remove-scroll": {
|
6397 |
-
"version": "2.7.0",
|
6398 |
-
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.0.tgz",
|
6399 |
-
"integrity": "sha512-sGsQtcjMqdQyijAHytfGEELB8FufGbfXIsvUTe+NLx1GDRJCXtCFLBLUI1eyZCKXXvbEU2C6gai0PZKoIE9Vbg==",
|
6400 |
-
"license": "MIT",
|
6401 |
-
"dependencies": {
|
6402 |
-
"react-remove-scroll-bar": "^2.3.7",
|
6403 |
-
"react-style-singleton": "^2.2.3",
|
6404 |
-
"tslib": "^2.1.0",
|
6405 |
-
"use-callback-ref": "^1.3.3",
|
6406 |
-
"use-sidecar": "^1.1.3"
|
6407 |
-
},
|
6408 |
-
"engines": {
|
6409 |
-
"node": ">=10"
|
6410 |
-
},
|
6411 |
-
"peerDependencies": {
|
6412 |
-
"@types/react": "*",
|
6413 |
-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
6414 |
-
},
|
6415 |
-
"peerDependenciesMeta": {
|
6416 |
-
"@types/react": {
|
6417 |
-
"optional": true
|
6418 |
-
}
|
6419 |
-
}
|
6420 |
-
},
|
6421 |
-
"node_modules/react-remove-scroll-bar": {
|
6422 |
-
"version": "2.3.8",
|
6423 |
-
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
6424 |
-
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
6425 |
-
"license": "MIT",
|
6426 |
-
"dependencies": {
|
6427 |
-
"react-style-singleton": "^2.2.2",
|
6428 |
-
"tslib": "^2.0.0"
|
6429 |
-
},
|
6430 |
-
"engines": {
|
6431 |
-
"node": ">=10"
|
6432 |
-
},
|
6433 |
-
"peerDependencies": {
|
6434 |
-
"@types/react": "*",
|
6435 |
-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
6436 |
-
},
|
6437 |
-
"peerDependenciesMeta": {
|
6438 |
-
"@types/react": {
|
6439 |
-
"optional": true
|
6440 |
-
}
|
6441 |
-
}
|
6442 |
-
},
|
6443 |
"node_modules/react-speech-recognition": {
|
6444 |
"version": "4.0.0",
|
6445 |
"resolved": "https://registry.npmjs.org/react-speech-recognition/-/react-speech-recognition-4.0.0.tgz",
|
@@ -6448,28 +5395,6 @@
|
|
6448 |
"react": ">=16.8.0"
|
6449 |
}
|
6450 |
},
|
6451 |
-
"node_modules/react-style-singleton": {
|
6452 |
-
"version": "2.2.3",
|
6453 |
-
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
6454 |
-
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
6455 |
-
"license": "MIT",
|
6456 |
-
"dependencies": {
|
6457 |
-
"get-nonce": "^1.0.0",
|
6458 |
-
"tslib": "^2.0.0"
|
6459 |
-
},
|
6460 |
-
"engines": {
|
6461 |
-
"node": ">=10"
|
6462 |
-
},
|
6463 |
-
"peerDependencies": {
|
6464 |
-
"@types/react": "*",
|
6465 |
-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
6466 |
-
},
|
6467 |
-
"peerDependenciesMeta": {
|
6468 |
-
"@types/react": {
|
6469 |
-
"optional": true
|
6470 |
-
}
|
6471 |
-
}
|
6472 |
-
},
|
6473 |
"node_modules/react-toastify": {
|
6474 |
"version": "11.0.5",
|
6475 |
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz",
|
@@ -6950,16 +5875,6 @@
|
|
6950 |
"is-arrayish": "^0.3.1"
|
6951 |
}
|
6952 |
},
|
6953 |
-
"node_modules/sonner": {
|
6954 |
-
"version": "2.0.3",
|
6955 |
-
"resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.3.tgz",
|
6956 |
-
"integrity": "sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==",
|
6957 |
-
"license": "MIT",
|
6958 |
-
"peerDependencies": {
|
6959 |
-
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
|
6960 |
-
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
6961 |
-
}
|
6962 |
-
},
|
6963 |
"node_modules/source-map": {
|
6964 |
"version": "0.6.1",
|
6965 |
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
@@ -7116,16 +6031,6 @@
|
|
7116 |
"node": ">=8"
|
7117 |
}
|
7118 |
},
|
7119 |
-
"node_modules/tailwind-merge": {
|
7120 |
-
"version": "3.3.0",
|
7121 |
-
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.0.tgz",
|
7122 |
-
"integrity": "sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==",
|
7123 |
-
"license": "MIT",
|
7124 |
-
"funding": {
|
7125 |
-
"type": "github",
|
7126 |
-
"url": "https://github.com/sponsors/dcastil"
|
7127 |
-
}
|
7128 |
-
},
|
7129 |
"node_modules/tailwindcss": {
|
7130 |
"version": "4.0.15",
|
7131 |
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.15.tgz",
|
@@ -7254,16 +6159,6 @@
|
|
7254 |
"node": "*"
|
7255 |
}
|
7256 |
},
|
7257 |
-
"node_modules/tw-animate-css": {
|
7258 |
-
"version": "1.3.0",
|
7259 |
-
"resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.0.tgz",
|
7260 |
-
"integrity": "sha512-jrJ0XenzS9KVuDThJDvnhalbl4IYiMQ/XvpA0a2FL8KmlK+6CSMviO7ROY/I7z1NnUs5NnDhlM6fXmF40xPxzw==",
|
7261 |
-
"dev": true,
|
7262 |
-
"license": "MIT",
|
7263 |
-
"funding": {
|
7264 |
-
"url": "https://github.com/sponsors/Wombosvideo"
|
7265 |
-
}
|
7266 |
-
},
|
7267 |
"node_modules/type-check": {
|
7268 |
"version": "0.4.0",
|
7269 |
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
@@ -7324,10 +6219,9 @@
|
|
7324 |
}
|
7325 |
},
|
7326 |
"node_modules/undici-types": {
|
7327 |
-
"version": "6.
|
7328 |
-
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.
|
7329 |
-
"integrity": "sha512-
|
7330 |
-
"license": "MIT"
|
7331 |
},
|
7332 |
"node_modules/unified": {
|
7333 |
"version": "11.0.5",
|
@@ -7457,58 +6351,6 @@
|
|
7457 |
"punycode": "^2.1.0"
|
7458 |
}
|
7459 |
},
|
7460 |
-
"node_modules/use-callback-ref": {
|
7461 |
-
"version": "1.3.3",
|
7462 |
-
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
7463 |
-
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
7464 |
-
"license": "MIT",
|
7465 |
-
"dependencies": {
|
7466 |
-
"tslib": "^2.0.0"
|
7467 |
-
},
|
7468 |
-
"engines": {
|
7469 |
-
"node": ">=10"
|
7470 |
-
},
|
7471 |
-
"peerDependencies": {
|
7472 |
-
"@types/react": "*",
|
7473 |
-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
7474 |
-
},
|
7475 |
-
"peerDependenciesMeta": {
|
7476 |
-
"@types/react": {
|
7477 |
-
"optional": true
|
7478 |
-
}
|
7479 |
-
}
|
7480 |
-
},
|
7481 |
-
"node_modules/use-sidecar": {
|
7482 |
-
"version": "1.1.3",
|
7483 |
-
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
|
7484 |
-
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
|
7485 |
-
"license": "MIT",
|
7486 |
-
"dependencies": {
|
7487 |
-
"detect-node-es": "^1.1.0",
|
7488 |
-
"tslib": "^2.0.0"
|
7489 |
-
},
|
7490 |
-
"engines": {
|
7491 |
-
"node": ">=10"
|
7492 |
-
},
|
7493 |
-
"peerDependencies": {
|
7494 |
-
"@types/react": "*",
|
7495 |
-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
7496 |
-
},
|
7497 |
-
"peerDependenciesMeta": {
|
7498 |
-
"@types/react": {
|
7499 |
-
"optional": true
|
7500 |
-
}
|
7501 |
-
}
|
7502 |
-
},
|
7503 |
-
"node_modules/use-sync-external-store": {
|
7504 |
-
"version": "1.5.0",
|
7505 |
-
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
7506 |
-
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
7507 |
-
"license": "MIT",
|
7508 |
-
"peerDependencies": {
|
7509 |
-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
7510 |
-
}
|
7511 |
-
},
|
7512 |
"node_modules/util-deprecate": {
|
7513 |
"version": "1.0.2",
|
7514 |
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
|
|
9 |
"version": "0.0.0",
|
10 |
"dependencies": {
|
11 |
"@huggingface/hub": "^1.1.1",
|
12 |
+
"@huggingface/inference": "^3.6.1",
|
13 |
"@monaco-editor/react": "^4.7.0",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
"@tailwindcss/vite": "^4.0.15",
|
15 |
"@xenova/transformers": "^2.17.2",
|
16 |
"body-parser": "^1.20.3",
|
|
|
17 |
"classnames": "^2.5.1",
|
|
|
18 |
"cookie-parser": "^1.4.7",
|
19 |
"dotenv": "^16.4.7",
|
20 |
"express": "^4.21.2",
|
|
|
|
|
21 |
"react": "^19.0.0",
|
22 |
"react-dom": "^19.0.0",
|
23 |
"react-icons": "^5.5.0",
|
|
|
25 |
"react-speech-recognition": "^4.0.0",
|
26 |
"react-toastify": "^11.0.5",
|
27 |
"react-use": "^17.6.0",
|
|
|
|
|
28 |
"tailwindcss": "^4.0.15"
|
29 |
},
|
30 |
"devDependencies": {
|
31 |
"@eslint/js": "^9.21.0",
|
32 |
"@types/express": "^5.0.1",
|
|
|
33 |
"@types/react": "^19.0.10",
|
34 |
"@types/react-dom": "^19.0.4",
|
35 |
"@types/react-speech-recognition": "^3.9.6",
|
|
|
38 |
"eslint-plugin-react-hooks": "^5.1.0",
|
39 |
"eslint-plugin-react-refresh": "^0.4.19",
|
40 |
"globals": "^15.15.0",
|
|
|
41 |
"typescript": "~5.7.2",
|
42 |
"typescript-eslint": "^8.24.1",
|
43 |
"vite": "^6.2.0"
|
|
|
172 |
}
|
173 |
},
|
174 |
"node_modules/@babel/helper-plugin-utils": {
|
175 |
+
"version": "7.26.5",
|
176 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
|
177 |
+
"integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==",
|
178 |
"dev": true,
|
|
|
179 |
"engines": {
|
180 |
"node": ">=6.9.0"
|
181 |
}
|
|
|
845 |
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
846 |
}
|
847 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
848 |
"node_modules/@huggingface/hub": {
|
849 |
"version": "1.1.1",
|
850 |
"resolved": "https://registry.npmjs.org/@huggingface/hub/-/hub-1.1.1.tgz",
|
|
|
862 |
"integrity": "sha512-HK6JTVB/nrgjOnbe77HFSENftfAp67AI4mHMR2x64Os1hvchuTT88M8fKEiyESSvqKFKwW4lQKkHva07p05AXw=="
|
863 |
},
|
864 |
"node_modules/@huggingface/inference": {
|
865 |
+
"version": "3.6.1",
|
866 |
+
"resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-3.6.1.tgz",
|
867 |
+
"integrity": "sha512-EtQlbBqcZycPe+qiTEFI+wNHOMpG0gwNTaZSvYu1juN1p/1dEgqAb2GO31dxLgNev2PzH9d+9nm8GngOsIepJg==",
|
|
|
868 |
"dependencies": {
|
869 |
+
"@huggingface/jinja": "^0.3.3",
|
870 |
+
"@huggingface/tasks": "^0.17.8"
|
871 |
},
|
872 |
"engines": {
|
873 |
"node": ">=18"
|
874 |
}
|
875 |
},
|
876 |
"node_modules/@huggingface/jinja": {
|
877 |
+
"version": "0.3.3",
|
878 |
+
"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.3.tgz",
|
879 |
+
"integrity": "sha512-vQQr2JyWvVFba3Lj9es4q9vCl1sAc74fdgnEMoX8qHrXtswap9ge9uO3ONDzQB0cQ0PUyaKY2N6HaVbTBvSXvw==",
|
|
|
880 |
"engines": {
|
881 |
"node": ">=18"
|
882 |
}
|
883 |
},
|
884 |
"node_modules/@huggingface/tasks": {
|
885 |
+
"version": "0.17.9",
|
886 |
+
"resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.17.9.tgz",
|
887 |
+
"integrity": "sha512-lV6RgCJkqy3p93FFxP9H4SGJmFcHAwr1FO+Zk56q/JWsf7Tdsel1DEo1Xfd3An7ZPWpc2Y9ldRecGo9efDYghg=="
|
|
|
888 |
},
|
889 |
"node_modules/@humanfs/core": {
|
890 |
"version": "0.19.1",
|
|
|
1104 |
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
1105 |
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
1106 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1107 |
"node_modules/@rollup/rollup-android-arm-eabi": {
|
1108 |
"version": "4.36.0",
|
1109 |
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.36.0.tgz",
|
|
|
1702 |
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="
|
1703 |
},
|
1704 |
"node_modules/@types/node": {
|
1705 |
+
"version": "22.13.13",
|
1706 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz",
|
1707 |
+
"integrity": "sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==",
|
|
|
1708 |
"dependencies": {
|
1709 |
+
"undici-types": "~6.20.0"
|
1710 |
}
|
1711 |
},
|
1712 |
"node_modules/@types/qs": {
|
|
|
1733 |
"version": "19.0.4",
|
1734 |
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz",
|
1735 |
"integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==",
|
1736 |
+
"dev": true,
|
1737 |
"peerDependencies": {
|
1738 |
"@types/react": "^19.0.0"
|
1739 |
}
|
|
|
2101 |
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
2102 |
"dev": true
|
2103 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2104 |
"node_modules/array-flatten": {
|
2105 |
"version": "1.1.1",
|
2106 |
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
|
|
2465 |
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
2466 |
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
2467 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2468 |
"node_modules/classnames": {
|
2469 |
"version": "2.5.1",
|
2470 |
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
|
|
2474 |
"version": "2.1.1",
|
2475 |
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
2476 |
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
|
|
2477 |
"engines": {
|
2478 |
"node": ">=6"
|
2479 |
}
|
|
|
2724 |
"node": ">=8"
|
2725 |
}
|
2726 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
2727 |
"node_modules/devlop": {
|
2728 |
"version": "1.1.0",
|
2729 |
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
|
|
|
3392 |
"url": "https://github.com/sponsors/ljharb"
|
3393 |
}
|
3394 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3395 |
"node_modules/get-proto": {
|
3396 |
"version": "1.0.1",
|
3397 |
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
|
|
4101 |
"yallist": "^3.0.2"
|
4102 |
}
|
4103 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4104 |
"node_modules/math-intrinsics": {
|
4105 |
"version": "1.1.0",
|
4106 |
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
|
|
4858 |
"node": ">= 0.6"
|
4859 |
}
|
4860 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4861 |
"node_modules/node-abi": {
|
4862 |
"version": "3.74.0",
|
4863 |
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz",
|
|
|
5387 |
"node": ">=0.10.0"
|
5388 |
}
|
5389 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5390 |
"node_modules/react-speech-recognition": {
|
5391 |
"version": "4.0.0",
|
5392 |
"resolved": "https://registry.npmjs.org/react-speech-recognition/-/react-speech-recognition-4.0.0.tgz",
|
|
|
5395 |
"react": ">=16.8.0"
|
5396 |
}
|
5397 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5398 |
"node_modules/react-toastify": {
|
5399 |
"version": "11.0.5",
|
5400 |
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz",
|
|
|
5875 |
"is-arrayish": "^0.3.1"
|
5876 |
}
|
5877 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5878 |
"node_modules/source-map": {
|
5879 |
"version": "0.6.1",
|
5880 |
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
|
|
6031 |
"node": ">=8"
|
6032 |
}
|
6033 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6034 |
"node_modules/tailwindcss": {
|
6035 |
"version": "4.0.15",
|
6036 |
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.15.tgz",
|
|
|
6159 |
"node": "*"
|
6160 |
}
|
6161 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6162 |
"node_modules/type-check": {
|
6163 |
"version": "0.4.0",
|
6164 |
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
|
|
6219 |
}
|
6220 |
},
|
6221 |
"node_modules/undici-types": {
|
6222 |
+
"version": "6.20.0",
|
6223 |
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
6224 |
+
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
|
|
|
6225 |
},
|
6226 |
"node_modules/unified": {
|
6227 |
"version": "11.0.5",
|
|
|
6351 |
"punycode": "^2.1.0"
|
6352 |
}
|
6353 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6354 |
"node_modules/util-deprecate": {
|
6355 |
"version": "1.0.2",
|
6356 |
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
package.json
CHANGED
@@ -12,30 +12,15 @@
|
|
12 |
},
|
13 |
"dependencies": {
|
14 |
"@huggingface/hub": "^1.1.1",
|
15 |
-
"@huggingface/inference": "^
|
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",
|
22 |
-
"@radix-ui/react-slot": "^1.2.3",
|
23 |
-
"@radix-ui/react-switch": "^1.2.5",
|
24 |
-
"@radix-ui/react-tabs": "^1.1.12",
|
25 |
-
"@radix-ui/react-toggle": "^1.1.9",
|
26 |
-
"@radix-ui/react-toggle-group": "^1.1.10",
|
27 |
-
"@radix-ui/react-tooltip": "^1.2.7",
|
28 |
"@tailwindcss/vite": "^4.0.15",
|
29 |
"@xenova/transformers": "^2.17.2",
|
30 |
"body-parser": "^1.20.3",
|
31 |
-
"class-variance-authority": "^0.7.1",
|
32 |
"classnames": "^2.5.1",
|
33 |
-
"clsx": "^2.1.1",
|
34 |
"cookie-parser": "^1.4.7",
|
35 |
"dotenv": "^16.4.7",
|
36 |
"express": "^4.21.2",
|
37 |
-
"lucide-react": "^0.511.0",
|
38 |
-
"next-themes": "^0.4.6",
|
39 |
"react": "^19.0.0",
|
40 |
"react-dom": "^19.0.0",
|
41 |
"react-icons": "^5.5.0",
|
@@ -43,14 +28,11 @@
|
|
43 |
"react-speech-recognition": "^4.0.0",
|
44 |
"react-toastify": "^11.0.5",
|
45 |
"react-use": "^17.6.0",
|
46 |
-
"sonner": "^2.0.3",
|
47 |
-
"tailwind-merge": "^3.3.0",
|
48 |
"tailwindcss": "^4.0.15"
|
49 |
},
|
50 |
"devDependencies": {
|
51 |
"@eslint/js": "^9.21.0",
|
52 |
"@types/express": "^5.0.1",
|
53 |
-
"@types/node": "^22.15.21",
|
54 |
"@types/react": "^19.0.10",
|
55 |
"@types/react-dom": "^19.0.4",
|
56 |
"@types/react-speech-recognition": "^3.9.6",
|
@@ -59,7 +41,6 @@
|
|
59 |
"eslint-plugin-react-hooks": "^5.1.0",
|
60 |
"eslint-plugin-react-refresh": "^0.4.19",
|
61 |
"globals": "^15.15.0",
|
62 |
-
"tw-animate-css": "^1.3.0",
|
63 |
"typescript": "~5.7.2",
|
64 |
"typescript-eslint": "^8.24.1",
|
65 |
"vite": "^6.2.0"
|
|
|
12 |
},
|
13 |
"dependencies": {
|
14 |
"@huggingface/hub": "^1.1.1",
|
15 |
+
"@huggingface/inference": "^3.6.1",
|
16 |
"@monaco-editor/react": "^4.7.0",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
"@tailwindcss/vite": "^4.0.15",
|
18 |
"@xenova/transformers": "^2.17.2",
|
19 |
"body-parser": "^1.20.3",
|
|
|
20 |
"classnames": "^2.5.1",
|
|
|
21 |
"cookie-parser": "^1.4.7",
|
22 |
"dotenv": "^16.4.7",
|
23 |
"express": "^4.21.2",
|
|
|
|
|
24 |
"react": "^19.0.0",
|
25 |
"react-dom": "^19.0.0",
|
26 |
"react-icons": "^5.5.0",
|
|
|
28 |
"react-speech-recognition": "^4.0.0",
|
29 |
"react-toastify": "^11.0.5",
|
30 |
"react-use": "^17.6.0",
|
|
|
|
|
31 |
"tailwindcss": "^4.0.15"
|
32 |
},
|
33 |
"devDependencies": {
|
34 |
"@eslint/js": "^9.21.0",
|
35 |
"@types/express": "^5.0.1",
|
|
|
36 |
"@types/react": "^19.0.10",
|
37 |
"@types/react-dom": "^19.0.4",
|
38 |
"@types/react-speech-recognition": "^3.9.6",
|
|
|
41 |
"eslint-plugin-react-hooks": "^5.1.0",
|
42 |
"eslint-plugin-react-refresh": "^0.4.19",
|
43 |
"globals": "^15.15.0",
|
|
|
44 |
"typescript": "~5.7.2",
|
45 |
"typescript-eslint": "^8.24.1",
|
46 |
"vite": "^6.2.0"
|
public/banner.png
DELETED
Git LFS Details
|
public/providers/together.svg
DELETED
server.js
CHANGED
@@ -14,7 +14,7 @@ import { InferenceClient } from "@huggingface/inference";
|
|
14 |
import bodyParser from "body-parser";
|
15 |
|
16 |
import checkUser from "./middlewares/checkUser.js";
|
17 |
-
import {
|
18 |
import { COLORS } from "./utils/colors.js";
|
19 |
|
20 |
// Load environment variables from .env file
|
@@ -30,12 +30,9 @@ const __dirname = path.dirname(__filename);
|
|
30 |
const PORT = process.env.APP_PORT || 3000;
|
31 |
const REDIRECT_URI =
|
32 |
process.env.REDIRECT_URI || `http://localhost:${PORT}/auth/login`;
|
|
|
33 |
const MAX_REQUESTS_PER_IP = 2;
|
34 |
|
35 |
-
const SEARCH_START = "<<<<<<< SEARCH";
|
36 |
-
const DIVIDER = "=======";
|
37 |
-
const REPLACE_END = ">>>>>>> REPLACE";
|
38 |
-
|
39 |
app.use(cookieParser());
|
40 |
app.use(bodyParser.json());
|
41 |
app.use(express.static(path.join(__dirname, "dist")));
|
@@ -204,9 +201,6 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
|
|
204 |
await uploadFiles({
|
205 |
repo,
|
206 |
files,
|
207 |
-
commitTitle: `${prompts[prompts.length - 1]} - ${
|
208 |
-
prompts.length > 1 ? "Follow Up" : "Initial"
|
209 |
-
} Deployment`,
|
210 |
accessToken: hf_token,
|
211 |
});
|
212 |
return res.status(200).send({ ok: true, path: repo.name });
|
@@ -219,42 +213,16 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
|
|
219 |
});
|
220 |
|
221 |
app.post("/api/ask-ai", async (req, res) => {
|
222 |
-
const { prompt,
|
223 |
-
if (!
|
224 |
return res.status(400).send({
|
225 |
ok: false,
|
226 |
message: "Missing required fields",
|
227 |
});
|
228 |
}
|
229 |
-
if (!redesignMarkdown && !prompt) {
|
230 |
-
return res.status(400).send({
|
231 |
-
ok: false,
|
232 |
-
message: "Missing required fields",
|
233 |
-
});
|
234 |
-
}
|
235 |
-
|
236 |
-
const initialSystemPrompt = `ONLY USE HTML, CSS AND JAVASCRIPT. If you want to use ICON make sure to import the library first. Try to create the best UI possible by using only HTML, CSS and JAVASCRIPT. MAKE IT RESPONSIVE USING TAILWINDCSS. Use as much as you can TailwindCSS for the CSS, if you can't do something with TailwindCSS, then use custom CSS (make sure to import <script src="https://cdn.tailwindcss.com"></script> in the head). Also, try to ellaborate as much as you can, to create something unique. ALWAYS GIVE THE RESPONSE INTO A SINGLE HTML FILE`;
|
237 |
-
|
238 |
-
const selectedModel = MODELS.find(
|
239 |
-
(m) => m.value === model || m.label === model
|
240 |
-
);
|
241 |
-
if (!selectedModel) {
|
242 |
-
return res.status(400).send({
|
243 |
-
ok: false,
|
244 |
-
message: "Invalid model selected",
|
245 |
-
});
|
246 |
-
}
|
247 |
-
if (!selectedModel.providers.includes(provider) && provider !== "auto") {
|
248 |
-
return res.status(400).send({
|
249 |
-
ok: false,
|
250 |
-
openSelectProvider: true,
|
251 |
-
message: `The selected model does not support the ${provider} provider.`,
|
252 |
-
});
|
253 |
-
}
|
254 |
|
255 |
let { hf_token } = req.cookies;
|
256 |
let token = hf_token;
|
257 |
-
let billTo = null;
|
258 |
|
259 |
if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
|
260 |
token = process.env.HF_TOKEN;
|
@@ -278,7 +246,6 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
278 |
}
|
279 |
|
280 |
token = process.env.DEFAULT_HF_TOKEN;
|
281 |
-
billTo = "huggingface";
|
282 |
}
|
283 |
|
284 |
// Set up response headers for streaming
|
@@ -290,11 +257,13 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
290 |
let completeResponse = "";
|
291 |
|
292 |
let TOKENS_USED = prompt?.length;
|
|
|
|
|
293 |
|
294 |
const DEFAULT_PROVIDER = PROVIDERS.novita;
|
295 |
const selectedProvider =
|
296 |
provider === "auto"
|
297 |
-
?
|
298 |
: PROVIDERS[provider] ?? DEFAULT_PROVIDER;
|
299 |
|
300 |
if (provider !== "auto" && TOKENS_USED >= selectedProvider.max_tokens) {
|
@@ -304,27 +273,43 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
304 |
message: `Context is too long. ${selectedProvider.name} allow ${selectedProvider.max_tokens} max tokens.`,
|
305 |
});
|
306 |
}
|
|
|
307 |
try {
|
308 |
-
const chatCompletion = client.chatCompletionStream(
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
|
329 |
while (true) {
|
330 |
const { done, value } = await chatCompletion.next();
|
@@ -333,37 +318,23 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
333 |
}
|
334 |
const chunk = value.choices[0]?.delta?.content;
|
335 |
if (chunk) {
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
if (completeResponse.includes("</html>")) {
|
343 |
-
break;
|
344 |
-
}
|
345 |
-
} else {
|
346 |
-
let newChunk = chunk;
|
347 |
-
if (chunk.includes("</html>")) {
|
348 |
-
newChunk = newChunk.replace(/<\/html>[\s\S]*/, "</html>");
|
349 |
-
}
|
350 |
-
completeResponse += newChunk;
|
351 |
-
res.write(newChunk);
|
352 |
-
if (newChunk.includes("</html>")) {
|
353 |
-
break;
|
354 |
-
}
|
355 |
}
|
356 |
} else {
|
357 |
-
|
|
|
|
|
|
|
|
|
358 |
completeResponse += newChunk;
|
359 |
res.write(newChunk);
|
360 |
-
if (
|
361 |
-
|
362 |
-
lastThinkTagIndex + "</think>".length
|
363 |
-
);
|
364 |
-
if (afterLastThinkTag.includes("</html>")) {
|
365 |
-
break;
|
366 |
-
}
|
367 |
}
|
368 |
}
|
369 |
}
|
@@ -391,230 +362,6 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
391 |
}
|
392 |
});
|
393 |
|
394 |
-
app.put("/api/ask-ai", async (req, res) => {
|
395 |
-
const { prompt, html, previousPrompt } = req.body;
|
396 |
-
if (!prompt || !html) {
|
397 |
-
return res.status(400).send({
|
398 |
-
ok: false,
|
399 |
-
message: "Missing required fields",
|
400 |
-
});
|
401 |
-
}
|
402 |
-
const followUpSystemPrompt = `You are an expert web developer modifying an existing HTML file.
|
403 |
-
The user wants to apply changes based on their request.
|
404 |
-
You MUST output ONLY the changes required using the following SEARCH/REPLACE block format. Do NOT output the entire file.
|
405 |
-
Explain the changes briefly *before* the blocks if necessary, but the code changes THEMSELVES MUST be within the blocks.
|
406 |
-
Format Rules:
|
407 |
-
1. Start with ${SEARCH_START}
|
408 |
-
2. Provide the exact lines from the current code that need to be replaced.
|
409 |
-
3. Use ${DIVIDER} to separate the search block from the replacement.
|
410 |
-
4. Provide the new lines that should replace the original lines.
|
411 |
-
5. End with ${REPLACE_END}
|
412 |
-
6. You can use multiple SEARCH/REPLACE blocks if changes are needed in different parts of the file.
|
413 |
-
7. To insert code, use an empty SEARCH block (only ${SEARCH_START} and ${DIVIDER} on their lines) if inserting at the very beginning, otherwise provide the line *before* the insertion point in the SEARCH block and include that line plus the new lines in the REPLACE block.
|
414 |
-
8. To delete code, provide the lines to delete in the SEARCH block and leave the REPLACE block empty (only ${DIVIDER} and ${REPLACE_END} on their lines).
|
415 |
-
9. IMPORTANT: The SEARCH block must *exactly* match the current code, including indentation and whitespace.
|
416 |
-
Example Modifying Code:
|
417 |
-
\`\`\`
|
418 |
-
Some explanation...
|
419 |
-
${SEARCH_START}
|
420 |
-
<h1>Old Title</h1>
|
421 |
-
${DIVIDER}
|
422 |
-
<h1>New Title</h1>
|
423 |
-
${REPLACE_END}
|
424 |
-
${SEARCH_START}
|
425 |
-
</body>
|
426 |
-
${DIVIDER}
|
427 |
-
<script>console.log("Added script");</script>
|
428 |
-
</body>
|
429 |
-
${REPLACE_END}
|
430 |
-
\`\`\`
|
431 |
-
Example Deleting Code:
|
432 |
-
\`\`\`
|
433 |
-
Removing the paragraph...
|
434 |
-
${SEARCH_START}
|
435 |
-
<p>This paragraph will be deleted.</p>
|
436 |
-
${DIVIDER}
|
437 |
-
${REPLACE_END}
|
438 |
-
\`\`\``;
|
439 |
-
|
440 |
-
// force to use deepseek-ai/DeepSeek-V3-0324 model, to avoid thinker models.
|
441 |
-
const selectedModel = MODELS[0];
|
442 |
-
|
443 |
-
let { hf_token } = req.cookies;
|
444 |
-
let token = hf_token;
|
445 |
-
let billTo = null;
|
446 |
-
|
447 |
-
if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
|
448 |
-
token = process.env.HF_TOKEN;
|
449 |
-
}
|
450 |
-
|
451 |
-
const ip =
|
452 |
-
req.headers["x-forwarded-for"]?.split(",")[0].trim() ||
|
453 |
-
req.headers["x-real-ip"] ||
|
454 |
-
req.socket.remoteAddress ||
|
455 |
-
req.ip ||
|
456 |
-
"0.0.0.0";
|
457 |
-
|
458 |
-
if (!token) {
|
459 |
-
ipAddresses.set(ip, (ipAddresses.get(ip) || 0) + 1);
|
460 |
-
if (ipAddresses.get(ip) > MAX_REQUESTS_PER_IP) {
|
461 |
-
return res.status(429).send({
|
462 |
-
ok: false,
|
463 |
-
openLogin: true,
|
464 |
-
message: "Log In to continue using the service",
|
465 |
-
});
|
466 |
-
}
|
467 |
-
|
468 |
-
token = process.env.DEFAULT_HF_TOKEN;
|
469 |
-
billTo = "huggingface";
|
470 |
-
}
|
471 |
-
|
472 |
-
const client = new InferenceClient(token);
|
473 |
-
|
474 |
-
const selectedProvider = PROVIDERS[selectedModel.autoProvider];
|
475 |
-
try {
|
476 |
-
const response = await client.chatCompletion(
|
477 |
-
{
|
478 |
-
model: selectedModel.value,
|
479 |
-
provider: selectedProvider.id,
|
480 |
-
messages: [
|
481 |
-
{
|
482 |
-
role: "system",
|
483 |
-
content: followUpSystemPrompt,
|
484 |
-
},
|
485 |
-
{
|
486 |
-
role: "user",
|
487 |
-
content: previousPrompt
|
488 |
-
? previousPrompt
|
489 |
-
: "You are modifying the HTML file based on the user's request.",
|
490 |
-
},
|
491 |
-
{
|
492 |
-
role: "assistant",
|
493 |
-
content: `The current code is: \n\`\`\`html\n${html}\n\`\`\``,
|
494 |
-
},
|
495 |
-
{
|
496 |
-
role: "user",
|
497 |
-
content: prompt,
|
498 |
-
},
|
499 |
-
],
|
500 |
-
...(selectedProvider.id !== "sambanova"
|
501 |
-
? {
|
502 |
-
max_tokens: selectedProvider.max_tokens,
|
503 |
-
}
|
504 |
-
: {}),
|
505 |
-
},
|
506 |
-
billTo ? { billTo } : {}
|
507 |
-
);
|
508 |
-
|
509 |
-
const chunk = response.choices[0]?.message?.content;
|
510 |
-
// TO DO: handle the case where there are multiple SEARCH/REPLACE blocks
|
511 |
-
if (!chunk) {
|
512 |
-
return res.status(400).send({
|
513 |
-
ok: false,
|
514 |
-
message: "No content returned from the model",
|
515 |
-
});
|
516 |
-
}
|
517 |
-
|
518 |
-
if (chunk) {
|
519 |
-
let newHtml = html;
|
520 |
-
// array of arrays to hold updated lines (start and end line numbers)
|
521 |
-
const updatedLines = [];
|
522 |
-
|
523 |
-
// Find all search/replace blocks in the chunk
|
524 |
-
let position = 0;
|
525 |
-
let moreBlocks = true;
|
526 |
-
|
527 |
-
while (moreBlocks) {
|
528 |
-
const searchStartIndex = chunk.indexOf(SEARCH_START, position);
|
529 |
-
if (searchStartIndex === -1) {
|
530 |
-
moreBlocks = false;
|
531 |
-
continue;
|
532 |
-
}
|
533 |
-
|
534 |
-
const dividerIndex = chunk.indexOf(DIVIDER, searchStartIndex);
|
535 |
-
if (dividerIndex === -1) {
|
536 |
-
moreBlocks = false;
|
537 |
-
continue;
|
538 |
-
}
|
539 |
-
|
540 |
-
const replaceEndIndex = chunk.indexOf(REPLACE_END, dividerIndex);
|
541 |
-
if (replaceEndIndex === -1) {
|
542 |
-
moreBlocks = false;
|
543 |
-
continue;
|
544 |
-
}
|
545 |
-
|
546 |
-
// Extract the search and replace blocks
|
547 |
-
const searchBlock = chunk.substring(
|
548 |
-
searchStartIndex + SEARCH_START.length,
|
549 |
-
dividerIndex
|
550 |
-
);
|
551 |
-
const replaceBlock = chunk.substring(
|
552 |
-
dividerIndex + DIVIDER.length,
|
553 |
-
replaceEndIndex
|
554 |
-
);
|
555 |
-
|
556 |
-
// Apply the replacement
|
557 |
-
if (searchBlock.trim() === "") {
|
558 |
-
// Inserting at the beginning
|
559 |
-
newHtml = `${replaceBlock}\n${newHtml}`;
|
560 |
-
|
561 |
-
// Track first line as updated
|
562 |
-
updatedLines.push([1, replaceBlock.split("\n").length]);
|
563 |
-
} else {
|
564 |
-
// Find the position of the search block in the HTML
|
565 |
-
const blockPosition = newHtml.indexOf(searchBlock);
|
566 |
-
if (blockPosition !== -1) {
|
567 |
-
// Count lines before the search block
|
568 |
-
const beforeText = newHtml.substring(0, blockPosition);
|
569 |
-
const startLineNumber = beforeText.split("\n").length;
|
570 |
-
|
571 |
-
// Count lines in search and replace blocks
|
572 |
-
const replaceLines = replaceBlock.split("\n").length;
|
573 |
-
|
574 |
-
// Calculate end line (start + length of replaced content)
|
575 |
-
const endLineNumber = startLineNumber + replaceLines - 1;
|
576 |
-
|
577 |
-
// Track the line numbers that were updated
|
578 |
-
updatedLines.push([startLineNumber, endLineNumber]);
|
579 |
-
|
580 |
-
// Perform the replacement
|
581 |
-
newHtml = newHtml.replace(searchBlock, replaceBlock);
|
582 |
-
}
|
583 |
-
}
|
584 |
-
|
585 |
-
// Move position to after this block to find the next one
|
586 |
-
position = replaceEndIndex + REPLACE_END.length;
|
587 |
-
}
|
588 |
-
|
589 |
-
return res.status(200).send({
|
590 |
-
ok: true,
|
591 |
-
html: newHtml,
|
592 |
-
updatedLines,
|
593 |
-
});
|
594 |
-
} else {
|
595 |
-
return res.status(400).send({
|
596 |
-
ok: false,
|
597 |
-
message: "No content returned from the model",
|
598 |
-
});
|
599 |
-
}
|
600 |
-
} catch (error) {
|
601 |
-
if (error.message.includes("exceeded your monthly included credits")) {
|
602 |
-
return res.status(402).send({
|
603 |
-
ok: false,
|
604 |
-
openProModal: true,
|
605 |
-
message: error.message,
|
606 |
-
});
|
607 |
-
}
|
608 |
-
if (!res.headersSent) {
|
609 |
-
res.status(500).send({
|
610 |
-
ok: false,
|
611 |
-
message:
|
612 |
-
error.message || "An error occurred while processing your request.",
|
613 |
-
});
|
614 |
-
}
|
615 |
-
}
|
616 |
-
});
|
617 |
-
|
618 |
app.get("/api/remix/:username/:repo", async (req, res) => {
|
619 |
const { username, repo } = req.params;
|
620 |
const { hf_token } = req.cookies;
|
@@ -683,43 +430,6 @@ app.get("/api/remix/:username/:repo", async (req, res) => {
|
|
683 |
});
|
684 |
}
|
685 |
});
|
686 |
-
|
687 |
-
app.post("/api/re-design", async (req, res) => {
|
688 |
-
const { url } = req.body;
|
689 |
-
if (!url) {
|
690 |
-
return res.status(400).send({
|
691 |
-
ok: false,
|
692 |
-
message: "Missing required fields",
|
693 |
-
});
|
694 |
-
}
|
695 |
-
|
696 |
-
// call the api https://r.jina.ai/{url} and return the response
|
697 |
-
try {
|
698 |
-
const response = await fetch(
|
699 |
-
`https://r.jina.ai/${encodeURIComponent(url)}`,
|
700 |
-
{
|
701 |
-
method: "POST",
|
702 |
-
}
|
703 |
-
);
|
704 |
-
if (!response.ok) {
|
705 |
-
return res.status(500).send({
|
706 |
-
ok: false,
|
707 |
-
message: "Failed to fetch redesign",
|
708 |
-
});
|
709 |
-
}
|
710 |
-
// return the html response
|
711 |
-
const markdown = await response.text();
|
712 |
-
return res.status(200).send({
|
713 |
-
ok: true,
|
714 |
-
markdown,
|
715 |
-
});
|
716 |
-
} catch (error) {
|
717 |
-
return res.status(500).send({
|
718 |
-
ok: false,
|
719 |
-
message: error.message,
|
720 |
-
});
|
721 |
-
}
|
722 |
-
});
|
723 |
app.get("*", (_req, res) => {
|
724 |
res.sendFile(path.join(__dirname, "dist", "index.html"));
|
725 |
});
|
|
|
14 |
import bodyParser from "body-parser";
|
15 |
|
16 |
import checkUser from "./middlewares/checkUser.js";
|
17 |
+
import { PROVIDERS } from "./utils/providers.js";
|
18 |
import { COLORS } from "./utils/colors.js";
|
19 |
|
20 |
// Load environment variables from .env file
|
|
|
30 |
const PORT = process.env.APP_PORT || 3000;
|
31 |
const REDIRECT_URI =
|
32 |
process.env.REDIRECT_URI || `http://localhost:${PORT}/auth/login`;
|
33 |
+
const MODEL_ID = "deepseek-ai/DeepSeek-V3-0324";
|
34 |
const MAX_REQUESTS_PER_IP = 2;
|
35 |
|
|
|
|
|
|
|
|
|
36 |
app.use(cookieParser());
|
37 |
app.use(bodyParser.json());
|
38 |
app.use(express.static(path.join(__dirname, "dist")));
|
|
|
201 |
await uploadFiles({
|
202 |
repo,
|
203 |
files,
|
|
|
|
|
|
|
204 |
accessToken: hf_token,
|
205 |
});
|
206 |
return res.status(200).send({ ok: true, path: repo.name });
|
|
|
213 |
});
|
214 |
|
215 |
app.post("/api/ask-ai", async (req, res) => {
|
216 |
+
const { prompt, html, previousPrompt, provider } = req.body;
|
217 |
+
if (!prompt) {
|
218 |
return res.status(400).send({
|
219 |
ok: false,
|
220 |
message: "Missing required fields",
|
221 |
});
|
222 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
|
224 |
let { hf_token } = req.cookies;
|
225 |
let token = hf_token;
|
|
|
226 |
|
227 |
if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
|
228 |
token = process.env.HF_TOKEN;
|
|
|
246 |
}
|
247 |
|
248 |
token = process.env.DEFAULT_HF_TOKEN;
|
|
|
249 |
}
|
250 |
|
251 |
// Set up response headers for streaming
|
|
|
257 |
let completeResponse = "";
|
258 |
|
259 |
let TOKENS_USED = prompt?.length;
|
260 |
+
if (previousPrompt) TOKENS_USED += previousPrompt.length;
|
261 |
+
if (html) TOKENS_USED += html.length;
|
262 |
|
263 |
const DEFAULT_PROVIDER = PROVIDERS.novita;
|
264 |
const selectedProvider =
|
265 |
provider === "auto"
|
266 |
+
? DEFAULT_PROVIDER
|
267 |
: PROVIDERS[provider] ?? DEFAULT_PROVIDER;
|
268 |
|
269 |
if (provider !== "auto" && TOKENS_USED >= selectedProvider.max_tokens) {
|
|
|
273 |
message: `Context is too long. ${selectedProvider.name} allow ${selectedProvider.max_tokens} max tokens.`,
|
274 |
});
|
275 |
}
|
276 |
+
|
277 |
try {
|
278 |
+
const chatCompletion = client.chatCompletionStream({
|
279 |
+
model: MODEL_ID,
|
280 |
+
provider: selectedProvider.id,
|
281 |
+
messages: [
|
282 |
+
{
|
283 |
+
role: "system",
|
284 |
+
content: `ONLY USE HTML, CSS AND JAVASCRIPT. If you want to use ICON make sure to import the library first. Try to create the best UI possible by using only HTML, CSS and JAVASCRIPT. Use as much as you can TailwindCSS for the CSS, if you can't do something with TailwindCSS, then use custom CSS (make sure to import <script src="https://cdn.tailwindcss.com"></script> in the head). Also, try to ellaborate as much as you can, to create something unique. ALWAYS GIVE THE RESPONSE INTO A SINGLE HTML FILE`,
|
285 |
+
},
|
286 |
+
...(previousPrompt
|
287 |
+
? [
|
288 |
+
{
|
289 |
+
role: "user",
|
290 |
+
content: previousPrompt,
|
291 |
+
},
|
292 |
+
]
|
293 |
+
: []),
|
294 |
+
...(html
|
295 |
+
? [
|
296 |
+
{
|
297 |
+
role: "assistant",
|
298 |
+
content: `The current code is: ${html}.`,
|
299 |
+
},
|
300 |
+
]
|
301 |
+
: []),
|
302 |
+
{
|
303 |
+
role: "user",
|
304 |
+
content: prompt,
|
305 |
+
},
|
306 |
+
],
|
307 |
+
...(selectedProvider.id !== "sambanova"
|
308 |
+
? {
|
309 |
+
max_tokens: selectedProvider.max_tokens,
|
310 |
+
}
|
311 |
+
: {}),
|
312 |
+
});
|
313 |
|
314 |
while (true) {
|
315 |
const { done, value } = await chatCompletion.next();
|
|
|
318 |
}
|
319 |
const chunk = value.choices[0]?.delta?.content;
|
320 |
if (chunk) {
|
321 |
+
if (provider !== "sambanova") {
|
322 |
+
res.write(chunk);
|
323 |
+
completeResponse += chunk;
|
324 |
+
|
325 |
+
if (completeResponse.includes("</html>")) {
|
326 |
+
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
}
|
328 |
} else {
|
329 |
+
let newChunk = chunk;
|
330 |
+
if (chunk.includes("</html>")) {
|
331 |
+
// Replace everything after the last </html> tag with an empty string
|
332 |
+
newChunk = newChunk.replace(/<\/html>[\s\S]*/, "</html>");
|
333 |
+
}
|
334 |
completeResponse += newChunk;
|
335 |
res.write(newChunk);
|
336 |
+
if (newChunk.includes("</html>")) {
|
337 |
+
break;
|
|
|
|
|
|
|
|
|
|
|
338 |
}
|
339 |
}
|
340 |
}
|
|
|
362 |
}
|
363 |
});
|
364 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
365 |
app.get("/api/remix/:username/:repo", async (req, res) => {
|
366 |
const { username, repo } = req.params;
|
367 |
const { hf_token } = req.cookies;
|
|
|
430 |
});
|
431 |
}
|
432 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
433 |
app.get("*", (_req, res) => {
|
434 |
res.sendFile(path.join(__dirname, "dist", "index.html"));
|
435 |
});
|
src/assets/index.css
CHANGED
@@ -1,7 +1,4 @@
|
|
1 |
@import "tailwindcss";
|
2 |
-
@import "tw-animate-css";
|
3 |
-
|
4 |
-
@custom-variant dark (&:is(.dark *));
|
5 |
|
6 |
* {
|
7 |
font-family: "Noto Sans";
|
@@ -10,133 +7,3 @@
|
|
10 |
.font-code {
|
11 |
font-family: "Source Code Pro";
|
12 |
}
|
13 |
-
|
14 |
-
@theme inline {
|
15 |
-
--radius-sm: calc(var(--radius) - 4px);
|
16 |
-
--radius-md: calc(var(--radius) - 2px);
|
17 |
-
--radius-lg: var(--radius);
|
18 |
-
--radius-xl: calc(var(--radius) + 4px);
|
19 |
-
--color-background: var(--background);
|
20 |
-
--color-foreground: var(--foreground);
|
21 |
-
--color-card: var(--card);
|
22 |
-
--color-card-foreground: var(--card-foreground);
|
23 |
-
--color-popover: var(--popover);
|
24 |
-
--color-popover-foreground: var(--popover-foreground);
|
25 |
-
--color-primary: var(--primary);
|
26 |
-
--color-primary-foreground: var(--primary-foreground);
|
27 |
-
--color-secondary: var(--secondary);
|
28 |
-
--color-secondary-foreground: var(--secondary-foreground);
|
29 |
-
--color-muted: var(--muted);
|
30 |
-
--color-muted-foreground: var(--muted-foreground);
|
31 |
-
--color-accent: var(--accent);
|
32 |
-
--color-accent-foreground: var(--accent-foreground);
|
33 |
-
--color-destructive: var(--destructive);
|
34 |
-
--color-border: var(--border);
|
35 |
-
--color-input: var(--input);
|
36 |
-
--color-ring: var(--ring);
|
37 |
-
--color-chart-1: var(--chart-1);
|
38 |
-
--color-chart-2: var(--chart-2);
|
39 |
-
--color-chart-3: var(--chart-3);
|
40 |
-
--color-chart-4: var(--chart-4);
|
41 |
-
--color-chart-5: var(--chart-5);
|
42 |
-
--color-sidebar: var(--sidebar);
|
43 |
-
--color-sidebar-foreground: var(--sidebar-foreground);
|
44 |
-
--color-sidebar-primary: var(--sidebar-primary);
|
45 |
-
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
46 |
-
--color-sidebar-accent: var(--sidebar-accent);
|
47 |
-
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
48 |
-
--color-sidebar-border: var(--sidebar-border);
|
49 |
-
--color-sidebar-ring: var(--sidebar-ring);
|
50 |
-
}
|
51 |
-
|
52 |
-
:root {
|
53 |
-
--radius: 0.625rem;
|
54 |
-
--background: oklch(1 0 0);
|
55 |
-
--foreground: oklch(0.145 0 0);
|
56 |
-
--card: oklch(1 0 0);
|
57 |
-
--card-foreground: oklch(0.145 0 0);
|
58 |
-
--popover: oklch(1 0 0);
|
59 |
-
--popover-foreground: oklch(0.145 0 0);
|
60 |
-
--primary: oklch(0.205 0 0);
|
61 |
-
--primary-foreground: oklch(0.985 0 0);
|
62 |
-
--secondary: oklch(0.97 0 0);
|
63 |
-
--secondary-foreground: oklch(0.205 0 0);
|
64 |
-
--muted: oklch(0.97 0 0);
|
65 |
-
--muted-foreground: oklch(0.556 0 0);
|
66 |
-
--accent: oklch(0.97 0 0);
|
67 |
-
--accent-foreground: oklch(0.205 0 0);
|
68 |
-
--destructive: oklch(0.577 0.245 27.325);
|
69 |
-
--border: oklch(0.922 0 0);
|
70 |
-
--input: oklch(0.922 0 0);
|
71 |
-
--ring: oklch(0.708 0 0);
|
72 |
-
--chart-1: oklch(0.646 0.222 41.116);
|
73 |
-
--chart-2: oklch(0.6 0.118 184.704);
|
74 |
-
--chart-3: oklch(0.398 0.07 227.392);
|
75 |
-
--chart-4: oklch(0.828 0.189 84.429);
|
76 |
-
--chart-5: oklch(0.769 0.188 70.08);
|
77 |
-
--sidebar: oklch(0.985 0 0);
|
78 |
-
--sidebar-foreground: oklch(0.145 0 0);
|
79 |
-
--sidebar-primary: oklch(0.205 0 0);
|
80 |
-
--sidebar-primary-foreground: oklch(0.985 0 0);
|
81 |
-
--sidebar-accent: oklch(0.97 0 0);
|
82 |
-
--sidebar-accent-foreground: oklch(0.205 0 0);
|
83 |
-
--sidebar-border: oklch(0.922 0 0);
|
84 |
-
--sidebar-ring: oklch(0.708 0 0);
|
85 |
-
}
|
86 |
-
|
87 |
-
.dark {
|
88 |
-
--background: oklch(0.145 0 0);
|
89 |
-
--foreground: oklch(0.985 0 0);
|
90 |
-
--card: oklch(0.205 0 0);
|
91 |
-
--card-foreground: oklch(0.985 0 0);
|
92 |
-
--popover: oklch(0.205 0 0);
|
93 |
-
--popover-foreground: oklch(0.985 0 0);
|
94 |
-
--primary: oklch(0.922 0 0);
|
95 |
-
--primary-foreground: oklch(0.205 0 0);
|
96 |
-
--secondary: oklch(0.269 0 0);
|
97 |
-
--secondary-foreground: oklch(0.985 0 0);
|
98 |
-
--muted: oklch(0.269 0 0);
|
99 |
-
--muted-foreground: oklch(0.708 0 0);
|
100 |
-
--accent: oklch(0.269 0 0);
|
101 |
-
--accent-foreground: oklch(0.985 0 0);
|
102 |
-
--destructive: oklch(0.704 0.191 22.216);
|
103 |
-
--border: oklch(1 0 0 / 10%);
|
104 |
-
--input: oklch(1 0 0 / 15%);
|
105 |
-
--ring: oklch(0.556 0 0);
|
106 |
-
--chart-1: oklch(0.488 0.243 264.376);
|
107 |
-
--chart-2: oklch(0.696 0.17 162.48);
|
108 |
-
--chart-3: oklch(0.769 0.188 70.08);
|
109 |
-
--chart-4: oklch(0.627 0.265 303.9);
|
110 |
-
--chart-5: oklch(0.645 0.246 16.439);
|
111 |
-
--sidebar: oklch(0.205 0 0);
|
112 |
-
--sidebar-foreground: oklch(0.985 0 0);
|
113 |
-
--sidebar-primary: oklch(0.488 0.243 264.376);
|
114 |
-
--sidebar-primary-foreground: oklch(0.985 0 0);
|
115 |
-
--sidebar-accent: oklch(0.269 0 0);
|
116 |
-
--sidebar-accent-foreground: oklch(0.985 0 0);
|
117 |
-
--sidebar-border: oklch(1 0 0 / 10%);
|
118 |
-
--sidebar-ring: oklch(0.556 0 0);
|
119 |
-
}
|
120 |
-
|
121 |
-
@layer base {
|
122 |
-
* {
|
123 |
-
@apply border-border outline-ring/50;
|
124 |
-
}
|
125 |
-
body {
|
126 |
-
@apply bg-background text-foreground;
|
127 |
-
}
|
128 |
-
}
|
129 |
-
|
130 |
-
.monaco-editor .margin {
|
131 |
-
@apply !bg-neutral-900;
|
132 |
-
}
|
133 |
-
.monaco-editor .monaco-editor-background {
|
134 |
-
@apply !bg-neutral-900;
|
135 |
-
}
|
136 |
-
.monaco-editor .line-numbers {
|
137 |
-
@apply !text-neutral-500;
|
138 |
-
}
|
139 |
-
|
140 |
-
.matched-line {
|
141 |
-
@apply bg-sky-500/30;
|
142 |
-
}
|
|
|
1 |
@import "tailwindcss";
|
|
|
|
|
|
|
2 |
|
3 |
* {
|
4 |
font-family: "Noto Sans";
|
|
|
7 |
.font-code {
|
8 |
font-family: "Source Code Pro";
|
9 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/assets/linux.png
DELETED
Binary file (8.63 kB)
|
|
src/{views → components}/App.tsx
RENAMED
@@ -1,50 +1,45 @@
|
|
1 |
import { useRef, useState } from "react";
|
|
|
|
|
|
|
2 |
import {
|
3 |
-
|
|
|
4 |
useEvent,
|
5 |
useLocalStorage,
|
6 |
-
useMount,
|
7 |
useSearchParam,
|
8 |
-
useUnmount,
|
9 |
-
useUpdateEffect,
|
10 |
} from "react-use";
|
11 |
-
import
|
12 |
-
import { editor } from "monaco-editor";
|
13 |
-
import { toast, Toaster } from "sonner";
|
14 |
-
import classNames from "classnames";
|
15 |
-
import { CopyIcon } from "lucide-react";
|
16 |
|
17 |
-
import
|
18 |
-
import
|
19 |
-
import {
|
20 |
-
import
|
21 |
-
import
|
22 |
-
import
|
23 |
-
import
|
24 |
-
import AskAI from "../components/ask-ai/ask-ai";
|
25 |
|
26 |
-
|
27 |
const [htmlStorage, , removeHtmlStorage] = useLocalStorage("html_content");
|
28 |
const remix = useSearchParam("remix");
|
29 |
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
30 |
-
const [_, copyToClipboard] = useCopyToClipboard();
|
31 |
|
32 |
const preview = useRef<HTMLDivElement>(null);
|
33 |
const editor = useRef<HTMLDivElement>(null);
|
34 |
const resizer = useRef<HTMLDivElement>(null);
|
35 |
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
|
36 |
-
const iframeRef = useRef<HTMLIFrameElement | null>(null);
|
37 |
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
38 |
-
const monacoRef = useRef<any>(null);
|
39 |
|
|
|
|
|
40 |
const [html, setHtml] = useState((htmlStorage as string) ?? defaultHTML);
|
41 |
const [isAiWorking, setisAiWorking] = useState(false);
|
42 |
const [auth, setAuth] = useState<Auth | undefined>(undefined);
|
|
|
|
|
|
|
43 |
const [prompts, setPrompts] = useState<string[]>([]);
|
44 |
-
const [
|
45 |
-
|
46 |
-
|
47 |
-
const [isResizing, setIsResizing] = useState(false);
|
48 |
|
49 |
const fetchMe = async () => {
|
50 |
const res = await fetch("/api/@me");
|
@@ -132,20 +127,36 @@ export default function App() {
|
|
132 |
document.removeEventListener("mouseup", handleMouseUp);
|
133 |
};
|
134 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
useMount(() => {
|
|
|
136 |
fetchMe();
|
137 |
fetchRemix();
|
138 |
|
|
|
139 |
if (htmlStorage) {
|
140 |
removeHtmlStorage();
|
141 |
-
toast.
|
142 |
}
|
143 |
|
|
|
144 |
resetLayout();
|
|
|
|
|
145 |
if (!resizer.current) return;
|
146 |
resizer.current.addEventListener("mousedown", handleMouseDown);
|
147 |
window.addEventListener("resize", resetLayout);
|
148 |
});
|
|
|
|
|
149 |
useUnmount(() => {
|
150 |
document.removeEventListener("mousemove", handleResize);
|
151 |
document.removeEventListener("mouseup", handleMouseUp);
|
@@ -155,178 +166,118 @@ export default function App() {
|
|
155 |
window.removeEventListener("resize", resetLayout);
|
156 |
});
|
157 |
|
158 |
-
// Prevent accidental navigation away when AI is working or content has changed
|
159 |
-
useEvent("beforeunload", (e) => {
|
160 |
-
if (isAiWorking || html !== defaultHTML) {
|
161 |
-
e.preventDefault();
|
162 |
-
return "";
|
163 |
-
}
|
164 |
-
});
|
165 |
-
|
166 |
-
useUpdateEffect(() => {
|
167 |
-
if (currentTab === "chat") {
|
168 |
-
// Reset editor width when switching to reasoning tab
|
169 |
-
resetLayout();
|
170 |
-
// re-add the event listener for resizing
|
171 |
-
if (resizer.current) {
|
172 |
-
resizer.current.addEventListener("mousedown", handleMouseDown);
|
173 |
-
}
|
174 |
-
} else {
|
175 |
-
if (preview.current) {
|
176 |
-
// Reset preview width when switching to preview tab
|
177 |
-
preview.current.style.width = "100%";
|
178 |
-
}
|
179 |
-
}
|
180 |
-
}, [currentTab]);
|
181 |
-
|
182 |
return (
|
183 |
-
<
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
<DeployButton
|
190 |
html={html}
|
|
|
191 |
auth={auth}
|
192 |
setHtml={setHtml}
|
193 |
prompts={prompts}
|
194 |
/>
|
195 |
</Header>
|
196 |
-
<main className="
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
}
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
setHtml={(newHtml: string) => {
|
238 |
-
setHtml(newHtml);
|
239 |
-
}}
|
240 |
-
htmlHistory={htmlHistory}
|
241 |
-
onSuccess={(
|
242 |
-
finalHtml: string,
|
243 |
-
p: string,
|
244 |
-
updatedLines?: number[][]
|
245 |
-
) => {
|
246 |
-
const currentHistory = [...htmlHistory];
|
247 |
-
currentHistory.unshift({
|
248 |
-
html: finalHtml,
|
249 |
-
createdAt: new Date(),
|
250 |
-
prompt: p,
|
251 |
-
});
|
252 |
-
setHtmlHistory(currentHistory);
|
253 |
-
// if xs or sm
|
254 |
-
if (window.innerWidth <= 1024) {
|
255 |
-
setCurrentTab("preview");
|
256 |
-
}
|
257 |
-
if (updatedLines && updatedLines?.length > 0) {
|
258 |
-
const decorations = updatedLines.map((line) => ({
|
259 |
-
range: new monacoRef.current.Range(
|
260 |
-
line[0],
|
261 |
-
1,
|
262 |
-
line[1],
|
263 |
-
1
|
264 |
-
),
|
265 |
-
options: {
|
266 |
-
inlineClassName: "matched-line",
|
267 |
-
},
|
268 |
-
}));
|
269 |
-
setTimeout(() => {
|
270 |
-
editorRef?.current
|
271 |
-
?.getModel()
|
272 |
-
?.deltaDecorations([], decorations);
|
273 |
-
|
274 |
-
editorRef.current?.revealLine(updatedLines[0][0]);
|
275 |
-
}, 100);
|
276 |
-
}
|
277 |
-
}}
|
278 |
-
isAiWorking={isAiWorking}
|
279 |
-
setisAiWorking={setisAiWorking}
|
280 |
-
onNewPrompt={(prompt: string) => {
|
281 |
-
setPrompts((prev) => [...prev, prompt]);
|
282 |
-
}}
|
283 |
-
onScrollToBottom={() => {
|
284 |
-
editorRef.current?.revealLine(
|
285 |
-
editorRef.current?.getModel()?.getLineCount() ?? 0
|
286 |
-
);
|
287 |
-
}}
|
288 |
-
/>
|
289 |
-
</div>
|
290 |
-
<div
|
291 |
-
ref={resizer}
|
292 |
-
className="bg-neutral-800 hover:bg-sky-500 active:bg-sky-500 w-1.5 cursor-col-resize h-full max-lg:hidden"
|
293 |
/>
|
294 |
-
|
295 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
296 |
<Preview
|
297 |
html={html}
|
298 |
isResizing={isResizing}
|
299 |
isAiWorking={isAiWorking}
|
300 |
ref={preview}
|
301 |
-
|
302 |
-
currentTab={currentTab}
|
303 |
-
iframeRef={iframeRef}
|
304 |
/>
|
305 |
</main>
|
306 |
-
|
307 |
-
onReset={() => {
|
308 |
-
if (isAiWorking) {
|
309 |
-
toast.warning("Please wait for the AI to finish working.");
|
310 |
-
return;
|
311 |
-
}
|
312 |
-
if (
|
313 |
-
window.confirm("You're about to reset the editor. Are you sure?")
|
314 |
-
) {
|
315 |
-
setHtml(defaultHTML);
|
316 |
-
removeHtmlStorage();
|
317 |
-
editorRef.current?.revealLine(
|
318 |
-
editorRef.current?.getModel()?.getLineCount() ?? 0
|
319 |
-
);
|
320 |
-
}
|
321 |
-
}}
|
322 |
-
htmlHistory={htmlHistory}
|
323 |
-
setHtml={setHtml}
|
324 |
-
iframeRef={iframeRef}
|
325 |
-
auth={auth}
|
326 |
-
device={device}
|
327 |
-
setDevice={setDevice}
|
328 |
-
/>
|
329 |
-
<Toaster richColors position="bottom-center" />
|
330 |
-
</ThemeProvider>
|
331 |
);
|
332 |
}
|
|
|
|
|
|
1 |
import { useRef, useState } from "react";
|
2 |
+
import Editor from "@monaco-editor/react";
|
3 |
+
import classNames from "classnames";
|
4 |
+
import { editor } from "monaco-editor";
|
5 |
import {
|
6 |
+
useMount,
|
7 |
+
useUnmount,
|
8 |
useEvent,
|
9 |
useLocalStorage,
|
|
|
10 |
useSearchParam,
|
|
|
|
|
11 |
} from "react-use";
|
12 |
+
import { toast } from "react-toastify";
|
|
|
|
|
|
|
|
|
13 |
|
14 |
+
import Header from "./header/header";
|
15 |
+
import DeployButton from "./deploy-button/deploy-button";
|
16 |
+
import { defaultHTML } from "./../../utils/consts";
|
17 |
+
import Tabs from "./tabs/tabs";
|
18 |
+
import AskAI from "./ask-ai/ask-ai";
|
19 |
+
import { Auth } from "./../../utils/types";
|
20 |
+
import Preview from "./preview/preview";
|
|
|
21 |
|
22 |
+
function App() {
|
23 |
const [htmlStorage, , removeHtmlStorage] = useLocalStorage("html_content");
|
24 |
const remix = useSearchParam("remix");
|
|
|
|
|
25 |
|
26 |
const preview = useRef<HTMLDivElement>(null);
|
27 |
const editor = useRef<HTMLDivElement>(null);
|
28 |
const resizer = useRef<HTMLDivElement>(null);
|
29 |
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
|
|
|
|
|
|
|
30 |
|
31 |
+
const [isResizing, setIsResizing] = useState(false);
|
32 |
+
const [error, setError] = useState(false);
|
33 |
const [html, setHtml] = useState((htmlStorage as string) ?? defaultHTML);
|
34 |
const [isAiWorking, setisAiWorking] = useState(false);
|
35 |
const [auth, setAuth] = useState<Auth | undefined>(undefined);
|
36 |
+
const [currentView, setCurrentView] = useState<"editor" | "preview">(
|
37 |
+
"editor"
|
38 |
+
);
|
39 |
const [prompts, setPrompts] = useState<string[]>([]);
|
40 |
+
const [htmlHistory, setHtmlHistory] = useState<
|
41 |
+
{ html: string; createdAt: Date; prompt: string }[]
|
42 |
+
>([]);
|
|
|
43 |
|
44 |
const fetchMe = async () => {
|
45 |
const res = await fetch("/api/@me");
|
|
|
127 |
document.removeEventListener("mouseup", handleMouseUp);
|
128 |
};
|
129 |
|
130 |
+
// Prevent accidental navigation away when AI is working or content has changed
|
131 |
+
useEvent("beforeunload", (e) => {
|
132 |
+
if (isAiWorking || html !== defaultHTML) {
|
133 |
+
e.preventDefault();
|
134 |
+
return "";
|
135 |
+
}
|
136 |
+
});
|
137 |
+
|
138 |
+
// Initialize component on mount
|
139 |
useMount(() => {
|
140 |
+
// Fetch user data
|
141 |
fetchMe();
|
142 |
fetchRemix();
|
143 |
|
144 |
+
// Restore content from storage if available
|
145 |
if (htmlStorage) {
|
146 |
removeHtmlStorage();
|
147 |
+
toast.warn("Previous HTML content restored from local storage.");
|
148 |
}
|
149 |
|
150 |
+
// Set initial layout based on window size
|
151 |
resetLayout();
|
152 |
+
|
153 |
+
// Attach event listeners
|
154 |
if (!resizer.current) return;
|
155 |
resizer.current.addEventListener("mousedown", handleMouseDown);
|
156 |
window.addEventListener("resize", resetLayout);
|
157 |
});
|
158 |
+
|
159 |
+
// Clean up event listeners on unmount
|
160 |
useUnmount(() => {
|
161 |
document.removeEventListener("mousemove", handleResize);
|
162 |
document.removeEventListener("mouseup", handleMouseUp);
|
|
|
166 |
window.removeEventListener("resize", resetLayout);
|
167 |
});
|
168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
return (
|
170 |
+
<div className="h-screen bg-gray-950 font-sans overflow-hidden">
|
171 |
+
<Header
|
172 |
+
onReset={() => {
|
173 |
+
if (isAiWorking) {
|
174 |
+
toast.warn("Please wait for the AI to finish working.");
|
175 |
+
return;
|
176 |
+
}
|
177 |
+
if (
|
178 |
+
window.confirm("You're about to reset the editor. Are you sure?")
|
179 |
+
) {
|
180 |
+
setHtml(defaultHTML);
|
181 |
+
setError(false);
|
182 |
+
removeHtmlStorage();
|
183 |
+
editorRef.current?.revealLine(
|
184 |
+
editorRef.current?.getModel()?.getLineCount() ?? 0
|
185 |
+
);
|
186 |
+
}
|
187 |
+
}}
|
188 |
+
>
|
189 |
<DeployButton
|
190 |
html={html}
|
191 |
+
error={error}
|
192 |
auth={auth}
|
193 |
setHtml={setHtml}
|
194 |
prompts={prompts}
|
195 |
/>
|
196 |
</Header>
|
197 |
+
<main className="max-lg:flex-col flex w-full">
|
198 |
+
<div
|
199 |
+
ref={editor}
|
200 |
+
className={classNames(
|
201 |
+
"w-full h-[calc(100dvh-49px)] lg:h-[calc(100dvh-54px)] relative overflow-hidden max-lg:transition-all max-lg:duration-200 select-none",
|
202 |
+
{
|
203 |
+
"max-lg:h-0": currentView === "preview",
|
204 |
+
}
|
205 |
+
)}
|
206 |
+
>
|
207 |
+
<Tabs htmlHistory={htmlHistory} setHtml={setHtml} />
|
208 |
+
<div
|
209 |
+
onClick={(e) => {
|
210 |
+
if (isAiWorking) {
|
211 |
+
e.preventDefault();
|
212 |
+
e.stopPropagation();
|
213 |
+
toast.warn("Please wait for the AI to finish working.");
|
214 |
+
}
|
215 |
+
}}
|
216 |
+
>
|
217 |
+
<Editor
|
218 |
+
language="html"
|
219 |
+
theme="vs-dark"
|
220 |
+
className={classNames(
|
221 |
+
"h-[calc(100dvh-90px)] lg:h-[calc(100dvh-96px)]",
|
222 |
+
{
|
223 |
+
"pointer-events-none": isAiWorking,
|
224 |
+
}
|
225 |
+
)}
|
226 |
+
value={html}
|
227 |
+
onValidate={(markers) => {
|
228 |
+
if (markers?.length > 0) {
|
229 |
+
setError(true);
|
230 |
+
}
|
231 |
+
}}
|
232 |
+
onChange={(value) => {
|
233 |
+
const newValue = value ?? "";
|
234 |
+
setHtml(newValue);
|
235 |
+
setError(false);
|
236 |
+
}}
|
237 |
+
onMount={(editor) => (editorRef.current = editor)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
238 |
/>
|
239 |
+
</div>
|
240 |
+
<AskAI
|
241 |
+
html={html}
|
242 |
+
setHtml={(newHtml: string) => {
|
243 |
+
setHtml(newHtml);
|
244 |
+
}}
|
245 |
+
onSuccess={(finalHtml: string, p: string) => {
|
246 |
+
const currentHistory = [...htmlHistory];
|
247 |
+
currentHistory.unshift({
|
248 |
+
html: finalHtml,
|
249 |
+
createdAt: new Date(),
|
250 |
+
prompt: p,
|
251 |
+
});
|
252 |
+
setHtmlHistory(currentHistory);
|
253 |
+
}}
|
254 |
+
isAiWorking={isAiWorking}
|
255 |
+
setisAiWorking={setisAiWorking}
|
256 |
+
setView={setCurrentView}
|
257 |
+
onNewPrompt={(prompt) => {
|
258 |
+
setPrompts((prev) => [...prev, prompt]);
|
259 |
+
}}
|
260 |
+
onScrollToBottom={() => {
|
261 |
+
editorRef.current?.revealLine(
|
262 |
+
editorRef.current?.getModel()?.getLineCount() ?? 0
|
263 |
+
);
|
264 |
+
}}
|
265 |
+
/>
|
266 |
+
</div>
|
267 |
+
<div
|
268 |
+
ref={resizer}
|
269 |
+
className="bg-gray-700 hover:bg-blue-500 w-2 cursor-col-resize h-[calc(100dvh-53px)] max-lg:hidden"
|
270 |
+
/>
|
271 |
<Preview
|
272 |
html={html}
|
273 |
isResizing={isResizing}
|
274 |
isAiWorking={isAiWorking}
|
275 |
ref={preview}
|
276 |
+
setView={setCurrentView}
|
|
|
|
|
277 |
/>
|
278 |
</main>
|
279 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
);
|
281 |
}
|
282 |
+
|
283 |
+
export default App;
|
src/components/ask-ai/ask-ai.tsx
CHANGED
@@ -1,23 +1,19 @@
|
|
1 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2 |
-
import { useState
|
|
|
|
|
3 |
import classNames from "classnames";
|
4 |
-
import { toast } from "
|
5 |
-
import {
|
6 |
-
import {
|
7 |
-
import {
|
8 |
|
9 |
import Login from "../login/login";
|
10 |
-
import { defaultHTML } from "
|
11 |
import SuccessSound from "./../../assets/success.mp3";
|
12 |
import Settings from "../settings/settings";
|
13 |
import ProModal from "../pro-modal/pro-modal";
|
14 |
-
import
|
15 |
-
// @ts-expect-error not needed
|
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 |
-
import ReImagine from "../re-imagine/re-imagine";
|
21 |
|
22 |
function AskAI({
|
23 |
html,
|
@@ -25,6 +21,7 @@ function AskAI({
|
|
25 |
onScrollToBottom,
|
26 |
isAiWorking,
|
27 |
setisAiWorking,
|
|
|
28 |
onNewPrompt,
|
29 |
onSuccess,
|
30 |
}: {
|
@@ -33,198 +30,115 @@ function AskAI({
|
|
33 |
onScrollToBottom: () => void;
|
34 |
isAiWorking: boolean;
|
35 |
onNewPrompt: (prompt: string) => void;
|
36 |
-
|
37 |
setisAiWorking: React.Dispatch<React.SetStateAction<boolean>>;
|
38 |
-
onSuccess: (h: string, p: string
|
39 |
}) {
|
40 |
-
const refThink = useRef<HTMLDivElement | null>(null);
|
41 |
-
|
42 |
const [open, setOpen] = useState(false);
|
43 |
const [prompt, setPrompt] = useState("");
|
44 |
const [hasAsked, setHasAsked] = useState(false);
|
45 |
const [previousPrompt, setPreviousPrompt] = useState("");
|
46 |
const [provider, setProvider] = useLocalStorage("provider", "auto");
|
47 |
-
const [model, setModel] = useLocalStorage("model", MODELS[0].value);
|
48 |
const [openProvider, setOpenProvider] = useState(false);
|
49 |
const [providerError, setProviderError] = useState("");
|
50 |
const [openProModal, setOpenProModal] = useState(false);
|
51 |
-
|
52 |
-
const [
|
53 |
-
const [isThinking, setIsThinking] = useState(true);
|
54 |
-
const [controller, setController] = useState<AbortController | null>(null);
|
55 |
|
56 |
const audio = new Audio(SuccessSound);
|
57 |
audio.volume = 0.5;
|
58 |
|
59 |
-
const callAi = async (
|
60 |
-
if (isAiWorking) return;
|
61 |
-
if (!redesignMarkdown && !prompt.trim()) return;
|
62 |
setisAiWorking(true);
|
63 |
setProviderError("");
|
64 |
-
setThink("");
|
65 |
-
setOpenThink(false);
|
66 |
-
setIsThinking(true);
|
67 |
|
68 |
let contentResponse = "";
|
69 |
-
let thinkResponse = "";
|
70 |
let lastRenderTime = 0;
|
71 |
-
|
72 |
-
const isFollowUp = html !== defaultHTML;
|
73 |
-
const abortController = new AbortController();
|
74 |
-
setController(abortController);
|
75 |
try {
|
76 |
onNewPrompt(prompt);
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
if (request && request.body) {
|
92 |
const res = await request.json();
|
93 |
-
if (
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
toast.error(res.message);
|
103 |
-
}
|
104 |
-
setisAiWorking(false);
|
105 |
-
return;
|
106 |
}
|
107 |
-
setHtml(res.html);
|
108 |
-
toast.success("AI responded successfully");
|
109 |
-
setPreviousPrompt(prompt);
|
110 |
-
setPrompt("");
|
111 |
setisAiWorking(false);
|
112 |
-
|
113 |
-
audio.play();
|
114 |
}
|
115 |
-
|
116 |
-
const
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
headers: {
|
125 |
-
"Content-Type": "application/json",
|
126 |
-
},
|
127 |
-
signal: abortController.signal,
|
128 |
-
});
|
129 |
-
if (request && request.body) {
|
130 |
-
if (!request.ok) {
|
131 |
-
const res = await request.json();
|
132 |
-
if (res.openLogin) {
|
133 |
-
setOpen(true);
|
134 |
-
} else if (res.openSelectProvider) {
|
135 |
-
setOpenProvider(true);
|
136 |
-
setProviderError(res.message);
|
137 |
-
} else if (res.openProModal) {
|
138 |
-
setOpenProModal(true);
|
139 |
-
} else {
|
140 |
-
toast.error(res.message);
|
141 |
-
}
|
142 |
setisAiWorking(false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
return;
|
144 |
}
|
145 |
-
const reader = request.body.getReader();
|
146 |
-
const decoder = new TextDecoder("utf-8");
|
147 |
-
const selectedModel = MODELS.find(
|
148 |
-
(m: { value: string }) => m.value === model
|
149 |
-
);
|
150 |
-
let contentThink: string | undefined = undefined;
|
151 |
-
const read = async () => {
|
152 |
-
const { done, value } = await reader.read();
|
153 |
-
if (done) {
|
154 |
-
toast.success("AI responded successfully");
|
155 |
-
setPreviousPrompt(prompt);
|
156 |
-
setPrompt("");
|
157 |
-
setisAiWorking(false);
|
158 |
-
setHasAsked(true);
|
159 |
-
audio.play();
|
160 |
-
|
161 |
-
// Now we have the complete HTML including </html>, so set it to be sure
|
162 |
-
const finalDoc = contentResponse.match(
|
163 |
-
/<!DOCTYPE html>[\s\S]*<\/html>/
|
164 |
-
)?.[0];
|
165 |
-
if (finalDoc) {
|
166 |
-
setHtml(finalDoc);
|
167 |
-
}
|
168 |
-
onSuccess(finalDoc ?? contentResponse, prompt);
|
169 |
|
170 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
}
|
172 |
|
173 |
-
|
174 |
-
|
175 |
-
if (
|
176 |
-
|
177 |
-
|
178 |
-
if ((contentThink?.length ?? 0) < 3) {
|
179 |
-
setOpenThink(true);
|
180 |
-
}
|
181 |
-
setThink(thinkMatch.replace("<think>", "").trim());
|
182 |
-
contentThink += chunk;
|
183 |
-
return read();
|
184 |
-
}
|
185 |
}
|
186 |
|
187 |
-
|
188 |
-
|
189 |
-
const newHtml = contentResponse.match(
|
190 |
-
/<!DOCTYPE html>[\s\S]*/
|
191 |
-
)?.[0];
|
192 |
-
if (newHtml) {
|
193 |
-
setIsThinking(false);
|
194 |
-
let partialDoc = newHtml;
|
195 |
-
if (
|
196 |
-
partialDoc.includes("<head>") &&
|
197 |
-
!partialDoc.includes("</head>")
|
198 |
-
) {
|
199 |
-
partialDoc += "\n</head>";
|
200 |
-
}
|
201 |
-
if (
|
202 |
-
partialDoc.includes("<body") &&
|
203 |
-
!partialDoc.includes("</body>")
|
204 |
-
) {
|
205 |
-
partialDoc += "\n</body>";
|
206 |
-
}
|
207 |
-
if (!partialDoc.includes("</html>")) {
|
208 |
-
partialDoc += "\n</html>";
|
209 |
-
}
|
210 |
-
|
211 |
-
// Throttle the re-renders to avoid flashing/flicker
|
212 |
-
const now = Date.now();
|
213 |
-
if (now - lastRenderTime > 300) {
|
214 |
-
setHtml(partialDoc);
|
215 |
-
lastRenderTime = now;
|
216 |
-
}
|
217 |
-
|
218 |
-
if (partialDoc.length > 200) {
|
219 |
-
onScrollToBottom();
|
220 |
-
}
|
221 |
}
|
222 |
-
|
223 |
-
};
|
224 |
-
|
225 |
read();
|
226 |
-
}
|
|
|
|
|
227 |
}
|
|
|
|
|
228 |
} catch (error: any) {
|
229 |
setisAiWorking(false);
|
230 |
toast.error(error.message);
|
@@ -234,124 +148,65 @@ function AskAI({
|
|
234 |
}
|
235 |
};
|
236 |
|
237 |
-
const stopController = () => {
|
238 |
-
if (controller) {
|
239 |
-
controller.abort();
|
240 |
-
setController(null);
|
241 |
-
setisAiWorking(false);
|
242 |
-
setThink("");
|
243 |
-
setOpenThink(false);
|
244 |
-
setIsThinking(false);
|
245 |
-
}
|
246 |
-
};
|
247 |
-
|
248 |
-
useUpdateEffect(() => {
|
249 |
-
if (refThink.current) {
|
250 |
-
refThink.current.scrollTop = refThink.current.scrollHeight;
|
251 |
-
}
|
252 |
-
}, [think]);
|
253 |
-
|
254 |
-
useUpdateEffect(() => {
|
255 |
-
if (!isThinking) {
|
256 |
-
setOpenThink(false);
|
257 |
-
}
|
258 |
-
}, [isThinking]);
|
259 |
-
|
260 |
return (
|
261 |
-
<div
|
262 |
-
{
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
<
|
283 |
-
|
284 |
-
|
285 |
-
"overflow-y-auto transition-all duration-200 ease-in-out",
|
286 |
-
{
|
287 |
-
"max-h-[0px]": !openThink,
|
288 |
-
"min-h-[250px] max-h-[250px] border-t border-neutral-700":
|
289 |
-
openThink,
|
290 |
-
}
|
291 |
-
)}
|
292 |
-
>
|
293 |
-
<p className="text-[13px] text-neutral-400 whitespace-pre-line px-5 pb-4 pt-3">
|
294 |
-
{think}
|
295 |
-
</p>
|
296 |
-
</main>
|
297 |
-
</div>
|
298 |
)}
|
299 |
<div className="w-full relative flex items-center justify-between">
|
300 |
-
|
301 |
-
<div className="absolute bg-neutral-800 rounded-lg bottom-0 left-4 w-[calc(100%-30px)] h-full z-1 flex items-center justify-between max-lg:text-sm">
|
302 |
-
<div className="flex items-center justify-start gap-2">
|
303 |
-
<Loading overlay={false} className="!size-4" />
|
304 |
-
<p className="text-neutral-400 text-sm">
|
305 |
-
AI is {isThinking ? "thinking" : "coding"}...{" "}
|
306 |
-
</p>
|
307 |
-
</div>
|
308 |
-
<div
|
309 |
-
className="text-xs text-neutral-400 px-1 py-0.5 rounded-md border border-neutral-600 flex items-center justify-center gap-1.5 bg-neutral-800 hover:brightness-110 transition-all duration-200 cursor-pointer"
|
310 |
-
onClick={stopController}
|
311 |
-
>
|
312 |
-
<FaStopCircle />
|
313 |
-
Stop generation
|
314 |
-
</div>
|
315 |
-
</div>
|
316 |
-
)}
|
317 |
<input
|
318 |
type="text"
|
319 |
disabled={isAiWorking}
|
320 |
-
className="w-full bg-transparent text-sm outline-none text-white placeholder:text-
|
321 |
placeholder={
|
322 |
-
hasAsked ? "
|
323 |
}
|
324 |
value={prompt}
|
325 |
onChange={(e) => setPrompt(e.target.value)}
|
326 |
onKeyDown={(e) => {
|
327 |
-
if (e.key === "Enter"
|
328 |
callAi();
|
329 |
}
|
330 |
}}
|
331 |
/>
|
332 |
-
</div>
|
333 |
-
<div className="flex items-center justify-between gap-2 px-4 pb-3">
|
334 |
-
<div className="flex-1 flex items-center justify-start gap-1.5">
|
335 |
-
<ReImagine onRedesign={(md) => callAi(md)} />
|
336 |
-
<InviteFriends />
|
337 |
-
</div>
|
338 |
<div className="flex items-center justify-end gap-2">
|
|
|
339 |
<Settings
|
340 |
provider={provider as string}
|
341 |
-
model={model as string}
|
342 |
onChange={setProvider}
|
343 |
-
onModelChange={setModel}
|
344 |
open={openProvider}
|
345 |
error={providerError}
|
346 |
onClose={setOpenProvider}
|
347 |
/>
|
348 |
-
<
|
349 |
-
|
350 |
-
|
351 |
-
onClick={
|
352 |
>
|
353 |
-
<
|
354 |
-
</
|
355 |
</div>
|
356 |
</div>
|
357 |
<div
|
@@ -365,7 +220,7 @@ function AskAI({
|
|
365 |
></div>
|
366 |
<div
|
367 |
className={classNames(
|
368 |
-
"absolute top-0 -translate-y-[calc(100%+8px)] right-0 z-10 w-80 border border-
|
369 |
{
|
370 |
"opacity-0 pointer-events-none": !open,
|
371 |
}
|
|
|
1 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2 |
+
import { useState } from "react";
|
3 |
+
import { RiSparkling2Fill } from "react-icons/ri";
|
4 |
+
import { GrSend } from "react-icons/gr";
|
5 |
import classNames from "classnames";
|
6 |
+
import { toast } from "react-toastify";
|
7 |
+
import { useCopyToClipboard, useLocalStorage } from "react-use";
|
8 |
+
import { MdPreview } from "react-icons/md";
|
9 |
+
import { IoCopy } from "react-icons/io5";
|
10 |
|
11 |
import Login from "../login/login";
|
12 |
+
import { defaultHTML } from "./../../../utils/consts";
|
13 |
import SuccessSound from "./../../assets/success.mp3";
|
14 |
import Settings from "../settings/settings";
|
15 |
import ProModal from "../pro-modal/pro-modal";
|
16 |
+
// import SpeechPrompt from "../speech-prompt/speech-prompt";
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
function AskAI({
|
19 |
html,
|
|
|
21 |
onScrollToBottom,
|
22 |
isAiWorking,
|
23 |
setisAiWorking,
|
24 |
+
setView,
|
25 |
onNewPrompt,
|
26 |
onSuccess,
|
27 |
}: {
|
|
|
30 |
onScrollToBottom: () => void;
|
31 |
isAiWorking: boolean;
|
32 |
onNewPrompt: (prompt: string) => void;
|
33 |
+
setView: React.Dispatch<React.SetStateAction<"editor" | "preview">>;
|
34 |
setisAiWorking: React.Dispatch<React.SetStateAction<boolean>>;
|
35 |
+
onSuccess: (h: string, p: string) => void;
|
36 |
}) {
|
|
|
|
|
37 |
const [open, setOpen] = useState(false);
|
38 |
const [prompt, setPrompt] = useState("");
|
39 |
const [hasAsked, setHasAsked] = useState(false);
|
40 |
const [previousPrompt, setPreviousPrompt] = useState("");
|
41 |
const [provider, setProvider] = useLocalStorage("provider", "auto");
|
|
|
42 |
const [openProvider, setOpenProvider] = useState(false);
|
43 |
const [providerError, setProviderError] = useState("");
|
44 |
const [openProModal, setOpenProModal] = useState(false);
|
45 |
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
46 |
+
const [_, copyToClipboard] = useCopyToClipboard();
|
|
|
|
|
47 |
|
48 |
const audio = new Audio(SuccessSound);
|
49 |
audio.volume = 0.5;
|
50 |
|
51 |
+
const callAi = async () => {
|
52 |
+
if (isAiWorking || !prompt.trim()) return;
|
|
|
53 |
setisAiWorking(true);
|
54 |
setProviderError("");
|
|
|
|
|
|
|
55 |
|
56 |
let contentResponse = "";
|
|
|
57 |
let lastRenderTime = 0;
|
|
|
|
|
|
|
|
|
58 |
try {
|
59 |
onNewPrompt(prompt);
|
60 |
+
const request = await fetch("/api/ask-ai", {
|
61 |
+
method: "POST",
|
62 |
+
body: JSON.stringify({
|
63 |
+
prompt,
|
64 |
+
provider,
|
65 |
+
...(html === defaultHTML ? {} : { html }),
|
66 |
+
...(previousPrompt ? { previousPrompt } : {}),
|
67 |
+
}),
|
68 |
+
headers: {
|
69 |
+
"Content-Type": "application/json",
|
70 |
+
},
|
71 |
+
});
|
72 |
+
if (request && request.body) {
|
73 |
+
if (!request.ok) {
|
|
|
74 |
const res = await request.json();
|
75 |
+
if (res.openLogin) {
|
76 |
+
setOpen(true);
|
77 |
+
} else if (res.openSelectProvider) {
|
78 |
+
setOpenProvider(true);
|
79 |
+
setProviderError(res.message);
|
80 |
+
} else if (res.openProModal) {
|
81 |
+
setOpenProModal(true);
|
82 |
+
} else {
|
83 |
+
toast.error(res.message);
|
|
|
|
|
|
|
|
|
84 |
}
|
|
|
|
|
|
|
|
|
85 |
setisAiWorking(false);
|
86 |
+
return;
|
|
|
87 |
}
|
88 |
+
const reader = request.body.getReader();
|
89 |
+
const decoder = new TextDecoder("utf-8");
|
90 |
+
|
91 |
+
const read = async () => {
|
92 |
+
const { done, value } = await reader.read();
|
93 |
+
if (done) {
|
94 |
+
toast.success("AI responded successfully");
|
95 |
+
setPreviousPrompt(prompt);
|
96 |
+
setPrompt("");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
setisAiWorking(false);
|
98 |
+
setHasAsked(true);
|
99 |
+
audio.play();
|
100 |
+
setView("preview");
|
101 |
+
|
102 |
+
// Now we have the complete HTML including </html>, so set it to be sure
|
103 |
+
const finalDoc = contentResponse.match(
|
104 |
+
/<!DOCTYPE html>[\s\S]*<\/html>/
|
105 |
+
)?.[0];
|
106 |
+
if (finalDoc) {
|
107 |
+
setHtml(finalDoc);
|
108 |
+
}
|
109 |
+
onSuccess(finalDoc ?? contentResponse, prompt);
|
110 |
+
|
111 |
return;
|
112 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
|
114 |
+
const chunk = decoder.decode(value, { stream: true });
|
115 |
+
contentResponse += chunk;
|
116 |
+
const newHtml = contentResponse.match(/<!DOCTYPE html>[\s\S]*/)?.[0];
|
117 |
+
if (newHtml) {
|
118 |
+
// Force-close the HTML tag so the iframe doesn't render half-finished markup
|
119 |
+
let partialDoc = newHtml;
|
120 |
+
if (!partialDoc.includes("</html>")) {
|
121 |
+
partialDoc += "\n</html>";
|
122 |
}
|
123 |
|
124 |
+
// Throttle the re-renders to avoid flashing/flicker
|
125 |
+
const now = Date.now();
|
126 |
+
if (now - lastRenderTime > 300) {
|
127 |
+
setHtml(partialDoc);
|
128 |
+
lastRenderTime = now;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
}
|
130 |
|
131 |
+
if (partialDoc.length > 200) {
|
132 |
+
onScrollToBottom();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
}
|
134 |
+
}
|
|
|
|
|
135 |
read();
|
136 |
+
};
|
137 |
+
|
138 |
+
read();
|
139 |
}
|
140 |
+
|
141 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
142 |
} catch (error: any) {
|
143 |
setisAiWorking(false);
|
144 |
toast.error(error.message);
|
|
|
148 |
}
|
149 |
};
|
150 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
return (
|
152 |
+
<div
|
153 |
+
className={`bg-gray-950 rounded-xl py-2 lg:py-2.5 pl-3.5 lg:pl-4 pr-2 lg:pr-2.5 absolute lg:sticky bottom-3 left-3 lg:bottom-4 lg:left-4 w-[calc(100%-1.5rem)] lg:w-[calc(100%-2rem)] z-10 group ${
|
154 |
+
isAiWorking ? "animate-pulse" : ""
|
155 |
+
}`}
|
156 |
+
>
|
157 |
+
{defaultHTML !== html && (
|
158 |
+
<p
|
159 |
+
className="text-xl text-white/50 hover:text-white/80 -translate-y-[calc(100%+8px)] absolute top-0 right-0 cursor-pointer"
|
160 |
+
onClick={() => {
|
161 |
+
copyToClipboard(html);
|
162 |
+
toast.success("HTML copied to clipboard");
|
163 |
+
}}
|
164 |
+
>
|
165 |
+
<IoCopy />
|
166 |
+
</p>
|
167 |
+
)}
|
168 |
+
{defaultHTML !== html && (
|
169 |
+
<button
|
170 |
+
className="bg-white lg:hidden -translate-y-[calc(100%+8px)] absolute left-0 top-0 shadow-md text-gray-950 text-xs font-medium py-2 px-3 lg:px-4 rounded-lg flex items-center gap-2 border border-gray-100 hover:brightness-150 transition-all duration-100 cursor-pointer"
|
171 |
+
onClick={() => setView("preview")}
|
172 |
+
>
|
173 |
+
<MdPreview className="text-sm" />
|
174 |
+
View Preview
|
175 |
+
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
)}
|
177 |
<div className="w-full relative flex items-center justify-between">
|
178 |
+
<RiSparkling2Fill className="text-lg lg:text-xl text-gray-500 group-focus-within:text-pink-500" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
179 |
<input
|
180 |
type="text"
|
181 |
disabled={isAiWorking}
|
182 |
+
className="w-full bg-transparent max-lg:text-sm outline-none px-3 text-white placeholder:text-gray-500 font-code"
|
183 |
placeholder={
|
184 |
+
hasAsked ? "What do you want to ask AI next?" : "Ask AI anything..."
|
185 |
}
|
186 |
value={prompt}
|
187 |
onChange={(e) => setPrompt(e.target.value)}
|
188 |
onKeyDown={(e) => {
|
189 |
+
if (e.key === "Enter") {
|
190 |
callAi();
|
191 |
}
|
192 |
}}
|
193 |
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
<div className="flex items-center justify-end gap-2">
|
195 |
+
{/* <SpeechPrompt setPrompt={setPrompt} /> */}
|
196 |
<Settings
|
197 |
provider={provider as string}
|
|
|
198 |
onChange={setProvider}
|
|
|
199 |
open={openProvider}
|
200 |
error={providerError}
|
201 |
onClose={setOpenProvider}
|
202 |
/>
|
203 |
+
<button
|
204 |
+
disabled={isAiWorking}
|
205 |
+
className="relative overflow-hidden cursor-pointer flex-none flex items-center justify-center rounded-full text-sm font-semibold size-8 text-center bg-pink-500 hover:bg-pink-400 text-white shadow-sm dark:shadow-highlight/20 disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed disabled:hover:bg-gray-300"
|
206 |
+
onClick={callAi}
|
207 |
>
|
208 |
+
<GrSend className="-translate-x-[1px]" />
|
209 |
+
</button>
|
210 |
</div>
|
211 |
</div>
|
212 |
<div
|
|
|
220 |
></div>
|
221 |
<div
|
222 |
className={classNames(
|
223 |
+
"absolute top-0 -translate-y-[calc(100%+8px)] right-0 z-10 w-80 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
|
224 |
{
|
225 |
"opacity-0 pointer-events-none": !open,
|
226 |
}
|
src/components/deploy-button/deploy-button.tsx
CHANGED
@@ -1,26 +1,43 @@
|
|
1 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2 |
import { useState } from "react";
|
3 |
-
import
|
|
|
|
|
4 |
|
5 |
import SpaceIcon from "@/assets/space.svg";
|
6 |
import Loading from "../loading/loading";
|
7 |
import Login from "../login/login";
|
8 |
import { Auth } from "./../../../utils/types";
|
9 |
import LoadButton from "../load-button/load-button";
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
function DeployButton({
|
14 |
html,
|
|
|
15 |
auth,
|
16 |
setHtml,
|
17 |
prompts,
|
18 |
}: {
|
19 |
html: string;
|
|
|
20 |
auth?: Auth;
|
21 |
setHtml: (html: string) => void;
|
22 |
prompts: string[];
|
23 |
}) {
|
|
|
24 |
const [loading, setLoading] = useState(false);
|
25 |
const [path, setPath] = useState<string | undefined>(undefined);
|
26 |
|
@@ -46,17 +63,14 @@ function DeployButton({
|
|
46 |
});
|
47 |
const response = await request.json();
|
48 |
if (response.ok) {
|
49 |
-
toast.success(
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
},
|
58 |
-
},
|
59 |
-
});
|
60 |
setPath(response.path);
|
61 |
} else {
|
62 |
toast.error(response.message);
|
@@ -65,6 +79,7 @@ function DeployButton({
|
|
65 |
toast.error(err.message);
|
66 |
} finally {
|
67 |
setLoading(false);
|
|
|
68 |
}
|
69 |
};
|
70 |
|
@@ -72,85 +87,135 @@ function DeployButton({
|
|
72 |
<div className="flex items-center justify-end gap-5">
|
73 |
<LoadButton auth={auth} setHtml={setHtml} setPath={setPath} />
|
74 |
<div className="relative flex items-center justify-end">
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
<
|
79 |
-
|
80 |
-
</
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
</p>
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
<
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
>
|
115 |
-
huggingface.co/{path}
|
116 |
-
</a>
|
117 |
-
. You can update it by deploying again.
|
118 |
-
</span>
|
119 |
-
) : (
|
120 |
-
"Deploy your project to a space on the Hub. Spaces are a way to share your project with the world."
|
121 |
-
)}
|
122 |
</p>
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
)}
|
139 |
-
<div className="pt-2 text-right">
|
140 |
-
<button
|
141 |
-
disabled={loading || (!path && !config.title)}
|
142 |
-
className="relative rounded-full bg-black px-5 py-2 text-white font-semibold text-xs hover:bg-black/90 transition-all duration-100 disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed disabled:hover:bg-gray-300"
|
143 |
-
onClick={createSpace}
|
144 |
-
>
|
145 |
-
{path ? "Update Space" : "Create Space"}
|
146 |
-
{loading && <Loading />}
|
147 |
-
</button>
|
148 |
-
</div>
|
149 |
-
</main>
|
150 |
-
</>
|
151 |
-
)}
|
152 |
-
</PopoverContent>
|
153 |
-
</Popover>
|
154 |
</div>
|
155 |
</div>
|
156 |
);
|
|
|
1 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2 |
import { useState } from "react";
|
3 |
+
import classNames from "classnames";
|
4 |
+
import { toast } from "react-toastify";
|
5 |
+
import { FaPowerOff } from "react-icons/fa6";
|
6 |
|
7 |
import SpaceIcon from "@/assets/space.svg";
|
8 |
import Loading from "../loading/loading";
|
9 |
import Login from "../login/login";
|
10 |
import { Auth } from "./../../../utils/types";
|
11 |
import LoadButton from "../load-button/load-button";
|
12 |
+
|
13 |
+
const MsgToast = ({ url }: { url: string }) => (
|
14 |
+
<div className="w-full flex items-center justify-center gap-3">
|
15 |
+
Your space is live!
|
16 |
+
<button
|
17 |
+
className="bg-black text-sm block text-white rounded-md px-3 py-1.5 hover:bg-gray-900 cursor-pointer"
|
18 |
+
onClick={() => {
|
19 |
+
window.open(url, "_blank");
|
20 |
+
}}
|
21 |
+
>
|
22 |
+
See Space
|
23 |
+
</button>
|
24 |
+
</div>
|
25 |
+
);
|
26 |
|
27 |
function DeployButton({
|
28 |
html,
|
29 |
+
error = false,
|
30 |
auth,
|
31 |
setHtml,
|
32 |
prompts,
|
33 |
}: {
|
34 |
html: string;
|
35 |
+
error: boolean;
|
36 |
auth?: Auth;
|
37 |
setHtml: (html: string) => void;
|
38 |
prompts: string[];
|
39 |
}) {
|
40 |
+
const [open, setOpen] = useState(false);
|
41 |
const [loading, setLoading] = useState(false);
|
42 |
const [path, setPath] = useState<string | undefined>(undefined);
|
43 |
|
|
|
63 |
});
|
64 |
const response = await request.json();
|
65 |
if (response.ok) {
|
66 |
+
toast.success(
|
67 |
+
<MsgToast
|
68 |
+
url={`https://huggingface.co/spaces/${response.path ?? path}`}
|
69 |
+
/>,
|
70 |
+
{
|
71 |
+
autoClose: 10000,
|
72 |
+
}
|
73 |
+
);
|
|
|
|
|
|
|
74 |
setPath(response.path);
|
75 |
} else {
|
76 |
toast.error(response.message);
|
|
|
79 |
toast.error(err.message);
|
80 |
} finally {
|
81 |
setLoading(false);
|
82 |
+
setOpen(false);
|
83 |
}
|
84 |
};
|
85 |
|
|
|
87 |
<div className="flex items-center justify-end gap-5">
|
88 |
<LoadButton auth={auth} setHtml={setHtml} setPath={setPath} />
|
89 |
<div className="relative flex items-center justify-end">
|
90 |
+
{auth &&
|
91 |
+
(auth.isLocalUse ? (
|
92 |
+
<>
|
93 |
+
<div className="bg-amber-500/10 border border-amber-10 text-amber-500 font-semibold leading-5 lg:leading-6 py-1 px-5 text-xs lg:text-sm rounded-md mr-4 select-none">
|
94 |
+
Local Usage
|
95 |
+
</div>
|
96 |
+
</>
|
97 |
+
) : (
|
98 |
+
<>
|
99 |
+
<button
|
100 |
+
className="mr-2 cursor-pointer"
|
101 |
+
onClick={() => {
|
102 |
+
if (confirm("Are you sure you want to log out?")) {
|
103 |
+
// go to /auth/logout page
|
104 |
+
window.location.href = "/auth/logout";
|
105 |
+
}
|
106 |
+
}}
|
107 |
+
>
|
108 |
+
<FaPowerOff className="text-lg text-red-500" />
|
109 |
+
</button>
|
110 |
+
<p className="mr-3 text-xs lg:text-sm text-gray-300">
|
111 |
+
<span className="max-lg:hidden">Connected as </span>
|
112 |
+
<a
|
113 |
+
href={`https://huggingface.co/${auth.preferred_username}`}
|
114 |
+
target="_blank"
|
115 |
+
className="underline hover:text-white"
|
116 |
+
>
|
117 |
+
{auth.preferred_username}
|
118 |
+
</a>
|
119 |
+
</p>
|
120 |
+
</>
|
121 |
+
))}
|
122 |
+
<button
|
123 |
+
className={classNames(
|
124 |
+
"relative cursor-pointer flex-none flex items-center justify-center rounded-md text-xs lg:text-sm font-semibold leading-5 lg:leading-6 py-1.5 px-5 hover:bg-pink-400 text-white shadow-sm dark:shadow-highlight/20",
|
125 |
+
{
|
126 |
+
"bg-pink-400": open,
|
127 |
+
"bg-pink-500": !open,
|
128 |
+
}
|
129 |
+
)}
|
130 |
+
onClick={() => setOpen(!open)}
|
131 |
+
>
|
132 |
+
{path ? "Update Space" : "Deploy to Space"}
|
133 |
+
</button>
|
134 |
+
<div
|
135 |
+
className={classNames(
|
136 |
+
"h-screen w-screen bg-black/20 fixed left-0 top-0 z-10",
|
137 |
+
{
|
138 |
+
"opacity-0 pointer-events-none": !open,
|
139 |
+
}
|
140 |
+
)}
|
141 |
+
onClick={() => setOpen(false)}
|
142 |
+
></div>
|
143 |
+
<div
|
144 |
+
className={classNames(
|
145 |
+
"absolute top-[calc(100%+8px)] right-0 z-10 w-80 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
|
146 |
+
{
|
147 |
+
"opacity-0 pointer-events-none": !open,
|
148 |
+
}
|
149 |
+
)}
|
150 |
+
>
|
151 |
+
{!auth ? (
|
152 |
+
<Login html={html}>
|
153 |
+
<p className="text-gray-500 text-sm mb-3">
|
154 |
+
Host this project for free and share it with your friends.
|
155 |
+
</p>
|
156 |
+
</Login>
|
157 |
+
) : (
|
158 |
+
<>
|
159 |
+
<header className="flex items-center text-sm px-4 py-2 border-b border-gray-200 gap-2 bg-gray-100 font-semibold text-gray-700">
|
160 |
+
<span className="text-xs bg-pink-500/10 text-pink-500 rounded-full pl-1.5 pr-2.5 py-0.5 flex items-center justify-start gap-1.5">
|
161 |
+
<img src={SpaceIcon} alt="Space Icon" className="size-4" />
|
162 |
+
Space
|
163 |
+
</span>
|
164 |
+
Configure Deployment
|
165 |
+
</header>
|
166 |
+
<main className="px-4 pt-3 pb-4 space-y-3">
|
167 |
+
<p className="text-xs text-amber-600 bg-amber-500/10 rounded-md p-2">
|
168 |
+
{path ? (
|
169 |
+
<span>
|
170 |
+
Your space is live at{" "}
|
171 |
+
<a
|
172 |
+
href={`https://huggingface.co/spaces/${path}`}
|
173 |
+
target="_blank"
|
174 |
+
className="underline hover:text-amber-700"
|
175 |
+
>
|
176 |
+
huggingface.co/{path}
|
177 |
+
</a>
|
178 |
+
. You can update it by deploying again.
|
179 |
+
</span>
|
180 |
+
) : (
|
181 |
+
"Deploy your project to a space on the Hub. Spaces are a way to share your project with the world."
|
182 |
+
)}
|
183 |
</p>
|
184 |
+
{!path && (
|
185 |
+
<label className="block">
|
186 |
+
<p className="text-gray-600 text-sm font-medium mb-1.5">
|
187 |
+
Space Title
|
188 |
+
</p>
|
189 |
+
<input
|
190 |
+
type="text"
|
191 |
+
value={config.title}
|
192 |
+
className="mr-2 border rounded-md px-3 py-1.5 border-gray-300 w-full text-sm"
|
193 |
+
placeholder="My Awesome Space"
|
194 |
+
onChange={(e) =>
|
195 |
+
setConfig({ ...config, title: e.target.value })
|
196 |
+
}
|
197 |
+
/>
|
198 |
+
</label>
|
199 |
+
)}
|
200 |
+
{error && (
|
201 |
+
<p className="text-red-500 text-xs bg-red-500/10 rounded-md p-2">
|
202 |
+
Your code has errors. Fix them before deploying.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
</p>
|
204 |
+
)}
|
205 |
+
<div className="pt-2 text-right">
|
206 |
+
<button
|
207 |
+
disabled={error || loading || (!path && !config.title)}
|
208 |
+
className="relative rounded-full bg-black px-5 py-2 text-white font-semibold text-xs hover:bg-black/90 transition-all duration-100 disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed disabled:hover:bg-gray-300"
|
209 |
+
onClick={createSpace}
|
210 |
+
>
|
211 |
+
{path ? "Update Space" : "Create Space"}
|
212 |
+
{loading && <Loading />}
|
213 |
+
</button>
|
214 |
+
</div>
|
215 |
+
</main>
|
216 |
+
</>
|
217 |
+
)}
|
218 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
</div>
|
220 |
</div>
|
221 |
);
|
src/components/footer/footer.tsx
DELETED
@@ -1,177 +0,0 @@
|
|
1 |
-
import classNames from "classnames";
|
2 |
-
import { FaMobileAlt, FaUserCircle } from "react-icons/fa";
|
3 |
-
import { ChevronDown, LogOut, RefreshCcw, SparkleIcon } from "lucide-react";
|
4 |
-
import { FaLaptopCode } from "react-icons/fa6";
|
5 |
-
import { Auth, HtmlHistory } from "../../../utils/types";
|
6 |
-
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
|
7 |
-
import {
|
8 |
-
DropdownMenu,
|
9 |
-
DropdownMenuContent,
|
10 |
-
DropdownMenuGroup,
|
11 |
-
DropdownMenuItem,
|
12 |
-
DropdownMenuLabel,
|
13 |
-
DropdownMenuSeparator,
|
14 |
-
DropdownMenuTrigger,
|
15 |
-
} from "../ui/dropdown-menu";
|
16 |
-
import { Button } from "../ui/button";
|
17 |
-
import { MdAdd } from "react-icons/md";
|
18 |
-
import History from "../history/history";
|
19 |
-
|
20 |
-
const DEVICES = [
|
21 |
-
{
|
22 |
-
name: "desktop",
|
23 |
-
icon: FaLaptopCode,
|
24 |
-
},
|
25 |
-
{
|
26 |
-
name: "mobile",
|
27 |
-
icon: FaMobileAlt,
|
28 |
-
},
|
29 |
-
];
|
30 |
-
|
31 |
-
function Footer({
|
32 |
-
onReset,
|
33 |
-
auth,
|
34 |
-
htmlHistory,
|
35 |
-
setHtml,
|
36 |
-
device,
|
37 |
-
setDevice,
|
38 |
-
iframeRef,
|
39 |
-
}: {
|
40 |
-
onReset: () => void;
|
41 |
-
auth?: Auth;
|
42 |
-
htmlHistory?: HtmlHistory[];
|
43 |
-
device: "desktop" | "mobile";
|
44 |
-
setHtml: (html: string) => void;
|
45 |
-
iframeRef?: React.RefObject<HTMLIFrameElement | null>;
|
46 |
-
setDevice: React.Dispatch<React.SetStateAction<"desktop" | "mobile">>;
|
47 |
-
}) {
|
48 |
-
const handleRefreshIframe = () => {
|
49 |
-
if (iframeRef?.current) {
|
50 |
-
const iframe = iframeRef.current;
|
51 |
-
const content = iframe.srcdoc;
|
52 |
-
iframe.srcdoc = "";
|
53 |
-
setTimeout(() => {
|
54 |
-
iframe.srcdoc = content;
|
55 |
-
}, 10);
|
56 |
-
}
|
57 |
-
};
|
58 |
-
|
59 |
-
return (
|
60 |
-
<footer className="border-t bg-slate-200 border-slate-300 dark:bg-neutral-950 dark:border-neutral-800 px-3 py-2 flex items-center justify-between sticky bottom-0 z-20">
|
61 |
-
<div className="flex items-center gap-2">
|
62 |
-
{auth &&
|
63 |
-
(auth?.isLocalUse ? (
|
64 |
-
<>
|
65 |
-
<div className="max-w-max bg-amber-500/10 rounded-full px-3 py-1 text-amber-500 border border-amber-500/20 text-sm font-semibold">
|
66 |
-
Local Usage
|
67 |
-
</div>
|
68 |
-
</>
|
69 |
-
) : (
|
70 |
-
<>
|
71 |
-
<DropdownMenu>
|
72 |
-
<DropdownMenuTrigger asChild>
|
73 |
-
<p className="mr-3 text-xs lg:text-sm text-gray-300 flex items-center gap-1 cursor-pointer hover:brightness-110">
|
74 |
-
<ChevronDown className="size-4" />
|
75 |
-
<Avatar className="size-6 mr-1">
|
76 |
-
<AvatarImage src={auth?.picture} alt="@shadcn" />
|
77 |
-
<AvatarFallback className="text-sm">
|
78 |
-
{auth?.preferred_username?.charAt(0).toUpperCase() ??
|
79 |
-
"E"}
|
80 |
-
</AvatarFallback>
|
81 |
-
</Avatar>
|
82 |
-
{auth?.preferred_username ?? "enzostvs"}
|
83 |
-
</p>
|
84 |
-
</DropdownMenuTrigger>
|
85 |
-
<DropdownMenuContent className="w-56" align="start">
|
86 |
-
<DropdownMenuLabel className="font-bold flex items-center gap-2 justify-start">
|
87 |
-
<FaUserCircle className="" />
|
88 |
-
My Account
|
89 |
-
</DropdownMenuLabel>
|
90 |
-
<DropdownMenuSeparator />
|
91 |
-
<DropdownMenuGroup>
|
92 |
-
<a
|
93 |
-
href="https://huggingface.co/settings/billing"
|
94 |
-
target="_blank"
|
95 |
-
>
|
96 |
-
<DropdownMenuItem>Usage Quota</DropdownMenuItem>
|
97 |
-
</a>
|
98 |
-
<a
|
99 |
-
href={`https://huggingface.co/${auth?.preferred_username}`}
|
100 |
-
target="_blank"
|
101 |
-
>
|
102 |
-
<DropdownMenuItem>Hugging Face profile</DropdownMenuItem>
|
103 |
-
</a>
|
104 |
-
</DropdownMenuGroup>
|
105 |
-
<DropdownMenuSeparator />
|
106 |
-
<DropdownMenuItem
|
107 |
-
onClick={() => {
|
108 |
-
if (confirm("Are you sure you want to log out?")) {
|
109 |
-
// go to /auth/logout page
|
110 |
-
window.location.href = "/auth/logout";
|
111 |
-
}
|
112 |
-
}}
|
113 |
-
>
|
114 |
-
<LogOut className="size-4 text-red-500" />
|
115 |
-
Log out
|
116 |
-
</DropdownMenuItem>
|
117 |
-
</DropdownMenuContent>
|
118 |
-
</DropdownMenu>
|
119 |
-
</>
|
120 |
-
))}
|
121 |
-
{auth && <p className="text-neutral-700">|</p>}
|
122 |
-
<Button size="sm" variant="secondary" onClick={onReset}>
|
123 |
-
<MdAdd className="text-sm" />
|
124 |
-
<span>New Project</span>
|
125 |
-
</Button>
|
126 |
-
{htmlHistory && htmlHistory.length > 0 && (
|
127 |
-
<>
|
128 |
-
<p className="text-neutral-700">|</p>
|
129 |
-
<History history={htmlHistory} setHtml={setHtml} />
|
130 |
-
</>
|
131 |
-
)}
|
132 |
-
</div>
|
133 |
-
<div className="flex justify-end items-center gap-2.5">
|
134 |
-
<a
|
135 |
-
href="https://huggingface.co/spaces/victor/deepsite-gallery"
|
136 |
-
target="_blank"
|
137 |
-
>
|
138 |
-
<Button size="sm" variant="ghost">
|
139 |
-
<SparkleIcon className="size-3.5" />
|
140 |
-
<span className="max-lg:hidden">DeepSite Gallery</span>
|
141 |
-
</Button>
|
142 |
-
</a>
|
143 |
-
<Button size="sm" variant="default" onClick={handleRefreshIframe}>
|
144 |
-
<RefreshCcw className="size-3.5" />
|
145 |
-
<span className="max-lg:hidden">Refresh Preview</span>
|
146 |
-
</Button>
|
147 |
-
<div className="flex items-center rounded-full p-0.5 bg-neutral-700/70 relative overflow-hidden z-0 max-lg:hidden gap-0.5">
|
148 |
-
<div
|
149 |
-
className={classNames(
|
150 |
-
"absolute left-0.5 top-0.5 rounded-full bg-white size-7 -z-[1] transition-all duration-200",
|
151 |
-
{
|
152 |
-
"translate-x-[calc(100%+2px)]": device === "mobile",
|
153 |
-
}
|
154 |
-
)}
|
155 |
-
/>
|
156 |
-
{DEVICES.map((deviceItem) => (
|
157 |
-
<button
|
158 |
-
key={deviceItem.name}
|
159 |
-
className={classNames(
|
160 |
-
"rounded-full text-neutral-300 size-7 flex items-center justify-center cursor-pointer",
|
161 |
-
{
|
162 |
-
"!text-black": device === deviceItem.name,
|
163 |
-
"hover:bg-neutral-800": device !== deviceItem.name,
|
164 |
-
}
|
165 |
-
)}
|
166 |
-
onClick={() => setDevice(deviceItem.name as "desktop" | "mobile")}
|
167 |
-
>
|
168 |
-
<deviceItem.icon className="text-sm" />
|
169 |
-
</button>
|
170 |
-
))}
|
171 |
-
</div>
|
172 |
-
</div>
|
173 |
-
</footer>
|
174 |
-
);
|
175 |
-
}
|
176 |
-
|
177 |
-
export default Footer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/header/header.tsx
CHANGED
@@ -1,68 +1,39 @@
|
|
1 |
import { ReactNode } from "react";
|
2 |
-
import {
|
3 |
|
4 |
import Logo from "@/assets/logo.svg";
|
5 |
|
6 |
-
import { Button } from "./../../components/ui/button";
|
7 |
-
import classNames from "classnames";
|
8 |
-
|
9 |
-
const TABS = [
|
10 |
-
{
|
11 |
-
value: "chat",
|
12 |
-
label: "Chat",
|
13 |
-
icon: MessageCircleCode,
|
14 |
-
},
|
15 |
-
{
|
16 |
-
value: "preview",
|
17 |
-
label: "Preview",
|
18 |
-
icon: Eye,
|
19 |
-
},
|
20 |
-
];
|
21 |
-
|
22 |
function Header({
|
23 |
-
|
24 |
-
onNewTab,
|
25 |
children,
|
26 |
}: {
|
27 |
-
|
28 |
-
onNewTab: (tab: string) => void;
|
29 |
children?: ReactNode;
|
30 |
}) {
|
31 |
return (
|
32 |
-
<header className="border-b
|
33 |
<div className="flex items-center justify-start gap-3">
|
34 |
-
<h1 className="text-
|
35 |
<img
|
36 |
src={Logo}
|
37 |
alt="DeepSite Logo"
|
38 |
-
className="size-6 lg:size-8 mr-2
|
39 |
/>
|
40 |
-
|
41 |
-
DeepSite
|
42 |
-
<span className="font-mono bg-gradient-to-br from-sky-500 to-emerald-500 text-neutral-950 rounded-full text-xs ml-2 px-1.5 py-0.5">
|
43 |
-
{" "}
|
44 |
-
v2
|
45 |
-
</span>
|
46 |
-
</p>
|
47 |
</h1>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
</div>
|
49 |
-
|
50 |
-
{TABS.map((item) => (
|
51 |
-
<Button
|
52 |
-
key={item.value}
|
53 |
-
variant={tab === item.value ? "secondary" : "ghost"}
|
54 |
-
className={classNames("", {
|
55 |
-
"opacity-60": tab !== item.value,
|
56 |
-
})}
|
57 |
-
size="sm"
|
58 |
-
onClick={() => onNewTab(item.value)}
|
59 |
-
>
|
60 |
-
<item.icon className="size-4" />
|
61 |
-
<span className="hidden md:inline">{item.label}</span>
|
62 |
-
</Button>
|
63 |
-
))}
|
64 |
-
</div>
|
65 |
-
<div className="flex items-center justify-end gap-3">{children}</div>
|
66 |
</header>
|
67 |
);
|
68 |
}
|
|
|
1 |
import { ReactNode } from "react";
|
2 |
+
import { MdAdd } from "react-icons/md";
|
3 |
|
4 |
import Logo from "@/assets/logo.svg";
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
function Header({
|
7 |
+
onReset,
|
|
|
8 |
children,
|
9 |
}: {
|
10 |
+
onReset: () => void;
|
|
|
11 |
children?: ReactNode;
|
12 |
}) {
|
13 |
return (
|
14 |
+
<header className="border-b border-gray-900 bg-gray-950 px-3 lg:px-6 py-2 flex justify-between items-center sticky top-0 z-20">
|
15 |
<div className="flex items-center justify-start gap-3">
|
16 |
+
<h1 className="text-white text-lg lg:text-xl font-bold flex items-center justify-start">
|
17 |
<img
|
18 |
src={Logo}
|
19 |
alt="DeepSite Logo"
|
20 |
+
className="size-6 lg:size-8 mr-2"
|
21 |
/>
|
22 |
+
DeepSite
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
</h1>
|
24 |
+
<p className="text-gray-700 max-md:hidden">|</p>
|
25 |
+
<button
|
26 |
+
className="max-md:hidden relative cursor-pointer flex-none flex items-center justify-center rounded-md text-xs font-semibold leading-4 py-1.5 px-3 hover:bg-gray-700 text-gray-100 shadow-sm dark:shadow-highlight/20 bg-gray-800"
|
27 |
+
onClick={onReset}
|
28 |
+
>
|
29 |
+
<MdAdd className="mr-1 text-base" />
|
30 |
+
New
|
31 |
+
</button>
|
32 |
+
<p className="text-gray-500 text-sm max-md:hidden">
|
33 |
+
Imagine and Share in 1-Click
|
34 |
+
</p>
|
35 |
</div>
|
36 |
+
{children}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
</header>
|
38 |
);
|
39 |
}
|
src/components/history/history.tsx
DELETED
@@ -1,138 +0,0 @@
|
|
1 |
-
import { HtmlHistory } from "../../../utils/types";
|
2 |
-
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
3 |
-
import { Button } from "../ui/button";
|
4 |
-
|
5 |
-
export default function History({
|
6 |
-
history,
|
7 |
-
setHtml,
|
8 |
-
}: {
|
9 |
-
history: HtmlHistory[];
|
10 |
-
setHtml: (html: string) => void;
|
11 |
-
}) {
|
12 |
-
return (
|
13 |
-
<Popover>
|
14 |
-
<PopoverTrigger asChild>
|
15 |
-
<Button variant="ghost" size="sm" className="max-lg:hidden">
|
16 |
-
{history?.length} edit{history.length !== 1 ? "s" : ""}
|
17 |
-
</Button>
|
18 |
-
</PopoverTrigger>
|
19 |
-
<PopoverContent
|
20 |
-
className="!rounded-2xl !p-0 overflow-hidden !bg-neutral-900"
|
21 |
-
align="start"
|
22 |
-
>
|
23 |
-
<header className="text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
|
24 |
-
History
|
25 |
-
</header>
|
26 |
-
<main className="px-4 space-y-3">
|
27 |
-
<ul className="max-h-[250px] overflow-y-auto">
|
28 |
-
{history?.map((item, index) => (
|
29 |
-
<li
|
30 |
-
key={index}
|
31 |
-
className="text-gray-300 text-xs py-2 border-b border-gray-800 last:border-0 flex items-center justify-between gap-2"
|
32 |
-
>
|
33 |
-
<div className="">
|
34 |
-
<span className="line-clamp-1">{item.prompt}</span>
|
35 |
-
<span className="text-gray-500 text-[10px]">
|
36 |
-
{new Date(item.createdAt).toLocaleDateString("en-US", {
|
37 |
-
month: "2-digit",
|
38 |
-
day: "2-digit",
|
39 |
-
year: "2-digit",
|
40 |
-
}) +
|
41 |
-
" " +
|
42 |
-
new Date(item.createdAt).toLocaleTimeString("en-US", {
|
43 |
-
hour: "2-digit",
|
44 |
-
minute: "2-digit",
|
45 |
-
second: "2-digit",
|
46 |
-
hour12: false,
|
47 |
-
})}
|
48 |
-
</span>
|
49 |
-
</div>
|
50 |
-
<button
|
51 |
-
className="bg-pink-500 text-white text-xs font-medium rounded-md px-2 py-1 transition-all duration-100 hover:bg-pink-600 cursor-pointer"
|
52 |
-
onClick={() => {
|
53 |
-
setHtml(item.html);
|
54 |
-
}}
|
55 |
-
>
|
56 |
-
Select
|
57 |
-
</button>
|
58 |
-
</li>
|
59 |
-
))}
|
60 |
-
</ul>
|
61 |
-
</main>
|
62 |
-
</PopoverContent>
|
63 |
-
</Popover>
|
64 |
-
// <div
|
65 |
-
// className="relative"
|
66 |
-
// onMouseEnter={() => setVisible(true)}
|
67 |
-
// onMouseLeave={() => setVisible(false)}
|
68 |
-
// >
|
69 |
-
// <button
|
70 |
-
// className={classNames(
|
71 |
-
// "text-gray-400 hover:text-gray-300 cursor-pointer text-sm nderline flex items-center justify-start gap-1",
|
72 |
-
// {
|
73 |
-
// "!text-gray-300": visible,
|
74 |
-
// }
|
75 |
-
// )}
|
76 |
-
// >
|
77 |
-
// <IoTimeOutline />
|
78 |
-
// {htmlHistory?.length} versions
|
79 |
-
// </button>
|
80 |
-
// <div
|
81 |
-
// className={classNames(
|
82 |
-
// "absolute bottom-0 left-0 min-w-sm w-full z-10 translate-y-full pt-2 transition-all duration-200",
|
83 |
-
// {
|
84 |
-
// "opacity-0 pointer-events-none": !visible,
|
85 |
-
// }
|
86 |
-
// )}
|
87 |
-
// >
|
88 |
-
// <div className="bg-gray-950 border border-gray-800 rounded-xl shadow-2xs p-4">
|
89 |
-
// <p className="text-xs font-bold text-white">Version History</p>
|
90 |
-
// <p className="text-gray-400 text-xs mt-1">
|
91 |
-
// This is a list of the full history of what AI has done to
|
92 |
-
// this.
|
93 |
-
// </p>
|
94 |
-
// <ul className="mt-2 max-h-[250px] overflow-y-auto">
|
95 |
-
// {htmlHistory?.map((item, index) => (
|
96 |
-
// <li
|
97 |
-
// key={index}
|
98 |
-
// className="text-gray-300 text-xs py-2 border-b border-gray-800 last:border-0 flex items-center justify-between gap-2"
|
99 |
-
// >
|
100 |
-
// <div className="">
|
101 |
-
// <span className="line-clamp-1">{item.prompt}</span>
|
102 |
-
// <span className="text-gray-500 text-[10px]">
|
103 |
-
// {new Date(item.createdAt).toLocaleDateString(
|
104 |
-
// "en-US",
|
105 |
-
// {
|
106 |
-
// month: "2-digit",
|
107 |
-
// day: "2-digit",
|
108 |
-
// year: "2-digit",
|
109 |
-
// }
|
110 |
-
// ) +
|
111 |
-
// " " +
|
112 |
-
// new Date(item.createdAt).toLocaleTimeString(
|
113 |
-
// "en-US",
|
114 |
-
// {
|
115 |
-
// hour: "2-digit",
|
116 |
-
// minute: "2-digit",
|
117 |
-
// second: "2-digit",
|
118 |
-
// hour12: false,
|
119 |
-
// }
|
120 |
-
// )}
|
121 |
-
// </span>
|
122 |
-
// </div>
|
123 |
-
// <button
|
124 |
-
// className="bg-pink-500 text-white text-xs font-medium rounded-md px-2 py-1 transition-all duration-100 hover:bg-pink-600 cursor-pointer"
|
125 |
-
// onClick={() => {
|
126 |
-
// setHtml(item.html);
|
127 |
-
// }}
|
128 |
-
// >
|
129 |
-
// Select
|
130 |
-
// </button>
|
131 |
-
// </li>
|
132 |
-
// ))}
|
133 |
-
// </ul>
|
134 |
-
// </div>
|
135 |
-
// </div>
|
136 |
-
// </div>
|
137 |
-
);
|
138 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/invite-friends/invite-friends.tsx
DELETED
@@ -1,78 +0,0 @@
|
|
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/load-button/load-button.tsx
CHANGED
@@ -1,13 +1,10 @@
|
|
1 |
import classNames from "classnames";
|
2 |
import { useState } from "react";
|
3 |
-
import { toast } from "
|
4 |
|
5 |
import SpaceIcon from "@/assets/space.svg";
|
6 |
import Loading from "../loading/loading";
|
7 |
import { Auth } from "../../../utils/types";
|
8 |
-
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
9 |
-
import { Input } from "../ui/input";
|
10 |
-
import { Button } from "../ui/button";
|
11 |
|
12 |
function LoadButton({
|
13 |
auth,
|
@@ -20,6 +17,7 @@ function LoadButton({
|
|
20 |
}) {
|
21 |
const [open, setOpen] = useState(false);
|
22 |
const [loading, setLoading] = useState(false);
|
|
|
23 |
const [url, setUrl] = useState<string | undefined>(undefined);
|
24 |
|
25 |
const loadSpace = async () => {
|
@@ -40,10 +38,12 @@ function LoadButton({
|
|
40 |
setOpen(false);
|
41 |
} else {
|
42 |
toast.error(data.message);
|
|
|
43 |
}
|
44 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
45 |
} catch (error: any) {
|
46 |
toast.error(error.message);
|
|
|
47 |
}
|
48 |
setLoading(false);
|
49 |
};
|
@@ -54,73 +54,81 @@ function LoadButton({
|
|
54 |
"border-r border-gray-700 pr-5": auth,
|
55 |
})}
|
56 |
>
|
57 |
-
<
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
<img src={SpaceIcon} alt="Space Icon" className="size-4" />
|
73 |
Space
|
74 |
</span>
|
75 |
Load Project
|
76 |
</header>
|
77 |
<main className="px-4 pt-3 pb-4 space-y-3">
|
78 |
-
<p className="text-sm text-
|
79 |
Load an existing DeepSite Space to continue working on it.
|
80 |
</p>
|
81 |
<label className="block">
|
82 |
-
<p className="text-
|
83 |
-
|
|
|
|
|
84 |
type="text"
|
85 |
value={url}
|
86 |
-
|
87 |
placeholder="https://huggingface.co/spaces/username/space-name"
|
|
|
|
|
88 |
onBlur={(e) => {
|
89 |
-
if (!e.target.value) {
|
90 |
-
return setUrl(undefined);
|
91 |
-
}
|
92 |
-
if (
|
93 |
-
!e.target.value.startsWith(
|
94 |
-
"https://huggingface.co/spaces/"
|
95 |
-
) &&
|
96 |
-
!e.target.value.includes("/")
|
97 |
-
) {
|
98 |
-
toast.error("Please enter a valid Hugging Face Space URL.");
|
99 |
-
return;
|
100 |
-
}
|
101 |
const pathParts = e.target.value.split("/");
|
102 |
setUrl(
|
103 |
`${pathParts[pathParts.length - 2]}/${
|
104 |
pathParts[pathParts.length - 1]
|
105 |
}`
|
106 |
);
|
|
|
107 |
}}
|
108 |
/>
|
109 |
</label>
|
|
|
|
|
|
|
|
|
|
|
110 |
<div className="pt-2 text-right">
|
111 |
-
<
|
112 |
-
|
113 |
-
|
114 |
-
disabled={loading || !url}
|
115 |
onClick={loadSpace}
|
116 |
>
|
117 |
-
Load
|
118 |
{loading && <Loading />}
|
119 |
-
</
|
120 |
</div>
|
121 |
</main>
|
122 |
-
|
123 |
-
</
|
124 |
</div>
|
125 |
);
|
126 |
}
|
|
|
1 |
import classNames from "classnames";
|
2 |
import { useState } from "react";
|
3 |
+
import { toast } from "react-toastify";
|
4 |
|
5 |
import SpaceIcon from "@/assets/space.svg";
|
6 |
import Loading from "../loading/loading";
|
7 |
import { Auth } from "../../../utils/types";
|
|
|
|
|
|
|
8 |
|
9 |
function LoadButton({
|
10 |
auth,
|
|
|
17 |
}) {
|
18 |
const [open, setOpen] = useState(false);
|
19 |
const [loading, setLoading] = useState(false);
|
20 |
+
const [error, setError] = useState(false);
|
21 |
const [url, setUrl] = useState<string | undefined>(undefined);
|
22 |
|
23 |
const loadSpace = async () => {
|
|
|
38 |
setOpen(false);
|
39 |
} else {
|
40 |
toast.error(data.message);
|
41 |
+
setError(data.message);
|
42 |
}
|
43 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
44 |
} catch (error: any) {
|
45 |
toast.error(error.message);
|
46 |
+
setError(error.message);
|
47 |
}
|
48 |
setLoading(false);
|
49 |
};
|
|
|
54 |
"border-r border-gray-700 pr-5": auth,
|
55 |
})}
|
56 |
>
|
57 |
+
<p
|
58 |
+
className="underline hover:text-white cursor-pointer text-xs lg:text-sm text-gray-300"
|
59 |
+
onClick={() => setOpen(!open)}
|
60 |
+
>
|
61 |
+
Load Space
|
62 |
+
</p>
|
63 |
+
<div
|
64 |
+
className={classNames(
|
65 |
+
"h-screen w-screen bg-black/20 fixed left-0 top-0 z-10",
|
66 |
+
{
|
67 |
+
"opacity-0 pointer-events-none": !open,
|
68 |
+
}
|
69 |
+
)}
|
70 |
+
onClick={() => setOpen(false)}
|
71 |
+
></div>
|
72 |
+
<div
|
73 |
+
className={classNames(
|
74 |
+
"absolute top-[calc(100%+8px)] right-2 z-10 w-80 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
|
75 |
+
{
|
76 |
+
"opacity-0 pointer-events-none": !open,
|
77 |
+
}
|
78 |
+
)}
|
79 |
+
>
|
80 |
+
<>
|
81 |
+
<header className="flex items-center text-sm px-4 py-2 border-b border-gray-200 gap-2 bg-gray-100 font-semibold text-gray-700">
|
82 |
+
<span className="text-xs bg-pink-500/10 text-pink-500 rounded-full pl-1.5 pr-2.5 py-0.5 flex items-center justify-start gap-1.5">
|
83 |
<img src={SpaceIcon} alt="Space Icon" className="size-4" />
|
84 |
Space
|
85 |
</span>
|
86 |
Load Project
|
87 |
</header>
|
88 |
<main className="px-4 pt-3 pb-4 space-y-3">
|
89 |
+
<p className="text-sm text-pink-600 bg-pink-100 rounded-md px-3 py-2">
|
90 |
Load an existing DeepSite Space to continue working on it.
|
91 |
</p>
|
92 |
<label className="block">
|
93 |
+
<p className="text-gray-600 text-sm font-medium mb-1.5">
|
94 |
+
Space URL
|
95 |
+
</p>
|
96 |
+
<input
|
97 |
type="text"
|
98 |
value={url}
|
99 |
+
className="mr-2 border rounded-md px-3 py-1.5 border-gray-300 w-full text-sm"
|
100 |
placeholder="https://huggingface.co/spaces/username/space-name"
|
101 |
+
onChange={(e) => setUrl(e.target.value)}
|
102 |
+
onFocus={() => setError(false)}
|
103 |
onBlur={(e) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
const pathParts = e.target.value.split("/");
|
105 |
setUrl(
|
106 |
`${pathParts[pathParts.length - 2]}/${
|
107 |
pathParts[pathParts.length - 1]
|
108 |
}`
|
109 |
);
|
110 |
+
setError(false);
|
111 |
}}
|
112 |
/>
|
113 |
</label>
|
114 |
+
{error && (
|
115 |
+
<p className="text-red-500 text-xs bg-red-500/10 rounded-md p-2 break-all">
|
116 |
+
{error}
|
117 |
+
</p>
|
118 |
+
)}
|
119 |
<div className="pt-2 text-right">
|
120 |
+
<button
|
121 |
+
disabled={error || loading || !url}
|
122 |
+
className="relative rounded-full bg-black px-5 py-2 text-white font-semibold text-xs hover:bg-black/90 transition-all duration-100 disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed disabled:hover:bg-gray-300"
|
|
|
123 |
onClick={loadSpace}
|
124 |
>
|
125 |
+
Load Space
|
126 |
{loading && <Loading />}
|
127 |
+
</button>
|
128 |
</div>
|
129 |
</main>
|
130 |
+
</>
|
131 |
+
</div>
|
132 |
</div>
|
133 |
);
|
134 |
}
|
src/components/loading/loading.tsx
CHANGED
@@ -1,21 +1,8 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
function Loading({
|
4 |
-
overlay = true,
|
5 |
-
className,
|
6 |
-
}: {
|
7 |
-
overlay?: boolean;
|
8 |
-
className?: string;
|
9 |
-
}) {
|
10 |
return (
|
11 |
-
<div
|
12 |
-
className={classNames("", {
|
13 |
-
"absolute left-0 top-0 h-full w-full flex items-center justify-center z-20 bg-black/50 rounded-full":
|
14 |
-
overlay,
|
15 |
-
})}
|
16 |
-
>
|
17 |
<svg
|
18 |
-
className=
|
19 |
xmlns="http://www.w3.org/2000/svg"
|
20 |
fill="none"
|
21 |
viewBox="0 0 24 24"
|
|
|
1 |
+
function Loading() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
return (
|
3 |
+
<div className="absolute left-0 top-0 h-full w-full flex items-center justify-center bg-white/30 z-20">
|
|
|
|
|
|
|
|
|
|
|
4 |
<svg
|
5 |
+
className="size-5 animate-spin text-white"
|
6 |
xmlns="http://www.w3.org/2000/svg"
|
7 |
fill="none"
|
8 |
viewBox="0 0 24 24"
|
src/components/login/login.tsx
CHANGED
@@ -23,17 +23,17 @@ function Login({
|
|
23 |
|
24 |
return (
|
25 |
<>
|
26 |
-
<header className="flex items-center text-sm px-4 py-
|
27 |
-
<span className="text-xs bg-red-500 text-
|
28 |
REQUIRED
|
29 |
</span>
|
30 |
Login with Hugging Face
|
31 |
</header>
|
32 |
<main className="px-4 py-4 space-y-3">
|
33 |
{children}
|
34 |
-
<button onClick={handleClick}
|
35 |
<img
|
36 |
-
src="https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-lg.svg"
|
37 |
alt="Sign in with Hugging Face"
|
38 |
className="mx-auto"
|
39 |
/>
|
|
|
23 |
|
24 |
return (
|
25 |
<>
|
26 |
+
<header className="flex items-center text-sm px-4 py-2 border-b border-gray-200 gap-2 bg-gray-100 font-semibold text-gray-700">
|
27 |
+
<span className="text-xs bg-red-500/10 text-red-500 rounded-full pl-1.5 pr-2.5 py-0.5 flex items-center justify-start gap-1.5">
|
28 |
REQUIRED
|
29 |
</span>
|
30 |
Login with Hugging Face
|
31 |
</header>
|
32 |
<main className="px-4 py-4 space-y-3">
|
33 |
{children}
|
34 |
+
<button onClick={handleClick}>
|
35 |
<img
|
36 |
+
src="https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-lg-dark.svg"
|
37 |
alt="Sign in with Hugging Face"
|
38 |
className="mx-auto"
|
39 |
/>
|
src/components/magicui/grid-pattern.tsx
DELETED
@@ -1,69 +0,0 @@
|
|
1 |
-
import { useId } from "react";
|
2 |
-
import { cn } from "../../lib/utils";
|
3 |
-
|
4 |
-
interface GridPatternProps extends React.SVGProps<SVGSVGElement> {
|
5 |
-
width?: number;
|
6 |
-
height?: number;
|
7 |
-
x?: number;
|
8 |
-
y?: number;
|
9 |
-
squares?: Array<[x: number, y: number]>;
|
10 |
-
strokeDasharray?: string;
|
11 |
-
className?: string;
|
12 |
-
[key: string]: unknown;
|
13 |
-
}
|
14 |
-
|
15 |
-
export function GridPattern({
|
16 |
-
width = 40,
|
17 |
-
height = 40,
|
18 |
-
x = -1,
|
19 |
-
y = -1,
|
20 |
-
strokeDasharray = "0",
|
21 |
-
squares,
|
22 |
-
className,
|
23 |
-
...props
|
24 |
-
}: GridPatternProps) {
|
25 |
-
const id = useId();
|
26 |
-
|
27 |
-
return (
|
28 |
-
<svg
|
29 |
-
aria-hidden="true"
|
30 |
-
className={cn(
|
31 |
-
"pointer-events-none absolute inset-0 h-full w-full fill-gray-400/30 stroke-neutral-700 -z-[1]",
|
32 |
-
className
|
33 |
-
)}
|
34 |
-
{...props}
|
35 |
-
>
|
36 |
-
<defs>
|
37 |
-
<pattern
|
38 |
-
id={id}
|
39 |
-
width={width}
|
40 |
-
height={height}
|
41 |
-
patternUnits="userSpaceOnUse"
|
42 |
-
x={x}
|
43 |
-
y={y}
|
44 |
-
>
|
45 |
-
<path
|
46 |
-
d={`M.5 ${height}V.5H${width}`}
|
47 |
-
fill="none"
|
48 |
-
strokeDasharray={strokeDasharray}
|
49 |
-
/>
|
50 |
-
</pattern>
|
51 |
-
</defs>
|
52 |
-
<rect width="100%" height="100%" strokeWidth={0} fill={`url(#${id})`} />
|
53 |
-
{squares && (
|
54 |
-
<svg x={x} y={y} className="overflow-visible">
|
55 |
-
{squares.map(([x, y]) => (
|
56 |
-
<rect
|
57 |
-
strokeWidth="0"
|
58 |
-
key={`${x}-${y}`}
|
59 |
-
width={width - 1}
|
60 |
-
height={height - 1}
|
61 |
-
x={x * width + 1}
|
62 |
-
y={y * height + 1}
|
63 |
-
/>
|
64 |
-
))}
|
65 |
-
</svg>
|
66 |
-
)}
|
67 |
-
</svg>
|
68 |
-
);
|
69 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/preview/preview.tsx
CHANGED
@@ -1,77 +1,83 @@
|
|
1 |
import classNames from "classnames";
|
2 |
-
|
3 |
-
import {
|
4 |
-
import {
|
5 |
-
import {
|
|
|
6 |
|
7 |
function Preview({
|
8 |
html,
|
9 |
isResizing,
|
10 |
isAiWorking,
|
|
|
11 |
ref,
|
12 |
-
device,
|
13 |
-
currentTab,
|
14 |
-
iframeRef,
|
15 |
}: {
|
16 |
html: string;
|
17 |
isResizing: boolean;
|
18 |
isAiWorking: boolean;
|
|
|
19 |
ref: React.RefObject<HTMLDivElement | null>;
|
20 |
-
iframeRef?: React.RefObject<HTMLIFrameElement | null>;
|
21 |
-
device: "desktop" | "mobile";
|
22 |
-
currentTab: string;
|
23 |
}) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
return (
|
25 |
<div
|
26 |
ref={ref}
|
27 |
-
className=
|
28 |
-
"w-full border-l border-gray-900 h-full relative z-0 flex items-center justify-center",
|
29 |
-
{
|
30 |
-
"lg:p-4": currentTab !== "preview",
|
31 |
-
}
|
32 |
-
)}
|
33 |
onClick={(e) => {
|
34 |
if (isAiWorking) {
|
35 |
e.preventDefault();
|
36 |
e.stopPropagation();
|
37 |
-
toast.
|
38 |
}
|
39 |
}}
|
40 |
>
|
41 |
-
<GridPattern
|
42 |
-
x={-1}
|
43 |
-
y={-1}
|
44 |
-
strokeDasharray={"4 2"}
|
45 |
-
className={cn(
|
46 |
-
"[mask-image:radial-gradient(900px_circle_at_center,white,transparent)]"
|
47 |
-
)}
|
48 |
-
/>
|
49 |
<iframe
|
50 |
-
id="preview-iframe"
|
51 |
ref={iframeRef}
|
52 |
title="output"
|
53 |
-
className={classNames(
|
54 |
-
"
|
55 |
-
|
56 |
-
"pointer-events-none": isResizing || isAiWorking,
|
57 |
-
"lg:max-w-md lg:mx-auto lg:h-[80dvh] lg:!rounded-[42px] lg:border-[8px] lg:border-neutral-700 lg:shadow-2xl":
|
58 |
-
device === "mobile",
|
59 |
-
"h-full": device === "desktop",
|
60 |
-
"lg:border-[8px] lg:border-neutral-700 lg:shadow-2xl lg:rounded-[44px]":
|
61 |
-
currentTab !== "preview" && device === "desktop",
|
62 |
-
}
|
63 |
-
)}
|
64 |
srcDoc={html}
|
65 |
-
onLoad={() => {
|
66 |
-
if (iframeRef?.current?.contentWindow?.document?.body) {
|
67 |
-
iframeRef.current.contentWindow.document.body.scrollIntoView({
|
68 |
-
block: isAiWorking ? "end" : "start",
|
69 |
-
inline: "nearest",
|
70 |
-
behavior: isAiWorking ? "instant" : "smooth",
|
71 |
-
});
|
72 |
-
}
|
73 |
-
}}
|
74 |
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
</div>
|
76 |
);
|
77 |
}
|
|
|
1 |
import classNames from "classnames";
|
2 |
+
import { useRef } from "react";
|
3 |
+
import { TbReload } from "react-icons/tb";
|
4 |
+
import { toast } from "react-toastify";
|
5 |
+
import { FaLaptopCode } from "react-icons/fa6";
|
6 |
+
import { defaultHTML } from "../../../utils/consts";
|
7 |
|
8 |
function Preview({
|
9 |
html,
|
10 |
isResizing,
|
11 |
isAiWorking,
|
12 |
+
setView,
|
13 |
ref,
|
|
|
|
|
|
|
14 |
}: {
|
15 |
html: string;
|
16 |
isResizing: boolean;
|
17 |
isAiWorking: boolean;
|
18 |
+
setView: React.Dispatch<React.SetStateAction<"editor" | "preview">>;
|
19 |
ref: React.RefObject<HTMLDivElement | null>;
|
|
|
|
|
|
|
20 |
}) {
|
21 |
+
const iframeRef = useRef<HTMLIFrameElement | null>(null);
|
22 |
+
|
23 |
+
const handleRefreshIframe = () => {
|
24 |
+
if (iframeRef.current) {
|
25 |
+
const iframe = iframeRef.current;
|
26 |
+
const content = iframe.srcdoc;
|
27 |
+
iframe.srcdoc = "";
|
28 |
+
setTimeout(() => {
|
29 |
+
iframe.srcdoc = content;
|
30 |
+
}, 10);
|
31 |
+
}
|
32 |
+
};
|
33 |
+
|
34 |
return (
|
35 |
<div
|
36 |
ref={ref}
|
37 |
+
className="w-full border-l border-gray-900 bg-white h-[calc(100dvh-49px)] lg:h-[calc(100dvh-53px)] relative"
|
|
|
|
|
|
|
|
|
|
|
38 |
onClick={(e) => {
|
39 |
if (isAiWorking) {
|
40 |
e.preventDefault();
|
41 |
e.stopPropagation();
|
42 |
+
toast.warn("Please wait for the AI to finish working.");
|
43 |
}
|
44 |
}}
|
45 |
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
<iframe
|
|
|
47 |
ref={iframeRef}
|
48 |
title="output"
|
49 |
+
className={classNames("w-full h-full select-none", {
|
50 |
+
"pointer-events-none": isResizing || isAiWorking,
|
51 |
+
})}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
srcDoc={html}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
/>
|
54 |
+
<div className="flex items-center justify-start gap-3 absolute bottom-3 lg:bottom-5 max-lg:left-3 lg:right-5">
|
55 |
+
<button
|
56 |
+
className="lg:hidden bg-gray-950 shadow-md text-white text-xs lg:text-sm font-medium py-2 px-3 lg:px-4 rounded-lg flex items-center gap-2 border border-gray-900 hover:brightness-150 transition-all duration-100 cursor-pointer"
|
57 |
+
onClick={() => setView("editor")}
|
58 |
+
>
|
59 |
+
<FaLaptopCode className="text-sm" />
|
60 |
+
Hide preview
|
61 |
+
</button>
|
62 |
+
{html === defaultHTML && (
|
63 |
+
<a
|
64 |
+
href="https://huggingface.co/spaces/victor/deepsite-gallery"
|
65 |
+
target="_blank"
|
66 |
+
className="bg-gray-200 text-gray-950 text-xs lg:text-sm font-medium py-2 px-3 lg:px-4 rounded-lg flex items-center gap-2 border border-gray-200 hover:bg-gray-300 transition-all duration-100 cursor-pointer"
|
67 |
+
>
|
68 |
+
🖼️ <span>DeepSite Gallery</span>
|
69 |
+
</a>
|
70 |
+
)}
|
71 |
+
{!isAiWorking && (
|
72 |
+
<button
|
73 |
+
className="bg-white lg:bg-gray-950 shadow-md text-gray-950 lg:text-white text-xs lg:text-sm font-medium py-2 px-3 lg:px-4 rounded-lg flex items-center gap-2 border border-gray-100 lg:border-gray-900 hover:brightness-150 transition-all duration-100 cursor-pointer"
|
74 |
+
onClick={handleRefreshIframe}
|
75 |
+
>
|
76 |
+
<TbReload className="text-sm" />
|
77 |
+
Refresh Preview
|
78 |
+
</button>
|
79 |
+
)}
|
80 |
+
</div>
|
81 |
</div>
|
82 |
);
|
83 |
}
|
src/components/pro-modal/pro-modal.tsx
CHANGED
@@ -1,8 +1,6 @@
|
|
|
|
1 |
import { useLocalStorage } from "react-use";
|
2 |
import { defaultHTML } from "../../../utils/consts";
|
3 |
-
import { Dialog, DialogContent } from "../ui/dialog";
|
4 |
-
import { Button } from "../ui/button";
|
5 |
-
import { CheckCheck } from "lucide-react";
|
6 |
|
7 |
function ProModal({
|
8 |
open,
|
@@ -22,73 +20,51 @@ function ProModal({
|
|
22 |
};
|
23 |
|
24 |
return (
|
25 |
-
|
26 |
-
<
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
</p>
|
42 |
-
<p className="text-
|
43 |
-
It
|
|
|
44 |
</p>
|
45 |
-
<
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
<ul className="mt-3 space-y-1 text-neutral-500">
|
50 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
51 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
52 |
-
DeepSite unlimited access to all Inference Providers
|
53 |
-
</li>
|
54 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
55 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
56 |
-
Get highest priority and 8x more quota on Spaces ZeroGPU
|
57 |
-
</li>
|
58 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
59 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
60 |
-
Activate Dataset Viewer on private datasets
|
61 |
-
</li>
|
62 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
63 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
64 |
-
Get exclusive early access to new features and updates
|
65 |
-
</li>
|
66 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
67 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
68 |
-
Get free credits across all Inference Providers
|
69 |
-
</li>
|
70 |
-
<li className="text-sm text-neutral-500 space-x-2 flex items-center justify-start gap-2 mt-3">
|
71 |
-
... and much more!
|
72 |
-
</li>
|
73 |
-
</ul>
|
74 |
-
<Button
|
75 |
-
variant="gray"
|
76 |
-
size="lg"
|
77 |
-
className="w-full !text-base !h-11 mt-8"
|
78 |
onClick={handleProClick}
|
79 |
>
|
80 |
Subscribe to PRO ($9/month)
|
81 |
-
</
|
82 |
</main>
|
83 |
-
</
|
84 |
-
|
85 |
);
|
86 |
}
|
87 |
-
|
88 |
-
<span
|
89 |
-
className={`${className} bg-linear-to-br shadow-green-500/10 dark:shadow-green-500/20 inline-block -skew-x-12 border border-gray-200 from-pink-300 via-green-200 to-yellow-200 text-xs font-bold text-black shadow-lg rounded-md px-2.5 py-0.5`}
|
90 |
-
>
|
91 |
-
PRO
|
92 |
-
</span>
|
93 |
-
);
|
94 |
export default ProModal;
|
|
|
1 |
+
import classNames from "classnames";
|
2 |
import { useLocalStorage } from "react-use";
|
3 |
import { defaultHTML } from "../../../utils/consts";
|
|
|
|
|
|
|
4 |
|
5 |
function ProModal({
|
6 |
open,
|
|
|
20 |
};
|
21 |
|
22 |
return (
|
23 |
+
<>
|
24 |
+
<div
|
25 |
+
className={classNames(
|
26 |
+
"h-screen w-screen bg-black/20 fixed left-0 top-0 z-40",
|
27 |
+
{
|
28 |
+
"opacity-0 pointer-events-none": !open,
|
29 |
+
}
|
30 |
+
)}
|
31 |
+
onClick={() => onClose(false)}
|
32 |
+
></div>
|
33 |
+
<div
|
34 |
+
className={classNames(
|
35 |
+
"absolute top-0 -translate-y-[calc(100%+16px)] right-0 z-40 w-96 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
|
36 |
+
{
|
37 |
+
"opacity-0 pointer-events-none": !open,
|
38 |
+
}
|
39 |
+
)}
|
40 |
+
>
|
41 |
+
<header className="flex items-center text-sm px-4 py-2 border-b border-gray-200 gap-2 bg-gray-100 font-semibold text-gray-700">
|
42 |
+
<span className="bg-linear-to-br shadow-green-500/10 dark:shadow-green-500/20 inline-block -skew-x-12 border border-gray-200 from-pink-300 via-green-200 to-yellow-200 text-xs font-bold text-black shadow-lg dark:from-pink-500 dark:via-green-500 dark:to-yellow-500 dark:text-black rounded-lg px-2.5 py-0.5 ">
|
43 |
+
PRO
|
44 |
+
</span>
|
45 |
+
Your free inference quota is exhausted
|
46 |
+
</header>
|
47 |
+
<main className="px-4 pt-3 pb-4">
|
48 |
+
<p className="text-gray-950 text-sm font-semibold flex items-center justify-between">
|
49 |
+
Upgrade to a PRO account to activate Inference Providers and
|
50 |
+
continue using DeepSite.
|
51 |
</p>
|
52 |
+
<p className="text-sm text-pretty text-gray-500 mt-2">
|
53 |
+
It also unlocks thousands of Space apps powered by ZeroGPU for 3d,
|
54 |
+
audio, music, video and more!
|
55 |
</p>
|
56 |
+
<a
|
57 |
+
href="https://huggingface.co/subscribe/pro"
|
58 |
+
target="_blank"
|
59 |
+
className="mt-4 bg-black text-white cursor-pointer rounded-full py-2 px-3 text-sm font-medium w-full block text-center hover:bg-gray-800 transition duration-200 ease-in-out"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
onClick={handleProClick}
|
61 |
>
|
62 |
Subscribe to PRO ($9/month)
|
63 |
+
</a>
|
64 |
</main>
|
65 |
+
</div>
|
66 |
+
</>
|
67 |
);
|
68 |
}
|
69 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
export default ProModal;
|
src/components/re-imagine/re-imagine.tsx
DELETED
@@ -1,136 +0,0 @@
|
|
1 |
-
import { useState } from "react";
|
2 |
-
import { Paintbrush } from "lucide-react";
|
3 |
-
import { toast } from "sonner";
|
4 |
-
|
5 |
-
import { Button } from "../ui/button";
|
6 |
-
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
7 |
-
import { Input } from "../ui/input";
|
8 |
-
import Loading from "../loading/loading";
|
9 |
-
|
10 |
-
export default function ReImagine({
|
11 |
-
onRedesign,
|
12 |
-
}: {
|
13 |
-
onRedesign: (md: string) => void;
|
14 |
-
}) {
|
15 |
-
const [url, setUrl] = useState<string>("");
|
16 |
-
const [open, setOpen] = useState(false);
|
17 |
-
const [isLoading, setIsLoading] = useState(false);
|
18 |
-
|
19 |
-
const checkIfUrlIsValid = (url: string) => {
|
20 |
-
const urlPattern = new RegExp(
|
21 |
-
/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/,
|
22 |
-
"i"
|
23 |
-
);
|
24 |
-
return urlPattern.test(url);
|
25 |
-
};
|
26 |
-
|
27 |
-
const handleClick = async () => {
|
28 |
-
if (!url) {
|
29 |
-
toast.error("Please enter a URL.");
|
30 |
-
return;
|
31 |
-
}
|
32 |
-
if (!checkIfUrlIsValid(url)) {
|
33 |
-
toast.error("Please enter a valid URL.");
|
34 |
-
return;
|
35 |
-
}
|
36 |
-
// Here you would typically handle the re-design logic
|
37 |
-
setIsLoading(true);
|
38 |
-
const request = await fetch("/api/re-design", {
|
39 |
-
method: "POST",
|
40 |
-
body: JSON.stringify({ url }),
|
41 |
-
headers: {
|
42 |
-
"Content-Type": "application/json",
|
43 |
-
},
|
44 |
-
});
|
45 |
-
const response = await request.json();
|
46 |
-
if (response.ok) {
|
47 |
-
setOpen(false);
|
48 |
-
setUrl("");
|
49 |
-
onRedesign(response.markdown);
|
50 |
-
toast.success("DeepSite is re-designing your site! Let him cook... 🔥");
|
51 |
-
} else {
|
52 |
-
toast.error(response.message || "Failed to re-design the site.");
|
53 |
-
}
|
54 |
-
setIsLoading(false);
|
55 |
-
};
|
56 |
-
|
57 |
-
return (
|
58 |
-
<Popover open={open} onOpenChange={setOpen}>
|
59 |
-
<form>
|
60 |
-
<PopoverTrigger asChild>
|
61 |
-
<Button
|
62 |
-
size="iconXs"
|
63 |
-
variant="outline"
|
64 |
-
className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
|
65 |
-
>
|
66 |
-
<Paintbrush className="size-4" />
|
67 |
-
</Button>
|
68 |
-
</PopoverTrigger>
|
69 |
-
<PopoverContent
|
70 |
-
align="start"
|
71 |
-
className="!rounded-2xl !p-0 !bg-white !border-neutral-100 min-w-xs text-center overflow-hidden"
|
72 |
-
>
|
73 |
-
<header className="bg-neutral-50 p-6 border-b border-neutral-200/60">
|
74 |
-
<div className="flex items-center justify-center -space-x-4 mb-3">
|
75 |
-
<div className="size-9 rounded-full bg-pink-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
|
76 |
-
🎨
|
77 |
-
</div>
|
78 |
-
<div className="size-11 rounded-full bg-amber-200 shadow-2xl flex items-center justify-center text-2xl z-2">
|
79 |
-
🥳
|
80 |
-
</div>
|
81 |
-
<div className="size-9 rounded-full bg-sky-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
|
82 |
-
💎
|
83 |
-
</div>
|
84 |
-
</div>
|
85 |
-
<p className="text-xl font-semibold text-neutral-950">
|
86 |
-
Redesign your Site!
|
87 |
-
</p>
|
88 |
-
<p className="text-sm text-neutral-500 mt-1.5">
|
89 |
-
Try our new Redesign feature to give your site a fresh look.
|
90 |
-
</p>
|
91 |
-
</header>
|
92 |
-
<main className="space-y-4 p-6">
|
93 |
-
<div>
|
94 |
-
<p className="text-sm text-neutral-700 mb-2">
|
95 |
-
Enter your website URL to get started:
|
96 |
-
</p>
|
97 |
-
<Input
|
98 |
-
type="text"
|
99 |
-
placeholder="https://example.com"
|
100 |
-
value={url}
|
101 |
-
onChange={(e) => setUrl(e.target.value)}
|
102 |
-
onBlur={(e) => {
|
103 |
-
const inputUrl = e.target.value.trim();
|
104 |
-
if (!inputUrl) {
|
105 |
-
setUrl("");
|
106 |
-
return;
|
107 |
-
}
|
108 |
-
if (!checkIfUrlIsValid(inputUrl)) {
|
109 |
-
toast.error("Please enter a valid URL.");
|
110 |
-
return;
|
111 |
-
}
|
112 |
-
setUrl(inputUrl);
|
113 |
-
}}
|
114 |
-
className="!bg-white !border-neutral-300 !text-neutral-800 !placeholder:text-neutral-400 selection:!bg-blue-100"
|
115 |
-
/>
|
116 |
-
</div>
|
117 |
-
<div>
|
118 |
-
<p className="text-sm text-neutral-700 mb-2">
|
119 |
-
Then, let's redesign it!
|
120 |
-
</p>
|
121 |
-
<Button
|
122 |
-
variant="gray"
|
123 |
-
onClick={handleClick}
|
124 |
-
className="relative w-full"
|
125 |
-
disabled={isLoading}
|
126 |
-
>
|
127 |
-
Redesign <Paintbrush className="size-4" />
|
128 |
-
{isLoading && <Loading className="ml-2 size-4 animate-spin" />}
|
129 |
-
</Button>
|
130 |
-
</div>
|
131 |
-
</main>
|
132 |
-
</PopoverContent>
|
133 |
-
</form>
|
134 |
-
</Popover>
|
135 |
-
);
|
136 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/settings/settings.tsx
CHANGED
@@ -1,195 +1,136 @@
|
|
1 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2 |
import classNames from "classnames";
|
3 |
-
import { PiGearSixFill } from "react-icons/pi";
|
4 |
-
import { RiCheckboxCircleFill } from "react-icons/ri";
|
5 |
|
6 |
-
import {
|
7 |
// @ts-expect-error not needed
|
8 |
-
import { PROVIDERS
|
9 |
-
import { Button } from "../ui/button";
|
10 |
-
import {
|
11 |
-
Select,
|
12 |
-
SelectContent,
|
13 |
-
SelectGroup,
|
14 |
-
SelectItem,
|
15 |
-
SelectLabel,
|
16 |
-
SelectTrigger,
|
17 |
-
SelectValue,
|
18 |
-
} from "../ui/select";
|
19 |
-
import { useMemo } from "react";
|
20 |
-
import { useUpdateEffect } from "react-use";
|
21 |
|
22 |
function Settings({
|
23 |
open,
|
24 |
onClose,
|
25 |
provider,
|
26 |
-
model,
|
27 |
error,
|
28 |
onChange,
|
29 |
-
onModelChange,
|
30 |
}: {
|
31 |
open: boolean;
|
32 |
provider: string;
|
33 |
-
model: string;
|
34 |
error?: string;
|
35 |
onClose: React.Dispatch<React.SetStateAction<boolean>>;
|
36 |
onChange: (provider: string) => void;
|
37 |
-
onModelChange: (model: string) => void;
|
38 |
}) {
|
39 |
-
const modelAvailableProviders = useMemo(() => {
|
40 |
-
const availableProviders = MODELS.find(
|
41 |
-
(m: { value: string }) => m.value === model
|
42 |
-
)?.providers;
|
43 |
-
if (!availableProviders) return Object.keys(PROVIDERS);
|
44 |
-
return Object.keys(PROVIDERS).filter((id) =>
|
45 |
-
availableProviders.includes(id)
|
46 |
-
);
|
47 |
-
}, [model]);
|
48 |
-
|
49 |
-
useUpdateEffect(() => {
|
50 |
-
if (provider !== "auto" && !modelAvailableProviders.includes(provider)) {
|
51 |
-
onChange("auto");
|
52 |
-
}
|
53 |
-
}, [model, provider]);
|
54 |
-
|
55 |
return (
|
56 |
<div className="">
|
57 |
-
<
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
<a
|
76 |
href="https://huggingface.co/spaces/enzostvs/deepsite/discussions/74"
|
77 |
target="_blank"
|
78 |
-
className="w-full flex items-center justify-between text-
|
79 |
>
|
80 |
How to use it locally?
|
81 |
-
<
|
|
|
|
|
82 |
</a>
|
83 |
-
|
84 |
-
<p className="text-
|
85 |
-
|
86 |
</p>
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
<SelectLabel>DeepSeek models</SelectLabel>
|
99 |
-
{MODELS.map(
|
100 |
-
({
|
101 |
-
value,
|
102 |
-
label,
|
103 |
-
isNew = false,
|
104 |
-
}: {
|
105 |
-
value: string;
|
106 |
-
label: string;
|
107 |
-
isNew?: boolean;
|
108 |
-
}) => (
|
109 |
-
<SelectItem key={value} value={value} className="">
|
110 |
-
{label}
|
111 |
-
{isNew && (
|
112 |
-
<span className="text-xs bg-gradient-to-br from-sky-400 to-sky-600 text-white rounded-full px-1.5 py-0.5">
|
113 |
-
New
|
114 |
-
</span>
|
115 |
-
)}
|
116 |
-
</SelectItem>
|
117 |
-
)
|
118 |
-
)}
|
119 |
-
</SelectGroup>
|
120 |
-
</SelectContent>
|
121 |
-
</Select>
|
122 |
-
</label>
|
123 |
-
<div className="flex flex-col gap-3">
|
124 |
-
<div className="flex items-center justify-between">
|
125 |
-
<div>
|
126 |
-
<p className="text-neutral-300 text-sm mb-1.5">
|
127 |
-
Use auto-provider
|
128 |
-
</p>
|
129 |
-
<p className="text-xs text-neutral-400/70">
|
130 |
-
We'll automatically select the best provider for you based
|
131 |
-
on your prompt.
|
132 |
-
</p>
|
133 |
-
</div>
|
134 |
<div
|
135 |
className={classNames(
|
136 |
-
"
|
137 |
{
|
138 |
-
"
|
139 |
}
|
140 |
)}
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
}
|
|
|
|
|
|
|
150 |
}}
|
151 |
>
|
152 |
-
<
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
"translate-x-4": provider === "auto",
|
157 |
-
}
|
158 |
-
)}
|
159 |
/>
|
|
|
160 |
</div>
|
161 |
-
|
162 |
-
<label className="block">
|
163 |
-
<p className="text-neutral-300 text-sm mb-2">
|
164 |
-
Inference Provider
|
165 |
-
</p>
|
166 |
-
<div className="grid grid-cols-2 gap-1.5">
|
167 |
-
{modelAvailableProviders.map((id: string) => (
|
168 |
-
<Button
|
169 |
-
key={id}
|
170 |
-
variant={id === provider ? "default" : "secondary"}
|
171 |
-
size="sm"
|
172 |
-
onClick={() => {
|
173 |
-
onChange(id);
|
174 |
-
}}
|
175 |
-
>
|
176 |
-
<img
|
177 |
-
src={`/providers/${id}.svg`}
|
178 |
-
alt={PROVIDERS[id].name}
|
179 |
-
className="size-5 mr-2"
|
180 |
-
/>
|
181 |
-
{PROVIDERS[id].name}
|
182 |
-
{id === provider && (
|
183 |
-
<RiCheckboxCircleFill className="ml-2 size-4 text-blue-500" />
|
184 |
-
)}
|
185 |
-
</Button>
|
186 |
-
))}
|
187 |
-
</div>
|
188 |
-
</label>
|
189 |
</div>
|
190 |
-
</
|
191 |
-
</
|
192 |
-
</
|
193 |
</div>
|
194 |
);
|
195 |
}
|
|
|
1 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2 |
import classNames from "classnames";
|
|
|
|
|
3 |
|
4 |
+
import { PiGearSixFill } from "react-icons/pi";
|
5 |
// @ts-expect-error not needed
|
6 |
+
import { PROVIDERS } from "./../../../utils/providers";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
function Settings({
|
9 |
open,
|
10 |
onClose,
|
11 |
provider,
|
|
|
12 |
error,
|
13 |
onChange,
|
|
|
14 |
}: {
|
15 |
open: boolean;
|
16 |
provider: string;
|
|
|
17 |
error?: string;
|
18 |
onClose: React.Dispatch<React.SetStateAction<boolean>>;
|
19 |
onChange: (provider: string) => void;
|
|
|
20 |
}) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
return (
|
22 |
<div className="">
|
23 |
+
<button
|
24 |
+
className="relative overflow-hidden cursor-pointer flex-none flex items-center justify-center rounded-full text-base font-semibold size-8 text-center bg-gray-800 hover:bg-gray-700 text-gray-100 shadow-sm dark:shadow-highlight/20"
|
25 |
+
onClick={() => {
|
26 |
+
onClose((prev) => !prev);
|
27 |
+
}}
|
28 |
+
>
|
29 |
+
<PiGearSixFill />
|
30 |
+
</button>
|
31 |
+
<div
|
32 |
+
className={classNames(
|
33 |
+
"h-screen w-screen bg-black/20 fixed left-0 top-0 z-40",
|
34 |
+
{
|
35 |
+
"opacity-0 pointer-events-none": !open,
|
36 |
+
}
|
37 |
+
)}
|
38 |
+
onClick={() => onClose(false)}
|
39 |
+
></div>
|
40 |
+
<div
|
41 |
+
className={classNames(
|
42 |
+
"absolute top-0 -translate-y-[calc(100%+16px)] right-0 z-40 w-96 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
|
43 |
+
{
|
44 |
+
"opacity-0 pointer-events-none": !open,
|
45 |
+
}
|
46 |
+
)}
|
47 |
+
>
|
48 |
+
<header className="flex items-center text-sm px-4 py-2 border-b border-gray-200 gap-2 bg-gray-100 font-semibold text-gray-700">
|
49 |
+
<span className="text-xs bg-blue-500/10 text-blue-500 rounded-full pl-1.5 pr-2.5 py-0.5 flex items-center justify-start gap-1.5">
|
50 |
+
Provider
|
51 |
+
</span>
|
52 |
+
Customize Settings
|
53 |
+
</header>
|
54 |
+
<main className="px-4 pt-3 pb-4 space-y-4">
|
55 |
+
{/* toggle using tailwind css */}
|
56 |
+
<div>
|
57 |
<a
|
58 |
href="https://huggingface.co/spaces/enzostvs/deepsite/discussions/74"
|
59 |
target="_blank"
|
60 |
+
className="w-full flex items-center justify-between text-gray-600 bg-gray-50 border border-gray-100 px-2 py-2 rounded-lg mb-3 text-sm font-medium hover:brightness-95"
|
61 |
>
|
62 |
How to use it locally?
|
63 |
+
<button className="bg-black text-white rounded-md px-3 py-1.5 text-xs font-semibold cursor-pointer">
|
64 |
+
See the guide
|
65 |
+
</button>
|
66 |
</a>
|
67 |
+
<div className="flex items-center justify-between">
|
68 |
+
<p className="text-gray-800 text-sm font-medium flex items-center justify-between">
|
69 |
+
Use auto-provider
|
70 |
</p>
|
71 |
+
<div
|
72 |
+
className={classNames(
|
73 |
+
"bg-gray-200 rounded-full w-10 h-6 flex items-center justify-between p-1 cursor-pointer transition-all duration-200",
|
74 |
+
{
|
75 |
+
"!bg-blue-500": provider === "auto",
|
76 |
+
}
|
77 |
+
)}
|
78 |
+
onClick={() => {
|
79 |
+
onChange(provider === "auto" ? "fireworks-ai" : "auto");
|
80 |
+
}}
|
81 |
+
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
<div
|
83 |
className={classNames(
|
84 |
+
"w-4 h-4 rounded-full shadow-md transition-all duration-200 bg-white",
|
85 |
{
|
86 |
+
"translate-x-4": provider === "auto",
|
87 |
}
|
88 |
)}
|
89 |
+
/>
|
90 |
+
</div>
|
91 |
+
</div>
|
92 |
+
<p className="text-xs text-gray-500 mt-2">
|
93 |
+
We'll automatically select the best provider for you based on your
|
94 |
+
prompt.
|
95 |
+
</p>
|
96 |
+
</div>
|
97 |
+
{error !== "" && (
|
98 |
+
<p className="text-red-500 text-sm font-medium mb-2 flex items-center justify-between bg-red-500/10 p-2 rounded-md">
|
99 |
+
{error}
|
100 |
+
</p>
|
101 |
+
)}
|
102 |
+
<label className="block">
|
103 |
+
<p className="text-gray-800 text-sm font-medium mb-2 flex items-center justify-between">
|
104 |
+
Inference Provider
|
105 |
+
</p>
|
106 |
+
<div className="grid grid-cols-2 gap-1.5">
|
107 |
+
{Object.keys(PROVIDERS).map((id: string) => (
|
108 |
+
<div
|
109 |
+
key={id}
|
110 |
+
className={classNames(
|
111 |
+
"text-gray-600 text-sm font-medium cursor-pointer border p-2 rounded-md flex items-center justify-start gap-2",
|
112 |
+
{
|
113 |
+
"bg-blue-500/10 border-blue-500/15 text-blue-500":
|
114 |
+
id === provider,
|
115 |
+
"hover:bg-gray-100 border-gray-100": id !== provider,
|
116 |
}
|
117 |
+
)}
|
118 |
+
onClick={() => {
|
119 |
+
onChange(id);
|
120 |
}}
|
121 |
>
|
122 |
+
<img
|
123 |
+
src={`/providers/${id}.svg`}
|
124 |
+
alt={PROVIDERS[id].name}
|
125 |
+
className="size-5"
|
|
|
|
|
|
|
126 |
/>
|
127 |
+
{PROVIDERS[id].name}
|
128 |
</div>
|
129 |
+
))}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
</div>
|
131 |
+
</label>
|
132 |
+
</main>
|
133 |
+
</div>
|
134 |
</div>
|
135 |
);
|
136 |
}
|
src/components/tabs/tabs.tsx
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useState } from "react";
|
2 |
+
import classNames from "classnames";
|
3 |
+
import { IoTimeOutline } from "react-icons/io5";
|
4 |
+
|
5 |
+
import Deepseek from "./../../assets/deepseek-color.svg";
|
6 |
+
|
7 |
+
function Tabs({
|
8 |
+
htmlHistory,
|
9 |
+
setHtml,
|
10 |
+
children,
|
11 |
+
}: {
|
12 |
+
htmlHistory?: { html: string; createdAt: Date; prompt: string }[];
|
13 |
+
setHtml: (html: string) => void;
|
14 |
+
children?: React.ReactNode;
|
15 |
+
}) {
|
16 |
+
const [visible, setVisible] = useState(false);
|
17 |
+
|
18 |
+
return (
|
19 |
+
<div className="border-b border-gray-800 pl-4 lg:pl-7 pr-3 flex items-center justify-between">
|
20 |
+
<div className="flex items-center justify-start gap-4 flex-1">
|
21 |
+
<div
|
22 |
+
className="
|
23 |
+
space-x-6"
|
24 |
+
>
|
25 |
+
<button className="rounded-md text-sm cursor-pointer transition-all duration-100 font-medium relative py-2.5 text-white">
|
26 |
+
index.html
|
27 |
+
<span className="absolute bottom-0 left-0 h-0.5 w-full transition-all duration-100 bg-white" />
|
28 |
+
</button>
|
29 |
+
</div>
|
30 |
+
{htmlHistory && htmlHistory?.length > 1 && (
|
31 |
+
<div
|
32 |
+
className="relative"
|
33 |
+
onMouseEnter={() => setVisible(true)}
|
34 |
+
onMouseLeave={() => setVisible(false)}
|
35 |
+
>
|
36 |
+
<button
|
37 |
+
className={classNames(
|
38 |
+
"text-gray-400 hover:text-gray-300 cursor-pointer text-sm nderline flex items-center justify-start gap-1",
|
39 |
+
{
|
40 |
+
"!text-gray-300": visible,
|
41 |
+
}
|
42 |
+
)}
|
43 |
+
>
|
44 |
+
<IoTimeOutline />
|
45 |
+
{htmlHistory?.length} versions
|
46 |
+
</button>
|
47 |
+
<div
|
48 |
+
className={classNames(
|
49 |
+
"absolute bottom-0 left-0 min-w-sm w-full z-10 translate-y-full pt-2 transition-all duration-200",
|
50 |
+
{
|
51 |
+
"opacity-0 pointer-events-none": !visible,
|
52 |
+
}
|
53 |
+
)}
|
54 |
+
>
|
55 |
+
<div className="bg-gray-950 border border-gray-800 rounded-xl shadow-2xs p-4">
|
56 |
+
<p className="text-xs font-bold text-white">Version History</p>
|
57 |
+
<p className="text-gray-400 text-xs mt-1">
|
58 |
+
This is a list of the full history of what AI has done to
|
59 |
+
this.
|
60 |
+
</p>
|
61 |
+
<ul className="mt-2 max-h-[250px] overflow-y-auto">
|
62 |
+
{htmlHistory?.map((item, index) => (
|
63 |
+
<li
|
64 |
+
key={index}
|
65 |
+
className="text-gray-300 text-xs py-2 border-b border-gray-800 last:border-0 flex items-center justify-between gap-2"
|
66 |
+
>
|
67 |
+
<div className="">
|
68 |
+
<span className="line-clamp-1">{item.prompt}</span>
|
69 |
+
<span className="text-gray-500 text-[10px]">
|
70 |
+
{new Date(item.createdAt).toLocaleDateString(
|
71 |
+
"en-US",
|
72 |
+
{
|
73 |
+
month: "2-digit",
|
74 |
+
day: "2-digit",
|
75 |
+
year: "2-digit",
|
76 |
+
}
|
77 |
+
) +
|
78 |
+
" " +
|
79 |
+
new Date(item.createdAt).toLocaleTimeString(
|
80 |
+
"en-US",
|
81 |
+
{
|
82 |
+
hour: "2-digit",
|
83 |
+
minute: "2-digit",
|
84 |
+
second: "2-digit",
|
85 |
+
hour12: false,
|
86 |
+
}
|
87 |
+
)}
|
88 |
+
</span>
|
89 |
+
</div>
|
90 |
+
<button
|
91 |
+
className="bg-pink-500 text-white text-xs font-medium rounded-md px-2 py-1 transition-all duration-100 hover:bg-pink-600 cursor-pointer"
|
92 |
+
onClick={() => {
|
93 |
+
setHtml(item.html);
|
94 |
+
}}
|
95 |
+
>
|
96 |
+
Select
|
97 |
+
</button>
|
98 |
+
</li>
|
99 |
+
))}
|
100 |
+
</ul>
|
101 |
+
</div>
|
102 |
+
</div>
|
103 |
+
</div>
|
104 |
+
)}
|
105 |
+
</div>
|
106 |
+
<div className="flex items-center justify-end gap-3">
|
107 |
+
<a
|
108 |
+
href="https://huggingface.co/deepseek-ai/DeepSeek-V3-0324"
|
109 |
+
target="_blank"
|
110 |
+
className="text-[12px] text-gray-300 hover:brightness-120 flex items-center gap-1 font-code"
|
111 |
+
>
|
112 |
+
Powered by <img src={Deepseek} className="size-5" /> Deepseek
|
113 |
+
</a>
|
114 |
+
{children}
|
115 |
+
</div>
|
116 |
+
</div>
|
117 |
+
);
|
118 |
+
}
|
119 |
+
|
120 |
+
export default Tabs;
|
src/components/theme/mode-toggle.tsx
DELETED
@@ -1,37 +0,0 @@
|
|
1 |
-
import { Moon, Sun } from "lucide-react";
|
2 |
-
|
3 |
-
import { Button } from "./../ui/button";
|
4 |
-
import {
|
5 |
-
DropdownMenu,
|
6 |
-
DropdownMenuContent,
|
7 |
-
DropdownMenuItem,
|
8 |
-
DropdownMenuTrigger,
|
9 |
-
} from "./../ui/dropdown-menu";
|
10 |
-
import { useTheme } from "./../theme/theme-provider";
|
11 |
-
|
12 |
-
export function ModeToggle() {
|
13 |
-
const { setTheme } = useTheme();
|
14 |
-
|
15 |
-
return (
|
16 |
-
<DropdownMenu>
|
17 |
-
<DropdownMenuTrigger asChild>
|
18 |
-
<Button variant="outline" size="icon">
|
19 |
-
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
20 |
-
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
21 |
-
<span className="sr-only">Toggle theme</span>
|
22 |
-
</Button>
|
23 |
-
</DropdownMenuTrigger>
|
24 |
-
<DropdownMenuContent align="end">
|
25 |
-
<DropdownMenuItem onClick={() => setTheme("light")}>
|
26 |
-
Light
|
27 |
-
</DropdownMenuItem>
|
28 |
-
<DropdownMenuItem onClick={() => setTheme("dark")}>
|
29 |
-
Dark
|
30 |
-
</DropdownMenuItem>
|
31 |
-
<DropdownMenuItem onClick={() => setTheme("system")}>
|
32 |
-
System
|
33 |
-
</DropdownMenuItem>
|
34 |
-
</DropdownMenuContent>
|
35 |
-
</DropdownMenu>
|
36 |
-
);
|
37 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/theme/theme-provider.tsx
DELETED
@@ -1,75 +0,0 @@
|
|
1 |
-
import { createContext, useContext, useEffect, useState } from "react";
|
2 |
-
|
3 |
-
type Theme = "dark" | "light" | "system";
|
4 |
-
|
5 |
-
type ThemeProviderProps = {
|
6 |
-
children: React.ReactNode;
|
7 |
-
defaultTheme?: Theme;
|
8 |
-
storageKey?: string;
|
9 |
-
className?: string;
|
10 |
-
};
|
11 |
-
|
12 |
-
type ThemeProviderState = {
|
13 |
-
theme: Theme;
|
14 |
-
setTheme: (theme: Theme) => void;
|
15 |
-
};
|
16 |
-
|
17 |
-
const initialState: ThemeProviderState = {
|
18 |
-
theme: "system",
|
19 |
-
setTheme: () => null,
|
20 |
-
};
|
21 |
-
|
22 |
-
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
|
23 |
-
|
24 |
-
export function ThemeProvider({
|
25 |
-
children,
|
26 |
-
defaultTheme = "system",
|
27 |
-
storageKey = "vite-ui-theme",
|
28 |
-
className,
|
29 |
-
...props
|
30 |
-
}: ThemeProviderProps) {
|
31 |
-
const [theme, setTheme] = useState<Theme>(
|
32 |
-
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
|
33 |
-
);
|
34 |
-
|
35 |
-
useEffect(() => {
|
36 |
-
const root = window.document.documentElement;
|
37 |
-
|
38 |
-
root.classList.remove("light", "dark");
|
39 |
-
|
40 |
-
if (theme === "system") {
|
41 |
-
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
42 |
-
.matches
|
43 |
-
? "dark"
|
44 |
-
: "light";
|
45 |
-
|
46 |
-
root.classList.add(systemTheme);
|
47 |
-
return;
|
48 |
-
}
|
49 |
-
|
50 |
-
root.classList.add(theme);
|
51 |
-
}, [theme]);
|
52 |
-
|
53 |
-
const value = {
|
54 |
-
theme,
|
55 |
-
setTheme: (theme: Theme) => {
|
56 |
-
localStorage.setItem(storageKey, theme);
|
57 |
-
setTheme(theme);
|
58 |
-
},
|
59 |
-
};
|
60 |
-
|
61 |
-
return (
|
62 |
-
<ThemeProviderContext.Provider {...props} value={value}>
|
63 |
-
<section className={className}>{children}</section>
|
64 |
-
</ThemeProviderContext.Provider>
|
65 |
-
);
|
66 |
-
}
|
67 |
-
|
68 |
-
export const useTheme = () => {
|
69 |
-
const context = useContext(ThemeProviderContext);
|
70 |
-
|
71 |
-
if (context === undefined)
|
72 |
-
throw new Error("useTheme must be used within a ThemeProvider");
|
73 |
-
|
74 |
-
return context;
|
75 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/avatar.tsx
DELETED
@@ -1,51 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
3 |
-
|
4 |
-
import { cn } from "./../../lib/utils";
|
5 |
-
|
6 |
-
function Avatar({
|
7 |
-
className,
|
8 |
-
...props
|
9 |
-
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
10 |
-
return (
|
11 |
-
<AvatarPrimitive.Root
|
12 |
-
data-slot="avatar"
|
13 |
-
className={cn(
|
14 |
-
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
15 |
-
className
|
16 |
-
)}
|
17 |
-
{...props}
|
18 |
-
/>
|
19 |
-
);
|
20 |
-
}
|
21 |
-
|
22 |
-
function AvatarImage({
|
23 |
-
className,
|
24 |
-
...props
|
25 |
-
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
26 |
-
return (
|
27 |
-
<AvatarPrimitive.Image
|
28 |
-
data-slot="avatar-image"
|
29 |
-
className={cn("aspect-square size-full", className)}
|
30 |
-
{...props}
|
31 |
-
/>
|
32 |
-
);
|
33 |
-
}
|
34 |
-
|
35 |
-
function AvatarFallback({
|
36 |
-
className,
|
37 |
-
...props
|
38 |
-
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
39 |
-
return (
|
40 |
-
<AvatarPrimitive.Fallback
|
41 |
-
data-slot="avatar-fallback"
|
42 |
-
className={cn(
|
43 |
-
"bg-neutral-100 flex size-full items-center justify-center rounded-full dark:bg-neutral-800",
|
44 |
-
className
|
45 |
-
)}
|
46 |
-
{...props}
|
47 |
-
/>
|
48 |
-
);
|
49 |
-
}
|
50 |
-
|
51 |
-
export { Avatar, AvatarImage, AvatarFallback };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/button.tsx
DELETED
@@ -1,64 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import { Slot } from "@radix-ui/react-slot";
|
3 |
-
import { cva, type VariantProps } from "class-variance-authority";
|
4 |
-
|
5 |
-
import { cn } from "./../../lib/utils";
|
6 |
-
|
7 |
-
const buttonVariants = cva(
|
8 |
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 cursor-pointer [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-neutral-950 focus-visible:ring-neutral-950/50 focus-visible:ring-[3px] aria-invalid:ring-red-500/20 dark:aria-invalid:ring-red-500/40 aria-invalid:border-red-500 dark:focus-visible:border-neutral-300 dark:focus-visible:ring-neutral-300/50 dark:aria-invalid:ring-red-900/20 dark:dark:aria-invalid:ring-red-900/40 dark:aria-invalid:border-red-900",
|
9 |
-
{
|
10 |
-
variants: {
|
11 |
-
variant: {
|
12 |
-
default:
|
13 |
-
"bg-neutral-900 text-neutral-50 shadow-xs hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90",
|
14 |
-
destructive: "bg-red-600 text-white shadow-xs hover:bg-red-500",
|
15 |
-
outline:
|
16 |
-
"border bg-white shadow-xs hover:bg-neutral-100 hover:text-neutral-900 dark:bg-neutral-200/30 dark:border-neutral-200 dark:hover:bg-neutral-200/50 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50 dark:dark:bg-neutral-800/30 dark:dark:border-neutral-800 dark:dark:hover:bg-neutral-800/50",
|
17 |
-
secondary:
|
18 |
-
"bg-neutral-100 text-neutral-900 shadow-xs hover:bg-neutral-100/80 dark:bg-neutral-800 dark:text-neutral-50 dark:hover:bg-neutral-800/80",
|
19 |
-
ghost:
|
20 |
-
"hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-100/50 dark:hover:bg-neutral-800 dark:hover:text-neutral-50 dark:dark:hover:bg-neutral-800/50",
|
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",
|
28 |
-
sm: "h-8 rounded-full text-[13px] gap-1.5 px-3",
|
29 |
-
lg: "h-10 rounded-full px-6 has-[>svg]:px-4",
|
30 |
-
icon: "size-9",
|
31 |
-
iconXs: "size-7",
|
32 |
-
iconXss: "size-6",
|
33 |
-
xs: "h-6 text-xs rounded-full pl-2 pr-2 gap-1",
|
34 |
-
},
|
35 |
-
},
|
36 |
-
defaultVariants: {
|
37 |
-
variant: "default",
|
38 |
-
size: "default",
|
39 |
-
},
|
40 |
-
}
|
41 |
-
);
|
42 |
-
|
43 |
-
function Button({
|
44 |
-
className,
|
45 |
-
variant,
|
46 |
-
size,
|
47 |
-
asChild = false,
|
48 |
-
...props
|
49 |
-
}: React.ComponentProps<"button"> &
|
50 |
-
VariantProps<typeof buttonVariants> & {
|
51 |
-
asChild?: boolean;
|
52 |
-
}) {
|
53 |
-
const Comp = asChild ? Slot : "button";
|
54 |
-
|
55 |
-
return (
|
56 |
-
<Comp
|
57 |
-
data-slot="button"
|
58 |
-
className={cn(buttonVariants({ variant, size, className }))}
|
59 |
-
{...props}
|
60 |
-
/>
|
61 |
-
);
|
62 |
-
}
|
63 |
-
|
64 |
-
export { Button, buttonVariants };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/dialog.tsx
DELETED
@@ -1,144 +0,0 @@
|
|
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 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/dropdown-menu.tsx
DELETED
@@ -1,258 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
3 |
-
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
4 |
-
|
5 |
-
import { cn } from "./../../lib/utils";
|
6 |
-
|
7 |
-
function DropdownMenu({
|
8 |
-
...props
|
9 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
10 |
-
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
11 |
-
}
|
12 |
-
|
13 |
-
function DropdownMenuPortal({
|
14 |
-
...props
|
15 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
16 |
-
return (
|
17 |
-
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
18 |
-
);
|
19 |
-
}
|
20 |
-
|
21 |
-
function DropdownMenuTrigger({
|
22 |
-
...props
|
23 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
24 |
-
return (
|
25 |
-
<DropdownMenuPrimitive.Trigger
|
26 |
-
data-slot="dropdown-menu-trigger"
|
27 |
-
{...props}
|
28 |
-
/>
|
29 |
-
);
|
30 |
-
}
|
31 |
-
|
32 |
-
function DropdownMenuContent({
|
33 |
-
className,
|
34 |
-
sideOffset = 4,
|
35 |
-
...props
|
36 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
37 |
-
return (
|
38 |
-
<DropdownMenuPrimitive.Portal>
|
39 |
-
<DropdownMenuPrimitive.Content
|
40 |
-
data-slot="dropdown-menu-content"
|
41 |
-
sideOffset={sideOffset}
|
42 |
-
className={cn(
|
43 |
-
"bg-white text-neutral-950 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-neutral-200 p-1 shadow-md dark:bg-neutral-950 dark:text-neutral-50 dark:border-neutral-800",
|
44 |
-
className
|
45 |
-
)}
|
46 |
-
{...props}
|
47 |
-
/>
|
48 |
-
</DropdownMenuPrimitive.Portal>
|
49 |
-
);
|
50 |
-
}
|
51 |
-
|
52 |
-
function DropdownMenuGroup({
|
53 |
-
...props
|
54 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
55 |
-
return (
|
56 |
-
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
57 |
-
);
|
58 |
-
}
|
59 |
-
|
60 |
-
function DropdownMenuItem({
|
61 |
-
className,
|
62 |
-
inset,
|
63 |
-
variant = "default",
|
64 |
-
...props
|
65 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
66 |
-
inset?: boolean;
|
67 |
-
variant?: "default" | "destructive";
|
68 |
-
}) {
|
69 |
-
return (
|
70 |
-
<DropdownMenuPrimitive.Item
|
71 |
-
data-slot="dropdown-menu-item"
|
72 |
-
data-inset={inset}
|
73 |
-
data-variant={variant}
|
74 |
-
className={cn(
|
75 |
-
"focus:bg-neutral-100 cursor-pointer focus:text-neutral-900 data-[variant=destructive]:text-red-500 data-[variant=destructive]:focus:bg-red-500/10 dark:data-[variant=destructive]:focus:bg-red-500/20 data-[variant=destructive]:focus:text-red-500 data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-neutral-500 relative flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:focus:bg-neutral-800 dark:focus:text-neutral-50 dark:data-[variant=destructive]:text-red-900 dark:data-[variant=destructive]:focus:bg-red-900/10 dark:dark:data-[variant=destructive]:focus:bg-red-900/20 dark:data-[variant=destructive]:focus:text-red-900 dark:[&_svg:not([class*='text-'])]:text-neutral-400",
|
76 |
-
className
|
77 |
-
)}
|
78 |
-
{...props}
|
79 |
-
/>
|
80 |
-
);
|
81 |
-
}
|
82 |
-
|
83 |
-
function DropdownMenuCheckboxItem({
|
84 |
-
className,
|
85 |
-
children,
|
86 |
-
checked,
|
87 |
-
...props
|
88 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
89 |
-
return (
|
90 |
-
<DropdownMenuPrimitive.CheckboxItem
|
91 |
-
data-slot="dropdown-menu-checkbox-item"
|
92 |
-
className={cn(
|
93 |
-
"focus:bg-neutral-100 focus:text-neutral-900 relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
|
94 |
-
className
|
95 |
-
)}
|
96 |
-
checked={checked}
|
97 |
-
{...props}
|
98 |
-
>
|
99 |
-
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
100 |
-
<DropdownMenuPrimitive.ItemIndicator>
|
101 |
-
<CheckIcon className="size-4" />
|
102 |
-
</DropdownMenuPrimitive.ItemIndicator>
|
103 |
-
</span>
|
104 |
-
{children}
|
105 |
-
</DropdownMenuPrimitive.CheckboxItem>
|
106 |
-
);
|
107 |
-
}
|
108 |
-
|
109 |
-
function DropdownMenuRadioGroup({
|
110 |
-
...props
|
111 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
112 |
-
return (
|
113 |
-
<DropdownMenuPrimitive.RadioGroup
|
114 |
-
data-slot="dropdown-menu-radio-group"
|
115 |
-
{...props}
|
116 |
-
/>
|
117 |
-
);
|
118 |
-
}
|
119 |
-
|
120 |
-
function DropdownMenuRadioItem({
|
121 |
-
className,
|
122 |
-
children,
|
123 |
-
...props
|
124 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
125 |
-
return (
|
126 |
-
<DropdownMenuPrimitive.RadioItem
|
127 |
-
data-slot="dropdown-menu-radio-item"
|
128 |
-
className={cn(
|
129 |
-
"focus:bg-neutral-100 focus:text-neutral-900 relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
|
130 |
-
className
|
131 |
-
)}
|
132 |
-
{...props}
|
133 |
-
>
|
134 |
-
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
135 |
-
<DropdownMenuPrimitive.ItemIndicator>
|
136 |
-
<CircleIcon className="size-2 fill-current" />
|
137 |
-
</DropdownMenuPrimitive.ItemIndicator>
|
138 |
-
</span>
|
139 |
-
{children}
|
140 |
-
</DropdownMenuPrimitive.RadioItem>
|
141 |
-
);
|
142 |
-
}
|
143 |
-
|
144 |
-
function DropdownMenuLabel({
|
145 |
-
className,
|
146 |
-
inset,
|
147 |
-
...props
|
148 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
149 |
-
inset?: boolean;
|
150 |
-
}) {
|
151 |
-
return (
|
152 |
-
<DropdownMenuPrimitive.Label
|
153 |
-
data-slot="dropdown-menu-label"
|
154 |
-
data-inset={inset}
|
155 |
-
className={cn(
|
156 |
-
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
157 |
-
className
|
158 |
-
)}
|
159 |
-
{...props}
|
160 |
-
/>
|
161 |
-
);
|
162 |
-
}
|
163 |
-
|
164 |
-
function DropdownMenuSeparator({
|
165 |
-
className,
|
166 |
-
...props
|
167 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
168 |
-
return (
|
169 |
-
<DropdownMenuPrimitive.Separator
|
170 |
-
data-slot="dropdown-menu-separator"
|
171 |
-
className={cn(
|
172 |
-
"bg-neutral-200 -mx-1 my-1 h-px dark:bg-neutral-800",
|
173 |
-
className
|
174 |
-
)}
|
175 |
-
{...props}
|
176 |
-
/>
|
177 |
-
);
|
178 |
-
}
|
179 |
-
|
180 |
-
function DropdownMenuShortcut({
|
181 |
-
className,
|
182 |
-
...props
|
183 |
-
}: React.ComponentProps<"span">) {
|
184 |
-
return (
|
185 |
-
<span
|
186 |
-
data-slot="dropdown-menu-shortcut"
|
187 |
-
className={cn(
|
188 |
-
"text-neutral-500 ml-auto text-xs tracking-widest dark:text-neutral-400",
|
189 |
-
className
|
190 |
-
)}
|
191 |
-
{...props}
|
192 |
-
/>
|
193 |
-
);
|
194 |
-
}
|
195 |
-
|
196 |
-
function DropdownMenuSub({
|
197 |
-
...props
|
198 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
199 |
-
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
200 |
-
}
|
201 |
-
|
202 |
-
function DropdownMenuSubTrigger({
|
203 |
-
className,
|
204 |
-
inset,
|
205 |
-
children,
|
206 |
-
...props
|
207 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
208 |
-
inset?: boolean;
|
209 |
-
}) {
|
210 |
-
return (
|
211 |
-
<DropdownMenuPrimitive.SubTrigger
|
212 |
-
data-slot="dropdown-menu-sub-trigger"
|
213 |
-
data-inset={inset}
|
214 |
-
className={cn(
|
215 |
-
"focus:bg-neutral-100 focus:text-neutral-900 data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-900 flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 dark:focus:bg-neutral-800 dark:focus:text-neutral-50 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-50",
|
216 |
-
className
|
217 |
-
)}
|
218 |
-
{...props}
|
219 |
-
>
|
220 |
-
{children}
|
221 |
-
<ChevronRightIcon className="ml-auto size-4" />
|
222 |
-
</DropdownMenuPrimitive.SubTrigger>
|
223 |
-
);
|
224 |
-
}
|
225 |
-
|
226 |
-
function DropdownMenuSubContent({
|
227 |
-
className,
|
228 |
-
...props
|
229 |
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
230 |
-
return (
|
231 |
-
<DropdownMenuPrimitive.SubContent
|
232 |
-
data-slot="dropdown-menu-sub-content"
|
233 |
-
className={cn(
|
234 |
-
"bg-white text-neutral-950 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border border-neutral-200 p-1 shadow-lg dark:bg-neutral-950 dark:text-neutral-50 dark:border-neutral-800",
|
235 |
-
className
|
236 |
-
)}
|
237 |
-
{...props}
|
238 |
-
/>
|
239 |
-
);
|
240 |
-
}
|
241 |
-
|
242 |
-
export {
|
243 |
-
DropdownMenu,
|
244 |
-
DropdownMenuPortal,
|
245 |
-
DropdownMenuTrigger,
|
246 |
-
DropdownMenuContent,
|
247 |
-
DropdownMenuGroup,
|
248 |
-
DropdownMenuLabel,
|
249 |
-
DropdownMenuItem,
|
250 |
-
DropdownMenuCheckboxItem,
|
251 |
-
DropdownMenuRadioGroup,
|
252 |
-
DropdownMenuRadioItem,
|
253 |
-
DropdownMenuSeparator,
|
254 |
-
DropdownMenuShortcut,
|
255 |
-
DropdownMenuSub,
|
256 |
-
DropdownMenuSubTrigger,
|
257 |
-
DropdownMenuSubContent,
|
258 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/input.tsx
DELETED
@@ -1,21 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
|
3 |
-
import { cn } from "./../../lib/utils";
|
4 |
-
|
5 |
-
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
6 |
-
return (
|
7 |
-
<input
|
8 |
-
type={type}
|
9 |
-
data-slot="input"
|
10 |
-
className={cn(
|
11 |
-
"file:text-neutral-950 placeholder:text-neutral-500 selection:bg-neutral-900 selection:text-neutral-50 dark:bg-neutral-200/30 border-neutral-200 flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:file:text-neutral-50 dark:placeholder:text-neutral-400 dark:selection:bg-neutral-50 dark:selection:text-neutral-900 dark:dark:bg-neutral-800/30 dark:border-neutral-800",
|
12 |
-
"focus-visible:border-neutral-950 focus-visible:ring-neutral-950/50 focus-visible:ring-[3px] dark:focus-visible:border-neutral-300 dark:focus-visible:ring-neutral-300/50",
|
13 |
-
"aria-invalid:ring-red-500/20 dark:aria-invalid:ring-red-500/40 aria-invalid:border-red-500 dark:aria-invalid:ring-red-900/20 dark:dark:aria-invalid:ring-red-900/40 dark:aria-invalid:border-red-900",
|
14 |
-
className
|
15 |
-
)}
|
16 |
-
{...props}
|
17 |
-
/>
|
18 |
-
);
|
19 |
-
}
|
20 |
-
|
21 |
-
export { Input };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/popover.tsx
DELETED
@@ -1,46 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
3 |
-
|
4 |
-
import { cn } from "./../../lib/utils";
|
5 |
-
|
6 |
-
function Popover({
|
7 |
-
...props
|
8 |
-
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
9 |
-
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
|
10 |
-
}
|
11 |
-
|
12 |
-
function PopoverTrigger({
|
13 |
-
...props
|
14 |
-
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
15 |
-
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
|
16 |
-
}
|
17 |
-
|
18 |
-
function PopoverContent({
|
19 |
-
className,
|
20 |
-
align = "center",
|
21 |
-
sideOffset = 4,
|
22 |
-
...props
|
23 |
-
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
24 |
-
return (
|
25 |
-
<PopoverPrimitive.Portal>
|
26 |
-
<PopoverPrimitive.Content
|
27 |
-
data-slot="popover-content"
|
28 |
-
align={align}
|
29 |
-
sideOffset={sideOffset}
|
30 |
-
className={cn(
|
31 |
-
"bg-white text-neutral-950 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border border-neutral-200 p-4 shadow-md outline-hidden dark:bg-neutral-950 dark:text-neutral-50 dark:border-neutral-800",
|
32 |
-
className
|
33 |
-
)}
|
34 |
-
{...props}
|
35 |
-
/>
|
36 |
-
</PopoverPrimitive.Portal>
|
37 |
-
);
|
38 |
-
}
|
39 |
-
|
40 |
-
function PopoverAnchor({
|
41 |
-
...props
|
42 |
-
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
43 |
-
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
|
44 |
-
}
|
45 |
-
|
46 |
-
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/select.tsx
DELETED
@@ -1,189 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as SelectPrimitive from "@radix-ui/react-select";
|
3 |
-
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
4 |
-
|
5 |
-
import { cn } from "./../../lib/utils";
|
6 |
-
|
7 |
-
function Select({
|
8 |
-
...props
|
9 |
-
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
10 |
-
return <SelectPrimitive.Root data-slot="select" {...props} />;
|
11 |
-
}
|
12 |
-
|
13 |
-
function SelectGroup({
|
14 |
-
...props
|
15 |
-
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
16 |
-
return <SelectPrimitive.Group data-slot="select-group" {...props} />;
|
17 |
-
}
|
18 |
-
|
19 |
-
function SelectValue({
|
20 |
-
...props
|
21 |
-
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
22 |
-
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
|
23 |
-
}
|
24 |
-
|
25 |
-
function SelectTrigger({
|
26 |
-
className,
|
27 |
-
size = "default",
|
28 |
-
children,
|
29 |
-
...props
|
30 |
-
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
31 |
-
size?: "sm" | "default";
|
32 |
-
}) {
|
33 |
-
return (
|
34 |
-
<SelectPrimitive.Trigger
|
35 |
-
data-slot="select-trigger"
|
36 |
-
data-size={size}
|
37 |
-
className={cn(
|
38 |
-
"border-neutral-200 data-[placeholder]:text-neutral-500 [&_svg:not([class*='text-'])]:text-neutral-500 focus-visible:border-neutral-950 focus-visible:ring-neutral-950/50 aria-invalid:ring-red-500/20 dark:aria-invalid:ring-red-500/40 aria-invalid:border-red-500 dark:bg-neutral-200/30 dark:hover:bg-neutral-200/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:border-neutral-800 dark:data-[placeholder]:text-neutral-400 dark:[&_svg:not([class*='text-'])]:text-neutral-400 dark:focus-visible:border-neutral-300 dark:focus-visible:ring-neutral-300/50 dark:aria-invalid:ring-red-900/20 dark:dark:aria-invalid:ring-red-900/40 dark:aria-invalid:border-red-900 dark:dark:bg-neutral-800/30 dark:dark:hover:bg-neutral-800/50",
|
39 |
-
className
|
40 |
-
)}
|
41 |
-
{...props}
|
42 |
-
>
|
43 |
-
{children}
|
44 |
-
<SelectPrimitive.Icon asChild>
|
45 |
-
<ChevronDownIcon className="size-4 opacity-50" />
|
46 |
-
</SelectPrimitive.Icon>
|
47 |
-
</SelectPrimitive.Trigger>
|
48 |
-
);
|
49 |
-
}
|
50 |
-
|
51 |
-
function SelectContent({
|
52 |
-
className,
|
53 |
-
children,
|
54 |
-
position = "popper",
|
55 |
-
...props
|
56 |
-
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
57 |
-
return (
|
58 |
-
<SelectPrimitive.Portal>
|
59 |
-
<SelectPrimitive.Content
|
60 |
-
data-slot="select-content"
|
61 |
-
className={cn(
|
62 |
-
"bg-white text-neutral-950 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-neutral-200 shadow-md dark:bg-neutral-950 dark:text-neutral-50 dark:border-neutral-800",
|
63 |
-
position === "popper" &&
|
64 |
-
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
65 |
-
className
|
66 |
-
)}
|
67 |
-
position={position}
|
68 |
-
{...props}
|
69 |
-
>
|
70 |
-
<SelectScrollUpButton />
|
71 |
-
<SelectPrimitive.Viewport
|
72 |
-
className={cn(
|
73 |
-
"p-1",
|
74 |
-
position === "popper" &&
|
75 |
-
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
76 |
-
)}
|
77 |
-
>
|
78 |
-
{children}
|
79 |
-
</SelectPrimitive.Viewport>
|
80 |
-
<SelectScrollDownButton />
|
81 |
-
</SelectPrimitive.Content>
|
82 |
-
</SelectPrimitive.Portal>
|
83 |
-
);
|
84 |
-
}
|
85 |
-
|
86 |
-
function SelectLabel({
|
87 |
-
className,
|
88 |
-
...props
|
89 |
-
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
90 |
-
return (
|
91 |
-
<SelectPrimitive.Label
|
92 |
-
data-slot="select-label"
|
93 |
-
className={cn(
|
94 |
-
"text-neutral-500 px-2 py-1.5 text-xs dark:text-neutral-400",
|
95 |
-
className
|
96 |
-
)}
|
97 |
-
{...props}
|
98 |
-
/>
|
99 |
-
);
|
100 |
-
}
|
101 |
-
|
102 |
-
function SelectItem({
|
103 |
-
className,
|
104 |
-
children,
|
105 |
-
...props
|
106 |
-
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
107 |
-
return (
|
108 |
-
<SelectPrimitive.Item
|
109 |
-
data-slot="select-item"
|
110 |
-
className={cn(
|
111 |
-
"focus:bg-neutral-100 focus:text-neutral-900 [&_svg:not([class*='text-'])]:text-neutral-500 relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 dark:focus:bg-neutral-800 dark:focus:text-neutral-50 dark:[&_svg:not([class*='text-'])]:text-neutral-400",
|
112 |
-
className
|
113 |
-
)}
|
114 |
-
{...props}
|
115 |
-
>
|
116 |
-
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
117 |
-
<SelectPrimitive.ItemIndicator>
|
118 |
-
<CheckIcon className="size-4" />
|
119 |
-
</SelectPrimitive.ItemIndicator>
|
120 |
-
</span>
|
121 |
-
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
122 |
-
</SelectPrimitive.Item>
|
123 |
-
);
|
124 |
-
}
|
125 |
-
|
126 |
-
function SelectSeparator({
|
127 |
-
className,
|
128 |
-
...props
|
129 |
-
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
130 |
-
return (
|
131 |
-
<SelectPrimitive.Separator
|
132 |
-
data-slot="select-separator"
|
133 |
-
className={cn(
|
134 |
-
"bg-neutral-200 pointer-events-none -mx-1 my-1 h-px dark:bg-neutral-800",
|
135 |
-
className
|
136 |
-
)}
|
137 |
-
{...props}
|
138 |
-
/>
|
139 |
-
);
|
140 |
-
}
|
141 |
-
|
142 |
-
function SelectScrollUpButton({
|
143 |
-
className,
|
144 |
-
...props
|
145 |
-
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
146 |
-
return (
|
147 |
-
<SelectPrimitive.ScrollUpButton
|
148 |
-
data-slot="select-scroll-up-button"
|
149 |
-
className={cn(
|
150 |
-
"flex cursor-default items-center justify-center py-1",
|
151 |
-
className
|
152 |
-
)}
|
153 |
-
{...props}
|
154 |
-
>
|
155 |
-
<ChevronUpIcon className="size-4" />
|
156 |
-
</SelectPrimitive.ScrollUpButton>
|
157 |
-
);
|
158 |
-
}
|
159 |
-
|
160 |
-
function SelectScrollDownButton({
|
161 |
-
className,
|
162 |
-
...props
|
163 |
-
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
164 |
-
return (
|
165 |
-
<SelectPrimitive.ScrollDownButton
|
166 |
-
data-slot="select-scroll-down-button"
|
167 |
-
className={cn(
|
168 |
-
"flex cursor-default items-center justify-center py-1",
|
169 |
-
className
|
170 |
-
)}
|
171 |
-
{...props}
|
172 |
-
>
|
173 |
-
<ChevronDownIcon className="size-4" />
|
174 |
-
</SelectPrimitive.ScrollDownButton>
|
175 |
-
);
|
176 |
-
}
|
177 |
-
|
178 |
-
export {
|
179 |
-
Select,
|
180 |
-
SelectContent,
|
181 |
-
SelectGroup,
|
182 |
-
SelectItem,
|
183 |
-
SelectLabel,
|
184 |
-
SelectScrollDownButton,
|
185 |
-
SelectScrollUpButton,
|
186 |
-
SelectSeparator,
|
187 |
-
SelectTrigger,
|
188 |
-
SelectValue,
|
189 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/sonner.tsx
DELETED
@@ -1,23 +0,0 @@
|
|
1 |
-
import { useTheme } from "next-themes"
|
2 |
-
import { Toaster as Sonner, ToasterProps } from "sonner"
|
3 |
-
|
4 |
-
const Toaster = ({ ...props }: ToasterProps) => {
|
5 |
-
const { theme = "system" } = useTheme()
|
6 |
-
|
7 |
-
return (
|
8 |
-
<Sonner
|
9 |
-
theme={theme as ToasterProps["theme"]}
|
10 |
-
className="toaster group"
|
11 |
-
style={
|
12 |
-
{
|
13 |
-
"--normal-bg": "var(--popover)",
|
14 |
-
"--normal-text": "var(--popover-foreground)",
|
15 |
-
"--normal-border": "var(--border)",
|
16 |
-
} as React.CSSProperties
|
17 |
-
}
|
18 |
-
{...props}
|
19 |
-
/>
|
20 |
-
)
|
21 |
-
}
|
22 |
-
|
23 |
-
export { Toaster }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/tabs.tsx
DELETED
@@ -1,64 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
3 |
-
|
4 |
-
import { cn } from "./../../lib/utils";
|
5 |
-
|
6 |
-
function Tabs({
|
7 |
-
className,
|
8 |
-
...props
|
9 |
-
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
10 |
-
return (
|
11 |
-
<TabsPrimitive.Root
|
12 |
-
data-slot="tabs"
|
13 |
-
className={cn("flex flex-col gap-2", className)}
|
14 |
-
{...props}
|
15 |
-
/>
|
16 |
-
);
|
17 |
-
}
|
18 |
-
|
19 |
-
function TabsList({
|
20 |
-
className,
|
21 |
-
...props
|
22 |
-
}: React.ComponentProps<typeof TabsPrimitive.List>) {
|
23 |
-
return (
|
24 |
-
<TabsPrimitive.List
|
25 |
-
data-slot="tabs-list"
|
26 |
-
className={cn(
|
27 |
-
"bg-neutral-100 text-neutral-500 inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px] dark:bg-neutral-800 dark:text-neutral-400",
|
28 |
-
className
|
29 |
-
)}
|
30 |
-
{...props}
|
31 |
-
/>
|
32 |
-
);
|
33 |
-
}
|
34 |
-
|
35 |
-
function TabsTrigger({
|
36 |
-
className,
|
37 |
-
...props
|
38 |
-
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
39 |
-
return (
|
40 |
-
<TabsPrimitive.Trigger
|
41 |
-
data-slot="tabs-trigger"
|
42 |
-
className={cn(
|
43 |
-
"data-[state=active]:bg-white dark:data-[state=active]:text-neutral-950 focus-visible:border-neutral-950 focus-visible:ring-neutral-950/50 focus-visible:outline-ring dark:data-[state=active]:border-neutral-200 dark:data-[state=active]:bg-neutral-200/30 text-neutral-950 dark:text-neutral-500 inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-neutral-200 border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:data-[state=active]:bg-neutral-950 dark:dark:data-[state=active]:text-neutral-50 dark:focus-visible:border-neutral-300 dark:focus-visible:ring-neutral-300/50 dark:dark:data-[state=active]:border-neutral-800 dark:dark:data-[state=active]:bg-neutral-800/30 dark:text-neutral-50 dark:dark:text-neutral-400 dark:border-neutral-800",
|
44 |
-
className
|
45 |
-
)}
|
46 |
-
{...props}
|
47 |
-
/>
|
48 |
-
);
|
49 |
-
}
|
50 |
-
|
51 |
-
function TabsContent({
|
52 |
-
className,
|
53 |
-
...props
|
54 |
-
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
55 |
-
return (
|
56 |
-
<TabsPrimitive.Content
|
57 |
-
data-slot="tabs-content"
|
58 |
-
className={cn("flex-1 outline-none", className)}
|
59 |
-
{...props}
|
60 |
-
/>
|
61 |
-
);
|
62 |
-
}
|
63 |
-
|
64 |
-
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/toggle-group.tsx
DELETED
@@ -1,71 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
|
3 |
-
import { type VariantProps } from "class-variance-authority";
|
4 |
-
|
5 |
-
import { cn } from "./../../lib/utils";
|
6 |
-
import { toggleVariants } from "./../ui/toggle";
|
7 |
-
|
8 |
-
const ToggleGroupContext = React.createContext<
|
9 |
-
VariantProps<typeof toggleVariants>
|
10 |
-
>({
|
11 |
-
size: "default",
|
12 |
-
variant: "default",
|
13 |
-
});
|
14 |
-
|
15 |
-
function ToggleGroup({
|
16 |
-
className,
|
17 |
-
variant,
|
18 |
-
size,
|
19 |
-
children,
|
20 |
-
...props
|
21 |
-
}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
|
22 |
-
VariantProps<typeof toggleVariants>) {
|
23 |
-
return (
|
24 |
-
<ToggleGroupPrimitive.Root
|
25 |
-
data-slot="toggle-group"
|
26 |
-
data-variant={variant}
|
27 |
-
data-size={size}
|
28 |
-
className={cn(
|
29 |
-
"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
|
30 |
-
className
|
31 |
-
)}
|
32 |
-
{...props}
|
33 |
-
>
|
34 |
-
<ToggleGroupContext.Provider value={{ variant, size }}>
|
35 |
-
{children}
|
36 |
-
</ToggleGroupContext.Provider>
|
37 |
-
</ToggleGroupPrimitive.Root>
|
38 |
-
);
|
39 |
-
}
|
40 |
-
|
41 |
-
function ToggleGroupItem({
|
42 |
-
className,
|
43 |
-
children,
|
44 |
-
variant,
|
45 |
-
size,
|
46 |
-
...props
|
47 |
-
}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
|
48 |
-
VariantProps<typeof toggleVariants>) {
|
49 |
-
const context = React.useContext(ToggleGroupContext);
|
50 |
-
|
51 |
-
return (
|
52 |
-
<ToggleGroupPrimitive.Item
|
53 |
-
data-slot="toggle-group-item"
|
54 |
-
data-variant={context.variant || variant}
|
55 |
-
data-size={context.size || size}
|
56 |
-
className={cn(
|
57 |
-
toggleVariants({
|
58 |
-
variant: context.variant || variant,
|
59 |
-
size: context.size || size,
|
60 |
-
}),
|
61 |
-
"min-w-0 !pl-3 flex-1 cursor-pointer shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
|
62 |
-
className
|
63 |
-
)}
|
64 |
-
{...props}
|
65 |
-
>
|
66 |
-
{children}
|
67 |
-
</ToggleGroupPrimitive.Item>
|
68 |
-
);
|
69 |
-
}
|
70 |
-
|
71 |
-
export { ToggleGroup, ToggleGroupItem };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/toggle.tsx
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
"use client";
|
2 |
-
|
3 |
-
import * as React from "react";
|
4 |
-
import * as TogglePrimitive from "@radix-ui/react-toggle";
|
5 |
-
import { cva, type VariantProps } from "class-variance-authority";
|
6 |
-
|
7 |
-
import { cn } from "./../../lib/utils";
|
8 |
-
|
9 |
-
const toggleVariants = cva(
|
10 |
-
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-neutral-100 hover:text-neutral-500 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-neutral-100 data-[state=on]:text-neutral-900 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-neutral-950 focus-visible:ring-neutral-950/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-red-500/20 dark:aria-invalid:ring-red-500/40 aria-invalid:border-red-500 whitespace-nowrap dark:hover:bg-neutral-800 dark:hover:text-neutral-400 dark:data-[state=on]:bg-neutral-800 dark:data-[state=on]:text-neutral-50 dark:focus-visible:border-neutral-300 dark:focus-visible:ring-neutral-300/50 dark:aria-invalid:ring-red-900/20 dark:dark:aria-invalid:ring-red-900/40 dark:aria-invalid:border-red-900",
|
11 |
-
{
|
12 |
-
variants: {
|
13 |
-
variant: {
|
14 |
-
default: "bg-transparent",
|
15 |
-
outline:
|
16 |
-
"border border-neutral-200 bg-transparent shadow-xs hover:bg-neutral-100 hover:text-neutral-900 dark:border-neutral-800 dark:hover:bg-neutral-800 dark:hover:text-neutral-50",
|
17 |
-
},
|
18 |
-
size: {
|
19 |
-
default: "h-9 px-2 min-w-9",
|
20 |
-
sm: "h-8 px-1.5 min-w-8",
|
21 |
-
lg: "h-10 px-2.5 min-w-10",
|
22 |
-
},
|
23 |
-
},
|
24 |
-
defaultVariants: {
|
25 |
-
variant: "default",
|
26 |
-
size: "default",
|
27 |
-
},
|
28 |
-
}
|
29 |
-
);
|
30 |
-
|
31 |
-
function Toggle({
|
32 |
-
className,
|
33 |
-
variant,
|
34 |
-
size,
|
35 |
-
...props
|
36 |
-
}: React.ComponentProps<typeof TogglePrimitive.Root> &
|
37 |
-
VariantProps<typeof toggleVariants>) {
|
38 |
-
return (
|
39 |
-
<TogglePrimitive.Root
|
40 |
-
data-slot="toggle"
|
41 |
-
className={cn(toggleVariants({ variant, size, className }))}
|
42 |
-
{...props}
|
43 |
-
/>
|
44 |
-
);
|
45 |
-
}
|
46 |
-
|
47 |
-
export { Toggle, toggleVariants };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/tooltip.tsx
DELETED
@@ -1,59 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
3 |
-
|
4 |
-
import { cn } from "./../../lib/utils";
|
5 |
-
|
6 |
-
function TooltipProvider({
|
7 |
-
delayDuration = 0,
|
8 |
-
...props
|
9 |
-
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
10 |
-
return (
|
11 |
-
<TooltipPrimitive.Provider
|
12 |
-
data-slot="tooltip-provider"
|
13 |
-
delayDuration={delayDuration}
|
14 |
-
{...props}
|
15 |
-
/>
|
16 |
-
);
|
17 |
-
}
|
18 |
-
|
19 |
-
function Tooltip({
|
20 |
-
...props
|
21 |
-
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
22 |
-
return (
|
23 |
-
<TooltipProvider>
|
24 |
-
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
25 |
-
</TooltipProvider>
|
26 |
-
);
|
27 |
-
}
|
28 |
-
|
29 |
-
function TooltipTrigger({
|
30 |
-
...props
|
31 |
-
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
32 |
-
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
33 |
-
}
|
34 |
-
|
35 |
-
function TooltipContent({
|
36 |
-
className,
|
37 |
-
sideOffset = 0,
|
38 |
-
children,
|
39 |
-
...props
|
40 |
-
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
41 |
-
return (
|
42 |
-
<TooltipPrimitive.Portal>
|
43 |
-
<TooltipPrimitive.Content
|
44 |
-
data-slot="tooltip-content"
|
45 |
-
sideOffset={sideOffset}
|
46 |
-
className={cn(
|
47 |
-
"bg-black text-neutral-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
48 |
-
className
|
49 |
-
)}
|
50 |
-
{...props}
|
51 |
-
>
|
52 |
-
{children}
|
53 |
-
<TooltipPrimitive.Arrow className="bg-black fill-black z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
54 |
-
</TooltipPrimitive.Content>
|
55 |
-
</TooltipPrimitive.Portal>
|
56 |
-
);
|
57 |
-
}
|
58 |
-
|
59 |
-
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/utils.ts
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
import { clsx, type ClassValue } from "clsx"
|
2 |
-
import { twMerge } from "tailwind-merge"
|
3 |
-
|
4 |
-
export function cn(...inputs: ClassValue[]) {
|
5 |
-
return twMerge(clsx(inputs))
|
6 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/main.tsx
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
import { StrictMode } from "react";
|
2 |
import { createRoot } from "react-dom/client";
|
|
|
3 |
import "./assets/index.css";
|
4 |
-
import App from "./
|
5 |
|
6 |
createRoot(document.getElementById("root")!).render(
|
7 |
<StrictMode>
|
8 |
<App />
|
|
|
9 |
</StrictMode>
|
10 |
);
|
|
|
1 |
import { StrictMode } from "react";
|
2 |
import { createRoot } from "react-dom/client";
|
3 |
+
import { ToastContainer } from "react-toastify";
|
4 |
import "./assets/index.css";
|
5 |
+
import App from "./components/App.tsx";
|
6 |
|
7 |
createRoot(document.getElementById("root")!).render(
|
8 |
<StrictMode>
|
9 |
<App />
|
10 |
+
<ToastContainer className="pt-11 max-md:p-4" />
|
11 |
</StrictMode>
|
12 |
);
|
tsconfig.app.json
CHANGED
@@ -6,7 +6,6 @@
|
|
6 |
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
7 |
"module": "ESNext",
|
8 |
"skipLibCheck": true,
|
9 |
-
"composite": true,
|
10 |
|
11 |
/* Bundler mode */
|
12 |
"moduleResolution": "bundler",
|
|
|
6 |
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
7 |
"module": "ESNext",
|
8 |
"skipLibCheck": true,
|
|
|
9 |
|
10 |
/* Bundler mode */
|
11 |
"moduleResolution": "bundler",
|
tsconfig.json
CHANGED
@@ -1,17 +1,13 @@
|
|
1 |
{
|
2 |
"files": [],
|
3 |
"references": [
|
4 |
-
{
|
5 |
-
|
6 |
-
},
|
7 |
-
{
|
8 |
-
"path": "./tsconfig.node.json"
|
9 |
-
}
|
10 |
],
|
11 |
"compilerOptions": {
|
12 |
"baseUrl": ".",
|
13 |
"paths": {
|
14 |
-
"@/*": ["
|
15 |
}
|
16 |
}
|
17 |
}
|
|
|
1 |
{
|
2 |
"files": [],
|
3 |
"references": [
|
4 |
+
{ "path": "./tsconfig.app.json" },
|
5 |
+
{ "path": "./tsconfig.node.json" }
|
|
|
|
|
|
|
|
|
6 |
],
|
7 |
"compilerOptions": {
|
8 |
"baseUrl": ".",
|
9 |
"paths": {
|
10 |
+
"@/*": ["src/*"]
|
11 |
}
|
12 |
}
|
13 |
}
|
utils/consts.ts
CHANGED
@@ -4,17 +4,38 @@ export const defaultHTML = `<!DOCTYPE html>
|
|
4 |
<title>My app</title>
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
6 |
<meta charset="utf-8">
|
7 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
</head>
|
9 |
-
<body
|
10 |
-
<
|
11 |
-
<span
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
</h1>
|
16 |
-
</div>
|
17 |
-
<img src="https://enzostvs-deepsite.hf.space/arrow.svg" class="absolute bottom-8 left-0 w-[100px] transform rotate-[30deg]" />
|
18 |
<script></script>
|
19 |
</body>
|
20 |
</html>
|
|
|
4 |
<title>My app</title>
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
6 |
<meta charset="utf-8">
|
7 |
+
<style>
|
8 |
+
body {
|
9 |
+
display: flex;
|
10 |
+
justify-content: center;
|
11 |
+
align-items: center;
|
12 |
+
overflow: hidden;
|
13 |
+
height: 100dvh;
|
14 |
+
font-family: "Arial", sans-serif;
|
15 |
+
text-align: center;
|
16 |
+
}
|
17 |
+
.arrow {
|
18 |
+
position: absolute;
|
19 |
+
bottom: 32px;
|
20 |
+
left: 0px;
|
21 |
+
width: 100px;
|
22 |
+
transform: rotate(30deg);
|
23 |
+
}
|
24 |
+
h1 {
|
25 |
+
font-size: 50px;
|
26 |
+
}
|
27 |
+
h1 span {
|
28 |
+
color: #acacac;
|
29 |
+
font-size: 32px;
|
30 |
+
}
|
31 |
+
</style>
|
32 |
</head>
|
33 |
+
<body>
|
34 |
+
<h1>
|
35 |
+
<span>I'm ready to work,</span><br />
|
36 |
+
Ask me anything.
|
37 |
+
</h1>
|
38 |
+
<img src="https://enzostvs-deepsite.hf.space/arrow.svg" class="arrow" />
|
|
|
|
|
|
|
39 |
<script></script>
|
40 |
</body>
|
41 |
</html>
|
utils/providers.js
CHANGED
@@ -11,7 +11,7 @@ export const PROVIDERS = {
|
|
11 |
},
|
12 |
sambanova: {
|
13 |
name: "SambaNova",
|
14 |
-
max_tokens:
|
15 |
id: "sambanova",
|
16 |
},
|
17 |
novita: {
|
@@ -19,38 +19,9 @@ export const PROVIDERS = {
|
|
19 |
max_tokens: 16_000,
|
20 |
id: "novita",
|
21 |
},
|
22 |
-
hyperbolic: {
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
},
|
27 |
-
together: {
|
28 |
-
name: "Together AI",
|
29 |
-
max_tokens: 128_000,
|
30 |
-
id: "together",
|
31 |
-
},
|
32 |
};
|
33 |
-
|
34 |
-
export const MODELS = [
|
35 |
-
{
|
36 |
-
value: "deepseek-ai/DeepSeek-V3-0324",
|
37 |
-
label: "DeepSeek V3 O324",
|
38 |
-
providers: ["fireworks-ai", "nebius", "sambanova", "novita", "hyperbolic"],
|
39 |
-
autoProvider: "fireworks-ai",
|
40 |
-
},
|
41 |
-
{
|
42 |
-
value: "deepseek-ai/DeepSeek-R1-0528",
|
43 |
-
label: "DeepSeek R1 0528",
|
44 |
-
providers: [
|
45 |
-
"fireworks-ai",
|
46 |
-
"novita",
|
47 |
-
"hyperbolic",
|
48 |
-
"nebius",
|
49 |
-
"together",
|
50 |
-
"sambanova",
|
51 |
-
],
|
52 |
-
autoProvider: "novita",
|
53 |
-
isNew: true,
|
54 |
-
isThinker: true,
|
55 |
-
},
|
56 |
-
];
|
|
|
11 |
},
|
12 |
sambanova: {
|
13 |
name: "SambaNova",
|
14 |
+
max_tokens: 8_000,
|
15 |
id: "sambanova",
|
16 |
},
|
17 |
novita: {
|
|
|
19 |
max_tokens: 16_000,
|
20 |
id: "novita",
|
21 |
},
|
22 |
+
// hyperbolic: {
|
23 |
+
// name: "Hyperbolic",
|
24 |
+
// max_tokens: 131_000,
|
25 |
+
// id: "hyperbolic",
|
26 |
+
// },
|
|
|
|
|
|
|
|
|
|
|
27 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
utils/types.ts
CHANGED
@@ -4,9 +4,3 @@ export interface Auth {
|
|
4 |
name: string;
|
5 |
isLocalUse?: boolean;
|
6 |
}
|
7 |
-
|
8 |
-
export interface HtmlHistory {
|
9 |
-
html: string;
|
10 |
-
createdAt: Date;
|
11 |
-
prompt: string;
|
12 |
-
}
|
|
|
4 |
name: string;
|
5 |
isLocalUse?: boolean;
|
6 |
}
|
|
|
|
|
|
|
|
|
|
|
|
vite.config.ts
CHANGED
@@ -1,14 +1,11 @@
|
|
1 |
-
import path from "path";
|
2 |
-
import tailwindcss from "@tailwindcss/vite";
|
3 |
-
import react from "@vitejs/plugin-react";
|
4 |
import { defineConfig } from "vite";
|
|
|
|
|
5 |
|
6 |
// https://vite.dev/config/
|
7 |
export default defineConfig({
|
8 |
plugins: [react(), tailwindcss()],
|
9 |
resolve: {
|
10 |
-
alias: {
|
11 |
-
"@": path.resolve(__dirname, "./src"),
|
12 |
-
},
|
13 |
},
|
14 |
});
|
|
|
|
|
|
|
|
|
1 |
import { defineConfig } from "vite";
|
2 |
+
import react from "@vitejs/plugin-react";
|
3 |
+
import tailwindcss from "@tailwindcss/vite";
|
4 |
|
5 |
// https://vite.dev/config/
|
6 |
export default defineConfig({
|
7 |
plugins: [react(), tailwindcss()],
|
8 |
resolve: {
|
9 |
+
alias: [{ find: "@", replacement: "/src" }],
|
|
|
|
|
10 |
},
|
11 |
});
|