Spaces:
Paused
Paused
Commit
β’
43dd1ac
1
Parent(s):
e5c2fd4
ready for release (sort of)
Browse files- README.md +5 -0
- next.config.js +10 -0
- package-lock.json +292 -0
- package.json +9 -0
- src/api/index.ts +0 -16
- src/app/api/tasks/[uuid]/route.ts +18 -0
- src/app/api/tasks/route.ts +24 -0
- src/app/layout.tsx +5 -4
- src/app/main.tsx +0 -66
- src/app/page.tsx +4 -15
- src/app/studio/[ownerId]/main.tsx +61 -0
- src/app/{pending β studio/[ownerId]}/page.tsx +5 -8
- src/app/types.ts +6 -6
- src/components/business/tasks/columns.tsx +39 -37
- src/components/business/tasks/data-table-faceted-filter.tsx +0 -147
- src/components/business/tasks/data-table-pagination.tsx +0 -97
- src/components/business/tasks/data-table-row-actions.tsx +7 -30
- src/components/business/tasks/data-table-toolbar.tsx +0 -61
- src/components/business/tasks/data-table-view-options.tsx +0 -59
- src/components/business/tasks/user-nav.tsx +0 -62
- src/components/business/tasks/{data-table.tsx β video-tasks-queue.tsx} +57 -65
- src/components/ui/alert.tsx +2 -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/calendar.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 +7 -7
- src/components/ui/input.tsx +1 -1
- src/components/ui/menubar.tsx +10 -10
- src/components/ui/popover.tsx +1 -1
- src/components/ui/select.tsx +4 -4
- src/components/ui/separator.tsx +1 -1
- src/components/ui/table.tsx +4 -4
- src/components/ui/textarea.tsx +24 -0
- src/server/README.md +1 -0
- src/server/actions.ts +14 -0
- src/{api β server}/base.ts +41 -2
- src/server/index.ts +39 -0
- tsconfig.json +1 -1
README.md
CHANGED
@@ -23,3 +23,8 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
|
|
23 |
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
24 |
|
25 |
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
|
|
|
|
|
|
|
|
|
|
|
23 |
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
24 |
|
25 |
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
26 |
+
|
27 |
+
## Things to know
|
28 |
+
|
29 |
+
Next will cache the API calls!
|
30 |
+
So be careful about this.
|
next.config.js
CHANGED
@@ -3,6 +3,16 @@ const nextConfig = {
|
|
3 |
experimental: {
|
4 |
serverActions: true,
|
5 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
}
|
7 |
|
8 |
module.exports = nextConfig
|
|
|
3 |
experimental: {
|
4 |
serverActions: true,
|
5 |
},
|
6 |
+
|
7 |
+
async redirects() {
|
8 |
+
return [
|
9 |
+
{
|
10 |
+
source: '/api/download/:id*',
|
11 |
+
destination: `${process.env.VC_VIDEOCHAIN_API_URL}/download/:id*`,
|
12 |
+
permanent: true,
|
13 |
+
},
|
14 |
+
]
|
15 |
+
},
|
16 |
}
|
17 |
|
18 |
module.exports = nextConfig
|
package-lock.json
CHANGED
@@ -9,13 +9,20 @@
|
|
9 |
"version": "0.1.0",
|
10 |
"dependencies": {
|
11 |
"@radix-ui/react-accordion": "^1.1.2",
|
|
|
12 |
"@radix-ui/react-checkbox": "^1.0.4",
|
13 |
"@radix-ui/react-collapsible": "^1.0.3",
|
14 |
"@radix-ui/react-dialog": "^1.0.4",
|
|
|
15 |
"@radix-ui/react-icons": "^1.3.0",
|
16 |
"@radix-ui/react-menubar": "^1.0.3",
|
|
|
|
|
|
|
17 |
"@radix-ui/react-slot": "^1.0.2",
|
18 |
"@silevis/reactgrid": "^4.0.5",
|
|
|
|
|
19 |
"@types/fluent-ffmpeg": "^2.1.21",
|
20 |
"@types/node": "20.4.2",
|
21 |
"@types/react": "18.2.15",
|
@@ -25,6 +32,7 @@
|
|
25 |
"class-variance-authority": "^0.6.1",
|
26 |
"clsx": "^2.0.0",
|
27 |
"cmdk": "^0.2.0",
|
|
|
28 |
"date-fns": "^2.30.0",
|
29 |
"eslint": "8.45.0",
|
30 |
"eslint-config-next": "13.4.10",
|
@@ -44,6 +52,7 @@
|
|
44 |
"ts-node": "^10.9.1",
|
45 |
"typescript": "5.1.6",
|
46 |
"uuid": "^9.0.0",
|
|
|
47 |
"zustand": "^4.3.9"
|
48 |
}
|
49 |
},
|
@@ -578,6 +587,14 @@
|
|
578 |
}
|
579 |
}
|
580 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
581 |
"node_modules/@radix-ui/primitive": {
|
582 |
"version": "1.0.1",
|
583 |
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
|
@@ -640,6 +657,32 @@
|
|
640 |
}
|
641 |
}
|
642 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
643 |
"node_modules/@radix-ui/react-checkbox": {
|
644 |
"version": "1.0.4",
|
645 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz",
|
@@ -840,6 +883,35 @@
|
|
840 |
}
|
841 |
}
|
842 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
843 |
"node_modules/@radix-ui/react-focus-guards": {
|
844 |
"version": "1.0.1",
|
845 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz",
|
@@ -980,6 +1052,43 @@
|
|
980 |
}
|
981 |
}
|
982 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
983 |
"node_modules/@radix-ui/react-popper": {
|
984 |
"version": "1.1.2",
|
985 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.2.tgz",
|
@@ -1113,6 +1222,72 @@
|
|
1113 |
}
|
1114 |
}
|
1115 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1116 |
"node_modules/@radix-ui/react-slot": {
|
1117 |
"version": "1.0.2",
|
1118 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
|
@@ -1254,6 +1429,29 @@
|
|
1254 |
}
|
1255 |
}
|
1256 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1257 |
"node_modules/@radix-ui/rect": {
|
1258 |
"version": "1.0.1",
|
1259 |
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz",
|
@@ -1288,6 +1486,72 @@
|
|
1288 |
"tslib": "^2.4.0"
|
1289 |
}
|
1290 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1291 |
"node_modules/@tsconfig/node10": {
|
1292 |
"version": "1.0.9",
|
1293 |
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
@@ -1308,6 +1572,11 @@
|
|
1308 |
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
1309 |
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="
|
1310 |
},
|
|
|
|
|
|
|
|
|
|
|
1311 |
"node_modules/@types/fluent-ffmpeg": {
|
1312 |
"version": "2.1.21",
|
1313 |
"resolved": "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.21.tgz",
|
@@ -2369,6 +2638,29 @@
|
|
2369 |
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
2370 |
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
2371 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2372 |
"node_modules/cosmiconfig": {
|
2373 |
"version": "8.2.0",
|
2374 |
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz",
|
|
|
9 |
"version": "0.1.0",
|
10 |
"dependencies": {
|
11 |
"@radix-ui/react-accordion": "^1.1.2",
|
12 |
+
"@radix-ui/react-avatar": "^1.0.3",
|
13 |
"@radix-ui/react-checkbox": "^1.0.4",
|
14 |
"@radix-ui/react-collapsible": "^1.0.3",
|
15 |
"@radix-ui/react-dialog": "^1.0.4",
|
16 |
+
"@radix-ui/react-dropdown-menu": "^2.0.5",
|
17 |
"@radix-ui/react-icons": "^1.3.0",
|
18 |
"@radix-ui/react-menubar": "^1.0.3",
|
19 |
+
"@radix-ui/react-popover": "^1.0.6",
|
20 |
+
"@radix-ui/react-select": "^1.2.2",
|
21 |
+
"@radix-ui/react-separator": "^1.0.3",
|
22 |
"@radix-ui/react-slot": "^1.0.2",
|
23 |
"@silevis/reactgrid": "^4.0.5",
|
24 |
+
"@tanstack/react-query": "^4.30.0",
|
25 |
+
"@tanstack/react-table": "^8.9.3",
|
26 |
"@types/fluent-ffmpeg": "^2.1.21",
|
27 |
"@types/node": "20.4.2",
|
28 |
"@types/react": "18.2.15",
|
|
|
32 |
"class-variance-authority": "^0.6.1",
|
33 |
"clsx": "^2.0.0",
|
34 |
"cmdk": "^0.2.0",
|
35 |
+
"cookies-next": "^2.1.2",
|
36 |
"date-fns": "^2.30.0",
|
37 |
"eslint": "8.45.0",
|
38 |
"eslint-config-next": "13.4.10",
|
|
|
52 |
"ts-node": "^10.9.1",
|
53 |
"typescript": "5.1.6",
|
54 |
"uuid": "^9.0.0",
|
55 |
+
"zod": "^3.21.4",
|
56 |
"zustand": "^4.3.9"
|
57 |
}
|
58 |
},
|
|
|
587 |
}
|
588 |
}
|
589 |
},
|
590 |
+
"node_modules/@radix-ui/number": {
|
591 |
+
"version": "1.0.1",
|
592 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
|
593 |
+
"integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==",
|
594 |
+
"dependencies": {
|
595 |
+
"@babel/runtime": "^7.13.10"
|
596 |
+
}
|
597 |
+
},
|
598 |
"node_modules/@radix-ui/primitive": {
|
599 |
"version": "1.0.1",
|
600 |
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
|
|
|
657 |
}
|
658 |
}
|
659 |
},
|
660 |
+
"node_modules/@radix-ui/react-avatar": {
|
661 |
+
"version": "1.0.3",
|
662 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.0.3.tgz",
|
663 |
+
"integrity": "sha512-9ToF7YNex3Ste45LrAeTlKtONI9yVRt/zOS158iilIkW5K/Apeyb/TUQlcEFTEFvWr8Kzdi2ZYrm1/suiXPajQ==",
|
664 |
+
"dependencies": {
|
665 |
+
"@babel/runtime": "^7.13.10",
|
666 |
+
"@radix-ui/react-context": "1.0.1",
|
667 |
+
"@radix-ui/react-primitive": "1.0.3",
|
668 |
+
"@radix-ui/react-use-callback-ref": "1.0.1",
|
669 |
+
"@radix-ui/react-use-layout-effect": "1.0.1"
|
670 |
+
},
|
671 |
+
"peerDependencies": {
|
672 |
+
"@types/react": "*",
|
673 |
+
"@types/react-dom": "*",
|
674 |
+
"react": "^16.8 || ^17.0 || ^18.0",
|
675 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
676 |
+
},
|
677 |
+
"peerDependenciesMeta": {
|
678 |
+
"@types/react": {
|
679 |
+
"optional": true
|
680 |
+
},
|
681 |
+
"@types/react-dom": {
|
682 |
+
"optional": true
|
683 |
+
}
|
684 |
+
}
|
685 |
+
},
|
686 |
"node_modules/@radix-ui/react-checkbox": {
|
687 |
"version": "1.0.4",
|
688 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz",
|
|
|
883 |
}
|
884 |
}
|
885 |
},
|
886 |
+
"node_modules/@radix-ui/react-dropdown-menu": {
|
887 |
+
"version": "2.0.5",
|
888 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.5.tgz",
|
889 |
+
"integrity": "sha512-xdOrZzOTocqqkCkYo8yRPCib5OkTkqN7lqNCdxwPOdE466DOaNl4N8PkUIlsXthQvW5Wwkd+aEmWpfWlBoDPEw==",
|
890 |
+
"dependencies": {
|
891 |
+
"@babel/runtime": "^7.13.10",
|
892 |
+
"@radix-ui/primitive": "1.0.1",
|
893 |
+
"@radix-ui/react-compose-refs": "1.0.1",
|
894 |
+
"@radix-ui/react-context": "1.0.1",
|
895 |
+
"@radix-ui/react-id": "1.0.1",
|
896 |
+
"@radix-ui/react-menu": "2.0.5",
|
897 |
+
"@radix-ui/react-primitive": "1.0.3",
|
898 |
+
"@radix-ui/react-use-controllable-state": "1.0.1"
|
899 |
+
},
|
900 |
+
"peerDependencies": {
|
901 |
+
"@types/react": "*",
|
902 |
+
"@types/react-dom": "*",
|
903 |
+
"react": "^16.8 || ^17.0 || ^18.0",
|
904 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
905 |
+
},
|
906 |
+
"peerDependenciesMeta": {
|
907 |
+
"@types/react": {
|
908 |
+
"optional": true
|
909 |
+
},
|
910 |
+
"@types/react-dom": {
|
911 |
+
"optional": true
|
912 |
+
}
|
913 |
+
}
|
914 |
+
},
|
915 |
"node_modules/@radix-ui/react-focus-guards": {
|
916 |
"version": "1.0.1",
|
917 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz",
|
|
|
1052 |
}
|
1053 |
}
|
1054 |
},
|
1055 |
+
"node_modules/@radix-ui/react-popover": {
|
1056 |
+
"version": "1.0.6",
|
1057 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.6.tgz",
|
1058 |
+
"integrity": "sha512-cZ4defGpkZ0qTRtlIBzJLSzL6ht7ofhhW4i1+pkemjV1IKXm0wgCRnee154qlV6r9Ttunmh2TNZhMfV2bavUyA==",
|
1059 |
+
"dependencies": {
|
1060 |
+
"@babel/runtime": "^7.13.10",
|
1061 |
+
"@radix-ui/primitive": "1.0.1",
|
1062 |
+
"@radix-ui/react-compose-refs": "1.0.1",
|
1063 |
+
"@radix-ui/react-context": "1.0.1",
|
1064 |
+
"@radix-ui/react-dismissable-layer": "1.0.4",
|
1065 |
+
"@radix-ui/react-focus-guards": "1.0.1",
|
1066 |
+
"@radix-ui/react-focus-scope": "1.0.3",
|
1067 |
+
"@radix-ui/react-id": "1.0.1",
|
1068 |
+
"@radix-ui/react-popper": "1.1.2",
|
1069 |
+
"@radix-ui/react-portal": "1.0.3",
|
1070 |
+
"@radix-ui/react-presence": "1.0.1",
|
1071 |
+
"@radix-ui/react-primitive": "1.0.3",
|
1072 |
+
"@radix-ui/react-slot": "1.0.2",
|
1073 |
+
"@radix-ui/react-use-controllable-state": "1.0.1",
|
1074 |
+
"aria-hidden": "^1.1.1",
|
1075 |
+
"react-remove-scroll": "2.5.5"
|
1076 |
+
},
|
1077 |
+
"peerDependencies": {
|
1078 |
+
"@types/react": "*",
|
1079 |
+
"@types/react-dom": "*",
|
1080 |
+
"react": "^16.8 || ^17.0 || ^18.0",
|
1081 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
1082 |
+
},
|
1083 |
+
"peerDependenciesMeta": {
|
1084 |
+
"@types/react": {
|
1085 |
+
"optional": true
|
1086 |
+
},
|
1087 |
+
"@types/react-dom": {
|
1088 |
+
"optional": true
|
1089 |
+
}
|
1090 |
+
}
|
1091 |
+
},
|
1092 |
"node_modules/@radix-ui/react-popper": {
|
1093 |
"version": "1.1.2",
|
1094 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.2.tgz",
|
|
|
1222 |
}
|
1223 |
}
|
1224 |
},
|
1225 |
+
"node_modules/@radix-ui/react-select": {
|
1226 |
+
"version": "1.2.2",
|
1227 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-1.2.2.tgz",
|
1228 |
+
"integrity": "sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==",
|
1229 |
+
"dependencies": {
|
1230 |
+
"@babel/runtime": "^7.13.10",
|
1231 |
+
"@radix-ui/number": "1.0.1",
|
1232 |
+
"@radix-ui/primitive": "1.0.1",
|
1233 |
+
"@radix-ui/react-collection": "1.0.3",
|
1234 |
+
"@radix-ui/react-compose-refs": "1.0.1",
|
1235 |
+
"@radix-ui/react-context": "1.0.1",
|
1236 |
+
"@radix-ui/react-direction": "1.0.1",
|
1237 |
+
"@radix-ui/react-dismissable-layer": "1.0.4",
|
1238 |
+
"@radix-ui/react-focus-guards": "1.0.1",
|
1239 |
+
"@radix-ui/react-focus-scope": "1.0.3",
|
1240 |
+
"@radix-ui/react-id": "1.0.1",
|
1241 |
+
"@radix-ui/react-popper": "1.1.2",
|
1242 |
+
"@radix-ui/react-portal": "1.0.3",
|
1243 |
+
"@radix-ui/react-primitive": "1.0.3",
|
1244 |
+
"@radix-ui/react-slot": "1.0.2",
|
1245 |
+
"@radix-ui/react-use-callback-ref": "1.0.1",
|
1246 |
+
"@radix-ui/react-use-controllable-state": "1.0.1",
|
1247 |
+
"@radix-ui/react-use-layout-effect": "1.0.1",
|
1248 |
+
"@radix-ui/react-use-previous": "1.0.1",
|
1249 |
+
"@radix-ui/react-visually-hidden": "1.0.3",
|
1250 |
+
"aria-hidden": "^1.1.1",
|
1251 |
+
"react-remove-scroll": "2.5.5"
|
1252 |
+
},
|
1253 |
+
"peerDependencies": {
|
1254 |
+
"@types/react": "*",
|
1255 |
+
"@types/react-dom": "*",
|
1256 |
+
"react": "^16.8 || ^17.0 || ^18.0",
|
1257 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
1258 |
+
},
|
1259 |
+
"peerDependenciesMeta": {
|
1260 |
+
"@types/react": {
|
1261 |
+
"optional": true
|
1262 |
+
},
|
1263 |
+
"@types/react-dom": {
|
1264 |
+
"optional": true
|
1265 |
+
}
|
1266 |
+
}
|
1267 |
+
},
|
1268 |
+
"node_modules/@radix-ui/react-separator": {
|
1269 |
+
"version": "1.0.3",
|
1270 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz",
|
1271 |
+
"integrity": "sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==",
|
1272 |
+
"dependencies": {
|
1273 |
+
"@babel/runtime": "^7.13.10",
|
1274 |
+
"@radix-ui/react-primitive": "1.0.3"
|
1275 |
+
},
|
1276 |
+
"peerDependencies": {
|
1277 |
+
"@types/react": "*",
|
1278 |
+
"@types/react-dom": "*",
|
1279 |
+
"react": "^16.8 || ^17.0 || ^18.0",
|
1280 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
1281 |
+
},
|
1282 |
+
"peerDependenciesMeta": {
|
1283 |
+
"@types/react": {
|
1284 |
+
"optional": true
|
1285 |
+
},
|
1286 |
+
"@types/react-dom": {
|
1287 |
+
"optional": true
|
1288 |
+
}
|
1289 |
+
}
|
1290 |
+
},
|
1291 |
"node_modules/@radix-ui/react-slot": {
|
1292 |
"version": "1.0.2",
|
1293 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
|
|
|
1429 |
}
|
1430 |
}
|
1431 |
},
|
1432 |
+
"node_modules/@radix-ui/react-visually-hidden": {
|
1433 |
+
"version": "1.0.3",
|
1434 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz",
|
1435 |
+
"integrity": "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==",
|
1436 |
+
"dependencies": {
|
1437 |
+
"@babel/runtime": "^7.13.10",
|
1438 |
+
"@radix-ui/react-primitive": "1.0.3"
|
1439 |
+
},
|
1440 |
+
"peerDependencies": {
|
1441 |
+
"@types/react": "*",
|
1442 |
+
"@types/react-dom": "*",
|
1443 |
+
"react": "^16.8 || ^17.0 || ^18.0",
|
1444 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
1445 |
+
},
|
1446 |
+
"peerDependenciesMeta": {
|
1447 |
+
"@types/react": {
|
1448 |
+
"optional": true
|
1449 |
+
},
|
1450 |
+
"@types/react-dom": {
|
1451 |
+
"optional": true
|
1452 |
+
}
|
1453 |
+
}
|
1454 |
+
},
|
1455 |
"node_modules/@radix-ui/rect": {
|
1456 |
"version": "1.0.1",
|
1457 |
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz",
|
|
|
1486 |
"tslib": "^2.4.0"
|
1487 |
}
|
1488 |
},
|
1489 |
+
"node_modules/@tanstack/query-core": {
|
1490 |
+
"version": "4.30.0",
|
1491 |
+
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.30.0.tgz",
|
1492 |
+
"integrity": "sha512-R5ozHCm3CJL9cT3j8cN6ztA0rdjw6pJN9e3zNeCPkwqfp89H1mQsn6W1RSJGuykzydQ+gFhAzteTM7NI3hz32g==",
|
1493 |
+
"funding": {
|
1494 |
+
"type": "github",
|
1495 |
+
"url": "https://github.com/sponsors/tannerlinsley"
|
1496 |
+
}
|
1497 |
+
},
|
1498 |
+
"node_modules/@tanstack/react-query": {
|
1499 |
+
"version": "4.30.0",
|
1500 |
+
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.30.0.tgz",
|
1501 |
+
"integrity": "sha512-uDURvabCVYtEamap4kmyLHCVOtzGSts83OsLpPvyzXMTHNptQwhU+YBH/vrgGAtceAuWn7JQfs9R9jJwPOJXXg==",
|
1502 |
+
"dependencies": {
|
1503 |
+
"@tanstack/query-core": "4.30.0",
|
1504 |
+
"use-sync-external-store": "^1.2.0"
|
1505 |
+
},
|
1506 |
+
"funding": {
|
1507 |
+
"type": "github",
|
1508 |
+
"url": "https://github.com/sponsors/tannerlinsley"
|
1509 |
+
},
|
1510 |
+
"peerDependencies": {
|
1511 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
1512 |
+
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
1513 |
+
"react-native": "*"
|
1514 |
+
},
|
1515 |
+
"peerDependenciesMeta": {
|
1516 |
+
"react-dom": {
|
1517 |
+
"optional": true
|
1518 |
+
},
|
1519 |
+
"react-native": {
|
1520 |
+
"optional": true
|
1521 |
+
}
|
1522 |
+
}
|
1523 |
+
},
|
1524 |
+
"node_modules/@tanstack/react-table": {
|
1525 |
+
"version": "8.9.3",
|
1526 |
+
"resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.9.3.tgz",
|
1527 |
+
"integrity": "sha512-Ng9rdm3JPoSCi6cVZvANsYnF+UoGVRxflMb270tVj0+LjeT/ZtZ9ckxF6oLPLcKesza6VKBqtdF9mQ+vaz24Aw==",
|
1528 |
+
"dependencies": {
|
1529 |
+
"@tanstack/table-core": "8.9.3"
|
1530 |
+
},
|
1531 |
+
"engines": {
|
1532 |
+
"node": ">=12"
|
1533 |
+
},
|
1534 |
+
"funding": {
|
1535 |
+
"type": "github",
|
1536 |
+
"url": "https://github.com/sponsors/tannerlinsley"
|
1537 |
+
},
|
1538 |
+
"peerDependencies": {
|
1539 |
+
"react": ">=16",
|
1540 |
+
"react-dom": ">=16"
|
1541 |
+
}
|
1542 |
+
},
|
1543 |
+
"node_modules/@tanstack/table-core": {
|
1544 |
+
"version": "8.9.3",
|
1545 |
+
"resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.9.3.tgz",
|
1546 |
+
"integrity": "sha512-NpHZBoHTfqyJk0m/s/+CSuAiwtebhYK90mDuf5eylTvgViNOujiaOaxNDxJkQQAsVvHWZftUGAx1EfO1rkKtLg==",
|
1547 |
+
"engines": {
|
1548 |
+
"node": ">=12"
|
1549 |
+
},
|
1550 |
+
"funding": {
|
1551 |
+
"type": "github",
|
1552 |
+
"url": "https://github.com/sponsors/tannerlinsley"
|
1553 |
+
}
|
1554 |
+
},
|
1555 |
"node_modules/@tsconfig/node10": {
|
1556 |
"version": "1.0.9",
|
1557 |
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
|
|
1572 |
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
1573 |
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="
|
1574 |
},
|
1575 |
+
"node_modules/@types/cookie": {
|
1576 |
+
"version": "0.4.1",
|
1577 |
+
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
1578 |
+
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
|
1579 |
+
},
|
1580 |
"node_modules/@types/fluent-ffmpeg": {
|
1581 |
"version": "2.1.21",
|
1582 |
"resolved": "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.21.tgz",
|
|
|
2638 |
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
2639 |
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
2640 |
},
|
2641 |
+
"node_modules/cookie": {
|
2642 |
+
"version": "0.4.2",
|
2643 |
+
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
2644 |
+
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
|
2645 |
+
"engines": {
|
2646 |
+
"node": ">= 0.6"
|
2647 |
+
}
|
2648 |
+
},
|
2649 |
+
"node_modules/cookies-next": {
|
2650 |
+
"version": "2.1.2",
|
2651 |
+
"resolved": "https://registry.npmjs.org/cookies-next/-/cookies-next-2.1.2.tgz",
|
2652 |
+
"integrity": "sha512-czxcfqVaQlo0Q/3xMgp/2jpspsuLJrIm6D37wlmibP3DAcYT315c8UxQmDMohhAT/GRWpaHzpDEFANBjzTFQGg==",
|
2653 |
+
"dependencies": {
|
2654 |
+
"@types/cookie": "^0.4.1",
|
2655 |
+
"@types/node": "^16.10.2",
|
2656 |
+
"cookie": "^0.4.0"
|
2657 |
+
}
|
2658 |
+
},
|
2659 |
+
"node_modules/cookies-next/node_modules/@types/node": {
|
2660 |
+
"version": "16.18.38",
|
2661 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.38.tgz",
|
2662 |
+
"integrity": "sha512-6sfo1qTulpVbkxECP+AVrHV9OoJqhzCsfTNp5NIG+enM4HyM3HvZCO798WShIXBN0+QtDIcutJCjsVYnQP5rIQ=="
|
2663 |
+
},
|
2664 |
"node_modules/cosmiconfig": {
|
2665 |
"version": "8.2.0",
|
2666 |
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz",
|
package.json
CHANGED
@@ -10,13 +10,20 @@
|
|
10 |
},
|
11 |
"dependencies": {
|
12 |
"@radix-ui/react-accordion": "^1.1.2",
|
|
|
13 |
"@radix-ui/react-checkbox": "^1.0.4",
|
14 |
"@radix-ui/react-collapsible": "^1.0.3",
|
15 |
"@radix-ui/react-dialog": "^1.0.4",
|
|
|
16 |
"@radix-ui/react-icons": "^1.3.0",
|
17 |
"@radix-ui/react-menubar": "^1.0.3",
|
|
|
|
|
|
|
18 |
"@radix-ui/react-slot": "^1.0.2",
|
19 |
"@silevis/reactgrid": "^4.0.5",
|
|
|
|
|
20 |
"@types/fluent-ffmpeg": "^2.1.21",
|
21 |
"@types/node": "20.4.2",
|
22 |
"@types/react": "18.2.15",
|
@@ -26,6 +33,7 @@
|
|
26 |
"class-variance-authority": "^0.6.1",
|
27 |
"clsx": "^2.0.0",
|
28 |
"cmdk": "^0.2.0",
|
|
|
29 |
"date-fns": "^2.30.0",
|
30 |
"eslint": "8.45.0",
|
31 |
"eslint-config-next": "13.4.10",
|
@@ -45,6 +53,7 @@
|
|
45 |
"ts-node": "^10.9.1",
|
46 |
"typescript": "5.1.6",
|
47 |
"uuid": "^9.0.0",
|
|
|
48 |
"zustand": "^4.3.9"
|
49 |
}
|
50 |
}
|
|
|
10 |
},
|
11 |
"dependencies": {
|
12 |
"@radix-ui/react-accordion": "^1.1.2",
|
13 |
+
"@radix-ui/react-avatar": "^1.0.3",
|
14 |
"@radix-ui/react-checkbox": "^1.0.4",
|
15 |
"@radix-ui/react-collapsible": "^1.0.3",
|
16 |
"@radix-ui/react-dialog": "^1.0.4",
|
17 |
+
"@radix-ui/react-dropdown-menu": "^2.0.5",
|
18 |
"@radix-ui/react-icons": "^1.3.0",
|
19 |
"@radix-ui/react-menubar": "^1.0.3",
|
20 |
+
"@radix-ui/react-popover": "^1.0.6",
|
21 |
+
"@radix-ui/react-select": "^1.2.2",
|
22 |
+
"@radix-ui/react-separator": "^1.0.3",
|
23 |
"@radix-ui/react-slot": "^1.0.2",
|
24 |
"@silevis/reactgrid": "^4.0.5",
|
25 |
+
"@tanstack/react-query": "^4.30.0",
|
26 |
+
"@tanstack/react-table": "^8.9.3",
|
27 |
"@types/fluent-ffmpeg": "^2.1.21",
|
28 |
"@types/node": "20.4.2",
|
29 |
"@types/react": "18.2.15",
|
|
|
33 |
"class-variance-authority": "^0.6.1",
|
34 |
"clsx": "^2.0.0",
|
35 |
"cmdk": "^0.2.0",
|
36 |
+
"cookies-next": "^2.1.2",
|
37 |
"date-fns": "^2.30.0",
|
38 |
"eslint": "8.45.0",
|
39 |
"eslint-config-next": "13.4.10",
|
|
|
53 |
"ts-node": "^10.9.1",
|
54 |
"typescript": "5.1.6",
|
55 |
"uuid": "^9.0.0",
|
56 |
+
"zod": "^3.21.4",
|
57 |
"zustand": "^4.3.9"
|
58 |
}
|
59 |
}
|
src/api/index.ts
DELETED
@@ -1,16 +0,0 @@
|
|
1 |
-
|
2 |
-
import { VideoTask } from "@/app/types"
|
3 |
-
|
4 |
-
import { get } from "./base"
|
5 |
-
|
6 |
-
export const getPendingTasks = async () => {
|
7 |
-
const tasks = await get<VideoTask[]>("", [])
|
8 |
-
|
9 |
-
return tasks
|
10 |
-
}
|
11 |
-
|
12 |
-
export const getTask = async (id: string) => {
|
13 |
-
const task = await get<VideoTask>(id, null as unknown as VideoTask)
|
14 |
-
|
15 |
-
return task
|
16 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app/api/tasks/[uuid]/route.ts
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { NextApiRequest, NextApiResponse } from "next"
|
2 |
+
|
3 |
+
import { VideoTask } from "@/app/types"
|
4 |
+
import { NextResponse } from "next/server"
|
5 |
+
import { getTask } from "@/server"
|
6 |
+
|
7 |
+
// TODO: implement some kind of quota system
|
8 |
+
export async function GET(
|
9 |
+
req: NextApiRequest,
|
10 |
+
res: NextApiResponse<{
|
11 |
+
task?: VideoTask
|
12 |
+
error?: string
|
13 |
+
}>
|
14 |
+
) {
|
15 |
+
return NextResponse.json({
|
16 |
+
task: await getTask(`${req.url?.split('/').pop() || ""}`)
|
17 |
+
})
|
18 |
+
}
|
src/app/api/tasks/route.ts
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { VideoTask, VideoTaskRequest } from "@/app/types"
|
2 |
+
import { getPendingTasks, submitNewTask } from "@/server"
|
3 |
+
import { NextApiRequest, NextApiResponse } from "next"
|
4 |
+
import { NextResponse } from "next/server"
|
5 |
+
|
6 |
+
// TODO: implement some kind of quota system
|
7 |
+
export async function GET() {
|
8 |
+
return NextResponse.json({
|
9 |
+
tasks: await getPendingTasks()
|
10 |
+
})
|
11 |
+
}
|
12 |
+
|
13 |
+
// TODO: implement some kind of quota system
|
14 |
+
export async function POST(
|
15 |
+
req: NextApiRequest,
|
16 |
+
res: NextApiResponse<VideoTask | {
|
17 |
+
error?: string
|
18 |
+
}>
|
19 |
+
) {
|
20 |
+
console.log('POST req.body:', req.body)
|
21 |
+
const taskRequest = req.body as VideoTaskRequest
|
22 |
+
const task = await submitNewTask(taskRequest)
|
23 |
+
res.status(200).json(task)
|
24 |
+
}
|
src/app/layout.tsx
CHANGED
@@ -1,13 +1,12 @@
|
|
1 |
import './globals.css'
|
2 |
import type { Metadata } from 'next'
|
3 |
import { Inter } from 'next/font/google'
|
4 |
-
import Head from 'next/head'
|
5 |
|
6 |
const inter = Inter({ subsets: ['latin'] })
|
7 |
|
8 |
export const metadata: Metadata = {
|
9 |
-
title: '
|
10 |
-
description: '
|
11 |
}
|
12 |
|
13 |
export default function RootLayout({
|
@@ -17,7 +16,9 @@ export default function RootLayout({
|
|
17 |
}) {
|
18 |
return (
|
19 |
<html lang="en">
|
20 |
-
<body className={inter.className}>
|
|
|
|
|
21 |
</html>
|
22 |
)
|
23 |
}
|
|
|
1 |
import './globals.css'
|
2 |
import type { Metadata } from 'next'
|
3 |
import { Inter } from 'next/font/google'
|
|
|
4 |
|
5 |
const inter = Inter({ subsets: ['latin'] })
|
6 |
|
7 |
export const metadata: Metadata = {
|
8 |
+
title: 'VideoChain UI',
|
9 |
+
description: 'Generate AI videos using this Hugging Face Space!',
|
10 |
}
|
11 |
|
12 |
export default function RootLayout({
|
|
|
16 |
}) {
|
17 |
return (
|
18 |
<html lang="en">
|
19 |
+
<body className={inter.className}>
|
20 |
+
{children}
|
21 |
+
</body>
|
22 |
</html>
|
23 |
)
|
24 |
}
|
src/app/main.tsx
DELETED
@@ -1,66 +0,0 @@
|
|
1 |
-
import { promises as fs } from "fs"
|
2 |
-
import path from "path"
|
3 |
-
import { Metadata } from "next"
|
4 |
-
import Image from "next/image"
|
5 |
-
import { z } from "zod"
|
6 |
-
|
7 |
-
import { taskSchema } from "./data/schema"
|
8 |
-
import { UserNav } from "@/components/business/tasks/user-nav"
|
9 |
-
import { DataTable } from "@/components/business/tasks/data-table"
|
10 |
-
import { columns } from "@/components/business/tasks/columns"
|
11 |
-
|
12 |
-
|
13 |
-
export const metadata: Metadata = {
|
14 |
-
title: "Tasks",
|
15 |
-
description: "A task and issue tracker build using Tanstack Table.",
|
16 |
-
}
|
17 |
-
|
18 |
-
// Simulate a database read for tasks.
|
19 |
-
async function getTasks() {
|
20 |
-
const data = await fs.readFile(
|
21 |
-
path.join(process.cwd(), "src/app/data/mock.json")
|
22 |
-
)
|
23 |
-
|
24 |
-
const tasks = JSON.parse(data.toString())
|
25 |
-
|
26 |
-
return z.array(taskSchema).parse(tasks)
|
27 |
-
}
|
28 |
-
|
29 |
-
export default async function Main() {
|
30 |
-
const tasks = await getTasks()
|
31 |
-
|
32 |
-
return (
|
33 |
-
<>
|
34 |
-
<div className="md:hidden">
|
35 |
-
<Image
|
36 |
-
src="/examples/tasks-light.png"
|
37 |
-
width={1280}
|
38 |
-
height={998}
|
39 |
-
alt="Playground"
|
40 |
-
className="block dark:hidden"
|
41 |
-
/>
|
42 |
-
<Image
|
43 |
-
src="/examples/tasks-dark.png"
|
44 |
-
width={1280}
|
45 |
-
height={998}
|
46 |
-
alt="Playground"
|
47 |
-
className="hidden dark:block"
|
48 |
-
/>
|
49 |
-
</div>
|
50 |
-
<div className="hidden h-full flex-1 flex-col space-y-8 p-8 md:flex">
|
51 |
-
<div className="flex items-center justify-between space-y-2">
|
52 |
-
<div>
|
53 |
-
<h2 className="text-2xl font-bold tracking-tight">Welcome back!</h2>
|
54 |
-
<p className="text-muted-foreground">
|
55 |
-
Here's a list of your tasks for this month!
|
56 |
-
</p>
|
57 |
-
</div>
|
58 |
-
<div className="flex items-center space-x-2">
|
59 |
-
<UserNav />
|
60 |
-
</div>
|
61 |
-
</div>
|
62 |
-
<DataTable data={tasks} columns={columns} />
|
63 |
-
</div>
|
64 |
-
</>
|
65 |
-
)
|
66 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app/page.tsx
CHANGED
@@ -1,18 +1,7 @@
|
|
1 |
-
import
|
2 |
-
|
3 |
-
import Main from "./main"
|
4 |
|
5 |
export default function Index() {
|
6 |
-
|
7 |
-
|
8 |
-
<Head>
|
9 |
-
<meta name="viewport" content="width=device-width, initial-scale=0.86, maximum-scale=5.0, minimum-scale=0.86" />
|
10 |
-
</Head>
|
11 |
-
<main className="h-screen w-full flex bg-gray-700 text-gray-200">
|
12 |
-
<div className="flex flex-col">
|
13 |
-
<Main />
|
14 |
-
</div>
|
15 |
-
</main>
|
16 |
-
</div>
|
17 |
-
)
|
18 |
}
|
|
|
1 |
+
import { redirect } from 'next/navigation'
|
2 |
+
import { v4 as uuidv4 } from "uuid"
|
|
|
3 |
|
4 |
export default function Index() {
|
5 |
+
const uuid = uuidv4()
|
6 |
+
redirect(`/studio/${uuid}`)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
}
|
src/app/studio/[ownerId]/main.tsx
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use server"
|
2 |
+
|
3 |
+
// import { experimental_useFormStatus as useFormStatus } from "react-dom"
|
4 |
+
|
5 |
+
import { VideoTasksQueue } from "@/components/business/tasks/video-tasks-queue"
|
6 |
+
import { Textarea } from "@/components/ui/textarea"
|
7 |
+
import { Button } from "@/components/ui/button"
|
8 |
+
import { formSubmit } from "@/server/actions"
|
9 |
+
import { getTasks } from "@/server"
|
10 |
+
|
11 |
+
export default async function Main({ ownerId }: { ownerId: string }) {
|
12 |
+
const tasks = await getTasks(ownerId)
|
13 |
+
|
14 |
+
return (
|
15 |
+
<form
|
16 |
+
className="h-full flex flex-col space-y-4 max-w-4xl w-full px-4 py-8"
|
17 |
+
action={formSubmit}
|
18 |
+
>
|
19 |
+
|
20 |
+
<div className="flex flex-col md:hidden w-full text-center">
|
21 |
+
<h2 className="text-4xl font-thin tracking-tight">VideoChain UI</h2>
|
22 |
+
<p className="text-md font-thin">
|
23 |
+
Powered by <span className="font-normal">Hugging Face π€</span>
|
24 |
+
</p>
|
25 |
+
</div>
|
26 |
+
|
27 |
+
<div className="flex items-center justify-between md:space-x-3 w-full">
|
28 |
+
<div className="hidden md:flex flex-col w-54">
|
29 |
+
<h2 className="text-4xl font-thin tracking-tight">VideoChain UI</h2>
|
30 |
+
<p className="text-md font-thin">
|
31 |
+
Powered by <span className="font-normal">Hugging Face π€</span>
|
32 |
+
</p>
|
33 |
+
</div>
|
34 |
+
|
35 |
+
<input
|
36 |
+
type="hidden"
|
37 |
+
id="ownerId"
|
38 |
+
name="ownerId"
|
39 |
+
value={ownerId}
|
40 |
+
/>
|
41 |
+
|
42 |
+
<Textarea
|
43 |
+
id="prompt"
|
44 |
+
name="prompt"
|
45 |
+
placeholder="Video of llamas playing baseball.."
|
46 |
+
className="md:w-3/6 mr-3 md:mr-0"
|
47 |
+
/>
|
48 |
+
|
49 |
+
<Button
|
50 |
+
variant="secondary"
|
51 |
+
size="lg"
|
52 |
+
className="text-md md:w-32"
|
53 |
+
type="submit"
|
54 |
+
>
|
55 |
+
Generate
|
56 |
+
</Button>
|
57 |
+
</div>
|
58 |
+
<VideoTasksQueue tasks={tasks} />
|
59 |
+
</form>
|
60 |
+
)
|
61 |
+
}
|
src/app/{pending β studio/[ownerId]}/page.tsx
RENAMED
@@ -1,20 +1,17 @@
|
|
1 |
import Head from "next/head"
|
2 |
|
3 |
-
import
|
4 |
|
|
|
|
|
5 |
|
6 |
-
export default async function Pending() {
|
7 |
-
const tasks = await getPendingTasks()
|
8 |
-
console.log(`tasks:`, tasks)
|
9 |
return (
|
10 |
<div>
|
11 |
<Head>
|
12 |
<meta name="viewport" content="width=device-width, initial-scale=0.86, maximum-scale=5.0, minimum-scale=0.86" />
|
13 |
</Head>
|
14 |
-
<main className="h-screen w-full flex bg-
|
15 |
-
<
|
16 |
-
Nb tasks: {tasks.length}
|
17 |
-
</div>
|
18 |
</main>
|
19 |
</div>
|
20 |
)
|
|
|
1 |
import Head from "next/head"
|
2 |
|
3 |
+
import Main from "./main"
|
4 |
|
5 |
+
export default async function StudioPage({ params: { ownerId } }: { params: { ownerId: string }}) {
|
6 |
+
console.log('ownerId:', ownerId)
|
7 |
|
|
|
|
|
|
|
8 |
return (
|
9 |
<div>
|
10 |
<Head>
|
11 |
<meta name="viewport" content="width=device-width, initial-scale=0.86, maximum-scale=5.0, minimum-scale=0.86" />
|
12 |
</Head>
|
13 |
+
<main className="dark h-screen w-full flex flex-col items-center bg-stone-900 text-stone-100">
|
14 |
+
<Main ownerId={`${ownerId || ""}`} />
|
|
|
|
|
15 |
</main>
|
16 |
</div>
|
17 |
)
|
src/app/types.ts
CHANGED
@@ -210,7 +210,6 @@ export interface VideoSequenceData {
|
|
210 |
|
211 |
hasAssembledVideo: boolean
|
212 |
nbCompletedShots: number
|
213 |
-
nbTotalShots: number
|
214 |
progressPercent: number
|
215 |
completedAt: string
|
216 |
completed: boolean
|
@@ -219,11 +218,12 @@ export interface VideoSequenceData {
|
|
219 |
|
220 |
export type VideoSequence = VideoSequenceMeta & VideoSequenceData
|
221 |
|
222 |
-
export type
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
|
|
227 |
|
228 |
export type VideoTask = VideoSequence & {
|
229 |
shots: VideoShot[]
|
|
|
210 |
|
211 |
hasAssembledVideo: boolean
|
212 |
nbCompletedShots: number
|
|
|
213 |
progressPercent: number
|
214 |
completedAt: string
|
215 |
completed: boolean
|
|
|
218 |
|
219 |
export type VideoSequence = VideoSequenceMeta & VideoSequenceData
|
220 |
|
221 |
+
export type VideoTaskRequest = Partial<{
|
222 |
+
prompt: string
|
223 |
+
ownerId: string
|
224 |
+
sequence: Partial<VideoSequenceMeta>
|
225 |
+
shots: Array<Partial<VideoShotMeta>>
|
226 |
+
}>
|
227 |
|
228 |
export type VideoTask = VideoSequence & {
|
229 |
shots: VideoShot[]
|
src/components/business/tasks/columns.tsx
CHANGED
@@ -1,17 +1,16 @@
|
|
1 |
"use client"
|
2 |
|
3 |
import { ColumnDef } from "@tanstack/react-table"
|
4 |
-
|
5 |
-
import { Badge } from "@/components/ui/badge"
|
6 |
import { Checkbox } from "@/components/ui/checkbox"
|
7 |
|
8 |
-
import {
|
9 |
|
10 |
import { DataTableColumnHeader } from "./data-table-column-header"
|
11 |
import { DataTableRowActions } from "./data-table-row-actions"
|
12 |
-
import { Task } from "@/app/data/schema"
|
13 |
|
14 |
-
|
|
|
|
|
15 |
{
|
16 |
id: "select",
|
17 |
header: ({ table }) => (
|
@@ -26,7 +25,7 @@ export const columns: ColumnDef<Task>[] = [
|
|
26 |
<Checkbox
|
27 |
checked={row.getIsSelected()}
|
28 |
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
29 |
-
aria-label="Select
|
30 |
className="translate-y-[2px]"
|
31 |
/>
|
32 |
),
|
@@ -36,25 +35,22 @@ export const columns: ColumnDef<Task>[] = [
|
|
36 |
{
|
37 |
accessorKey: "id",
|
38 |
header: ({ column }) => (
|
39 |
-
<DataTableColumnHeader column={column} title="
|
40 |
),
|
41 |
-
cell: ({ row }) => <div className="w-[80px]">{row.getValue("id")}
|
42 |
enableSorting: false,
|
43 |
enableHiding: false,
|
44 |
},
|
45 |
{
|
46 |
-
accessorKey: "
|
47 |
header: ({ column }) => (
|
48 |
-
<DataTableColumnHeader column={column} title="
|
49 |
),
|
50 |
cell: ({ row }) => {
|
51 |
-
const label = labels.find((label) => label.value === row.original.label)
|
52 |
-
|
53 |
return (
|
54 |
<div className="flex space-x-2">
|
55 |
-
{label && <Badge variant="outline">{label.label}</Badge>}
|
56 |
<span className="max-w-[500px] truncate font-medium">
|
57 |
-
{row.getValue("
|
58 |
</span>
|
59 |
</div>
|
60 |
)
|
@@ -88,34 +84,40 @@ export const columns: ColumnDef<Task>[] = [
|
|
88 |
},
|
89 |
},
|
90 |
{
|
91 |
-
accessorKey: "
|
92 |
header: ({ column }) => (
|
93 |
-
|
94 |
),
|
95 |
-
cell: ({ row }) =>
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
|
|
|
|
|
|
116 |
},
|
|
|
|
|
117 |
{
|
118 |
id: "actions",
|
119 |
cell: ({ row }) => <DataTableRowActions row={row} />,
|
120 |
},
|
|
|
121 |
]
|
|
|
1 |
"use client"
|
2 |
|
3 |
import { ColumnDef } from "@tanstack/react-table"
|
|
|
|
|
4 |
import { Checkbox } from "@/components/ui/checkbox"
|
5 |
|
6 |
+
import { statuses } from "@/app/data/data"
|
7 |
|
8 |
import { DataTableColumnHeader } from "./data-table-column-header"
|
9 |
import { DataTableRowActions } from "./data-table-row-actions"
|
|
|
10 |
|
11 |
+
import { VideoTask } from "@/app/types"
|
12 |
+
|
13 |
+
export const columns: ColumnDef<VideoTask>[] = [
|
14 |
{
|
15 |
id: "select",
|
16 |
header: ({ table }) => (
|
|
|
25 |
<Checkbox
|
26 |
checked={row.getIsSelected()}
|
27 |
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
28 |
+
aria-label="Select video"
|
29 |
className="translate-y-[2px]"
|
30 |
/>
|
31 |
),
|
|
|
35 |
{
|
36 |
accessorKey: "id",
|
37 |
header: ({ column }) => (
|
38 |
+
<DataTableColumnHeader column={column} title="Video ID" />
|
39 |
),
|
40 |
+
cell: ({ row }) => <div className="w-[80px]">{`${row.getValue("id") || ''}`.split("-")[0]}..</div>,
|
41 |
enableSorting: false,
|
42 |
enableHiding: false,
|
43 |
},
|
44 |
{
|
45 |
+
accessorKey: "videoPrompt",
|
46 |
header: ({ column }) => (
|
47 |
+
<DataTableColumnHeader column={column} title="Prompt" />
|
48 |
),
|
49 |
cell: ({ row }) => {
|
|
|
|
|
50 |
return (
|
51 |
<div className="flex space-x-2">
|
|
|
52 |
<span className="max-w-[500px] truncate font-medium">
|
53 |
+
{row.getValue("videoPrompt")}
|
54 |
</span>
|
55 |
</div>
|
56 |
)
|
|
|
84 |
},
|
85 |
},
|
86 |
{
|
87 |
+
accessorKey: "preview",
|
88 |
header: ({ column }) => (
|
89 |
+
null // no header
|
90 |
),
|
91 |
+
cell: ({ row }) => <div className="w-[200px]">
|
92 |
+
<a
|
93 |
+
className="hover:underline cursor-pointer"
|
94 |
+
target="_blank"
|
95 |
+
href={`/api/download/${row.getValue("fileName")}`}>
|
96 |
+
<video src={`/api/download/${row.getValue("fileName")}`} muted autoPlay />
|
97 |
+
</a>
|
98 |
+
</div>,
|
99 |
+
enableSorting: false,
|
100 |
+
enableHiding: false,
|
101 |
+
},
|
102 |
+
{
|
103 |
+
accessorKey: "fileName",
|
104 |
+
header: ({ column }) => (
|
105 |
+
null // no header
|
106 |
+
),
|
107 |
+
cell: ({ row }) => <div className="w-[80px]">
|
108 |
+
<a
|
109 |
+
className="hover:underline cursor-pointer"
|
110 |
+
target="_blank"
|
111 |
+
href={`/api/download/${row.getValue("fileName")}`}>Download</a>
|
112 |
+
</div>,
|
113 |
+
enableSorting: false,
|
114 |
+
enableHiding: false,
|
115 |
},
|
116 |
+
/*
|
117 |
+
action menu (currently disabled)
|
118 |
{
|
119 |
id: "actions",
|
120 |
cell: ({ row }) => <DataTableRowActions row={row} />,
|
121 |
},
|
122 |
+
*/
|
123 |
]
|
src/components/business/tasks/data-table-faceted-filter.tsx
DELETED
@@ -1,147 +0,0 @@
|
|
1 |
-
import * as React from "react"
|
2 |
-
import { CheckIcon, PlusCircledIcon } from "@radix-ui/react-icons"
|
3 |
-
import { Column } from "@tanstack/react-table"
|
4 |
-
|
5 |
-
import { cn } from "@/lib/utils"
|
6 |
-
import { Badge } from "@/components/ui/badge"
|
7 |
-
import { Button } from "@/components/ui/button"
|
8 |
-
import {
|
9 |
-
Command,
|
10 |
-
CommandEmpty,
|
11 |
-
CommandGroup,
|
12 |
-
CommandInput,
|
13 |
-
CommandItem,
|
14 |
-
CommandList,
|
15 |
-
CommandSeparator,
|
16 |
-
} from "@/components/ui/command"
|
17 |
-
import {
|
18 |
-
Popover,
|
19 |
-
PopoverContent,
|
20 |
-
PopoverTrigger,
|
21 |
-
} from "@/components/ui/popover"
|
22 |
-
import { Separator } from "@/components/ui/separator"
|
23 |
-
|
24 |
-
interface DataTableFacetedFilter<TData, TValue> {
|
25 |
-
column?: Column<TData, TValue>
|
26 |
-
title?: string
|
27 |
-
options: {
|
28 |
-
label: string
|
29 |
-
value: string
|
30 |
-
icon?: React.ComponentType<{ className?: string }>
|
31 |
-
}[]
|
32 |
-
}
|
33 |
-
|
34 |
-
export function DataTableFacetedFilter<TData, TValue>({
|
35 |
-
column,
|
36 |
-
title,
|
37 |
-
options,
|
38 |
-
}: DataTableFacetedFilter<TData, TValue>) {
|
39 |
-
const facets = column?.getFacetedUniqueValues()
|
40 |
-
const selectedValues = new Set(column?.getFilterValue() as string[])
|
41 |
-
|
42 |
-
return (
|
43 |
-
<Popover>
|
44 |
-
<PopoverTrigger asChild>
|
45 |
-
<Button variant="outline" size="sm" className="h-8 border-dashed">
|
46 |
-
<PlusCircledIcon className="mr-2 h-4 w-4" />
|
47 |
-
{title}
|
48 |
-
{selectedValues?.size > 0 && (
|
49 |
-
<>
|
50 |
-
<Separator orientation="vertical" className="mx-2 h-4" />
|
51 |
-
<Badge
|
52 |
-
variant="secondary"
|
53 |
-
className="rounded-sm px-1 font-normal lg:hidden"
|
54 |
-
>
|
55 |
-
{selectedValues.size}
|
56 |
-
</Badge>
|
57 |
-
<div className="hidden space-x-1 lg:flex">
|
58 |
-
{selectedValues.size > 2 ? (
|
59 |
-
<Badge
|
60 |
-
variant="secondary"
|
61 |
-
className="rounded-sm px-1 font-normal"
|
62 |
-
>
|
63 |
-
{selectedValues.size} selected
|
64 |
-
</Badge>
|
65 |
-
) : (
|
66 |
-
options
|
67 |
-
.filter((option) => selectedValues.has(option.value))
|
68 |
-
.map((option) => (
|
69 |
-
<Badge
|
70 |
-
variant="secondary"
|
71 |
-
key={option.value}
|
72 |
-
className="rounded-sm px-1 font-normal"
|
73 |
-
>
|
74 |
-
{option.label}
|
75 |
-
</Badge>
|
76 |
-
))
|
77 |
-
)}
|
78 |
-
</div>
|
79 |
-
</>
|
80 |
-
)}
|
81 |
-
</Button>
|
82 |
-
</PopoverTrigger>
|
83 |
-
<PopoverContent className="w-[200px] p-0" align="start">
|
84 |
-
<Command>
|
85 |
-
<CommandInput placeholder={title} />
|
86 |
-
<CommandList>
|
87 |
-
<CommandEmpty>No results found.</CommandEmpty>
|
88 |
-
<CommandGroup>
|
89 |
-
{options.map((option) => {
|
90 |
-
const isSelected = selectedValues.has(option.value)
|
91 |
-
return (
|
92 |
-
<CommandItem
|
93 |
-
key={option.value}
|
94 |
-
onSelect={() => {
|
95 |
-
if (isSelected) {
|
96 |
-
selectedValues.delete(option.value)
|
97 |
-
} else {
|
98 |
-
selectedValues.add(option.value)
|
99 |
-
}
|
100 |
-
const filterValues = Array.from(selectedValues)
|
101 |
-
column?.setFilterValue(
|
102 |
-
filterValues.length ? filterValues : undefined
|
103 |
-
)
|
104 |
-
}}
|
105 |
-
>
|
106 |
-
<div
|
107 |
-
className={cn(
|
108 |
-
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
109 |
-
isSelected
|
110 |
-
? "bg-primary text-primary-foreground"
|
111 |
-
: "opacity-50 [&_svg]:invisible"
|
112 |
-
)}
|
113 |
-
>
|
114 |
-
<CheckIcon className={cn("h-4 w-4")} />
|
115 |
-
</div>
|
116 |
-
{option.icon && (
|
117 |
-
<option.icon className="mr-2 h-4 w-4 text-muted-foreground" />
|
118 |
-
)}
|
119 |
-
<span>{option.label}</span>
|
120 |
-
{facets?.get(option.value) && (
|
121 |
-
<span className="ml-auto flex h-4 w-4 items-center justify-center font-mono text-xs">
|
122 |
-
{facets.get(option.value)}
|
123 |
-
</span>
|
124 |
-
)}
|
125 |
-
</CommandItem>
|
126 |
-
)
|
127 |
-
})}
|
128 |
-
</CommandGroup>
|
129 |
-
{selectedValues.size > 0 && (
|
130 |
-
<>
|
131 |
-
<CommandSeparator />
|
132 |
-
<CommandGroup>
|
133 |
-
<CommandItem
|
134 |
-
onSelect={() => column?.setFilterValue(undefined)}
|
135 |
-
className="justify-center text-center"
|
136 |
-
>
|
137 |
-
Clear filters
|
138 |
-
</CommandItem>
|
139 |
-
</CommandGroup>
|
140 |
-
</>
|
141 |
-
)}
|
142 |
-
</CommandList>
|
143 |
-
</Command>
|
144 |
-
</PopoverContent>
|
145 |
-
</Popover>
|
146 |
-
)
|
147 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/business/tasks/data-table-pagination.tsx
DELETED
@@ -1,97 +0,0 @@
|
|
1 |
-
import {
|
2 |
-
ChevronLeftIcon,
|
3 |
-
ChevronRightIcon,
|
4 |
-
DoubleArrowLeftIcon,
|
5 |
-
DoubleArrowRightIcon,
|
6 |
-
} from "@radix-ui/react-icons"
|
7 |
-
import { Table } from "@tanstack/react-table"
|
8 |
-
|
9 |
-
import { Button } from "@/components/ui/button"
|
10 |
-
import {
|
11 |
-
Select,
|
12 |
-
SelectContent,
|
13 |
-
SelectItem,
|
14 |
-
SelectTrigger,
|
15 |
-
SelectValue,
|
16 |
-
} from "@/components/ui/select"
|
17 |
-
|
18 |
-
interface DataTablePaginationProps<TData> {
|
19 |
-
table: Table<TData>
|
20 |
-
}
|
21 |
-
|
22 |
-
export function DataTablePagination<TData>({
|
23 |
-
table,
|
24 |
-
}: DataTablePaginationProps<TData>) {
|
25 |
-
return (
|
26 |
-
<div className="flex items-center justify-between px-2">
|
27 |
-
<div className="flex-1 text-sm text-muted-foreground">
|
28 |
-
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
29 |
-
{table.getFilteredRowModel().rows.length} row(s) selected.
|
30 |
-
</div>
|
31 |
-
<div className="flex items-center space-x-6 lg:space-x-8">
|
32 |
-
<div className="flex items-center space-x-2">
|
33 |
-
<p className="text-sm font-medium">Rows per page</p>
|
34 |
-
<Select
|
35 |
-
value={`${table.getState().pagination.pageSize}`}
|
36 |
-
onValueChange={(value) => {
|
37 |
-
table.setPageSize(Number(value))
|
38 |
-
}}
|
39 |
-
>
|
40 |
-
<SelectTrigger className="h-8 w-[70px]">
|
41 |
-
<SelectValue placeholder={table.getState().pagination.pageSize} />
|
42 |
-
</SelectTrigger>
|
43 |
-
<SelectContent side="top">
|
44 |
-
{[10, 20, 30, 40, 50].map((pageSize) => (
|
45 |
-
<SelectItem key={pageSize} value={`${pageSize}`}>
|
46 |
-
{pageSize}
|
47 |
-
</SelectItem>
|
48 |
-
))}
|
49 |
-
</SelectContent>
|
50 |
-
</Select>
|
51 |
-
</div>
|
52 |
-
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
|
53 |
-
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
54 |
-
{table.getPageCount()}
|
55 |
-
</div>
|
56 |
-
<div className="flex items-center space-x-2">
|
57 |
-
<Button
|
58 |
-
variant="outline"
|
59 |
-
className="hidden h-8 w-8 p-0 lg:flex"
|
60 |
-
onClick={() => table.setPageIndex(0)}
|
61 |
-
disabled={!table.getCanPreviousPage()}
|
62 |
-
>
|
63 |
-
<span className="sr-only">Go to first page</span>
|
64 |
-
<DoubleArrowLeftIcon className="h-4 w-4" />
|
65 |
-
</Button>
|
66 |
-
<Button
|
67 |
-
variant="outline"
|
68 |
-
className="h-8 w-8 p-0"
|
69 |
-
onClick={() => table.previousPage()}
|
70 |
-
disabled={!table.getCanPreviousPage()}
|
71 |
-
>
|
72 |
-
<span className="sr-only">Go to previous page</span>
|
73 |
-
<ChevronLeftIcon className="h-4 w-4" />
|
74 |
-
</Button>
|
75 |
-
<Button
|
76 |
-
variant="outline"
|
77 |
-
className="h-8 w-8 p-0"
|
78 |
-
onClick={() => table.nextPage()}
|
79 |
-
disabled={!table.getCanNextPage()}
|
80 |
-
>
|
81 |
-
<span className="sr-only">Go to next page</span>
|
82 |
-
<ChevronRightIcon className="h-4 w-4" />
|
83 |
-
</Button>
|
84 |
-
<Button
|
85 |
-
variant="outline"
|
86 |
-
className="hidden h-8 w-8 p-0 lg:flex"
|
87 |
-
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
88 |
-
disabled={!table.getCanNextPage()}
|
89 |
-
>
|
90 |
-
<span className="sr-only">Go to last page</span>
|
91 |
-
<DoubleArrowRightIcon className="h-4 w-4" />
|
92 |
-
</Button>
|
93 |
-
</div>
|
94 |
-
</div>
|
95 |
-
</div>
|
96 |
-
)
|
97 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/business/tasks/data-table-row-actions.tsx
CHANGED
@@ -8,27 +8,19 @@ import {
|
|
8 |
DropdownMenu,
|
9 |
DropdownMenuContent,
|
10 |
DropdownMenuItem,
|
11 |
-
DropdownMenuRadioGroup,
|
12 |
-
DropdownMenuRadioItem,
|
13 |
DropdownMenuSeparator,
|
14 |
DropdownMenuShortcut,
|
15 |
-
DropdownMenuSub,
|
16 |
-
DropdownMenuSubContent,
|
17 |
-
DropdownMenuSubTrigger,
|
18 |
DropdownMenuTrigger,
|
19 |
} from "@/components/ui/dropdown-menu"
|
20 |
|
21 |
-
import {
|
22 |
-
import { taskSchema } from "@/app/data/schema"
|
23 |
|
24 |
-
|
25 |
-
row: Row<TData>
|
26 |
-
}
|
27 |
-
|
28 |
-
export function DataTableRowActions<TData>({
|
29 |
row,
|
30 |
-
}:
|
31 |
-
|
|
|
|
|
32 |
|
33 |
return (
|
34 |
<DropdownMenu>
|
@@ -42,22 +34,7 @@ export function DataTableRowActions<TData>({
|
|
42 |
</Button>
|
43 |
</DropdownMenuTrigger>
|
44 |
<DropdownMenuContent align="end" className="w-[160px]">
|
45 |
-
<DropdownMenuItem>
|
46 |
-
<DropdownMenuItem>Make a copy</DropdownMenuItem>
|
47 |
-
<DropdownMenuItem>Favorite</DropdownMenuItem>
|
48 |
-
<DropdownMenuSeparator />
|
49 |
-
<DropdownMenuSub>
|
50 |
-
<DropdownMenuSubTrigger>Labels</DropdownMenuSubTrigger>
|
51 |
-
<DropdownMenuSubContent>
|
52 |
-
<DropdownMenuRadioGroup value={task.label}>
|
53 |
-
{labels.map((label) => (
|
54 |
-
<DropdownMenuRadioItem key={label.value} value={label.value}>
|
55 |
-
{label.label}
|
56 |
-
</DropdownMenuRadioItem>
|
57 |
-
))}
|
58 |
-
</DropdownMenuRadioGroup>
|
59 |
-
</DropdownMenuSubContent>
|
60 |
-
</DropdownMenuSub>
|
61 |
<DropdownMenuSeparator />
|
62 |
<DropdownMenuItem>
|
63 |
Delete
|
|
|
8 |
DropdownMenu,
|
9 |
DropdownMenuContent,
|
10 |
DropdownMenuItem,
|
|
|
|
|
11 |
DropdownMenuSeparator,
|
12 |
DropdownMenuShortcut,
|
|
|
|
|
|
|
13 |
DropdownMenuTrigger,
|
14 |
} from "@/components/ui/dropdown-menu"
|
15 |
|
16 |
+
import { VideoTask } from "@/app/types"
|
|
|
17 |
|
18 |
+
export function DataTableRowActions({
|
|
|
|
|
|
|
|
|
19 |
row,
|
20 |
+
}: {
|
21 |
+
row: Row<VideoTask>
|
22 |
+
}) {
|
23 |
+
const task = row.original
|
24 |
|
25 |
return (
|
26 |
<DropdownMenu>
|
|
|
34 |
</Button>
|
35 |
</DropdownMenuTrigger>
|
36 |
<DropdownMenuContent align="end" className="w-[160px]">
|
37 |
+
<DropdownMenuItem>Download</DropdownMenuItem>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
<DropdownMenuSeparator />
|
39 |
<DropdownMenuItem>
|
40 |
Delete
|
src/components/business/tasks/data-table-toolbar.tsx
DELETED
@@ -1,61 +0,0 @@
|
|
1 |
-
"use client"
|
2 |
-
|
3 |
-
import { Cross2Icon } from "@radix-ui/react-icons"
|
4 |
-
import { Table } from "@tanstack/react-table"
|
5 |
-
|
6 |
-
import { Button } from "@/components/ui/button"
|
7 |
-
import { Input } from "@/components/ui/input"
|
8 |
-
import { DataTableViewOptions } from "@/components/business/tasks/data-table-view-options"
|
9 |
-
|
10 |
-
import { DataTableFacetedFilter } from "./data-table-faceted-filter"
|
11 |
-
import { priorities, statuses } from "@/app/data/data"
|
12 |
-
|
13 |
-
interface DataTableToolbarProps<TData> {
|
14 |
-
table: Table<TData>
|
15 |
-
}
|
16 |
-
|
17 |
-
export function DataTableToolbar<TData>({
|
18 |
-
table,
|
19 |
-
}: DataTableToolbarProps<TData>) {
|
20 |
-
const isFiltered = table.getState().columnFilters.length > 0
|
21 |
-
|
22 |
-
return (
|
23 |
-
<div className="flex items-center justify-between">
|
24 |
-
<div className="flex flex-1 items-center space-x-2">
|
25 |
-
<Input
|
26 |
-
placeholder="Filter tasks..."
|
27 |
-
value={(table.getColumn("title")?.getFilterValue() as string) ?? ""}
|
28 |
-
onChange={(event) =>
|
29 |
-
table.getColumn("title")?.setFilterValue(event.target.value)
|
30 |
-
}
|
31 |
-
className="h-8 w-[150px] lg:w-[250px]"
|
32 |
-
/>
|
33 |
-
{table.getColumn("status") && (
|
34 |
-
<DataTableFacetedFilter
|
35 |
-
column={table.getColumn("status")}
|
36 |
-
title="Status"
|
37 |
-
options={statuses}
|
38 |
-
/>
|
39 |
-
)}
|
40 |
-
{table.getColumn("priority") && (
|
41 |
-
<DataTableFacetedFilter
|
42 |
-
column={table.getColumn("priority")}
|
43 |
-
title="Priority"
|
44 |
-
options={priorities}
|
45 |
-
/>
|
46 |
-
)}
|
47 |
-
{isFiltered && (
|
48 |
-
<Button
|
49 |
-
variant="ghost"
|
50 |
-
onClick={() => table.resetColumnFilters()}
|
51 |
-
className="h-8 px-2 lg:px-3"
|
52 |
-
>
|
53 |
-
Reset
|
54 |
-
<Cross2Icon className="ml-2 h-4 w-4" />
|
55 |
-
</Button>
|
56 |
-
)}
|
57 |
-
</div>
|
58 |
-
<DataTableViewOptions table={table} />
|
59 |
-
</div>
|
60 |
-
)
|
61 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/business/tasks/data-table-view-options.tsx
DELETED
@@ -1,59 +0,0 @@
|
|
1 |
-
"use client"
|
2 |
-
|
3 |
-
import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu"
|
4 |
-
import { MixerHorizontalIcon } from "@radix-ui/react-icons"
|
5 |
-
import { Table } from "@tanstack/react-table"
|
6 |
-
|
7 |
-
import { Button } from "@/components/ui/button"
|
8 |
-
import {
|
9 |
-
DropdownMenu,
|
10 |
-
DropdownMenuCheckboxItem,
|
11 |
-
DropdownMenuContent,
|
12 |
-
DropdownMenuLabel,
|
13 |
-
DropdownMenuSeparator,
|
14 |
-
} from "@/components/ui/dropdown-menu"
|
15 |
-
|
16 |
-
interface DataTableViewOptionsProps<TData> {
|
17 |
-
table: Table<TData>
|
18 |
-
}
|
19 |
-
|
20 |
-
export function DataTableViewOptions<TData>({
|
21 |
-
table,
|
22 |
-
}: DataTableViewOptionsProps<TData>) {
|
23 |
-
return (
|
24 |
-
<DropdownMenu>
|
25 |
-
<DropdownMenuTrigger asChild>
|
26 |
-
<Button
|
27 |
-
variant="outline"
|
28 |
-
size="sm"
|
29 |
-
className="ml-auto hidden h-8 lg:flex"
|
30 |
-
>
|
31 |
-
<MixerHorizontalIcon className="mr-2 h-4 w-4" />
|
32 |
-
View
|
33 |
-
</Button>
|
34 |
-
</DropdownMenuTrigger>
|
35 |
-
<DropdownMenuContent align="end" className="w-[150px]">
|
36 |
-
<DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
|
37 |
-
<DropdownMenuSeparator />
|
38 |
-
{table
|
39 |
-
.getAllColumns()
|
40 |
-
.filter(
|
41 |
-
(column) =>
|
42 |
-
typeof column.accessorFn !== "undefined" && column.getCanHide()
|
43 |
-
)
|
44 |
-
.map((column) => {
|
45 |
-
return (
|
46 |
-
<DropdownMenuCheckboxItem
|
47 |
-
key={column.id}
|
48 |
-
className="capitalize"
|
49 |
-
checked={column.getIsVisible()}
|
50 |
-
onCheckedChange={(value) => column.toggleVisibility(!!value)}
|
51 |
-
>
|
52 |
-
{column.id}
|
53 |
-
</DropdownMenuCheckboxItem>
|
54 |
-
)
|
55 |
-
})}
|
56 |
-
</DropdownMenuContent>
|
57 |
-
</DropdownMenu>
|
58 |
-
)
|
59 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/business/tasks/user-nav.tsx
DELETED
@@ -1,62 +0,0 @@
|
|
1 |
-
import {
|
2 |
-
Avatar,
|
3 |
-
AvatarFallback,
|
4 |
-
AvatarImage,
|
5 |
-
} from "@/components/ui/avatar"
|
6 |
-
import { Button } from "@/components/ui/button"
|
7 |
-
import {
|
8 |
-
DropdownMenu,
|
9 |
-
DropdownMenuContent,
|
10 |
-
DropdownMenuGroup,
|
11 |
-
DropdownMenuItem,
|
12 |
-
DropdownMenuLabel,
|
13 |
-
DropdownMenuSeparator,
|
14 |
-
DropdownMenuShortcut,
|
15 |
-
DropdownMenuTrigger,
|
16 |
-
} from "@/components/ui/dropdown-menu"
|
17 |
-
|
18 |
-
export function UserNav() {
|
19 |
-
return (
|
20 |
-
<DropdownMenu>
|
21 |
-
<DropdownMenuTrigger asChild>
|
22 |
-
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
|
23 |
-
<Avatar className="h-9 w-9">
|
24 |
-
<AvatarImage src="/avatars/03.png" alt="@shadcn" />
|
25 |
-
<AvatarFallback>SC</AvatarFallback>
|
26 |
-
</Avatar>
|
27 |
-
</Button>
|
28 |
-
</DropdownMenuTrigger>
|
29 |
-
<DropdownMenuContent className="w-56" align="end" forceMount>
|
30 |
-
<DropdownMenuLabel className="font-normal">
|
31 |
-
<div className="flex flex-col space-y-1">
|
32 |
-
<p className="text-sm font-medium leading-none">shadcn</p>
|
33 |
-
<p className="text-xs leading-none text-muted-foreground">
|
34 | |
35 |
-
</p>
|
36 |
-
</div>
|
37 |
-
</DropdownMenuLabel>
|
38 |
-
<DropdownMenuSeparator />
|
39 |
-
<DropdownMenuGroup>
|
40 |
-
<DropdownMenuItem>
|
41 |
-
Profile
|
42 |
-
<DropdownMenuShortcut>β§βP</DropdownMenuShortcut>
|
43 |
-
</DropdownMenuItem>
|
44 |
-
<DropdownMenuItem>
|
45 |
-
Billing
|
46 |
-
<DropdownMenuShortcut>βB</DropdownMenuShortcut>
|
47 |
-
</DropdownMenuItem>
|
48 |
-
<DropdownMenuItem>
|
49 |
-
Settings
|
50 |
-
<DropdownMenuShortcut>βS</DropdownMenuShortcut>
|
51 |
-
</DropdownMenuItem>
|
52 |
-
<DropdownMenuItem>New Team</DropdownMenuItem>
|
53 |
-
</DropdownMenuGroup>
|
54 |
-
<DropdownMenuSeparator />
|
55 |
-
<DropdownMenuItem>
|
56 |
-
Log out
|
57 |
-
<DropdownMenuShortcut>β§βQ</DropdownMenuShortcut>
|
58 |
-
</DropdownMenuItem>
|
59 |
-
</DropdownMenuContent>
|
60 |
-
</DropdownMenu>
|
61 |
-
)
|
62 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/business/tasks/{data-table.tsx β video-tasks-queue.tsx}
RENAMED
@@ -25,18 +25,14 @@ import {
|
|
25 |
TableRow,
|
26 |
} from "@/components/ui/table"
|
27 |
|
28 |
-
import {
|
29 |
-
import {
|
30 |
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
export function DataTable<TData, TValue>({
|
37 |
-
columns,
|
38 |
-
data,
|
39 |
-
}: DataTableProps<TData, TValue>) {
|
40 |
const [rowSelection, setRowSelection] = React.useState({})
|
41 |
const [columnVisibility, setColumnVisibility] =
|
42 |
React.useState<VisibilityState>({})
|
@@ -46,8 +42,8 @@ export function DataTable<TData, TValue>({
|
|
46 |
const [sorting, setSorting] = React.useState<SortingState>([])
|
47 |
|
48 |
const table = useReactTable({
|
49 |
-
data,
|
50 |
-
columns,
|
51 |
state: {
|
52 |
sorting,
|
53 |
columnVisibility,
|
@@ -68,59 +64,55 @@ export function DataTable<TData, TValue>({
|
|
68 |
})
|
69 |
|
70 |
return (
|
71 |
-
<div className="
|
72 |
-
<
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
</TableCell>
|
107 |
-
))}
|
108 |
-
</TableRow>
|
109 |
-
))
|
110 |
-
) : (
|
111 |
-
<TableRow>
|
112 |
-
<TableCell
|
113 |
-
colSpan={columns.length}
|
114 |
-
className="h-24 text-center"
|
115 |
-
>
|
116 |
-
No results.
|
117 |
-
</TableCell>
|
118 |
</TableRow>
|
119 |
-
)
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
</div>
|
125 |
)
|
126 |
}
|
|
|
25 |
TableRow,
|
26 |
} from "@/components/ui/table"
|
27 |
|
28 |
+
import { columns } from "@/components/business/tasks/columns"
|
29 |
+
import { VideoTask } from "@/app/types"
|
30 |
|
31 |
+
export function VideoTasksQueue({
|
32 |
+
tasks
|
33 |
+
}: {
|
34 |
+
tasks: VideoTask[]
|
35 |
+
}) {
|
|
|
|
|
|
|
|
|
36 |
const [rowSelection, setRowSelection] = React.useState({})
|
37 |
const [columnVisibility, setColumnVisibility] =
|
38 |
React.useState<VisibilityState>({})
|
|
|
42 |
const [sorting, setSorting] = React.useState<SortingState>([])
|
43 |
|
44 |
const table = useReactTable({
|
45 |
+
data: tasks,
|
46 |
+
columns: columns as ColumnDef<VideoTask, any>[],
|
47 |
state: {
|
48 |
sorting,
|
49 |
columnVisibility,
|
|
|
64 |
})
|
65 |
|
66 |
return (
|
67 |
+
<div className="rounded-lg border overflow-hidden">
|
68 |
+
<Table>
|
69 |
+
<TableHeader>
|
70 |
+
{table.getHeaderGroups().map((headerGroup) => (
|
71 |
+
<TableRow key={headerGroup.id}>
|
72 |
+
{headerGroup.headers.map((header) => {
|
73 |
+
return (
|
74 |
+
<TableHead key={header.id}>
|
75 |
+
{header.isPlaceholder
|
76 |
+
? null
|
77 |
+
: flexRender(
|
78 |
+
header.column.columnDef.header,
|
79 |
+
header.getContext()
|
80 |
+
)}
|
81 |
+
</TableHead>
|
82 |
+
)
|
83 |
+
})}
|
84 |
+
</TableRow>
|
85 |
+
))}
|
86 |
+
</TableHeader>
|
87 |
+
<TableBody>
|
88 |
+
{table.getRowModel().rows?.length ? (
|
89 |
+
table.getRowModel().rows.map((row) => (
|
90 |
+
<TableRow
|
91 |
+
key={row.id}
|
92 |
+
data-state={row.getIsSelected() && "selected"}
|
93 |
+
>
|
94 |
+
{row.getVisibleCells().map((cell) => (
|
95 |
+
<TableCell key={cell.id}>
|
96 |
+
{flexRender(
|
97 |
+
cell.column.columnDef.cell,
|
98 |
+
cell.getContext()
|
99 |
+
)}
|
100 |
+
</TableCell>
|
101 |
+
))}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
</TableRow>
|
103 |
+
))
|
104 |
+
) : (
|
105 |
+
<TableRow>
|
106 |
+
<TableCell
|
107 |
+
colSpan={columns.length}
|
108 |
+
className="h-24 text-center"
|
109 |
+
>
|
110 |
+
No recent video.
|
111 |
+
</TableCell>
|
112 |
+
</TableRow>
|
113 |
+
)}
|
114 |
+
</TableBody>
|
115 |
+
</Table>
|
116 |
</div>
|
117 |
)
|
118 |
}
|
src/components/ui/alert.tsx
CHANGED
@@ -4,11 +4,11 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|
4 |
import { cn } from "@/lib/utils"
|
5 |
|
6 |
const alertVariants = cva(
|
7 |
-
"relative w-full rounded-lg border border-
|
8 |
{
|
9 |
variants: {
|
10 |
variant: {
|
11 |
-
default: "bg-white text-
|
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"
|
5 |
|
6 |
const alertVariants = cva(
|
7 |
+
"relative w-full rounded-lg border border-stone-200 p-4 [&:has(svg)]:pl-11 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-stone-950 dark:border-stone-800 dark:[&>svg]:text-stone-50",
|
8 |
{
|
9 |
variants: {
|
10 |
variant: {
|
11 |
+
default: "bg-white text-stone-950 dark:bg-stone-950 dark:text-stone-50",
|
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 |
},
|
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-stone-100 dark:bg-stone-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"
|
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"
|
5 |
|
6 |
const badgeVariants = cva(
|
7 |
+
"inline-flex items-center rounded-full border border-stone-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-stone-400 focus:ring-offset-2 dark:border-stone-800 dark:focus:ring-stone-800",
|
8 |
{
|
9 |
variants: {
|
10 |
variant: {
|
11 |
default:
|
12 |
+
"border-transparent bg-stone-900 text-stone-50 hover:bg-stone-900/80 dark:bg-stone-50 dark:text-stone-900 dark:hover:bg-stone-50/80",
|
13 |
secondary:
|
14 |
+
"border-transparent bg-stone-100 text-stone-900 hover:bg-stone-100/80 dark:bg-stone-800 dark:text-stone-50 dark:hover:bg-stone-800/80",
|
15 |
destructive:
|
16 |
+
"border-transparent bg-red-500 text-stone-50 hover:bg-red-500/80 dark:bg-red-900 dark:text-red-50 dark:hover:bg-red-900/80",
|
17 |
+
outline: "text-stone-950 dark:text-stone-50",
|
18 |
},
|
19 |
},
|
20 |
defaultVariants: {
|
src/components/ui/button.tsx
CHANGED
@@ -5,19 +5,19 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|
5 |
import { cn } from "@/lib/utils"
|
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: "bg-
|
13 |
destructive:
|
14 |
-
"bg-red-500 text-
|
15 |
outline:
|
16 |
-
"border border-
|
17 |
secondary:
|
18 |
-
"bg-
|
19 |
-
ghost: "hover:bg-
|
20 |
-
link: "text-
|
21 |
},
|
22 |
size: {
|
23 |
default: "h-10 px-4 py-2",
|
|
|
5 |
import { cn } from "@/lib/utils"
|
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-stone-400 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-stone-950 dark:focus-visible:ring-stone-800",
|
9 |
{
|
10 |
variants: {
|
11 |
variant: {
|
12 |
+
default: "bg-stone-900 text-stone-50 hover:bg-stone-900/90 dark:bg-stone-50 dark:text-stone-900 dark:hover:bg-stone-50/90",
|
13 |
destructive:
|
14 |
+
"bg-red-500 text-stone-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-red-50 dark:hover:bg-red-900/90",
|
15 |
outline:
|
16 |
+
"border border-stone-200 bg-white hover:bg-stone-100 hover:text-stone-900 dark:border-stone-800 dark:bg-stone-950 dark:hover:bg-stone-800 dark:hover:text-stone-50",
|
17 |
secondary:
|
18 |
+
"bg-stone-100 text-stone-900 hover:bg-stone-100/80 dark:bg-stone-800 dark:text-stone-50 dark:hover:bg-stone-800/80",
|
19 |
+
ghost: "hover:bg-stone-100 hover:text-stone-900 dark:hover:bg-stone-800 dark:hover:text-stone-50",
|
20 |
+
link: "text-stone-900 underline-offset-4 hover:underline dark:text-stone-50",
|
21 |
},
|
22 |
size: {
|
23 |
default: "h-10 px-4 py-2",
|
src/components/ui/calendar.tsx
CHANGED
@@ -34,20 +34,20 @@ function Calendar({
|
|
34 |
table: "w-full border-collapse space-y-1",
|
35 |
head_row: "flex",
|
36 |
head_cell:
|
37 |
-
"text-
|
38 |
row: "flex w-full mt-2",
|
39 |
-
cell: "text-center text-sm p-0 relative [&:has([aria-selected])]:bg-
|
40 |
day: cn(
|
41 |
buttonVariants({ variant: "ghost" }),
|
42 |
"h-9 w-9 p-0 font-normal aria-selected:opacity-100"
|
43 |
),
|
44 |
day_selected:
|
45 |
-
"bg-
|
46 |
-
day_today: "bg-
|
47 |
-
day_outside: "text-
|
48 |
-
day_disabled: "text-
|
49 |
day_range_middle:
|
50 |
-
"aria-selected:bg-
|
51 |
day_hidden: "invisible",
|
52 |
...classNames,
|
53 |
}}
|
|
|
34 |
table: "w-full border-collapse space-y-1",
|
35 |
head_row: "flex",
|
36 |
head_cell:
|
37 |
+
"text-stone-500 rounded-md w-9 font-normal text-[0.8rem] dark:text-stone-400",
|
38 |
row: "flex w-full mt-2",
|
39 |
+
cell: "text-center text-sm p-0 relative [&:has([aria-selected])]:bg-stone-100 first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20 dark:[&:has([aria-selected])]:bg-stone-800",
|
40 |
day: cn(
|
41 |
buttonVariants({ variant: "ghost" }),
|
42 |
"h-9 w-9 p-0 font-normal aria-selected:opacity-100"
|
43 |
),
|
44 |
day_selected:
|
45 |
+
"bg-stone-900 text-stone-50 hover:bg-stone-900 hover:text-stone-50 focus:bg-stone-900 focus:text-stone-50 dark:bg-stone-50 dark:text-stone-900 dark:hover:bg-stone-50 dark:hover:text-stone-900 dark:focus:bg-stone-50 dark:focus:text-stone-900",
|
46 |
+
day_today: "bg-stone-100 text-stone-900 dark:bg-stone-800 dark:text-stone-50",
|
47 |
+
day_outside: "text-stone-500 opacity-50 dark:text-stone-400",
|
48 |
+
day_disabled: "text-stone-500 opacity-50 dark:text-stone-400",
|
49 |
day_range_middle:
|
50 |
+
"aria-selected:bg-stone-100 aria-selected:text-stone-900 dark:aria-selected:bg-stone-800 dark:aria-selected:text-stone-50",
|
51 |
day_hidden: "invisible",
|
52 |
...classNames,
|
53 |
}}
|
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-stone-200 bg-white text-stone-950 shadow-sm dark:border-stone-800 dark:bg-stone-950 dark:text-stone-50",
|
13 |
className
|
14 |
)}
|
15 |
{...props}
|
|
|
50 |
>(({ className, ...props }, ref) => (
|
51 |
<p
|
52 |
ref={ref}
|
53 |
+
className={cn("text-sm text-stone-500 dark:text-stone-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-stone-200 border-stone-900 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stone-400 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-stone-900 data-[state=checked]:text-stone-50 dark:border-stone-800 dark:border-stone-50 dark:ring-offset-stone-950 dark:focus-visible:ring-stone-800 dark:data-[state=checked]:bg-stone-50 dark:data-[state=checked]:text-stone-900",
|
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-stone-950 dark:bg-stone-950 dark:text-stone-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-stone-500 [&_[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 dark:[&_[cmdk-group-heading]]:text-stone-400">
|
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-stone-500 disabled:cursor-not-allowed disabled:opacity-50 dark:placeholder:text-stone-400",
|
50 |
className
|
51 |
)}
|
52 |
{...props}
|
|
|
89 |
<CommandPrimitive.Group
|
90 |
ref={ref}
|
91 |
className={cn(
|
92 |
+
"overflow-hidden p-1 text-stone-950 [&_[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-stone-500 dark:text-stone-50 dark:[&_[cmdk-group-heading]]:text-stone-400",
|
93 |
className
|
94 |
)}
|
95 |
{...props}
|
|
|
104 |
>(({ className, ...props }, ref) => (
|
105 |
<CommandPrimitive.Separator
|
106 |
ref={ref}
|
107 |
+
className={cn("-mx-1 h-px bg-stone-200 dark:bg-stone-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-stone-100 aria-selected:text-stone-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:aria-selected:bg-stone-800 dark:aria-selected:text-stone-50",
|
121 |
className
|
122 |
)}
|
123 |
{...props}
|
|
|
133 |
return (
|
134 |
<span
|
135 |
className={cn(
|
136 |
+
"ml-auto text-xs tracking-widest text-stone-500 dark:text-stone-400",
|
137 |
className
|
138 |
)}
|
139 |
{...props}
|
src/components/ui/dialog.tsx
CHANGED
@@ -25,7 +25,7 @@ const DialogOverlay = React.forwardRef<
|
|
25 |
<DialogPrimitive.Overlay
|
26 |
ref={ref}
|
27 |
className={cn(
|
28 |
-
"fixed inset-0 z-50 bg-white/80 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-
|
29 |
className
|
30 |
)}
|
31 |
{...props}
|
@@ -42,13 +42,13 @@ const DialogContent = React.forwardRef<
|
|
42 |
<DialogPrimitive.Content
|
43 |
ref={ref}
|
44 |
className={cn(
|
45 |
-
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-
|
46 |
className
|
47 |
)}
|
48 |
{...props}
|
49 |
>
|
50 |
{children}
|
51 |
-
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-
|
52 |
<X className="h-4 w-4" />
|
53 |
<span className="sr-only">Close</span>
|
54 |
</DialogPrimitive.Close>
|
@@ -106,7 +106,7 @@ const DialogDescription = React.forwardRef<
|
|
106 |
>(({ className, ...props }, ref) => (
|
107 |
<DialogPrimitive.Description
|
108 |
ref={ref}
|
109 |
-
className={cn("text-sm text-
|
110 |
{...props}
|
111 |
/>
|
112 |
))
|
|
|
25 |
<DialogPrimitive.Overlay
|
26 |
ref={ref}
|
27 |
className={cn(
|
28 |
+
"fixed inset-0 z-50 bg-white/80 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-stone-950/80",
|
29 |
className
|
30 |
)}
|
31 |
{...props}
|
|
|
42 |
<DialogPrimitive.Content
|
43 |
ref={ref}
|
44 |
className={cn(
|
45 |
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-stone-200 bg-white p-6 shadow-lg 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%] sm:rounded-lg md:w-full dark:border-stone-800 dark:bg-stone-950",
|
46 |
className
|
47 |
)}
|
48 |
{...props}
|
49 |
>
|
50 |
{children}
|
51 |
+
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-stone-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-stone-100 data-[state=open]:text-stone-500 dark:ring-offset-stone-950 dark:focus:ring-stone-800 dark:data-[state=open]:bg-stone-800 dark:data-[state=open]:text-stone-400">
|
52 |
<X className="h-4 w-4" />
|
53 |
<span className="sr-only">Close</span>
|
54 |
</DialogPrimitive.Close>
|
|
|
106 |
>(({ className, ...props }, ref) => (
|
107 |
<DialogPrimitive.Description
|
108 |
ref={ref}
|
109 |
+
className={cn("text-sm text-stone-500 dark:text-stone-400", className)}
|
110 |
{...props}
|
111 |
/>
|
112 |
))
|
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 focus: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 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 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 focus:bg-
|
127 |
className
|
128 |
)}
|
129 |
{...props}
|
@@ -162,7 +162,7 @@ const DropdownMenuSeparator = React.forwardRef<
|
|
162 |
>(({ className, ...props }, ref) => (
|
163 |
<DropdownMenuPrimitive.Separator
|
164 |
ref={ref}
|
165 |
-
className={cn("-mx-1 my-1 h-px bg-
|
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 focus:bg-stone-100 data-[state=open]:bg-stone-100 dark:focus:bg-stone-800 dark:data-[state=open]:bg-stone-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-stone-200 bg-white p-1 text-stone-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-stone-800 dark:bg-stone-950 dark:text-stone-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-stone-200 bg-white p-1 text-stone-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-stone-800 dark:bg-stone-950 dark:text-stone-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 focus:bg-stone-100 focus:text-stone-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-stone-800 dark:focus:text-stone-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 focus:bg-stone-100 focus:text-stone-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-stone-800 dark:focus:text-stone-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 focus:bg-stone-100 focus:text-stone-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-stone-800 dark:focus:text-stone-50",
|
127 |
className
|
128 |
)}
|
129 |
{...props}
|
|
|
162 |
>(({ className, ...props }, ref) => (
|
163 |
<DropdownMenuPrimitive.Separator
|
164 |
ref={ref}
|
165 |
+
className={cn("-mx-1 my-1 h-px bg-stone-100 dark:bg-stone-800", className)}
|
166 |
{...props}
|
167 |
/>
|
168 |
))
|
src/components/ui/input.tsx
CHANGED
@@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
11 |
<input
|
12 |
type={type}
|
13 |
className={cn(
|
14 |
-
"flex h-10 w-full rounded-md border border-
|
15 |
className
|
16 |
)}
|
17 |
ref={ref}
|
|
|
11 |
<input
|
12 |
type={type}
|
13 |
className={cn(
|
14 |
+
"flex h-10 w-full rounded-md border border-stone-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-stone-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stone-400 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-stone-800 dark:bg-stone-950 dark:ring-offset-stone-950 dark:placeholder:text-stone-400 dark:focus-visible:ring-stone-800",
|
15 |
className
|
16 |
)}
|
17 |
ref={ref}
|
src/components/ui/menubar.tsx
CHANGED
@@ -23,7 +23,7 @@ const Menubar = React.forwardRef<
|
|
23 |
<MenubarPrimitive.Root
|
24 |
ref={ref}
|
25 |
className={cn(
|
26 |
-
"flex h-10 items-center space-x-1 rounded-md border 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.5 text-sm font-medium outline-none focus: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 focus: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 border-
|
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 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 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 focus:bg-
|
159 |
className
|
160 |
)}
|
161 |
{...props}
|
@@ -194,7 +194,7 @@ const MenubarSeparator = React.forwardRef<
|
|
194 |
>(({ className, ...props }, ref) => (
|
195 |
<MenubarPrimitive.Separator
|
196 |
ref={ref}
|
197 |
-
className={cn("-mx-1 my-1 h-px bg-
|
198 |
{...props}
|
199 |
/>
|
200 |
))
|
@@ -207,7 +207,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 |
+
"flex h-10 items-center space-x-1 rounded-md border border-stone-200 bg-white p-1 dark:border-stone-800 dark:bg-stone-950",
|
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.5 text-sm font-medium outline-none focus:bg-stone-100 focus:text-stone-900 data-[state=open]:bg-stone-100 data-[state=open]:text-stone-900 dark:focus:bg-stone-800 dark:focus:text-stone-50 dark:data-[state=open]:bg-stone-800 dark:data-[state=open]:text-stone-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 focus:bg-stone-100 focus:text-stone-900 data-[state=open]:bg-stone-100 data-[state=open]:text-stone-900 dark:focus:bg-stone-800 dark:focus:text-stone-50 dark:data-[state=open]:bg-stone-800 dark:data-[state=open]:text-stone-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 border-stone-200 bg-white p-1 text-stone-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-stone-800 dark:bg-stone-950 dark:text-stone-50",
|
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-stone-200 bg-white p-1 text-stone-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-stone-800 dark:bg-stone-950 dark:text-stone-50",
|
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 focus:bg-stone-100 focus:text-stone-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-stone-800 dark:focus:text-stone-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 focus:bg-stone-100 focus:text-stone-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-stone-800 dark:focus:text-stone-50",
|
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 focus:bg-stone-100 focus:text-stone-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-stone-800 dark:focus:text-stone-50",
|
159 |
className
|
160 |
)}
|
161 |
{...props}
|
|
|
194 |
>(({ className, ...props }, ref) => (
|
195 |
<MenubarPrimitive.Separator
|
196 |
ref={ref}
|
197 |
+
className={cn("-mx-1 my-1 h-px bg-stone-100 dark:bg-stone-800", className)}
|
198 |
{...props}
|
199 |
/>
|
200 |
))
|
|
|
207 |
return (
|
208 |
<span
|
209 |
className={cn(
|
210 |
+
"ml-auto text-xs tracking-widest text-stone-500 dark:text-stone-400",
|
211 |
className
|
212 |
)}
|
213 |
{...props}
|
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-stone-200 bg-white p-4 text-stone-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-stone-800 dark:bg-stone-950 dark:text-stone-50",
|
23 |
className
|
24 |
)}
|
25 |
{...props}
|
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 focus:bg-
|
85 |
className
|
86 |
)}
|
87 |
{...props}
|
@@ -103,7 +103,7 @@ const SelectSeparator = React.forwardRef<
|
|
103 |
>(({ className, ...props }, ref) => (
|
104 |
<SelectPrimitive.Separator
|
105 |
ref={ref}
|
106 |
-
className={cn("-mx-1 my-1 h-px bg-
|
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-stone-200 border-stone-200 bg-transparent px-3 py-2 text-sm ring-offset-white placeholder:text-stone-500 focus:outline-none focus:ring-2 focus:ring-stone-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-stone-800 dark:border-stone-800 dark:ring-offset-stone-950 dark:placeholder:text-stone-400 dark:focus:ring-stone-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-stone-200 bg-white text-stone-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-stone-800 dark:bg-stone-950 dark:text-stone-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 focus:bg-stone-100 focus:text-stone-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-stone-800 dark:focus:text-stone-50",
|
85 |
className
|
86 |
)}
|
87 |
{...props}
|
|
|
103 |
>(({ className, ...props }, ref) => (
|
104 |
<SelectPrimitive.Separator
|
105 |
ref={ref}
|
106 |
+
className={cn("-mx-1 my-1 h-px bg-stone-100 dark:bg-stone-800", className)}
|
107 |
{...props}
|
108 |
/>
|
109 |
))
|
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-stone-200 dark:bg-stone-800",
|
22 |
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
23 |
className
|
24 |
)}
|
src/components/ui/table.tsx
CHANGED
@@ -42,7 +42,7 @@ const TableFooter = React.forwardRef<
|
|
42 |
>(({ className, ...props }, ref) => (
|
43 |
<tfoot
|
44 |
ref={ref}
|
45 |
-
className={cn("bg-
|
46 |
{...props}
|
47 |
/>
|
48 |
))
|
@@ -55,7 +55,7 @@ const TableRow = React.forwardRef<
|
|
55 |
<tr
|
56 |
ref={ref}
|
57 |
className={cn(
|
58 |
-
"border-b transition-colors hover:bg-
|
59 |
className
|
60 |
)}
|
61 |
{...props}
|
@@ -70,7 +70,7 @@ const TableHead = React.forwardRef<
|
|
70 |
<th
|
71 |
ref={ref}
|
72 |
className={cn(
|
73 |
-
"h-12 px-4 text-left align-middle font-medium text-
|
74 |
className
|
75 |
)}
|
76 |
{...props}
|
@@ -96,7 +96,7 @@ const TableCaption = React.forwardRef<
|
|
96 |
>(({ className, ...props }, ref) => (
|
97 |
<caption
|
98 |
ref={ref}
|
99 |
-
className={cn("mt-4 text-sm text-
|
100 |
{...props}
|
101 |
/>
|
102 |
))
|
|
|
42 |
>(({ className, ...props }, ref) => (
|
43 |
<tfoot
|
44 |
ref={ref}
|
45 |
+
className={cn("bg-stone-900 font-medium text-stone-50 dark:bg-stone-50 dark:text-stone-900", className)}
|
46 |
{...props}
|
47 |
/>
|
48 |
))
|
|
|
55 |
<tr
|
56 |
ref={ref}
|
57 |
className={cn(
|
58 |
+
"border-b transition-colors hover:bg-stone-100/50 data-[state=selected]:bg-stone-100 dark:hover:bg-stone-800/50 dark:data-[state=selected]:bg-stone-800",
|
59 |
className
|
60 |
)}
|
61 |
{...props}
|
|
|
70 |
<th
|
71 |
ref={ref}
|
72 |
className={cn(
|
73 |
+
"h-12 px-4 text-left align-middle font-medium text-stone-500 [&:has([role=checkbox])]:pr-0 dark:text-stone-400",
|
74 |
className
|
75 |
)}
|
76 |
{...props}
|
|
|
96 |
>(({ className, ...props }, ref) => (
|
97 |
<caption
|
98 |
ref={ref}
|
99 |
+
className={cn("mt-4 text-sm text-stone-500 dark:text-stone-400", className)}
|
100 |
{...props}
|
101 |
/>
|
102 |
))
|
src/components/ui/textarea.tsx
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import * as React from "react"
|
2 |
+
|
3 |
+
import { cn } from "@/lib/utils"
|
4 |
+
|
5 |
+
export interface TextareaProps
|
6 |
+
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
7 |
+
|
8 |
+
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
9 |
+
({ className, ...props }, ref) => {
|
10 |
+
return (
|
11 |
+
<textarea
|
12 |
+
className={cn(
|
13 |
+
"flex min-h-[80px] w-full rounded-md border border-stone-200 border-stone-200 bg-transparent px-3 py-2 text-sm ring-offset-white placeholder:text-stone-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stone-400 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-stone-800 dark:border-stone-800 dark:ring-offset-stone-950 dark:placeholder:text-stone-400 dark:focus-visible:ring-stone-800",
|
14 |
+
className
|
15 |
+
)}
|
16 |
+
ref={ref}
|
17 |
+
{...props}
|
18 |
+
/>
|
19 |
+
)
|
20 |
+
}
|
21 |
+
)
|
22 |
+
Textarea.displayName = "Textarea"
|
23 |
+
|
24 |
+
export { Textarea }
|
src/server/README.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
All those files and functions are server for server-side use only.
|
src/server/actions.ts
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use server"
|
2 |
+
|
3 |
+
import { revalidatePath } from "next/cache"
|
4 |
+
import { submitNewTask } from "."
|
5 |
+
|
6 |
+
export async function formSubmit(formData: FormData) {
|
7 |
+
await submitNewTask({
|
8 |
+
prompt: `${formData.get("prompt") || ""}`,
|
9 |
+
ownerId: `${formData.get("ownerId") || ""}`,
|
10 |
+
})
|
11 |
+
|
12 |
+
// for doc see https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
|
13 |
+
revalidatePath('/')
|
14 |
+
}
|
src/{api β server}/base.ts
RENAMED
@@ -5,13 +5,18 @@ const apiUrl = process.env.VC_VIDEOCHAIN_API_URL
|
|
5 |
|
6 |
export const get = async <T>(path: string = '', defaultValue: T): Promise<T> => {
|
7 |
try {
|
|
|
8 |
const res = await fetch(`${apiUrl}/${path}`, {
|
|
|
9 |
headers: {
|
10 |
-
method: "GET",
|
11 |
Accept: "application/json",
|
12 |
Authorization: `Bearer ${process.env.VC_SECRET_ACCESS_TOKEN}`,
|
13 |
-
}
|
|
|
|
|
|
|
14 |
})
|
|
|
15 |
// The return value is *not* serialized
|
16 |
// You can return Date, Map, Set, etc.
|
17 |
|
@@ -23,6 +28,40 @@ export const get = async <T>(path: string = '', defaultValue: T): Promise<T> =>
|
|
23 |
|
24 |
const data = await res.json()
|
25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
return ((data as T) || defaultValue)
|
27 |
} catch (err) {
|
28 |
console.error(err)
|
|
|
5 |
|
6 |
export const get = async <T>(path: string = '', defaultValue: T): Promise<T> => {
|
7 |
try {
|
8 |
+
console.log("fetching:", `${apiUrl}/${path} with Bearer ${process.env.VC_SECRET_ACCESS_TOKEN}`)
|
9 |
const res = await fetch(`${apiUrl}/${path}`, {
|
10 |
+
method: "GET",
|
11 |
headers: {
|
|
|
12 |
Accept: "application/json",
|
13 |
Authorization: `Bearer ${process.env.VC_SECRET_ACCESS_TOKEN}`,
|
14 |
+
},
|
15 |
+
cache: 'no-store',
|
16 |
+
// we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
|
17 |
+
// next: { revalidate: 10 }
|
18 |
})
|
19 |
+
console.log("res:", res)
|
20 |
// The return value is *not* serialized
|
21 |
// You can return Date, Map, Set, etc.
|
22 |
|
|
|
28 |
|
29 |
const data = await res.json()
|
30 |
|
31 |
+
console.log("data:", data)
|
32 |
+
return ((data as T) || defaultValue)
|
33 |
+
} catch (err) {
|
34 |
+
console.error(err)
|
35 |
+
return defaultValue
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
|
40 |
+
export const post = async <S, T>(path: string = '', payload: S, defaultValue: T): Promise<T> => {
|
41 |
+
try {
|
42 |
+
const res = await fetch(`${apiUrl}/${path}`, {
|
43 |
+
method: "POST",
|
44 |
+
headers: {
|
45 |
+
Accept: "application/json",
|
46 |
+
"Content-Type": "application/json",
|
47 |
+
Authorization: `Bearer ${process.env.VC_SECRET_ACCESS_TOKEN}`,
|
48 |
+
},
|
49 |
+
body: JSON.stringify(payload),
|
50 |
+
cache: 'no-store',
|
51 |
+
// we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
|
52 |
+
// next: { revalidate: 10 }
|
53 |
+
})
|
54 |
+
// The return value is *not* serialized
|
55 |
+
// You can return Date, Map, Set, etc.
|
56 |
+
|
57 |
+
// Recommendation: handle errors
|
58 |
+
if (res.status !== 200) {
|
59 |
+
// This will activate the closest `error.js` Error Boundary
|
60 |
+
throw new Error('Failed to post data')
|
61 |
+
}
|
62 |
+
|
63 |
+
const data = await res.json()
|
64 |
+
|
65 |
return ((data as T) || defaultValue)
|
66 |
} catch (err) {
|
67 |
console.error(err)
|
src/server/index.ts
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use server"
|
2 |
+
|
3 |
+
import { VideoTask, VideoTaskRequest } from "@/app/types"
|
4 |
+
|
5 |
+
import { get, post } from "./base"
|
6 |
+
|
7 |
+
// note: for security purposes we do not directly expose the VideoChain API:
|
8 |
+
// all calls are protected with a token, that way it the VideooChain API can stay
|
9 |
+
// lightweight, security and quotas are handled outside
|
10 |
+
|
11 |
+
// attention: this return *ALL* pending tasks, including those of other users
|
12 |
+
export const getPendingTasks = async () => {
|
13 |
+
const tasks = await get<VideoTask[]>("", [])
|
14 |
+
|
15 |
+
return tasks
|
16 |
+
}
|
17 |
+
|
18 |
+
// return all tasks of a owner
|
19 |
+
export const getTasks = async (ownerId: string) => {
|
20 |
+
const tasks = await get<VideoTask[]>(`owner/${ownerId}`, [])
|
21 |
+
|
22 |
+
return tasks
|
23 |
+
}
|
24 |
+
|
25 |
+
export const getTask = async (ownerAndVideoId: string) => {
|
26 |
+
const task = await get<VideoTask>(ownerAndVideoId, null as unknown as VideoTask)
|
27 |
+
|
28 |
+
return task
|
29 |
+
}
|
30 |
+
|
31 |
+
export const submitNewTask = async (taskRequest: VideoTaskRequest) => {
|
32 |
+
const task = await post<VideoTaskRequest, VideoTask>(
|
33 |
+
"",
|
34 |
+
taskRequest,
|
35 |
+
null as unknown as VideoTask
|
36 |
+
)
|
37 |
+
|
38 |
+
return task
|
39 |
+
}
|
tsconfig.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
{
|
2 |
"compilerOptions": {
|
3 |
-
"target": "
|
4 |
"lib": ["dom", "dom.iterable", "esnext"],
|
5 |
"allowJs": true,
|
6 |
"skipLibCheck": true,
|
|
|
1 |
{
|
2 |
"compilerOptions": {
|
3 |
+
"target": "ES2022",
|
4 |
"lib": ["dom", "dom.iterable", "esnext"],
|
5 |
"allowJs": true,
|
6 |
"skipLibCheck": true,
|