diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 1b2a485..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,425 +0,0 @@
-{
- "name": "devhub",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "dependencies": {
- "@tsparticles/engine": "^3.5.0",
- "@tsparticles/react": "^3.0.0",
- "@tsparticles/slim": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/basic": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/basic/-/basic-3.5.0.tgz",
- "integrity": "sha512-oty33TxM2aHWrzcwWRic1bQ04KBCdpnvzv8JXEkx5Uyp70vgVegUbtKmwGki3shqKZIt3v2qE4I8NsK6onhLrA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/matteobruni"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/tsparticles"
- },
- {
- "type": "buymeacoffee",
- "url": "https://www.buymeacoffee.com/matteobruni"
- }
- ],
- "dependencies": {
- "@tsparticles/engine": "^3.5.0",
- "@tsparticles/move-base": "^3.5.0",
- "@tsparticles/shape-circle": "^3.5.0",
- "@tsparticles/updater-color": "^3.5.0",
- "@tsparticles/updater-opacity": "^3.5.0",
- "@tsparticles/updater-out-modes": "^3.5.0",
- "@tsparticles/updater-size": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/engine": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/engine/-/engine-3.5.0.tgz",
- "integrity": "sha512-RCwrJ2SvSYdhXJ24oUCjSUKEZQ9lXwObOWMvfMC9vS6/bk+Qo0N7Xx8AfumqzP/LebB1YJdlCvuoJMauAon0Pg==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/matteobruni"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/tsparticles"
- },
- {
- "type": "buymeacoffee",
- "url": "https://www.buymeacoffee.com/matteobruni"
- }
- ],
- "hasInstallScript": true
- },
- "node_modules/@tsparticles/interaction-external-attract": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-attract/-/interaction-external-attract-3.5.0.tgz",
- "integrity": "sha512-BQYjoHtq7yaETSvPtzKt93OO9MZ1WuDZj7cFPG+iujNekXiwhLRQ89a+QMcsTrCLx70KLJ7SuTzQL5MT1/kb2Q==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-bounce": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-bounce/-/interaction-external-bounce-3.5.0.tgz",
- "integrity": "sha512-H/0//dn4zwKes8zWIjolfeokL0VAlj+EkK7LUhznPhPu+Gt+h6aJqPlwC2MdI5Rvcnps8dT7YoCBWBQ4tJH6zg==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-bubble": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-bubble/-/interaction-external-bubble-3.5.0.tgz",
- "integrity": "sha512-xTS4PQDMC5j9qOAFTC1M9DfBTJl8P8M41ySGtZHnCvVqG0oLlLSw15msniamjXyaoA4tZvBPM6G+GmFdgE9w1A==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-connect": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-connect/-/interaction-external-connect-3.5.0.tgz",
- "integrity": "sha512-VSpyZ0P8Hu4nq6C917X3tnwEROfGjrm0ivWJmbBv/lFJ9euZ2VeezeITNZNtNvt/hS5vLI8npDetB/wtd994HQ==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-grab": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-grab/-/interaction-external-grab-3.5.0.tgz",
- "integrity": "sha512-WOTWSGVerlfJZ9zwq8Eyutq1h0LAr1hI/Fs8j7s5qabZjxPzUBV8rhgghZ/nGrHEiB6j8SW4XMHkN6XR0VM9Ww==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-pause": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-pause/-/interaction-external-pause-3.5.0.tgz",
- "integrity": "sha512-Hnj1mBH5X3d3zwTP6R+tYn45uTq5XGLDINhEzl30EAjXK30LQe8/RgE91O4CsMSrlTmouG0OuHYGC3nyrn/dcw==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-push": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-push/-/interaction-external-push-3.5.0.tgz",
- "integrity": "sha512-8UNt5lYRhydDJCK7AznR3s1nJj3OCeLcDknARoq7hATdI+G151QAubD9NUUURCZ1GdXpftT5Bh0Bl1YtiZwOhg==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-remove": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-remove/-/interaction-external-remove-3.5.0.tgz",
- "integrity": "sha512-+qiVRnR8xywg++gn8fagwpuQVh0WWKxIMkY6l6lMw9UoXz8L6MUVgvWaT632EVmkrTgM43pZ1m0W3m9aBY9rZw==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-repulse": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-repulse/-/interaction-external-repulse-3.5.0.tgz",
- "integrity": "sha512-lTF7iLqCCQ3AbQSDVTpE3TihoVvI322/5QTqQmwylrrmjbDxGu4Hym4BHK5GqDHOdodOnwU2DWjRF5cRx3aPPg==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-external-slow": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-external-slow/-/interaction-external-slow-3.5.0.tgz",
- "integrity": "sha512-KYp1GWbXdnLunFvHJt2YMZMMITebAt0XkzisKoSe+rfvoCbcMGXI2XvDYb0UkGvd8sKTSnHcn7cGH8dhVXXYaQ==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-particles-attract": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-particles-attract/-/interaction-particles-attract-3.5.0.tgz",
- "integrity": "sha512-ICnT9+9ZxINh5ZijyxjFXOOMC/jNQgOXPe+5MxgK/WYXE8mRbRzsOdaxiS3zK5PSFlqtztn189anDbfqcHDutQ==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-particles-collisions": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-particles-collisions/-/interaction-particles-collisions-3.5.0.tgz",
- "integrity": "sha512-KrfyXy4l6nW2z0An2FE4z5R4rEiIONYPcDpkBhWqQK+pyLkHhtGYmqmP7Pb22IC9noFzjOCaR5CNVjWP7B+1vA==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/interaction-particles-links": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/interaction-particles-links/-/interaction-particles-links-3.5.0.tgz",
- "integrity": "sha512-ZdIixcGcRJMxCq4zxeRAzzbbuN5vVoy3pDDLaO3mnWnfJWywkYZToV0XvOUaHUT2AkUuKa9ZuQKx0LO3z1AO+w==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/move-base": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/move-base/-/move-base-3.5.0.tgz",
- "integrity": "sha512-9oDk7zTxyhUCstj3lHTNTiWAgqIBzWa2o1tVQFK63Qwq+/WxzJCSwZOocC9PAHGM1IP6nA4zYJSfjbMBTrUocA==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/move-parallax": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/move-parallax/-/move-parallax-3.5.0.tgz",
- "integrity": "sha512-1NC2OGsbdLc5T4uiRqq7i24b9FIhfaLnx4wVtOQjX48jWfy/ZKOdIEYLFKOPHnaMI0MjinJTNXLi9i6zVNCobg==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/plugin-easing-quad": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/plugin-easing-quad/-/plugin-easing-quad-3.5.0.tgz",
- "integrity": "sha512-Pd44hTiVlaaeQZwRlP+ih8jKmWuIQdkpPUJS0Qwzeck2nfK01IAflDJoxXxGF53vA8QOrz/K6VdVQJShD8yCsg==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/matteobruni"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/tsparticles"
- },
- {
- "type": "buymeacoffee",
- "url": "https://www.buymeacoffee.com/matteobruni"
- }
- ],
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/react": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/react/-/react-3.0.0.tgz",
- "integrity": "sha512-hjGEtTT1cwv6BcjL+GcVgH++KYs52bIuQGW3PWv7z3tMa8g0bd6RI/vWSLj7p//NZ3uTjEIeilYIUPBh7Jfq/Q==",
- "peerDependencies": {
- "@tsparticles/engine": "^3.0.2",
- "react": ">=16.8.0",
- "react-dom": ">=16.8.0"
- }
- },
- "node_modules/@tsparticles/shape-circle": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/shape-circle/-/shape-circle-3.5.0.tgz",
- "integrity": "sha512-59TmXkeeI6Jzv5vt/D3TkclglabaoEXQi2kbDjSCBK68SXRHzlQu29mSAL41Y5S0Ft5ZJKkAQHX1IqEnm8Hyjg==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/shape-emoji": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/shape-emoji/-/shape-emoji-3.5.0.tgz",
- "integrity": "sha512-cxWHxQxnG5vLDltkoxdo7KS87uKPwQgf4SDWy/WCxW4Psm1TEeeSGYMJPVed+wWPspOKmLb7u8OaEexgE2pHHQ==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/shape-image": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/shape-image/-/shape-image-3.5.0.tgz",
- "integrity": "sha512-lWYg7DTv74dSOnXy+4dr7t1/OSuUmxDpIo12Lbxgx/QBN7A5I/HoqbKcs13TSA0RS1hcuMgtti07BcDTEYW3Dw==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/shape-line": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/shape-line/-/shape-line-3.5.0.tgz",
- "integrity": "sha512-Qc4jwFEi/VnwmGwQBO/kCJEfNYdKHpeXfrdcqmm9c1B4iYHHDoaXJp6asMTggEfeAWu7fyPaO/7MURiPEqg7Hg==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/shape-polygon": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/shape-polygon/-/shape-polygon-3.5.0.tgz",
- "integrity": "sha512-sqYL+YXpnq3nSWcOEGZaJ4Z7Cb7x8M0iORSLpPdNEIvwDKdPczYyQM95D8ep19Pv1CV5L0uRthV36wg7UpnJ9Q==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/shape-square": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/shape-square/-/shape-square-3.5.0.tgz",
- "integrity": "sha512-rPHpA4Pzm1W5DIIow+lQS+VS7D2thSBQQbV9eHxb933Wh0/QC3me3w4vovuq7hdtVANhsUVO04n44Gc/2TgHkw==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/shape-star": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/shape-star/-/shape-star-3.5.0.tgz",
- "integrity": "sha512-EDEJc4MYv3UbOeA3wrZjuJVtZ08PdCzzBij3T/7Tp3HUCf/p9XnfHBd/CPR5Mo6X0xpGfrein8UQN9CjGLHwUA==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/slim": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/slim/-/slim-3.5.0.tgz",
- "integrity": "sha512-CKx3VtzsY0fs/dQc41PYtL3edm1z2sBROTgvz3adwqMyTWkQGnjLQhsM777Ebb6Yjf5Jxu4TzWOBc2HO7Cstkg==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/matteobruni"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/tsparticles"
- },
- {
- "type": "buymeacoffee",
- "url": "https://www.buymeacoffee.com/matteobruni"
- }
- ],
- "dependencies": {
- "@tsparticles/basic": "^3.5.0",
- "@tsparticles/engine": "^3.5.0",
- "@tsparticles/interaction-external-attract": "^3.5.0",
- "@tsparticles/interaction-external-bounce": "^3.5.0",
- "@tsparticles/interaction-external-bubble": "^3.5.0",
- "@tsparticles/interaction-external-connect": "^3.5.0",
- "@tsparticles/interaction-external-grab": "^3.5.0",
- "@tsparticles/interaction-external-pause": "^3.5.0",
- "@tsparticles/interaction-external-push": "^3.5.0",
- "@tsparticles/interaction-external-remove": "^3.5.0",
- "@tsparticles/interaction-external-repulse": "^3.5.0",
- "@tsparticles/interaction-external-slow": "^3.5.0",
- "@tsparticles/interaction-particles-attract": "^3.5.0",
- "@tsparticles/interaction-particles-collisions": "^3.5.0",
- "@tsparticles/interaction-particles-links": "^3.5.0",
- "@tsparticles/move-parallax": "^3.5.0",
- "@tsparticles/plugin-easing-quad": "^3.5.0",
- "@tsparticles/shape-emoji": "^3.5.0",
- "@tsparticles/shape-image": "^3.5.0",
- "@tsparticles/shape-line": "^3.5.0",
- "@tsparticles/shape-polygon": "^3.5.0",
- "@tsparticles/shape-square": "^3.5.0",
- "@tsparticles/shape-star": "^3.5.0",
- "@tsparticles/updater-life": "^3.5.0",
- "@tsparticles/updater-rotate": "^3.5.0",
- "@tsparticles/updater-stroke-color": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/updater-color": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/updater-color/-/updater-color-3.5.0.tgz",
- "integrity": "sha512-TGGgiLixIg37sst2Fj9IV4XbdMwkT6PYanM7qEqyfmv4hJ/RHMQlCznEe6b7OhChQVBg5ov5EMl/BT4/fIWEYw==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/updater-life": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/updater-life/-/updater-life-3.5.0.tgz",
- "integrity": "sha512-jlMEq16dwN+rZmW/UmLdqaCe4W0NFrVdmXkZV8QWYgu06a+Ucslz337nHYaP89/9rZWpNua/uq1JDjDzaVD5Jg==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/updater-opacity": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/updater-opacity/-/updater-opacity-3.5.0.tgz",
- "integrity": "sha512-T2YfqdIFV/f5VOg1JQsXu6/owdi9g9K2wrJlBfgteo+IboVp6Lcuo4PGAfilWVkWrTdp1Nz4mz39NrLHfOce2g==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/updater-out-modes": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/updater-out-modes/-/updater-out-modes-3.5.0.tgz",
- "integrity": "sha512-y6NZe2OSk5SrYdaLwUIQnHICsNEDIdPPJHQ2nAWSvAuPJphlSKjUknc7OaGiFwle6l0OkhWoZZe1rV1ktbw/lA==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/updater-rotate": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/updater-rotate/-/updater-rotate-3.5.0.tgz",
- "integrity": "sha512-j4qPHQd1eUmDoGnIJOsVswHLqtTof1je+b2GTOLB3WIoKmlyUpzQYjVc7PNfLMuCEUubwpZCfcd/vC80VZeWkg==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/updater-size": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/updater-size/-/updater-size-3.5.0.tgz",
- "integrity": "sha512-TnWlOChBsVZffT2uO0S4ALGSzxT6UAMIVlhGMGFgSeIlktKMqM+dxDGAPrYa1n8IS2dkVGisiXzsV0Ss6Ceu1A==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/@tsparticles/updater-stroke-color": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@tsparticles/updater-stroke-color/-/updater-stroke-color-3.5.0.tgz",
- "integrity": "sha512-29X1zER+W9IBDv0nTD/jRXnu5rEU7uv7+W1N0B6leBipjAY24sg7Kub2SvXAaBKz6kHHWuCeccBOwIiiTpDqMA==",
- "dependencies": {
- "@tsparticles/engine": "^3.5.0"
- }
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "peer": true
- },
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "peer": true,
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/react": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
- "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
- "peer": true,
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-dom": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
- "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
- "peer": true,
- "dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.2"
- },
- "peerDependencies": {
- "react": "^18.3.1"
- }
- },
- "node_modules/scheduler": {
- "version": "0.23.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
- "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
- "peer": true,
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
- }
- }
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index ecee130..0000000
--- a/package.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "dependencies": {
- "@tsparticles/engine": "^3.5.0",
- "@tsparticles/react": "^3.0.0",
- "@tsparticles/slim": "^3.5.0"
- }
-}
diff --git a/server/api/handlers/projects/projects.py b/server/api/handlers/projects/projects.py
index 204332d..3f9fc21 100644
--- a/server/api/handlers/projects/projects.py
+++ b/server/api/handlers/projects/projects.py
@@ -1,96 +1,172 @@
from flask import request, jsonify, current_app
from models import Project
from extensions import neo4j_db
+import uuid
+
+def increment_star(username, project_id):
+ check_query = """
+ MATCH (u:User {username: $username})-[:STARRED]->(p:Project {project_id: $project_id})
+ RETURN p
+ """
+ increment_star_query = """
+ MATCH (u:User {username: $username}), (p:Project {project_id: $project_id})
+ WHERE NOT (u)-[:STARRED]->(p)
+ SET p.star = p.star + 1
+ CREATE (u)-[:STARRED]->(p)
+ RETURN p
+ """
+ try:
+ with neo4j_db.driver.session() as session:
+ # Check if the user has already starred the project
+ check_result = session.run(check_query, username=username, project_id=project_id)
+ if check_result.single():
+ return jsonify({'message': 'You have already starred this project'}), 400
+
+ # Increment the star count and create a STARRED relationship
+ result = session.run(increment_star_query, username=username, project_id=project_id)
+ project_record = result.single()
+
+ if project_record:
+ project = project_record["p"]
+ return jsonify({
+ 'message': 'Star count incremented successfully',
+ 'project': {
+ 'projectId': project["project_id"],
+ 'title': project["title"],
+ 'description': project.get("description", ""),
+ 'repoLink': project.get("repo_link", ""),
+ 'star': project.get("star")
+ }
+ }), 200
+ else:
+ return jsonify({'message': 'Project not found'}), 404
+
+ except Exception as e:
+ current_app.logger.error(f"Error incrementing star count: {e}")
+ return jsonify({'message': 'An error occurred while incrementing the star count'}), 500
+
+def get_projects(username):
+ query = """
+ MATCH (u:User {username: $username})-[:OWNS]->(p:Project)
+ OPTIONAL MATCH (p)-[:TAGGED_WITH]->(t:Tag)
+ RETURN p, collect(t.name) AS tags
+ """
+ try:
+ with neo4j_db.driver.session() as session:
+ result = session.run(query, username=username)
+ projects = []
+
+ for record in result:
+ project = record["p"]
+ tags = record["tags"]
+ projects.append({
+ 'projectId': project.get('project_id'),
+ 'title': project.get('title'),
+ 'description': project.get('description', ''),
+ 'repoLink': project.get('repo_link', ''),
+ 'tags': tags if tags else [],
+ 'starCount' : project.get('star')
+ })
+
+ if projects:
+ return jsonify({'projects': projects}), 200
+ else:
+ return jsonify({'message': 'No projects found for the user'}), 404
+
+ except Exception as e:
+ current_app.logger.error(f"Error fetching projects: {e}")
+ return jsonify({'message': 'An error occurred while fetching projects'}), 500
def add_project(username):
data = request.get_json()
-
- # Get project details from request
title = data.get('title')
description = data.get('description', '')
repo_link = data.get('repo_link', '')
tags = data.get('tags', '')
+ project_id = str(uuid.uuid4())
+
+ domain_tags = [tag.strip() for tag in tags.split(',') if tag.strip()]
- # Define a query to create a project without tags initially
create_project_query = """
MATCH (u:User {username: $username})
- CREATE (p:Project {title: $title, description: $description, repo_link: $repo_link, tags: $tags})
+ CREATE (p:Project {project_id: $project_id, title: $title, description: $description, repo_link: $repo_link, star: 0})
CREATE (u)-[:OWNS]->(p)
RETURN p
"""
-
try:
with neo4j_db.driver.session() as session:
- # Create the project
- result = session.run(create_project_query, username=username, title=title, description=description, repo_link=repo_link, tags=tags)
+ result = session.run(create_project_query, username=username, project_id=project_id, title=title, description=description, repo_link=repo_link)
project_record = result.single()
if project_record:
project = project_record["p"]
- domain_tags = [tag for tag in tags.split(',') if tag.strip() in tags]
-
- # Update project with tags
- update_project_query = """
- MATCH (p:Project {title: $title, description: $description, repo_link: $repo_link})
- WITH p, $tags AS tags
- UNWIND tags AS tagName
- MERGE (t:Tag {name: tagName})
- CREATE (p)-[:TAGGED_WITH]->(t)
- RETURN p
- """
+ if domain_tags:
+ update_project_query = """
+ MATCH (p:Project {project_id: $project_id})
+ WITH p, $tags AS tags
+ UNWIND tags AS tagName
+ MERGE (t:Tag {name: tagName})
+ CREATE (p)-[:TAGGED_WITH]->(t)
+ RETURN p
+ """
+ session.run(update_project_query, project_id=project_id, tags=domain_tags)
- # Update the project with tags
- session.run(update_project_query, title=title, description=description, repo_link=repo_link, tags=domain_tags)
-
- return jsonify({'message': 'Project added and categorized successfully', 'project': {
- 'title': project["title"],
- 'description': project.get("description", ""),
- 'repoLink': project.get("repo_link", ""),
- 'tags': domain_tags
- }}), 201
+ return jsonify({
+ 'message': 'Project added and categorized successfully',
+ 'project': {
+ 'projectId': project["project_id"],
+ 'title': project["title"],
+ 'description': project.get("description", ""),
+ 'repoLink': project.get("repo_link", ""),
+ 'tags': domain_tags,
+ 'star': 0
+ }
+ }), 201
else:
return jsonify({'message': 'User not found'}), 404
except Exception as e:
current_app.logger.error(f"Error adding project: {e}")
return jsonify({'message': 'An error occurred while adding the project'}), 500
-
-
def update_project(username, project_id):
data = request.get_json()
title = data.get('title')
description = data.get('description')
repo_link = data.get('repo_link')
- tags = data.get('tags', '')
+ tags = [tag.strip() for tag in data.get('tags', '').split(',')] if data.get('tags') else []
query = """
- MATCH (u:User {username: $username})-[:OWNS]->(p:Project {id: $project_id})
+ MATCH (u:User {username: $username})-[:OWNS]->(p:Project {project_id: $project_id})
SET p.title = $title, p.description = $description, p.repo_link = $repo_link
WITH p
OPTIONAL MATCH (p)-[r:TAGGED_WITH]->(t:Tag)
DELETE r
- WITH p
- UNWIND $tags AS tagName
+ WITH p, $tags AS tags
+ UNWIND tags AS tagName
MERGE (t:Tag {name: tagName})
- CREATE (p)-[:TAGGED_WITH]->(t)
+ MERGE (p)-[:TAGGED_WITH]->(t) // Change here to use MERGE for the relationship
RETURN p
"""
- with neo4j_db.driver.session() as session:
- result = session.run(query, username=username, project_id=project_id, title=title, description=description, repo_link=repo_link, tags=tags.split(', ') if tags else [])
- if result.single():
- return jsonify({'message': 'Project updated successfully'}), 200
- return jsonify({'message': 'Project or user not found'}), 404
+ try:
+ with neo4j_db.driver.session() as session:
+ result = session.run(query, username=username, project_id=project_id, title=title, description=description, repo_link=repo_link, tags=tags)
+ if result.single():
+ return jsonify({'message': 'Project updated successfully'}), 200
+ return jsonify({'message': 'Project or user not found'}), 404
+ except Exception as e:
+ current_app.logger.error(f"Error updating project: {e}")
+ return jsonify({'message': 'An error occurred while updating the project'}), 500
-def delete_project(username, project_title):
+def delete_project(username, project_id):
query = """
- MATCH (u:User {username: $username})-[:OWNS]->(p:Project {title: $project_title})
+ MATCH (u:User {username: $username})-[:OWNS]->(p:Project {project_id: $project_id})
OPTIONAL MATCH (p)-[r]-()
DELETE r, p
RETURN u
"""
with neo4j_db.driver.session() as session:
- result = session.run(query, username=username, project_title=project_title)
+ result = session.run(query, username=username, project_id=project_id)
if result.single():
return jsonify({'message': 'Project deleted successfully'}), 200
- return jsonify({'message': 'Project or user not found'}), 404
\ No newline at end of file
+ return jsonify({'message': 'Project or user not found'}), 404
diff --git a/server/api/urls.py b/server/api/urls.py
index ce72174..5f3614e 100644
--- a/server/api/urls.py
+++ b/server/api/urls.py
@@ -1,6 +1,6 @@
from api.handlers.auth.userauth import signup, login, check_auth, home, logout, index, check_username
from api.handlers.user.profile import get_profile, update_profile
-from api.handlers.projects.projects import add_project, update_project, delete_project
+from api.handlers.projects.projects import add_project, update_project, delete_project, get_projects, increment_star
from api.handlers.analyze.githubdata import github_data, top_languages, streak_stats, pinned_repos, streak_chart
from api.handlers.analyze.leetcodedata import leetcode_data, leetcode_card
from api.handlers.query.querymodel import chat,chat_history
@@ -34,9 +34,11 @@ def register_routes(app):
app.add_url_rule('/analyze/leetcode_card', 'leetcode_card', leetcode_card, methods=['POST'])
# Project routes
+ app.add_url_rule('/profile/
/projects', 'get_projects', get_projects, methods=['GET'])
app.add_url_rule('/profile//projects', 'add_project', add_project, methods=['POST'])
- app.add_url_rule('/profile//projects/', 'update_project', update_project, methods=['PUT'])
- app.add_url_rule('/profile//projects/', 'delete_project', delete_project, methods=['DELETE'])
+ app.add_url_rule('/profile//projects/', 'update_project', update_project, methods=['PUT'])
+ app.add_url_rule('/profile//projects/', 'delete_project', delete_project, methods=['DELETE'])
+ app.add_url_rule('/profile//projects//star', 'increment_star', increment_star, methods=['POST'])
# Chat with model routes
app.add_url_rule('/chat', 'chat', chat, methods=['POST'])
diff --git a/server/models.py b/server/models.py
index a824088..fafebd6 100644
--- a/server/models.py
+++ b/server/models.py
@@ -61,21 +61,24 @@ def remove_friend(self, friend_user):
class Project(Base):
__tablename__ = 'projects'
-
- id = Column(Integer, primary_key=True)
+
+ project_id = Column(Integer, primary_key=True)
title = Column(String, nullable=False)
description = Column(Text, nullable=True)
repo_link = Column(String, nullable=True)
+ star = Column(Integer, default=0, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship('User', back_populates='projects')
tags = relationship('Tag', secondary=project_tags, back_populates='projects')
- def __init__(self, title, description=None, repo_link=None):
+ def __init__(self, title, description=None, repo_link=None, star=0):
self.title = title
self.description = description
self.repo_link = repo_link
+ self.star = star
+
class Tag(Base):
__tablename__ = 'tags'