Generated
+448
-1
@@ -28,7 +28,8 @@
|
|||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"remark-math": "^6.0.0"
|
"remark-math": "^6.0.0",
|
||||||
|
"tsparticles-slim": "^2.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
@@ -4535,6 +4536,452 @@
|
|||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
|
"node_modules/tsparticles-basic": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-basic/-/tsparticles-basic-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-pN6FBpL0UsIUXjYbiui5+IVsbIItbQGOlwyGV55g6IYJBgdTNXgFX0HRYZGE9ZZ9psEXqzqwLM37zvWnb5AG9g==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0",
|
||||||
|
"tsparticles-move-base": "^2.12.0",
|
||||||
|
"tsparticles-shape-circle": "^2.12.0",
|
||||||
|
"tsparticles-updater-color": "^2.12.0",
|
||||||
|
"tsparticles-updater-opacity": "^2.12.0",
|
||||||
|
"tsparticles-updater-out-modes": "^2.12.0",
|
||||||
|
"tsparticles-updater-size": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-engine": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-engine/-/tsparticles-engine-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-ZjDIYex6jBJ4iMc9+z0uPe7SgBnmb6l+EJm83MPIsOny9lPpetMsnw/8YJ3xdxn8hV+S3myTpTN1CkOVmFv0QQ==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"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,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-attract": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-attract/-/tsparticles-interaction-external-attract-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-0roC6D1QkFqMVomcMlTaBrNVjVOpyNzxIUsjMfshk2wUZDAvTNTuWQdUpmsLS4EeSTDN3rzlGNnIuuUQqyBU5w==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-bounce": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-bounce/-/tsparticles-interaction-external-bounce-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-MMcqKLnQMJ30hubORtdq+4QMldQ3+gJu0bBYsQr9BsThsh8/V0xHc1iokZobqHYVP5tV77mbFBD8Z7iSCf0TMQ==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-bubble": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-bubble/-/tsparticles-interaction-external-bubble-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-5kImCSCZlLNccXOHPIi2Yn+rQWTX3sEa/xCHwXW19uHxtILVJlnAweayc8+Zgmb7mo0DscBtWVFXHPxrVPFDUA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-connect": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-connect/-/tsparticles-interaction-external-connect-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-ymzmFPXz6AaA1LAOL5Ihuy7YSQEW8MzuSJzbd0ES13U8XjiU3HlFqlH6WGT1KvXNw6WYoqrZt0T3fKxBW3/C3A==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-grab": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-grab/-/tsparticles-interaction-external-grab-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-iQF/A947hSfDNqAjr49PRjyQaeRkYgTYpfNmAf+EfME8RsbapeP/BSyF6mTy0UAFC0hK2A2Hwgw72eT78yhXeQ==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-pause": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-pause/-/tsparticles-interaction-external-pause-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-4SUikNpsFROHnRqniL+uX2E388YTtfRWqqqZxRhY0BrijH4z04Aii3YqaGhJxfrwDKkTQlIoM2GbFT552QZWjw==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-push": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-push/-/tsparticles-interaction-external-push-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-kqs3V0dgDKgMoeqbdg+cKH2F+DTrvfCMrPF1MCCUpBCqBiH+TRQpJNNC86EZYHfNUeeLuIM3ttWwIkk2hllR/Q==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-remove": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-remove/-/tsparticles-interaction-external-remove-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-2eNIrv4m1WB2VfSVj46V2L/J9hNEZnMgFc+A+qmy66C8KzDN1G8aJUAf1inW8JVc0lmo5+WKhzex4X0ZSMghBg==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-repulse": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-repulse/-/tsparticles-interaction-external-repulse-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-rSzdnmgljeBCj5FPp4AtGxOG9TmTsK3AjQW0vlyd1aG2O5kSqFjR+FuT7rfdSk9LEJGH5SjPFE6cwbuy51uEWA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-external-slow": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-external-slow/-/tsparticles-interaction-external-slow-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-2IKdMC3om7DttqyroMtO//xNdF0NvJL/Lx7LDo08VpfTgJJozxU+JAUT8XVT7urxhaDzbxSSIROc79epESROtA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-particles-attract": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-attract/-/tsparticles-interaction-particles-attract-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-Hl8qwuwF9aLq3FOkAW+Zomu7Gb8IKs6Y3tFQUQScDmrrSCaeRt2EGklAiwgxwgntmqzL7hbMWNx06CHHcUQKdQ==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-particles-collisions": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-collisions/-/tsparticles-interaction-particles-collisions-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-Se9nPWlyPxdsnHgR6ap4YUImAu3W5MeGKJaQMiQpm1vW8lSMOUejI1n1ioIaQth9weKGKnD9rvcNn76sFlzGBA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-interaction-particles-links": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-links/-/tsparticles-interaction-particles-links-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-e7I8gRs4rmKfcsHONXMkJnymRWpxHmeaJIo4g2NaDRjIgeb2AcJSWKWZvrsoLnm7zvaf/cMQlbN6vQwCixYq3A==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-move-base": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-move-base/-/tsparticles-move-base-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-oSogCDougIImq+iRtIFJD0YFArlorSi8IW3HD2gO3USkH+aNn3ZqZNTqp321uB08K34HpS263DTbhLHa/D6BWw==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-move-parallax": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-move-parallax/-/tsparticles-move-parallax-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-58CYXaX8Ih5rNtYhpnH0YwU4Ks7gVZMREGUJtmjhuYN+OFr9FVdF3oDIJ9N6gY5a5AnAKz8f5j5qpucoPRcYrQ==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-particles.js": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-particles.js/-/tsparticles-particles.js-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-LyOuvYdhbUScmA4iDgV3LxA0HzY1DnOwQUy3NrPYO393S2YwdDjdwMod6Btq7EBUjg9FVIh+sZRizgV5elV2dg==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-plugin-easing-quad": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-plugin-easing-quad/-/tsparticles-plugin-easing-quad-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-2mNqez5pydDewMIUWaUhY5cNQ80IUOYiujwG6qx9spTq1D6EEPLbRNAEL8/ecPdn2j1Um3iWSx6lo340rPkv4Q==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-circle": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-circle/-/tsparticles-shape-circle-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-L6OngbAlbadG7b783x16ns3+SZ7i0SSB66M8xGa5/k+YcY7zm8zG0uPt1Hd+xQDR2aNA3RngVM10O23/Lwk65Q==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-image": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-image/-/tsparticles-shape-image-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-iCkSdUVa40DxhkkYjYuYHr9MJGVw+QnQuN5UC+e/yBgJQY+1tQL8UH0+YU/h0GHTzh5Sm+y+g51gOFxHt1dj7Q==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-line": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-line/-/tsparticles-shape-line-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-RcpKmmpKlk+R8mM5wA2v64Lv1jvXtU4SrBDv3vbdRodKbKaWGGzymzav1Q0hYyDyUZgplEK/a5ZwrfrOwmgYGA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-polygon": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-polygon/-/tsparticles-shape-polygon-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-5YEy7HVMt1Obxd/jnlsjajchAlYMr9eRZWN+lSjcFSH6Ibra7h59YuJVnwxOxAobpijGxsNiBX0PuGQnB47pmA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-square": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-square/-/tsparticles-shape-square-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-33vfajHqmlODKaUzyPI/aVhnAOT09V7nfEPNl8DD0cfiNikEuPkbFqgJezJuE55ebtVo7BZPDA9o7GYbWxQNuw==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-star": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-star/-/tsparticles-shape-star-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-4sfG/BBqm2qBnPLASl2L5aBfCx86cmZLXeh49Un+TIR1F5Qh4XUFsahgVOG0vkZQa+rOsZPEH04xY5feWmj90g==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-text": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-text/-/tsparticles-shape-text-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-v2/FCA+hyTbDqp2ymFOe97h/NFb2eezECMrdirHWew3E3qlvj9S/xBibjbpZva2gnXcasBwxn0+LxKbgGdP0rA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-slim": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-slim/-/tsparticles-slim-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-27w9aGAAAPKHvP4LHzWFpyqu7wKyulayyaZ/L6Tuuejy4KP4BBEB4rY5GG91yvAPsLtr6rwWAn3yS+uxnBDpkA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-basic": "^2.12.0",
|
||||||
|
"tsparticles-engine": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-attract": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-bounce": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-bubble": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-connect": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-grab": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-pause": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-push": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-remove": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-repulse": "^2.12.0",
|
||||||
|
"tsparticles-interaction-external-slow": "^2.12.0",
|
||||||
|
"tsparticles-interaction-particles-attract": "^2.12.0",
|
||||||
|
"tsparticles-interaction-particles-collisions": "^2.12.0",
|
||||||
|
"tsparticles-interaction-particles-links": "^2.12.0",
|
||||||
|
"tsparticles-move-base": "^2.12.0",
|
||||||
|
"tsparticles-move-parallax": "^2.12.0",
|
||||||
|
"tsparticles-particles.js": "^2.12.0",
|
||||||
|
"tsparticles-plugin-easing-quad": "^2.12.0",
|
||||||
|
"tsparticles-shape-circle": "^2.12.0",
|
||||||
|
"tsparticles-shape-image": "^2.12.0",
|
||||||
|
"tsparticles-shape-line": "^2.12.0",
|
||||||
|
"tsparticles-shape-polygon": "^2.12.0",
|
||||||
|
"tsparticles-shape-square": "^2.12.0",
|
||||||
|
"tsparticles-shape-star": "^2.12.0",
|
||||||
|
"tsparticles-shape-text": "^2.12.0",
|
||||||
|
"tsparticles-updater-color": "^2.12.0",
|
||||||
|
"tsparticles-updater-life": "^2.12.0",
|
||||||
|
"tsparticles-updater-opacity": "^2.12.0",
|
||||||
|
"tsparticles-updater-out-modes": "^2.12.0",
|
||||||
|
"tsparticles-updater-rotate": "^2.12.0",
|
||||||
|
"tsparticles-updater-size": "^2.12.0",
|
||||||
|
"tsparticles-updater-stroke-color": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-color": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-color/-/tsparticles-updater-color-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-KcG3a8zd0f8CTiOrylXGChBrjhKcchvDJjx9sp5qpwQK61JlNojNCU35xoaSk2eEHeOvFjh0o3CXWUmYPUcBTQ==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-life": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-life/-/tsparticles-updater-life-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-J7RWGHAZkowBHpcLpmjKsxwnZZJ94oGEL2w+wvW1/+ZLmAiFFF6UgU0rHMC5CbHJT4IPx9cbkYMEHsBkcRJ0Bw==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-opacity": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-opacity/-/tsparticles-updater-opacity-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-YUjMsgHdaYi4HN89LLogboYcCi1o9VGo21upoqxq19yRy0hRCtx2NhH22iHF/i5WrX6jqshN0iuiiNefC53CsA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-out-modes": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-out-modes/-/tsparticles-updater-out-modes-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-owBp4Gk0JNlSrmp12XVEeBroDhLZU+Uq3szbWlHGSfcR88W4c/0bt0FiH5bHUqORIkw+m8O56hCjbqwj69kpOQ==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-rotate": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-rotate/-/tsparticles-updater-rotate-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-waOFlGFmEZOzsQg4C4VSejNVXGf4dMf3fsnQrEROASGf1FCd8B6WcZau7JtXSTFw0OUGuk8UGz36ETWN72DkCw==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-size": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-size/-/tsparticles-updater-size-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-B0yRdEDd/qZXCGDL/ussHfx5YJ9UhTqNvmS5X2rR2hiZhBAE2fmsXLeWkdtF2QusjPeEqFDxrkGiLOsh6poqRA==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-stroke-color": {
|
||||||
|
"version": "2.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-stroke-color/-/tsparticles-updater-stroke-color-2.12.0.tgz",
|
||||||
|
"integrity": "sha512-MPou1ZDxsuVq6SN1fbX+aI5yrs6FyP2iPCqqttpNbWyL+R6fik1rL0ab/x02B57liDXqGKYomIbBQVP3zUTW1A==",
|
||||||
|
"deprecated": "starting from tsparticles v3 the packages are now moved to @tsparticles/package-name instead of tsparticles-package-name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.7.2",
|
"version": "5.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
|
||||||
|
|||||||
+2
-1
@@ -29,7 +29,8 @@
|
|||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"remark-math": "^6.0.0"
|
"remark-math": "^6.0.0",
|
||||||
|
"tsparticles-slim": "^2.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { getBlog, getBlogs } from "@/blogApi";
|
|
||||||
import { notion, databaseId, n2m } from "@/notion";
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const url = new URL(request.url);
|
|
||||||
const id = url.searchParams.get("id");
|
|
||||||
if (id) {
|
|
||||||
let [status, data] = await getBlog(notion, n2m, id);
|
|
||||||
return Response.json(data, { status });
|
|
||||||
} else {
|
|
||||||
var cursor = url.searchParams.get("cursor") || undefined;
|
|
||||||
if (cursor === "") cursor = undefined;
|
|
||||||
const size = parseInt(url.searchParams.get("size") || "5");
|
|
||||||
let [status, response] = await getBlogs(notion, databaseId, cursor, size);
|
|
||||||
return Response.json(response, { status });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export function GET(req: Request) {
|
|
||||||
return new Response(JSON.stringify({
|
|
||||||
version: "1.0.2",
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { getBlogs, searchBlog } from "@/blogApi";
|
|
||||||
import { notion, databaseId } from "@/notion";
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const url = new URL(request.url);
|
|
||||||
let [status, response] = await searchBlog(
|
|
||||||
notion,
|
|
||||||
url.searchParams.get("query") || ""
|
|
||||||
);
|
|
||||||
return Response.json(response, { status });
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import MarkdownRenderer from "@/components/MarkdownRenderer";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import "./style.css";
|
|
||||||
|
|
||||||
type Blog = {
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
id: string;
|
|
||||||
tags: { name: string; color: string }[];
|
|
||||||
markdown: string;
|
|
||||||
date: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Blog({ params }: { params: Promise<{ id: string }> }) {
|
|
||||||
const [blog, setBlog] = useState<null | Blog>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
params.then(({ id }) =>
|
|
||||||
fetch(`/api/blog/?id=${id}`)
|
|
||||||
.then((res) => {
|
|
||||||
res
|
|
||||||
.json()
|
|
||||||
.then((response) => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
setBlog(response);
|
|
||||||
} else {
|
|
||||||
console.error(`'/api/blog/${id}' Error:`, response.msg);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(`'/api/blog/${id}' Unable to obtain json:`, e);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(`'/api/blog/${id}' Error:`, e);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}, [params]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="content-center w-full lg:mx-auto pt-16 lg:pt-0 relative z-20 pb-16 md:pb-0 animate-fadeIn">
|
|
||||||
<div className="w-full max-w-screen-lg mx-auto">
|
|
||||||
<div className="px-6 md:px-10 lg:px-15 xl:px-2">
|
|
||||||
<div className="pt-8 pb-6 px-8 bg-transparent-ish rounded-xl h-screen">
|
|
||||||
{blog ? (
|
|
||||||
<div>
|
|
||||||
<h1 className="text-red-400">{blog.title}</h1>
|
|
||||||
<p className="text-gray-400">
|
|
||||||
{new Date(blog.date).toDateString()}
|
|
||||||
</p>
|
|
||||||
<div className="mt-4 blog-md">
|
|
||||||
<MarkdownRenderer>
|
|
||||||
{blog.markdown
|
|
||||||
.replaceAll(/\n!\n/g, "\n<br/>\n")
|
|
||||||
.replaceAll(/\n-/g, "\n\n-")}
|
|
||||||
</MarkdownRenderer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
.blog-md h1 {
|
|
||||||
color: #fa5770;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-md a {
|
|
||||||
color: #fa5770;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-md code {
|
|
||||||
color: #fa5770;
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
type Blog = {
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
id: string;
|
|
||||||
tags: { name: string; color: string }[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Blog() {
|
|
||||||
const [blogs, setBlogs] = useState<Blog[]>([]);
|
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
|
||||||
|
|
||||||
const fetchBlogs = (query: string) => {
|
|
||||||
(query === ""
|
|
||||||
? fetch("/api/blog/")
|
|
||||||
: fetch(`/api/search/?query=${encodeURIComponent(query)}`)
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
res
|
|
||||||
.json()
|
|
||||||
.then((response) => {
|
|
||||||
if (response && response.items) {
|
|
||||||
setBlogs(response.items);
|
|
||||||
} else {
|
|
||||||
console.error("`/api/blog/` Response is invalid:", response);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error("`/api/blog/` Unable to obtain json:", e);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error("`/api/blog/` Error:", e);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handler = setTimeout(() => {
|
|
||||||
fetchBlogs(searchQuery);
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
return () => clearTimeout(handler);
|
|
||||||
}, [searchQuery]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="content-center w-full lg:mx-auto pt-16 lg:pt-0 relative z-20 pb-16 md:pb-0 animate-fadeIn">
|
|
||||||
<div className="w-full max-w-screen-lg mx-auto">
|
|
||||||
<div className="px-6 md:px-10 lg:px-15 xl:px-2">
|
|
||||||
<div className="pt-8 pb-6 px-8 bg-transparent-ish rounded-xl h-screen">
|
|
||||||
<h1 className="text-red-400 w-max mx-auto">Leo's blog</h1>
|
|
||||||
<input
|
|
||||||
type="search"
|
|
||||||
name="Blog"
|
|
||||||
id="blog-search"
|
|
||||||
className="p-3 bg-transparent border border-red rounded-xl w-72 mx-auto mt-5"
|
|
||||||
onChange={(event) => setSearchQuery(event.target.value)}
|
|
||||||
placeholder="Search"
|
|
||||||
/>
|
|
||||||
<div className="mt-10 grid gap-6 w-full lg:grid-cols-2">
|
|
||||||
{blogs.map((blog, i) => (
|
|
||||||
<div
|
|
||||||
className="p-3 px-5 h-52 border border-red rounded-xl backdrop-blur-xl"
|
|
||||||
key={i}
|
|
||||||
>
|
|
||||||
<h1 className="hover:text-red text-ellipsis overflow-hidden">
|
|
||||||
<Link href={"/blog/" + blog.id}>{blog.title}</Link>
|
|
||||||
</h1>
|
|
||||||
<p className="pt-1 max-h-[72px] overflow-hidden">
|
|
||||||
{blog.description}
|
|
||||||
</p>
|
|
||||||
<div className="flex gap-5 pt-3 flex-wrap overflow-hidden h-10">
|
|
||||||
{blog.tags.map((tag, i) => (
|
|
||||||
<span
|
|
||||||
className="inline-flex items-center rounded-md border px-2.5 py-0.5 font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 text-foreground text-xs bg-red-600/10 border-red-600"
|
|
||||||
key={i}
|
|
||||||
>
|
|
||||||
{tag.name}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -38,13 +38,4 @@ body {
|
|||||||
h1 {
|
h1 {
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
|
||||||
|
|
||||||
.skill .tooltip {
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity .3s linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skill:hover .tooltip {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
}
|
||||||
+3
-3
@@ -16,9 +16,9 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body className={`antialiased bg-black`}>
|
<body className={`antialiased bg-black`}>
|
||||||
<Background />
|
<Background>
|
||||||
<Navbar />
|
{children}
|
||||||
{children}
|
</Background>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|||||||
+43
-50
@@ -10,77 +10,70 @@ import {
|
|||||||
faReact,
|
faReact,
|
||||||
faRust,
|
faRust,
|
||||||
} from "@fortawesome/free-brands-svg-icons";
|
} from "@fortawesome/free-brands-svg-icons";
|
||||||
|
import { faJava } from "@fortawesome/free-brands-svg-icons/faJava";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="content-center w-full lg:mx-auto pt-16 lg:pt-0 relative z-20 pb-16 md:pb-0 animate-fadeIn">
|
<div className="content-center w-full lg:mx-auto pt-5 relative z-20 pb-10 animate-fadeIn">
|
||||||
<div className="w-full max-w-screen-lg mx-auto">
|
<div className="w-full max-w-screen-lg mx-auto">
|
||||||
<div className="px-8 md:px-10 lg:px-15 xl:px-24">
|
<div className="px-8 md:px-10 lg:px-15 xl:px-24">
|
||||||
<h1 className="py-2 text-gray-300">Hey, I'm Leo 👋🏻</h1>
|
<h1 className="py-2 text-gray-300">Hey, I'm Klesti! 👋🏻</h1>
|
||||||
<p className="font-semibold text-gray-300">
|
<p className="font-semibold text-gray-300">
|
||||||
A passionate software engineer and freelancer from Tirane,
|
A 15 year old Software Engineer from Tirane, Albania, with 5 years
|
||||||
Albania, specializing in full-stack web development, desktop
|
of experience, specializing in full-stack web development, desktop
|
||||||
applications, and TUI apps. I have a deep interest in low-level
|
applications, TUI apps, and hacking. I have a deep interest in
|
||||||
programming, often building projects like CPU emulators from
|
low-level programming.
|
||||||
scratch.
|
|
||||||
</p>
|
</p>
|
||||||
<div className="pt-5 flex flex-row gap-5 w-max">
|
|
||||||
<a href="https://github.com/kleo-dev/" target="blank_">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon={faGithub}
|
|
||||||
width={36}
|
|
||||||
className="text-red"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://www.linkedin.com/in/klesti-selimaj-7a0162343/"
|
|
||||||
target="blank_"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon={faLinkedin}
|
|
||||||
width={36}
|
|
||||||
className="text-red"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<a href="https://www.instagram.com/kleo.dev/" target="blank_">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon={faInstagram}
|
|
||||||
width={36}
|
|
||||||
className="text-red"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<h1 className="pt-5 text-red-400">Pinned Projects</h1>
|
|
||||||
<section className="">
|
|
||||||
<PinnedRepos />
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Experience and skill */}
|
{/* Socials and skill */}
|
||||||
<div className="pt-10 grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 bg-transparent">
|
<div className="pt-10 grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 bg-transparent">
|
||||||
{/* skill */}
|
{/* socials */}
|
||||||
|
<div className="pt-5 flex flex-row gap-5 w-max">
|
||||||
|
<a href="https://github.com/kleo-dev/" target="blank_">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faGithub}
|
||||||
|
width={36}
|
||||||
|
className="text-red"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://www.linkedin.com/in/klesti-selimaj-7a0162343/"
|
||||||
|
target="blank_"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faLinkedin}
|
||||||
|
width={36}
|
||||||
|
className="text-red"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.instagram.com/kleo.dev/" target="blank_">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faInstagram}
|
||||||
|
width={36}
|
||||||
|
className="text-red"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h1 className="pb-3 text-red-400 w-max">My Skills</h1>
|
|
||||||
<div className="p-3 bg-transparent-ish rounded-xl">
|
<div className="p-3 bg-transparent-ish rounded-xl">
|
||||||
<div className="mx-auto w-max flex flex-row gap-5">
|
<div className="mx-auto w-max flex flex-row gap-5">
|
||||||
<Skill skill="Rust" icon={faRust} />
|
<Skill skill="Rust" icon={faRust} />
|
||||||
<Skill skill="Python" icon={faPython} />
|
<Skill skill="Go" icon={faGolang} />
|
||||||
<Skill skill="Go" icon={faGolang} mt="mt-2" />
|
|
||||||
<Skill skill="JavaScript" icon={faJs} />
|
<Skill skill="JavaScript" icon={faJs} />
|
||||||
|
<Skill skill="Java" icon={faJava} classInsert="p-1" />
|
||||||
|
<Skill skill="Python" icon={faPython} />
|
||||||
<Skill skill="React" icon={faReact} />
|
<Skill skill="React" icon={faReact} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Experience */}
|
|
||||||
<div>
|
|
||||||
<h1 className="pb-3 text-red-400 w-max">My Experience</h1>
|
|
||||||
<div className="p-3 bg-transparent-ish rounded-xl">
|
|
||||||
<div className="mx-auto w-max">Soon</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h1 className="pt-5 text-red-400">Pinned Projects</h1>
|
||||||
|
<section className="">
|
||||||
|
<PinnedRepos />
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
import {
|
|
||||||
faCheck,
|
|
||||||
faCode,
|
|
||||||
faDatabase,
|
|
||||||
faRocket,
|
|
||||||
faWrench,
|
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
||||||
|
|
||||||
export default function Pricing() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{/* <Background /> */}
|
|
||||||
<div className="content-center w-full lg:mx-auto pt-16 lg:pt-0 relative z-20 pb-16 md:pb-0 animate-fadeIn">
|
|
||||||
<div className="w-full max-w-screen-lg mx-auto px-4 md:px-10">
|
|
||||||
<h1 className="pt-10 w-max mx-auto text-red-400">Pricing plans</h1>
|
|
||||||
<div className="pt-10 h-full grid grid-cols-1 lg:grid-cols-2 grid-rows-2 gap-8">
|
|
||||||
<div className="h-full rounded-xl bg-transparent-ish border border-red p-9">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="mx-auto text-red-600 w-6"
|
|
||||||
icon={faCode}
|
|
||||||
/>
|
|
||||||
<h1 className="w-max mx-auto text-red-400">Standard</h1>
|
|
||||||
<h2 className="text-2xl w-max mx-auto text-red">$25</h2>
|
|
||||||
<ul className="pt-4 list-none space-y-2">
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
24-48 hours
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Simple projects or tasks (e.g., bug fixes)
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Response via Email or Discord
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="h-full rounded-xl bg-transparent-ish border border-red p-9">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="mx-auto text-red-600 w-6"
|
|
||||||
icon={faRocket}
|
|
||||||
/>
|
|
||||||
<h1 className="w-max mx-auto text-red-400">Premium</h1>
|
|
||||||
<h2 className="text-2xl w-max mx-auto text-red">$50</h2>
|
|
||||||
<ul className="pt-4 list-none space-y-2">
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Up to a week
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Complex projects
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Large tasks (e.g., refractoring, bug hunting)
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Documenting
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="h-full rounded-xl bg-transparent-ish border border-red p-9">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="mx-auto text-red-600 w-6"
|
|
||||||
icon={faDatabase}
|
|
||||||
/>
|
|
||||||
<h1 className="w-max mx-auto text-red-400">Enterprise</h1>
|
|
||||||
<h2 className="text-2xl w-max mx-auto text-red">$200</h2>
|
|
||||||
<ul className="pt-4 list-none space-y-2">
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Up to a month
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Large, Complex projects
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Higher priority
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="h-full rounded-xl bg-transparent-ish border border-red p-9">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="mx-auto text-red-600 w-6"
|
|
||||||
icon={faWrench}
|
|
||||||
/>
|
|
||||||
<h1 className="w-max mx-auto text-red-400">Maintenance</h1>
|
|
||||||
<h2 className="text-2xl w-max mx-auto text-red">$40-150 / mo</h2>
|
|
||||||
<ul className="pt-4 list-none space-y-2">
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Weekly bug checks & fixes
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Cybersecurity pen testing
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Feature requests
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li className="flex items-center">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-green-500 mr-2"
|
|
||||||
icon={faCheck}
|
|
||||||
width={14}
|
|
||||||
/>
|
|
||||||
Performance Optimization
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="md:mx-auto md:w-max">NOTE: if the project requires more than a month there will be a extra payments</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
@keyframes move {
|
|
||||||
100% {
|
|
||||||
transform: translate3d(0, 0, 1px) rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.background {
|
|
||||||
position: absolute;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
background: #000000;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.background span {
|
|
||||||
width: 24vmin;
|
|
||||||
height: 24vmin;
|
|
||||||
border-radius: 24vmin;
|
|
||||||
backface-visibility: hidden;
|
|
||||||
position: absolute;
|
|
||||||
animation: move;
|
|
||||||
animation-duration: 6;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.background span:nth-child(0) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 24%;
|
|
||||||
left: 18%;
|
|
||||||
animation-duration: 220s;
|
|
||||||
animation-delay: -272s;
|
|
||||||
transform-origin: -5vw -4vh;
|
|
||||||
box-shadow: 48vmin 0 6.421535280295322vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(1) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 86%;
|
|
||||||
left: 77%;
|
|
||||||
animation-duration: 91s;
|
|
||||||
animation-delay: -322s;
|
|
||||||
transform-origin: 14vw 0vh;
|
|
||||||
box-shadow: -48vmin 0 6.323515398437237vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(2) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 17%;
|
|
||||||
left: 44%;
|
|
||||||
animation-duration: 248s;
|
|
||||||
animation-delay: -181s;
|
|
||||||
transform-origin: 0vw -7vh;
|
|
||||||
box-shadow: -48vmin 0 6.116084464270985vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(3) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 43%;
|
|
||||||
left: 15%;
|
|
||||||
animation-duration: 98s;
|
|
||||||
animation-delay: -211s;
|
|
||||||
transform-origin: -21vw 8vh;
|
|
||||||
box-shadow: 48vmin 0 6.907246782805462vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(4) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 66%;
|
|
||||||
left: 60%;
|
|
||||||
animation-duration: 241s;
|
|
||||||
animation-delay: -75s;
|
|
||||||
transform-origin: 15vw -9vh;
|
|
||||||
box-shadow: -48vmin 0 6.832728853871303vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(5) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 79%;
|
|
||||||
left: 87%;
|
|
||||||
animation-duration: 207s;
|
|
||||||
animation-delay: -234s;
|
|
||||||
transform-origin: -19vw 4vh;
|
|
||||||
box-shadow: -48vmin 0 6.062609002101319vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(6) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 45%;
|
|
||||||
left: 79%;
|
|
||||||
animation-duration: 243s;
|
|
||||||
animation-delay: -285s;
|
|
||||||
transform-origin: 11vw 25vh;
|
|
||||||
box-shadow: -48vmin 0 6.42616777258573vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(7) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 43%;
|
|
||||||
left: 51%;
|
|
||||||
animation-duration: 227s;
|
|
||||||
animation-delay: -181s;
|
|
||||||
transform-origin: -23vw 1vh;
|
|
||||||
box-shadow: 48vmin 0 6.831515741167314vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(8) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 21%;
|
|
||||||
left: 59%;
|
|
||||||
animation-duration: 228s;
|
|
||||||
animation-delay: -196s;
|
|
||||||
transform-origin: -23vw 23vh;
|
|
||||||
box-shadow: 48vmin 0 6.824335114512845vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(9) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 95%;
|
|
||||||
left: 81%;
|
|
||||||
animation-duration: 202s;
|
|
||||||
animation-delay: -141s;
|
|
||||||
transform-origin: 17vw 24vh;
|
|
||||||
box-shadow: 48vmin 0 6.5732268320821685vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(10) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 23%;
|
|
||||||
left: 90%;
|
|
||||||
animation-duration: 43s;
|
|
||||||
animation-delay: -406s;
|
|
||||||
transform-origin: -7vw -12vh;
|
|
||||||
box-shadow: 48vmin 0 6.1955583991481vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(11) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 6%;
|
|
||||||
left: 94%;
|
|
||||||
animation-duration: 422s;
|
|
||||||
animation-delay: -38s;
|
|
||||||
transform-origin: -5vw 16vh;
|
|
||||||
box-shadow: 48vmin 0 6.212234588070589vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(12) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 76%;
|
|
||||||
left: 22%;
|
|
||||||
animation-duration: 258s;
|
|
||||||
animation-delay: -58s;
|
|
||||||
transform-origin: -23vw -6vh;
|
|
||||||
box-shadow: 48vmin 0 6.165111619626152vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(13) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 20%;
|
|
||||||
left: 80%;
|
|
||||||
animation-duration: 363s;
|
|
||||||
animation-delay: -411s;
|
|
||||||
transform-origin: 22vw 25vh;
|
|
||||||
box-shadow: -48vmin 0 6.179675889584371vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(14) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 88%;
|
|
||||||
left: 36%;
|
|
||||||
animation-duration: 12s;
|
|
||||||
animation-delay: -69s;
|
|
||||||
transform-origin: -11vw -4vh;
|
|
||||||
box-shadow: -48vmin 0 6.07188338021629vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(15) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 97%;
|
|
||||||
left: 11%;
|
|
||||||
animation-duration: 351s;
|
|
||||||
animation-delay: -130s;
|
|
||||||
transform-origin: -16vw -18vh;
|
|
||||||
box-shadow: 48vmin 0 6.558182158209241vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(16) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 60%;
|
|
||||||
left: 99%;
|
|
||||||
animation-duration: 193s;
|
|
||||||
animation-delay: -67s;
|
|
||||||
transform-origin: 10vw 25vh;
|
|
||||||
box-shadow: 48vmin 0 6.570051729134467vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(17) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 12%;
|
|
||||||
left: 8%;
|
|
||||||
animation-duration: 166s;
|
|
||||||
animation-delay: -69s;
|
|
||||||
transform-origin: 7vw -1vh;
|
|
||||||
box-shadow: -48vmin 0 6.742868690500271vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(18) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 44%;
|
|
||||||
left: 38%;
|
|
||||||
animation-duration: 96s;
|
|
||||||
animation-delay: -279s;
|
|
||||||
transform-origin: 11vw 1vh;
|
|
||||||
box-shadow: -48vmin 0 6.261014277195781vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(19) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 96%;
|
|
||||||
left: 77%;
|
|
||||||
animation-duration: 122s;
|
|
||||||
animation-delay: -355s;
|
|
||||||
transform-origin: 6vw 3vh;
|
|
||||||
box-shadow: -48vmin 0 6.438018625575824vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(20) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 2%;
|
|
||||||
left: 81%;
|
|
||||||
animation-duration: 331s;
|
|
||||||
animation-delay: -355s;
|
|
||||||
transform-origin: 11vw -18vh;
|
|
||||||
box-shadow: -48vmin 0 6.555921470976377vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(21) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 42%;
|
|
||||||
left: 9%;
|
|
||||||
animation-duration: 439s;
|
|
||||||
animation-delay: -233s;
|
|
||||||
transform-origin: -20vw -24vh;
|
|
||||||
box-shadow: -48vmin 0 6.570997236391078vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(22) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 69%;
|
|
||||||
left: 23%;
|
|
||||||
animation-duration: 400s;
|
|
||||||
animation-delay: -390s;
|
|
||||||
transform-origin: -18vw -21vh;
|
|
||||||
box-shadow: 48vmin 0 6.279087258882428vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(23) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 33%;
|
|
||||||
left: 95%;
|
|
||||||
animation-duration: 18s;
|
|
||||||
animation-delay: -98s;
|
|
||||||
transform-origin: 22vw 8vh;
|
|
||||||
box-shadow: -48vmin 0 6.088381708804739vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(24) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 39%;
|
|
||||||
left: 69%;
|
|
||||||
animation-duration: 337s;
|
|
||||||
animation-delay: -83s;
|
|
||||||
transform-origin: 15vw -5vh;
|
|
||||||
box-shadow: -48vmin 0 6.515991392427649vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(25) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 57%;
|
|
||||||
left: 17%;
|
|
||||||
animation-duration: 126s;
|
|
||||||
animation-delay: -93s;
|
|
||||||
transform-origin: -7vw 9vh;
|
|
||||||
box-shadow: 48vmin 0 6.431063119719202vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(26) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 91%;
|
|
||||||
left: 76%;
|
|
||||||
animation-duration: 131s;
|
|
||||||
animation-delay: -256s;
|
|
||||||
transform-origin: -4vw 23vh;
|
|
||||||
box-shadow: 48vmin 0 6.370776053425152vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(27) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 44%;
|
|
||||||
left: 65%;
|
|
||||||
animation-duration: 160s;
|
|
||||||
animation-delay: -235s;
|
|
||||||
transform-origin: -23vw 12vh;
|
|
||||||
box-shadow: 48vmin 0 6.34935032141241vmin currentColor;
|
|
||||||
}
|
|
||||||
.background span:nth-child(28) {
|
|
||||||
color: #f5304c;
|
|
||||||
top: 89%;
|
|
||||||
left: 36%;
|
|
||||||
animation-duration: 298s;
|
|
||||||
animation-delay: -400s;
|
|
||||||
transform-origin: -7vw 2vh;
|
|
||||||
box-shadow: -48vmin 0 6.935061205772426vmin currentColor;
|
|
||||||
}
|
|
||||||
+184
-34
@@ -1,39 +1,189 @@
|
|||||||
import "./Background.css";
|
'use client';
|
||||||
|
|
||||||
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
export default function Background({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||||
|
const animationRef = useRef<number>(0);
|
||||||
|
const particlesRef = useRef<Particle[]>([]);
|
||||||
|
const [dimensions, setDimensions] = useState<{ width: number; height: number }>({
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Particle configuration
|
||||||
|
const config = {
|
||||||
|
particleCount: 80,
|
||||||
|
maxDistance: 120,
|
||||||
|
particleSpeed: 0.5,
|
||||||
|
particleSize: 2,
|
||||||
|
lineOpacity: 0.6,
|
||||||
|
particleOpacity: 0.8,
|
||||||
|
colors: {
|
||||||
|
particles: "#f5304c", // blue-400
|
||||||
|
connections: "#f5304c", // blue-500
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Particle class
|
||||||
|
class Particle {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
vx: number;
|
||||||
|
vy: number;
|
||||||
|
size: number;
|
||||||
|
|
||||||
|
constructor(width: number, height: number) {
|
||||||
|
this.x = Math.random() * width;
|
||||||
|
this.y = Math.random() * height;
|
||||||
|
this.vx = (Math.random() - 0.5) * config.particleSpeed;
|
||||||
|
this.vy = (Math.random() - 0.5) * config.particleSpeed;
|
||||||
|
this.size = config.particleSize + Math.random() * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(width: number, height: number) {
|
||||||
|
this.x += this.vx;
|
||||||
|
this.y += this.vy;
|
||||||
|
|
||||||
|
// Bounce off edges
|
||||||
|
if (this.x < 0 || this.x > width) {
|
||||||
|
this.vx = -this.vx;
|
||||||
|
this.x = Math.max(0, Math.min(width, this.x));
|
||||||
|
}
|
||||||
|
if (this.y < 0 || this.y > height) {
|
||||||
|
this.vy = -this.vy;
|
||||||
|
this.y = Math.max(0, Math.min(height, this.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(ctx: CanvasRenderingContext2D) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = `${config.colors.particles}${Math.round(
|
||||||
|
config.particleOpacity * 255
|
||||||
|
)
|
||||||
|
.toString(16)
|
||||||
|
.padStart(2, "0")}`;
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize particles
|
||||||
|
const initParticles = (width: number, height: number) => {
|
||||||
|
particlesRef.current = [];
|
||||||
|
for (let i = 0; i < config.particleCount; i++) {
|
||||||
|
particlesRef.current.push(new Particle(width, height));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Draw connections between nearby particles
|
||||||
|
const drawConnections = (ctx: CanvasRenderingContext2D, particles: Particle[]) => {
|
||||||
|
for (let i = 0; i < particles.length; i++) {
|
||||||
|
for (let j = i + 1; j < particles.length; j++) {
|
||||||
|
const dx = particles[i].x - particles[j].x;
|
||||||
|
const dy = particles[i].y - particles[j].y;
|
||||||
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance < config.maxDistance) {
|
||||||
|
const opacity = 1 - distance / config.maxDistance;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(particles[i].x, particles[i].y);
|
||||||
|
ctx.lineTo(particles[j].x, particles[j].y);
|
||||||
|
ctx.strokeStyle = `${config.colors.connections}${Math.round(
|
||||||
|
opacity * config.lineOpacity * 255
|
||||||
|
)
|
||||||
|
.toString(16)
|
||||||
|
.padStart(2, "0")}`;
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Animation loop
|
||||||
|
const animate = () => {
|
||||||
|
const canvas = canvasRef.current;
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
const { width, height } = dimensions;
|
||||||
|
|
||||||
|
// Clear canvas
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
|
// Update and draw particles
|
||||||
|
particlesRef.current.forEach((particle) => {
|
||||||
|
particle.update(width, height);
|
||||||
|
particle.draw(ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Draw connections
|
||||||
|
drawConnections(ctx, particlesRef.current);
|
||||||
|
|
||||||
|
animationRef.current = requestAnimationFrame(animate);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle window resize
|
||||||
|
const handleResize = () => {
|
||||||
|
const canvas = canvasRef.current;
|
||||||
|
if (!canvas || !canvas.parentElement) return;
|
||||||
|
|
||||||
|
const rect = canvas.parentElement.getBoundingClientRect();
|
||||||
|
const width = rect.width;
|
||||||
|
const height = rect.height;
|
||||||
|
|
||||||
|
const dpr = window.devicePixelRatio || 1;
|
||||||
|
canvas.width = width * dpr;
|
||||||
|
canvas.height = height * dpr;
|
||||||
|
canvas.style.width = `${width}px`;
|
||||||
|
canvas.style.height = `${height}px`;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
if (ctx) {
|
||||||
|
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset scaling before re-scaling
|
||||||
|
ctx.scale(dpr, dpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
setDimensions({ width, height });
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("resize", handleResize);
|
||||||
|
if (animationRef.current) {
|
||||||
|
cancelAnimationFrame(animationRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (dimensions.width && dimensions.height) {
|
||||||
|
initParticles(dimensions.width, dimensions.height);
|
||||||
|
animate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (animationRef.current) {
|
||||||
|
cancelAnimationFrame(animationRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [dimensions]);
|
||||||
|
|
||||||
const Background = () => {
|
|
||||||
return (
|
return (
|
||||||
<div className="background blur-2xl">
|
<div className="relative w-full min-h-screen overflow-hidden bg-black">
|
||||||
<span></span>
|
<canvas ref={canvasRef} className="absolute inset-0 w-full h-full" />
|
||||||
<span></span>
|
|
||||||
<span></span>
|
{children}
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Background;
|
|
||||||
|
|||||||
@@ -28,15 +28,6 @@ export default function Navbar() {
|
|||||||
>
|
>
|
||||||
Pricing
|
Pricing
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
|
||||||
href="/blog"
|
|
||||||
className={
|
|
||||||
"hover:text-red transition-colors duration-300" +
|
|
||||||
(pathname === "/blog" ? " text-red" : "")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Blog
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { stringify } from "querystring";
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
type PinnedRepo = {
|
type PinnedRepo = {
|
||||||
author: string;
|
author: string;
|
||||||
@@ -33,8 +35,7 @@ export function Repo({
|
|||||||
hover:shadow-md
|
hover:shadow-md
|
||||||
transition-shadow
|
transition-shadow
|
||||||
duration-300
|
duration-300
|
||||||
bg-transparent-ish
|
backdrop-blur-[2px]
|
||||||
backdrop-blur-xl
|
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
@@ -103,7 +104,8 @@ export function Repo({
|
|||||||
<span className="text-gray-300">{forks}</span>
|
<span className="text-gray-300">{forks}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
{lang && (
|
||||||
|
<div
|
||||||
className="inline-flex items-center rounded-md border px-2.5 py-0.5 font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 text-foreground text-xs bg-red-600/10 border-red-600"
|
className="inline-flex items-center rounded-md border px-2.5 py-0.5 font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 text-foreground text-xs bg-red-600/10 border-red-600"
|
||||||
data-sentry-component="Badge"
|
data-sentry-component="Badge"
|
||||||
data-sentry-source-file="badge.tsx"
|
data-sentry-source-file="badge.tsx"
|
||||||
@@ -126,6 +128,7 @@ export function Repo({
|
|||||||
</svg>
|
</svg>
|
||||||
{lang}
|
{lang}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,11 +137,21 @@ export function Repo({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function PinnedRepos() {
|
export default function PinnedRepos() {
|
||||||
try {
|
try {
|
||||||
const pinned: PinnedRepo[] = await (
|
const [pinned, setPinned] = useState<PinnedRepo[]>([]);
|
||||||
await fetch("https://pinned.berrysauce.dev/get/kleo-dev")
|
|
||||||
).json();
|
useEffect(() => {
|
||||||
|
fetch("https://pinned.berrysauce.dev/get/kleo-dev").then(r => {
|
||||||
|
r.json().then(p => {
|
||||||
|
setPinned(p);
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 bg-transparent">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 bg-transparent">
|
||||||
|
|||||||
@@ -4,16 +4,27 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
export default function Skill({
|
export default function Skill({
|
||||||
skill,
|
skill,
|
||||||
icon,
|
icon,
|
||||||
mt,
|
classInsert,
|
||||||
}: {
|
}: {
|
||||||
skill: string;
|
skill: string;
|
||||||
icon: IconProp;
|
icon: IconProp;
|
||||||
mt?: string;
|
classInsert?: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="skill">
|
<div className="relative flex items-center justify-center group">
|
||||||
<FontAwesomeIcon icon={icon} width={40} className={`text-red ${mt}`} />
|
<span
|
||||||
<span className="tooltip absolute bg-transparent-ish">{skill}</span>
|
className="absolute bottom-full mb-2 left-1/2 -translate-x-1/2
|
||||||
|
bg-black text-white text-sm px-2 py-1 rounded
|
||||||
|
opacity-0 group-hover:opacity-100 transition-opacity duration-300 whitespace-nowrap"
|
||||||
|
>
|
||||||
|
Skilled in {" "} {skill}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={icon}
|
||||||
|
width={40}
|
||||||
|
className={`text-red ${classInsert} cursor-pointer`}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user