Compare commits
8 Commits
036f23b777
...
7aeae9020d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aeae9020d | ||
| 85fa1942e9 | |||
|
|
c9274a0caa | ||
| 58853f38c4 | |||
|
|
1884189fb2 | ||
| 118cadefdf | |||
| b14acab08f | |||
| 60925ee6ac |
223
package-lock.json
generated
223
package-lock.json
generated
@ -11,13 +11,17 @@
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "^2.7.2",
|
||||
"@prisma/client": "^6.5.0",
|
||||
"@prisma/extension-accelerate": "^2.0.0",
|
||||
"@t3-oss/env-nextjs": "^0.12.0",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tanstack/react-query": "^5.69.0",
|
||||
"@trpc/client": "^11.0.0",
|
||||
"@trpc/react-query": "^11.0.0",
|
||||
"@trpc/server": "^11.0.0",
|
||||
"cuid": "^3.0.0",
|
||||
"dompurify": "^3.2.5",
|
||||
"github-markdown-css": "^5.8.1",
|
||||
"gray-matter": "^4.0.3",
|
||||
"mermaid": "^11.6.0",
|
||||
"minio": "^8.0.5",
|
||||
"next": "^15.2.3",
|
||||
@ -27,7 +31,9 @@
|
||||
"react-hot-toast": "^2.5.2",
|
||||
"react-markdown": "^10.1.0",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"remark": "^15.0.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-html": "^16.0.1",
|
||||
"server-only": "^0.0.1",
|
||||
"superjson": "^2.2.1",
|
||||
"zod": "^3.24.2"
|
||||
@ -36,6 +42,7 @@
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@tailwindcss/postcss": "^4.0.15",
|
||||
"@types/busboy": "^1.5.4",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^20.14.10",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
@ -1541,6 +1548,17 @@
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@prisma/extension-accelerate": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/extension-accelerate/-/extension-accelerate-2.0.0.tgz",
|
||||
"integrity": "sha512-8phE1FQ/sqNQM5VRnWog2jp3r+/acffIJR1D7QHPk8d/WHdKUyLhIVSKnd1Gq+5orwzzW2I0O16gvb6Uzp0PRw==",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@prisma/client": ">=4.16.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/fetch-engine": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.6.0.tgz",
|
||||
@ -2301,6 +2319,13 @@
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mime-types": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz",
|
||||
"integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ms": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
||||
@ -3508,6 +3533,13 @@
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cuid": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cuid/-/cuid-3.0.0.tgz",
|
||||
"integrity": "sha512-WZYYkHdIDnaxdeP8Misq3Lah5vFjJwGuItJuV+tvMafosMzw0nF297T7mrm8IOWiPJkV6gc7sa8pzx27+w25Zg==",
|
||||
"deprecated": "Cuid and other k-sortable and non-cryptographic ids (Ulid, ObjectId, KSUID, all UUIDs) are all insecure. Use @paralleldrive/cuid2 instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cytoscape": {
|
||||
"version": "3.32.0",
|
||||
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.32.0.tgz",
|
||||
@ -4883,6 +4915,19 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"license": "BSD-2-Clause",
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/esquery": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
|
||||
@ -4957,6 +5002,18 @@
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extendable": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
@ -5247,6 +5304,18 @@
|
||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/github-markdown-css": {
|
||||
"version": "5.8.1",
|
||||
"resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-5.8.1.tgz",
|
||||
"integrity": "sha512-8G+PFvqigBQSWLQjyzgpa2ThD9bo7+kDsriUIidGcRhXgmcaAWUIpCZf8DavJgc+xifjbCG+GvMyWr0XMXmc7g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
@ -5325,6 +5394,43 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/gray-matter": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
|
||||
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-yaml": "^3.13.1",
|
||||
"kind-of": "^6.0.2",
|
||||
"section-matter": "^1.0.0",
|
||||
"strip-bom-string": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gray-matter/node_modules/argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/gray-matter/node_modules/js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/hachure-fill": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz",
|
||||
@ -5479,6 +5585,44 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-sanitize": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-5.0.2.tgz",
|
||||
"integrity": "sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@ungap/structured-clone": "^1.0.0",
|
||||
"unist-util-position": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-html": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz",
|
||||
"integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/unist": "^3.0.0",
|
||||
"ccount": "^2.0.0",
|
||||
"comma-separated-tokens": "^2.0.0",
|
||||
"hast-util-whitespace": "^3.0.0",
|
||||
"html-void-elements": "^3.0.0",
|
||||
"mdast-util-to-hast": "^13.0.0",
|
||||
"property-information": "^7.0.0",
|
||||
"space-separated-tokens": "^2.0.0",
|
||||
"stringify-entities": "^4.0.0",
|
||||
"zwitch": "^2.0.4"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-jsx-runtime": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz",
|
||||
@ -5880,6 +6024,15 @@
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extendable": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
|
||||
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@ -6315,6 +6468,15 @@
|
||||
"resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz",
|
||||
"integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="
|
||||
},
|
||||
"node_modules/kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/kolorist": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
|
||||
@ -8716,6 +8878,22 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark": {
|
||||
"version": "15.0.1",
|
||||
"resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz",
|
||||
"integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"unified": "^11.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-gfm": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
|
||||
@ -8734,6 +8912,23 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-html": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/remark-html/-/remark-html-16.0.1.tgz",
|
||||
"integrity": "sha512-B9JqA5i0qZe0Nsf49q3OXyGvyXuZFDzAP2iOFLEumymuYJITVpiH1IgsTEwTpdptDmZlMDMWeDmSawdaJIGCXQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"hast-util-sanitize": "^5.0.0",
|
||||
"hast-util-to-html": "^9.0.0",
|
||||
"mdast-util-to-hast": "^13.0.0",
|
||||
"unified": "^11.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-parse": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
|
||||
@ -8974,6 +9169,19 @@
|
||||
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/section-matter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
||||
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"kind-of": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
@ -9219,6 +9427,12 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/stable-hash": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
|
||||
@ -9404,6 +9618,15 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-bom-string": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
|
||||
"integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-json-comments": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
|
||||
@ -23,13 +23,17 @@
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "^2.7.2",
|
||||
"@prisma/client": "^6.5.0",
|
||||
"@prisma/extension-accelerate": "^2.0.0",
|
||||
"@t3-oss/env-nextjs": "^0.12.0",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tanstack/react-query": "^5.69.0",
|
||||
"@trpc/client": "^11.0.0",
|
||||
"@trpc/react-query": "^11.0.0",
|
||||
"@trpc/server": "^11.0.0",
|
||||
"cuid": "^3.0.0",
|
||||
"dompurify": "^3.2.5",
|
||||
"github-markdown-css": "^5.8.1",
|
||||
"gray-matter": "^4.0.3",
|
||||
"mermaid": "^11.6.0",
|
||||
"minio": "^8.0.5",
|
||||
"next": "^15.2.3",
|
||||
@ -39,7 +43,9 @@
|
||||
"react-hot-toast": "^2.5.2",
|
||||
"react-markdown": "^10.1.0",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"remark": "^15.0.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-html": "^16.0.1",
|
||||
"server-only": "^0.0.1",
|
||||
"superjson": "^2.2.1",
|
||||
"zod": "^3.24.2"
|
||||
@ -48,6 +54,7 @@
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@tailwindcss/postcss": "^4.0.15",
|
||||
"@types/busboy": "^1.5.4",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^20.14.10",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
|
||||
@ -4,10 +4,11 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-3.0.x"]
|
||||
output = "/app/generated/prisma-client"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
provider = "postgresql"
|
||||
// NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
|
||||
// Further reading:
|
||||
// https://next-auth.js.org/adapters/prisma#create-the-prisma-schema
|
||||
@ -23,7 +24,7 @@ model Account {
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String
|
||||
refresh_token String? @db.Text
|
||||
refresh_token String? //@db.Text
|
||||
access_token String? // @db.Text
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
|
||||
70
src/app/LoadingSkeleton.tsx
Normal file
70
src/app/LoadingSkeleton.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
import React, { Suspense } from "react";
|
||||
import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import {
|
||||
FileActionsContainer,
|
||||
} from "~/app/_components/ActionButtons"; // Import the client component
|
||||
|
||||
const LoadingSkeleton: React.FC = () => (
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||
<div className="absolute top-4 left-4">
|
||||
<HomeButton />
|
||||
</div>
|
||||
<Toaster position="top-right" reverseOrder={false} />
|
||||
<div className="container flex flex-col items-center gap-12 px-4 py-16">
|
||||
<h1 className="text-5xl font-extrabold tracking-tight sm:text-[5rem]">
|
||||
<span className="text-[hsl(280,100%,70%)]">File</span> Details
|
||||
</h1>
|
||||
<div className="mt-6">
|
||||
<svg
|
||||
className="h-6 w-6 animate-spin text-white/70"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="w-full max-w-md rounded-lg bg-white/10 p-6 text-white shadow-md">
|
||||
<p>
|
||||
<strong>Name:</strong> <span className="inline-block h-6 w-24 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</p>
|
||||
<p>
|
||||
<strong>Size:</strong> <span className="inline-block h-6 w-16 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</p>
|
||||
<p>
|
||||
<strong>Owner:</strong> <span className="inline-block h-6 w-20 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</p>
|
||||
<p>
|
||||
<strong>Upload Date:</strong> <span className="inline-block h-6 w-28 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</p>
|
||||
<div>
|
||||
<strong>Description:</strong> <span className="inline-block h-6 w-40 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</div>
|
||||
<div className="mt-4 flex justify-center">
|
||||
<FileActionsContainer
|
||||
fileId={""}
|
||||
fileName={""}
|
||||
fileUrl={""}
|
||||
isOwner={false}
|
||||
isPublic={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
export default LoadingSkeleton;
|
||||
@ -59,7 +59,7 @@ export function FileActionsContainer({
|
||||
console.error(err);
|
||||
}
|
||||
}}
|
||||
className="flex items-center justify-center rounded-full bg-red-500 p-2 hover:bg-red-600"
|
||||
className="flex items-center justify-center rounded-full bg-red-500 p-2 hover:bg-red-700"
|
||||
>
|
||||
<img src="/icons/delete.svg" alt="Remove" className="h-6 w-6" />
|
||||
</button>
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { env } from "~/env.js";
|
||||
import { FilePreview } from "~/app/_components/FilePreview";
|
||||
import { useFileActions } from "~/app/_components/FileActions";
|
||||
import { FileActionsContainer } from "./ActionButtons";
|
||||
import { checkOwner } from "~/utils/checkOwner"; // Import the client component
|
||||
|
||||
interface FileDetails {
|
||||
id: string;
|
||||
@ -73,13 +71,15 @@ export default function FileGrid({ session }: FileGridProps) {
|
||||
|
||||
const eventSource = new EventSource("/api/files/stream");
|
||||
eventSource.onmessage = (event) => {
|
||||
const data: { type: string; file?: FileDetails; fileId?: string } = JSON.parse(event.data);
|
||||
|
||||
if (data.type === "file-added" && data.file) {
|
||||
setFiles((prevFiles) => (data.file ? [...prevFiles, data.file] : prevFiles));
|
||||
toast.success(`File "${data.file.name}" added!`);
|
||||
const data: { type: string; fileId?: string } = JSON.parse(event.data);
|
||||
console.log("SSE event:", data);
|
||||
if (data.type === "file-added" && data.fileId) {
|
||||
fetchFiles();
|
||||
} else if (data.type === "file-updated" && data.fileId) {
|
||||
// Fetch the updated file details
|
||||
fetchFiles();
|
||||
} else if (data.type === "file-removed" && data.fileId) {
|
||||
setFiles((prevFiles) => prevFiles.filter((file) => file.id !== data.fileId));
|
||||
setFiles((prevFiles => prevFiles.filter(file => file.id !== data.fileId)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -105,7 +105,7 @@ export default function FileGrid({ session }: FileGridProps) {
|
||||
key={file.id}
|
||||
className="flex place-content-end max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 hover:bg-white/20"
|
||||
>
|
||||
{<div className=" self-center max-w-50"><FilePreview fileId={file.id} fileType={file.extension} /></div>}
|
||||
{<div className=" self-center max-w-50"><FilePreview fileId={file.id} fileType={file.extension} share={false} /></div>}
|
||||
|
||||
<button onClick={() => router.push(pageUrl + file.url)}>
|
||||
<h3 className="text-2xl font-bold">{file.name}</h3>
|
||||
|
||||
@ -1,16 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { getFileType } from "~/utils/fileType"; // Adjust the import path as necessary
|
||||
import { remark } from 'remark';
|
||||
import html from 'remark-html';
|
||||
import matter from 'gray-matter';
|
||||
import "github-markdown-css/github-markdown.css";
|
||||
import "../styles/custom.css"; // Adjust the path as necessary
|
||||
import { MarkdownRenderer } from "../../components/MarkdownRenderer";
|
||||
|
||||
interface FilePreviewProps {
|
||||
fileId: string;
|
||||
fileType: string; // Pass the file type as a prop
|
||||
}
|
||||
|
||||
export function FilePreview({ fileId, fileType }: FilePreviewProps) {
|
||||
export function FilePreview({ fileId, fileType, share }: FilePreviewProps & { share: boolean }) {
|
||||
const [mediaSrc, setMediaSrc] = useState<string | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [markdownContent, setMarkdownContent] = useState<string | null>(null);
|
||||
|
||||
console.log("File Type:", fileType);
|
||||
|
||||
@ -47,20 +53,53 @@ export function FilePreview({ fileId, fileType }: FilePreviewProps) {
|
||||
};
|
||||
}, [fileId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (fileType.startsWith("markdown")) {
|
||||
const fetchMarkdown = async () => {
|
||||
try {
|
||||
const result = await renderMarkdown({ id: fileId });
|
||||
setMarkdownContent(result.props.postData.contentHtml);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch markdown content:", err);
|
||||
}
|
||||
};
|
||||
|
||||
fetchMarkdown();
|
||||
}
|
||||
}, [fileId, fileType]);
|
||||
|
||||
|
||||
if (error) {
|
||||
return <div className="text-red-500">{error}</div>;
|
||||
}
|
||||
|
||||
if (!mediaSrc) {
|
||||
if (!mediaSrc && !markdownContent) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
if (fileType.startsWith("markdown")) {
|
||||
if (share) {
|
||||
return (
|
||||
<div className="overflow-y-auto max-h-96 rounded-lg shadow-md">
|
||||
{markdownContent ? (
|
||||
<MarkdownRenderer markdownContent={markdownContent} />
|
||||
) : (
|
||||
<div>Loading markdown...</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<img src="/icons/files/code.svg" alt="Code file preview" className="max-w-full max-h-96 rounded-lg invert" />
|
||||
);
|
||||
}
|
||||
|
||||
if (fileType.startsWith("video")) {
|
||||
return (
|
||||
<video
|
||||
controls
|
||||
className="max-w-full max-h-96 rounded-lg shadow-md"
|
||||
src={mediaSrc}
|
||||
src={mediaSrc || ""}
|
||||
>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
@ -71,14 +110,14 @@ export function FilePreview({ fileId, fileType }: FilePreviewProps) {
|
||||
<audio
|
||||
controls
|
||||
className="max-w-full max-h-96 rounded-lg shadow-md"
|
||||
src={mediaSrc}
|
||||
src={mediaSrc || ""}
|
||||
>
|
||||
Your browser does not support the audio tag.
|
||||
</audio>
|
||||
);
|
||||
}
|
||||
if (fileType.startsWith("image")) {
|
||||
return <img src={mediaSrc} alt="Media preview" className="max-w-full max-h-96 rounded-lg shadow-md" />;
|
||||
return <img src={mediaSrc || ""} alt="Media preview" className="max-w-full max-h-96 rounded-lg shadow-md" />;
|
||||
}
|
||||
|
||||
if (fileType.startsWith("text")) {
|
||||
@ -91,17 +130,48 @@ export function FilePreview({ fileId, fileType }: FilePreviewProps) {
|
||||
<img src="/icons/files/archive.svg" alt="Archive file preview" className="max-w-full max-h-96 rounded-lg invert" />
|
||||
);
|
||||
}
|
||||
if (fileType.startsWith("code") || fileType.startsWith("markdown")) {
|
||||
if (fileType.startsWith("code")) {
|
||||
return (
|
||||
<img src="/icons/files/code.svg" alt="Code file preview" className="max-w-full max-h-96 rounded-lg invert" />
|
||||
);
|
||||
}
|
||||
// if (fileType.startsWith("markdown")) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// log file type
|
||||
console.log("Unsupported file type:", fileType);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function rendererMarkdown(id: string) {
|
||||
const fileContents = await fetch(`/api/files/serv?id=${encodeURIComponent(id)}`)
|
||||
.then((res) => res.text())
|
||||
.catch((err) => {
|
||||
console.error("Failed to fetch file contents:", err);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (!fileContents) {
|
||||
throw new Error("File contents could not be fetched.");
|
||||
}
|
||||
const matterResult = matter(fileContents);
|
||||
|
||||
const processedContent = await remark()
|
||||
.use(html)
|
||||
.process(matterResult.content);
|
||||
const contentHtml = processedContent.toString();
|
||||
|
||||
return {
|
||||
id,
|
||||
contentHtml,
|
||||
...matterResult.data,
|
||||
};
|
||||
}
|
||||
|
||||
export async function renderMarkdown({ id }: { id: string }) {
|
||||
const postData = await rendererMarkdown(id);
|
||||
|
||||
return {
|
||||
props: {
|
||||
postData,
|
||||
},
|
||||
};
|
||||
}
|
||||
45
src/app/_components/GenerateMetadata.tsx
Normal file
45
src/app/_components/GenerateMetadata.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export async function generateMetadata({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { id?: string };
|
||||
}): Promise<Metadata> {
|
||||
const fileId = searchParams.id;
|
||||
|
||||
if (!fileId) {
|
||||
return {
|
||||
title: "File Not Found",
|
||||
description: "The file you are looking for does not exist.",
|
||||
};
|
||||
}
|
||||
|
||||
// Fetch file details for metadata
|
||||
const response = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_PAGE_URL}/api/files/share?id=${encodeURIComponent(fileId)}`,
|
||||
{ cache: "no-store" },
|
||||
);
|
||||
if (!response.ok) {
|
||||
return {
|
||||
title: "File Not Found",
|
||||
description: "The file you are looking for does not exist.",
|
||||
};
|
||||
}
|
||||
const fileDetails = await response.json();
|
||||
|
||||
return {
|
||||
title: fileDetails.name,
|
||||
description: fileDetails.description || fileDetails.name,
|
||||
openGraph: {
|
||||
title: fileDetails.name,
|
||||
description: fileDetails.description || fileDetails.name,
|
||||
url: `${process.env.NEXT_PUBLIC_PAGE_URL}/share?id=${fileDetails.id}`,
|
||||
images: [
|
||||
{
|
||||
url: `${process.env.NEXT_PUBLIC_PAGE_URL}/api/files/serv?id=${fileDetails.id}`,
|
||||
alt: `${fileDetails.name} preview`,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -10,6 +10,7 @@ export default function UploadForm() {
|
||||
const [uploadedFileUrl, setUploadedFileUrl] = useState<string | null>(null);
|
||||
const [progress, setProgress] = useState<number>(0); // Track upload progress
|
||||
const fileInputRef = useRef<HTMLInputElement | null>(null); // Ref for the file input
|
||||
const [isDragActive, setIsDragActive] = useState(false); // Track drag state
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files) {
|
||||
@ -20,6 +21,34 @@ export default function UploadForm() {
|
||||
}
|
||||
};
|
||||
|
||||
// Drag and drop handlers
|
||||
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragActive(true);
|
||||
};
|
||||
|
||||
const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragActive(false);
|
||||
};
|
||||
|
||||
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragActive(false);
|
||||
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
||||
setFile(e.dataTransfer.files[0] ?? null);
|
||||
setUploadedFileUrl(null);
|
||||
setProgress(0);
|
||||
setUploading(false);
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpload = async () => {
|
||||
if (!file) return toast.error("Please select a file to upload.");
|
||||
setUploading(true);
|
||||
@ -41,15 +70,14 @@ export default function UploadForm() {
|
||||
|
||||
xhr.onload = () => {
|
||||
if (xhr.status === 200) {
|
||||
const response: { url: string } = JSON.parse(xhr.responseText); // Explicitly type the response
|
||||
setUploadedFileUrl(response.url); // Assume the API returns the uploaded file URL
|
||||
notifyClients({type: "file-uploaded", fileUrl: response.url}); // Notify other clients about the new file
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
setUploadedFileUrl(response.file?.url || null); // Use the new response structure
|
||||
toast.success("File uploaded successfully!");
|
||||
|
||||
// Clear the file input and reset state
|
||||
setFile(null);
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = ""; // Clear the file input
|
||||
fileInputRef.current.value = "";
|
||||
}
|
||||
} else {
|
||||
console.error("Upload failed:", xhr.responseText);
|
||||
@ -86,42 +114,48 @@ export default function UploadForm() {
|
||||
{/* Toast container */}
|
||||
<Toaster position="top-right" reverseOrder={false} />
|
||||
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
{/* Custom file input */}
|
||||
<label
|
||||
htmlFor="file-upload"
|
||||
className="cursor-pointer flex items-center gap-2 rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20"
|
||||
>
|
||||
{file ? (
|
||||
<>
|
||||
File Selected
|
||||
{/* SVG Icon */}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={2}
|
||||
stroke="currentColor"
|
||||
className="h-5 w-5 text-green-500"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
</>
|
||||
) : (
|
||||
"Select File"
|
||||
)}
|
||||
</label>
|
||||
{/* Drag and Drop Area */}
|
||||
<div
|
||||
className={`w-full max-w-md flex flex-col items-center justify-center border-2 border-dashed rounded-lg p-6 mb-2 transition-colors duration-200 ${isDragActive ? "border-blue-500 bg-blue-100/30" : "border-gray-400 bg-transparent hover:bg-gray-50/10"}`}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
{/* Hidden file input for click-to-select */}
|
||||
<input
|
||||
id="file-upload"
|
||||
ref={fileInputRef} // Attach the ref to the file input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
style={{ display: "none" }}
|
||||
onChange={handleFileChange}
|
||||
className="hidden" // Hide the default file input
|
||||
/>
|
||||
<span className="text-gray-300">
|
||||
{isDragActive ? "Drop your file here" : "Drag & drop a file here, or click to select"}
|
||||
</span>
|
||||
{file && (
|
||||
<div className="mt-2 flex items-center gap-2">
|
||||
<span className="text-green-500 font-semibold">{file.name}</span>
|
||||
{/* Add button to remove file */}
|
||||
<button
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setFile(null);
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = "";
|
||||
}
|
||||
}}
|
||||
className="flex items-center justify-center rounded-full bg-red-500 p-2 hover:bg-red-700"
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<img src="/icons/delete.svg" alt="Remove" className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* Show upload button only when file is selected */}
|
||||
{file && (
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
<button
|
||||
onClick={handleUpload}
|
||||
disabled={uploading || !file}
|
||||
@ -129,7 +163,7 @@ export default function UploadForm() {
|
||||
>
|
||||
{uploading ? "Uploading..." : "Upload"}
|
||||
</button>
|
||||
</div>
|
||||
</div>)}
|
||||
|
||||
{file && uploading && (
|
||||
<div className="w-full max-w-md flex items-center gap-2">
|
||||
@ -142,31 +176,17 @@ export default function UploadForm() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{uploadedFileUrl && (
|
||||
{/* {uploadedFileUrl && file && (
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
<p className="text-white">{uploadedFileUrl}</p>
|
||||
<p className="text-white">{file.name}</p>
|
||||
<button
|
||||
onClick={handleCopyUrl}
|
||||
className="flex items-center justify-center rounded-full bg-blue-500 p-2 hover:bg-blue-600"
|
||||
>
|
||||
{/* Copy Icon */}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={2}
|
||||
stroke="currentColor"
|
||||
className="h-5 w-5 text-white"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M8 16h8M8 12h8m-7 8h6a2 2 0 002-2V6a2 2 0 00-2-2H9a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
<img src="/icons/copy.svg" alt="Copy URL" className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,10 +1,12 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import Busboy from "busboy";
|
||||
import { Readable } from "stream";
|
||||
import crypto from "crypto";
|
||||
import { db } from "~/server/db";
|
||||
import { auth } from "~/server/auth";
|
||||
import { minioClient, ensureBucketExists } from "~/utils/minioClient";
|
||||
import { getFileType } from "~/utils/fileType";
|
||||
import cuid from 'cuid';
|
||||
import { notifyClients } from "~/utils/notifyClients";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
@ -22,7 +24,9 @@ export async function POST(req: Request) {
|
||||
await ensureBucketExists(bucketName);
|
||||
|
||||
return new Promise<Response>((resolve, reject) => {
|
||||
const busboy = Busboy({ headers: { "content-type": req.headers.get("content-type") ?? "" } });
|
||||
const busboy = Busboy({
|
||||
headers: { "content-type": req.headers.get("content-type") ?? "" },
|
||||
});
|
||||
let fileName = "";
|
||||
let fileBuffer = Buffer.alloc(0);
|
||||
|
||||
@ -38,8 +42,11 @@ export async function POST(req: Request) {
|
||||
fileBuffer = Buffer.concat(chunks);
|
||||
|
||||
// Generate a unique ID for the file
|
||||
const fileId = crypto.randomUUID();
|
||||
const fileId = session.user.id + "-" + cuid()
|
||||
const objectName = `${fileId}-${fileName}`;
|
||||
// Change UUID to CUID
|
||||
|
||||
|
||||
|
||||
try {
|
||||
// Upload the file to MinIO
|
||||
@ -52,12 +59,19 @@ export async function POST(req: Request) {
|
||||
url: `/share?id=${fileId}`,
|
||||
name: fileName,
|
||||
size: fileBuffer.length,
|
||||
extension: info.mimeType,
|
||||
extension: getFileType(fileName),
|
||||
uploadedById: session.user.id,
|
||||
},
|
||||
});
|
||||
notifyClients({ type: "file-added", fileId: fileId });
|
||||
|
||||
resolve(NextResponse.json({ message: "File uploaded successfully", file: newFile }));
|
||||
resolve(
|
||||
NextResponse.json({
|
||||
message: "File uploaded successfully",
|
||||
file: newFile,
|
||||
fileId: fileId,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error uploading file to MinIO:", error);
|
||||
reject(new Error("Failed to upload file"));
|
||||
@ -86,4 +100,4 @@ export async function POST(req: Request) {
|
||||
nodeStream.pipe(busboy);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
1
src/app/generated/prisma-client/client.d.ts
vendored
Normal file
1
src/app/generated/prisma-client/client.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from "./index"
|
||||
4
src/app/generated/prisma-client/client.js
Normal file
4
src/app/generated/prisma-client/client.js
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
module.exports = { ...require('.') }
|
||||
1
src/app/generated/prisma-client/default.d.ts
vendored
Normal file
1
src/app/generated/prisma-client/default.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from "./index"
|
||||
4
src/app/generated/prisma-client/default.js
Normal file
4
src/app/generated/prisma-client/default.js
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
module.exports = { ...require('.') }
|
||||
1
src/app/generated/prisma-client/edge.d.ts
vendored
Normal file
1
src/app/generated/prisma-client/edge.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from "./default"
|
||||
243
src/app/generated/prisma-client/edge.js
Normal file
243
src/app/generated/prisma-client/edge.js
Normal file
File diff suppressed because one or more lines are too long
225
src/app/generated/prisma-client/index-browser.js
Normal file
225
src/app/generated/prisma-client/index-browser.js
Normal file
@ -0,0 +1,225 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
Decimal,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Public,
|
||||
getRuntime,
|
||||
skip
|
||||
} = require('./runtime/index-browser.js')
|
||||
|
||||
|
||||
const Prisma = {}
|
||||
|
||||
exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 6.8.2
|
||||
* Query Engine version: 2060c79ba17c6bb9f5823312b6f6b7f4a845738e
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "6.8.2",
|
||||
engine: "2060c79ba17c6bb9f5823312b6f6b7f4a845738e"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)};
|
||||
Prisma.PrismaClientUnknownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientRustPanicError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientInitializationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientValidationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.Decimal = Decimal
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
Prisma.sql = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.empty = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.join = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.raw = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.validator = Public.validator
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
Prisma.getExtensionContext = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.defineExtension = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
|
||||
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
});
|
||||
|
||||
exports.Prisma.AccountScalarFieldEnum = {
|
||||
id: 'id',
|
||||
userId: 'userId',
|
||||
type: 'type',
|
||||
provider: 'provider',
|
||||
providerAccountId: 'providerAccountId',
|
||||
refresh_token: 'refresh_token',
|
||||
access_token: 'access_token',
|
||||
expires_at: 'expires_at',
|
||||
token_type: 'token_type',
|
||||
scope: 'scope',
|
||||
id_token: 'id_token',
|
||||
session_state: 'session_state',
|
||||
refresh_token_expires_in: 'refresh_token_expires_in'
|
||||
};
|
||||
|
||||
exports.Prisma.SessionScalarFieldEnum = {
|
||||
id: 'id',
|
||||
sessionToken: 'sessionToken',
|
||||
userId: 'userId',
|
||||
expires: 'expires'
|
||||
};
|
||||
|
||||
exports.Prisma.UserScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
email: 'email',
|
||||
emailVerified: 'emailVerified',
|
||||
image: 'image'
|
||||
};
|
||||
|
||||
exports.Prisma.VerificationTokenScalarFieldEnum = {
|
||||
identifier: 'identifier',
|
||||
token: 'token',
|
||||
expires: 'expires'
|
||||
};
|
||||
|
||||
exports.Prisma.FileScalarFieldEnum = {
|
||||
id: 'id',
|
||||
url: 'url',
|
||||
name: 'name',
|
||||
size: 'size',
|
||||
extension: 'extension',
|
||||
uploadDate: 'uploadDate',
|
||||
description: 'description',
|
||||
uploadedById: 'uploadedById',
|
||||
public: 'public'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
};
|
||||
|
||||
exports.Prisma.QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
};
|
||||
|
||||
exports.Prisma.NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last'
|
||||
};
|
||||
|
||||
|
||||
exports.Prisma.ModelName = {
|
||||
Account: 'Account',
|
||||
Session: 'Session',
|
||||
User: 'User',
|
||||
VerificationToken: 'VerificationToken',
|
||||
File: 'File'
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a stub Prisma Client that will error at runtime if called.
|
||||
*/
|
||||
class PrismaClient {
|
||||
constructor() {
|
||||
return new Proxy(this, {
|
||||
get(target, prop) {
|
||||
let message
|
||||
const runtime = getRuntime()
|
||||
if (runtime.isEdge) {
|
||||
message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either:
|
||||
- Use Prisma Accelerate: https://pris.ly/d/accelerate
|
||||
- Use Driver Adapters: https://pris.ly/d/driver-adapters
|
||||
`;
|
||||
} else {
|
||||
message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).'
|
||||
}
|
||||
|
||||
message += `
|
||||
If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report`
|
||||
|
||||
throw new Error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.PrismaClient = PrismaClient
|
||||
|
||||
Object.assign(exports, Prisma)
|
||||
8947
src/app/generated/prisma-client/index.d.ts
vendored
Normal file
8947
src/app/generated/prisma-client/index.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
258
src/app/generated/prisma-client/index.js
Normal file
258
src/app/generated/prisma-client/index.js
Normal file
File diff suppressed because one or more lines are too long
140
src/app/generated/prisma-client/package.json
Normal file
140
src/app/generated/prisma-client/package.json
Normal file
@ -0,0 +1,140 @@
|
||||
{
|
||||
"name": "prisma-client-08d22f6c857ed95dda3e967008d87d351c30e87c75486e96dad4c24294f1763e",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"browser": "index-browser.js",
|
||||
"exports": {
|
||||
"./client": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./edge": {
|
||||
"types": "./edge.d.ts",
|
||||
"require": "./edge.js",
|
||||
"import": "./edge.js",
|
||||
"default": "./edge.js"
|
||||
},
|
||||
"./react-native": {
|
||||
"types": "./react-native.d.ts",
|
||||
"require": "./react-native.js",
|
||||
"import": "./react-native.js",
|
||||
"default": "./react-native.js"
|
||||
},
|
||||
"./extension": {
|
||||
"types": "./extension.d.ts",
|
||||
"require": "./extension.js",
|
||||
"import": "./extension.js",
|
||||
"default": "./extension.js"
|
||||
},
|
||||
"./index-browser": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index-browser.js",
|
||||
"import": "./index-browser.js",
|
||||
"default": "./index-browser.js"
|
||||
},
|
||||
"./index": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index.js",
|
||||
"import": "./index.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./wasm": {
|
||||
"types": "./wasm.d.ts",
|
||||
"require": "./wasm.js",
|
||||
"import": "./wasm.mjs",
|
||||
"default": "./wasm.mjs"
|
||||
},
|
||||
"./runtime/client": {
|
||||
"types": "./runtime/client.d.ts",
|
||||
"require": "./runtime/client.js",
|
||||
"import": "./runtime/client.mjs",
|
||||
"default": "./runtime/client.mjs"
|
||||
},
|
||||
"./runtime/library": {
|
||||
"types": "./runtime/library.d.ts",
|
||||
"require": "./runtime/library.js",
|
||||
"import": "./runtime/library.mjs",
|
||||
"default": "./runtime/library.mjs"
|
||||
},
|
||||
"./runtime/binary": {
|
||||
"types": "./runtime/binary.d.ts",
|
||||
"require": "./runtime/binary.js",
|
||||
"import": "./runtime/binary.mjs",
|
||||
"default": "./runtime/binary.mjs"
|
||||
},
|
||||
"./runtime/wasm": {
|
||||
"types": "./runtime/wasm.d.ts",
|
||||
"require": "./runtime/wasm.js",
|
||||
"import": "./runtime/wasm.mjs",
|
||||
"default": "./runtime/wasm.mjs"
|
||||
},
|
||||
"./runtime/edge": {
|
||||
"types": "./runtime/edge.d.ts",
|
||||
"require": "./runtime/edge.js",
|
||||
"import": "./runtime/edge-esm.js",
|
||||
"default": "./runtime/edge-esm.js"
|
||||
},
|
||||
"./runtime/react-native": {
|
||||
"types": "./runtime/react-native.d.ts",
|
||||
"require": "./runtime/react-native.js",
|
||||
"import": "./runtime/react-native.js",
|
||||
"default": "./runtime/react-native.js"
|
||||
},
|
||||
"./generator-build": {
|
||||
"require": "./generator-build/index.js",
|
||||
"import": "./generator-build/index.js",
|
||||
"default": "./generator-build/index.js"
|
||||
},
|
||||
"./sql": {
|
||||
"require": {
|
||||
"types": "./sql.d.ts",
|
||||
"node": "./sql.js",
|
||||
"default": "./sql.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./sql.d.ts",
|
||||
"node": "./sql.mjs",
|
||||
"default": "./sql.mjs"
|
||||
},
|
||||
"default": "./sql.js"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"version": "6.8.2",
|
||||
"sideEffects": false
|
||||
}
|
||||
34
src/app/generated/prisma-client/runtime/edge-esm.js
Normal file
34
src/app/generated/prisma-client/runtime/edge-esm.js
Normal file
File diff suppressed because one or more lines are too long
34
src/app/generated/prisma-client/runtime/edge.js
Normal file
34
src/app/generated/prisma-client/runtime/edge.js
Normal file
File diff suppressed because one or more lines are too long
370
src/app/generated/prisma-client/runtime/index-browser.d.ts
vendored
Normal file
370
src/app/generated/prisma-client/runtime/index-browser.d.ts
vendored
Normal file
@ -0,0 +1,370 @@
|
||||
declare class AnyNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
declare type Args<T, F extends Operation> = T extends {
|
||||
[K: symbol]: {
|
||||
types: {
|
||||
operations: {
|
||||
[K in F]: {
|
||||
args: any;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} ? T[symbol]['types']['operations'][F]['args'] : any;
|
||||
|
||||
declare class DbNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
export declare function Decimal(n: Decimal.Value): Decimal;
|
||||
|
||||
export declare namespace Decimal {
|
||||
export type Constructor = typeof Decimal;
|
||||
export type Instance = Decimal;
|
||||
export type Rounding = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||
export type Modulo = Rounding | 9;
|
||||
export type Value = string | number | Decimal;
|
||||
|
||||
// http://mikemcl.github.io/decimal.js/#constructor-properties
|
||||
export interface Config {
|
||||
precision?: number;
|
||||
rounding?: Rounding;
|
||||
toExpNeg?: number;
|
||||
toExpPos?: number;
|
||||
minE?: number;
|
||||
maxE?: number;
|
||||
crypto?: boolean;
|
||||
modulo?: Modulo;
|
||||
defaults?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export declare class Decimal {
|
||||
readonly d: number[];
|
||||
readonly e: number;
|
||||
readonly s: number;
|
||||
|
||||
constructor(n: Decimal.Value);
|
||||
|
||||
absoluteValue(): Decimal;
|
||||
abs(): Decimal;
|
||||
|
||||
ceil(): Decimal;
|
||||
|
||||
clampedTo(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
clamp(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
|
||||
comparedTo(n: Decimal.Value): number;
|
||||
cmp(n: Decimal.Value): number;
|
||||
|
||||
cosine(): Decimal;
|
||||
cos(): Decimal;
|
||||
|
||||
cubeRoot(): Decimal;
|
||||
cbrt(): Decimal;
|
||||
|
||||
decimalPlaces(): number;
|
||||
dp(): number;
|
||||
|
||||
dividedBy(n: Decimal.Value): Decimal;
|
||||
div(n: Decimal.Value): Decimal;
|
||||
|
||||
dividedToIntegerBy(n: Decimal.Value): Decimal;
|
||||
divToInt(n: Decimal.Value): Decimal;
|
||||
|
||||
equals(n: Decimal.Value): boolean;
|
||||
eq(n: Decimal.Value): boolean;
|
||||
|
||||
floor(): Decimal;
|
||||
|
||||
greaterThan(n: Decimal.Value): boolean;
|
||||
gt(n: Decimal.Value): boolean;
|
||||
|
||||
greaterThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
gte(n: Decimal.Value): boolean;
|
||||
|
||||
hyperbolicCosine(): Decimal;
|
||||
cosh(): Decimal;
|
||||
|
||||
hyperbolicSine(): Decimal;
|
||||
sinh(): Decimal;
|
||||
|
||||
hyperbolicTangent(): Decimal;
|
||||
tanh(): Decimal;
|
||||
|
||||
inverseCosine(): Decimal;
|
||||
acos(): Decimal;
|
||||
|
||||
inverseHyperbolicCosine(): Decimal;
|
||||
acosh(): Decimal;
|
||||
|
||||
inverseHyperbolicSine(): Decimal;
|
||||
asinh(): Decimal;
|
||||
|
||||
inverseHyperbolicTangent(): Decimal;
|
||||
atanh(): Decimal;
|
||||
|
||||
inverseSine(): Decimal;
|
||||
asin(): Decimal;
|
||||
|
||||
inverseTangent(): Decimal;
|
||||
atan(): Decimal;
|
||||
|
||||
isFinite(): boolean;
|
||||
|
||||
isInteger(): boolean;
|
||||
isInt(): boolean;
|
||||
|
||||
isNaN(): boolean;
|
||||
|
||||
isNegative(): boolean;
|
||||
isNeg(): boolean;
|
||||
|
||||
isPositive(): boolean;
|
||||
isPos(): boolean;
|
||||
|
||||
isZero(): boolean;
|
||||
|
||||
lessThan(n: Decimal.Value): boolean;
|
||||
lt(n: Decimal.Value): boolean;
|
||||
|
||||
lessThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
lte(n: Decimal.Value): boolean;
|
||||
|
||||
logarithm(n?: Decimal.Value): Decimal;
|
||||
log(n?: Decimal.Value): Decimal;
|
||||
|
||||
minus(n: Decimal.Value): Decimal;
|
||||
sub(n: Decimal.Value): Decimal;
|
||||
|
||||
modulo(n: Decimal.Value): Decimal;
|
||||
mod(n: Decimal.Value): Decimal;
|
||||
|
||||
naturalExponential(): Decimal;
|
||||
exp(): Decimal;
|
||||
|
||||
naturalLogarithm(): Decimal;
|
||||
ln(): Decimal;
|
||||
|
||||
negated(): Decimal;
|
||||
neg(): Decimal;
|
||||
|
||||
plus(n: Decimal.Value): Decimal;
|
||||
add(n: Decimal.Value): Decimal;
|
||||
|
||||
precision(includeZeros?: boolean): number;
|
||||
sd(includeZeros?: boolean): number;
|
||||
|
||||
round(): Decimal;
|
||||
|
||||
sine() : Decimal;
|
||||
sin() : Decimal;
|
||||
|
||||
squareRoot(): Decimal;
|
||||
sqrt(): Decimal;
|
||||
|
||||
tangent() : Decimal;
|
||||
tan() : Decimal;
|
||||
|
||||
times(n: Decimal.Value): Decimal;
|
||||
mul(n: Decimal.Value) : Decimal;
|
||||
|
||||
toBinary(significantDigits?: number): string;
|
||||
toBinary(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toDecimalPlaces(decimalPlaces?: number): Decimal;
|
||||
toDecimalPlaces(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
toDP(decimalPlaces?: number): Decimal;
|
||||
toDP(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toExponential(decimalPlaces?: number): string;
|
||||
toExponential(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFixed(decimalPlaces?: number): string;
|
||||
toFixed(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFraction(max_denominator?: Decimal.Value): Decimal[];
|
||||
|
||||
toHexadecimal(significantDigits?: number): string;
|
||||
toHexadecimal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
toHex(significantDigits?: number): string;
|
||||
toHex(significantDigits: number, rounding?: Decimal.Rounding): string;
|
||||
|
||||
toJSON(): string;
|
||||
|
||||
toNearest(n: Decimal.Value, rounding?: Decimal.Rounding): Decimal;
|
||||
|
||||
toNumber(): number;
|
||||
|
||||
toOctal(significantDigits?: number): string;
|
||||
toOctal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toPower(n: Decimal.Value): Decimal;
|
||||
pow(n: Decimal.Value): Decimal;
|
||||
|
||||
toPrecision(significantDigits?: number): string;
|
||||
toPrecision(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toSignificantDigits(significantDigits?: number): Decimal;
|
||||
toSignificantDigits(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
toSD(significantDigits?: number): Decimal;
|
||||
toSD(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toString(): string;
|
||||
|
||||
truncated(): Decimal;
|
||||
trunc(): Decimal;
|
||||
|
||||
valueOf(): string;
|
||||
|
||||
static abs(n: Decimal.Value): Decimal;
|
||||
static acos(n: Decimal.Value): Decimal;
|
||||
static acosh(n: Decimal.Value): Decimal;
|
||||
static add(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static asin(n: Decimal.Value): Decimal;
|
||||
static asinh(n: Decimal.Value): Decimal;
|
||||
static atan(n: Decimal.Value): Decimal;
|
||||
static atanh(n: Decimal.Value): Decimal;
|
||||
static atan2(y: Decimal.Value, x: Decimal.Value): Decimal;
|
||||
static cbrt(n: Decimal.Value): Decimal;
|
||||
static ceil(n: Decimal.Value): Decimal;
|
||||
static clamp(n: Decimal.Value, min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
static clone(object?: Decimal.Config): Decimal.Constructor;
|
||||
static config(object: Decimal.Config): Decimal.Constructor;
|
||||
static cos(n: Decimal.Value): Decimal;
|
||||
static cosh(n: Decimal.Value): Decimal;
|
||||
static div(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static exp(n: Decimal.Value): Decimal;
|
||||
static floor(n: Decimal.Value): Decimal;
|
||||
static hypot(...n: Decimal.Value[]): Decimal;
|
||||
static isDecimal(object: any): object is Decimal;
|
||||
static ln(n: Decimal.Value): Decimal;
|
||||
static log(n: Decimal.Value, base?: Decimal.Value): Decimal;
|
||||
static log2(n: Decimal.Value): Decimal;
|
||||
static log10(n: Decimal.Value): Decimal;
|
||||
static max(...n: Decimal.Value[]): Decimal;
|
||||
static min(...n: Decimal.Value[]): Decimal;
|
||||
static mod(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static mul(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static noConflict(): Decimal.Constructor; // Browser only
|
||||
static pow(base: Decimal.Value, exponent: Decimal.Value): Decimal;
|
||||
static random(significantDigits?: number): Decimal;
|
||||
static round(n: Decimal.Value): Decimal;
|
||||
static set(object: Decimal.Config): Decimal.Constructor;
|
||||
static sign(n: Decimal.Value): number;
|
||||
static sin(n: Decimal.Value): Decimal;
|
||||
static sinh(n: Decimal.Value): Decimal;
|
||||
static sqrt(n: Decimal.Value): Decimal;
|
||||
static sub(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static sum(...n: Decimal.Value[]): Decimal;
|
||||
static tan(n: Decimal.Value): Decimal;
|
||||
static tanh(n: Decimal.Value): Decimal;
|
||||
static trunc(n: Decimal.Value): Decimal;
|
||||
|
||||
static readonly default?: Decimal.Constructor;
|
||||
static readonly Decimal?: Decimal.Constructor;
|
||||
|
||||
static readonly precision: number;
|
||||
static readonly rounding: Decimal.Rounding;
|
||||
static readonly toExpNeg: number;
|
||||
static readonly toExpPos: number;
|
||||
static readonly minE: number;
|
||||
static readonly maxE: number;
|
||||
static readonly crypto: boolean;
|
||||
static readonly modulo: Decimal.Modulo;
|
||||
|
||||
static readonly ROUND_UP: 0;
|
||||
static readonly ROUND_DOWN: 1;
|
||||
static readonly ROUND_CEIL: 2;
|
||||
static readonly ROUND_FLOOR: 3;
|
||||
static readonly ROUND_HALF_UP: 4;
|
||||
static readonly ROUND_HALF_DOWN: 5;
|
||||
static readonly ROUND_HALF_EVEN: 6;
|
||||
static readonly ROUND_HALF_CEIL: 7;
|
||||
static readonly ROUND_HALF_FLOOR: 8;
|
||||
static readonly EUCLID: 9;
|
||||
}
|
||||
|
||||
declare type Exact<A, W> = (A extends unknown ? (W extends A ? {
|
||||
[K in keyof A]: Exact<A[K], W[K]>;
|
||||
} : W) : never) | (A extends Narrowable ? A : never);
|
||||
|
||||
export declare function getRuntime(): GetRuntimeOutput;
|
||||
|
||||
declare type GetRuntimeOutput = {
|
||||
id: RuntimeName;
|
||||
prettyName: string;
|
||||
isEdge: boolean;
|
||||
};
|
||||
|
||||
declare class JsonNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates more strict variant of an enum which, unlike regular enum,
|
||||
* throws on non-existing property access. This can be useful in following situations:
|
||||
* - we have an API, that accepts both `undefined` and `SomeEnumType` as an input
|
||||
* - enum values are generated dynamically from DMMF.
|
||||
*
|
||||
* In that case, if using normal enums and no compile-time typechecking, using non-existing property
|
||||
* will result in `undefined` value being used, which will be accepted. Using strict enum
|
||||
* in this case will help to have a runtime exception, telling you that you are probably doing something wrong.
|
||||
*
|
||||
* Note: if you need to check for existence of a value in the enum you can still use either
|
||||
* `in` operator or `hasOwnProperty` function.
|
||||
*
|
||||
* @param definition
|
||||
* @returns
|
||||
*/
|
||||
export declare function makeStrictEnum<T extends Record<PropertyKey, string | number>>(definition: T): T;
|
||||
|
||||
declare type Narrowable = string | number | bigint | boolean | [];
|
||||
|
||||
declare class NullTypesEnumValue extends ObjectEnumValue {
|
||||
_getNamespace(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for unique values of object-valued enums.
|
||||
*/
|
||||
declare abstract class ObjectEnumValue {
|
||||
constructor(arg?: symbol);
|
||||
abstract _getNamespace(): string;
|
||||
_getName(): string;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
export declare const objectEnumValues: {
|
||||
classes: {
|
||||
DbNull: typeof DbNull;
|
||||
JsonNull: typeof JsonNull;
|
||||
AnyNull: typeof AnyNull;
|
||||
};
|
||||
instances: {
|
||||
DbNull: DbNull;
|
||||
JsonNull: JsonNull;
|
||||
AnyNull: AnyNull;
|
||||
};
|
||||
};
|
||||
|
||||
declare type Operation = 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'findMany' | 'create' | 'createMany' | 'createManyAndReturn' | 'update' | 'updateMany' | 'updateManyAndReturn' | 'upsert' | 'delete' | 'deleteMany' | 'aggregate' | 'count' | 'groupBy' | '$queryRaw' | '$executeRaw' | '$queryRawUnsafe' | '$executeRawUnsafe' | 'findRaw' | 'aggregateRaw' | '$runCommandRaw';
|
||||
|
||||
declare namespace Public {
|
||||
export {
|
||||
validator
|
||||
}
|
||||
}
|
||||
export { Public }
|
||||
|
||||
declare type RuntimeName = 'workerd' | 'deno' | 'netlify' | 'node' | 'bun' | 'edge-light' | '';
|
||||
|
||||
declare function validator<V>(): <S>(select: Exact<S, V>) => S;
|
||||
|
||||
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation>(client: C, model: M, operation: O): <S>(select: Exact<S, Args<C[M], O>>) => S;
|
||||
|
||||
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation, P extends keyof Args<C[M], O>>(client: C, model: M, operation: O, prop: P): <S>(select: Exact<S, Args<C[M], O>[P]>) => S;
|
||||
|
||||
export { }
|
||||
16
src/app/generated/prisma-client/runtime/index-browser.js
Normal file
16
src/app/generated/prisma-client/runtime/index-browser.js
Normal file
File diff suppressed because one or more lines are too long
3647
src/app/generated/prisma-client/runtime/library.d.ts
vendored
Normal file
3647
src/app/generated/prisma-client/runtime/library.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
146
src/app/generated/prisma-client/runtime/library.js
Normal file
146
src/app/generated/prisma-client/runtime/library.js
Normal file
File diff suppressed because one or more lines are too long
83
src/app/generated/prisma-client/runtime/react-native.js
vendored
Normal file
83
src/app/generated/prisma-client/runtime/react-native.js
vendored
Normal file
File diff suppressed because one or more lines are too long
35
src/app/generated/prisma-client/runtime/wasm.js
Normal file
35
src/app/generated/prisma-client/runtime/wasm.js
Normal file
File diff suppressed because one or more lines are too long
77
src/app/generated/prisma-client/schema.prisma
Normal file
77
src/app/generated/prisma-client/schema.prisma
Normal file
@ -0,0 +1,77 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-3.0.x"]
|
||||
output = "/app/generated/prisma-client"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
// NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
|
||||
// Further reading:
|
||||
// https://next-auth.js.org/adapters/prisma#create-the-prisma-schema
|
||||
// https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// Necessary for Next auth
|
||||
model Account {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String
|
||||
refresh_token String? @db.Text
|
||||
access_token String? // @db.Text
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
id_token String? // @db.Text
|
||||
session_state String?
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
refresh_token_expires_in Int?
|
||||
|
||||
@@unique([provider, providerAccountId])
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(cuid())
|
||||
sessionToken String @unique
|
||||
userId String
|
||||
expires DateTime
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
files File[] // Relation to the File model
|
||||
}
|
||||
|
||||
model VerificationToken {
|
||||
identifier String
|
||||
token String @unique
|
||||
expires DateTime
|
||||
|
||||
@@unique([identifier, token])
|
||||
}
|
||||
|
||||
model File {
|
||||
id String @id @default(cuid())
|
||||
url String
|
||||
name String
|
||||
size Int // Size in bytes
|
||||
extension String
|
||||
uploadDate DateTime @default(now())
|
||||
description String @default("")
|
||||
uploadedBy User? @relation(fields: [uploadedById], references: [id], onDelete: SetNull)
|
||||
uploadedById String?
|
||||
public Boolean @default(false) // Indicates if the file is public or private
|
||||
}
|
||||
1
src/app/generated/prisma-client/wasm.d.ts
vendored
Normal file
1
src/app/generated/prisma-client/wasm.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from "./index"
|
||||
225
src/app/generated/prisma-client/wasm.js
Normal file
225
src/app/generated/prisma-client/wasm.js
Normal file
@ -0,0 +1,225 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
Decimal,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Public,
|
||||
getRuntime,
|
||||
skip
|
||||
} = require('./runtime/index-browser.js')
|
||||
|
||||
|
||||
const Prisma = {}
|
||||
|
||||
exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 6.8.2
|
||||
* Query Engine version: 2060c79ba17c6bb9f5823312b6f6b7f4a845738e
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "6.8.2",
|
||||
engine: "2060c79ba17c6bb9f5823312b6f6b7f4a845738e"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)};
|
||||
Prisma.PrismaClientUnknownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientRustPanicError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientInitializationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientValidationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.Decimal = Decimal
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
Prisma.sql = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.empty = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.join = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.raw = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.validator = Public.validator
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
Prisma.getExtensionContext = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.defineExtension = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
|
||||
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
});
|
||||
|
||||
exports.Prisma.AccountScalarFieldEnum = {
|
||||
id: 'id',
|
||||
userId: 'userId',
|
||||
type: 'type',
|
||||
provider: 'provider',
|
||||
providerAccountId: 'providerAccountId',
|
||||
refresh_token: 'refresh_token',
|
||||
access_token: 'access_token',
|
||||
expires_at: 'expires_at',
|
||||
token_type: 'token_type',
|
||||
scope: 'scope',
|
||||
id_token: 'id_token',
|
||||
session_state: 'session_state',
|
||||
refresh_token_expires_in: 'refresh_token_expires_in'
|
||||
};
|
||||
|
||||
exports.Prisma.SessionScalarFieldEnum = {
|
||||
id: 'id',
|
||||
sessionToken: 'sessionToken',
|
||||
userId: 'userId',
|
||||
expires: 'expires'
|
||||
};
|
||||
|
||||
exports.Prisma.UserScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
email: 'email',
|
||||
emailVerified: 'emailVerified',
|
||||
image: 'image'
|
||||
};
|
||||
|
||||
exports.Prisma.VerificationTokenScalarFieldEnum = {
|
||||
identifier: 'identifier',
|
||||
token: 'token',
|
||||
expires: 'expires'
|
||||
};
|
||||
|
||||
exports.Prisma.FileScalarFieldEnum = {
|
||||
id: 'id',
|
||||
url: 'url',
|
||||
name: 'name',
|
||||
size: 'size',
|
||||
extension: 'extension',
|
||||
uploadDate: 'uploadDate',
|
||||
description: 'description',
|
||||
uploadedById: 'uploadedById',
|
||||
public: 'public'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
};
|
||||
|
||||
exports.Prisma.QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
};
|
||||
|
||||
exports.Prisma.NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last'
|
||||
};
|
||||
|
||||
|
||||
exports.Prisma.ModelName = {
|
||||
Account: 'Account',
|
||||
Session: 'Session',
|
||||
User: 'User',
|
||||
VerificationToken: 'VerificationToken',
|
||||
File: 'File'
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a stub Prisma Client that will error at runtime if called.
|
||||
*/
|
||||
class PrismaClient {
|
||||
constructor() {
|
||||
return new Proxy(this, {
|
||||
get(target, prop) {
|
||||
let message
|
||||
const runtime = getRuntime()
|
||||
if (runtime.isEdge) {
|
||||
message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either:
|
||||
- Use Prisma Accelerate: https://pris.ly/d/accelerate
|
||||
- Use Driver Adapters: https://pris.ly/d/driver-adapters
|
||||
`;
|
||||
} else {
|
||||
message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).'
|
||||
}
|
||||
|
||||
message += `
|
||||
If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report`
|
||||
|
||||
throw new Error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.PrismaClient = PrismaClient
|
||||
|
||||
Object.assign(exports, Prisma)
|
||||
6
src/app/loading.tsx
Normal file
6
src/app/loading.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import LoadingSkeleton from './LoadingSkeleton';
|
||||
|
||||
export default function Loading() {
|
||||
// You can add any UI inside Loading, including a Skeleton.
|
||||
return <LoadingSkeleton />
|
||||
}
|
||||
101
src/app/page.tsx
101
src/app/page.tsx
@ -1,15 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { auth } from "~/server/auth";
|
||||
import { HydrateClient } from "~/trpc/server";
|
||||
import { useEffect, useState } from "react";
|
||||
import FileGrid from "~/app/_components/FileGrid";
|
||||
import UploadForm from "~/app/_components/UploadForm";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { Suspense } from "react";
|
||||
import LoadingSkeleton from "./LoadingSkeleton";
|
||||
|
||||
export default async function Home() {
|
||||
const session = await auth();
|
||||
// Custom fallback for FileGrid
|
||||
function FileGridFallback() {
|
||||
return (
|
||||
<div className="grid w-full max-w-4xl animate-pulse grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3">
|
||||
{[...Array(6)].map((_, i) => (
|
||||
<div key={i} className="flex flex-col items-center">
|
||||
<span className="mb-2 text-lg text-white/60">Loading</span>
|
||||
<div className="h-32 w-full rounded bg-white/10" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Custom fallback for UploadForm
|
||||
function UploadFormFallback() {
|
||||
return (
|
||||
<div className="mt-8 flex w-full max-w-md animate-pulse flex-col gap-4">
|
||||
<div className="h-10 rounded bg-white/20" />
|
||||
<div className="h-10 rounded bg-white/10" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Home() {
|
||||
const [session, setSession] = useState<{ user?: any } | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
useEffect(() => {
|
||||
async function fetchSession() {
|
||||
setLoading(true);
|
||||
const res = await fetch("/api/auth/session");
|
||||
const data = await res.json();
|
||||
setSession(data);
|
||||
setLoading(false);
|
||||
}
|
||||
fetchSession();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<HydrateClient>
|
||||
<>
|
||||
<Toaster position="top-right" reverseOrder={false} />
|
||||
<main className="relative flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||
{/* Top-right corner sign-out button */}
|
||||
@ -53,28 +91,59 @@ export default async function Home() {
|
||||
{/* Conditionally render FileGrid and UploadForm if the user is logged in */}
|
||||
{session?.user ? (
|
||||
<>
|
||||
<FileGrid session={session} />
|
||||
<UploadForm />
|
||||
<Suspense fallback={<FileGridFallback />}>
|
||||
<FileGrid session={session as { user: { id: string } }} />
|
||||
</Suspense>
|
||||
<Suspense fallback={<UploadFormFallback />}>
|
||||
<UploadForm />
|
||||
</Suspense>
|
||||
</>
|
||||
) : (
|
||||
) : !loading ? (
|
||||
<p className="text-center text-2xl text-white">
|
||||
Please log in to upload and view files.
|
||||
</p>
|
||||
)}
|
||||
) : null}
|
||||
{!session?.user && (
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<div className="flex flex-col items-center justify-center gap-4">
|
||||
<Link
|
||||
href={session ? "/api/auth/signout" : "/api/auth/signin"}
|
||||
className="rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20"
|
||||
>
|
||||
{session ? "Sign out" : "Sign in"}
|
||||
</Link>
|
||||
{!loading ? (
|
||||
<Link
|
||||
href={session ? "/api/auth/signout" : "/api/auth/signin"}
|
||||
className="rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20"
|
||||
>
|
||||
{session ? "Sign out" : "Sign in"}
|
||||
</Link>
|
||||
) : (
|
||||
<div className="flex h-10 items-center justify-center">
|
||||
<svg
|
||||
className="h-6 w-6 animate-spin text-white/70"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
</HydrateClient>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
||||
|
||||
@ -91,7 +91,7 @@ export default function SearchFile() {
|
||||
className="flex place-content-end w-xxs flex-col gap-4 rounded-xl bg-white/10 p-4 hover:bg-white/20"
|
||||
>
|
||||
<div className="self-center max-w-100 sm:max-w-50">
|
||||
<FilePreview fileId={file.id} fileType={file.extension} />
|
||||
<FilePreview fileId={file.id} fileType={file.extension} share={false} />
|
||||
</div>
|
||||
|
||||
<button onClick={() => router.push(pageUrl + file.url)}>
|
||||
|
||||
70
src/app/share/LoadingSkeleton.tsx
Normal file
70
src/app/share/LoadingSkeleton.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
import React, { Suspense } from "react";
|
||||
import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import {
|
||||
FileActionsContainer,
|
||||
} from "~/app/_components/ActionButtons"; // Import the client component
|
||||
|
||||
const LoadingSkeleton: React.FC = () => (
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||
<div className="absolute top-4 left-4">
|
||||
<HomeButton />
|
||||
</div>
|
||||
<Toaster position="top-right" reverseOrder={false} />
|
||||
<div className="container flex flex-col items-center gap-12 px-4 py-16">
|
||||
<h1 className="text-5xl font-extrabold tracking-tight sm:text-[5rem]">
|
||||
<span className="text-[hsl(280,100%,70%)]">File</span> Details
|
||||
</h1>
|
||||
<div className="mt-6">
|
||||
<svg
|
||||
className="h-6 w-6 animate-spin text-white/70"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="w-full max-w-md rounded-lg bg-white/10 p-6 text-white shadow-md">
|
||||
<p>
|
||||
<strong>Name:</strong> <span className="inline-block h-6 w-24 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</p>
|
||||
<p>
|
||||
<strong>Size:</strong> <span className="inline-block h-6 w-16 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</p>
|
||||
<p>
|
||||
<strong>Owner:</strong> <span className="inline-block h-6 w-20 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</p>
|
||||
<p>
|
||||
<strong>Upload Date:</strong> <span className="inline-block h-6 w-28 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</p>
|
||||
<div>
|
||||
<strong>Description:</strong> <span className="inline-block h-6 w-40 rounded bg-white/20 animate-pulse align-middle ml-2" />
|
||||
</div>
|
||||
<div className="mt-4 flex justify-center">
|
||||
<FileActionsContainer
|
||||
fileId={""}
|
||||
fileName={""}
|
||||
fileUrl={""}
|
||||
isOwner={false}
|
||||
isPublic={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
export default LoadingSkeleton;
|
||||
6
src/app/share/loading.tsx
Normal file
6
src/app/share/loading.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import LoadingSkeleton from './LoadingSkeleton';
|
||||
|
||||
export default function Loading() {
|
||||
// You can add any UI inside Loading, including a Skeleton.
|
||||
return <LoadingSkeleton />
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { Suspense } from "react";
|
||||
import { FilePreview } from "~/app/_components/FilePreview";
|
||||
import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
|
||||
import { Toaster } from "react-hot-toast";
|
||||
@ -129,7 +130,9 @@ export default async function FilePreviewContainer({
|
||||
</h1>
|
||||
<div className="mt-6">
|
||||
{fileDetails.type !== "unknown" && (
|
||||
<FilePreview fileId={fileDetails.id} fileType={fileDetails.type} />
|
||||
<Suspense fallback={<div className="text-white">Loading...</div>}>
|
||||
<FilePreview fileId={fileDetails.id} fileType={fileDetails.type} share={true} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full max-w-md rounded-lg bg-white/10 p-6 text-white shadow-md">
|
||||
@ -148,32 +151,40 @@ export default async function FilePreviewContainer({
|
||||
</p>
|
||||
<p>
|
||||
<strong>Owner:</strong>{" "}
|
||||
<img
|
||||
<Suspense fallback={<div className="text-white">Loading...</div>}>
|
||||
<img
|
||||
className="inline size-5 rounded-md"
|
||||
src={fileDetails.ownerAvatar || ""}
|
||||
alt="Owner avatar"
|
||||
/>{" "}
|
||||
/>{" "}
|
||||
{fileDetails.owner}
|
||||
</Suspense>
|
||||
</p>
|
||||
<p>
|
||||
<strong>Upload Date:</strong>{" "}
|
||||
{new Date(fileDetails.uploadDate).toLocaleString()}
|
||||
<Suspense fallback={<div className="text-white">Loading...</div>}>
|
||||
{new Date(fileDetails.uploadDate).toLocaleString()}
|
||||
</Suspense>
|
||||
</p>
|
||||
<div>
|
||||
<strong>Description:</strong>{" "}
|
||||
<FileDescriptionContainer
|
||||
fileId={fileDetails.id}
|
||||
fileDescription={fileDetails.description}
|
||||
/>
|
||||
<Suspense fallback={<div className="text-white">Loading...</div>}>
|
||||
<FileDescriptionContainer
|
||||
fileId={fileDetails.id}
|
||||
fileDescription={fileDetails.description}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className="mt-4 flex justify-center">
|
||||
<FileActionsContainer
|
||||
fileId={fileDetails.id}
|
||||
fileName={fileDetails.name}
|
||||
fileUrl={fileDetails.url}
|
||||
isOwner={session?.user?.id ? await checkOwner(fileDetails.ownerId, session.user.id) : false}
|
||||
isPublic={fileDetails.isPublic}
|
||||
/>
|
||||
<Suspense fallback={<div className="text-white">Loading...</div>}>
|
||||
<FileActionsContainer
|
||||
fileId={fileDetails.id}
|
||||
fileName={fileDetails.name}
|
||||
fileUrl={fileDetails.url}
|
||||
isOwner={session?.user?.id ? await checkOwner(fileDetails.ownerId, session.user.id) : false}
|
||||
isPublic={fileDetails.isPublic}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
9
src/app/styles/custom.css
Normal file
9
src/app/styles/custom.css
Normal file
@ -0,0 +1,9 @@
|
||||
.markdown-body ul,
|
||||
.markdown-body ol {
|
||||
list-style: initial; /* Ensures bullets or numbers are displayed */
|
||||
margin-left: 1.5em; /* Adds proper indentation */
|
||||
}
|
||||
|
||||
.markdown-body li {
|
||||
margin-bottom: 0.5em; /* Adds spacing between list items */
|
||||
}
|
||||
78
src/components/MarkdownRenderer.tsx
Normal file
78
src/components/MarkdownRenderer.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import { useEffect } from "react";
|
||||
import "github-markdown-css/github-markdown.css";
|
||||
|
||||
interface MarkdownRendererProps {
|
||||
markdownContent: string;
|
||||
}
|
||||
|
||||
export function MarkdownRenderer({ markdownContent }: MarkdownRendererProps) {
|
||||
useEffect(() => {
|
||||
if (markdownContent) {
|
||||
const markdownContainer = document.querySelector("#markdown-preview");
|
||||
if (!markdownContainer) return;
|
||||
|
||||
const codeBlocks = markdownContainer.querySelectorAll("code");
|
||||
|
||||
codeBlocks.forEach((block) => {
|
||||
// Check if the block is already wrapped
|
||||
if (block.parentElement?.classList.contains("code-wrapper")) return;
|
||||
|
||||
// Check if the code block is multiline
|
||||
const isMultiline = block.textContent?.includes("\n");
|
||||
if (!isMultiline) return;
|
||||
|
||||
// Create a wrapper only if it doesn't already exist
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.className = "code-wrapper"; // Add a class to identify the wrapper
|
||||
wrapper.style.display = "flex";
|
||||
wrapper.style.alignItems = "flex-start";
|
||||
wrapper.style.justifyContent = "space-between";
|
||||
wrapper.style.gap = "8px";
|
||||
wrapper.style.width = "100%";
|
||||
wrapper.style.position = "relative";
|
||||
|
||||
const codeContainer = document.createElement("div");
|
||||
codeContainer.style.flex = "1";
|
||||
codeContainer.appendChild(block.cloneNode(true));
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.innerHTML = `
|
||||
<img src="/icons/copy.svg" alt="Copy" class="h-4 w-4" style="filter: invert(1) sepia(1) saturate(5) hue-rotate(180deg);"/>
|
||||
`;
|
||||
button.className =
|
||||
"copy-button inline-flex items-center justify-center bg-gray-200 rounded hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 transition";
|
||||
button.style.marginLeft = "8px";
|
||||
button.style.width = "1.5rem";
|
||||
button.style.height = "1.5rem";
|
||||
|
||||
button.addEventListener("click", () => {
|
||||
navigator.clipboard.writeText(block.textContent || "").then(() => {
|
||||
button.innerHTML = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
`;
|
||||
setTimeout(() => {
|
||||
button.innerHTML = `
|
||||
<img src="/icons/copy.svg" alt="Copy" class="h-4 w-4" style="filter: invert(1) sepia(1) saturate(5) hue-rotate(180deg);"/>
|
||||
`;
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
wrapper.appendChild(codeContainer);
|
||||
wrapper.appendChild(button);
|
||||
|
||||
// Replace the original block with the wrapper
|
||||
block.replaceWith(wrapper);
|
||||
});
|
||||
}
|
||||
}, [markdownContent]);
|
||||
|
||||
return (
|
||||
<div className="markdown-body max-w-full p-4 pt-0 pb-0" id="markdown-preview">
|
||||
<div dangerouslySetInnerHTML={{ __html: markdownContent }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
0
src/server/api/routers/file.ts
Normal file
0
src/server/api/routers/file.ts
Normal file
@ -1,4 +1,5 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { PrismaClient } from "~/app/generated/prisma-client";
|
||||
import { withAccelerate } from '@prisma/extension-accelerate'
|
||||
|
||||
import { env } from "~/env";
|
||||
|
||||
@ -6,7 +7,7 @@ const createPrismaClient = () =>
|
||||
new PrismaClient({
|
||||
log:
|
||||
env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
|
||||
});
|
||||
}).$extends(withAccelerate());
|
||||
|
||||
const globalForPrisma = globalThis as unknown as {
|
||||
prisma: ReturnType<typeof createPrismaClient> | undefined;
|
||||
|
||||
@ -1,32 +1,48 @@
|
||||
// This function takes a file name as input and returns the file type based on its extension.
|
||||
import mime from "mime-types";
|
||||
|
||||
export function getFileType(fileName: string): string {
|
||||
const extension = fileName.split(".").pop()?.toLowerCase();
|
||||
const fileTypes: Record<string, string> = {
|
||||
// Video
|
||||
"mp4": "video/mp4",
|
||||
"webm": "video/webm",
|
||||
"ogg": "video/ogg",
|
||||
// Image
|
||||
"jpg": "image/jpeg",
|
||||
"jpeg": "image/jpeg",
|
||||
"png": "image/png",
|
||||
"gif": "image/gif",
|
||||
"svg": "image/svg+xml",
|
||||
// Audio
|
||||
"mp3": "audio/mpeg",
|
||||
"wav": "audio/wav",
|
||||
// Archive
|
||||
"zip": "archive/zip",
|
||||
"rar": "archive/rar",
|
||||
"jar": "archive/jar",
|
||||
"iso": "archive/iso",
|
||||
// Text
|
||||
"pdf": "text/pdf",
|
||||
"txt": "text/plain",
|
||||
// Code
|
||||
"c": "code/c",
|
||||
"cpp": "code/cpp",
|
||||
"py": "code/python",
|
||||
"js": "code/javascript",
|
||||
"html": "code/html",
|
||||
"css": "code/css",
|
||||
"md": "markdown/markdown",
|
||||
"json": "code/json",
|
||||
"xml": "code/xml",
|
||||
"csv": "code/csv",
|
||||
// Markdown
|
||||
"md": "markdown/markdown",
|
||||
// Applications
|
||||
"exe": "application/executable",
|
||||
"apk": "application/android",
|
||||
};
|
||||
return extension ? fileTypes[extension] || "unknown" : "unknown";
|
||||
return extension ? fileTypes[extension] ||
|
||||
//get the file type using the mime type library
|
||||
mime.lookup(extension) || "application/octet-stream" : "application/octet-stream";
|
||||
|
||||
};
|
||||
@ -34,8 +34,8 @@
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.cjs",
|
||||
"**/*.js",
|
||||
// "**/*.cjs",
|
||||
// "**/*.js",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user