diff --git a/.vercel/README.txt b/.vercel/README.txt new file mode 100644 index 0000000..525d8ce --- /dev/null +++ b/.vercel/README.txt @@ -0,0 +1,11 @@ +> Why do I have a folder named ".vercel" in my project? +The ".vercel" folder is created when you link a directory to a Vercel project. + +> What does the "project.json" file contain? +The "project.json" file contains: +- The ID of the Vercel project that you linked ("projectId") +- The ID of the user or team your Vercel project is owned by ("orgId") + +> Should I commit the ".vercel" folder? +No, you should not share the ".vercel" folder with anyone. +Upon creation, it will be automatically added to your ".gitignore" file. diff --git a/.vercel/project.json b/.vercel/project.json new file mode 100644 index 0000000..2940633 --- /dev/null +++ b/.vercel/project.json @@ -0,0 +1 @@ +{"projectId":"prj_mviE4QuVIY1jqwDW43dnewthkKBg","orgId":"team_qnuIc1YJcQtnGmdXyWj97YF2"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1849579..d4581e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "subjugator", "version": "0.0.0", "dependencies": { + "heic2any": "^0.0.4", "react": "^19.0.0", "react-dom": "^19.0.0", "react-icons": "^5.5.0", @@ -24,7 +25,7 @@ "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.18", "globals": "^15.14.0", - "vite": "^6.1.0" + "vite": "^6.3.5" } }, "node_modules/@ampproject/remapping": { @@ -324,14 +325,13 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -341,14 +341,13 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -358,14 +357,13 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -375,14 +373,13 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -392,14 +389,13 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -409,14 +405,13 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -426,14 +421,13 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -443,14 +437,13 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -460,14 +453,13 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -477,14 +469,13 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -494,14 +485,13 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -511,14 +501,13 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -528,14 +517,13 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", "cpu": [ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -545,14 +533,13 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -562,14 +549,13 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -579,14 +565,13 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -596,14 +581,13 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -613,14 +597,13 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -630,14 +613,13 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -647,14 +629,13 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -664,14 +645,13 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -681,14 +661,13 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -698,14 +677,13 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -715,14 +693,13 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -732,14 +709,13 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1009,266 +985,260 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", - "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz", + "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", - "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz", + "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", - "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz", + "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", - "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz", + "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", - "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz", + "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", - "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz", + "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", - "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz", + "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", - "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz", + "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", - "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz", + "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", - "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz", + "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", - "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz", + "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", - "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz", + "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", - "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz", + "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz", + "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", - "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz", + "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", - "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz", + "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", - "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz", + "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", - "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz", + "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", - "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz", + "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", - "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz", + "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1326,11 +1296,10 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT" + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -2143,12 +2112,11 @@ } }, "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -2156,31 +2124,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" } }, "node_modules/escalade": { @@ -2437,6 +2405,20 @@ "dev": true, "license": "MIT" }, + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -2510,7 +2492,6 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -2777,6 +2758,11 @@ "node": ">= 0.4" } }, + "node_modules/heic2any": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/heic2any/-/heic2any-0.0.4.tgz", + "integrity": "sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA==" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3667,6 +3653,18 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -3898,13 +3896,12 @@ } }, "node_modules/rollup": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", - "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz", + "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==", "dev": true, - "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -3914,25 +3911,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.8", - "@rollup/rollup-android-arm64": "4.34.8", - "@rollup/rollup-darwin-arm64": "4.34.8", - "@rollup/rollup-darwin-x64": "4.34.8", - "@rollup/rollup-freebsd-arm64": "4.34.8", - "@rollup/rollup-freebsd-x64": "4.34.8", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", - "@rollup/rollup-linux-arm-musleabihf": "4.34.8", - "@rollup/rollup-linux-arm64-gnu": "4.34.8", - "@rollup/rollup-linux-arm64-musl": "4.34.8", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", - "@rollup/rollup-linux-riscv64-gnu": "4.34.8", - "@rollup/rollup-linux-s390x-gnu": "4.34.8", - "@rollup/rollup-linux-x64-gnu": "4.34.8", - "@rollup/rollup-linux-x64-musl": "4.34.8", - "@rollup/rollup-win32-arm64-msvc": "4.34.8", - "@rollup/rollup-win32-ia32-msvc": "4.34.8", - "@rollup/rollup-win32-x64-msvc": "4.34.8", + "@rollup/rollup-android-arm-eabi": "4.44.0", + "@rollup/rollup-android-arm64": "4.44.0", + "@rollup/rollup-darwin-arm64": "4.44.0", + "@rollup/rollup-darwin-x64": "4.44.0", + "@rollup/rollup-freebsd-arm64": "4.44.0", + "@rollup/rollup-freebsd-x64": "4.44.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.0", + "@rollup/rollup-linux-arm-musleabihf": "4.44.0", + "@rollup/rollup-linux-arm64-gnu": "4.44.0", + "@rollup/rollup-linux-arm64-musl": "4.44.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-musl": "4.44.0", + "@rollup/rollup-linux-s390x-gnu": "4.44.0", + "@rollup/rollup-linux-x64-gnu": "4.44.0", + "@rollup/rollup-linux-x64-musl": "4.44.0", + "@rollup/rollup-win32-arm64-msvc": "4.44.0", + "@rollup/rollup-win32-ia32-msvc": "4.44.0", + "@rollup/rollup-win32-x64-msvc": "4.44.0", "fsevents": "~2.3.2" } }, @@ -4314,6 +4312,22 @@ "integrity": "sha512-nNE3pnTHxXN/Phw768u0Grr7W4+rumGg/H6PgeseNJojkJtmeHJfZWi41Gp2mpXl1pg1pf1zjwR4McM1jTqkpg==", "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/turbo-stream": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", @@ -4472,15 +4486,17 @@ } }, "node_modules/vite": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz", - "integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, - "license": "MIT", "dependencies": { - "esbuild": "^0.24.2", - "postcss": "^8.5.2", - "rollup": "^4.30.1" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" diff --git a/package.json b/package.json index 06a8501..d8d8b79 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "heic2any": "^0.0.4", "react": "^19.0.0", "react-dom": "^19.0.0", "react-icons": "^5.5.0", @@ -26,6 +27,6 @@ "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.18", "globals": "^15.14.0", - "vite": "^6.1.0" + "vite": "^6.3.5" } } diff --git a/public/assets/advanced-autonomy.png b/public/assets/advanced-autonomy.png new file mode 100644 index 0000000..4fe69fe Binary files /dev/null and b/public/assets/advanced-autonomy.png differ diff --git a/public/assets/logo.png b/public/assets/logo.png new file mode 100644 index 0000000..0822acc Binary files /dev/null and b/public/assets/logo.png differ diff --git a/public/assets/people/adam_hamdan.png b/public/assets/people/adam_hamdan.png new file mode 100644 index 0000000..4a0c9af Binary files /dev/null and b/public/assets/people/adam_hamdan.png differ diff --git a/public/assets/people/adam_mcaleer.png b/public/assets/people/adam_mcaleer.png new file mode 100644 index 0000000..76cf73e Binary files /dev/null and b/public/assets/people/adam_mcaleer.png differ diff --git a/public/assets/people/adrian_fernandez.png b/public/assets/people/adrian_fernandez.png new file mode 100644 index 0000000..e6cfe3b Binary files /dev/null and b/public/assets/people/adrian_fernandez.png differ diff --git a/public/assets/people/alex_johnson.png b/public/assets/people/alex_johnson.png new file mode 100644 index 0000000..f8e945b Binary files /dev/null and b/public/assets/people/alex_johnson.png differ diff --git a/public/assets/people/cameron_brown.jpeg b/public/assets/people/cameron_brown.jpeg new file mode 100644 index 0000000..3965348 Binary files /dev/null and b/public/assets/people/cameron_brown.jpeg differ diff --git a/public/assets/people/carlos_chavez.png b/public/assets/people/carlos_chavez.png new file mode 100644 index 0000000..7e69bd8 Binary files /dev/null and b/public/assets/people/carlos_chavez.png differ diff --git a/public/assets/people/daniel_parra.png b/public/assets/people/daniel_parra.png new file mode 100644 index 0000000..73a933b Binary files /dev/null and b/public/assets/people/daniel_parra.png differ diff --git a/public/assets/people/ethan_mitchell.png b/public/assets/people/ethan_mitchell.png new file mode 100644 index 0000000..303187d Binary files /dev/null and b/public/assets/people/ethan_mitchell.png differ diff --git a/public/assets/people/joseph_goodman.png b/public/assets/people/joseph_goodman.png new file mode 100644 index 0000000..96f2416 Binary files /dev/null and b/public/assets/people/joseph_goodman.png differ diff --git a/public/assets/people/keith_khadar.jpg b/public/assets/people/keith_khadar.jpg new file mode 100644 index 0000000..b7b2c04 Binary files /dev/null and b/public/assets/people/keith_khadar.jpg differ diff --git a/public/assets/people/lester_bonilla.jpg b/public/assets/people/lester_bonilla.jpg new file mode 100644 index 0000000..0f8ec97 Binary files /dev/null and b/public/assets/people/lester_bonilla.jpg differ diff --git a/public/assets/people/lorant_domokos.png b/public/assets/people/lorant_domokos.png new file mode 100644 index 0000000..91425a6 Binary files /dev/null and b/public/assets/people/lorant_domokos.png differ diff --git a/public/assets/people/ryan_hoburg.png b/public/assets/people/ryan_hoburg.png new file mode 100644 index 0000000..afd4552 Binary files /dev/null and b/public/assets/people/ryan_hoburg.png differ diff --git a/public/assets/robosub_logo.png b/public/assets/robosub_logo.png new file mode 100644 index 0000000..5fd49c0 Binary files /dev/null and b/public/assets/robosub_logo.png differ diff --git a/public/assets/robosub_preparation.png b/public/assets/robosub_preparation.png new file mode 100644 index 0000000..1f94864 Binary files /dev/null and b/public/assets/robosub_preparation.png differ diff --git a/public/assets/simulation_enviornment.png b/public/assets/simulation_enviornment.png new file mode 100644 index 0000000..128a5f1 Binary files /dev/null and b/public/assets/simulation_enviornment.png differ diff --git a/public/assets/sponsors/JD-squared-transparent.png b/public/assets/sponsors/JD-squared-transparent.png new file mode 100644 index 0000000..40cb0d1 Binary files /dev/null and b/public/assets/sponsors/JD-squared-transparent.png differ diff --git a/public/assets/sponsors/MAE_logo.png b/public/assets/sponsors/MAE_logo.png new file mode 100644 index 0000000..13443fd Binary files /dev/null and b/public/assets/sponsors/MAE_logo.png differ diff --git a/public/assets/sponsors/Sylphase.png b/public/assets/sponsors/Sylphase.png new file mode 100644 index 0000000..3b53cf7 Binary files /dev/null and b/public/assets/sponsors/Sylphase.png differ diff --git a/public/assets/sponsorship_packet.pdf b/public/assets/sponsorship_packet.pdf new file mode 100644 index 0000000..d06cc9a Binary files /dev/null and b/public/assets/sponsorship_packet.pdf differ diff --git a/public/assets/subjugator8-hero.png b/public/assets/subjugator8-hero.png new file mode 100644 index 0000000..655200b Binary files /dev/null and b/public/assets/subjugator8-hero.png differ diff --git a/public/assets/submarine-blueprint.png b/public/assets/submarine-blueprint.png new file mode 100644 index 0000000..2373874 Binary files /dev/null and b/public/assets/submarine-blueprint.png differ diff --git a/public/assets/submarines/sub9_1.jpeg b/public/assets/submarines/sub9_1.jpeg new file mode 100644 index 0000000..810df6b Binary files /dev/null and b/public/assets/submarines/sub9_1.jpeg differ diff --git a/public/assets/submarines/sub9_cherry_1.png b/public/assets/submarines/sub9_cherry_1.png new file mode 100644 index 0000000..53b5b68 Binary files /dev/null and b/public/assets/submarines/sub9_cherry_1.png differ diff --git a/public/assets/submarines/sub9_development.jpg b/public/assets/submarines/sub9_development.jpg new file mode 100644 index 0000000..a9a89fb Binary files /dev/null and b/public/assets/submarines/sub9_development.jpg differ diff --git a/public/assets/submarines/sub9_frame.png b/public/assets/submarines/sub9_frame.png new file mode 100644 index 0000000..810d8c9 Binary files /dev/null and b/public/assets/submarines/sub9_frame.png differ diff --git a/public/assets/submarines/subjugator_1.png b/public/assets/submarines/subjugator_1.png new file mode 100644 index 0000000..bf0c4eb Binary files /dev/null and b/public/assets/submarines/subjugator_1.png differ diff --git a/public/assets/submarines/subjugator_3.png b/public/assets/submarines/subjugator_3.png new file mode 100644 index 0000000..66f3969 Binary files /dev/null and b/public/assets/submarines/subjugator_3.png differ diff --git a/public/assets/submarines/subjugator_6.png b/public/assets/submarines/subjugator_6.png new file mode 100644 index 0000000..ae5a0aa Binary files /dev/null and b/public/assets/submarines/subjugator_6.png differ diff --git a/public/assets/submarines/subjugator_8.png b/public/assets/submarines/subjugator_8.png new file mode 100644 index 0000000..24ae1e3 Binary files /dev/null and b/public/assets/submarines/subjugator_8.png differ diff --git a/public/assets/submarines/subjugator_9.1.png b/public/assets/submarines/subjugator_9.1.png new file mode 100644 index 0000000..4189d8c Binary files /dev/null and b/public/assets/submarines/subjugator_9.1.png differ diff --git a/public/assets/submarines/subjugator_9.png b/public/assets/submarines/subjugator_9.png new file mode 100644 index 0000000..a50f54a Binary files /dev/null and b/public/assets/submarines/subjugator_9.png differ diff --git a/public/assets/team-photo.jpg b/public/assets/team-photo.jpg new file mode 100644 index 0000000..107766e Binary files /dev/null and b/public/assets/team-photo.jpg differ diff --git a/src/App.css b/src/App.css index b9d355d..2f3fce3 100644 --- a/src/App.css +++ b/src/App.css @@ -1,3 +1,7 @@ +:root { + --navbar-height: 80px; +} + #root { max-width: 1280px; margin: 0 auto; @@ -40,3 +44,7 @@ .read-the-docs { color: #888; } + +.main-content { + padding-top: var(--navbar-height); +} diff --git a/src/App.jsx b/src/App.jsx index fee585b..8c86e47 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,7 @@ -// App.jsx import React from "react"; -import { Routes, Route } from "react-router-dom"; +import { Routes, Route, useLocation } from "react-router-dom"; import Navbar from "./Components/Navbar"; +import ScrollToTop from "./Pages/ScrollToTop"; import Home from "./Pages/Home"; import AboutUs from "./Pages/AboutUs"; import Contact from "./Pages/Contact"; @@ -12,10 +12,14 @@ import OurTeam from "./Pages/OurTeam"; import "./App.css"; function App() { + const location = useLocation(); + const isHome = location.pathname === "/"; + return (
-
+ +
} /> } /> @@ -26,9 +30,8 @@ function App() { } />
- {/* We'll add a footer component later */}
); } -export default App; \ No newline at end of file +export default App; diff --git a/src/Components/Navbar.css b/src/Components/Navbar.css index 504a04a..1fcd05e 100644 --- a/src/Components/Navbar.css +++ b/src/Components/Navbar.css @@ -24,12 +24,16 @@ padding: 0 var(--space-lg); } + .nav-logo { - height: 45px; - width: auto; + --logo-h: clamp(135px, 6vw, 130px); + height: var(--logo-h); + width: calc(var(--logo-h) * 3.1); + background: url("/src/assets/subjugator_logo.png") center/contain no-repeat; transition: opacity var(--transition-fast); } + .nav-logo:hover { opacity: 0.8; } diff --git a/src/Components/Navbar.jsx b/src/Components/Navbar.jsx index 2f72180..2ce67b7 100644 --- a/src/Components/Navbar.jsx +++ b/src/Components/Navbar.jsx @@ -46,12 +46,7 @@ function Navbar() {
{/* Logo */} - - SubjuGator Logo + {/* Navigation */} diff --git a/src/Pages/AUVTechnology.jsx b/src/Pages/AUVTechnology.jsx index 000a38d..7adb1eb 100644 --- a/src/Pages/AUVTechnology.jsx +++ b/src/Pages/AUVTechnology.jsx @@ -1,54 +1,78 @@ import React, { useEffect, useRef, useState } from "react"; -import { Link } from "react-router-dom"; +import { useLocation, Link } from "react-router-dom"; import { FaCogs, FaBolt, FaLaptopCode, FaInfoCircle, - FaArrowsAlt, FaExpand, } from "react-icons/fa"; import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import "../styles/AUVTechnology.css"; - -// Helper component for hotspots that appear on the 3D model -const Hotspot = ({ id, title, isActive, onClick }) => { - return ( -
-
- -
-
{title}
+import techReport from "../assets/Design_and_Development_of_SubjuGator_9.pdf"; + +// Hotspot button on the model +const Hotspot = ({ id, title, isActive, onClick }) => ( +
+
+
- ); -}; +
{title}
+
+); + +// Specification card below the 3D canvas +const SpecCard = ({ icon, title, description, list }) => ( +
+
{icon}
+

{title}

+

{description}

+ {list && ( +
    + {list.map((item, i) => ( +
  • {item}
  • + ))} +
+ )} +
+); + +export default function AUVTechnology() { + const location = useLocation(); + + // 1) Keep --vh up to date for mobile address-bar hiding + useEffect(() => { + const setVh = () => + document.documentElement.style.setProperty( + "--vh", + `${window.innerHeight * 0.01}px` + ); + setVh(); + window.addEventListener("resize", setVh); + window.addEventListener("orientationchange", setVh); + return () => { + window.removeEventListener("resize", setVh); + window.removeEventListener("orientationchange", setVh); + }; + }, []); -// Helper component for technical specifications -const SpecCard = ({ icon, title, description, list }) => { - return ( -
-
{icon}
-

{title}

-

{description}

- {list && ( -
    - {list.map((item, index) => ( -
  • {item}
  • - ))} -
- )} -
- ); -}; + // 2) Smooth-scroll to anchors + useEffect(() => { + if (location.hash) { + setTimeout(() => { + const el = document.querySelector(location.hash); + if (el) el.scrollIntoView({ behavior: "smooth" }); + }, 100); + } + }, [location.hash]); -function AUVTechnology() { - // Refs for DOM elements and Three.js objects + // Three.js refs const canvasContainerRef = useRef(null); const canvasRef = useRef(null); const sceneRef = useRef(null); @@ -56,101 +80,25 @@ function AUVTechnology() { const rendererRef = useRef(null); const controlsRef = useRef(null); const modelRef = useRef(null); - const animationFrameRef = useRef(null); + const frameRef = useRef(null); - // State for UI and interactions - const [activeSection, setActiveSection] = useState("overview"); + // UI state const [activeHotspot, setActiveHotspot] = useState(null); const [isLoading, setIsLoading] = useState(true); - const [viewMode, setViewMode] = useState("complete"); // complete or exploded - const [infoVisible, setInfoVisible] = useState(true); const [isModelLoaded, setIsModelLoaded] = useState(false); + const [viewMode, setViewMode] = useState("complete"); + const [infoVisible, setInfoVisible] = useState(true); - // Define hotspots to display on the model + // Hotspot definitions const hotspots = [ - { - id: "thrusters", - title: "Thrusters", - position: { x: 0.3, y: 0.1, z: 0.2 }, - }, - { - id: "camera", - title: "Vision System", - position: { x: -0.2, y: 0.15, z: 0.3 }, - }, - { id: "mainHull", title: "Main Hull", position: { x: 0, y: 0, z: 0 } }, - { - id: "torpedos", - title: "Torpedo System", - position: { x: 0.4, y: 0, z: -0.2 }, - }, - { - id: "gripper", - title: "Gripper", - position: { x: -0.35, y: -0.1, z: 0.15 }, - }, + { id: "thrusters", title: "Thrusters" }, + { id: "camera", title: "Vision System" }, + { id: "mainHull", title: "Main Hull" }, + { id: "torpedos", title: "Torpedo System" }, + { id: "gripper", title: "Gripper" }, ]; - // Function to update hotspot positions - now inside the component - const updateHotspotPositions = () => { - if ( - !modelRef.current || - !cameraRef.current || - !sceneRef.current || - !canvasRef.current - ) - return; - - // Get the canvas dimensions for calculations - const canvas = canvasRef.current; - const rect = canvas.getBoundingClientRect(); - - // - Thrusters are now positioned at the rear (underside) - // - Camera (vision system) is raised on the front - // - Main Hull remains centered - // - Torpedo system is placed on the front right - // - Gripper is placed on the front left - const attachmentPoints = { - thrusters: new THREE.Vector3(0, -0.1, -0.3), - camera: new THREE.Vector3(0, 0.05, 0.2), - mainHull: new THREE.Vector3(0, 0, 0), - torpedos: new THREE.Vector3(0.1, -0.01, 0.15), - gripper: new THREE.Vector3(-0.5, 0.1, -0.35), - }; - - hotspots.forEach((hotspot) => { - if (!attachmentPoints[hotspot.id]) return; - const point = attachmentPoints[hotspot.id].clone(); - - // Convert model space to world space - if (modelRef.current) { - const worldMatrix = modelRef.current.matrixWorld.clone(); - point.applyMatrix4(worldMatrix); - } - - // Project 3D point to 2D screen coordinates - point.project(cameraRef.current); - - // Convert to CSS coordinates - const x = (point.x * 0.5 + 0.5) * rect.width; - const y = (-point.y * 0.5 + 0.5) * rect.height; - - // Check if point is in front of the camera (z between -1 and 1 after projection) - const visible = point.z > -1 && point.z < 1; - - // Update hotspot DOM element position - const hotspotElement = document.querySelector( - `.model-hotspot[data-id="${hotspot.id}"]` - ); - if (hotspotElement) { - hotspotElement.style.left = `${x}px`; - hotspotElement.style.top = `${y}px`; - hotspotElement.style.visibility = visible ? "visible" : "hidden"; - } - }); - }; - - // Technical specifications for each system + // Technical specifications data const technicalSpecs = { mechanical: { icon: , @@ -158,10 +106,10 @@ function AUVTechnology() { description: "SubjuGator features precision-engineered mechanical systems, including servo-actuated mechanisms and a carbon fiber frame.", list: [ - "Servo-actuated gripper with serrated aluminum jaws", + "Servo-actuated gripper with serrated jaws", "Dual torpedo launchers with rack and pinion actuators", - "Marker dropper with rotational mechanism", - "Eight-thruster configuration for redundant motion control", + "Ball dropper with rotational mechanism", + "Eight-thruster configuration for robust motion control", "Carbon fiber and aluminum space-frame chassis", ], }, @@ -172,7 +120,6 @@ function AUVTechnology() { "Custom-designed electrical infrastructure provides reliable power, communications, and sensor integration.", list: [ "Battery monitoring system with voltage and current tracking", - "CAN bus for internal communications", "Water-cooling system for optimal thermal management", "Custom thruster/kill board for safety and control", "Multi-level power regulation for various subsystems", @@ -184,7 +131,7 @@ function AUVTechnology() { description: "Built on ROS (Robot Operating System), SubjuGator's software enables advanced autonomy and perception.", list: [ - "Custom state estimation using unscented Kalman filter", + "Custom state estimation using Extended Kalman filter", "Trajectory generation and control system", "Computer vision with deep neural networks (YOLO)", "Asynchronous mission planning infrastructure", @@ -193,42 +140,28 @@ function AUVTechnology() { }, }; - // Initialize Three.js scene + // Initialize Three.js scene, lights, camera, controls, loader, animate useEffect(() => { if (!canvasRef.current) return; - // Create scene, camera, renderer + // Scene const scene = new THREE.Scene(); - sceneRef.current = scene; scene.background = new THREE.Color(0x050505); + sceneRef.current = scene; - // Adjusted lighting setup for better visibility without making the model pure white - const ambientLight = new THREE.AmbientLight(0xffffff, 1.2); // Reduced from 2.5 - scene.add(ambientLight); - - // Make the directional light a bit more subtle - const mainLight = new THREE.DirectionalLight(0xffffff, 1.8); // Reduced from 3 - mainLight.position.set(2, 5, 5); - scene.add(mainLight); - - // Add a spotlight to highlight the front of the model - const spotlight = new THREE.SpotLight(0xffffff, 1.5); // Reduced from 3 - spotlight.position.set(0, 0, 10); - spotlight.angle = Math.PI / 6; - spotlight.penumbra = 0.5; - spotlight.distance = 20; - spotlight.decay = 0.5; - scene.add(spotlight); - - // Make the colored accent lights more subtle - const blueLight = new THREE.PointLight(0x4a9fff, 1.8, 15); // Reduced from 3 - blueLight.position.set(-3, 2, 3); - scene.add(blueLight); - - const orangeLight = new THREE.PointLight(0xfa4616, 1.8, 15); // Reduced from 3 - orangeLight.position.set(3, -2, -3); - scene.add(orangeLight); - // Create and position camera + // Lights + scene.add(new THREE.AmbientLight(0xffffff, 1.2)); + const dir = new THREE.DirectionalLight(0xffffff, 1.8); + dir.position.set(2, 5, 5); + scene.add(dir); + const spot = new THREE.SpotLight(0xffffff, 1.5); + spot.position.set(0, 0, 10); + spot.angle = Math.PI / 6; + scene.add(spot); + scene.add(new THREE.PointLight(0x4a9fff, 1.8, 15)); + scene.add(new THREE.PointLight(0xfa4616, 1.8, 15)); + + // Camera const container = canvasContainerRef.current; const camera = new THREE.PerspectiveCamera( 45, @@ -236,689 +169,274 @@ function AUVTechnology() { 0.1, 1000 ); - cameraRef.current = camera; camera.position.set(0, 0, 2); + cameraRef.current = camera; - // Create WebGL renderer + // Renderer const renderer = new THREE.WebGLRenderer({ canvas: canvasRef.current, antialias: true, alpha: true, }); - rendererRef.current = renderer; - renderer.setSize(container.clientWidth, container.clientHeight); renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(container.clientWidth, container.clientHeight); + rendererRef.current = renderer; - // Add orbit controls for user interaction + // Controls const controls = new OrbitControls(camera, renderer.domElement); - controlsRef.current = controls; controls.enableDamping = true; controls.dampingFactor = 0.05; - controls.enableZoom = true; - controls.enablePan = true; controls.autoRotate = true; controls.autoRotateSpeed = 0.5; + controlsRef.current = controls; - // Animation loop - const animate = () => { - animationFrameRef.current = requestAnimationFrame(animate); - - if (controlsRef.current) { - controlsRef.current.update(); - } - - if (rendererRef.current && sceneRef.current && cameraRef.current) { - rendererRef.current.render(sceneRef.current, cameraRef.current); - updateHotspotPositions(); // Now properly defined within component scope - } - }; - - // Start animation loop - animate(); - - // Handle window resize - const handleResize = () => { - if (!cameraRef.current || !rendererRef.current || !container) return; - - const width = container.clientWidth; - const height = container.clientHeight; - - cameraRef.current.aspect = width / height; - cameraRef.current.updateProjectionMatrix(); - - rendererRef.current.setSize(width, height); - }; - - window.addEventListener("resize", handleResize); - - // Load 3D model using GLTFLoader + // Load model const loader = new GLTFLoader(); - - // Try loading the actual GLTF model loader.load( - "/models/subjugator.glb", // Path to model in public folder + "/models/subjugator.glb", (gltf) => { const model = gltf.scene; - modelRef.current = model; scene.add(model); + modelRef.current = model; - // Center the model + // center & scale const box = new THREE.Box3().setFromObject(model); const center = box.getCenter(new THREE.Vector3()); - model.position.x = -center.x; - model.position.y = -center.y; - model.position.z = -center.z; - - // Scale the model if needed - const size = box.getSize(new THREE.Vector3()); - const maxDim = Math.max(size.x, size.y, size.z); - if (maxDim > 5) { - const scale = 5 / maxDim; - model.scale.set(scale, scale, scale); - } - - // Store original positions for exploded view - model.traverse((child) => { - if (child.isMesh) { - if (child.material) { - child.material.needsUpdate = true; - child.material.emissive = new THREE.Color(0x111111); - child.material.emissiveIntensity = 0.1; - child.material.metalness = 0.4; - child.material.roughness = 0.2; - } - child.userData.originalPosition = child.position.clone(); + model.position.sub(center); + const size = box.getSize(new THREE.Vector3()).length(); + if (size > 5) model.scale.setScalar(5 / size); + + model.traverse((c) => { + if (c.isMesh) { + c.userData.originalPosition = c.position.clone(); + c.material.emissive = new THREE.Color(0x111111); + c.material.emissiveIntensity = 0.1; + c.material.metalness = 0.4; + c.material.roughness = 0.2; } }); setIsModelLoaded(true); setIsLoading(false); }, - // Progress callback - (xhr) => { - console.log((xhr.loaded / xhr.total) * 100 + "% loaded"); - }, - // Error callback - fallback to temporary model if loading fails - (error) => { - console.error("Error loading model:", error); - // Create a temporary model as fallback - const model = createTemporaryModel(); - modelRef.current = model; - scene.add(model); - - // Simulate loading time - setTimeout(() => { - setIsLoading(false); - setIsModelLoaded(true); - }, 1000); + undefined, + (err) => { + console.error("Model load error:", err); + setIsLoading(false); + setIsModelLoaded(true); } ); - // Fallback model creation function - const createTemporaryModel = () => { - // Create a temporary submarine-like shape - const group = new THREE.Group(); - - // Main hull - cylinder - const hullGeometry = new THREE.CylinderGeometry(0.5, 0.5, 2, 32); - const hullMaterial = new THREE.MeshStandardMaterial({ - color: 0x888888, - metalness: 0.6, - roughness: 0.4, - emissive: 0x111111, - emissiveIntensity: 0.1, - }); - const hull = new THREE.Mesh(hullGeometry, hullMaterial); - hull.rotation.x = Math.PI / 2; - hull.userData.originalPosition = hull.position.clone(); - hull.userData.id = "mainHull"; - group.add(hull); - - // Nose cone - const noseGeometry = new THREE.ConeGeometry(0.5, 0.8, 32); - const noseMaterial = new THREE.MeshStandardMaterial({ - color: 0x333333, - metalness: 0.8, - roughness: 0.2, - }); - const nose = new THREE.Mesh(noseGeometry, noseMaterial); - nose.rotation.x = -Math.PI / 2; - nose.position.z = 1.4; - nose.userData.originalPosition = nose.position.clone(); - group.add(nose); - - // Thrusters - const thrusterGeometry = new THREE.CylinderGeometry(0.15, 0.15, 0.3, 16); - const thrusterMaterial = new THREE.MeshStandardMaterial({ - color: 0x222222, - metalness: 0.9, - roughness: 0.1, - }); - - // Create 8 thrusters positioned around the hull - const thrusterPositions = [ - { x: 0.6, y: 0.6, z: -0.5 }, - { x: -0.6, y: 0.6, z: -0.5 }, - { x: 0.6, y: -0.6, z: -0.5 }, - { x: -0.6, y: -0.6, z: -0.5 }, - { x: 0.6, y: 0.6, z: 0.5 }, - { x: -0.6, y: 0.6, z: 0.5 }, - { x: 0.6, y: -0.6, z: 0.5 }, - { x: -0.6, y: -0.6, z: 0.5 }, - ]; - - thrusterPositions.forEach((pos, index) => { - const thruster = new THREE.Mesh(thrusterGeometry, thrusterMaterial); - thruster.position.set(pos.x, pos.y, pos.z); - thruster.rotation.x = Math.PI / 2; - thruster.userData.originalPosition = thruster.position.clone(); - thruster.userData.id = "thrusters"; - group.add(thruster); - }); - - // Camera dome - const cameraGeometry = new THREE.SphereGeometry( - 0.2, - 32, - 32, - 0, - Math.PI * 2, - 0, - Math.PI / 2 - ); - const cameraMaterial = new THREE.MeshStandardMaterial({ - color: 0x3366ff, - transparent: true, - opacity: 0.7, - }); - const camera = new THREE.Mesh(cameraGeometry, cameraMaterial); - camera.position.set(0, -0.5, 1); - camera.rotation.x = Math.PI; - camera.userData.originalPosition = camera.position.clone(); - camera.userData.id = "camera"; - group.add(camera); - - // Add orange accent - const accentGeometry = new THREE.BoxGeometry(0.1, 0.1, 2.5); - const accentMaterial = new THREE.MeshStandardMaterial({ - color: 0xfa4616, - }); - const accent = new THREE.Mesh(accentGeometry, accentMaterial); - accent.position.set(0, 0.53, 0); - accent.userData.originalPosition = accent.position.clone(); - group.add(accent); - - return group; + // Animation loop + const animate = () => { + frameRef.current = requestAnimationFrame(animate); + controls.update(); + renderer.render(scene, camera); + // updateHotspots(); }; + animate(); - // Clean up on component unmount + // Resize handler + const onResize = () => { + const w = container.clientWidth; + const h = container.clientHeight; + camera.aspect = w / h; + camera.updateProjectionMatrix(); + renderer.setSize(w, h); + }; + window.addEventListener("resize", onResize); return () => { - window.removeEventListener("resize", handleResize); - - if (animationFrameRef.current) { - cancelAnimationFrame(animationFrameRef.current); - } - - if (rendererRef.current) { - rendererRef.current.dispose(); - } - - if (sceneRef.current) { - // Clean up Three.js objects - while (sceneRef.current.children.length > 0) { - const object = sceneRef.current.children[0]; - sceneRef.current.remove(object); - } - } + window.removeEventListener("resize", onResize); + cancelAnimationFrame(frameRef.current); + renderer.dispose(); }; }, []); - // Handle exploded view toggle + // Exploded / complete toggle useEffect(() => { if (!modelRef.current) return; - - if (viewMode === "exploded") { - // Move parts apart to create an exploded view - modelRef.current.traverse((child) => { - if (child.isMesh && child.userData.originalPosition) { - // Calculate direction from center - const direction = new THREE.Vector3(); - direction - .subVectors(child.position, new THREE.Vector3(0, 0, 0)) - .normalize(); - - // Store current position before exploding - child.userData.preExplodedPosition = child.position.clone(); - - // Move outward - const explosionDistance = 1.5; - child.position.add(direction.multiplyScalar(explosionDistance)); - } - }); - } else { - // Reset to original positions - modelRef.current.traverse((child) => { - if (child.isMesh) { - if (child.userData.preExplodedPosition) { - child.position.copy(child.userData.preExplodedPosition); - } else if (child.userData.originalPosition) { - child.position.copy(child.userData.originalPosition); - } - } - }); - } - }, [viewMode]); - - // Handle scroll effect to show different sections - useEffect(() => { - const handleScroll = () => { - const scrollY = window.scrollY; - const windowHeight = window.innerHeight; - - // Determine active section based on scroll position - const sections = document.querySelectorAll(".section"); - sections.forEach((section) => { - const rect = section.getBoundingClientRect(); - const sectionId = section.id; - - if (rect.top < windowHeight / 2 && rect.bottom > windowHeight / 2) { - setActiveSection(sectionId); - } - }); - - // Parallax effect for certain elements - const parallaxElements = document.querySelectorAll(".parallax"); - parallaxElements.forEach((element) => { - if (element.dataset && element.dataset.speed) { - const speed = parseFloat(element.dataset.speed) || 0.2; - element.style.transform = `translateY(${scrollY * speed}px)`; - } - }); - - // Optional: Adjust camera or model position based on scroll - if (modelRef.current && controlsRef.current) { - // Example: Rotate model slightly based on scroll - modelRef.current.rotation.y = scrollY * 0.001; + modelRef.current.traverse((c) => { + if (!c.isMesh || !c.userData.originalPosition) return; + if (viewMode === "exploded") { + const dir = c.position.clone().normalize().multiplyScalar(1.5); + c.position.copy(c.userData.originalPosition).add(dir); + } else { + c.position.copy(c.userData.originalPosition); } - }; - - window.addEventListener("scroll", handleScroll); - return () => window.removeEventListener("scroll", handleScroll); - }, []); + }); + }, [viewMode]); - // Control auto-rotation based on user interaction + // Interaction handlers const handleModelInteraction = () => { - if (controlsRef.current) { - controlsRef.current.autoRotate = false; - - // Resume auto-rotation after a period of inactivity - clearTimeout(controlsRef.current.userData.rotationTimeout); - controlsRef.current.userData.rotationTimeout = setTimeout(() => { - if (controlsRef.current) { - controlsRef.current.autoRotate = true; - } - }, 5000); - } + if (controlsRef.current) controlsRef.current.autoRotate = false; }; - // Handle hotspot clicks - const handleHotspotClick = (hotspotId) => { - // Toggle logic - if clicking the already active hotspot, deselect it - if (activeHotspot === hotspotId) { - setActiveHotspot(null); // Deselect the hotspot - - // Optional: Reset camera to default rotation if you want - if (controlsRef.current) { - controlsRef.current.autoRotate = true; // Resume auto-rotation - } - - return; // Exit the function early - } - - // If it's a different hotspot, select it (existing functionality) - setActiveHotspot(hotspotId); - - // Move camera to focus on the selected component - if (modelRef.current && cameraRef.current && controlsRef.current) { - // Find the component in the model - const targetComponent = modelRef.current.children.find( - (child) => child.userData.id === hotspotId - ); - - if (targetComponent) { - // Disable auto-rotation when focusing on a component - controlsRef.current.autoRotate = false; - - // Set camera target directly - controlsRef.current.target.copy(targetComponent.position); + const updateHotspotPositions = () => { + if (!modelRef.current || !cameraRef.current || !canvasRef.current) return; + const rect = canvasRef.current.getBoundingClientRect(); + const attach = { + thrusters: new THREE.Vector3(0, -0.1, -0.3), + camera: new THREE.Vector3(0, 0.05, 0.2), + mainHull: new THREE.Vector3(0, 0, 0), + torpedos: new THREE.Vector3(0.1, -0.01, 0.15), + gripper: new THREE.Vector3(-0.5, 0.1, -0.35), + }; + hotspots.forEach((h) => { + const pt = attach[h.id]?.clone(); + if (!pt) return; + pt.applyMatrix4(modelRef.current.matrixWorld); + pt.project(cameraRef.current); + const x = (pt.x * 0.5 + 0.5) * rect.width; + const y = (-pt.y * 0.5 + 0.5) * rect.height; + const vis = pt.z > -1 && pt.z < 1; + const el = document.querySelector(`.model-hotspot[data-id="${h.id}"]`); + if (el) { + el.style.left = `${x}px`; + el.style.top = `${y}px`; + el.style.visibility = vis ? "visible" : "hidden"; } - } - }; - - // Toggle between complete and exploded views - const toggleViewMode = () => { - setViewMode((prevMode) => - prevMode === "complete" ? "exploded" : "complete" - ); + }); }; - // Toggle information overlay visibility - const toggleInfoVisibility = () => { - setInfoVisible((prev) => !prev); - }; + useEffect(() => { + // on each frame draw, also update hotspots + const id = setInterval(() => { + if (isModelLoaded) updateHotspotPositions(); + }, 100); + return () => clearInterval(id); + }, [isModelLoaded]); return (
- {/* Hero Section with 3D Model */} + {/* ===== Hero ===== */}
-
-
-
-

- AUV Technology -

-

- Exploring the innovation behind SubjuGator -

- - {/* 3D Model Canvas Container */} -
- {isLoading && ( -
-
-

Loading 3D Model...

-
- )} - - - - {isModelLoaded && ( - <> - {/* Interactive Hotspots */} -
- {hotspots.map((hotspot) => ( - handleHotspotClick(hotspot.id)} - /> - ))} -
- - {/* Model Controls */} -
- - - -
- - )} - - {/* Component Information Panel */} - {activeHotspot && infoVisible && ( -
-

{hotspots.find((h) => h.id === activeHotspot)?.title}

-

- {activeHotspot === "thrusters" && - "Eight-thruster configuration provides redundant six degrees of freedom control, maintaining full functionality even if one thruster fails."} - {activeHotspot === "camera" && - "Computer vision system using advanced neural networks for object detection and classification underwater."} - {activeHotspot === "mainHull" && - "Houses the main computer, power distribution, and electronic systems in a waterproof enclosure."} - {activeHotspot === "torpedos" && - "Dual servo-actuated torpedo launchers with rack and pinion mechanisms for competition tasks."} - {activeHotspot === "gripper" && - "Servo-actuated gripper with serrated aluminum jaws for manipulating underwater objects."} -

+ /> + ))}
- )} -
- -
-

- Click and drag to rotate • Scroll to zoom • Click on hotspots to - explore -

-
+
+ + +
+ {activeHotspot && infoVisible && ( +
+

+ {hotspots.find((h) => h.id === activeHotspot)?.title} +

+

+ {/* Add your active-hotspot description here */} +

+
+ )} + + )}
- {/* Technical Specifications Section */} + {/* ===== Technical Specifications ===== */}
-
+

Technical Specifications

-
+

Cutting-edge systems powering autonomous underwater exploration

-
- - - - - -
-
-
- - {/* Feature Highlight Section */} -
-
-
-

Key Innovations

-
-

- Pioneering advancements that set SubjuGator apart -

-
- -
-
- {/* Background image will be set in CSS */} -
-
-

- Adaptive{" "} - Control System -

-

- Our state-of-the-art control system uses an unscented Kalman - filter operating on manifolds to efficiently handle attitude - singularities. The trajectory generator produces 3rd-order - continuous trajectories while accounting for vehicle - constraints. -

- - Read Research Paper - -
+ + +
- -
-
- {/* Background image will be set in CSS */} -
-
-

- Deep Learning{" "} - Vision -

-

- SubjuGator combines traditional computer vision techniques with - advanced deep neural networks (YOLO architecture) to identify - competition elements and navigate dynamic underwater - environments. -

- - Explore Vision System - -
-
- -
-
- {/* Background image will be set in CSS */} -
-
-

- Advanced{" "} - Electro-Mechanical{" "} - Design -

-

- Our innovative electro-mechanical systems include custom PCB - designs, CAN bus communications, servo-actuated mechanisms, and - aluminum components manufactured using precision CNC and - water-jet cutting techniques. -

- - See Design Details - -
-
-
-
- - {/* Next Generation Section */} -
-
-
-

SubjuGator 9

-
-

- The next generation of autonomous underwater excellence -

-
- -
-
- {/* This will be a background image set in CSS */} -
-
-

Evolution of Innovation

-

- Currently in development, SubjuGator 9 represents the - culmination of years of research and competition experience. - With a completely redesigned aluminum chassis and electronics - hull, this next-generation AUV will push the boundaries of - what's possible in autonomous underwater robotics. -

-
-
-

Enhanced Chassis

-

- Fully CNC-machined from 6061-T6 aluminum for optimal - strength and weight -

-
-
-

Advanced Electronics

-

- Redesigned electronics hull with improved thermal management - and expanded sensor capacity -

-
-
-

Next-Gen Software

-

- Enhanced autonomy algorithms and improved mission planning - capabilities -

-
-
-
+
- {/* Resources Section */} + {/* ===== Resources ===== */}
-
+

Technical Resources

-
+

In-depth documentation and research materials

-
- -
- -
-

Mechanical Documentation

-

Detailed specifications, CAD files, and assembly guides

- - - -
- -
-

Electrical Schematics

-

PCB designs, wiring diagrams, and component datasheets

- - - +

Software Repository

Open-source codebase, ROS packages, and development guides

- - +
PDF

Technical Paper

-

- Comprehensive overview of SubjuGator's design and implementation -

+

Comprehensive overview of SubjuGator's design and implementation

- {/* Call to Action */} + {/* ===== Call to Action ===== */}

Experience Innovation

-

- Want to learn more about SubjuGator or get involved with our team? -

+

Want to learn more about SubjuGator or get involved with our team?

- + RoboSub Competition - + Meet The Team
@@ -957,5 +471,3 @@ function AUVTechnology() {
); } - -export default AUVTechnology; diff --git a/src/Pages/AboutUs.jsx b/src/Pages/AboutUs.jsx index 07e2e53..163813e 100644 --- a/src/Pages/AboutUs.jsx +++ b/src/Pages/AboutUs.jsx @@ -198,7 +198,7 @@ function AboutUs() { collaboration within the global AUV community.

    -
  • 7x AUVSI RoboSub champions
  • +
  • 5x AUVSI RoboSub champions
  • Consistent innovation award recipients
  • International recognition for technical merit
@@ -229,10 +229,7 @@ function AboutUs() {

Team Formation

@@ -255,10 +252,7 @@ function AboutUs() {

First Competition Win

@@ -281,10 +275,7 @@ function AboutUs() {

Technology Evolution

@@ -307,10 +298,8 @@ function AboutUs() {

Advanced Autonomy

@@ -333,10 +322,7 @@ function AboutUs() {

SubjuGator 9

@@ -424,7 +410,7 @@ function AboutUs() {
- + Meet Our Team Members
@@ -456,7 +442,7 @@ function AboutUs() {

Dr. Eric M. Schwartz

- Director, Machine Intelligence Laboratory + Director, SubjuGator AUV Project & Machine Intelligence Laboratory

Areas of Expertise:

@@ -467,8 +453,8 @@ function AboutUs() {

- Provides overall guidance for the SubjuGator team and - coordinates resources across the university. + Provides overall guidance, invaluable insight and + coordinates resources across the university for the SubjuGator team.

@@ -513,7 +499,7 @@ function AboutUs() {
-

7x RoboSub Champions

+

5x RoboSub Champions

First place wins at the international AUVSI RoboSub Competition

@@ -548,7 +534,7 @@ function AboutUs() { underwater robotics!

- + Contact Us diff --git a/src/Pages/Contact.jsx b/src/Pages/Contact.jsx index 050c984..a9ed51b 100644 --- a/src/Pages/Contact.jsx +++ b/src/Pages/Contact.jsx @@ -2,6 +2,8 @@ import React, { useState, useEffect, useRef } from "react"; import { Link } from "react-router-dom"; import { FaMapMarkerAlt, FaEnvelope, FaPhone, FaUsers } from "react-icons/fa"; import "../styles/Contact.css"; +import { useLocation } from "react-router-dom"; + function Contact() { const [formStatus, setFormStatus] = useState(""); @@ -11,6 +13,19 @@ function Contact() { const subtitleRef = useRef(null); const contactInfoRef = useRef(null); const formRef = useRef(null); + + useEffect(() => { + const hash = location.hash; + if (hash) { + // Delay to ensure the target element is rendered + setTimeout(() => { + const element = document.querySelector(hash); + if (element) { + element.scrollIntoView({ behavior: "smooth" }); + } + }, 100); + } + }, [location]); // Initialize form data const [formData, setFormData] = useState({ @@ -120,7 +135,7 @@ function Contact() { return (
{/* Hero Section */} -
+
{/* Background image is set in CSS */}
diff --git a/src/Pages/Home.jsx b/src/Pages/Home.jsx index ee6f022..2382fb9 100644 --- a/src/Pages/Home.jsx +++ b/src/Pages/Home.jsx @@ -1,8 +1,50 @@ -import React, { useEffect, useRef } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { Link } from "react-router-dom"; import { FaCogs, FaBolt, FaLaptopCode } from "react-icons/fa"; import "../styles/Home.css"; + + +function CountdownCard({ targetDate }) { + const [timeLeft, setTimeLeft] = useState(getDiff()); + + function getDiff() { + const diff = new Date(targetDate) - new Date(); + return diff > 0 ? diff : 0; + } + + useEffect(() => { + const id = setInterval(() => setTimeLeft(getDiff()), 1000); + return () => clearInterval(id); + }, []); + + const days = Math.floor(timeLeft / 8.64e7); + const hrs = Math.floor((timeLeft % 8.64e7) / 3.6e6); + const mins = Math.floor((timeLeft % 3.6e6) / 6e4); + const secs = Math.floor((timeLeft % 6e4) / 1e3); + + return ( +
+
+

Countdown to RoboSub 2025

+
+ + + + +
+
+
+ ); +} + +const TimeBox = ({ value, label }) => ( +
+ {String(value).padStart(2, "0")} + {label} +
+); + function Home() { const heroBackgroundRef = useRef(null); const titleRef = useRef(null); @@ -71,10 +113,10 @@ function Home() { Exploring the Depths of Innovation

- + Explore Technology - + Learn About RoboSub
@@ -103,7 +145,7 @@ function Home() {
Years of Development
-
8
+
9
Generations of AUVs
@@ -163,7 +205,7 @@ function Home() {
- + Explore Full Capabilities
@@ -178,60 +220,41 @@ function Home() {
+ {/* — 1 — */}
-
- {/* Update image will be background in CSS */} -
+
{/* add bg via CSS */}
- February 28, 2025 +

SubjuGator 9 Development

- Progress on our next-generation AUV including aluminum chassis + Progress on our new AUV including aluminum chassis completion and electronics hull integration.

- - Read More - + Read More
-
-
- {/* Update image will be background in CSS */} -
+ {/* — 2 — */} + + + {/* — 3 — */} +
+
- January 15, 2025 +

RoboSub 2025 Preparation

- Team training and technology refinement for the upcoming + Team testing and technology refinement for the upcoming competition season.

- - Read More - -
-
- -
-
- {/* Update image will be background in CSS */} -
-
- December 10, 2024 -

End-of-Year Achievements

-

- Celebrating our accomplishments and recognizing team - contributions. -

- - Read More - + Read More
-
+
+ {/* Call to Action */}
@@ -242,10 +265,19 @@ function Home() { technology. Connect with our team or support our mission.

- + Meet Our Team - + { + const el = document.querySelector("#top-sponsor"); + if (el) { + el.scrollIntoView({ behavior: "smooth" }); + } + }} + > Become a Sponsor
diff --git a/src/Pages/OurTeam.jsx b/src/Pages/OurTeam.jsx index 200276d..adeabb1 100644 --- a/src/Pages/OurTeam.jsx +++ b/src/Pages/OurTeam.jsx @@ -1,12 +1,141 @@ -import React from "react"; +import React, { useEffect } from "react"; +import { useLocation } from "react-router-dom"; +import { Link } from "react-router-dom"; +import "../styles/OurTeam.css"; +/* ---------- auto-import headshots from /assets/people ---------- */ +const peopleModules = import.meta.glob( + "../assets/people/*.{png,jpg,jpeg,webp,gif}", + { eager: true } +); +const memberImages = Object.fromEntries( + Object.entries(peopleModules).map(([path, mod]) => [ + path.split("/").pop(), + mod.default, + ]) +); + +const toSlug = (name) => + name.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+/g, "_"); + +const resolveImage = (slug) => { + for (const ext of ["png", "jpg", "jpeg", "webp", "gif"]) { + const key = `${slug}.${ext}`; + if (memberImages[key]) return memberImages[key]; + } + return undefined; // fallback – no head‑shot found +}; + +/* ---------- card component ---------- */ +const TeamMemberCard = ({ member }) => { + const hasImage = Boolean(member.img); + + return ( +
+ {hasImage && ( +
+ {`${member.name} +
+ )} + +

{member.name}

+

{member.role}

+
+ ); +}; + +/* ---------- page component ---------- */ function OurTeam() { + const rawMembers = [ + { name: "Adam McAleer", role: "Mechanical Lead" }, + { name: "Joseph Goodman", role: "Electrical Lead" }, + { name: "Cameron Brown", role: "Software Lead" }, + { name: "Adrian Fernandez", role: "Electrical Lead" }, + { name: "Lester Bonilla", role: "Electrical Lead" }, + { name: "Adam Hamdan", role: "Mechanical Lead" }, + { name: "Ryan Hoburg", role: "Mechanical Lead" }, + { name: "Alex Johnson", role: "Software Lead" }, + { name: "Carlos Chavez", role: "Software Lead" }, + { name: "Eric(Jack) Rainville", role: "Electrical Lead" }, + { name: "Ethan Mitchell", role: "Electrical Member" }, + { name: "Keith Khadar", role: "Software Lead" }, + { name: "Daniel Parra", role: "Software Lead" }, + { name: "Lorant Domokos", role: "Mechanical Lead" }, + + + ]; + + /* attach images */ + const teamMembers = rawMembers.map((m) => ({ + ...m, + img: resolveImage(toSlug(m.name)), + })); + + const location = useLocation(); + + useEffect(() => { + const hash = location.hash; + if (hash) { + // Delay to ensure the target element is rendered + setTimeout(() => { + const element = document.querySelector(hash); + if (element) { + element.scrollIntoView({ behavior: "smooth" }); + } + }, 100); + } + }, [location]); + + + /* devtools verification – run once */ + useEffect(() => { + console.table(teamMembers.map((m) => ({ name: m.name, imgFound: !!m.img }))); + }, []); return ( -
-

Our Team

-

This is a placeholder for now.

-
+
+
+

+ 2025 Team  + Members +

+
+ + {/* ----- grid section ----- */} +
+
+

+ Meet the engineers shaping SubjuGator +

+ +
+ {teamMembers.map((member) => ( + + ))} +
+
+
+ +
+
+

Passionate about underwater robotics?

+
+ + Contact Us + +
+
+
+ +
); } -export default OurTeam; +export default OurTeam; \ No newline at end of file diff --git a/src/Pages/RoboSub.jsx b/src/Pages/RoboSub.jsx index f1eef37..0084942 100644 --- a/src/Pages/RoboSub.jsx +++ b/src/Pages/RoboSub.jsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useRef } from "react"; +import { useLocation } from "react-router-dom"; import { Link } from "react-router-dom"; import { FaRobot, @@ -69,6 +70,21 @@ function RoboSub() { const titleRef = useRef(null); const subtitleRef = useRef(null); + const location = useLocation(); + + useEffect(() => { + const hash = location.hash; + if (hash) { + // Delay to ensure the target element is rendered + setTimeout(() => { + const element = document.querySelector(hash); + if (element) { + element.scrollIntoView({ behavior: "smooth" }); + } + }, 100); + } + }, [location]); + useEffect(() => { // Force immediate display of elements instead of relying on animations const heroBackground = heroBackgroundRef.current; @@ -90,7 +106,7 @@ function RoboSub() { return (
-
+
{/* Background image now set with inline style as fallback */}
@@ -106,9 +122,8 @@ function RoboSub() {
SubjuGator 8 AUV
@@ -166,21 +181,25 @@ function RoboSub() {

Competition Vehicle

- Meet SubjuGator 8, our flagship autonomous underwater vehicle + Meet SubjuGator 9, our flagship autonomous underwater vehicle

- SubjuGator 8 -
SubjuGator 8 - University of Florida's AUV
+ SubjuGator 9 +
Subjugator 9 - First Swim
-

SubjuGator 8

+

SubjuGator 9

- SubjuGator 8 has served as the flagship autonomous submarine for the Machine Intelligence Laboratory (MIL) at the University of Florida for the past five years. It features a modular design that allows for rapid iteration and improvement of individual components. + SubjuGator 9 represents the + culmination of years of research and competition experience. + With a completely redesigned aluminum chassis and electronics + hull, this next-generation AUV pushes the boundaries of + what's possible in autonomous underwater robotics.

@@ -189,24 +208,22 @@ function RoboSub() {
Computing - Intel i9-9900k + Nvidia RTX 2080 + Nvidia Jetson Orion NX
Power - 22.2V LiPo Batteries + 14.8V LiPo Batteries
Framework - ROS Noetic + ROS 2 Jazzy
-
- Technical Design Report -
+
@@ -224,12 +241,20 @@ function RoboSub() {

Innovative Design

-

- The mechanical design of SubjuGator 8 incorporates four independently operated electronic servo mechanisms: a gripper, two torpedo launchers, and a marker dropper. These mechanisms are used to complete mission-specific tasks, and they are controlled through the servo controller board housed in a separate, compact pressure vessel. -

+
+ +
+

Mechanisms

+

+ Three independently + operated electronic servo mechanisms: a gripper, + torpedo launcher, and a ball dropper. +

+
+
-

Space-Frame Chassis

+

Durable Frame

Carbon fiber tubes and aluminum sheet sections provide protection for delicate components while enabling modularity.

@@ -237,17 +262,16 @@ function RoboSub() {

CNC milled and abrasive water-jetted aluminum components replaced many previously 3D printed parts for improved durability.

-

Redundant Thruster Configuration

+

Thruster Configuration

Eight thrusters provide full six degrees of freedom control with built-in redundancy for mission reliability.

- SubjuGator 8 Mechanical System + SubjuGator 9 Mechanical System
-

Servo Actuators

-

Waterproof servo system ensures reliable actuation for all manipulation tasks

+

SubjuGator 9 Frame

@@ -268,18 +292,17 @@ function RoboSub() {
- SubjuGator 8 Electrical Architecture + SubjuGator 9 Electrical Architecture

Student-Designed PCBs

-

Custom boards for thruster control, power management, and sensor integration

Robust Electrical Systems

- SubjuGator 8 consists of a robust set of embedded industry standards and student-designed electronic devices. Peripheral to the main computer is a suite of devices to aid in navigation, safety, power delivery, and communication. + SubjuGator 9 consists of a robust set of embedded industry standards and student-designed electronic devices. Peripheral to the main computer is a suite of devices to aid in navigation, safety, power delivery, and communication.

@@ -291,8 +314,8 @@ function RoboSub() {

Hall-effect-based manual shut-off feature allows immediate power cutoff to thrusters for safety during testing and competitions.

-

Water Cooling System

-

Closed-loop water cooling ensures optimal thermal efficiency for the main computer and GPGPU.

+

Open Architecture

+

Subjuss computers and sesnors are connected via a gigabit Ethernet switch. Adding and removing systems is as simple as connecting or disconnecting network devices.

@@ -315,12 +338,12 @@ function RoboSub() {

Advanced Autonomy

- SubjuGator 8's software stack is built on the Noetic version of the Robot Operating System (ROS). Our stack has grown to over 60+ ROS packages, all of which are open-source, allowing other teams to share the benefits of our work. + SubjuGator 9's software stack is built on the Jazzy version of the Robot Operating System 2 (ROS2). Our stack has grown to over 60+ ROS packages, all of which are open-source, allowing other teams to share the benefits of our work.

State Estimation

-

An unscented Kalman filter operating on manifolds provides efficient handling of attitude singularities, fusing data from IMU, DVL, and other sensors.

+

An Extended Kalman filter operating on manifolds provides efficient handling of attitude singularities, fusing data from IMU, DVL, and other sensors.

Computer Vision

@@ -333,7 +356,7 @@ function RoboSub() {
- SubjuGator 8 Software Architecture + SubjuGator 8 Software Architecture

Simulation Environment

@@ -358,7 +381,7 @@ function RoboSub() {
- RoboSub Competition + RoboSub Competition
diff --git a/src/Pages/ScrollToTop.jsx b/src/Pages/ScrollToTop.jsx new file mode 100644 index 0000000..d965e32 --- /dev/null +++ b/src/Pages/ScrollToTop.jsx @@ -0,0 +1,10 @@ +import { useEffect } from "react"; +import { useLocation } from "react-router-dom"; + +export default function ScrollToTop() { + const { pathname } = useLocation(); + useEffect(() => { + window.scrollTo(0, 0); + }, [pathname]); + return null; +} diff --git a/src/Pages/Sponsors.jsx b/src/Pages/Sponsors.jsx index 3b1aced..3c1697d 100644 --- a/src/Pages/Sponsors.jsx +++ b/src/Pages/Sponsors.jsx @@ -1,12 +1,144 @@ -import React from "react"; +// src/Pages/Sponsors.jsx +import React, { useEffect } from "react"; +import { useLocation } from "react-router-dom"; +import "../styles/Sponsors.css"; -function Sponsors() { - return ( -
-

Sponsors

-

This is a placeholder for now.

+// local logo & pdf imports +import sylphaseLogo from "../assets/sponsors/Sylphase.png"; +import sponsorPacket from "../assets/sponsorship_packet.pdf"; + +/* ---------- Tier component ---------- */ +const SponsorSection = ({ title, sponsors }) => ( +
+

{title}

+ +
+ {sponsors.map((s, i) => { + const isPerson = !s.url; // people / alumni have no URL + return ( +
+ {s.imgSrc && ( + isPerson ? ( + {s.imgAlt} + ) : ( + + {s.imgAlt} + + ) + )} + {isPerson &&

{s.name}

} +
+ ); + })}
+
+); + +/* ---------- Main page ---------- */ +const Sponsors = () => { + const diamondSponsors = [ + { + name: "Sylphase", + url: "https://sylphase.com", + imgSrc: sylphaseLogo, + imgAlt: "Sylphase Logo", + }, + { + name: "L3Harris Technologies", + url: "https://l3harris.com", + imgSrc: + "https://upload.wikimedia.org/wikipedia/en/thumb/2/23/L3Harris_Technologies_logo.svg/1280px-L3Harris_Technologies_logo.svg.png", + imgAlt: "L3Harris Logo", + }, + { + name: "Erik de la Inglesia", + imgSrc: "https://mil.ufl.edu/sponsors/Erik.png", + imgAlt: "Erik de la Iglesia", + }, + ]; + + const platinumSponsors = [ + { + name: "JD Squared", + url: "https://jd2.com", + imgSrc: "http://mil.ufl.edu/sponsors/JD-squared-transparent.png", + imgAlt: "JD Squared Logo", + }, + { + name: "Texas Instruments", + url: "https://ti.com", + imgSrc: "https://1000logos.net/wp-content/uploads/2020/04/Logo-Texas-Instruments.jpg", + imgAlt: "Texas Instruments Logo", + }, + ]; + + const goldSponsors = [ + { name: "Kevin Allen (MIL alumnus)", imgSrc: "http://mil.ufl.edu/sponsors/kevin.jpeg", imgAlt: "Kevin Allen" }, + { name: "Anonymous (MIL alumnus)" }, + ]; + + const silverSponsors = [ + { name: "Matthew Langford (MIL alumnus)" }, + { name: "IEEE", url: "https://www.ieee.org", imgSrc: "https://upload.wikimedia.org/wikipedia/commons/2/21/IEEE_logo.svg", imgAlt: "IEEE Logo" }, + { name: "Anonymous (MIL alumnus)" }, + { name: "Electrical and Computer Engineering, UF", url: "https://ece.ufl.edu", imgSrc: "https://www.ece.ufl.edu/wp-content/uploads/2024/10/ElectricalComputerEngineering-VECTOR-RGB.svg", imgAlt: "ECE Logo" }, + { name: "Mechanical and Aerospace Engineering, UF", url: "https://mae.ufl.edu", imgSrc: "https://mil.ufl.edu/sponsors/MAE_logo.png", imgAlt: "MAE Logo" }, + ]; + + const bronzeSponsors = [ + { name: "Dr. Andrew Gray (MIL alumnus)" }, + { name: "DigiKey", url: "https://www.digikey.com", imgSrc: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/DigiKey_logo.svg/1280px-DigiKey_logo.svg.png", imgAlt: "DigiKey Logo" }, + ]; + + const location = useLocation(); + + useEffect(() => { + const hash = location.hash; + if (hash) { + // Delay to ensure the target element is rendered + setTimeout(() => { + const element = document.querySelector(hash); + if (element) { + element.scrollIntoView({ behavior: "smooth" }); + } + }, 100); + } + }, [location]); + + return ( +
+ {/* ----- hero ----- */} +
+

2025 Sponsors

+

+ We have been very fortunate to have generous partners in industry and at the University of Florida to support the SubjuGator project. Listed below are active sponsors for the SubjuGator project at the University of Florida. For more information about becoming a sponsor, please see our sponsorship packet below. +

+
+ + {/* ----- sponsor tiers ----- */} +
+ + + + + +
+ + {/* ----- footer with call‑to‑action button ----- */} +
+
); -} +}; export default Sponsors; diff --git a/src/assets/Design_and_Development_of_SubjuGator_9.pdf b/src/assets/Design_and_Development_of_SubjuGator_9.pdf new file mode 100644 index 0000000..d88cb7d Binary files /dev/null and b/src/assets/Design_and_Development_of_SubjuGator_9.pdf differ diff --git a/src/assets/PCB.png b/src/assets/PCB.png new file mode 100644 index 0000000..2173dde Binary files /dev/null and b/src/assets/PCB.png differ diff --git a/src/assets/advanced-autonomy.png b/src/assets/advanced-autonomy.png new file mode 100644 index 0000000..4fe69fe Binary files /dev/null and b/src/assets/advanced-autonomy.png differ diff --git a/src/assets/people/adam_hamdan.png b/src/assets/people/adam_hamdan.png new file mode 100644 index 0000000..4a0c9af Binary files /dev/null and b/src/assets/people/adam_hamdan.png differ diff --git a/src/assets/people/adam_mcaleer.png b/src/assets/people/adam_mcaleer.png new file mode 100644 index 0000000..76cf73e Binary files /dev/null and b/src/assets/people/adam_mcaleer.png differ diff --git a/src/assets/people/adrian_fernandez.png b/src/assets/people/adrian_fernandez.png new file mode 100644 index 0000000..e6cfe3b Binary files /dev/null and b/src/assets/people/adrian_fernandez.png differ diff --git a/src/assets/people/alex_johnson.png b/src/assets/people/alex_johnson.png new file mode 100644 index 0000000..f8e945b Binary files /dev/null and b/src/assets/people/alex_johnson.png differ diff --git a/src/assets/people/cameron_brown.jpeg b/src/assets/people/cameron_brown.jpeg new file mode 100644 index 0000000..3965348 Binary files /dev/null and b/src/assets/people/cameron_brown.jpeg differ diff --git a/src/assets/people/carlos_chavez.png b/src/assets/people/carlos_chavez.png new file mode 100644 index 0000000..7e69bd8 Binary files /dev/null and b/src/assets/people/carlos_chavez.png differ diff --git a/src/assets/people/daniel_parra.png b/src/assets/people/daniel_parra.png new file mode 100644 index 0000000..73a933b Binary files /dev/null and b/src/assets/people/daniel_parra.png differ diff --git a/src/assets/people/ericjack_rainville.jpg b/src/assets/people/ericjack_rainville.jpg new file mode 100644 index 0000000..fddcb2d Binary files /dev/null and b/src/assets/people/ericjack_rainville.jpg differ diff --git a/src/assets/people/ethan_mitchell.png b/src/assets/people/ethan_mitchell.png new file mode 100644 index 0000000..303187d Binary files /dev/null and b/src/assets/people/ethan_mitchell.png differ diff --git a/src/assets/people/joseph_goodman.png b/src/assets/people/joseph_goodman.png new file mode 100644 index 0000000..96f2416 Binary files /dev/null and b/src/assets/people/joseph_goodman.png differ diff --git a/src/assets/people/keith_khadar.jpg b/src/assets/people/keith_khadar.jpg new file mode 100644 index 0000000..b7b2c04 Binary files /dev/null and b/src/assets/people/keith_khadar.jpg differ diff --git a/src/assets/people/lester_bonilla.jpg b/src/assets/people/lester_bonilla.jpg new file mode 100644 index 0000000..0f8ec97 Binary files /dev/null and b/src/assets/people/lester_bonilla.jpg differ diff --git a/src/assets/people/lorant_domokos.png b/src/assets/people/lorant_domokos.png new file mode 100644 index 0000000..91425a6 Binary files /dev/null and b/src/assets/people/lorant_domokos.png differ diff --git a/src/assets/people/ryan_hoburg.png b/src/assets/people/ryan_hoburg.png new file mode 100644 index 0000000..afd4552 Binary files /dev/null and b/src/assets/people/ryan_hoburg.png differ diff --git a/src/assets/robosub_logo.png b/src/assets/robosub_logo.png new file mode 100644 index 0000000..5fd49c0 Binary files /dev/null and b/src/assets/robosub_logo.png differ diff --git a/src/assets/robosub_preparation.png b/src/assets/robosub_preparation.png new file mode 100644 index 0000000..1f94864 Binary files /dev/null and b/src/assets/robosub_preparation.png differ diff --git a/src/assets/simulation_enviornment.png b/src/assets/simulation_enviornment.png new file mode 100644 index 0000000..128a5f1 Binary files /dev/null and b/src/assets/simulation_enviornment.png differ diff --git a/src/assets/sponsors/JD-squared-transparent.png b/src/assets/sponsors/JD-squared-transparent.png new file mode 100644 index 0000000..40cb0d1 Binary files /dev/null and b/src/assets/sponsors/JD-squared-transparent.png differ diff --git a/src/assets/sponsors/MAE_logo.png b/src/assets/sponsors/MAE_logo.png new file mode 100644 index 0000000..13443fd Binary files /dev/null and b/src/assets/sponsors/MAE_logo.png differ diff --git a/src/assets/sponsors/Sylphase.png b/src/assets/sponsors/Sylphase.png new file mode 100644 index 0000000..3b53cf7 Binary files /dev/null and b/src/assets/sponsors/Sylphase.png differ diff --git a/src/assets/sponsorship_packet.pdf b/src/assets/sponsorship_packet.pdf new file mode 100644 index 0000000..d06cc9a Binary files /dev/null and b/src/assets/sponsorship_packet.pdf differ diff --git a/src/assets/subjugator_logo.png b/src/assets/subjugator_logo.png new file mode 100644 index 0000000..b3a3eaf Binary files /dev/null and b/src/assets/subjugator_logo.png differ diff --git a/src/assets/submarines/sub9_1.jpeg b/src/assets/submarines/sub9_1.jpeg new file mode 100644 index 0000000..810df6b Binary files /dev/null and b/src/assets/submarines/sub9_1.jpeg differ diff --git a/src/assets/submarines/sub9_cherry_1.png b/src/assets/submarines/sub9_cherry_1.png new file mode 100644 index 0000000..53b5b68 Binary files /dev/null and b/src/assets/submarines/sub9_cherry_1.png differ diff --git a/src/assets/submarines/sub9_development.jpg b/src/assets/submarines/sub9_development.jpg new file mode 100644 index 0000000..a9a89fb Binary files /dev/null and b/src/assets/submarines/sub9_development.jpg differ diff --git a/src/assets/submarines/sub9_frame.png b/src/assets/submarines/sub9_frame.png new file mode 100644 index 0000000..810d8c9 Binary files /dev/null and b/src/assets/submarines/sub9_frame.png differ diff --git a/src/assets/submarines/subjugator_1.png b/src/assets/submarines/subjugator_1.png new file mode 100644 index 0000000..bf0c4eb Binary files /dev/null and b/src/assets/submarines/subjugator_1.png differ diff --git a/src/assets/submarines/subjugator_3.png b/src/assets/submarines/subjugator_3.png new file mode 100644 index 0000000..66f3969 Binary files /dev/null and b/src/assets/submarines/subjugator_3.png differ diff --git a/src/assets/submarines/subjugator_6.png b/src/assets/submarines/subjugator_6.png new file mode 100644 index 0000000..ae5a0aa Binary files /dev/null and b/src/assets/submarines/subjugator_6.png differ diff --git a/src/assets/submarines/subjugator_8.png b/src/assets/submarines/subjugator_8.png new file mode 100644 index 0000000..24ae1e3 Binary files /dev/null and b/src/assets/submarines/subjugator_8.png differ diff --git a/src/assets/submarines/subjugator_9.1.png b/src/assets/submarines/subjugator_9.1.png new file mode 100644 index 0000000..4189d8c Binary files /dev/null and b/src/assets/submarines/subjugator_9.1.png differ diff --git a/src/assets/submarines/subjugator_9.png b/src/assets/submarines/subjugator_9.png new file mode 100644 index 0000000..a50f54a Binary files /dev/null and b/src/assets/submarines/subjugator_9.png differ diff --git a/src/index.css b/src/index.css index 6119ad9..b5b3f12 100644 --- a/src/index.css +++ b/src/index.css @@ -1,18 +1,21 @@ :root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; + --navbar-height: 80px; + --max-width: 1280px; + --space-sm: 0.5rem; + --space-md: 1rem; + --space-lg: 2rem; - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; + --color-text-primary: #ffffff; + --color-text-secondary: #d1d5db; + --color-primary: #fa4616; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + --color-background: #000000; + + --transition-fast: 0.2s ease; + --transition-medium: 0.4s ease; } + a { font-weight: 500; color: #646cff; @@ -28,6 +31,10 @@ body { place-items: center; min-width: 320px; min-height: 100vh; + padding: 0; + color: white; + background-color: #000000; + overflow-x: hidden; } h1 { diff --git a/src/main.jsx b/src/main.jsx index 9191daf..d719969 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -2,11 +2,12 @@ import React from "react"; import ReactDOM from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; -import "./styles/GlobalStyles.css"; import "./index.css"; ReactDOM.createRoot(document.getElementById("root")).render( - - - -); \ No newline at end of file + + + + + +); diff --git a/src/styles/AUVTechnology.css b/src/styles/AUVTechnology.css index 7e62c94..84bb0e4 100644 --- a/src/styles/AUVTechnology.css +++ b/src/styles/AUVTechnology.css @@ -2,17 +2,28 @@ .auv-technology-page { background-color: var(--color-background); color: #ffffff; + font-family: 'Montserrat', sans-serif; + +} + + +.tech-specs-section .tech-button-container { + margin-top: 6rem; + } /* ========== Hero Section with 3D Model ========== */ .hero-section { - height: 100vh; + height: calc(var(--vh) * 100 - var(--navbar-height, 0px)); position: relative; - display: flex; align-items: center; + overflow: visible; justify-content: center; - overflow: hidden; - background-color: #000000; + position: relative; + display: flex; + height: 100svh; + height: 100dvh; + height: 100vh; } .hero-background { @@ -263,7 +274,6 @@ gap: 10px; z-index: 5; } - .control-button { background-color: rgba(0, 0, 0, 0.7); border: 1px solid rgba(255, 255, 255, 0.2); diff --git a/src/styles/AboutUs.css b/src/styles/AboutUs.css index ab77d21..3a33abc 100644 --- a/src/styles/AboutUs.css +++ b/src/styles/AboutUs.css @@ -1,4 +1,8 @@ /* Hero Section with Team Photo Background - Improved */ +html, body { + font-family: "Open Sans", Helvetica, Arial, sans-serif !important; +} + .about-hero-section { min-height: 70vh; position: relative; @@ -17,17 +21,27 @@ border-radius: 12px; /* Optional: rounded corners for container */ } - +.about-hero-section::before { + content: ""; + position: absolute; + top: 0; left: 0; + width: 100%; height: 100%; + background: rgba(0, 0, 0, 0.5); + pointer-events: none; + z-index: 1; +} .about-hero-section .container { - position: relative; + position: absolute; + top: 45%; + left: 50%; + transform: translate(-50%,-50%); z-index: 1; width: 100%; max-width: var(--max-width); padding: 0 20px; margin-bottom: 20px; } - .hero-title { font-size: clamp(2rem, 5vw, 3.5rem); margin-bottom: 10px; @@ -360,6 +374,12 @@ gap: 8px; } +.image-sub1 { background-image: url("/src/assets/submarines/subjugator_1.png"); } +.image-sub3 { background-image: url("/src/assets/submarines/subjugator_3.png"); } +.image-sub6 { background-image: url("/src/assets/submarines/subjugator_6.png"); } +.image-sub8 { background-image: url("/src/assets/submarines/subjugator_8.png"); } +.image-sub9 { background-image: url("/src/assets/submarines/subjugator_9.png"); } + .tech-tag { display: inline-block; padding: 4px 10px; diff --git a/src/styles/Contact.css b/src/styles/Contact.css index ecd71ab..ba16a4b 100644 --- a/src/styles/Contact.css +++ b/src/styles/Contact.css @@ -63,6 +63,7 @@ .contact-hero-section .hero-content { text-align: center; max-width: 800px; + color: white; } .contact-hero-section .hero-title { diff --git a/src/styles/Home.css b/src/styles/Home.css index 0b76335..52fc9cb 100644 --- a/src/styles/Home.css +++ b/src/styles/Home.css @@ -16,7 +16,7 @@ width: 100%; max-width: 1200px; margin: 0 auto; - padding: 0 20px; + padding: 0 0px; z-index: 1; } @@ -26,7 +26,7 @@ left: 0; width: 100%; height: 100%; - background-image: url("/src/assets/submarine-hero.jpg"); + background-image: url("/src/assets/subjugator8-hero.png"); background-size: cover; background-position: center; z-index: -1; @@ -75,16 +75,6 @@ color: #ffffff; } -.hero-subtitle { - opacity: 0; - font-size: clamp(1.5rem, 4vw, 2.5rem); - font-weight: 300; - color: #ffffff; - margin-top: 0; - margin-bottom: 2rem; - text-align: center; - width: 100%; -} .hero-cta { display: flex; @@ -184,10 +174,9 @@ } .animate-fadeIn { - opacity: 1 !important; /* Force opacity to 1 */ + opacity: 1 !important; } -/* Add a new class for slide up animation */ .animate-slideUp { animation: slideUp 1.5s ease forwards; } @@ -248,11 +237,13 @@ .subtitle { font-size: 1.2rem; - color: rgba(255, 255, 255, 0.85); /* Improved contrast */ + color: rgba(255, 255, 255, 0.85); max-width: 700px; margin: 0 auto; } + + .stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); @@ -322,9 +313,8 @@ } .highlight-content { - width: 50%; - margin-left: auto; - padding: var(--space-xl) 0; + margin: 0 auto; + text-align: center; } .tech-features { @@ -390,6 +380,12 @@ background-color: var(--color-background); padding: 80px 0; position: relative; + padding-bottom: 260px; +} +.updates-section::after { + content: ""; /* creates a real box */ + display: block; + height: 12rem; /* tweak up/down to taste (≈ 96 px) */ } .updates-section .section-header { @@ -479,6 +475,55 @@ transform: translateX(4px); } +.countdown-card { + display: flex; + align-items: center; + justify-content: center; + background: #111; +} + +.countdown-title { + text-align: center; + margin-bottom: var(--space-md); +} + +.countdown-clock { + display: flex; + justify-content: center; + gap: 1rem; +} +.countdown-clock .time-box:nth-child(4) .time-value +{ + color: #fa4616; +} + +.time-box { + background: #1a1a1a; + border: 1px solid #333; + padding: 0.6rem 0.8rem; + border-radius: 6px; + min-width: 60px; +} + +.time-value { + font-size: 1.6rem; + font-weight: 600; + color: #4a9fff; + display: block; +} + +.time-label { + font-size: 0.75rem; + color: #ccc; + text-transform: uppercase; + letter-spacing: 0.02em; +} + +.image-sub9 { background-image: url("/src/assets/submarines/sub9_development.jpg"); } +.image-robosub{ background-image: url("/src/assets/robosub_preparation.png"); } +.update-image { background-size: cover; background-position: center; } + + /* ========== CTA Section (Join the Journey) ========== */ .cta-section { padding: 100px 0; /* Increase vertical padding */ @@ -488,6 +533,7 @@ background-position: center; background-attachment: fixed; text-align: center; + } .cta-content { @@ -582,73 +628,102 @@ } } -/* Responsive adjustments */ -@media screen and (max-width: 992px) { - .tech-highlights-section .btn { - margin-left: 0; - margin-right: auto; - align-self: flex-start; + +html, body { overflow-x: hidden; } + + +@media (max-width: 680px) { + .stats-grid, .updates-grid { + grid-template-columns: 1fr; + padding-inline: 0.75rem; + gap: 20px; } + + .overview-section { + padding-bottom: 40px; /* down from 80px */ + } + .highlight-image { - width: 100%; - height: 300px; position: relative; + width: 100%; + height: 220px; clip-path: none; } - .updates-grid { - grid-template-columns: repeat(2, 1fr); /* 2 columns on medium screens */ + .container{ + width: 100%; + position: relative; } + /* —— MOBILE FIX FOR TECH HIGHLIGHTS —— */ .tech-highlights-section { - flex-direction: column; + display: flex; /* ensure it’s flex */ + flex-direction: column; /* stack image + content */ + align-items: center; /* center children horizontally */ } - .highlight-content { + .tech-highlights-section .highlight-image { + position: relative; /* flow normally */ + width: 100%; /* full-width banner */ + height: 220px; /* adjust as needed */ + clip-path: none; /* remove the desktop diagonal */ + } + + .tech-highlights-section .container { + display: block; /* override the flex container */ width: 100%; - margin: 0; - padding: var(--space-xl) var(--space-lg); + max-width: 1200px; /* keep your desktop cap if you like */ + margin: 0 auto; /* center it */ + padding: 0 20px; + box-sizing: border-box; + } + + .highlight-content { + max-width: 700px; /* optional cap so it doesn’t stretch too far */ + margin: 1rem auto; /* vertical spacing + horizontal centering */ + text-align: center; } - .hero-cta { + + .tech-features { display: flex; - gap: 20px; - justify-content: center; - margin-top: 2rem; - width: 100%; - opacity: 0; + flex-direction: column; /* stack the three feature blocks */ + gap: 20px; /* space between them */ + align-items: center; /* center each block */ } - .hero-cta .btn { - opacity: 0; + + .feature { width: 100%; + max-width: 320px; } - .cta-buttons { - flex-direction: column; - gap: var(--space-md); + .tech-highlights-section .btn { + display: block; + margin: 2rem auto 0; + width: 100%; + max-width: 320px; + padding-top: 10px; + min-height: auto; + text-align: center; } + } -@media screen and (max-width: 768px) { - .stats-grid, - .updates-grid { - grid-template-columns: 1fr; - } - .hero-section { - padding-top: var(--navbar-height); - } - .feature-text p { - max-width: 100%; - } - .feature-icon { - width: 50px; - height: 50px; - margin-right: var(--space-md); +@media (max-width: 680px) { + .hero-cta .btn, + .cta-buttons .btn { + min-width: 0; + width: 100%; } +} - .feature-text h3 { - font-size: 1.5rem; - } +.hero-section, +.tech-highlights-section, +.updates-section, +.overview-section { + overflow-x: hidden; } + + .overview-section .section-header, .updates-section .section-header { width: 100%; diff --git a/src/styles/OurTeam.css b/src/styles/OurTeam.css new file mode 100644 index 0000000..2adbec3 --- /dev/null +++ b/src/styles/OurTeam.css @@ -0,0 +1,113 @@ +:root { + --orange: #fa4616; + --page-bg: #000000; + --shade-bg: #141414; + --card-bg: #1f1f1f; + --text-primary: #ffffff; + --text-secondary: #cccccc; +} + +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap'); + +/* ---------- page shell ---------- */ +.our-team-page { + min-height: 100px; + background: var(--page-bg); + color: var(--text-primary); + display: flex; + flex-direction: column; +} + +/* ---------- containers ---------- */ +.container-fluid { width: 100%; padding-inline: 1rem; } +.container-xl { width: 100%; max-width: 1440px; margin-inline: auto; padding-inline: 1rem; } + +.hero { padding-block: clamp(4rem, 10vw, 6rem) 0; } +.hero-title { font-size: clamp(3rem, 8vw, 5.5rem); line-height: 1.1; margin: 0; opacity: 0; animation: slideUp 1.2s ease forwards; } +.hero-title .highlight { + background: linear-gradient(90deg, #fa4616, #f7cbbe); /* ⬅️ your new gradient */ + background-size: 200% auto; + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +.team-section { + background: var(--shade-bg); + width: 100%; + margin-top: clamp(5rem, 10vw, 6rem); + padding-block: clamp(2rem, 5vw, 3rem) clamp(3rem, 6vw, 5rem); + padding-inline: clamp(0.5rem, 3vw, 2rem); + border-radius: 0.75rem 0.75rem 0 0; +} + +/* increase vertical gap so the grid sits lower */ +.team-section__inner { + display: flex; + flex-direction: column; + gap: clamp(2rem, 4vw, 2.75rem); /* ⬅️ was 1rem */ +} + +.grid-subtitle { + font-size: clamp(1.25rem, 2.2vw, 1.75rem); /* responsive subtitle size */ + color: var(--text-secondary); + text-align: center; + opacity: 0; + animation: slideUp 1.1s ease 0.15s forwards; +} + +.team-grid { + display: grid; + grid-template-columns: repeat(3, minmax(120px, 240px)); + row-gap: clamp(8rem, 0.1vw, 9rem); + column-gap: clamp(0.75rem, 3vw, 1.5rem); + margin-top: clamp(5rem, 3vw, 2rem); /* ⬅️ pushes grid down */ + opacity: 0; + animation: slideUp 1.2s ease 0.3s forwards; +} + + +/* card */ +.team-card { position:relative; background-color:var(--card-bg); border:1px solid transparent; border-top:4px solid var(--orange); border-radius:0.75rem; padding: 1.25rem 0.7rem 0.9rem; /* compact padding */ /* compact padding */ text-align:center; display:flex; flex-direction:column; align-items:center; min-height:170px; transition:transform 0.25s ease,border-color 0.25s ease,box-shadow 0.25s ease; } +@media(hover:hover){ .team-card:hover,.team-card:focus-visible{ transform:translate3d(0,-6px,0); border-color:var(--orange); box-shadow:0 4px 10px rgba(0,0,0,.35); } } +.team-card:focus-visible{ outline:2px solid var(--orange); outline-offset:4px; } + +/* image */ +.team-card__image-wrapper { + position: absolute; + top: -80px; + left: 50%; + translate: -50% 0; + width: 120px; + height: 120px; + border-radius: 0.5rem; + overflow: hidden; + box-shadow: none; + z-index: 1; + border: 1px solid var(--orange); +} +.team-card__image { + width:100%; + height:100%; + object-fit:cover; +} + +/* ---------- typography inside card ---------- */ +.team-card__name { font-family:'Poppins',sans-serif; font-size:1.25rem; font-weight:600; margin:0.3rem 0 0.2rem; } +.team-card__role { font-family:'Poppins',sans-serif; font-size:1.05rem; color:var(--text-secondary); } + +.team-card.no-photo{ padding-top:0.75rem; } +.team-card.has-photo{ padding-top:3.5rem; } + +/* ---------- CTA section ---------- */ +.cta-section{ background:linear-gradient(180deg,#111 0%,#000 80%); padding-block:clamp(4rem,10vw,6rem); margin-top:auto; } +.cta-wrapper{ text-align:center; max-width:720px; margin-inline:auto; } +.cta-heading{ font-size:clamp(2rem,5vw,3rem); font-weight:700; margin-bottom:1.5rem; } +.cta-buttons{ display:flex; flex-wrap:wrap; gap:1rem; justify-content:center; } +.btn{ padding:0.6rem 1.4rem; border-radius:9999px; font-weight:600; transition:background 0.2s ease; } +.btn-primary{ background:var(--orange); color:var(--text-primary);} .btn-primary:hover,.btn-primary:focus-visible{ background:#ff651f; } +.btn-secondary{ background:#ffffff10; color:var(--text-primary); border:1px solid #ffffff25;} .btn-secondary:hover,.btn-secondary:focus-visible{ background:#ffffff22; } + +/* ---------- animations ---------- */ +@keyframes slideUp{ from{ transform:translateY(30px); opacity:0;} to{ transform:translateY(0); opacity:1;} } +@keyframes gradientShift{ 0%{ background-position:0% center;} 100%{ background-position:200% center;} } \ No newline at end of file diff --git a/src/styles/RoboSub.css b/src/styles/RoboSub.css index 47a54d1..108a47f 100644 --- a/src/styles/RoboSub.css +++ b/src/styles/RoboSub.css @@ -3,18 +3,20 @@ /* Base styles for the page */ color: var(--color-text-primary); background-color: var(--color-background); - overflow-x: hidden; + height: calc(100vh - var(--navbar-height)); + overflow-x: visible; } /* Hero Section with regular background (not underwater) */ .robosub-page .robosub-hero-section { - height: 100vh; - position: relative; - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; - background-color: #000000; + height: calc(100vh - var(--navbar-height)); + position: relative; + align-items: center; + overflow: visible; + justify-content: center; + position: relative; + margin-top: 160px; + display: flex; } /* Background image styling similar to Home page */ @@ -80,7 +82,6 @@ .robosub-page .hero-title { font-size: clamp(3.5rem, 10vw, 7rem); - font-weight: 800; color: #ffffff; margin-bottom: 0; text-shadow: 0 0 15px rgba(0, 0, 0, 0.5); @@ -875,4 +876,11 @@ opacity: 1; transform: translateY(0); } - \ No newline at end of file + +.hero-bg { background-image: url("/src/assets/submarine-hero.jpg"); } +.hero-auv { content: url("/src/assets/submarines/subjugator_9.1.png"); } +.image-sub9-swim { content: url("/src/assets/submarines/sub9_cherry_1.png"); } +.image-sub9-frame { content: url("/src/assets/submarines/sub9_1.jpeg"); } +.image-electrical { content: url("/src/assets/PCB.png"); } +.image-sim-env { content: url("/src/assets/simulation_enviornment.png"); } +.image-robosub-logo { content: url("/src/assets/robosub_logo.png"); } diff --git a/src/styles/Sponsors.css b/src/styles/Sponsors.css new file mode 100644 index 0000000..6bf4aa3 --- /dev/null +++ b/src/styles/Sponsors.css @@ -0,0 +1,223 @@ +/* ---------- root palette ---------- */ +:root { + --orange: #fa4616; + --text-primary: #ffffff; + --text-secondary: #cccccc; + --shade-bg: #141414; +} + +/* ---------- page shell ---------- */ +.sponsors-page { + background-color: #000; + color: var(--text-primary); + min-height: 100vh; +} + +/* ---------- hero ---------- */ +.hero { + padding-block: clamp(4rem, 8vw, 6rem) 2rem; +} + +.hero-title { + color: var(--text-primary); /* ensures white text */ + font-size: clamp(2.5rem, 7vw, 5rem); + font-weight: 700; + margin: 0; +} + +.hero-title .highlight { + background: linear-gradient(90deg, #fa4616, #ff8c69); + background-clip: text; + -webkit-background-clip: text; + color: transparent; /* gradient text */ +} + +.hero-subtitle { + margin-top: 1rem; + font-size: 1.2rem; + color: var(--text-secondary); +} + +/* ---------- sponsor tiers ---------- */ +.sponsor-section { + padding-block: 5rem; +} + +.sponsor-section__title { + text-align: center; + font-size: 1.75rem; + font-weight: 600; + color: var(--orange); + margin-bottom: 2.5rem; + position: relative; + padding-bottom: 0.5rem; +} + +.sponsor-section__title::after { + content: ""; + position: absolute; + left: 50%; + bottom: 0; + transform: translateX(-50%); + width: 80px; + height: 3px; + background: var(--orange); + border-radius: 4px; +} + +.sponsor-grid { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 2rem; + row-gap: 3rem; +} + +/* ---------- sponsor card ---------- */ +.sponsor-card { + background: var(--shade-bg); /* dark card body */ + border-radius: 0.5rem; + padding: 1.5rem; + text-align: center; + max-width: 280px; + width: 100%; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25); + transition: transform 0.2s ease; +} + +.sponsor-card:hover { + transform: translateY(-4px); +} + +/* ---------- logo image ---------- */ +.sponsor-card__logo { + max-width: 100%; + max-height: 120px; /* larger logos */ + object-fit: contain; + margin-bottom: 1rem; +} + +/* allow explicit up-sizing via .large helper */ +.sponsor-card__logo.large { + max-height: 120px; /* matches default – keep for clarity */ +} + +/* ---------- name & optional description ---------- */ +.sponsor-card__name { + font-weight: 600; + font-size: 1.1rem; + margin-bottom: 0.5rem; +} + +.sponsor-card__description { + font-size: 0.95rem; + color: var(--text-secondary); +} +/* no background / box for each sponsor */ +.sponsor-card { + background: none; + box-shadow: none; + padding: 0; + transition: transform 0.2s ease; +} + +/* enlarge logos a bit */ +.sponsor-card__logo { + max-height: 140px; + margin-bottom: 0.8rem; +} + +/* remove underline & make company links white */ +.no-style-link { + text-decoration: none; + color: var(--text-primary); +} + +/* company names (inside anchor) inherit white text */ +.company-name a { color: var(--text-primary); } + +/* people names stay blue */ +.person-name { + color: #3b82f6; /* tailwind blue-500 */ +} + +.hero-subtitle { + max-width: 720px; + margin: 1rem auto; + font-size: 1.05rem; + color: var(--text-secondary); + line-height: 1.45; +} + +.sponsor-footer { + padding: 3rem 1rem 4rem; +} + +.sponsor-pdf-link { + color: var(--orange); + font-weight: 600; + text-decoration: underline; +} + +/* footer layout */ +.sponsor-footer { + padding: 4rem 1rem; + display: flex; + flex-direction: column; + align-items: center; + gap: 1.5rem; +} + +/* big white heading */ +.sponsor-call { + font-size: 4.5rem; /* larger */ + color: var(--text-primary); + margin: 0; +} + +/* blue gradient underline */ +.sponsor-underline { + display: block; + width: 140px; + height: 5px; + margin: 0.6rem auto 2rem; + border-radius: 9999px; + background: linear-gradient(90deg, #3b82f6 0%, #1e40af 100%); +} + +/* orange pill-button */ +.sponsor-btn { + background: var(--orange); /* orange by default */ + color: var(--text-primary); + padding: 1rem 2.4rem; + border-radius: 9999px; + font-weight: 600; + text-decoration: none; + transition: background 0.25s ease, transform 0.15s ease; +} + +/* turn blue – subtle lift on hover / focus */ +.sponsor-btn:hover, +.sponsor-btn:focus-visible { + background: #06369e; /* Tailwind blue-600 */ + transform: translateY(-2px); +} + +/* optional: shade darker while active / clicking */ +.sponsor-btn:active { + background: #1e40af; /* blue-800 */ + transform: translateY(0); +} + +/* keep button text white in every state */ +.sponsor-btn, +.sponsor-btn:visited, +.sponsor-btn:hover, +.sponsor-btn:focus-visible, +.sponsor-btn:active { + color: var(--text-primary) !important; +} + + + + diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..6a92648 --- /dev/null +++ b/vercel.json @@ -0,0 +1,5 @@ +{ + "rewrites": [ + { "source": "/(.*)", "destination": "/" } + ] +}