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": { |       "dependencies": { | ||||||
|         "@auth/prisma-adapter": "^2.7.2", |         "@auth/prisma-adapter": "^2.7.2", | ||||||
|         "@prisma/client": "^6.5.0", |         "@prisma/client": "^6.5.0", | ||||||
|  |         "@prisma/extension-accelerate": "^2.0.0", | ||||||
|         "@t3-oss/env-nextjs": "^0.12.0", |         "@t3-oss/env-nextjs": "^0.12.0", | ||||||
|         "@tailwindcss/typography": "^0.5.16", |         "@tailwindcss/typography": "^0.5.16", | ||||||
|         "@tanstack/react-query": "^5.69.0", |         "@tanstack/react-query": "^5.69.0", | ||||||
|         "@trpc/client": "^11.0.0", |         "@trpc/client": "^11.0.0", | ||||||
|         "@trpc/react-query": "^11.0.0", |         "@trpc/react-query": "^11.0.0", | ||||||
|         "@trpc/server": "^11.0.0", |         "@trpc/server": "^11.0.0", | ||||||
|  |         "cuid": "^3.0.0", | ||||||
|         "dompurify": "^3.2.5", |         "dompurify": "^3.2.5", | ||||||
|  |         "github-markdown-css": "^5.8.1", | ||||||
|  |         "gray-matter": "^4.0.3", | ||||||
|         "mermaid": "^11.6.0", |         "mermaid": "^11.6.0", | ||||||
|         "minio": "^8.0.5", |         "minio": "^8.0.5", | ||||||
|         "next": "^15.2.3", |         "next": "^15.2.3", | ||||||
| @ -27,7 +31,9 @@ | |||||||
|         "react-hot-toast": "^2.5.2", |         "react-hot-toast": "^2.5.2", | ||||||
|         "react-markdown": "^10.1.0", |         "react-markdown": "^10.1.0", | ||||||
|         "rehype-raw": "^7.0.0", |         "rehype-raw": "^7.0.0", | ||||||
|  |         "remark": "^15.0.1", | ||||||
|         "remark-gfm": "^4.0.1", |         "remark-gfm": "^4.0.1", | ||||||
|  |         "remark-html": "^16.0.1", | ||||||
|         "server-only": "^0.0.1", |         "server-only": "^0.0.1", | ||||||
|         "superjson": "^2.2.1", |         "superjson": "^2.2.1", | ||||||
|         "zod": "^3.24.2" |         "zod": "^3.24.2" | ||||||
| @ -36,6 +42,7 @@ | |||||||
|         "@eslint/eslintrc": "^3.3.1", |         "@eslint/eslintrc": "^3.3.1", | ||||||
|         "@tailwindcss/postcss": "^4.0.15", |         "@tailwindcss/postcss": "^4.0.15", | ||||||
|         "@types/busboy": "^1.5.4", |         "@types/busboy": "^1.5.4", | ||||||
|  |         "@types/mime-types": "^2.1.4", | ||||||
|         "@types/node": "^20.14.10", |         "@types/node": "^20.14.10", | ||||||
|         "@types/react": "^19.0.0", |         "@types/react": "^19.0.0", | ||||||
|         "@types/react-dom": "^19.0.0", |         "@types/react-dom": "^19.0.0", | ||||||
| @ -1541,6 +1548,17 @@ | |||||||
|       "devOptional": true, |       "devOptional": true, | ||||||
|       "license": "Apache-2.0" |       "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": { |     "node_modules/@prisma/fetch-engine": { | ||||||
|       "version": "6.6.0", |       "version": "6.6.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.6.0.tgz", |       "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.6.0.tgz", | ||||||
| @ -2301,6 +2319,13 @@ | |||||||
|         "@types/unist": "*" |         "@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": { |     "node_modules/@types/ms": { | ||||||
|       "version": "2.1.0", |       "version": "2.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", |       "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", | ||||||
| @ -3508,6 +3533,13 @@ | |||||||
|       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", |       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", | ||||||
|       "license": "MIT" |       "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": { |     "node_modules/cytoscape": { | ||||||
|       "version": "3.32.0", |       "version": "3.32.0", | ||||||
|       "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.32.0.tgz", |       "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.32.0.tgz", | ||||||
| @ -4883,6 +4915,19 @@ | |||||||
|         "url": "https://opencollective.com/eslint" |         "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": { |     "node_modules/esquery": { | ||||||
|       "version": "1.6.0", |       "version": "1.6.0", | ||||||
|       "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", |       "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", | ||||||
| @ -4957,6 +5002,18 @@ | |||||||
|       "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", |       "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", | ||||||
|       "license": "MIT" |       "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": { |     "node_modules/fast-deep-equal": { | ||||||
|       "version": "3.1.3", |       "version": "3.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", |       "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" |         "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": { |     "node_modules/glob-parent": { | ||||||
|       "version": "6.0.2", |       "version": "6.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", |       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", | ||||||
| @ -5325,6 +5394,43 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT" |       "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": { |     "node_modules/hachure-fill": { | ||||||
|       "version": "0.5.2", |       "version": "0.5.2", | ||||||
|       "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", |       "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", | ||||||
| @ -5479,6 +5585,44 @@ | |||||||
|         "url": "https://opencollective.com/unified" |         "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": { |     "node_modules/hast-util-to-jsx-runtime": { | ||||||
|       "version": "2.3.6", |       "version": "2.3.6", | ||||||
|       "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", |       "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" |         "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": { |     "node_modules/is-extglob": { | ||||||
|       "version": "2.1.1", |       "version": "2.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", | ||||||
|       "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" |       "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": { |     "node_modules/kolorist": { | ||||||
|       "version": "1.8.0", |       "version": "1.8.0", | ||||||
|       "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", |       "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", | ||||||
| @ -8716,6 +8878,22 @@ | |||||||
|         "url": "https://opencollective.com/unified" |         "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": { |     "node_modules/remark-gfm": { | ||||||
|       "version": "4.0.1", |       "version": "4.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", |       "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", | ||||||
| @ -8734,6 +8912,23 @@ | |||||||
|         "url": "https://opencollective.com/unified" |         "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": { |     "node_modules/remark-parse": { | ||||||
|       "version": "11.0.0", |       "version": "11.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", |       "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", | ||||||
| @ -8974,6 +9169,19 @@ | |||||||
|       "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", |       "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", | ||||||
|       "license": "MIT" |       "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": { |     "node_modules/semver": { | ||||||
|       "version": "7.7.1", |       "version": "7.7.1", | ||||||
|       "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", |       "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", | ||||||
| @ -9219,6 +9427,12 @@ | |||||||
|         "node": ">=6" |         "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": { |     "node_modules/stable-hash": { | ||||||
|       "version": "0.0.5", |       "version": "0.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", |       "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", | ||||||
| @ -9404,6 +9618,15 @@ | |||||||
|         "node": ">=4" |         "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": { |     "node_modules/strip-json-comments": { | ||||||
|       "version": "3.1.1", |       "version": "3.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", |       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", | ||||||
|  | |||||||
| @ -23,13 +23,17 @@ | |||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@auth/prisma-adapter": "^2.7.2", |     "@auth/prisma-adapter": "^2.7.2", | ||||||
|     "@prisma/client": "^6.5.0", |     "@prisma/client": "^6.5.0", | ||||||
|  |     "@prisma/extension-accelerate": "^2.0.0", | ||||||
|     "@t3-oss/env-nextjs": "^0.12.0", |     "@t3-oss/env-nextjs": "^0.12.0", | ||||||
|     "@tailwindcss/typography": "^0.5.16", |     "@tailwindcss/typography": "^0.5.16", | ||||||
|     "@tanstack/react-query": "^5.69.0", |     "@tanstack/react-query": "^5.69.0", | ||||||
|     "@trpc/client": "^11.0.0", |     "@trpc/client": "^11.0.0", | ||||||
|     "@trpc/react-query": "^11.0.0", |     "@trpc/react-query": "^11.0.0", | ||||||
|     "@trpc/server": "^11.0.0", |     "@trpc/server": "^11.0.0", | ||||||
|  |     "cuid": "^3.0.0", | ||||||
|     "dompurify": "^3.2.5", |     "dompurify": "^3.2.5", | ||||||
|  |     "github-markdown-css": "^5.8.1", | ||||||
|  |     "gray-matter": "^4.0.3", | ||||||
|     "mermaid": "^11.6.0", |     "mermaid": "^11.6.0", | ||||||
|     "minio": "^8.0.5", |     "minio": "^8.0.5", | ||||||
|     "next": "^15.2.3", |     "next": "^15.2.3", | ||||||
| @ -39,7 +43,9 @@ | |||||||
|     "react-hot-toast": "^2.5.2", |     "react-hot-toast": "^2.5.2", | ||||||
|     "react-markdown": "^10.1.0", |     "react-markdown": "^10.1.0", | ||||||
|     "rehype-raw": "^7.0.0", |     "rehype-raw": "^7.0.0", | ||||||
|  |     "remark": "^15.0.1", | ||||||
|     "remark-gfm": "^4.0.1", |     "remark-gfm": "^4.0.1", | ||||||
|  |     "remark-html": "^16.0.1", | ||||||
|     "server-only": "^0.0.1", |     "server-only": "^0.0.1", | ||||||
|     "superjson": "^2.2.1", |     "superjson": "^2.2.1", | ||||||
|     "zod": "^3.24.2" |     "zod": "^3.24.2" | ||||||
| @ -48,6 +54,7 @@ | |||||||
|     "@eslint/eslintrc": "^3.3.1", |     "@eslint/eslintrc": "^3.3.1", | ||||||
|     "@tailwindcss/postcss": "^4.0.15", |     "@tailwindcss/postcss": "^4.0.15", | ||||||
|     "@types/busboy": "^1.5.4", |     "@types/busboy": "^1.5.4", | ||||||
|  |     "@types/mime-types": "^2.1.4", | ||||||
|     "@types/node": "^20.14.10", |     "@types/node": "^20.14.10", | ||||||
|     "@types/react": "^19.0.0", |     "@types/react": "^19.0.0", | ||||||
|     "@types/react-dom": "^19.0.0", |     "@types/react-dom": "^19.0.0", | ||||||
|  | |||||||
| @ -4,10 +4,11 @@ | |||||||
| generator client { | generator client { | ||||||
|     provider = "prisma-client-js" |     provider = "prisma-client-js" | ||||||
|     binaryTargets = ["native", "debian-openssl-3.0.x"] |     binaryTargets = ["native", "debian-openssl-3.0.x"] | ||||||
|  |     output   = "/app/generated/prisma-client" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| datasource db { | datasource db { | ||||||
|     provider = "mysql" |     provider = "postgresql" | ||||||
|     // NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below |     // NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below | ||||||
|     // Further reading: |     // Further reading: | ||||||
|     // https://next-auth.js.org/adapters/prisma#create-the-prisma-schema |     // https://next-auth.js.org/adapters/prisma#create-the-prisma-schema | ||||||
| @ -23,7 +24,7 @@ model Account { | |||||||
|     type                     String |     type                     String | ||||||
|     provider                 String |     provider                 String | ||||||
|     providerAccountId        String |     providerAccountId        String | ||||||
|     refresh_token            String? @db.Text |     refresh_token            String? //@db.Text | ||||||
|     access_token             String? // @db.Text |     access_token             String? // @db.Text | ||||||
|     expires_at               Int? |     expires_at               Int? | ||||||
|     token_type               String? |     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); |           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" /> |         <img src="/icons/delete.svg" alt="Remove" className="h-6 w-6" /> | ||||||
|       </button> |       </button> | ||||||
|  | |||||||
| @ -1,13 +1,11 @@ | |||||||
| "use client"; | "use client"; | ||||||
| 
 | 
 | ||||||
| import { useEffect, useState } from "react"; | import { useEffect, useState } from "react"; | ||||||
| import toast from "react-hot-toast"; |  | ||||||
| import { useRouter } from "next/navigation"; | import { useRouter } from "next/navigation"; | ||||||
| import { env } from "~/env.js"; | import { env } from "~/env.js"; | ||||||
| import { FilePreview } from "~/app/_components/FilePreview"; | import { FilePreview } from "~/app/_components/FilePreview"; | ||||||
| import { useFileActions } from "~/app/_components/FileActions"; | import { useFileActions } from "~/app/_components/FileActions"; | ||||||
| import { FileActionsContainer } from "./ActionButtons"; | import { FileActionsContainer } from "./ActionButtons"; | ||||||
| import { checkOwner } from "~/utils/checkOwner"; // Import the client component
 |  | ||||||
| 
 | 
 | ||||||
| interface FileDetails { | interface FileDetails { | ||||||
|   id: string; |   id: string; | ||||||
| @ -73,13 +71,15 @@ export default function FileGrid({ session }: FileGridProps) { | |||||||
| 
 | 
 | ||||||
|     const eventSource = new EventSource("/api/files/stream"); |     const eventSource = new EventSource("/api/files/stream"); | ||||||
|     eventSource.onmessage = (event) => { |     eventSource.onmessage = (event) => { | ||||||
|       const data: { type: string; file?: FileDetails; fileId?: string } = JSON.parse(event.data); |       const data: { type: string; fileId?: string } = JSON.parse(event.data); | ||||||
| 
 |       console.log("SSE event:", data); | ||||||
|       if (data.type === "file-added" && data.file) { |       if (data.type === "file-added" && data.fileId) { | ||||||
|         setFiles((prevFiles) => (data.file ? [...prevFiles, data.file] : prevFiles)); |         fetchFiles(); | ||||||
|         toast.success(`File "${data.file.name}" added!`); |       } else if (data.type === "file-updated" && data.fileId) { | ||||||
|  |         // Fetch the updated file details
 | ||||||
|  |         fetchFiles(); | ||||||
|       } else if (data.type === "file-removed" && data.fileId) { |       } 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} |             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" |             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)}> |             <button onClick={() => router.push(pageUrl + file.url)}> | ||||||
|               <h3 className="text-2xl font-bold">{file.name}</h3> |               <h3 className="text-2xl font-bold">{file.name}</h3> | ||||||
|  | |||||||
| @ -1,16 +1,22 @@ | |||||||
| "use client"; | "use client"; | ||||||
| 
 | 
 | ||||||
| import { useEffect, useState } from "react"; | 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 { | interface FilePreviewProps { | ||||||
|   fileId: string; |   fileId: string; | ||||||
|   fileType: string; // Pass the file type as a prop
 |   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 [mediaSrc, setMediaSrc] = useState<string | null>(null); | ||||||
|   const [error, setError] = useState<string | null>(null); |   const [error, setError] = useState<string | null>(null); | ||||||
|  |   const [markdownContent, setMarkdownContent] = useState<string | null>(null); | ||||||
| 
 | 
 | ||||||
|   console.log("File Type:", fileType); |   console.log("File Type:", fileType); | ||||||
| 
 | 
 | ||||||
| @ -47,20 +53,53 @@ export function FilePreview({ fileId, fileType }: FilePreviewProps) { | |||||||
|     }; |     }; | ||||||
|   }, [fileId]); |   }, [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) { |   if (error) { | ||||||
|     return <div className="text-red-500">{error}</div>; |     return <div className="text-red-500">{error}</div>; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (!mediaSrc) { |   if (!mediaSrc && !markdownContent) { | ||||||
|     return <div>Loading...</div>; |     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")) { |   if (fileType.startsWith("video")) { | ||||||
|     return ( |     return ( | ||||||
|       <video |       <video | ||||||
|         controls |         controls | ||||||
|         className="max-w-full max-h-96 rounded-lg shadow-md" |         className="max-w-full max-h-96 rounded-lg shadow-md" | ||||||
|         src={mediaSrc} |         src={mediaSrc || ""} | ||||||
|       > |       > | ||||||
|         Your browser does not support the video tag. |         Your browser does not support the video tag. | ||||||
|       </video> |       </video> | ||||||
| @ -71,14 +110,14 @@ export function FilePreview({ fileId, fileType }: FilePreviewProps) { | |||||||
|       <audio |       <audio | ||||||
|         controls |         controls | ||||||
|         className="max-w-full max-h-96 rounded-lg shadow-md" |         className="max-w-full max-h-96 rounded-lg shadow-md" | ||||||
|         src={mediaSrc} |         src={mediaSrc || ""} | ||||||
|       > |       > | ||||||
|         Your browser does not support the audio tag. |         Your browser does not support the audio tag. | ||||||
|       </audio> |       </audio> | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   if (fileType.startsWith("image")) { |   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")) { |   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" /> |       <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 ( |     return ( | ||||||
|       <img src="/icons/files/code.svg" alt="Code file preview" className="max-w-full max-h-96 rounded-lg invert" /> |       <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); |   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 [uploadedFileUrl, setUploadedFileUrl] = useState<string | null>(null); | ||||||
|   const [progress, setProgress] = useState<number>(0); // Track upload progress
 |   const [progress, setProgress] = useState<number>(0); // Track upload progress
 | ||||||
|   const fileInputRef = useRef<HTMLInputElement | null>(null); // Ref for the file input
 |   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>) => { |   const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||||||
|     if (e.target.files) { |     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 () => { |   const handleUpload = async () => { | ||||||
|     if (!file) return toast.error("Please select a file to upload."); |     if (!file) return toast.error("Please select a file to upload."); | ||||||
|     setUploading(true); |     setUploading(true); | ||||||
| @ -41,15 +70,14 @@ export default function UploadForm() { | |||||||
| 
 | 
 | ||||||
|       xhr.onload = () => { |       xhr.onload = () => { | ||||||
|         if (xhr.status === 200) { |         if (xhr.status === 200) { | ||||||
|           const response: { url: string } = JSON.parse(xhr.responseText); // Explicitly type the response
 |           const response = JSON.parse(xhr.responseText); | ||||||
|           setUploadedFileUrl(response.url); // Assume the API returns the uploaded file URL
 |           setUploadedFileUrl(response.file?.url || null); // Use the new response structure
 | ||||||
|           notifyClients({type: "file-uploaded", fileUrl: response.url}); // Notify other clients about the new file
 |  | ||||||
|           toast.success("File uploaded successfully!"); |           toast.success("File uploaded successfully!"); | ||||||
| 
 | 
 | ||||||
|           // Clear the file input and reset state
 |           // Clear the file input and reset state
 | ||||||
|           setFile(null); |           setFile(null); | ||||||
|           if (fileInputRef.current) { |           if (fileInputRef.current) { | ||||||
|             fileInputRef.current.value = ""; // Clear the file input
 |             fileInputRef.current.value = ""; | ||||||
|           } |           } | ||||||
|         } else { |         } else { | ||||||
|           console.error("Upload failed:", xhr.responseText); |           console.error("Upload failed:", xhr.responseText); | ||||||
| @ -86,42 +114,48 @@ export default function UploadForm() { | |||||||
|       {/* Toast container */} |       {/* Toast container */} | ||||||
|       <Toaster position="top-right" reverseOrder={false} /> |       <Toaster position="top-right" reverseOrder={false} /> | ||||||
| 
 | 
 | ||||||
|       <div className="flex flex-row items-center gap-4"> |       {/* Drag and Drop Area */} | ||||||
|         {/* Custom file input */} |       <div | ||||||
|         <label |         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"}`} | ||||||
|           htmlFor="file-upload" |         onDragOver={handleDragOver} | ||||||
|           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" |         onDragLeave={handleDragLeave} | ||||||
|         > |         onDrop={handleDrop} | ||||||
|           {file ? ( |         onClick={() => fileInputRef.current?.click()} | ||||||
|             <> |         style={{ cursor: "pointer" }} | ||||||
|               File Selected |       > | ||||||
|               {/* SVG Icon */} |         {/* Hidden file input for click-to-select */} | ||||||
|               <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> |  | ||||||
|         <input |         <input | ||||||
|           id="file-upload" |  | ||||||
|           ref={fileInputRef} // Attach the ref to the file input
 |  | ||||||
|           type="file" |           type="file" | ||||||
|  |           ref={fileInputRef} | ||||||
|  |           style={{ display: "none" }} | ||||||
|           onChange={handleFileChange} |           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 |         <button | ||||||
|           onClick={handleUpload} |           onClick={handleUpload} | ||||||
|           disabled={uploading || !file} |           disabled={uploading || !file} | ||||||
| @ -129,7 +163,7 @@ export default function UploadForm() { | |||||||
|         > |         > | ||||||
|           {uploading ? "Uploading..." : "Upload"} |           {uploading ? "Uploading..." : "Upload"} | ||||||
|         </button> |         </button> | ||||||
|       </div> |       </div>)} | ||||||
| 
 | 
 | ||||||
|       {file && uploading && ( |       {file && uploading && ( | ||||||
|         <div className="w-full max-w-md flex items-center gap-2"> |         <div className="w-full max-w-md flex items-center gap-2"> | ||||||
| @ -142,31 +176,17 @@ export default function UploadForm() { | |||||||
|         </div> |         </div> | ||||||
|       )} |       )} | ||||||
| 
 | 
 | ||||||
|       {uploadedFileUrl && ( |       {/* {uploadedFileUrl && file && ( | ||||||
|         <div className="flex flex-row items-center gap-4"> |         <div className="flex flex-row items-center gap-4"> | ||||||
|           <p className="text-white">{uploadedFileUrl}</p> |           <p className="text-white">{file.name}</p> | ||||||
|           <button |           <button | ||||||
|             onClick={handleCopyUrl} |             onClick={handleCopyUrl} | ||||||
|             className="flex items-center justify-center rounded-full bg-blue-500 p-2 hover:bg-blue-600" |             className="flex items-center justify-center rounded-full bg-blue-500 p-2 hover:bg-blue-600" | ||||||
|           > |           > | ||||||
|             {/* Copy Icon */} |             <img src="/icons/copy.svg" alt="Copy URL" className="h-6 w-6" /> | ||||||
|             <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> |  | ||||||
|           </button> |           </button> | ||||||
|         </div> |         </div> | ||||||
|       )} |       )} */} | ||||||
|     </div> |     </div> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
| @ -1,10 +1,12 @@ | |||||||
| import { NextResponse } from "next/server"; | import { NextResponse } from "next/server"; | ||||||
| import Busboy from "busboy"; | import Busboy from "busboy"; | ||||||
| import { Readable } from "stream"; | import { Readable } from "stream"; | ||||||
| import crypto from "crypto"; |  | ||||||
| import { db } from "~/server/db"; | import { db } from "~/server/db"; | ||||||
| import { auth } from "~/server/auth"; | import { auth } from "~/server/auth"; | ||||||
| import { minioClient, ensureBucketExists } from "~/utils/minioClient"; | import { minioClient, ensureBucketExists } from "~/utils/minioClient"; | ||||||
|  | import { getFileType } from "~/utils/fileType"; | ||||||
|  | import cuid from 'cuid'; | ||||||
|  | import { notifyClients } from "~/utils/notifyClients"; | ||||||
| 
 | 
 | ||||||
| export const config = { | export const config = { | ||||||
|   api: { |   api: { | ||||||
| @ -22,7 +24,9 @@ export async function POST(req: Request) { | |||||||
|   await ensureBucketExists(bucketName); |   await ensureBucketExists(bucketName); | ||||||
| 
 | 
 | ||||||
|   return new Promise<Response>((resolve, reject) => { |   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 fileName = ""; | ||||||
|     let fileBuffer = Buffer.alloc(0); |     let fileBuffer = Buffer.alloc(0); | ||||||
| 
 | 
 | ||||||
| @ -38,8 +42,11 @@ export async function POST(req: Request) { | |||||||
|         fileBuffer = Buffer.concat(chunks); |         fileBuffer = Buffer.concat(chunks); | ||||||
| 
 | 
 | ||||||
|         // Generate a unique ID for the file
 |         // Generate a unique ID for the file
 | ||||||
|         const fileId = crypto.randomUUID(); |         const fileId = session.user.id + "-" + cuid() | ||||||
|         const objectName = `${fileId}-${fileName}`; |         const objectName = `${fileId}-${fileName}`; | ||||||
|  |         // Change UUID to CUID
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|           // Upload the file to MinIO
 |           // Upload the file to MinIO
 | ||||||
| @ -52,12 +59,19 @@ export async function POST(req: Request) { | |||||||
|               url: `/share?id=${fileId}`, |               url: `/share?id=${fileId}`, | ||||||
|               name: fileName, |               name: fileName, | ||||||
|               size: fileBuffer.length, |               size: fileBuffer.length, | ||||||
|               extension: info.mimeType, |               extension: getFileType(fileName), | ||||||
|               uploadedById: session.user.id, |               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) { |         } catch (error) { | ||||||
|           console.error("Error uploading file to MinIO:", error); |           console.error("Error uploading file to MinIO:", error); | ||||||
|           reject(new Error("Failed to upload file")); |           reject(new Error("Failed to upload file")); | ||||||
|  | |||||||
							
								
								
									
										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 Link from "next/link"; | ||||||
| import { auth } from "~/server/auth"; | import { useEffect, useState } from "react"; | ||||||
| import { HydrateClient } from "~/trpc/server"; |  | ||||||
| import FileGrid from "~/app/_components/FileGrid"; | import FileGrid from "~/app/_components/FileGrid"; | ||||||
| import UploadForm from "~/app/_components/UploadForm"; | import UploadForm from "~/app/_components/UploadForm"; | ||||||
| import { Toaster } from "react-hot-toast"; | import { Toaster } from "react-hot-toast"; | ||||||
|  | import { Suspense } from "react"; | ||||||
|  | import LoadingSkeleton from "./LoadingSkeleton"; | ||||||
| 
 | 
 | ||||||
| export default async function Home() { | // Custom fallback for FileGrid
 | ||||||
|   const session = await auth(); | 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 ( |   return ( | ||||||
|     <HydrateClient> |     <> | ||||||
|       <Toaster position="top-right" reverseOrder={false} /> |       <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"> |       <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 */} |         {/* 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 */} |           {/* Conditionally render FileGrid and UploadForm if the user is logged in */} | ||||||
|           {session?.user ? ( |           {session?.user ? ( | ||||||
|             <> |             <> | ||||||
|               <FileGrid session={session} /> |               <Suspense fallback={<FileGridFallback />}> | ||||||
|               <UploadForm /> |                 <FileGrid session={session as { user: { id: string } }} /> | ||||||
|  |               </Suspense> | ||||||
|  |               <Suspense fallback={<UploadFormFallback />}> | ||||||
|  |                 <UploadForm /> | ||||||
|  |               </Suspense> | ||||||
|             </> |             </> | ||||||
|           ) : ( |           ) : !loading ? ( | ||||||
|             <p className="text-center text-2xl text-white"> |             <p className="text-center text-2xl text-white"> | ||||||
|               Please log in to upload and view files. |               Please log in to upload and view files. | ||||||
|             </p> |             </p> | ||||||
|           )} |           ) : null} | ||||||
|           {!session?.user && ( |           {!session?.user && ( | ||||||
|             <div className="flex flex-col items-center gap-2"> |             <div className="flex flex-col items-center gap-2"> | ||||||
|               <div className="flex flex-col items-center justify-center gap-4"> |               <div className="flex flex-col items-center justify-center gap-4"> | ||||||
|                 <Link |                 {!loading ? ( | ||||||
|                   href={session ? "/api/auth/signout" : "/api/auth/signin"} |                   <Link | ||||||
|                   className="rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20" |                     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> |                     {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> |             </div> | ||||||
|           )} |           )} | ||||||
|         </div> |         </div> | ||||||
|       </main> |       </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" |                 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"> |                 <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> |                 </div> | ||||||
| 
 | 
 | ||||||
|                 <button onClick={() => router.push(pageUrl + file.url)}> |                 <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 { notFound } from "next/navigation"; | ||||||
|  | import { Suspense } from "react"; | ||||||
| import { FilePreview } from "~/app/_components/FilePreview"; | import { FilePreview } from "~/app/_components/FilePreview"; | ||||||
| import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
 | import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
 | ||||||
| import { Toaster } from "react-hot-toast"; | import { Toaster } from "react-hot-toast"; | ||||||
| @ -129,7 +130,9 @@ export default async function FilePreviewContainer({ | |||||||
|         </h1> |         </h1> | ||||||
|         <div className="mt-6"> |         <div className="mt-6"> | ||||||
|           {fileDetails.type !== "unknown" && ( |           {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> | ||||||
|         <div className="w-full max-w-md rounded-lg bg-white/10 p-6 text-white shadow-md"> |         <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> | ||||||
|           <p> |           <p> | ||||||
|             <strong>Owner:</strong>{" "} |             <strong>Owner:</strong>{" "} | ||||||
|             <img |             <Suspense fallback={<div className="text-white">Loading...</div>}> | ||||||
|  |               <img | ||||||
|               className="inline size-5 rounded-md" |               className="inline size-5 rounded-md" | ||||||
|               src={fileDetails.ownerAvatar || ""} |               src={fileDetails.ownerAvatar || ""} | ||||||
|               alt="Owner avatar" |               alt="Owner avatar" | ||||||
|             />{" "} |               />{" "} | ||||||
|             {fileDetails.owner} |             {fileDetails.owner} | ||||||
|  |             </Suspense> | ||||||
|           </p> |           </p> | ||||||
|           <p> |           <p> | ||||||
|             <strong>Upload Date:</strong>{" "} |             <strong>Upload Date:</strong>{" "} | ||||||
|             {new Date(fileDetails.uploadDate).toLocaleString()} |             <Suspense fallback={<div className="text-white">Loading...</div>}> | ||||||
|  |               {new Date(fileDetails.uploadDate).toLocaleString()} | ||||||
|  |             </Suspense> | ||||||
|           </p> |           </p> | ||||||
|           <div> |           <div> | ||||||
|             <strong>Description:</strong>{" "} |             <strong>Description:</strong>{" "} | ||||||
|             <FileDescriptionContainer |             <Suspense fallback={<div className="text-white">Loading...</div>}> | ||||||
|               fileId={fileDetails.id} |               <FileDescriptionContainer | ||||||
|               fileDescription={fileDetails.description} |                 fileId={fileDetails.id} | ||||||
|             /> |                 fileDescription={fileDetails.description} | ||||||
|  |               /> | ||||||
|  |             </Suspense> | ||||||
|           </div> |           </div> | ||||||
|           <div className="mt-4 flex justify-center"> |           <div className="mt-4 flex justify-center"> | ||||||
|             <FileActionsContainer |             <Suspense fallback={<div className="text-white">Loading...</div>}> | ||||||
|               fileId={fileDetails.id} |               <FileActionsContainer | ||||||
|               fileName={fileDetails.name} |                 fileId={fileDetails.id} | ||||||
|               fileUrl={fileDetails.url} |                 fileName={fileDetails.name} | ||||||
|               isOwner={session?.user?.id ? await checkOwner(fileDetails.ownerId, session.user.id) : false} |                 fileUrl={fileDetails.url} | ||||||
|               isPublic={fileDetails.isPublic} |                 isOwner={session?.user?.id ? await checkOwner(fileDetails.ownerId, session.user.id) : false} | ||||||
|             /> |                 isPublic={fileDetails.isPublic} | ||||||
|  |               /> | ||||||
|  |             </Suspense> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </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"; | import { env } from "~/env"; | ||||||
| 
 | 
 | ||||||
| @ -6,7 +7,7 @@ const createPrismaClient = () => | |||||||
|   new PrismaClient({ |   new PrismaClient({ | ||||||
|     log: |     log: | ||||||
|       env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], |       env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], | ||||||
|   }); |   }).$extends(withAccelerate()); | ||||||
| 
 | 
 | ||||||
| const globalForPrisma = globalThis as unknown as { | const globalForPrisma = globalThis as unknown as { | ||||||
|   prisma: ReturnType<typeof createPrismaClient> | undefined; |   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.
 | // 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 { | export function getFileType(fileName: string): string { | ||||||
|     const extension = fileName.split(".").pop()?.toLowerCase(); |     const extension = fileName.split(".").pop()?.toLowerCase(); | ||||||
|     const fileTypes: Record<string, string> = { |     const fileTypes: Record<string, string> = { | ||||||
|  |         // Video
 | ||||||
|         "mp4": "video/mp4", |         "mp4": "video/mp4", | ||||||
|         "webm": "video/webm", |         "webm": "video/webm", | ||||||
|         "ogg": "video/ogg", |         "ogg": "video/ogg", | ||||||
|  |         // Image
 | ||||||
|         "jpg": "image/jpeg", |         "jpg": "image/jpeg", | ||||||
|         "jpeg": "image/jpeg", |         "jpeg": "image/jpeg", | ||||||
|         "png": "image/png", |         "png": "image/png", | ||||||
|         "gif": "image/gif", |         "gif": "image/gif", | ||||||
|         "svg": "image/svg+xml", |         "svg": "image/svg+xml", | ||||||
|  |         // Audio
 | ||||||
|         "mp3": "audio/mpeg", |         "mp3": "audio/mpeg", | ||||||
|         "wav": "audio/wav", |         "wav": "audio/wav", | ||||||
|  |         // Archive
 | ||||||
|         "zip": "archive/zip", |         "zip": "archive/zip", | ||||||
|         "rar": "archive/rar", |         "rar": "archive/rar", | ||||||
|  |         "jar": "archive/jar", | ||||||
|  |         "iso": "archive/iso", | ||||||
|  |         // Text
 | ||||||
|         "pdf": "text/pdf", |         "pdf": "text/pdf", | ||||||
|         "txt": "text/plain", |         "txt": "text/plain", | ||||||
|  |         // Code
 | ||||||
|         "c": "code/c", |         "c": "code/c", | ||||||
|         "cpp": "code/cpp", |         "cpp": "code/cpp", | ||||||
|         "py": "code/python", |         "py": "code/python", | ||||||
|         "js": "code/javascript", |         "js": "code/javascript", | ||||||
|         "html": "code/html", |         "html": "code/html", | ||||||
|         "css": "code/css", |         "css": "code/css", | ||||||
|         "md": "markdown/markdown", |  | ||||||
|         "json": "code/json", |         "json": "code/json", | ||||||
|         "xml": "code/xml", |         "xml": "code/xml", | ||||||
|         "csv": "code/csv", |         "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", |     "next-env.d.ts", | ||||||
|     "**/*.ts", |     "**/*.ts", | ||||||
|     "**/*.tsx", |     "**/*.tsx", | ||||||
|     "**/*.cjs", |     // "**/*.cjs", | ||||||
|     "**/*.js", |     // "**/*.js", | ||||||
|     ".next/types/**/*.ts" |     ".next/types/**/*.ts" | ||||||
|   ], |   ], | ||||||
|   "exclude": ["node_modules"] |   "exclude": ["node_modules"] | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user