Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Commit
•
aeeae20
1
Parent(s):
3635e59
neutral theme, comfy auth, dynamic workflows
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- documentation/design/README.md +70 -0
- package-lock.json +31 -16
- package.json +6 -5
- src/app/api/resolve/providers/comfy-replicate/index.ts +52 -15
- src/app/api/resolve/providers/comfyui/getComfyWorkflow.ts +0 -33
- src/app/api/resolve/providers/comfyui/index.ts +44 -6
- src/app/api/resolve/providers/comfyui/temporary_demo.json +0 -80
- src/app/embed/embed.tsx +1 -1
- src/app/main.tsx +23 -4
- src/components/dialogs/iframe-warning/index.tsx +2 -2
- src/components/dialogs/loader/index.tsx +1 -1
- src/components/forms/FormSection.tsx +1 -1
- src/components/mobile/MobileMenu.tsx +25 -0
- src/components/monitor/StaticPlayer/index.tsx +2 -2
- src/components/settings/index.tsx +3 -3
- src/components/settings/provider.tsx +26 -2
- src/components/tags/colors.ts +1 -1
- src/components/toolbars/bottom-bar/metrics/index.tsx +2 -2
- src/components/toolbars/editors-menu/EditorsSideMenuItem.tsx +2 -2
- src/components/toolbars/system-menu/index.tsx +13 -10
- src/components/toolbars/top-menu/ToggleView/index.tsx +1 -1
- src/components/toolbars/top-menu/index.tsx +2 -2
- src/components/ui/alert.tsx +3 -2
- src/components/ui/avatar.tsx +1 -1
- src/components/ui/badge.tsx +5 -5
- src/components/ui/button.tsx +7 -7
- src/components/ui/card.tsx +2 -2
- src/components/ui/checkbox.tsx +1 -1
- src/components/ui/command.tsx +7 -7
- src/components/ui/dialog.tsx +4 -4
- src/components/ui/dropdown-menu.tsx +10 -7
- src/components/ui/popover.tsx +1 -1
- src/components/ui/progress.tsx +2 -2
- src/components/ui/scroll-area.tsx +1 -1
- src/components/ui/select.tsx +7 -4
- src/components/ui/separator.tsx +1 -1
- src/components/ui/sheet.tsx +143 -0
- src/components/ui/sonner.tsx +4 -4
- src/components/ui/table.tsx +7 -4
- src/components/ui/tabs.tsx +3 -3
- src/components/ui/textarea.tsx +1 -1
- src/components/ui/toast.tsx +5 -5
- src/components/ui/tooltip.tsx +1 -1
- src/components/ui/vertical-slider.tsx +3 -3
- src/components/wizards/project/index.tsx +3 -3
- src/experiments/moodboard/MoodboardView.tsx +1 -1
- src/experiments/moodboard/Node.tsx +1 -1
- src/lib/core/constants.ts +1 -1
- src/services/debug.ts +9 -2
- src/services/editors/script-editor/useScriptEditor.ts +3 -2
documentation/design/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Design
|
2 |
+
|
3 |
+
(those are just quick notes for now, we can elaborate later)
|
4 |
+
|
5 |
+
## Designing Clapper for the Web
|
6 |
+
|
7 |
+
### Targeted devices
|
8 |
+
|
9 |
+
Currently Clapper works best on a laptop,
|
10 |
+
since the UI has been developed around the presence of a relatively wide screen,
|
11 |
+
a mouse and a touch pad (for horizontal scrolling in the timeline).
|
12 |
+
|
13 |
+
However I think we should try to better support the following environments:
|
14 |
+
|
15 |
+
- Tiny laptop (12", 11")
|
16 |
+
- Tablet (without a mouse)
|
17 |
+
- Desktop computer with multiple screens
|
18 |
+
|
19 |
+
(mobile has its own chapter, see below in this document)
|
20 |
+
|
21 |
+
### Use Web APIs in priority
|
22 |
+
|
23 |
+
We should try to use standard Web APIs (ratified by the W3C) as much as possible, with polyfills in case some browsers don't implement them yet.
|
24 |
+
|
25 |
+
We can use experimental standards (eg. WebGPU),
|
26 |
+
but since they are unstable and not supported by all browsers, they should not be mandatory to the experience.
|
27 |
+
|
28 |
+
## Designing Clapper for desktop
|
29 |
+
|
30 |
+
The experience on Desktop should be similar to the one in a browser, but we can do some changes:
|
31 |
+
|
32 |
+
### Customizing the look of the app window
|
33 |
+
|
34 |
+
Electron offers us to hide or customize the app's window, so we should do it.
|
35 |
+
|
36 |
+
We don't have to follow the design principles of the underlying operating system (some apps don't care eg. video games, Spotify, Slack, FLStudio, Discord..) but it may be necessary for some operations (file pickers, installer, window management etc).
|
37 |
+
|
38 |
+
### Use the native file system
|
39 |
+
|
40 |
+
The big benefit of running Clapper as a desktop application is that we can access the file system, meaning we can work with files of arbitrary file length (note: for this kind of file system manipulation, we will have to use extra code eg. NodeJS)
|
41 |
+
|
42 |
+
This can also be used for performance optimization such as using temporary files, or pre-computing things and store them in a cache for the next time Clapper is opened.
|
43 |
+
|
44 |
+
### Download additional data for local use
|
45 |
+
|
46 |
+
By running Clapper on the user's device, we can also make it download data of arbitrary size.
|
47 |
+
|
48 |
+
This can help with various use cases, such as running AI models locally.
|
49 |
+
|
50 |
+
For instance the desktop app LMStudio can download models from Hugging Face.
|
51 |
+
|
52 |
+
### Call external or embedded native libraries
|
53 |
+
|
54 |
+
We have complete freedom to ship Clapper with embedded native tools eg. a database or a native library (eg. a C++ library to run a LLM locally).
|
55 |
+
|
56 |
+
We could even use Python scripts with Clapper.
|
57 |
+
|
58 |
+
Please note however that we will have to make sure anything we embed works on various operating systems (Windows/macOS/Linux) so this requires dedicated skills and maintenance.
|
59 |
+
|
60 |
+
### Use System Notifications
|
61 |
+
|
62 |
+
When a job is pending, finished, a software update is ready etc.
|
63 |
+
|
64 |
+
## Clapper Design For Mobile
|
65 |
+
|
66 |
+
Currently Clapper can *run* on mobile, but it is not designed for it.
|
67 |
+
|
68 |
+
So things like the top menu etc will be pretty much unuseable, unless we adapt them.
|
69 |
+
|
70 |
+
|
package-lock.json
CHANGED
@@ -11,7 +11,7 @@
|
|
11 |
"dependencies": {
|
12 |
"@aitube/broadway": "0.2.3",
|
13 |
"@aitube/clap": "0.2.3",
|
14 |
-
"@aitube/clapper-services": "0.2.3-
|
15 |
"@aitube/client": "0.2.3",
|
16 |
"@aitube/engine": "0.2.3",
|
17 |
"@aitube/timeline": "0.2.3",
|
@@ -33,7 +33,7 @@
|
|
33 |
"@radix-ui/react-avatar": "^1.0.4",
|
34 |
"@radix-ui/react-checkbox": "^1.0.4",
|
35 |
"@radix-ui/react-collapsible": "^1.0.3",
|
36 |
-
"@radix-ui/react-dialog": "^1.
|
37 |
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
38 |
"@radix-ui/react-icons": "^1.3.0",
|
39 |
"@radix-ui/react-label": "^2.0.2",
|
@@ -66,7 +66,7 @@
|
|
66 |
"class-variance-authority": "^0.7.0",
|
67 |
"clsx": "^2.1.1",
|
68 |
"cmdk": "^0.2.1",
|
69 |
-
"comfydeploy": "^0.0.
|
70 |
"date-fns": "^3.6.0",
|
71 |
"dotenv": "^16.4.5",
|
72 |
"fflate": "^0.8.2",
|
@@ -89,6 +89,7 @@
|
|
89 |
"react-dnd-html5-backend": "^16.0.1",
|
90 |
"react-dom": "^18.3.1",
|
91 |
"react-drag-drop-files": "^2.3.10",
|
|
|
92 |
"react-hook-consent": "^3.5.3",
|
93 |
"react-hotkeys-hook": "^4.5.0",
|
94 |
"react-icons": "^5.2.1",
|
@@ -99,7 +100,7 @@
|
|
99 |
"replicate": "^0.32.0",
|
100 |
"sharp": "0.33.4",
|
101 |
"sonner": "^1.5.0",
|
102 |
-
"tailwind-merge": "^2.
|
103 |
"tailwindcss-animate": "^1.0.7",
|
104 |
"three": "^0.164.1",
|
105 |
"ts-node": "^10.9.2",
|
@@ -109,7 +110,7 @@
|
|
109 |
"web-audio-beat-detector": "^8.2.12",
|
110 |
"yaml": "^2.4.5",
|
111 |
"zustand": "4.5.2",
|
112 |
-
"zx": "^8.1.
|
113 |
},
|
114 |
"devDependencies": {
|
115 |
"@electron-forge/cli": "^7.4.0",
|
@@ -191,9 +192,9 @@
|
|
191 |
}
|
192 |
},
|
193 |
"node_modules/@aitube/clapper-services": {
|
194 |
-
"version": "0.2.3-
|
195 |
-
"resolved": "https://registry.npmjs.org/@aitube/clapper-services/-/clapper-services-0.2.3-
|
196 |
-
"integrity": "sha512-
|
197 |
"peerDependencies": {
|
198 |
"@aitube/clap": "0.2.3",
|
199 |
"@aitube/timeline": "0.2.3",
|
@@ -9394,11 +9395,14 @@
|
|
9394 |
}
|
9395 |
},
|
9396 |
"node_modules/comfydeploy": {
|
9397 |
-
"version": "0.0.
|
9398 |
-
"resolved": "https://registry.npmjs.org/comfydeploy/-/comfydeploy-0.0.
|
9399 |
-
"integrity": "sha512-
|
9400 |
-
"
|
9401 |
-
"zod": "
|
|
|
|
|
|
|
9402 |
}
|
9403 |
},
|
9404 |
"node_modules/comma-separated-tokens": {
|
@@ -17745,6 +17749,17 @@
|
|
17745 |
"react-dom": "^18.0.0"
|
17746 |
}
|
17747 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17748 |
"node_modules/react-hook-consent": {
|
17749 |
"version": "3.5.3",
|
17750 |
"resolved": "https://registry.npmjs.org/react-hook-consent/-/react-hook-consent-3.5.3.tgz",
|
@@ -19595,9 +19610,9 @@
|
|
19595 |
"dev": true
|
19596 |
},
|
19597 |
"node_modules/tailwind-merge": {
|
19598 |
-
"version": "2.
|
19599 |
-
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.
|
19600 |
-
"integrity": "sha512-
|
19601 |
"funding": {
|
19602 |
"type": "github",
|
19603 |
"url": "https://github.com/sponsors/dcastil"
|
|
|
11 |
"dependencies": {
|
12 |
"@aitube/broadway": "0.2.3",
|
13 |
"@aitube/clap": "0.2.3",
|
14 |
+
"@aitube/clapper-services": "0.2.3-2",
|
15 |
"@aitube/client": "0.2.3",
|
16 |
"@aitube/engine": "0.2.3",
|
17 |
"@aitube/timeline": "0.2.3",
|
|
|
33 |
"@radix-ui/react-avatar": "^1.0.4",
|
34 |
"@radix-ui/react-checkbox": "^1.0.4",
|
35 |
"@radix-ui/react-collapsible": "^1.0.3",
|
36 |
+
"@radix-ui/react-dialog": "^1.1.1",
|
37 |
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
38 |
"@radix-ui/react-icons": "^1.3.0",
|
39 |
"@radix-ui/react-label": "^2.0.2",
|
|
|
66 |
"class-variance-authority": "^0.7.0",
|
67 |
"clsx": "^2.1.1",
|
68 |
"cmdk": "^0.2.1",
|
69 |
+
"comfydeploy": "^0.0.21",
|
70 |
"date-fns": "^3.6.0",
|
71 |
"dotenv": "^16.4.5",
|
72 |
"fflate": "^0.8.2",
|
|
|
89 |
"react-dnd-html5-backend": "^16.0.1",
|
90 |
"react-dom": "^18.3.1",
|
91 |
"react-drag-drop-files": "^2.3.10",
|
92 |
+
"react-error-boundary": "^4.0.13",
|
93 |
"react-hook-consent": "^3.5.3",
|
94 |
"react-hotkeys-hook": "^4.5.0",
|
95 |
"react-icons": "^5.2.1",
|
|
|
100 |
"replicate": "^0.32.0",
|
101 |
"sharp": "0.33.4",
|
102 |
"sonner": "^1.5.0",
|
103 |
+
"tailwind-merge": "^2.5.2",
|
104 |
"tailwindcss-animate": "^1.0.7",
|
105 |
"three": "^0.164.1",
|
106 |
"ts-node": "^10.9.2",
|
|
|
110 |
"web-audio-beat-detector": "^8.2.12",
|
111 |
"yaml": "^2.4.5",
|
112 |
"zustand": "4.5.2",
|
113 |
+
"zx": "^8.1.4"
|
114 |
},
|
115 |
"devDependencies": {
|
116 |
"@electron-forge/cli": "^7.4.0",
|
|
|
192 |
}
|
193 |
},
|
194 |
"node_modules/@aitube/clapper-services": {
|
195 |
+
"version": "0.2.3-2",
|
196 |
+
"resolved": "https://registry.npmjs.org/@aitube/clapper-services/-/clapper-services-0.2.3-2.tgz",
|
197 |
+
"integrity": "sha512-Qd6Riridk4FVcTjlscxw5wsbUgojwi1wkTIjlgPluhT5J5kLyEJQL/hmT2gBDBRsB4kyieVNZiGflgXnauDENw==",
|
198 |
"peerDependencies": {
|
199 |
"@aitube/clap": "0.2.3",
|
200 |
"@aitube/timeline": "0.2.3",
|
|
|
9395 |
}
|
9396 |
},
|
9397 |
"node_modules/comfydeploy": {
|
9398 |
+
"version": "0.0.21",
|
9399 |
+
"resolved": "https://registry.npmjs.org/comfydeploy/-/comfydeploy-0.0.21.tgz",
|
9400 |
+
"integrity": "sha512-v5i6igitVWN6jmDlg35g8XyJuGsToD1sbhEZIz4nM3F6gSXZf2YjJzL/wzabsHlOtHhKsO/vdQAXuvO7/w8deQ==",
|
9401 |
+
"dependencies": {
|
9402 |
+
"zod": "^3.22.4"
|
9403 |
+
},
|
9404 |
+
"engines": {
|
9405 |
+
"node": ">=16"
|
9406 |
}
|
9407 |
},
|
9408 |
"node_modules/comma-separated-tokens": {
|
|
|
17749 |
"react-dom": "^18.0.0"
|
17750 |
}
|
17751 |
},
|
17752 |
+
"node_modules/react-error-boundary": {
|
17753 |
+
"version": "4.0.13",
|
17754 |
+
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz",
|
17755 |
+
"integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==",
|
17756 |
+
"dependencies": {
|
17757 |
+
"@babel/runtime": "^7.12.5"
|
17758 |
+
},
|
17759 |
+
"peerDependencies": {
|
17760 |
+
"react": ">=16.13.1"
|
17761 |
+
}
|
17762 |
+
},
|
17763 |
"node_modules/react-hook-consent": {
|
17764 |
"version": "3.5.3",
|
17765 |
"resolved": "https://registry.npmjs.org/react-hook-consent/-/react-hook-consent-3.5.3.tgz",
|
|
|
19610 |
"dev": true
|
19611 |
},
|
19612 |
"node_modules/tailwind-merge": {
|
19613 |
+
"version": "2.5.2",
|
19614 |
+
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz",
|
19615 |
+
"integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==",
|
19616 |
"funding": {
|
19617 |
"type": "github",
|
19618 |
"url": "https://github.com/sponsors/dcastil"
|
package.json
CHANGED
@@ -38,7 +38,7 @@
|
|
38 |
"dependencies": {
|
39 |
"@aitube/broadway": "0.2.3",
|
40 |
"@aitube/clap": "0.2.3",
|
41 |
-
"@aitube/clapper-services": "0.2.3-
|
42 |
"@aitube/client": "0.2.3",
|
43 |
"@aitube/engine": "0.2.3",
|
44 |
"@aitube/timeline": "0.2.3",
|
@@ -60,7 +60,7 @@
|
|
60 |
"@radix-ui/react-avatar": "^1.0.4",
|
61 |
"@radix-ui/react-checkbox": "^1.0.4",
|
62 |
"@radix-ui/react-collapsible": "^1.0.3",
|
63 |
-
"@radix-ui/react-dialog": "^1.
|
64 |
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
65 |
"@radix-ui/react-icons": "^1.3.0",
|
66 |
"@radix-ui/react-label": "^2.0.2",
|
@@ -93,7 +93,7 @@
|
|
93 |
"class-variance-authority": "^0.7.0",
|
94 |
"clsx": "^2.1.1",
|
95 |
"cmdk": "^0.2.1",
|
96 |
-
"comfydeploy": "^0.0.
|
97 |
"date-fns": "^3.6.0",
|
98 |
"dotenv": "^16.4.5",
|
99 |
"fflate": "^0.8.2",
|
@@ -116,6 +116,7 @@
|
|
116 |
"react-dnd-html5-backend": "^16.0.1",
|
117 |
"react-dom": "^18.3.1",
|
118 |
"react-drag-drop-files": "^2.3.10",
|
|
|
119 |
"react-hook-consent": "^3.5.3",
|
120 |
"react-hotkeys-hook": "^4.5.0",
|
121 |
"react-icons": "^5.2.1",
|
@@ -126,7 +127,7 @@
|
|
126 |
"replicate": "^0.32.0",
|
127 |
"sharp": "0.33.4",
|
128 |
"sonner": "^1.5.0",
|
129 |
-
"tailwind-merge": "^2.
|
130 |
"tailwindcss-animate": "^1.0.7",
|
131 |
"three": "^0.164.1",
|
132 |
"ts-node": "^10.9.2",
|
@@ -136,7 +137,7 @@
|
|
136 |
"web-audio-beat-detector": "^8.2.12",
|
137 |
"yaml": "^2.4.5",
|
138 |
"zustand": "4.5.2",
|
139 |
-
"zx": "^8.1.
|
140 |
},
|
141 |
"devDependencies": {
|
142 |
"@electron-forge/cli": "^7.4.0",
|
|
|
38 |
"dependencies": {
|
39 |
"@aitube/broadway": "0.2.3",
|
40 |
"@aitube/clap": "0.2.3",
|
41 |
+
"@aitube/clapper-services": "0.2.3-2",
|
42 |
"@aitube/client": "0.2.3",
|
43 |
"@aitube/engine": "0.2.3",
|
44 |
"@aitube/timeline": "0.2.3",
|
|
|
60 |
"@radix-ui/react-avatar": "^1.0.4",
|
61 |
"@radix-ui/react-checkbox": "^1.0.4",
|
62 |
"@radix-ui/react-collapsible": "^1.0.3",
|
63 |
+
"@radix-ui/react-dialog": "^1.1.1",
|
64 |
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
65 |
"@radix-ui/react-icons": "^1.3.0",
|
66 |
"@radix-ui/react-label": "^2.0.2",
|
|
|
93 |
"class-variance-authority": "^0.7.0",
|
94 |
"clsx": "^2.1.1",
|
95 |
"cmdk": "^0.2.1",
|
96 |
+
"comfydeploy": "^0.0.21",
|
97 |
"date-fns": "^3.6.0",
|
98 |
"dotenv": "^16.4.5",
|
99 |
"fflate": "^0.8.2",
|
|
|
116 |
"react-dnd-html5-backend": "^16.0.1",
|
117 |
"react-dom": "^18.3.1",
|
118 |
"react-drag-drop-files": "^2.3.10",
|
119 |
+
"react-error-boundary": "^4.0.13",
|
120 |
"react-hook-consent": "^3.5.3",
|
121 |
"react-hotkeys-hook": "^4.5.0",
|
122 |
"react-icons": "^5.2.1",
|
|
|
127 |
"replicate": "^0.32.0",
|
128 |
"sharp": "0.33.4",
|
129 |
"sonner": "^1.5.0",
|
130 |
+
"tailwind-merge": "^2.5.2",
|
131 |
"tailwindcss-animate": "^1.0.7",
|
132 |
"three": "^0.164.1",
|
133 |
"ts-node": "^10.9.2",
|
|
|
137 |
"web-audio-beat-detector": "^8.2.12",
|
138 |
"yaml": "^2.4.5",
|
139 |
"zustand": "4.5.2",
|
140 |
+
"zx": "^8.1.4"
|
141 |
},
|
142 |
"devDependencies": {
|
143 |
"@electron-forge/cli": "^7.4.0",
|
src/app/api/resolve/providers/comfy-replicate/index.ts
CHANGED
@@ -1,7 +1,11 @@
|
|
1 |
-
import {
|
|
|
|
|
|
|
|
|
2 |
|
3 |
import { ResolveRequest } from '@aitube/clapper-services'
|
4 |
-
import { getComfyWorkflow } from '
|
5 |
import { runWorkflow } from './runWorkflow'
|
6 |
import { TimelineSegment } from '@aitube/timeline'
|
7 |
|
@@ -11,22 +15,55 @@ export async function resolveSegment(
|
|
11 |
if (!request.settings.replicateApiKey) {
|
12 |
throw new Error(`Missing API key for "Replicate.com"`)
|
13 |
}
|
14 |
-
const workflow = getComfyWorkflow(request)
|
15 |
|
16 |
const segment: TimelineSegment = request.segment
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
}
|
31 |
|
32 |
return segment
|
|
|
1 |
+
import {
|
2 |
+
ClapSegmentCategory,
|
3 |
+
ClapSegmentStatus,
|
4 |
+
getClapAssetSourceType,
|
5 |
+
} from '@aitube/clap'
|
6 |
|
7 |
import { ResolveRequest } from '@aitube/clapper-services'
|
8 |
+
import { getComfyWorkflow } from '../../../../../services/editors/workflow-editor/workflows/comfyui/getComfyWorkflow'
|
9 |
import { runWorkflow } from './runWorkflow'
|
10 |
import { TimelineSegment } from '@aitube/timeline'
|
11 |
|
|
|
15 |
if (!request.settings.replicateApiKey) {
|
16 |
throw new Error(`Missing API key for "Replicate.com"`)
|
17 |
}
|
|
|
18 |
|
19 |
const segment: TimelineSegment = request.segment
|
20 |
|
21 |
+
if (request.segment.category === ClapSegmentCategory.STORYBOARD) {
|
22 |
+
const inputFields =
|
23 |
+
request.settings.imageGenerationWorkflow.inputFields || []
|
24 |
+
|
25 |
+
// since this is a random "wild" workflow, it is possible
|
26 |
+
// that the field name is a bit different
|
27 |
+
// we try to look into the workflow input fields
|
28 |
+
// to find the best match
|
29 |
+
const promptFields = [
|
30 |
+
inputFields.find((f) => f.id === 'prompt'), // exactMatch,
|
31 |
+
inputFields.find((f) => f.id.includes('prompt')), // similarName,
|
32 |
+
inputFields.find((f) => f.type === 'string'), // similarType
|
33 |
+
].filter((x) => typeof x !== 'undefined')
|
34 |
+
|
35 |
+
const promptField = promptFields[0]
|
36 |
+
if (!promptField) {
|
37 |
+
throw new Error(
|
38 |
+
`this workflow doesn't seem to have a parameter called "prompt"`
|
39 |
+
)
|
40 |
+
}
|
41 |
+
|
42 |
+
console.log(`TODO: inject parameters into the final request object`)
|
43 |
+
const workflow = `{}` // <- the final workflow sent to Replicate
|
44 |
+
|
45 |
+
try {
|
46 |
+
segment.assetUrl = await runWorkflow({
|
47 |
+
apiKey: request.settings.replicateApiKey,
|
48 |
+
workflow,
|
49 |
+
})
|
50 |
+
segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
|
51 |
+
} catch (err) {
|
52 |
+
console.error(`failed to call Replicate: `, err)
|
53 |
+
segment.assetUrl = ''
|
54 |
+
segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
|
55 |
+
segment.status = ClapSegmentStatus.TO_GENERATE
|
56 |
+
// request.segment.status = ClapSegmentStatus.ERROR
|
57 |
+
}
|
58 |
+
} else if (request.segment.category === ClapSegmentCategory.VIDEO) {
|
59 |
+
// TODO do the same for video
|
60 |
+
throw new Error(
|
61 |
+
`Clapper doesn't support ${request.segment.category} generation for provider "Comfy.icu". Please open a pull request with (working code) to solve this!`
|
62 |
+
)
|
63 |
+
} else {
|
64 |
+
throw new Error(
|
65 |
+
`Clapper doesn't support ${request.segment.category} generation for provider "Comfy.icu". Please open a pull request with (working code) to solve this!`
|
66 |
+
)
|
67 |
}
|
68 |
|
69 |
return segment
|
src/app/api/resolve/providers/comfyui/getComfyWorkflow.ts
DELETED
@@ -1,33 +0,0 @@
|
|
1 |
-
import { ClapSegmentCategory } from '@aitube/clap'
|
2 |
-
import { getVideoPrompt } from '@aitube/engine'
|
3 |
-
|
4 |
-
import { ComfyNode, ResolveRequest } from '@aitube/clapper-services'
|
5 |
-
|
6 |
-
// TODO move this to @aitube/engine or @aitube/engine-comfy
|
7 |
-
export function getComfyWorkflow(request: ResolveRequest) {
|
8 |
-
let comfyWorkflow = '{}'
|
9 |
-
|
10 |
-
if (request.segment.category === ClapSegmentCategory.STORYBOARD) {
|
11 |
-
comfyWorkflow = request.settings.comfyWorkflowForImage
|
12 |
-
} else if (request.segment.category === ClapSegmentCategory.VIDEO) {
|
13 |
-
comfyWorkflow = request.settings.comfyWorkflowForVideo
|
14 |
-
}
|
15 |
-
|
16 |
-
// parse the node array from the ComfyUI workflow
|
17 |
-
const nodes = Object.values(JSON.parse(comfyWorkflow)) as ComfyNode[]
|
18 |
-
|
19 |
-
const visualPrompt = getVideoPrompt(request.segments, request.entities)
|
20 |
-
|
21 |
-
const output: Record<string, ComfyNode> = {}
|
22 |
-
|
23 |
-
nodes.forEach((node, i) => {
|
24 |
-
if (typeof node.inputs.text === 'string') {
|
25 |
-
if (node._meta.title.includes('Prompt')) {
|
26 |
-
node.inputs.text = visualPrompt
|
27 |
-
}
|
28 |
-
}
|
29 |
-
output[`${i}`] = node
|
30 |
-
})
|
31 |
-
|
32 |
-
return JSON.stringify(output)
|
33 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app/api/resolve/providers/comfyui/index.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import { ResolveRequest } from '@aitube/clapper-services'
|
2 |
import {
|
|
|
3 |
ClapSegmentCategory,
|
4 |
ClapSegmentStatus,
|
5 |
generateSeed,
|
@@ -7,6 +8,7 @@ import {
|
|
7 |
} from '@aitube/clap'
|
8 |
import { TimelineSegment } from '@aitube/timeline'
|
9 |
import {
|
|
|
10 |
CallWrapper,
|
11 |
ComfyApi,
|
12 |
PromptBuilder,
|
@@ -15,6 +17,7 @@ import {
|
|
15 |
} from '@saintno/comfyui-sdk'
|
16 |
|
17 |
import { getWorkflowInputValues } from '../getWorkflowInputValues'
|
|
|
18 |
|
19 |
export async function resolveSegment(
|
20 |
request: ResolveRequest
|
@@ -25,10 +28,25 @@ export async function resolveSegment(
|
|
25 |
|
26 |
const segment: TimelineSegment = { ...request.segment }
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
// for API doc please see:
|
29 |
// https://github.com/tctien342/comfyui-sdk/blob/main/examples/example-t2i.ts
|
30 |
const api = new ComfyApi(
|
31 |
-
request.settings.comfyUiApiUrl || 'http://localhost:8188'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
).init()
|
33 |
|
34 |
if (request.segment.category === ClapSegmentCategory.STORYBOARD) {
|
@@ -123,18 +141,38 @@ export async function resolveSegment(
|
|
123 |
.onStart(() => console.log('Task is started'))
|
124 |
.onPreview((blob) => console.log(blob))
|
125 |
.onFinished((data) => {
|
126 |
-
console.log(
|
127 |
-
data.images?.images.map((img: any) => api.getPathImage(img))
|
128 |
-
)
|
129 |
})
|
130 |
.onProgress((info) =>
|
131 |
console.log('Processing node', info.node, `${info.value}/${info.max}`)
|
132 |
)
|
133 |
.onFailed((err) => console.log('Task is failed', err))
|
134 |
|
135 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
|
137 |
-
|
138 |
} else {
|
139 |
throw new Error(
|
140 |
`Clapper doesn't support ${request.segment.category} generation for provider "ComfyUI". Please open a pull request with (working code) to solve this!`
|
|
|
1 |
import { ResolveRequest } from '@aitube/clapper-services'
|
2 |
import {
|
3 |
+
ClapAssetSource,
|
4 |
ClapSegmentCategory,
|
5 |
ClapSegmentStatus,
|
6 |
generateSeed,
|
|
|
8 |
} from '@aitube/clap'
|
9 |
import { TimelineSegment } from '@aitube/timeline'
|
10 |
import {
|
11 |
+
BasicCredentials,
|
12 |
CallWrapper,
|
13 |
ComfyApi,
|
14 |
PromptBuilder,
|
|
|
17 |
} from '@saintno/comfyui-sdk'
|
18 |
|
19 |
import { getWorkflowInputValues } from '../getWorkflowInputValues'
|
20 |
+
import { decodeOutput } from '@/lib/utils/decodeOutput'
|
21 |
|
22 |
export async function resolveSegment(
|
23 |
request: ResolveRequest
|
|
|
28 |
|
29 |
const segment: TimelineSegment = { ...request.segment }
|
30 |
|
31 |
+
const credentials: BasicCredentials = {
|
32 |
+
type: 'basic',
|
33 |
+
username: request.settings.comfyUiHttpAuthLogin,
|
34 |
+
password: request.settings.comfyUiHttpAuthPassword,
|
35 |
+
}
|
36 |
+
|
37 |
// for API doc please see:
|
38 |
// https://github.com/tctien342/comfyui-sdk/blob/main/examples/example-t2i.ts
|
39 |
const api = new ComfyApi(
|
40 |
+
request.settings.comfyUiApiUrl || 'http://localhost:8188',
|
41 |
+
request.settings.comfyUiClientId,
|
42 |
+
|
43 |
+
// HTTP Auth is optional
|
44 |
+
// also in the future, we might support other things (bearer tokens?)
|
45 |
+
request.settings.comfyUiHttpAuthLogin
|
46 |
+
? {
|
47 |
+
credentials,
|
48 |
+
}
|
49 |
+
: undefined
|
50 |
).init()
|
51 |
|
52 |
if (request.segment.category === ClapSegmentCategory.STORYBOARD) {
|
|
|
141 |
.onStart(() => console.log('Task is started'))
|
142 |
.onPreview((blob) => console.log(blob))
|
143 |
.onFinished((data) => {
|
144 |
+
console.log('Pipeline finished')
|
|
|
|
|
145 |
})
|
146 |
.onProgress((info) =>
|
147 |
console.log('Processing node', info.node, `${info.value}/${info.max}`)
|
148 |
)
|
149 |
.onFailed((err) => console.log('Task is failed', err))
|
150 |
|
151 |
+
const rawOutput = await pipeline.run()
|
152 |
+
|
153 |
+
if (!rawOutput) {
|
154 |
+
throw new Error(`failed to run the pipeline (no output)`)
|
155 |
+
}
|
156 |
+
|
157 |
+
const imagePaths = rawOutput.images?.images.map((img: any) =>
|
158 |
+
api.getPathImage(img)
|
159 |
+
)
|
160 |
+
|
161 |
+
console.log(`imagePaths:`, imagePaths)
|
162 |
+
|
163 |
+
const imagePath = imagePaths.at(0)
|
164 |
+
if (!imagePath) {
|
165 |
+
throw new Error(`failed to run the pipeline (no image)`)
|
166 |
+
}
|
167 |
+
|
168 |
+
// TODO: check what the imagePath looks like exactly
|
169 |
+
const assetUrl = await decodeOutput(imagePath)
|
170 |
+
|
171 |
+
console.log(`assetUrl:`, imagePaths)
|
172 |
+
segment.assetUrl = assetUrl
|
173 |
+
segment.assetSourceType = ClapAssetSource.DATA
|
174 |
|
175 |
+
// TODO:
|
176 |
} else {
|
177 |
throw new Error(
|
178 |
`Clapper doesn't support ${request.segment.category} generation for provider "ComfyUI". Please open a pull request with (working code) to solve this!`
|
src/app/api/resolve/providers/comfyui/temporary_demo.json
DELETED
@@ -1,80 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"3": {
|
3 |
-
"inputs": {
|
4 |
-
"seed": 303533494192794,
|
5 |
-
"steps": 20,
|
6 |
-
"cfg": 8,
|
7 |
-
"sampler_name": "euler",
|
8 |
-
"scheduler": "normal",
|
9 |
-
"denoise": 1,
|
10 |
-
"model": ["4", 0],
|
11 |
-
"positive": ["6", 0],
|
12 |
-
"negative": ["7", 0],
|
13 |
-
"latent_image": ["5", 0]
|
14 |
-
},
|
15 |
-
"class_type": "KSampler",
|
16 |
-
"_meta": {
|
17 |
-
"title": "KSampler"
|
18 |
-
}
|
19 |
-
},
|
20 |
-
"4": {
|
21 |
-
"inputs": {
|
22 |
-
"ckpt_name": "SD15/counterfeitV30_v30.safetensors"
|
23 |
-
},
|
24 |
-
"class_type": "CheckpointLoaderSimple",
|
25 |
-
"_meta": {
|
26 |
-
"title": "Load Checkpoint"
|
27 |
-
}
|
28 |
-
},
|
29 |
-
"5": {
|
30 |
-
"inputs": {
|
31 |
-
"width": 512,
|
32 |
-
"height": 512,
|
33 |
-
"batch_size": 1
|
34 |
-
},
|
35 |
-
"class_type": "EmptyLatentImage",
|
36 |
-
"_meta": {
|
37 |
-
"title": "Empty Latent Image"
|
38 |
-
}
|
39 |
-
},
|
40 |
-
"6": {
|
41 |
-
"inputs": {
|
42 |
-
"text": "beautiful scenery nature glass bottle landscape, , purple galaxy bottle,",
|
43 |
-
"clip": ["4", 1]
|
44 |
-
},
|
45 |
-
"class_type": "CLIPTextEncode",
|
46 |
-
"_meta": {
|
47 |
-
"title": "CLIP Text Encode (Prompt)"
|
48 |
-
}
|
49 |
-
},
|
50 |
-
"7": {
|
51 |
-
"inputs": {
|
52 |
-
"text": "text, watermark",
|
53 |
-
"clip": ["4", 1]
|
54 |
-
},
|
55 |
-
"class_type": "CLIPTextEncode",
|
56 |
-
"_meta": {
|
57 |
-
"title": "CLIP Text Encode (Prompt)"
|
58 |
-
}
|
59 |
-
},
|
60 |
-
"8": {
|
61 |
-
"inputs": {
|
62 |
-
"samples": ["3", 0],
|
63 |
-
"vae": ["4", 2]
|
64 |
-
},
|
65 |
-
"class_type": "VAEDecode",
|
66 |
-
"_meta": {
|
67 |
-
"title": "VAE Decode"
|
68 |
-
}
|
69 |
-
},
|
70 |
-
"9": {
|
71 |
-
"inputs": {
|
72 |
-
"filename_prefix": "ComfyUI",
|
73 |
-
"images": ["8", 0]
|
74 |
-
},
|
75 |
-
"class_type": "SaveImage",
|
76 |
-
"_meta": {
|
77 |
-
"title": "Save Image"
|
78 |
-
}
|
79 |
-
}
|
80 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app/embed/embed.tsx
CHANGED
@@ -23,7 +23,7 @@ export function Embed() {
|
|
23 |
<div
|
24 |
ref={ref}
|
25 |
className={cn(
|
26 |
-
`dark fixed flex h-screen w-screen select-none flex-col items-center justify-center overflow-hidden font-light text-
|
27 |
)}
|
28 |
style={{ backgroundImage: theme.wallpaperBgImage }}
|
29 |
>
|
|
|
23 |
<div
|
24 |
ref={ref}
|
25 |
className={cn(
|
26 |
+
`dark fixed flex h-screen w-screen select-none flex-col items-center justify-center overflow-hidden font-light text-neutral-900/90 dark:text-neutral-100/90`
|
27 |
)}
|
28 |
style={{ backgroundImage: theme.wallpaperBgImage }}
|
29 |
>
|
src/app/main.tsx
CHANGED
@@ -6,6 +6,7 @@ import { useSearchParams } from 'next/navigation'
|
|
6 |
import { DndProvider, useDrop } from 'react-dnd'
|
7 |
import { HTML5Backend, NativeTypes } from 'react-dnd-html5-backend'
|
8 |
import { UIWindowLayout } from '@aitube/clapper-services'
|
|
|
9 |
|
10 |
import { Toaster } from '@/components/ui/sonner'
|
11 |
import { cn } from '@/lib/utils'
|
@@ -14,12 +15,10 @@ import { Monitor } from '@/components/monitor'
|
|
14 |
|
15 |
import { SettingsDialog } from '@/components/settings'
|
16 |
import { LoadingDialog } from '@/components/dialogs/loader/LoadingDialog'
|
17 |
-
import { useUI, useIO } from '@/services'
|
18 |
import { TopBar } from '@/components/toolbars/top-bar'
|
19 |
import { Timeline } from '@/components/core/timeline'
|
20 |
import { ChatView } from '@/components/assistant/ChatView'
|
21 |
import { Editors } from '@/components/editors/Editors'
|
22 |
-
import { useTheme } from '@/services/ui/useTheme'
|
23 |
import { BottomToolbar } from '@/components/toolbars/bottom-bar'
|
24 |
import { FruityDesktop, FruityWindow } from '@/components/windows'
|
25 |
import { ScriptEditor } from '@/components/editors/ScriptEditor'
|
@@ -27,7 +26,10 @@ import { SegmentEditor } from '@/components/editors/SegmentEditor'
|
|
27 |
import { EntityEditor } from '@/components/editors/EntityEditor'
|
28 |
import { WorkflowEditor } from '@/components/editors/WorkflowEditor'
|
29 |
import { FilterEditor } from '@/components/editors/FilterEditor'
|
|
|
|
|
30 |
import { useRenderLoop } from '@/services/renderer'
|
|
|
31 |
|
32 |
type DroppableThing = { files: File[] }
|
33 |
|
@@ -47,6 +49,10 @@ function MainContent() {
|
|
47 |
// perform its routine even when the monitor component is hidden
|
48 |
useRenderLoop()
|
49 |
|
|
|
|
|
|
|
|
|
50 |
const [{ isOver, canDrop }, connectFileDrop] = useDrop({
|
51 |
accept: [NativeTypes.FILE],
|
52 |
drop: (item: DroppableThing): void => {
|
@@ -229,7 +235,7 @@ function MainContent() {
|
|
229 |
: 'pointer-events-none hidden',
|
230 |
`fixed top-9 h-[calc(100vh-36px)] w-screen flex-row overflow-hidden`,
|
231 |
`items-center justify-center`,
|
232 |
-
`bg-
|
233 |
)}
|
234 |
>
|
235 |
<div
|
@@ -310,11 +316,24 @@ function MainContent() {
|
|
310 |
)
|
311 |
}
|
312 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
export function Main() {
|
314 |
return (
|
315 |
<TooltipProvider>
|
316 |
<DndProvider backend={HTML5Backend}>
|
317 |
-
<
|
|
|
|
|
318 |
</DndProvider>
|
319 |
</TooltipProvider>
|
320 |
)
|
|
|
6 |
import { DndProvider, useDrop } from 'react-dnd'
|
7 |
import { HTML5Backend, NativeTypes } from 'react-dnd-html5-backend'
|
8 |
import { UIWindowLayout } from '@aitube/clapper-services'
|
9 |
+
import { ErrorBoundary, FallbackProps } from 'react-error-boundary'
|
10 |
|
11 |
import { Toaster } from '@/components/ui/sonner'
|
12 |
import { cn } from '@/lib/utils'
|
|
|
15 |
|
16 |
import { SettingsDialog } from '@/components/settings'
|
17 |
import { LoadingDialog } from '@/components/dialogs/loader/LoadingDialog'
|
|
|
18 |
import { TopBar } from '@/components/toolbars/top-bar'
|
19 |
import { Timeline } from '@/components/core/timeline'
|
20 |
import { ChatView } from '@/components/assistant/ChatView'
|
21 |
import { Editors } from '@/components/editors/Editors'
|
|
|
22 |
import { BottomToolbar } from '@/components/toolbars/bottom-bar'
|
23 |
import { FruityDesktop, FruityWindow } from '@/components/windows'
|
24 |
import { ScriptEditor } from '@/components/editors/ScriptEditor'
|
|
|
26 |
import { EntityEditor } from '@/components/editors/EntityEditor'
|
27 |
import { WorkflowEditor } from '@/components/editors/WorkflowEditor'
|
28 |
import { FilterEditor } from '@/components/editors/FilterEditor'
|
29 |
+
|
30 |
+
import { useUI, useIO, useTheme } from '@/services'
|
31 |
import { useRenderLoop } from '@/services/renderer'
|
32 |
+
import { useDynamicWorkflows } from '@/services/editors/workflow-editor/useDynamicWorkflows'
|
33 |
|
34 |
type DroppableThing = { files: File[] }
|
35 |
|
|
|
49 |
// perform its routine even when the monitor component is hidden
|
50 |
useRenderLoop()
|
51 |
|
52 |
+
// this has to be done at the root of the app, that way it can
|
53 |
+
// sync workflows even when the workflow component is hidden
|
54 |
+
useDynamicWorkflows()
|
55 |
+
|
56 |
const [{ isOver, canDrop }, connectFileDrop] = useDrop({
|
57 |
accept: [NativeTypes.FILE],
|
58 |
drop: (item: DroppableThing): void => {
|
|
|
235 |
: 'pointer-events-none hidden',
|
236 |
`fixed top-9 h-[calc(100vh-36px)] w-screen flex-row overflow-hidden`,
|
237 |
`items-center justify-center`,
|
238 |
+
`bg-neutral-950`
|
239 |
)}
|
240 |
>
|
241 |
<div
|
|
|
316 |
)
|
317 |
}
|
318 |
|
319 |
+
function fallbackRender({ error, resetErrorBoundary }: FallbackProps) {
|
320 |
+
// Call resetErrorBoundary() to reset the error boundary and retry the render.
|
321 |
+
|
322 |
+
return (
|
323 |
+
<div role="alert">
|
324 |
+
<p>Something went wrong:</p>
|
325 |
+
<pre style={{ color: 'red' }}>{error.message}</pre>
|
326 |
+
</div>
|
327 |
+
)
|
328 |
+
}
|
329 |
+
|
330 |
export function Main() {
|
331 |
return (
|
332 |
<TooltipProvider>
|
333 |
<DndProvider backend={HTML5Backend}>
|
334 |
+
<ErrorBoundary fallbackRender={fallbackRender}>
|
335 |
+
<MainContent />
|
336 |
+
</ErrorBoundary>
|
337 |
</DndProvider>
|
338 |
</TooltipProvider>
|
339 |
)
|
src/components/dialogs/iframe-warning/index.tsx
CHANGED
@@ -18,7 +18,7 @@ export function IframeWarning() {
|
|
18 |
return (
|
19 |
<div
|
20 |
className={cn(
|
21 |
-
`fixed bottom-0 left-0 right-0 top-0 z-[999] m-0 flex h-screen w-screen items-center justify-center overflow-hidden bg-
|
22 |
showWarning
|
23 |
? 'pointer-events-auto opacity-100'
|
24 |
: 'pointer-events-none opacity-0'
|
@@ -26,7 +26,7 @@ export function IframeWarning() {
|
|
26 |
style={{ backgroundImage: theme.wallpaperBgImage }}
|
27 |
>
|
28 |
<p
|
29 |
-
className={cn('font-sans text-
|
30 |
style={{ textShadow: '#000 1px 0 3px' }}
|
31 |
>
|
32 |
<span className="text-[2vw] font-thin">
|
|
|
18 |
return (
|
19 |
<div
|
20 |
className={cn(
|
21 |
+
`fixed bottom-0 left-0 right-0 top-0 z-[999] m-0 flex h-screen w-screen items-center justify-center overflow-hidden bg-neutral-950 p-0 text-center`,
|
22 |
showWarning
|
23 |
? 'pointer-events-auto opacity-100'
|
24 |
: 'pointer-events-none opacity-0'
|
|
|
26 |
style={{ backgroundImage: theme.wallpaperBgImage }}
|
27 |
>
|
28 |
<p
|
29 |
+
className={cn('font-sans text-neutral-100')}
|
30 |
style={{ textShadow: '#000 1px 0 3px' }}
|
31 |
>
|
32 |
<span className="text-[2vw] font-thin">
|
src/components/dialogs/loader/index.tsx
CHANGED
@@ -27,7 +27,7 @@ export function DeprecatedLoader({
|
|
27 |
)}
|
28 |
>
|
29 |
<p
|
30 |
-
className={cn('font-sans text-[3vw] font-thin text-
|
31 |
style={{ textShadow: '#000 1px 0 3px' }}
|
32 |
>
|
33 |
<span className="">Loading..</span>
|
|
|
27 |
)}
|
28 |
>
|
29 |
<p
|
30 |
+
className={cn('font-sans text-[3vw] font-thin text-neutral-100')}
|
31 |
style={{ textShadow: '#000 1px 0 3px' }}
|
32 |
>
|
33 |
<span className="">Loading..</span>
|
src/components/forms/FormSection.tsx
CHANGED
@@ -15,7 +15,7 @@ export function FormSection({
|
|
15 |
<div
|
16 |
className={cn(
|
17 |
'@container', // so that inputs can use container queries
|
18 |
-
`flex h-full w-full flex-col space-y-2 overflow-y-scroll scrollbar scrollbar-track-
|
19 |
className
|
20 |
)}
|
21 |
>
|
|
|
15 |
<div
|
16 |
className={cn(
|
17 |
'@container', // so that inputs can use container queries
|
18 |
+
`flex h-full w-full flex-col space-y-2 overflow-y-scroll scrollbar scrollbar-track-neutral-300 scrollbar-thumb-neutral-700 scrollbar-corner-neutral-500`,
|
19 |
className
|
20 |
)}
|
21 |
>
|
src/components/mobile/MobileMenu.tsx
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {
|
2 |
+
Sheet,
|
3 |
+
SheetContent,
|
4 |
+
SheetDescription,
|
5 |
+
SheetHeader,
|
6 |
+
SheetTitle,
|
7 |
+
SheetTrigger,
|
8 |
+
} from '@/components/ui/sheet'
|
9 |
+
|
10 |
+
export function MobileMenu() {
|
11 |
+
return (
|
12 |
+
<Sheet>
|
13 |
+
<SheetTrigger>Open</SheetTrigger>
|
14 |
+
<SheetContent>
|
15 |
+
<SheetHeader>
|
16 |
+
<SheetTitle>Clapper</SheetTitle>
|
17 |
+
<SheetDescription>
|
18 |
+
TODO JULIAN: we need a way to display the hierarchical menu on
|
19 |
+
mobile
|
20 |
+
</SheetDescription>
|
21 |
+
</SheetHeader>
|
22 |
+
</SheetContent>
|
23 |
+
</Sheet>
|
24 |
+
)
|
25 |
+
}
|
src/components/monitor/StaticPlayer/index.tsx
CHANGED
@@ -54,7 +54,7 @@ export function StaticPlayer(
|
|
54 |
}, [setStaticVideoRef])
|
55 |
|
56 |
const placeholder = (
|
57 |
-
<div className="text-center text-base text-
|
58 |
{error ? <span>{error}</span> : <span>No video yet</span>}
|
59 |
</div>
|
60 |
)
|
@@ -85,7 +85,7 @@ export function StaticPlayer(
|
|
85 |
// autoPlay
|
86 |
// muted
|
87 |
loop
|
88 |
-
className="h-full rounded-lg border border-
|
89 |
style={{}}
|
90 |
/>
|
91 |
) : (
|
|
|
54 |
}, [setStaticVideoRef])
|
55 |
|
56 |
const placeholder = (
|
57 |
+
<div className="text-center text-base text-neutral-50/90 dark:text-neutral-50/90">
|
58 |
{error ? <span>{error}</span> : <span>No video yet</span>}
|
59 |
</div>
|
60 |
)
|
|
|
85 |
// autoPlay
|
86 |
// muted
|
87 |
loop
|
88 |
+
className="h-full rounded-lg border border-neutral-950 object-cover"
|
89 |
style={{}}
|
90 |
/>
|
91 |
) : (
|
src/components/settings/index.tsx
CHANGED
@@ -67,7 +67,7 @@ export function SettingsDialog() {
|
|
67 |
<Button
|
68 |
key={key}
|
69 |
variant="ghost"
|
70 |
-
className="flex w-full flex-col items-end text-right text-lg font-thin capitalize text-
|
71 |
onClick={() => setShowSettings(key as SettingsCategory)}
|
72 |
>
|
73 |
{panelLabels[key]}
|
@@ -76,14 +76,14 @@ export function SettingsDialog() {
|
|
76 |
</div>
|
77 |
</ScrollArea>
|
78 |
|
79 |
-
<div className="flex h-full max-w-[calc(100%-150px)] flex-grow select-none flex-col justify-between border-l border-
|
80 |
<ScrollArea className="flex h-full flex-row">
|
81 |
{panels[showSettings]}
|
82 |
</ScrollArea>
|
83 |
<DialogFooter>
|
84 |
<Button
|
85 |
variant="outline"
|
86 |
-
className="text-sm font-light dark:border-
|
87 |
onClick={() => {
|
88 |
setShowSettings(SettingsCategory.NONE)
|
89 |
}}
|
|
|
67 |
<Button
|
68 |
key={key}
|
69 |
variant="ghost"
|
70 |
+
className="flex w-full flex-col items-end text-right text-lg font-thin capitalize text-neutral-300"
|
71 |
onClick={() => setShowSettings(key as SettingsCategory)}
|
72 |
>
|
73 |
{panelLabels[key]}
|
|
|
76 |
</div>
|
77 |
</ScrollArea>
|
78 |
|
79 |
+
<div className="flex h-full max-w-[calc(100%-150px)] flex-grow select-none flex-col justify-between border-l border-neutral-800 pl-8">
|
80 |
<ScrollArea className="flex h-full flex-row">
|
81 |
{panels[showSettings]}
|
82 |
</ScrollArea>
|
83 |
<DialogFooter>
|
84 |
<Button
|
85 |
variant="outline"
|
86 |
+
className="text-sm font-light dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-400"
|
87 |
onClick={() => {
|
88 |
setShowSettings(SettingsCategory.NONE)
|
89 |
}}
|
src/components/settings/provider.tsx
CHANGED
@@ -17,7 +17,7 @@ function GetItHere({ href, children }: { href: string; children: ReactNode }) {
|
|
17 |
<span>
|
18 |
{children} (
|
19 |
<a
|
20 |
-
className="text-
|
21 |
href={href}
|
22 |
target="_blank"
|
23 |
>
|
@@ -42,6 +42,14 @@ export function SettingsSectionProvider() {
|
|
42 |
const comfyUiClientId = useSettings((s) => s.comfyUiClientId)
|
43 |
const setComfyUiClientId = useSettings((s) => s.setComfyUiClientId)
|
44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
const comfyIcuApiKey = useSettings((s) => s.comfyIcuApiKey)
|
46 |
const setComfyIcuApiKey = useSettings((s) => s.setComfyIcuApiKey)
|
47 |
|
@@ -89,7 +97,7 @@ export function SettingsSectionProvider() {
|
|
89 |
return (
|
90 |
<div className="flex flex-col justify-between space-y-6">
|
91 |
<FormSection label="Compute providers">
|
92 |
-
<p className="max-w-80 text-sm italic text-
|
93 |
Note: preferences and credentials are stored inside your browser local
|
94 |
storage.
|
95 |
<br />
|
@@ -135,6 +143,22 @@ export function SettingsSectionProvider() {
|
|
135 |
type="text"
|
136 |
/>
|
137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
<FormInput
|
139 |
label="Comfy.icu API key"
|
140 |
value={comfyIcuApiKey}
|
|
|
17 |
<span>
|
18 |
{children} (
|
19 |
<a
|
20 |
+
className="text-neutral-500 underline hover:text-neutral-400"
|
21 |
href={href}
|
22 |
target="_blank"
|
23 |
>
|
|
|
42 |
const comfyUiClientId = useSettings((s) => s.comfyUiClientId)
|
43 |
const setComfyUiClientId = useSettings((s) => s.setComfyUiClientId)
|
44 |
|
45 |
+
const comfyUiHttpAuthLogin = useSettings((s) => s.comfyUiHttpAuthLogin)
|
46 |
+
const setComfyUiHttpAuthLogin = useSettings((s) => s.setComfyUiHttpAuthLogin)
|
47 |
+
|
48 |
+
const comfyUiHttpAuthPassword = useSettings((s) => s.comfyUiHttpAuthPassword)
|
49 |
+
const setComfyUiHttpAuthPassword = useSettings(
|
50 |
+
(s) => s.setComfyUiHttpAuthPassword
|
51 |
+
)
|
52 |
+
|
53 |
const comfyIcuApiKey = useSettings((s) => s.comfyIcuApiKey)
|
54 |
const setComfyIcuApiKey = useSettings((s) => s.setComfyIcuApiKey)
|
55 |
|
|
|
97 |
return (
|
98 |
<div className="flex flex-col justify-between space-y-6">
|
99 |
<FormSection label="Compute providers">
|
100 |
+
<p className="max-w-80 text-sm italic text-neutral-500">
|
101 |
Note: preferences and credentials are stored inside your browser local
|
102 |
storage.
|
103 |
<br />
|
|
|
143 |
type="text"
|
144 |
/>
|
145 |
|
146 |
+
<FormInput
|
147 |
+
label="ComfyUI HTTP Auth login (optional)"
|
148 |
+
value={comfyUiHttpAuthLogin}
|
149 |
+
defaultValue={defaultSettings.comfyUiHttpAuthLogin}
|
150 |
+
onChange={setComfyUiHttpAuthLogin}
|
151 |
+
type="text"
|
152 |
+
/>
|
153 |
+
|
154 |
+
<FormInput
|
155 |
+
label="ComfyUI HTTP Auth password (optional)"
|
156 |
+
value={comfyUiHttpAuthPassword}
|
157 |
+
defaultValue={defaultSettings.comfyUiHttpAuthPassword}
|
158 |
+
onChange={setComfyUiHttpAuthPassword}
|
159 |
+
type={apiKeyType}
|
160 |
+
/>
|
161 |
+
|
162 |
<FormInput
|
163 |
label="Comfy.icu API key"
|
164 |
value={comfyIcuApiKey}
|
src/components/tags/colors.ts
CHANGED
@@ -14,7 +14,7 @@ export const tagColorToTailwindClass: Record<TagColor, string> = {
|
|
14 |
[TagColor.GRAY]: `bg-gray-800 border-gray-600 text-gray-300`,
|
15 |
[TagColor.ZINC]: `bg-zinc-800 border-zinc-600 text-zinc-300`,
|
16 |
[TagColor.NEUTRAL]: `bg-neutral-800 border-neutral-600 text-neutral-300`,
|
17 |
-
[TagColor.STONE]: `bg-
|
18 |
[TagColor.RED]: `bg-red-800 border-red-600 text-red-300`,
|
19 |
[TagColor.ORANGE]: `bg-orange-800 border-orange-600 text-orange-300`,
|
20 |
[TagColor.AMBER]: `bg-amber-800 border-amber-600 text-amber-300`,
|
|
|
14 |
[TagColor.GRAY]: `bg-gray-800 border-gray-600 text-gray-300`,
|
15 |
[TagColor.ZINC]: `bg-zinc-800 border-zinc-600 text-zinc-300`,
|
16 |
[TagColor.NEUTRAL]: `bg-neutral-800 border-neutral-600 text-neutral-300`,
|
17 |
+
[TagColor.STONE]: `bg-neutral-800 border-neutral-600 text-neutral-300`,
|
18 |
[TagColor.RED]: `bg-red-800 border-red-600 text-red-300`,
|
19 |
[TagColor.ORANGE]: `bg-orange-800 border-orange-600 text-orange-300`,
|
20 |
[TagColor.AMBER]: `bg-amber-800 border-amber-600 text-amber-300`,
|
src/components/toolbars/bottom-bar/metrics/index.tsx
CHANGED
@@ -13,8 +13,8 @@ export function Metrics() {
|
|
13 |
|
14 |
return (
|
15 |
<div className="flex flex-row space-x-1">
|
16 |
-
<span className="text-
|
17 |
-
<span className="text-
|
18 |
{!bytes ? 'waiting..' : humanReadableString || ''}
|
19 |
</span>
|
20 |
</div>
|
|
|
13 |
|
14 |
return (
|
15 |
<div className="flex flex-row space-x-1">
|
16 |
+
<span className="text-neutral-500">memory usage:</span>
|
17 |
+
<span className="text-neutral-400">
|
18 |
{!bytes ? 'waiting..' : humanReadableString || ''}
|
19 |
</span>
|
20 |
</div>
|
src/components/toolbars/editors-menu/EditorsSideMenuItem.tsx
CHANGED
@@ -63,8 +63,8 @@ export function EditorsSideMenuItem({
|
|
63 |
unmanaged || isActive ? '' : `cursor-pointer`,
|
64 |
`border-l-[2px]`,
|
65 |
isActive
|
66 |
-
? 'fill-
|
67 |
-
: 'fill-
|
68 |
`group`
|
69 |
)}
|
70 |
style={{
|
|
|
63 |
unmanaged || isActive ? '' : `cursor-pointer`,
|
64 |
`border-l-[2px]`,
|
65 |
isActive
|
66 |
+
? 'fill-neutral-50/80 text-neutral-50 opacity-100 hover:fill-neutral-50 hover:text-neutral-50'
|
67 |
+
: 'fill-neutral-400/80 text-gray-400 opacity-80 hover:fill-neutral-200 hover:text-neutral-200 hover:opacity-100',
|
68 |
`group`
|
69 |
)}
|
70 |
style={{
|
src/components/toolbars/system-menu/index.tsx
CHANGED
@@ -23,7 +23,7 @@ const Menubar = React.forwardRef<
|
|
23 |
<MenubarPrimitive.Root
|
24 |
ref={ref}
|
25 |
className={cn(
|
26 |
-
'border-bottom flex h-9 items-center space-x-1 rounded-md border-
|
27 |
className
|
28 |
)}
|
29 |
{...props}
|
@@ -38,7 +38,7 @@ const MenubarTrigger = React.forwardRef<
|
|
38 |
<MenubarPrimitive.Trigger
|
39 |
ref={ref}
|
40 |
className={cn(
|
41 |
-
'flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-light outline-none data-[state=open]:bg-
|
42 |
className
|
43 |
)}
|
44 |
{...props}
|
@@ -55,7 +55,7 @@ const MenubarSubTrigger = React.forwardRef<
|
|
55 |
<MenubarPrimitive.SubTrigger
|
56 |
ref={ref}
|
57 |
className={cn(
|
58 |
-
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-
|
59 |
inset && 'pl-8',
|
60 |
className
|
61 |
)}
|
@@ -74,7 +74,7 @@ const MenubarSubContent = React.forwardRef<
|
|
74 |
<MenubarPrimitive.SubContent
|
75 |
ref={ref}
|
76 |
className={cn(
|
77 |
-
'z-50 min-w-[8rem] overflow-hidden rounded-md border-transparent bg-white p-1 text-
|
78 |
className
|
79 |
)}
|
80 |
{...props}
|
@@ -97,7 +97,7 @@ const MenubarContent = React.forwardRef<
|
|
97 |
alignOffset={alignOffset}
|
98 |
sideOffset={sideOffset}
|
99 |
className={cn(
|
100 |
-
'z-50 min-w-[12rem] overflow-hidden rounded-md border border-
|
101 |
className
|
102 |
)}
|
103 |
{...props}
|
@@ -116,7 +116,7 @@ const MenubarItem = React.forwardRef<
|
|
116 |
<MenubarPrimitive.Item
|
117 |
ref={ref}
|
118 |
className={cn(
|
119 |
-
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-
|
120 |
inset && 'pl-8',
|
121 |
className
|
122 |
)}
|
@@ -132,7 +132,7 @@ const MenubarCheckboxItem = React.forwardRef<
|
|
132 |
<MenubarPrimitive.CheckboxItem
|
133 |
ref={ref}
|
134 |
className={cn(
|
135 |
-
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-
|
136 |
className
|
137 |
)}
|
138 |
checked={checked}
|
@@ -155,7 +155,7 @@ const MenubarRadioItem = React.forwardRef<
|
|
155 |
<MenubarPrimitive.RadioItem
|
156 |
ref={ref}
|
157 |
className={cn(
|
158 |
-
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-
|
159 |
className
|
160 |
)}
|
161 |
{...props}
|
@@ -194,7 +194,10 @@ const MenubarSeparator = React.forwardRef<
|
|
194 |
>(({ className, ...props }, ref) => (
|
195 |
<MenubarPrimitive.Separator
|
196 |
ref={ref}
|
197 |
-
className={cn(
|
|
|
|
|
|
|
198 |
{...props}
|
199 |
/>
|
200 |
))
|
@@ -207,7 +210,7 @@ const MenubarShortcut = ({
|
|
207 |
return (
|
208 |
<span
|
209 |
className={cn(
|
210 |
-
'ml-auto text-xs tracking-widest text-
|
211 |
className
|
212 |
)}
|
213 |
{...props}
|
|
|
23 |
<MenubarPrimitive.Root
|
24 |
ref={ref}
|
25 |
className={cn(
|
26 |
+
'border-bottom flex h-9 items-center space-x-1 rounded-md border-neutral-800 bg-white p-1 dark:border-neutral-800 dark:bg-neutral-800',
|
27 |
className
|
28 |
)}
|
29 |
{...props}
|
|
|
38 |
<MenubarPrimitive.Trigger
|
39 |
ref={ref}
|
40 |
className={cn(
|
41 |
+
'flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-light outline-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-900 focus:bg-neutral-100 focus:text-neutral-900 dark:data-[state=open]:bg-neutral-700 dark:data-[state=open]:text-neutral-50 dark:focus:bg-neutral-700 dark:focus:text-neutral-50',
|
42 |
className
|
43 |
)}
|
44 |
{...props}
|
|
|
55 |
<MenubarPrimitive.SubTrigger
|
56 |
ref={ref}
|
57 |
className={cn(
|
58 |
+
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-900 focus:bg-neutral-100 focus:text-neutral-900 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-100 dark:focus:bg-neutral-700 dark:focus:text-neutral-50',
|
59 |
inset && 'pl-8',
|
60 |
className
|
61 |
)}
|
|
|
74 |
<MenubarPrimitive.SubContent
|
75 |
ref={ref}
|
76 |
className={cn(
|
77 |
+
'z-50 min-w-[8rem] overflow-hidden rounded-md border-transparent bg-white p-1 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 dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-100',
|
78 |
className
|
79 |
)}
|
80 |
{...props}
|
|
|
97 |
alignOffset={alignOffset}
|
98 |
sideOffset={sideOffset}
|
99 |
className={cn(
|
100 |
+
'z-50 min-w-[12rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-md data-[state=open]:animate-in 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 dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-100',
|
101 |
className
|
102 |
)}
|
103 |
{...props}
|
|
|
116 |
<MenubarPrimitive.Item
|
117 |
ref={ref}
|
118 |
className={cn(
|
119 |
+
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-neutral-100 focus:text-neutral-900 dark:focus:bg-neutral-700 dark:focus:text-neutral-50',
|
120 |
inset && 'pl-8',
|
121 |
className
|
122 |
)}
|
|
|
132 |
<MenubarPrimitive.CheckboxItem
|
133 |
ref={ref}
|
134 |
className={cn(
|
135 |
+
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-neutral-100 focus:text-neutral-900 dark:focus:bg-neutral-700 dark:focus:text-neutral-100',
|
136 |
className
|
137 |
)}
|
138 |
checked={checked}
|
|
|
155 |
<MenubarPrimitive.RadioItem
|
156 |
ref={ref}
|
157 |
className={cn(
|
158 |
+
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-neutral-100 focus:text-neutral-900 dark:focus:bg-neutral-700 dark:focus:text-neutral-100',
|
159 |
className
|
160 |
)}
|
161 |
{...props}
|
|
|
194 |
>(({ className, ...props }, ref) => (
|
195 |
<MenubarPrimitive.Separator
|
196 |
ref={ref}
|
197 |
+
className={cn(
|
198 |
+
'-mx-1 my-1 h-px bg-neutral-100 dark:bg-neutral-700',
|
199 |
+
className
|
200 |
+
)}
|
201 |
{...props}
|
202 |
/>
|
203 |
))
|
|
|
210 |
return (
|
211 |
<span
|
212 |
className={cn(
|
213 |
+
'ml-auto text-xs tracking-widest text-neutral-500 dark:text-neutral-400',
|
214 |
className
|
215 |
)}
|
216 |
{...props}
|
src/components/toolbars/top-menu/ToggleView/index.tsx
CHANGED
@@ -31,7 +31,7 @@ export function ToggleView({
|
|
31 |
>
|
32 |
<div
|
33 |
className={cn(
|
34 |
-
`flex transition-all duration-200 ease-in-out group-hover:scale-110 group-hover:border-
|
35 |
isVisible
|
36 |
? `border-neutral-100 bg-neutral-400`
|
37 |
: `border-neutral-400`,
|
|
|
31 |
>
|
32 |
<div
|
33 |
className={cn(
|
34 |
+
`flex transition-all duration-200 ease-in-out group-hover:scale-110 group-hover:border-neutral-100`,
|
35 |
isVisible
|
36 |
? `border-neutral-100 bg-neutral-400`
|
37 |
: `border-neutral-400`,
|
src/components/toolbars/top-menu/index.tsx
CHANGED
@@ -143,7 +143,7 @@ export function TopMenu() {
|
|
143 |
|
144 |
<Tooltip>
|
145 |
<TooltipTrigger className="">
|
146 |
-
<div className="ml-2 scale-100 cursor-pointer text-
|
147 |
<a href="https://discord.gg/AEruz9B92B" target='"_blank'>
|
148 |
<TbBrandDiscord className="h-4 w-4" />
|
149 |
</a>
|
@@ -156,7 +156,7 @@ export function TopMenu() {
|
|
156 |
|
157 |
<Tooltip>
|
158 |
<TooltipTrigger className="">
|
159 |
-
<div className="scale-100 cursor-pointer text-
|
160 |
<a href="https://github.com/jbilcke-hf/clapper" target='"_blank'>
|
161 |
<FaGithubAlt className="h-4 w-4" />
|
162 |
</a>
|
|
|
143 |
|
144 |
<Tooltip>
|
145 |
<TooltipTrigger className="">
|
146 |
+
<div className="ml-2 scale-100 cursor-pointer text-neutral-300/70 transition-all duration-200 ease-in-out hover:scale-110 hover:text-neutral-100/90">
|
147 |
<a href="https://discord.gg/AEruz9B92B" target='"_blank'>
|
148 |
<TbBrandDiscord className="h-4 w-4" />
|
149 |
</a>
|
|
|
156 |
|
157 |
<Tooltip>
|
158 |
<TooltipTrigger className="">
|
159 |
+
<div className="scale-100 cursor-pointer text-neutral-300/70 transition-all duration-200 ease-in-out hover:scale-110 hover:text-neutral-100/90">
|
160 |
<a href="https://github.com/jbilcke-hf/clapper" target='"_blank'>
|
161 |
<FaGithubAlt className="h-4 w-4" />
|
162 |
</a>
|
src/components/ui/alert.tsx
CHANGED
@@ -4,11 +4,12 @@ import { cva, type VariantProps } from 'class-variance-authority'
|
|
4 |
import { cn } from '@/lib/utils/cn'
|
5 |
|
6 |
const alertVariants = cva(
|
7 |
-
'relative w-full rounded-lg border border-
|
8 |
{
|
9 |
variants: {
|
10 |
variant: {
|
11 |
-
default:
|
|
|
12 |
destructive:
|
13 |
'border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900',
|
14 |
},
|
|
|
4 |
import { cn } from '@/lib/utils/cn'
|
5 |
|
6 |
const alertVariants = cva(
|
7 |
+
'relative w-full rounded-lg border border-neutral-200 p-4 [&:has(svg)]:pl-11 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-neutral-950 dark:border-neutral-800 dark:[&>svg]:text-neutral-50',
|
8 |
{
|
9 |
variants: {
|
10 |
variant: {
|
11 |
+
default:
|
12 |
+
'bg-white text-neutral-950 dark:bg-neutral-950 dark:text-neutral-50',
|
13 |
destructive:
|
14 |
'border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900',
|
15 |
},
|
src/components/ui/avatar.tsx
CHANGED
@@ -39,7 +39,7 @@ const AvatarFallback = React.forwardRef<
|
|
39 |
<AvatarPrimitive.Fallback
|
40 |
ref={ref}
|
41 |
className={cn(
|
42 |
-
'flex h-full w-full items-center justify-center rounded-full bg-
|
43 |
className
|
44 |
)}
|
45 |
{...props}
|
|
|
39 |
<AvatarPrimitive.Fallback
|
40 |
ref={ref}
|
41 |
className={cn(
|
42 |
+
'flex h-full w-full items-center justify-center rounded-full bg-neutral-100 dark:bg-neutral-800',
|
43 |
className
|
44 |
)}
|
45 |
{...props}
|
src/components/ui/badge.tsx
CHANGED
@@ -4,17 +4,17 @@ import { cva, type VariantProps } from 'class-variance-authority'
|
|
4 |
import { cn } from '@/lib/utils/cn'
|
5 |
|
6 |
const badgeVariants = cva(
|
7 |
-
'inline-flex items-center rounded-full border border-
|
8 |
{
|
9 |
variants: {
|
10 |
variant: {
|
11 |
default:
|
12 |
-
'border-transparent bg-
|
13 |
secondary:
|
14 |
-
'border-transparent bg-
|
15 |
destructive:
|
16 |
-
'border-transparent bg-red-500 text-
|
17 |
-
outline: 'text-
|
18 |
},
|
19 |
},
|
20 |
defaultVariants: {
|
|
|
4 |
import { cn } from '@/lib/utils/cn'
|
5 |
|
6 |
const badgeVariants = cva(
|
7 |
+
'inline-flex items-center rounded-full border border-neutral-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-neutral-400 focus:ring-offset-2 dark:border-neutral-800 dark:focus:ring-neutral-800',
|
8 |
{
|
9 |
variants: {
|
10 |
variant: {
|
11 |
default:
|
12 |
+
'border-transparent bg-neutral-900 text-neutral-50 hover:bg-neutral-900/80 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/80',
|
13 |
secondary:
|
14 |
+
'border-transparent bg-neutral-100 text-neutral-900 hover:bg-neutral-100/80 dark:bg-neutral-800 dark:text-neutral-50 dark:hover:bg-neutral-800/80',
|
15 |
destructive:
|
16 |
+
'border-transparent bg-red-500 text-neutral-50 hover:bg-red-500/80 dark:bg-red-900 dark:text-red-50 dark:hover:bg-red-900/80',
|
17 |
+
outline: 'text-neutral-950 dark:text-neutral-50',
|
18 |
},
|
19 |
},
|
20 |
defaultVariants: {
|
src/components/ui/button.tsx
CHANGED
@@ -5,21 +5,21 @@ import { cva, type VariantProps } from 'class-variance-authority'
|
|
5 |
import { cn } from '@/lib/utils/cn'
|
6 |
|
7 |
const buttonVariants = cva(
|
8 |
-
'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-
|
9 |
{
|
10 |
variants: {
|
11 |
variant: {
|
12 |
default:
|
13 |
-
'bg-
|
14 |
destructive:
|
15 |
-
'bg-red-500 text-
|
16 |
outline:
|
17 |
-
'border border-
|
18 |
secondary:
|
19 |
-
'bg-
|
20 |
ghost:
|
21 |
-
'hover:bg-
|
22 |
-
link: 'text-
|
23 |
},
|
24 |
size: {
|
25 |
default: 'h-10 px-4 py-2',
|
|
|
5 |
import { cn } from '@/lib/utils/cn'
|
6 |
|
7 |
const buttonVariants = cva(
|
8 |
+
'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-neutral-950 dark:focus-visible:ring-neutral-800',
|
9 |
{
|
10 |
variants: {
|
11 |
variant: {
|
12 |
default:
|
13 |
+
'bg-neutral-900 text-neutral-50 hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90',
|
14 |
destructive:
|
15 |
+
'bg-red-500 text-neutral-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-red-50 dark:hover:bg-red-900/90',
|
16 |
outline:
|
17 |
+
'border border-neutral-200 bg-white hover:bg-neutral-100 hover:text-neutral-900 dark:border-neutral-800 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50',
|
18 |
secondary:
|
19 |
+
'bg-neutral-100 text-neutral-900 hover:bg-neutral-100/80 dark:bg-neutral-800 dark:text-neutral-50 dark:hover:bg-neutral-800/80',
|
20 |
ghost:
|
21 |
+
'hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-800 dark:hover:text-neutral-50',
|
22 |
+
link: 'text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50',
|
23 |
},
|
24 |
size: {
|
25 |
default: 'h-10 px-4 py-2',
|
src/components/ui/card.tsx
CHANGED
@@ -9,7 +9,7 @@ const Card = React.forwardRef<
|
|
9 |
<div
|
10 |
ref={ref}
|
11 |
className={cn(
|
12 |
-
'rounded-lg border border-
|
13 |
className
|
14 |
)}
|
15 |
{...props}
|
@@ -50,7 +50,7 @@ const CardDescription = React.forwardRef<
|
|
50 |
>(({ className, ...props }, ref) => (
|
51 |
<p
|
52 |
ref={ref}
|
53 |
-
className={cn('text-sm text-
|
54 |
{...props}
|
55 |
/>
|
56 |
))
|
|
|
9 |
<div
|
10 |
ref={ref}
|
11 |
className={cn(
|
12 |
+
'rounded-lg border border-neutral-200 bg-white text-neutral-950 shadow-sm dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50',
|
13 |
className
|
14 |
)}
|
15 |
{...props}
|
|
|
50 |
>(({ className, ...props }, ref) => (
|
51 |
<p
|
52 |
ref={ref}
|
53 |
+
className={cn('text-sm text-neutral-500 dark:text-neutral-400', className)}
|
54 |
{...props}
|
55 |
/>
|
56 |
))
|
src/components/ui/checkbox.tsx
CHANGED
@@ -13,7 +13,7 @@ const Checkbox = React.forwardRef<
|
|
13 |
<CheckboxPrimitive.Root
|
14 |
ref={ref}
|
15 |
className={cn(
|
16 |
-
'peer h-4 w-4 shrink-0 rounded-sm border border-
|
17 |
className
|
18 |
)}
|
19 |
{...props}
|
|
|
13 |
<CheckboxPrimitive.Root
|
14 |
ref={ref}
|
15 |
className={cn(
|
16 |
+
'peer h-4 w-4 shrink-0 rounded-sm border border-neutral-200 border-neutral-900 ring-offset-white data-[state=checked]:bg-neutral-900 data-[state=checked]:text-neutral-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-neutral-50 dark:border-neutral-800 dark:ring-offset-neutral-950 dark:data-[state=checked]:bg-neutral-50 dark:data-[state=checked]:text-neutral-900 dark:focus-visible:ring-neutral-800',
|
17 |
className
|
18 |
)}
|
19 |
{...props}
|
src/components/ui/command.tsx
CHANGED
@@ -15,7 +15,7 @@ const Command = React.forwardRef<
|
|
15 |
<CommandPrimitive
|
16 |
ref={ref}
|
17 |
className={cn(
|
18 |
-
'flex h-full w-full flex-col overflow-hidden rounded-md bg-white text-
|
19 |
className
|
20 |
)}
|
21 |
{...props}
|
@@ -29,7 +29,7 @@ const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
|
29 |
return (
|
30 |
<Dialog {...props}>
|
31 |
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
32 |
-
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-
|
33 |
{children}
|
34 |
</Command>
|
35 |
</DialogContent>
|
@@ -46,7 +46,7 @@ const CommandInput = React.forwardRef<
|
|
46 |
<CommandPrimitive.Input
|
47 |
ref={ref}
|
48 |
className={cn(
|
49 |
-
'flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-
|
50 |
className
|
51 |
)}
|
52 |
{...props}
|
@@ -89,7 +89,7 @@ const CommandGroup = React.forwardRef<
|
|
89 |
<CommandPrimitive.Group
|
90 |
ref={ref}
|
91 |
className={cn(
|
92 |
-
'overflow-hidden p-1 text-
|
93 |
className
|
94 |
)}
|
95 |
{...props}
|
@@ -104,7 +104,7 @@ const CommandSeparator = React.forwardRef<
|
|
104 |
>(({ className, ...props }, ref) => (
|
105 |
<CommandPrimitive.Separator
|
106 |
ref={ref}
|
107 |
-
className={cn('-mx-1 h-px bg-
|
108 |
{...props}
|
109 |
/>
|
110 |
))
|
@@ -117,7 +117,7 @@ const CommandItem = React.forwardRef<
|
|
117 |
<CommandPrimitive.Item
|
118 |
ref={ref}
|
119 |
className={cn(
|
120 |
-
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-
|
121 |
className
|
122 |
)}
|
123 |
{...props}
|
@@ -133,7 +133,7 @@ const CommandShortcut = ({
|
|
133 |
return (
|
134 |
<span
|
135 |
className={cn(
|
136 |
-
'ml-auto text-xs tracking-widest text-
|
137 |
className
|
138 |
)}
|
139 |
{...props}
|
|
|
15 |
<CommandPrimitive
|
16 |
ref={ref}
|
17 |
className={cn(
|
18 |
+
'flex h-full w-full flex-col overflow-hidden rounded-md bg-white text-neutral-950 dark:bg-neutral-950 dark:text-neutral-50',
|
19 |
className
|
20 |
)}
|
21 |
{...props}
|
|
|
29 |
return (
|
30 |
<Dialog {...props}>
|
31 |
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
32 |
+
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-neutral-500 dark:[&_[cmdk-group-heading]]:text-neutral-400 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
33 |
{children}
|
34 |
</Command>
|
35 |
</DialogContent>
|
|
|
46 |
<CommandPrimitive.Input
|
47 |
ref={ref}
|
48 |
className={cn(
|
49 |
+
'flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-neutral-500 disabled:cursor-not-allowed disabled:opacity-50 dark:placeholder:text-neutral-400',
|
50 |
className
|
51 |
)}
|
52 |
{...props}
|
|
|
89 |
<CommandPrimitive.Group
|
90 |
ref={ref}
|
91 |
className={cn(
|
92 |
+
'overflow-hidden p-1 text-neutral-950 dark:text-neutral-50 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-neutral-500 dark:[&_[cmdk-group-heading]]:text-neutral-400',
|
93 |
className
|
94 |
)}
|
95 |
{...props}
|
|
|
104 |
>(({ className, ...props }, ref) => (
|
105 |
<CommandPrimitive.Separator
|
106 |
ref={ref}
|
107 |
+
className={cn('-mx-1 h-px bg-neutral-200 dark:bg-neutral-800', className)}
|
108 |
{...props}
|
109 |
/>
|
110 |
))
|
|
|
117 |
<CommandPrimitive.Item
|
118 |
ref={ref}
|
119 |
className={cn(
|
120 |
+
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-neutral-100 aria-selected:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:aria-selected:bg-neutral-800 dark:aria-selected:text-neutral-50',
|
121 |
className
|
122 |
)}
|
123 |
{...props}
|
|
|
133 |
return (
|
134 |
<span
|
135 |
className={cn(
|
136 |
+
'ml-auto text-xs tracking-widest text-neutral-500 dark:text-neutral-400',
|
137 |
className
|
138 |
)}
|
139 |
{...props}
|
src/components/ui/dialog.tsx
CHANGED
@@ -22,7 +22,7 @@ const DialogOverlay = React.forwardRef<
|
|
22 |
<DialogPrimitive.Overlay
|
23 |
ref={ref}
|
24 |
className={cn(
|
25 |
-
'fixed inset-0 z-50 blur-sm backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 dark:bg-
|
26 |
className
|
27 |
)}
|
28 |
{...props}
|
@@ -39,13 +39,13 @@ const DialogContent = React.forwardRef<
|
|
39 |
<DialogPrimitive.Content
|
40 |
ref={ref}
|
41 |
className={cn(
|
42 |
-
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-
|
43 |
className
|
44 |
)}
|
45 |
{...props}
|
46 |
>
|
47 |
{children}
|
48 |
-
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity data-[state=open]:bg-
|
49 |
<X className="h-4 w-4" />
|
50 |
<span className="sr-only">Close</span>
|
51 |
</DialogPrimitive.Close>
|
@@ -103,7 +103,7 @@ const DialogDescription = React.forwardRef<
|
|
103 |
>(({ className, ...props }, ref) => (
|
104 |
<DialogPrimitive.Description
|
105 |
ref={ref}
|
106 |
-
className={cn('text-sm text-
|
107 |
{...props}
|
108 |
/>
|
109 |
))
|
|
|
22 |
<DialogPrimitive.Overlay
|
23 |
ref={ref}
|
24 |
className={cn(
|
25 |
+
'fixed inset-0 z-50 blur-sm backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 dark:bg-neutral-900/50',
|
26 |
className
|
27 |
)}
|
28 |
{...props}
|
|
|
39 |
<DialogPrimitive.Content
|
40 |
ref={ref}
|
41 |
className={cn(
|
42 |
+
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-neutral-200 bg-white p-6 shadow-sm duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] dark:border-neutral-800 dark:bg-neutral-900 sm:rounded-lg md:w-full',
|
43 |
className
|
44 |
)}
|
45 |
{...props}
|
46 |
>
|
47 |
{children}
|
48 |
+
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-neutral-400 focus:ring-offset-2 disabled:pointer-events-none dark:ring-offset-neutral-950 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400 dark:focus:ring-neutral-800">
|
49 |
<X className="h-4 w-4" />
|
50 |
<span className="sr-only">Close</span>
|
51 |
</DialogPrimitive.Close>
|
|
|
103 |
>(({ className, ...props }, ref) => (
|
104 |
<DialogPrimitive.Description
|
105 |
ref={ref}
|
106 |
+
className={cn('text-sm text-neutral-500 dark:text-neutral-400', className)}
|
107 |
{...props}
|
108 |
/>
|
109 |
))
|
src/components/ui/dropdown-menu.tsx
CHANGED
@@ -27,7 +27,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
|
27 |
<DropdownMenuPrimitive.SubTrigger
|
28 |
ref={ref}
|
29 |
className={cn(
|
30 |
-
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-
|
31 |
inset && 'pl-8',
|
32 |
className
|
33 |
)}
|
@@ -47,7 +47,7 @@ const DropdownMenuSubContent = React.forwardRef<
|
|
47 |
<DropdownMenuPrimitive.SubContent
|
48 |
ref={ref}
|
49 |
className={cn(
|
50 |
-
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-
|
51 |
className
|
52 |
)}
|
53 |
{...props}
|
@@ -65,7 +65,7 @@ const DropdownMenuContent = React.forwardRef<
|
|
65 |
ref={ref}
|
66 |
sideOffset={sideOffset}
|
67 |
className={cn(
|
68 |
-
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-
|
69 |
className
|
70 |
)}
|
71 |
{...props}
|
@@ -83,7 +83,7 @@ const DropdownMenuItem = React.forwardRef<
|
|
83 |
<DropdownMenuPrimitive.Item
|
84 |
ref={ref}
|
85 |
className={cn(
|
86 |
-
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-
|
87 |
inset && 'pl-8',
|
88 |
className
|
89 |
)}
|
@@ -99,7 +99,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|
99 |
<DropdownMenuPrimitive.CheckboxItem
|
100 |
ref={ref}
|
101 |
className={cn(
|
102 |
-
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-
|
103 |
className
|
104 |
)}
|
105 |
checked={checked}
|
@@ -123,7 +123,7 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|
123 |
<DropdownMenuPrimitive.RadioItem
|
124 |
ref={ref}
|
125 |
className={cn(
|
126 |
-
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-
|
127 |
className
|
128 |
)}
|
129 |
{...props}
|
@@ -162,7 +162,10 @@ const DropdownMenuSeparator = React.forwardRef<
|
|
162 |
>(({ className, ...props }, ref) => (
|
163 |
<DropdownMenuPrimitive.Separator
|
164 |
ref={ref}
|
165 |
-
className={cn(
|
|
|
|
|
|
|
166 |
{...props}
|
167 |
/>
|
168 |
))
|
|
|
27 |
<DropdownMenuPrimitive.SubTrigger
|
28 |
ref={ref}
|
29 |
className={cn(
|
30 |
+
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-neutral-100 focus:bg-neutral-100 dark:data-[state=open]:bg-neutral-800 dark:focus:bg-neutral-800',
|
31 |
inset && 'pl-8',
|
32 |
className
|
33 |
)}
|
|
|
47 |
<DropdownMenuPrimitive.SubContent
|
48 |
ref={ref}
|
49 |
className={cn(
|
50 |
+
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-lg 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 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50',
|
51 |
className
|
52 |
)}
|
53 |
{...props}
|
|
|
65 |
ref={ref}
|
66 |
sideOffset={sideOffset}
|
67 |
className={cn(
|
68 |
+
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-md 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 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50',
|
69 |
className
|
70 |
)}
|
71 |
{...props}
|
|
|
83 |
<DropdownMenuPrimitive.Item
|
84 |
ref={ref}
|
85 |
className={cn(
|
86 |
+
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-neutral-100 focus:text-neutral-900 dark:focus:bg-neutral-800 dark:focus:text-neutral-50',
|
87 |
inset && 'pl-8',
|
88 |
className
|
89 |
)}
|
|
|
99 |
<DropdownMenuPrimitive.CheckboxItem
|
100 |
ref={ref}
|
101 |
className={cn(
|
102 |
+
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-neutral-100 focus:text-neutral-900 dark:focus:bg-neutral-800 dark:focus:text-neutral-50',
|
103 |
className
|
104 |
)}
|
105 |
checked={checked}
|
|
|
123 |
<DropdownMenuPrimitive.RadioItem
|
124 |
ref={ref}
|
125 |
className={cn(
|
126 |
+
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-neutral-100 focus:text-neutral-900 dark:focus:bg-neutral-800 dark:focus:text-neutral-50',
|
127 |
className
|
128 |
)}
|
129 |
{...props}
|
|
|
162 |
>(({ className, ...props }, ref) => (
|
163 |
<DropdownMenuPrimitive.Separator
|
164 |
ref={ref}
|
165 |
+
className={cn(
|
166 |
+
'-mx-1 my-1 h-px bg-neutral-100 dark:bg-neutral-800',
|
167 |
+
className
|
168 |
+
)}
|
169 |
{...props}
|
170 |
/>
|
171 |
))
|
src/components/ui/popover.tsx
CHANGED
@@ -19,7 +19,7 @@ const PopoverContent = React.forwardRef<
|
|
19 |
align={align}
|
20 |
sideOffset={sideOffset}
|
21 |
className={cn(
|
22 |
-
'z-50 w-72 rounded-md border border-
|
23 |
className
|
24 |
)}
|
25 |
{...props}
|
|
|
19 |
align={align}
|
20 |
sideOffset={sideOffset}
|
21 |
className={cn(
|
22 |
+
'z-50 w-72 rounded-md border border-neutral-200 bg-white p-4 text-neutral-950 shadow-md outline-none 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 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50',
|
23 |
className
|
24 |
)}
|
25 |
{...props}
|
src/components/ui/progress.tsx
CHANGED
@@ -12,13 +12,13 @@ const Progress = React.forwardRef<
|
|
12 |
<ProgressPrimitive.Root
|
13 |
ref={ref}
|
14 |
className={cn(
|
15 |
-
'relative h-4 w-full overflow-hidden rounded-full bg-
|
16 |
className
|
17 |
)}
|
18 |
{...props}
|
19 |
>
|
20 |
<ProgressPrimitive.Indicator
|
21 |
-
className="h-full w-full flex-1 bg-
|
22 |
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
23 |
/>
|
24 |
</ProgressPrimitive.Root>
|
|
|
12 |
<ProgressPrimitive.Root
|
13 |
ref={ref}
|
14 |
className={cn(
|
15 |
+
'relative h-4 w-full overflow-hidden rounded-full bg-neutral-100 dark:bg-neutral-800',
|
16 |
className
|
17 |
)}
|
18 |
{...props}
|
19 |
>
|
20 |
<ProgressPrimitive.Indicator
|
21 |
+
className="h-full w-full flex-1 bg-neutral-900 transition-all dark:bg-neutral-50"
|
22 |
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
23 |
/>
|
24 |
</ProgressPrimitive.Root>
|
src/components/ui/scroll-area.tsx
CHANGED
@@ -40,7 +40,7 @@ const ScrollBar = React.forwardRef<
|
|
40 |
)}
|
41 |
{...props}
|
42 |
>
|
43 |
-
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-
|
44 |
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
45 |
))
|
46 |
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
|
|
40 |
)}
|
41 |
{...props}
|
42 |
>
|
43 |
+
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-neutral-200 dark:bg-neutral-800" />
|
44 |
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
45 |
))
|
46 |
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
src/components/ui/select.tsx
CHANGED
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
|
|
19 |
<SelectPrimitive.Trigger
|
20 |
ref={ref}
|
21 |
className={cn(
|
22 |
-
'flex h-10 w-full items-center justify-between rounded-md border border-
|
23 |
className
|
24 |
)}
|
25 |
{...props}
|
@@ -40,7 +40,7 @@ const SelectContent = React.forwardRef<
|
|
40 |
<SelectPrimitive.Content
|
41 |
ref={ref}
|
42 |
className={cn(
|
43 |
-
'relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-
|
44 |
position === 'popper' &&
|
45 |
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
46 |
className
|
@@ -81,7 +81,7 @@ const SelectItem = React.forwardRef<
|
|
81 |
<SelectPrimitive.Item
|
82 |
ref={ref}
|
83 |
className={cn(
|
84 |
-
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-
|
85 |
className
|
86 |
)}
|
87 |
{...props}
|
@@ -103,7 +103,10 @@ const SelectSeparator = React.forwardRef<
|
|
103 |
>(({ className, ...props }, ref) => (
|
104 |
<SelectPrimitive.Separator
|
105 |
ref={ref}
|
106 |
-
className={cn(
|
|
|
|
|
|
|
107 |
{...props}
|
108 |
/>
|
109 |
))
|
|
|
19 |
<SelectPrimitive.Trigger
|
20 |
ref={ref}
|
21 |
className={cn(
|
22 |
+
'flex h-10 w-full items-center justify-between rounded-md border border-neutral-200 bg-transparent px-3 py-2 text-sm ring-offset-white placeholder:text-neutral-500 focus:outline-none focus:ring-2 focus:ring-neutral-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-neutral-800 dark:ring-offset-neutral-950 dark:placeholder:text-neutral-400 dark:focus:ring-neutral-800',
|
23 |
className
|
24 |
)}
|
25 |
{...props}
|
|
|
40 |
<SelectPrimitive.Content
|
41 |
ref={ref}
|
42 |
className={cn(
|
43 |
+
'relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white text-neutral-950 shadow-md 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 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50',
|
44 |
position === 'popper' &&
|
45 |
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
46 |
className
|
|
|
81 |
<SelectPrimitive.Item
|
82 |
ref={ref}
|
83 |
className={cn(
|
84 |
+
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-neutral-100 focus:text-neutral-900 dark:focus:bg-neutral-800 dark:focus:text-neutral-50',
|
85 |
className
|
86 |
)}
|
87 |
{...props}
|
|
|
103 |
>(({ className, ...props }, ref) => (
|
104 |
<SelectPrimitive.Separator
|
105 |
ref={ref}
|
106 |
+
className={cn(
|
107 |
+
'-mx-1 my-1 h-px bg-neutral-100 dark:bg-neutral-800',
|
108 |
+
className
|
109 |
+
)}
|
110 |
{...props}
|
111 |
/>
|
112 |
))
|
src/components/ui/separator.tsx
CHANGED
@@ -18,7 +18,7 @@ const Separator = React.forwardRef<
|
|
18 |
decorative={decorative}
|
19 |
orientation={orientation}
|
20 |
className={cn(
|
21 |
-
'shrink-0 bg-
|
22 |
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
23 |
className
|
24 |
)}
|
|
|
18 |
decorative={decorative}
|
19 |
orientation={orientation}
|
20 |
className={cn(
|
21 |
+
'shrink-0 bg-neutral-200 dark:bg-neutral-800',
|
22 |
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
23 |
className
|
24 |
)}
|
src/components/ui/sheet.tsx
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use client'
|
2 |
+
|
3 |
+
import * as React from 'react'
|
4 |
+
import * as SheetPrimitive from '@radix-ui/react-dialog'
|
5 |
+
import { cva, type VariantProps } from 'class-variance-authority'
|
6 |
+
import { X } from 'lucide-react'
|
7 |
+
|
8 |
+
import { cn } from '@/lib/utils'
|
9 |
+
|
10 |
+
const Sheet = SheetPrimitive.Root
|
11 |
+
|
12 |
+
const SheetTrigger = SheetPrimitive.Trigger
|
13 |
+
|
14 |
+
const SheetClose = SheetPrimitive.Close
|
15 |
+
|
16 |
+
const SheetPortal = SheetPrimitive.Portal
|
17 |
+
|
18 |
+
const SheetOverlay = React.forwardRef<
|
19 |
+
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
20 |
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
21 |
+
>(({ className, ...props }, ref) => (
|
22 |
+
<SheetPrimitive.Overlay
|
23 |
+
className={cn(
|
24 |
+
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
25 |
+
className
|
26 |
+
)}
|
27 |
+
{...props}
|
28 |
+
ref={ref}
|
29 |
+
/>
|
30 |
+
))
|
31 |
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
|
32 |
+
|
33 |
+
const sheetVariants = cva(
|
34 |
+
'fixed z-50 gap-4 bg-white p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 dark:bg-neutral-950',
|
35 |
+
{
|
36 |
+
variants: {
|
37 |
+
side: {
|
38 |
+
top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
|
39 |
+
bottom:
|
40 |
+
'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
|
41 |
+
left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
|
42 |
+
right:
|
43 |
+
'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
|
44 |
+
},
|
45 |
+
},
|
46 |
+
defaultVariants: {
|
47 |
+
side: 'right',
|
48 |
+
},
|
49 |
+
}
|
50 |
+
)
|
51 |
+
|
52 |
+
interface SheetContentProps
|
53 |
+
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
54 |
+
VariantProps<typeof sheetVariants> {}
|
55 |
+
|
56 |
+
const SheetContent = React.forwardRef<
|
57 |
+
React.ElementRef<typeof SheetPrimitive.Content>,
|
58 |
+
SheetContentProps
|
59 |
+
>(({ side = 'right', className, children, ...props }, ref) => (
|
60 |
+
<SheetPortal>
|
61 |
+
<SheetOverlay />
|
62 |
+
<SheetPrimitive.Content
|
63 |
+
ref={ref}
|
64 |
+
className={cn(sheetVariants({ side }), className)}
|
65 |
+
{...props}
|
66 |
+
>
|
67 |
+
{children}
|
68 |
+
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity data-[state=open]:bg-neutral-100 hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-neutral-950 focus:ring-offset-2 disabled:pointer-events-none dark:ring-offset-neutral-950 dark:data-[state=open]:bg-neutral-800 dark:focus:ring-neutral-300">
|
69 |
+
<X className="h-4 w-4" />
|
70 |
+
<span className="sr-only">Close</span>
|
71 |
+
</SheetPrimitive.Close>
|
72 |
+
</SheetPrimitive.Content>
|
73 |
+
</SheetPortal>
|
74 |
+
))
|
75 |
+
SheetContent.displayName = SheetPrimitive.Content.displayName
|
76 |
+
|
77 |
+
const SheetHeader = ({
|
78 |
+
className,
|
79 |
+
...props
|
80 |
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
81 |
+
<div
|
82 |
+
className={cn(
|
83 |
+
'flex flex-col space-y-2 text-center sm:text-left',
|
84 |
+
className
|
85 |
+
)}
|
86 |
+
{...props}
|
87 |
+
/>
|
88 |
+
)
|
89 |
+
SheetHeader.displayName = 'SheetHeader'
|
90 |
+
|
91 |
+
const SheetFooter = ({
|
92 |
+
className,
|
93 |
+
...props
|
94 |
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
95 |
+
<div
|
96 |
+
className={cn(
|
97 |
+
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
98 |
+
className
|
99 |
+
)}
|
100 |
+
{...props}
|
101 |
+
/>
|
102 |
+
)
|
103 |
+
SheetFooter.displayName = 'SheetFooter'
|
104 |
+
|
105 |
+
const SheetTitle = React.forwardRef<
|
106 |
+
React.ElementRef<typeof SheetPrimitive.Title>,
|
107 |
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
108 |
+
>(({ className, ...props }, ref) => (
|
109 |
+
<SheetPrimitive.Title
|
110 |
+
ref={ref}
|
111 |
+
className={cn(
|
112 |
+
'text-lg font-semibold text-neutral-950 dark:text-neutral-50',
|
113 |
+
className
|
114 |
+
)}
|
115 |
+
{...props}
|
116 |
+
/>
|
117 |
+
))
|
118 |
+
SheetTitle.displayName = SheetPrimitive.Title.displayName
|
119 |
+
|
120 |
+
const SheetDescription = React.forwardRef<
|
121 |
+
React.ElementRef<typeof SheetPrimitive.Description>,
|
122 |
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
123 |
+
>(({ className, ...props }, ref) => (
|
124 |
+
<SheetPrimitive.Description
|
125 |
+
ref={ref}
|
126 |
+
className={cn('text-sm text-neutral-500 dark:text-neutral-400', className)}
|
127 |
+
{...props}
|
128 |
+
/>
|
129 |
+
))
|
130 |
+
SheetDescription.displayName = SheetPrimitive.Description.displayName
|
131 |
+
|
132 |
+
export {
|
133 |
+
Sheet,
|
134 |
+
SheetPortal,
|
135 |
+
SheetOverlay,
|
136 |
+
SheetTrigger,
|
137 |
+
SheetClose,
|
138 |
+
SheetContent,
|
139 |
+
SheetHeader,
|
140 |
+
SheetFooter,
|
141 |
+
SheetTitle,
|
142 |
+
SheetDescription,
|
143 |
+
}
|
src/components/ui/sonner.tsx
CHANGED
@@ -15,13 +15,13 @@ const Toaster = ({ ...props }: ToasterProps) => {
|
|
15 |
toastOptions={{
|
16 |
classNames: {
|
17 |
toast:
|
18 |
-
'group toast group-[.toaster]:bg-white group-[.toaster]:text-
|
19 |
description:
|
20 |
-
'group-[.toast]:text-
|
21 |
actionButton:
|
22 |
-
'group-[.toast]:bg-
|
23 |
cancelButton:
|
24 |
-
'group-[.toast]:bg-
|
25 |
},
|
26 |
}}
|
27 |
{...props}
|
|
|
15 |
toastOptions={{
|
16 |
classNames: {
|
17 |
toast:
|
18 |
+
'group toast group-[.toaster]:bg-white group-[.toaster]:text-neutral-950 group-[.toaster]:border-neutral-200 group-[.toaster]:shadow-lg dark:group-[.toaster]:bg-neutral-950 dark:group-[.toaster]:text-neutral-50 dark:group-[.toaster]:border-neutral-800',
|
19 |
description:
|
20 |
+
'group-[.toast]:text-neutral-500 dark:group-[.toast]:text-neutral-400',
|
21 |
actionButton:
|
22 |
+
'group-[.toast]:bg-neutral-900 group-[.toast]:text-neutral-50 dark:group-[.toast]:bg-neutral-50 dark:group-[.toast]:text-neutral-900',
|
23 |
cancelButton:
|
24 |
+
'group-[.toast]:bg-neutral-100 group-[.toast]:text-neutral-500 dark:group-[.toast]:bg-neutral-800 dark:group-[.toast]:text-neutral-400',
|
25 |
},
|
26 |
}}
|
27 |
{...props}
|
src/components/ui/table.tsx
CHANGED
@@ -43,7 +43,7 @@ const TableFooter = React.forwardRef<
|
|
43 |
<tfoot
|
44 |
ref={ref}
|
45 |
className={cn(
|
46 |
-
'bg-
|
47 |
className
|
48 |
)}
|
49 |
{...props}
|
@@ -58,7 +58,7 @@ const TableRow = React.forwardRef<
|
|
58 |
<tr
|
59 |
ref={ref}
|
60 |
className={cn(
|
61 |
-
'border-b transition-colors data-[state=selected]:bg-
|
62 |
className
|
63 |
)}
|
64 |
{...props}
|
@@ -73,7 +73,7 @@ const TableHead = React.forwardRef<
|
|
73 |
<th
|
74 |
ref={ref}
|
75 |
className={cn(
|
76 |
-
'h-12 px-4 text-left align-middle font-medium text-
|
77 |
className
|
78 |
)}
|
79 |
{...props}
|
@@ -99,7 +99,10 @@ const TableCaption = React.forwardRef<
|
|
99 |
>(({ className, ...props }, ref) => (
|
100 |
<caption
|
101 |
ref={ref}
|
102 |
-
className={cn(
|
|
|
|
|
|
|
103 |
{...props}
|
104 |
/>
|
105 |
))
|
|
|
43 |
<tfoot
|
44 |
ref={ref}
|
45 |
className={cn(
|
46 |
+
'bg-neutral-900 font-medium text-neutral-50 dark:bg-neutral-50 dark:text-neutral-900',
|
47 |
className
|
48 |
)}
|
49 |
{...props}
|
|
|
58 |
<tr
|
59 |
ref={ref}
|
60 |
className={cn(
|
61 |
+
'border-b transition-colors data-[state=selected]:bg-neutral-100 hover:bg-neutral-100/50 dark:data-[state=selected]:bg-neutral-800 dark:hover:bg-neutral-800/50',
|
62 |
className
|
63 |
)}
|
64 |
{...props}
|
|
|
73 |
<th
|
74 |
ref={ref}
|
75 |
className={cn(
|
76 |
+
'h-12 px-4 text-left align-middle font-medium text-neutral-500 dark:text-neutral-400 [&:has([role=checkbox])]:pr-0',
|
77 |
className
|
78 |
)}
|
79 |
{...props}
|
|
|
99 |
>(({ className, ...props }, ref) => (
|
100 |
<caption
|
101 |
ref={ref}
|
102 |
+
className={cn(
|
103 |
+
'mt-4 text-sm text-neutral-500 dark:text-neutral-400',
|
104 |
+
className
|
105 |
+
)}
|
106 |
{...props}
|
107 |
/>
|
108 |
))
|
src/components/ui/tabs.tsx
CHANGED
@@ -14,7 +14,7 @@ const TabsList = React.forwardRef<
|
|
14 |
<TabsPrimitive.List
|
15 |
ref={ref}
|
16 |
className={cn(
|
17 |
-
'inline-flex h-10 items-center justify-center rounded-md bg-
|
18 |
className
|
19 |
)}
|
20 |
{...props}
|
@@ -29,7 +29,7 @@ const TabsTrigger = React.forwardRef<
|
|
29 |
<TabsPrimitive.Trigger
|
30 |
ref={ref}
|
31 |
className={cn(
|
32 |
-
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-white transition-all data-[state=active]:bg-white data-[state=active]:text-
|
33 |
className
|
34 |
)}
|
35 |
{...props}
|
@@ -44,7 +44,7 @@ const TabsContent = React.forwardRef<
|
|
44 |
<TabsPrimitive.Content
|
45 |
ref={ref}
|
46 |
className={cn(
|
47 |
-
'mt-2 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-
|
48 |
className
|
49 |
)}
|
50 |
{...props}
|
|
|
14 |
<TabsPrimitive.List
|
15 |
ref={ref}
|
16 |
className={cn(
|
17 |
+
'inline-flex h-10 items-center justify-center rounded-md bg-neutral-100 p-1 text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400',
|
18 |
className
|
19 |
)}
|
20 |
{...props}
|
|
|
29 |
<TabsPrimitive.Trigger
|
30 |
ref={ref}
|
31 |
className={cn(
|
32 |
+
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-white transition-all data-[state=active]:bg-white data-[state=active]:text-neutral-950 data-[state=active]:shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-neutral-950 dark:data-[state=active]:bg-neutral-950 dark:data-[state=active]:text-neutral-50 dark:focus-visible:ring-neutral-300',
|
33 |
className
|
34 |
)}
|
35 |
{...props}
|
|
|
44 |
<TabsPrimitive.Content
|
45 |
ref={ref}
|
46 |
className={cn(
|
47 |
+
'mt-2 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 dark:ring-offset-neutral-950 dark:focus-visible:ring-neutral-300',
|
48 |
className
|
49 |
)}
|
50 |
{...props}
|
src/components/ui/textarea.tsx
CHANGED
@@ -10,7 +10,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
10 |
return (
|
11 |
<textarea
|
12 |
className={cn(
|
13 |
-
'flex min-h-[80px] w-full rounded-md border border-
|
14 |
className
|
15 |
)}
|
16 |
ref={ref}
|
|
|
10 |
return (
|
11 |
<textarea
|
12 |
className={cn(
|
13 |
+
'flex min-h-[80px] w-full rounded-md border border-neutral-200 bg-transparent px-3 py-2 text-sm ring-offset-white placeholder:text-neutral-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-neutral-800 dark:ring-offset-neutral-950 dark:placeholder:text-neutral-400 dark:focus-visible:ring-neutral-800',
|
14 |
className
|
15 |
)}
|
16 |
ref={ref}
|
src/components/ui/toast.tsx
CHANGED
@@ -23,14 +23,14 @@ const ToastViewport = React.forwardRef<
|
|
23 |
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
|
24 |
|
25 |
const toastVariants = cva(
|
26 |
-
'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border border-
|
27 |
{
|
28 |
variants: {
|
29 |
variant: {
|
30 |
default:
|
31 |
-
'border bg-white text-
|
32 |
destructive:
|
33 |
-
'destructive group border-red-500 bg-red-500 text-
|
34 |
},
|
35 |
},
|
36 |
defaultVariants: {
|
@@ -61,7 +61,7 @@ const ToastAction = React.forwardRef<
|
|
61 |
<ToastPrimitives.Action
|
62 |
ref={ref}
|
63 |
className={cn(
|
64 |
-
'inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-
|
65 |
className
|
66 |
)}
|
67 |
{...props}
|
@@ -76,7 +76,7 @@ const ToastClose = React.forwardRef<
|
|
76 |
<ToastPrimitives.Close
|
77 |
ref={ref}
|
78 |
className={cn(
|
79 |
-
'absolute right-2 top-2 rounded-md p-1 text-
|
80 |
className
|
81 |
)}
|
82 |
toast-close=""
|
|
|
23 |
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
|
24 |
|
25 |
const toastVariants = cva(
|
26 |
+
'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border border-neutral-200 p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full dark:border-neutral-800',
|
27 |
{
|
28 |
variants: {
|
29 |
variant: {
|
30 |
default:
|
31 |
+
'border bg-white text-neutral-950 dark:bg-neutral-950 dark:text-neutral-50',
|
32 |
destructive:
|
33 |
+
'destructive group border-red-500 bg-red-500 text-neutral-50 dark:border-red-900 dark:bg-red-900 dark:text-neutral-50',
|
34 |
},
|
35 |
},
|
36 |
defaultVariants: {
|
|
|
61 |
<ToastPrimitives.Action
|
62 |
ref={ref}
|
63 |
className={cn(
|
64 |
+
'inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-neutral-200 bg-transparent px-3 text-sm font-medium ring-offset-white transition-colors group-[.destructive]:border-neutral-100/40 hover:bg-neutral-100 group-[.destructive]:hover:border-red-500/30 group-[.destructive]:hover:bg-red-500 group-[.destructive]:hover:text-neutral-50 focus:outline-none focus:ring-2 focus:ring-neutral-950 focus:ring-offset-2 group-[.destructive]:focus:ring-red-500 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-800 dark:ring-offset-neutral-950 dark:group-[.destructive]:border-neutral-800/40 dark:hover:bg-neutral-800 dark:group-[.destructive]:hover:border-red-900/30 dark:group-[.destructive]:hover:bg-red-900 dark:group-[.destructive]:hover:text-neutral-50 dark:focus:ring-neutral-300 dark:group-[.destructive]:focus:ring-red-900',
|
65 |
className
|
66 |
)}
|
67 |
{...props}
|
|
|
76 |
<ToastPrimitives.Close
|
77 |
ref={ref}
|
78 |
className={cn(
|
79 |
+
'absolute right-2 top-2 rounded-md p-1 text-neutral-950/50 opacity-0 transition-opacity group-hover:opacity-100 group-[.destructive]:text-red-300 hover:text-neutral-950 group-[.destructive]:hover:text-red-50 focus:opacity-100 focus:outline-none focus:ring-2 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 dark:text-neutral-50/50 dark:hover:text-neutral-50',
|
80 |
className
|
81 |
)}
|
82 |
toast-close=""
|
src/components/ui/tooltip.tsx
CHANGED
@@ -19,7 +19,7 @@ const TooltipContent = React.forwardRef<
|
|
19 |
ref={ref}
|
20 |
sideOffset={sideOffset}
|
21 |
className={cn(
|
22 |
-
'z-50 overflow-hidden rounded-md border border-
|
23 |
className
|
24 |
)}
|
25 |
{...props}
|
|
|
19 |
ref={ref}
|
20 |
sideOffset={sideOffset}
|
21 |
className={cn(
|
22 |
+
'z-50 overflow-hidden rounded-md border border-neutral-200 bg-white px-3 py-1.5 text-sm text-neutral-950 shadow-md 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 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50',
|
23 |
className
|
24 |
)}
|
25 |
{...props}
|
src/components/ui/vertical-slider.tsx
CHANGED
@@ -17,10 +17,10 @@ const VerticalSlider = React.forwardRef<
|
|
17 |
)}
|
18 |
{...props}
|
19 |
>
|
20 |
-
<SliderPrimitive.Track className="relative h-full w-2 grow overflow-hidden rounded-full bg-
|
21 |
-
<SliderPrimitive.Range className="absolute w-full bg-
|
22 |
</SliderPrimitive.Track>
|
23 |
-
<SliderPrimitive.Thumb className="-ml-1.5 block h-5 w-5 rounded-full border-2 border-
|
24 |
</SliderPrimitive.Root>
|
25 |
))
|
26 |
VerticalSlider.displayName = 'VerticalSlider'
|
|
|
17 |
)}
|
18 |
{...props}
|
19 |
>
|
20 |
+
<SliderPrimitive.Track className="relative h-full w-2 grow overflow-hidden rounded-full bg-neutral-300 dark:bg-neutral-700">
|
21 |
+
<SliderPrimitive.Range className="absolute w-full bg-neutral-700 dark:bg-neutral-50" />
|
22 |
</SliderPrimitive.Track>
|
23 |
+
<SliderPrimitive.Thumb className="-ml-1.5 block h-5 w-5 rounded-full border-2 border-neutral-700 bg-neutral-300 ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-50 dark:bg-neutral-700 dark:ring-offset-neutral-950 dark:focus-visible:ring-neutral-300" />
|
24 |
</SliderPrimitive.Root>
|
25 |
))
|
26 |
VerticalSlider.displayName = 'VerticalSlider'
|
src/components/wizards/project/index.tsx
CHANGED
@@ -64,7 +64,7 @@ export function ProjectCreationWizard() {
|
|
64 |
<Button
|
65 |
key={key}
|
66 |
variant="ghost"
|
67 |
-
className="flex w-full flex-col items-end text-right text-lg font-thin capitalize text-
|
68 |
onClick={() =>
|
69 |
setProjectCreationWizardStep(key as ProjectCreationWizardStep)
|
70 |
}
|
@@ -75,14 +75,14 @@ export function ProjectCreationWizard() {
|
|
75 |
</div>
|
76 |
</ScrollArea>
|
77 |
|
78 |
-
<div className="flex h-full max-w-[calc(100%-150px)] flex-grow select-none flex-col justify-between border-l border-
|
79 |
<ScrollArea className="flex h-full flex-row">
|
80 |
{stepPanels[projectCreationWizardStep]}
|
81 |
</ScrollArea>
|
82 |
<DialogFooter>
|
83 |
<Button
|
84 |
variant="outline"
|
85 |
-
className="text-sm font-light dark:border-
|
86 |
onClick={() => {
|
87 |
setProjectCreationWizardStep(ProjectCreationWizardStep.NONE)
|
88 |
}}
|
|
|
64 |
<Button
|
65 |
key={key}
|
66 |
variant="ghost"
|
67 |
+
className="flex w-full flex-col items-end text-right text-lg font-thin capitalize text-neutral-300"
|
68 |
onClick={() =>
|
69 |
setProjectCreationWizardStep(key as ProjectCreationWizardStep)
|
70 |
}
|
|
|
75 |
</div>
|
76 |
</ScrollArea>
|
77 |
|
78 |
+
<div className="flex h-full max-w-[calc(100%-150px)] flex-grow select-none flex-col justify-between border-l border-neutral-800 pl-8">
|
79 |
<ScrollArea className="flex h-full flex-row">
|
80 |
{stepPanels[projectCreationWizardStep]}
|
81 |
</ScrollArea>
|
82 |
<DialogFooter>
|
83 |
<Button
|
84 |
variant="outline"
|
85 |
+
className="text-sm font-light dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-400"
|
86 |
onClick={() => {
|
87 |
setProjectCreationWizardStep(ProjectCreationWizardStep.NONE)
|
88 |
}}
|
src/experiments/moodboard/MoodboardView.tsx
CHANGED
@@ -58,7 +58,7 @@ export function MoodboardView() {
|
|
58 |
|
59 |
const onConnect: OnConnect = useCallback(
|
60 |
(params) => setEdges((eds) => addEdge(params, eds)),
|
61 |
-
[]
|
62 |
)
|
63 |
|
64 |
return (
|
|
|
58 |
|
59 |
const onConnect: OnConnect = useCallback(
|
60 |
(params) => setEdges((eds) => addEdge(params, eds)),
|
61 |
+
[setEdges]
|
62 |
)
|
63 |
|
64 |
return (
|
src/experiments/moodboard/Node.tsx
CHANGED
@@ -11,7 +11,7 @@ function NodeComponent({
|
|
11 |
}
|
12 |
}) {
|
13 |
return (
|
14 |
-
<div className="rounded-md border-2 border-
|
15 |
<div className="flex">
|
16 |
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
|
17 |
{data.emoji}
|
|
|
11 |
}
|
12 |
}) {
|
13 |
return (
|
14 |
+
<div className="rounded-md border-2 border-neutral-400 bg-white px-4 py-2 shadow-md">
|
15 |
<div className="flex">
|
16 |
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
|
17 |
{data.emoji}
|
src/lib/core/constants.ts
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
export const HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL = 32
|
4 |
|
5 |
export const APP_NAME = 'Clapper.app'
|
6 |
-
export const APP_REVISION = '
|
7 |
|
8 |
export const APP_DOMAIN = 'Clapper.app'
|
9 |
export const APP_LINK = 'https://clapper.app'
|
|
|
3 |
export const HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL = 32
|
4 |
|
5 |
export const APP_NAME = 'Clapper.app'
|
6 |
+
export const APP_REVISION = '20240814+1439'
|
7 |
|
8 |
export const APP_DOMAIN = 'Clapper.app'
|
9 |
export const APP_LINK = 'https://clapper.app'
|
src/services/debug.ts
CHANGED
@@ -11,6 +11,7 @@ import {
|
|
11 |
useProjectEditor,
|
12 |
useScriptEditor,
|
13 |
useSegmentEditor,
|
|
|
14 |
} from './editors'
|
15 |
import { useIO } from './io/useIO'
|
16 |
import { useMetrics } from './metrics/useMetrics'
|
@@ -24,6 +25,7 @@ import { useWindows } from './windows/useWindows'
|
|
24 |
|
25 |
// those are just used for developer convenience
|
26 |
// to help debug things in the chrome developer console
|
|
|
27 |
if (typeof window !== 'undefined') {
|
28 |
const w = window as any
|
29 |
w.useTasks = useTasks
|
@@ -31,13 +33,18 @@ if (typeof window !== 'undefined') {
|
|
31 |
w.useMic = useMic
|
32 |
w.useAudio = useAudio
|
33 |
w.useBroadcast = useBroadcast
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
w.useEntityEditor = useEntityEditor
|
36 |
w.useFilterEditor = useFilterEditor
|
37 |
w.useProjectEditor = useProjectEditor
|
38 |
w.useScriptEditor = useScriptEditor
|
39 |
w.useSegmentEditor = useSegmentEditor
|
40 |
-
w.useIO = useIO
|
41 |
w.useMetrics = useMetrics
|
42 |
w.useMonitor = useMonitor
|
43 |
w.useRenderer = useRenderer
|
|
|
11 |
useProjectEditor,
|
12 |
useScriptEditor,
|
13 |
useSegmentEditor,
|
14 |
+
useWorkflowEditor,
|
15 |
} from './editors'
|
16 |
import { useIO } from './io/useIO'
|
17 |
import { useMetrics } from './metrics/useMetrics'
|
|
|
25 |
|
26 |
// those are just used for developer convenience
|
27 |
// to help debug things in the chrome developer console
|
28 |
+
|
29 |
if (typeof window !== 'undefined') {
|
30 |
const w = window as any
|
31 |
w.useTasks = useTasks
|
|
|
33 |
w.useMic = useMic
|
34 |
w.useAudio = useAudio
|
35 |
w.useBroadcast = useBroadcast
|
36 |
+
|
37 |
+
// I think we have a cyclic dependency somewhere,
|
38 |
+
// because uncommenting the following lines will crash the app
|
39 |
+
// w.useEditors = useEditors
|
40 |
+
// w.useWorkflowEditor = useWorkflowEditor
|
41 |
+
// w.useIO = useIO
|
42 |
+
|
43 |
w.useEntityEditor = useEntityEditor
|
44 |
w.useFilterEditor = useFilterEditor
|
45 |
w.useProjectEditor = useProjectEditor
|
46 |
w.useScriptEditor = useScriptEditor
|
47 |
w.useSegmentEditor = useSegmentEditor
|
|
|
48 |
w.useMetrics = useMetrics
|
49 |
w.useMonitor = useMonitor
|
50 |
w.useRenderer = useRenderer
|
src/services/editors/script-editor/useScriptEditor.ts
CHANGED
@@ -18,7 +18,7 @@ import {
|
|
18 |
} from '@aitube/clapper-services'
|
19 |
|
20 |
import { getDefaultScriptEditorState } from './getDefaultScriptEditorState'
|
21 |
-
import { useAssistant } from '@/services/assistant/useAssistant'
|
22 |
|
23 |
export const useScriptEditor = create<ScriptEditorStore>((set, get) => ({
|
24 |
...getDefaultScriptEditorState(),
|
@@ -85,7 +85,8 @@ export const useScriptEditor = create<ScriptEditorStore>((set, get) => ({
|
|
85 |
// console.log('existingText:', existingText)
|
86 |
// console.log('newTextAddition:', newTextAddition)
|
87 |
|
88 |
-
|
|
|
89 |
|
90 |
// call the LLM, with a prompt like:
|
91 |
},
|
|
|
18 |
} from '@aitube/clapper-services'
|
19 |
|
20 |
import { getDefaultScriptEditorState } from './getDefaultScriptEditorState'
|
21 |
+
// import { useAssistant } from '@/services/assistant/useAssistant'
|
22 |
|
23 |
export const useScriptEditor = create<ScriptEditorStore>((set, get) => ({
|
24 |
...getDefaultScriptEditorState(),
|
|
|
85 |
// console.log('existingText:', existingText)
|
86 |
// console.log('newTextAddition:', newTextAddition)
|
87 |
|
88 |
+
// attention here! the assistant might not be initialized
|
89 |
+
// const assistant = useAssistant.getState()
|
90 |
|
91 |
// call the LLM, with a prompt like:
|
92 |
},
|