projects
This commit is contained in:
210
package-lock.json
generated
210
package-lock.json
generated
@@ -12,9 +12,11 @@
|
|||||||
"@react-three/fiber": "^9.3.0",
|
"@react-three/fiber": "^9.3.0",
|
||||||
"@react-three/postprocessing": "^3.0.4",
|
"@react-three/postprocessing": "^3.0.4",
|
||||||
"framer-motion": "^12.23.24",
|
"framer-motion": "^12.23.24",
|
||||||
|
"mongoose": "^8.19.1",
|
||||||
"next": "15.5.4",
|
"next": "15.5.4",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
"react-typed": "^2.0.12"
|
"react-typed": "^2.0.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -783,6 +785,15 @@
|
|||||||
"integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==",
|
"integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/@mongodb-js/saslprep": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-QgA5AySqB27cGTXBFmnpifAi7HxoGUeezwo6p9dI03MuDB6Pp33zgclqVb6oVK3j6I9Vesg0+oojW2XxB59SGg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"sparse-bitfield": "^3.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@monogrid/gainmap-js": {
|
"node_modules/@monogrid/gainmap-js": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz",
|
||||||
@@ -1530,12 +1541,27 @@
|
|||||||
"meshoptimizer": "~0.22.0"
|
"meshoptimizer": "~0.22.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/webidl-conversions": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/webxr": {
|
"node_modules/@types/webxr": {
|
||||||
"version": "0.5.24",
|
"version": "0.5.24",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz",
|
||||||
"integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==",
|
"integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/whatwg-url": {
|
||||||
|
"version": "11.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
|
||||||
|
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/webidl-conversions": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz",
|
||||||
@@ -2463,6 +2489,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bson": {
|
||||||
|
"version": "6.10.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz",
|
||||||
|
"integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.20.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/buffer": {
|
"node_modules/buffer": {
|
||||||
"version": "6.0.3",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||||
@@ -2743,7 +2778,6 @@
|
|||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "^2.1.3"
|
"ms": "^2.1.3"
|
||||||
@@ -4579,6 +4613,15 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/kareem": {
|
||||||
|
"version": "2.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
|
||||||
|
"integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
@@ -4937,6 +4980,12 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/memory-pager": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/merge2": {
|
"node_modules/merge2": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||||
@@ -5022,6 +5071,84 @@
|
|||||||
"node": ">= 18"
|
"node": ">= 18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mongodb": {
|
||||||
|
"version": "6.20.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz",
|
||||||
|
"integrity": "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@mongodb-js/saslprep": "^1.3.0",
|
||||||
|
"bson": "^6.10.4",
|
||||||
|
"mongodb-connection-string-url": "^3.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.20.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@aws-sdk/credential-providers": "^3.188.0",
|
||||||
|
"@mongodb-js/zstd": "^1.1.0 || ^2.0.0",
|
||||||
|
"gcp-metadata": "^5.2.0",
|
||||||
|
"kerberos": "^2.0.1",
|
||||||
|
"mongodb-client-encryption": ">=6.0.0 <7",
|
||||||
|
"snappy": "^7.3.2",
|
||||||
|
"socks": "^2.7.1"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@aws-sdk/credential-providers": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@mongodb-js/zstd": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"gcp-metadata": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"kerberos": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"mongodb-client-encryption": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"snappy": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"socks": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mongodb-connection-string-url": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/whatwg-url": "^11.0.2",
|
||||||
|
"whatwg-url": "^14.1.0 || ^13.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mongoose": {
|
||||||
|
"version": "8.19.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.19.1.tgz",
|
||||||
|
"integrity": "sha512-oB7hGQJn4f8aebqE7mhE54EReb5cxVgpCxQCQj0K/cK3q4J3Tg08nFP6sM52nJ4Hlm8jsDnhVYpqIITZUAhckQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bson": "^6.10.4",
|
||||||
|
"kareem": "2.6.3",
|
||||||
|
"mongodb": "~6.20.0",
|
||||||
|
"mpath": "0.9.0",
|
||||||
|
"mquery": "5.0.0",
|
||||||
|
"ms": "2.1.3",
|
||||||
|
"sift": "17.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.20.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mongoose"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/motion-dom": {
|
"node_modules/motion-dom": {
|
||||||
"version": "12.23.23",
|
"version": "12.23.23",
|
||||||
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
|
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
|
||||||
@@ -5037,11 +5164,31 @@
|
|||||||
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
|
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/mpath": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mquery": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "4.x"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/n8ao": {
|
"node_modules/n8ao": {
|
||||||
@@ -5514,7 +5661,6 @@
|
|||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -5562,6 +5708,15 @@
|
|||||||
"react": "^19.1.0"
|
"react": "^19.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-icons": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
@@ -6009,6 +6164,12 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sift": {
|
||||||
|
"version": "17.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
|
||||||
|
"integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
@@ -6018,6 +6179,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sparse-bitfield": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"memory-pager": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"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",
|
||||||
@@ -6397,6 +6567,18 @@
|
|||||||
"node": ">=8.0"
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"punycode": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/troika-three-text": {
|
"node_modules/troika-three-text": {
|
||||||
"version": "0.52.4",
|
"version": "0.52.4",
|
||||||
"resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz",
|
||||||
@@ -6707,6 +6889,28 @@
|
|||||||
"integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==",
|
"integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "14.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
|
||||||
|
"integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "^5.1.0",
|
||||||
|
"webidl-conversions": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
"@react-three/fiber": "^9.3.0",
|
"@react-three/fiber": "^9.3.0",
|
||||||
"@react-three/postprocessing": "^3.0.4",
|
"@react-three/postprocessing": "^3.0.4",
|
||||||
"framer-motion": "^12.23.24",
|
"framer-motion": "^12.23.24",
|
||||||
|
"mongoose": "^8.19.1",
|
||||||
"next": "15.5.4",
|
"next": "15.5.4",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
"react-typed": "^2.0.12"
|
"react-typed": "^2.0.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
BIN
public/ai.jpg
Normal file
BIN
public/ai.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 709 KiB |
BIN
public/clg.jpg
Normal file
BIN
public/clg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 674 KiB |
41
src/app/api/projects/route.js
Normal file
41
src/app/api/projects/route.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import connectToDatabase from "../../../lib/db";
|
||||||
|
import Project from "../../../models/Projects";
|
||||||
|
|
||||||
|
// 🟢 Create new project
|
||||||
|
export async function POST(req) {
|
||||||
|
try {
|
||||||
|
const { name, techStack, description, githubLink, deployedLink } = await req.json();
|
||||||
|
|
||||||
|
await connectToDatabase();
|
||||||
|
|
||||||
|
const newProject = new Project({
|
||||||
|
name,
|
||||||
|
techStack,
|
||||||
|
description,
|
||||||
|
githubLink,
|
||||||
|
deployedLink,
|
||||||
|
});
|
||||||
|
|
||||||
|
await newProject.save();
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ message: "Project added successfully!" }),
|
||||||
|
{ status: 201 }
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(" Error saving project:", error);
|
||||||
|
return new Response(JSON.stringify({ error: error.message }), { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔵 Fetch all projects
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
await connectToDatabase();
|
||||||
|
const projects = await Project.find({});
|
||||||
|
return new Response(JSON.stringify(projects), { status: 200 });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(" Error fetching projects:", error);
|
||||||
|
return new Response(JSON.stringify({ error: error.message }), { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,8 @@ const ANIMATIONS = {
|
|||||||
|
|
||||||
export default function Navbar() {
|
export default function Navbar() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [showDropdown, setShowDropdown] = useState(false);
|
const [showDropdownResources, setShowDropdownResources] = useState(false);
|
||||||
|
const [showDropdownProjects, setShowDropdownProjects] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onKey = (e) => e.key === "Escape" && setIsOpen(false);
|
const onKey = (e) => e.key === "Escape" && setIsOpen(false);
|
||||||
@@ -46,8 +47,8 @@ export default function Navbar() {
|
|||||||
|
|
||||||
const mainLinks = [
|
const mainLinks = [
|
||||||
"Home",
|
"Home",
|
||||||
"Events",
|
|
||||||
"Projects",
|
"Projects",
|
||||||
|
"Events",
|
||||||
"Team",
|
"Team",
|
||||||
"Resources",
|
"Resources",
|
||||||
"Contact",
|
"Contact",
|
||||||
@@ -119,7 +120,6 @@ export default function Navbar() {
|
|||||||
variants={ANIMATIONS.menuItem}
|
variants={ANIMATIONS.menuItem}
|
||||||
className="flex flex-col items-start w-full"
|
className="flex flex-col items-start w-full"
|
||||||
>
|
>
|
||||||
{/* Title */}
|
|
||||||
<motion.span
|
<motion.span
|
||||||
className="text-xl text-white font-semibold mb-2"
|
className="text-xl text-white font-semibold mb-2"
|
||||||
variants={ANIMATIONS.menuItem}
|
variants={ANIMATIONS.menuItem}
|
||||||
@@ -127,7 +127,6 @@ export default function Navbar() {
|
|||||||
Resources
|
Resources
|
||||||
</motion.span>
|
</motion.span>
|
||||||
|
|
||||||
{/* Subsections with vertical blue line */}
|
|
||||||
<motion.div
|
<motion.div
|
||||||
className="flex flex-col items-start gap-2 border-l-2 border-blue-500 pl-4"
|
className="flex flex-col items-start gap-2 border-l-2 border-blue-500 pl-4"
|
||||||
variants={ANIMATIONS.menuItem}
|
variants={ANIMATIONS.menuItem}
|
||||||
@@ -136,6 +135,7 @@ export default function Navbar() {
|
|||||||
href="/onlineresources"
|
href="/onlineresources"
|
||||||
className="text-white text-base hover:text-blue-300"
|
className="text-white text-base hover:text-blue-300"
|
||||||
variants={ANIMATIONS.menuItem}
|
variants={ANIMATIONS.menuItem}
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
>
|
>
|
||||||
Online Resources
|
Online Resources
|
||||||
</motion.a>
|
</motion.a>
|
||||||
@@ -143,6 +143,7 @@ export default function Navbar() {
|
|||||||
href="/books"
|
href="/books"
|
||||||
className="text-white text-base hover:text-blue-300"
|
className="text-white text-base hover:text-blue-300"
|
||||||
variants={ANIMATIONS.menuItem}
|
variants={ANIMATIONS.menuItem}
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
>
|
>
|
||||||
Books
|
Books
|
||||||
</motion.a>
|
</motion.a>
|
||||||
@@ -151,6 +152,45 @@ export default function Navbar() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item === "Projects") {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key="projects"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
className="flex flex-col items-start w-full"
|
||||||
|
>
|
||||||
|
<motion.span
|
||||||
|
className="text-xl text-white font-semibold mb-2"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
>
|
||||||
|
Projects
|
||||||
|
</motion.span>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
className="flex flex-col items-start gap-2 border-l-2 border-blue-500 pl-4"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
>
|
||||||
|
<motion.a
|
||||||
|
href="/upload"
|
||||||
|
className="text-white text-base hover:text-blue-300"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
>
|
||||||
|
Upload Projects
|
||||||
|
</motion.a>
|
||||||
|
<motion.a
|
||||||
|
href="/projects"
|
||||||
|
className="text-white text-base hover:text-blue-300"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
>
|
||||||
|
View Projects
|
||||||
|
</motion.a>
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.a
|
<motion.a
|
||||||
key={item}
|
key={item}
|
||||||
@@ -228,27 +268,71 @@ export default function Navbar() {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<motion.div
|
<motion.div
|
||||||
className="flex flex-col md:flex-row md:flex-wrap items-center justify-center gap-6 max-w-4xl px-4"
|
className="flex flex-wrap items-center justify-center gap-6 max-w-4xl px-4"
|
||||||
variants={ANIMATIONS.menuContainer}
|
variants={ANIMATIONS.menuContainer}
|
||||||
>
|
>
|
||||||
{mainLinks.map((item) => {
|
{mainLinks.map((item) => {
|
||||||
|
if (item === "Projects") {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key="projects"
|
||||||
|
className="relative group"
|
||||||
|
onMouseEnter={() => setShowDropdownProjects(true)}
|
||||||
|
onMouseLeave={() => setShowDropdownProjects(false)}
|
||||||
|
>
|
||||||
|
<motion.span
|
||||||
|
className="text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5 cursor-pointer select-none"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
>
|
||||||
|
Projects ▾
|
||||||
|
</motion.span>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
|
{showDropdownProjects && (
|
||||||
|
<motion.div
|
||||||
|
className="absolute top-full left-0 mt-2 flex flex-col bg-white/10 border border-white/20 rounded-lg shadow-lg"
|
||||||
|
initial={{ opacity: 0, y: -10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -10 }}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/upload"
|
||||||
|
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
>
|
||||||
|
Upload Projects
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/projects"
|
||||||
|
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
>
|
||||||
|
View Projects
|
||||||
|
</a>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (item === "Resources") {
|
if (item === "Resources") {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key="resources-desktop"
|
key="resources"
|
||||||
className="relative group"
|
className="relative group"
|
||||||
onMouseEnter={() => setShowDropdown(true)}
|
onMouseEnter={() => setShowDropdownResources(true)}
|
||||||
onMouseLeave={() => setShowDropdown(false)}
|
onMouseLeave={() => setShowDropdownResources(false)}
|
||||||
>
|
>
|
||||||
<motion.span
|
<motion.span
|
||||||
className="text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5"
|
className="text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5 cursor-pointer select-none"
|
||||||
variants={ANIMATIONS.menuItem}
|
variants={ANIMATIONS.menuItem}
|
||||||
>
|
>
|
||||||
Resources ▾
|
Resources ▾
|
||||||
</motion.span>
|
</motion.span>
|
||||||
|
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{showDropdown && (
|
{showDropdownResources && (
|
||||||
<motion.div
|
<motion.div
|
||||||
className="absolute top-full left-0 mt-2 flex flex-col bg-white/10 border border-white/20 rounded-lg shadow-lg"
|
className="absolute top-full left-0 mt-2 flex flex-col bg-white/10 border border-white/20 rounded-lg shadow-lg"
|
||||||
initial={{ opacity: 0, y: -10 }}
|
initial={{ opacity: 0, y: -10 }}
|
||||||
@@ -258,12 +342,14 @@ export default function Navbar() {
|
|||||||
<a
|
<a
|
||||||
href="/onlineresources"
|
href="/onlineresources"
|
||||||
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
>
|
>
|
||||||
Online Resources
|
Online Resources
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="/books"
|
href="/books"
|
||||||
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
>
|
>
|
||||||
Books
|
Books
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
135
src/app/projects/page.tsx
Normal file
135
src/app/projects/page.tsx
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Orbitron } from "next/font/google";
|
||||||
|
import { FaGithub } from "react-icons/fa";
|
||||||
|
|
||||||
|
const orbitron = Orbitron({
|
||||||
|
subsets: ["latin"],
|
||||||
|
weight: ["400", "700"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const cardThemes = [
|
||||||
|
{
|
||||||
|
bg: "from-[#0F172A] to-[#1E293B]",
|
||||||
|
headerBg: "bg-[#1E3A8A]",
|
||||||
|
accent: "#60A5FA",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bg: "from-[#0A0F1E] to-[#112240]",
|
||||||
|
headerBg: "bg-[#0EA5E9]",
|
||||||
|
accent: "#38BDF8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bg: "from-[#1E293B] to-[#0F172A]",
|
||||||
|
headerBg: "bg-[#0284C7]",
|
||||||
|
accent: "#7DD3FC",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ProjectsPage: React.FC = () => {
|
||||||
|
const [projects, setProjects] = useState<any[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchProjects = async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/projects", { cache: "no-store" });
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (!res.ok) throw new Error(data.error || "Failed to fetch projects");
|
||||||
|
setProjects(data);
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("Error fetching projects:", err);
|
||||||
|
setError(err.message || "Something went wrong");
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchProjects();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex items-center justify-center text-cyan-400 text-2xl font-bold">
|
||||||
|
Loading Projects...
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex items-center justify-center text-red-500 text-xl font-semibold">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen w-full bg-gradient-to-b from-[#050816] via-[#0A0F1E] to-[#0F172A] py-16 px-4 sm:px-8">
|
||||||
|
<h1
|
||||||
|
className={`text-4xl sm:text-5xl font-bold text-center text-cyan-400 mb-12 ${orbitron.className}`}
|
||||||
|
>
|
||||||
|
PROJECTS
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 max-w-7xl mx-auto">
|
||||||
|
{projects.map((project, index) => {
|
||||||
|
const theme = cardThemes[index % cardThemes.length];
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={project._id || index}
|
||||||
|
className={`rounded-xl overflow-hidden border border-cyan-500/20 shadow-[0_0_25px_rgba(0,255,255,0.1)] hover:shadow-[0_0_35px_rgba(0,255,255,0.25)] transition duration-300 bg-gradient-to-br ${theme.bg}`}
|
||||||
|
>
|
||||||
|
<div className={`${theme.headerBg} py-4 px-6 text-center border-b border-cyan-400/30`}>
|
||||||
|
<h2 className={`text-2xl font-bold text-white tracking-wide ${orbitron.className}`}>
|
||||||
|
{project.name}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-6 text-white flex flex-col gap-3">
|
||||||
|
<p className="text-gray-300">
|
||||||
|
<strong>Tech Stack:</strong> {project.techStack}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{project.description && (
|
||||||
|
<p className="text-gray-400 text-sm italic">{project.description}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between mt-4">
|
||||||
|
{project.deployedLink && (
|
||||||
|
<a
|
||||||
|
href={project.deployedLink}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{ color: theme.accent }}
|
||||||
|
className="underline hover:opacity-80 transition duration-200"
|
||||||
|
>
|
||||||
|
View Project
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{project.githubLink && (
|
||||||
|
<a
|
||||||
|
href={project.githubLink}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-2xl hover:scale-110 transition-transform"
|
||||||
|
style={{ color: theme.accent }}
|
||||||
|
>
|
||||||
|
<FaGithub />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProjectsPage;
|
||||||
197
src/app/upload/page.tsx
Normal file
197
src/app/upload/page.tsx
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
'use client';
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
const UploadPage: React.FC = () => {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
projectName: "",
|
||||||
|
techStack: "",
|
||||||
|
description: "",
|
||||||
|
github: "",
|
||||||
|
deployed: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
const [message, setMessage] = useState("");
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
setFormData({ ...formData, [e.target.id]: e.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setIsSubmitting(true);
|
||||||
|
setMessage("");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/projects", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: formData.projectName,
|
||||||
|
techStack: formData.techStack,
|
||||||
|
description: formData.description,
|
||||||
|
githubLink: formData.github,
|
||||||
|
deployedLink: formData.deployed,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
setMessage(" Project submitted successfully!");
|
||||||
|
setShowModal(true);
|
||||||
|
setFormData({
|
||||||
|
projectName: "",
|
||||||
|
techStack: "",
|
||||||
|
description: "",
|
||||||
|
github: "",
|
||||||
|
deployed: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Redirect after 2 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
setShowModal(false);
|
||||||
|
router.push("/projects");
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
setMessage(" Failed to submit. Try again.");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
setMessage(" Something went wrong.");
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex flex-col md:flex-row">
|
||||||
|
<div className="hidden md:block md:w-1/2 relative">
|
||||||
|
<Image
|
||||||
|
src="/clg.jpg"
|
||||||
|
alt="ml4e"
|
||||||
|
fill
|
||||||
|
style={{ objectFit: "cover" }}
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full md:w-1/2 min-h-screen flex items-center justify-center p-6 sm:p-10 bg-gradient-to-b from-[#0A0A23] via-[#1B1B3A] to-[#3C4EC0]">
|
||||||
|
<form
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
className="w-full max-w-xl text-white p-6 sm:p-8 rounded-xl border border-blue-500 shadow-[0_0_15px_2px_rgba(100,149,237,0.4)] backdrop-blur-sm"
|
||||||
|
>
|
||||||
|
<h2 className="text-3xl font-bold mb-8 text-center">Submit Your Project</h2>
|
||||||
|
|
||||||
|
<div className="mb-6">
|
||||||
|
<label htmlFor="projectName" className="block mb-2 text-lg font-semibold">
|
||||||
|
Project Name
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="projectName"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
value={formData.projectName}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="Project name"
|
||||||
|
className="w-full p-3 rounded bg-transparent border border-white placeholder-gray-400 text-white focus:outline-none focus:ring-2 focus:ring-blue-400"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6">
|
||||||
|
<label htmlFor="techStack" className="block mb-2 text-lg font-semibold">
|
||||||
|
Tech Stack
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="techStack"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
value={formData.techStack}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="React, Node.js, MongoDB, FASTAPI, etc."
|
||||||
|
className="w-full p-3 rounded bg-transparent border border-white placeholder-gray-400 text-white focus:outline-none focus:ring-2 focus:ring-blue-400"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6">
|
||||||
|
<label htmlFor="description" className="block mb-2 text-lg font-semibold">
|
||||||
|
Description
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="description"
|
||||||
|
required
|
||||||
|
value={formData.description}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="Brief description of your project..."
|
||||||
|
rows={4}
|
||||||
|
className="w-full p-3 rounded bg-transparent border border-white placeholder-gray-400 text-white focus:outline-none focus:ring-2 focus:ring-blue-400"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6">
|
||||||
|
<label htmlFor="github" className="block mb-2 text-lg font-semibold">
|
||||||
|
GitHub Repository Link
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="github"
|
||||||
|
type="url"
|
||||||
|
value={formData.github}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="https://github.com/yourproject"
|
||||||
|
className="w-full p-3 rounded bg-transparent border border-white placeholder-gray-400 text-white focus:outline-none focus:ring-2 focus:ring-blue-400"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-8">
|
||||||
|
<label htmlFor="deployed" className="block mb-2 text-lg font-semibold">
|
||||||
|
Deployed Project Link
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="deployed"
|
||||||
|
type="url"
|
||||||
|
value={formData.deployed}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="https://yourproject.vercel.app"
|
||||||
|
className="w-full p-3 rounded bg-transparent border border-white placeholder-gray-400 text-white focus:outline-none focus:ring-2 focus:ring-blue-400"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
className={`w-full py-3 cursor-pointer rounded font-bold transition ${
|
||||||
|
isSubmitting
|
||||||
|
? "bg-gray-500 cursor-not-allowed"
|
||||||
|
: "bg-white text-[#0A0A23] hover:bg-blue-400 hover:text-white"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{isSubmitting ? "Submitting..." : "Submit Project"}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{message && (
|
||||||
|
<p className="text-center mt-4 text-blue-300 font-semibold">{message}</p>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showModal && (
|
||||||
|
<div className="fixed inset-0 bg-black bg-opacity-60 flex items-center justify-center z-50">
|
||||||
|
<div className="bg-blue-600 text-white rounded-xl shadow-xl p-8 max-w-sm w-full text-center animate-fade-in">
|
||||||
|
<h2 className="text-2xl font-bold mb-4"> Project Submitted!</h2>
|
||||||
|
<p className="text-gray-200 mb-6">
|
||||||
|
Redirecting you to the projects page...
|
||||||
|
</p>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<div className="w-6 h-6 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UploadPage;
|
||||||
16
src/lib/db.js
Normal file
16
src/lib/db.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
const connectToDatabase = async () => {
|
||||||
|
if (mongoose.connection.readyState >= 1) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mongoose.connect(process.env.MongoURL, {
|
||||||
|
dbName: "portfolioDB",
|
||||||
|
});
|
||||||
|
console.log(" Connected to MongoDB");
|
||||||
|
} catch (error) {
|
||||||
|
console.error(" MongoDB connection error:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connectToDatabase;
|
||||||
14
src/models/Projects.js
Normal file
14
src/models/Projects.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
const ProjectSchema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
name: { type: String, required: true },
|
||||||
|
techStack: { type: String, required: true },
|
||||||
|
description: { type: String, required: true },
|
||||||
|
deployedLink: { type: String, required: true },
|
||||||
|
githubLink: { type: String, required: true },
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
export default mongoose.models.Project || mongoose.model("Project", ProjectSchema);
|
||||||
Reference in New Issue
Block a user