diff --git a/package-lock.json b/package-lock.json index ede8db8..d84fe5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,9 +17,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", "cpu": [ "ppc64" ], @@ -34,9 +34,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", "cpu": [ "arm" ], @@ -51,9 +51,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", "cpu": [ "arm64" ], @@ -68,9 +68,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", "cpu": [ "x64" ], @@ -85,9 +85,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], @@ -102,9 +102,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", "cpu": [ "x64" ], @@ -119,9 +119,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", "cpu": [ "arm64" ], @@ -136,9 +136,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", "cpu": [ "x64" ], @@ -153,9 +153,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", "cpu": [ "arm" ], @@ -170,9 +170,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", "cpu": [ "arm64" ], @@ -187,9 +187,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", "cpu": [ "ia32" ], @@ -204,9 +204,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", "cpu": [ "loong64" ], @@ -221,9 +221,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", "cpu": [ "mips64el" ], @@ -238,9 +238,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", "cpu": [ "ppc64" ], @@ -255,9 +255,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", "cpu": [ "riscv64" ], @@ -272,9 +272,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", "cpu": [ "s390x" ], @@ -289,9 +289,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ "x64" ], @@ -306,9 +306,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ "arm64" ], @@ -323,9 +323,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", "cpu": [ "x64" ], @@ -340,9 +340,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", "cpu": [ "arm64" ], @@ -357,9 +357,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", "cpu": [ "x64" ], @@ -373,10 +373,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", "cpu": [ "x64" ], @@ -391,9 +408,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", "cpu": [ "arm64" ], @@ -408,9 +425,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", "cpu": [ "ia32" ], @@ -425,9 +442,9 @@ } }, "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.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", "cpu": [ "x64" ], @@ -442,9 +459,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", - "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.48.0.tgz", + "integrity": "sha512-aVzKH922ogVAWkKiyKXorjYymz2084zrhrZRXtLrA5eEx5SO8Dj0c/4FpCHZyn7MKzhW2pW4tK28vVr+5oQ2xw==", "cpu": [ "arm" ], @@ -456,9 +473,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", - "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.48.0.tgz", + "integrity": "sha512-diOdQuw43xTa1RddAFbhIA8toirSzFMcnIg8kvlzRbK26xqEnKJ/vqQnghTAajy2Dcy42v+GMPMo6jq67od+Dw==", "cpu": [ "arm64" ], @@ -470,9 +487,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", - "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.48.0.tgz", + "integrity": "sha512-QhR2KA18fPlJWFefySJPDYZELaVqIUVnYgAOdtJ+B/uH96CFg2l1TQpX19XpUMWUqMyIiyY45wje8K6F4w4/CA==", "cpu": [ "arm64" ], @@ -484,9 +501,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", - "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.48.0.tgz", + "integrity": "sha512-Q9RMXnQVJ5S1SYpNSTwXDpoQLgJ/fbInWOyjbCnnqTElEyeNvLAB3QvG5xmMQMhFN74bB5ZZJYkKaFPcOG8sGg==", "cpu": [ "x64" ], @@ -498,9 +515,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", - "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.48.0.tgz", + "integrity": "sha512-3jzOhHWM8O8PSfyft+ghXZfBkZawQA0PUGtadKYxFqpcYlOYjTi06WsnYBsbMHLawr+4uWirLlbhcYLHDXR16w==", "cpu": [ "arm64" ], @@ -512,9 +529,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", - "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.48.0.tgz", + "integrity": "sha512-NcD5uVUmE73C/TPJqf78hInZmiSBsDpz3iD5MF/BuB+qzm4ooF2S1HfeTChj5K4AV3y19FFPgxonsxiEpy8v/A==", "cpu": [ "x64" ], @@ -526,9 +543,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", - "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.48.0.tgz", + "integrity": "sha512-JWnrj8qZgLWRNHr7NbpdnrQ8kcg09EBBq8jVOjmtlB3c8C6IrynAJSMhMVGME4YfTJzIkJqvSUSVJRqkDnu/aA==", "cpu": [ "arm" ], @@ -540,9 +557,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", - "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.48.0.tgz", + "integrity": "sha512-9xu92F0TxuMH0tD6tG3+GtngwdgSf8Bnz+YcsPG91/r5Vgh5LNofO48jV55priA95p3c92FLmPM7CvsVlnSbGQ==", "cpu": [ "arm" ], @@ -554,9 +571,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", - "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.48.0.tgz", + "integrity": "sha512-NLtvJB5YpWn7jlp1rJiY0s+G1Z1IVmkDuiywiqUhh96MIraC0n7XQc2SZ1CZz14shqkM+XN2UrfIo7JB6UufOA==", "cpu": [ "arm64" ], @@ -568,9 +585,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", - "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.48.0.tgz", + "integrity": "sha512-QJ4hCOnz2SXgCh+HmpvZkM+0NSGcZACyYS8DGbWn2PbmA0e5xUk4bIP8eqJyNXLtyB4gZ3/XyvKtQ1IFH671vQ==", "cpu": [ "arm64" ], @@ -582,9 +599,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", - "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.48.0.tgz", + "integrity": "sha512-Pk0qlGJnhILdIC5zSKQnprFjrGmjfDM7TPZ0FKJxRkoo+kgMRAg4ps1VlTZf8u2vohSicLg7NP+cA5qE96PaFg==", "cpu": [ "loong64" ], @@ -595,10 +612,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", - "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.48.0.tgz", + "integrity": "sha512-/dNFc6rTpoOzgp5GKoYjT6uLo8okR/Chi2ECOmCZiS4oqh3mc95pThWma7Bgyk6/WTEvjDINpiBCuecPLOgBLQ==", "cpu": [ "ppc64" ], @@ -610,9 +627,23 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", - "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.48.0.tgz", + "integrity": "sha512-YBwXsvsFI8CVA4ej+bJF2d9uAeIiSkqKSPQNn0Wyh4eMDY4wxuSp71BauPjQNCKK2tD2/ksJ7uhJ8X/PVY9bHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.48.0.tgz", + "integrity": "sha512-FI3Rr2aGAtl1aHzbkBIamsQyuauYtTF9SDUJ8n2wMXuuxwchC3QkumZa1TEXYIv/1AUp1a25Kwy6ONArvnyeVQ==", "cpu": [ "riscv64" ], @@ -624,9 +655,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", - "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.48.0.tgz", + "integrity": "sha512-Dx7qH0/rvNNFmCcIRe1pyQ9/H0XO4v/f0SDoafwRYwc2J7bJZ5N4CHL/cdjamISZ5Cgnon6iazAVRFlxSoHQnQ==", "cpu": [ "s390x" ], @@ -638,9 +669,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", - "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.48.0.tgz", + "integrity": "sha512-GUdZKTeKBq9WmEBzvFYuC88yk26vT66lQV8D5+9TgkfbewhLaTHRNATyzpQwwbHIfJvDJ3N9WJ90wK/uR3cy3Q==", "cpu": [ "x64" ], @@ -652,9 +683,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", - "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.48.0.tgz", + "integrity": "sha512-ao58Adz/v14MWpQgYAb4a4h3fdw73DrDGtaiF7Opds5wNyEQwtO6M9dBh89nke0yoZzzaegq6J/EXs7eBebG8A==", "cpu": [ "x64" ], @@ -666,9 +697,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", - "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.48.0.tgz", + "integrity": "sha512-kpFno46bHtjZVdRIOxqaGeiABiToo2J+st7Yce+aiAoo1H0xPi2keyQIP04n2JjDVuxBN6bSz9R6RdTK5hIppw==", "cpu": [ "arm64" ], @@ -680,9 +711,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", - "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.48.0.tgz", + "integrity": "sha512-rFYrk4lLk9YUTIeihnQMiwMr6gDhGGSbWThPEDfBoU/HdAtOzPXeexKi7yU8jO+LWRKnmqPN9NviHQf6GDwBcQ==", "cpu": [ "ia32" ], @@ -694,9 +725,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", - "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.48.0.tgz", + "integrity": "sha512-sq0hHLTgdtwOPDB5SJOuaoHyiP1qSwg+71TQWk8iDS04bW1wIE0oQ6otPiRj2ZvLYNASLMaTp8QRGUVZ+5OL5A==", "cpu": [ "x64" ], @@ -714,9 +745,9 @@ "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==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, @@ -753,9 +784,9 @@ "license": "BSD-3-Clause" }, "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.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -766,31 +797,50 @@ "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.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, "node_modules/fflate": { @@ -821,9 +871,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -846,10 +896,23 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -867,7 +930,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -876,13 +939,13 @@ } }, "node_modules/rollup": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", - "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", + "version": "4.48.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.48.0.tgz", + "integrity": "sha512-BXHRqK1vyt9XVSEHZ9y7xdYtuYbwVod2mLwOMFP7t/Eqoc1pHRlG/WdV2qNeNvZHRQdLedaFycljaYYM96RqJQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -892,25 +955,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.30.1", - "@rollup/rollup-android-arm64": "4.30.1", - "@rollup/rollup-darwin-arm64": "4.30.1", - "@rollup/rollup-darwin-x64": "4.30.1", - "@rollup/rollup-freebsd-arm64": "4.30.1", - "@rollup/rollup-freebsd-x64": "4.30.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", - "@rollup/rollup-linux-arm-musleabihf": "4.30.1", - "@rollup/rollup-linux-arm64-gnu": "4.30.1", - "@rollup/rollup-linux-arm64-musl": "4.30.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", - "@rollup/rollup-linux-riscv64-gnu": "4.30.1", - "@rollup/rollup-linux-s390x-gnu": "4.30.1", - "@rollup/rollup-linux-x64-gnu": "4.30.1", - "@rollup/rollup-linux-x64-musl": "4.30.1", - "@rollup/rollup-win32-arm64-msvc": "4.30.1", - "@rollup/rollup-win32-ia32-msvc": "4.30.1", - "@rollup/rollup-win32-x64-msvc": "4.30.1", + "@rollup/rollup-android-arm-eabi": "4.48.0", + "@rollup/rollup-android-arm64": "4.48.0", + "@rollup/rollup-darwin-arm64": "4.48.0", + "@rollup/rollup-darwin-x64": "4.48.0", + "@rollup/rollup-freebsd-arm64": "4.48.0", + "@rollup/rollup-freebsd-x64": "4.48.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.48.0", + "@rollup/rollup-linux-arm-musleabihf": "4.48.0", + "@rollup/rollup-linux-arm64-gnu": "4.48.0", + "@rollup/rollup-linux-arm64-musl": "4.48.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.48.0", + "@rollup/rollup-linux-ppc64-gnu": "4.48.0", + "@rollup/rollup-linux-riscv64-gnu": "4.48.0", + "@rollup/rollup-linux-riscv64-musl": "4.48.0", + "@rollup/rollup-linux-s390x-gnu": "4.48.0", + "@rollup/rollup-linux-x64-gnu": "4.48.0", + "@rollup/rollup-linux-x64-musl": "4.48.0", + "@rollup/rollup-win32-arm64-msvc": "4.48.0", + "@rollup/rollup-win32-ia32-msvc": "4.48.0", + "@rollup/rollup-win32-x64-msvc": "4.48.0", "fsevents": "~2.3.2" } }, @@ -930,6 +994,23 @@ "integrity": "sha512-AUwVmViIEUgBwxJJ7stnF0NkPpZxx1aZ6WiAbQ/Qq61h6I9UR4grXtZDmO8mnlaNORhHnIBlXJ1uBxILEKuVyw==", "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, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", @@ -945,15 +1026,18 @@ } }, "node_modules/vite": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz", - "integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==", + "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.4.49", - "rollup": "^4.23.0" + "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/src/components/cd-cover/index.ts b/src/components/cd-cover/index.ts deleted file mode 100644 index 01604bc..0000000 --- a/src/components/cd-cover/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -import './styles.css'; - -export type cdCoverContent = { - readonly coverTitle: string; - readonly coverDescription: string; - readonly coverImage: string; -} - -// -------------------------------------------------------------------------------- - -export function cdCover() { - const cdItem = document.createElement('div'); - const cover = document.createElement('div'); - const textBlurb = document.createElement('div'); - const title = document.createElement('p'); - const description = document.createElement('p'); - - cdItem.className = 'cd-cover'; - cover.className = 'cover-image'; - textBlurb.className = 'cover-text-blurb'; - title.className = 'cover-title'; - description.className = 'cover-description'; - - title.textContent = "test"; - description.textContent = 'This is a test description for the CD cover.'; - - textBlurb.appendChild(title); - textBlurb.appendChild(description); - cdItem.appendChild(cover); - cdItem.appendChild(textBlurb); - - return cdItem; -} \ No newline at end of file diff --git a/src/components/cd-cover/styles.css b/src/components/cd-cover/styles.css deleted file mode 100644 index 98f59ff..0000000 --- a/src/components/cd-cover/styles.css +++ /dev/null @@ -1,11 +0,0 @@ -.cd-cover { - max-width: 100%; - text-align: center; -} - -.cover-image { - width: 100%; - height: 250px; - background-color: #3BFFC5; -} - diff --git a/src/components/logo/assets/cd-labs-logo.png b/src/components/logo/assets/cd-labs-logo.png new file mode 100755 index 0000000..d176a68 Binary files /dev/null and b/src/components/logo/assets/cd-labs-logo.png differ diff --git a/src/components/logo/index.ts b/src/components/logo/index.ts new file mode 100644 index 0000000..7e80041 --- /dev/null +++ b/src/components/logo/index.ts @@ -0,0 +1,35 @@ +import './styles.css'; +import LOGO from './assets/cd-labs-logo.png'; + +// -------------------------------------------------------------------------------- + +export function buildMainLogo() { + const logoContainer = document.createElement('div'); + const logoImg = document.createElement('img'); + const logoText = document.createElement('p'); + + logoContainer.className = 'main-logo'; + + logoImg.src = LOGO; + logoImg.alt = "CD-Labs Logo"; + + logoText.textContent = "CD-Labs"; + + logoContainer.appendChild(logoImg); + logoContainer.appendChild(logoText); + + return logoContainer; +} + +// -------------------------------------------------------------------------------- + +export function changeLogoOnScroll() { + const logoContainer = document.querySelector('.main-logo') as HTMLElement; + if (!logoContainer) return; + + if (window.scrollY > 50) { + logoContainer.classList.add('scrolled'); + } else { + logoContainer.classList.remove('scrolled'); + } +} \ No newline at end of file diff --git a/src/components/logo/styles.css b/src/components/logo/styles.css new file mode 100644 index 0000000..825aca4 --- /dev/null +++ b/src/components/logo/styles.css @@ -0,0 +1,46 @@ +.main-logo { + position: fixed; + top: 40px; + left: 55px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 10; + + img { + width: 95px; + height: 95px; + image-rendering: pixelated; + transition: width 0.3s, height 0.3s; + } + + img:hover { + animation: rotate 0.5s steps(4) infinite; + } + + p { + margin-top: 9px; + text-align: center; + text-transform: uppercase; + font-family: "Handjet", sans-serif; + font-size: 2em; + font-weight: 900; + transition: opacity 0.3s; + } +} + +.main-logo.scrolled img { + width: 60px; + height: 60px; +} + +.main-logo.scrolled p { + opacity: 0; + pointer-events: none; +} + + +@keyframes rotate { + 100% { + transform: rotate(360deg); + } +} + diff --git a/src/components/pixel-grid/index.ts b/src/components/pixel-grid/index.ts new file mode 100644 index 0000000..ef685ca --- /dev/null +++ b/src/components/pixel-grid/index.ts @@ -0,0 +1,96 @@ +import './styles.css'; +import { createPixelPattern } from './pixel.ts'; + +export type GRID_CONFIG = { + rows: number; + colors: string[]; +}; + +const EMPTY_RATIO = 0.5; // Fixed constant for empty bias + +// -------------------------------------------------------------------------------- + +export function createPixelGrid(config: GRID_CONFIG, alignment: 'left' | 'right'): HTMLCanvasElement { + const canvas = createCanvasElement(); + const ctx = canvas.getContext('2d'); + + if (!ctx) return canvas; + + // Use ResizeObserver for responsive updates + const resizeObserver = new ResizeObserver(() => { + const parent = canvas.parentElement; + if (parent) { + renderPixelGrid(canvas, ctx, config, alignment, parent.clientWidth, parent.clientHeight); + } + }); + + // Initial render + setTimeout(() => { + const parent = canvas.parentElement; + if (parent) { + resizeObserver.observe(parent); + renderPixelGrid(canvas, ctx, config, alignment, parent.clientWidth, parent.clientHeight); + } + }, 0); + + return canvas; +} + +// -------------------------------------------------------------------------------- + +function createCanvasElement(): HTMLCanvasElement { + const canvas = document.createElement('canvas'); + canvas.className = 'pixel-grid'; + canvas.style.width = '100%'; + canvas.style.height = '100%'; + canvas.style.display = 'block'; + return canvas; +} + +function renderPixelGrid( + canvas: HTMLCanvasElement, + ctx: CanvasRenderingContext2D, + config: GRID_CONFIG, + alignment: 'left' | 'right', + width: number, + height: number +) { + // Setup canvas + canvas.width = width; + canvas.height = height; + ctx.clearRect(0, 0, width, height); + + // Calculate pixel size based on rows (perfect squares) + const pixelSize = height / config.rows; + + // Calculate number of columns dynamically based on width and pixel size + const cols = Math.ceil(width / pixelSize); + + const canvasRect = canvas.getBoundingClientRect(); + + // Render each pixel + for (let row = 0; row < config.rows; row++) { + for (let col = 0; col < cols; col++) { + const screenX = canvasRect.left + (col * pixelSize); + const color = createPixelPattern({ + row, + col, + totalRows: config.rows, + totalCols: cols, + screenX, + screenWidth: window.innerWidth, + alignment, + emptyRatio: EMPTY_RATIO, + colors: config.colors + }); + + if (color) { + ctx.fillStyle = color; + const x = Math.floor(col * pixelSize); + const y = Math.floor(row * pixelSize); + const size = Math.ceil(pixelSize) + 1; + ctx.fillRect(x, y, size, size); + } + } + } +} \ No newline at end of file diff --git a/src/components/pixel-grid/pixel.ts b/src/components/pixel-grid/pixel.ts new file mode 100644 index 0000000..3017856 --- /dev/null +++ b/src/components/pixel-grid/pixel.ts @@ -0,0 +1,70 @@ + +type PixelInput = { + row: number; + col: number; + totalRows: number; + totalCols: number; + screenX: number; + screenWidth: number; + alignment: 'left' | 'right'; + emptyRatio: number; + colors: readonly string[]; +}; + +// -------------------------------------------------------------------------------- + +export function createPixelPattern(input: PixelInput): string | null { + const normalizedX = input.col / (input.totalCols - 1); + const normalizedY = input.row / (input.totalRows - 1); + const normalizedScreenX = input.screenX / input.screenWidth; + + const isEmpty = shouldPixelBeEmpty( + normalizedX, + normalizedScreenX, + normalizedY, + input.alignment, + input.emptyRatio + ); + + return isEmpty ? null : getRandomColor(input.colors); +} + +// -------------------------------------------------------------------------------- + +function shouldPixelBeEmpty( + _normalizedX: number, // Container position (unused, kept for future use) + normalizedScreenX: number, + normalizedY: number, + alignment: 'left' | 'right', + emptyRatio: number +): boolean { + const boundary = calculateBoundary(normalizedY, emptyRatio); + + if (alignment === 'right') { + return normalizedScreenX > boundary ? hasGhostPixel() : hasScatterEffect(normalizedScreenX, boundary, normalizedY); + } else { + return normalizedScreenX < boundary ? hasGhostPixel() : hasScatterEffect(normalizedScreenX, boundary, normalizedY); + } +} + +function calculateBoundary(normalizedY: number, emptyRatio: number): number { + const waveOffset = Math.sin(normalizedY * Math.PI * 3) * 0.1; + const randomOffset = (Math.random() - 0.5) * 0.15; + return emptyRatio + waveOffset + randomOffset; +} + +function hasScatterEffect(screenX: number, boundary: number, normalizedY: number): boolean { + const distance = Math.abs(screenX - boundary); + const scatterChance = Math.pow(1 - distance / boundary, 2) * 0.25; + const rowVariation = Math.sin(normalizedY * Math.PI * 2) * 0.1; + + return Math.random() < (scatterChance + rowVariation); +} + +function hasGhostPixel(): boolean { + return Math.random() >= 0.3; +} + +function getRandomColor(colors: readonly string[]): string { + return colors[Math.floor(Math.random() * colors.length)]; +} \ No newline at end of file diff --git a/src/components/pixel-grid/styles.css b/src/components/pixel-grid/styles.css new file mode 100644 index 0000000..70ed05f --- /dev/null +++ b/src/components/pixel-grid/styles.css @@ -0,0 +1,20 @@ +canvas.pixel-grid { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; + overflow: hidden; + background: transparent; +} + +.pixel { + transition: background 0.2s; +} + +.pixel-empty { + background: transparent !important; + opacity: 0; +} \ No newline at end of file diff --git a/src/components/top-nav/index.ts b/src/components/top-nav/index.ts new file mode 100644 index 0000000..82cf75e --- /dev/null +++ b/src/components/top-nav/index.ts @@ -0,0 +1,37 @@ +import './styles.css'; + +type LinkItem = [ + name: string, + path: string, +] + +const navLinks: LinkItem[] = [ + ['Side Quests', '/projects'], + ['About', '/about'], + ['Logs', '/logs'], + ['Contact', '/contact'], +] + +//----------------------------------------------------------------------- + +export function buildTopNav() { + const navBox = document.createElement("div"); + const ul = document.createElement("ul"); + + navBox.id = "top-nav"; + + navLinks.forEach(link => { + const [name, path] = link; + const li = document.createElement("li"); + const a = document.createElement("a"); + + a.href = path; + a.textContent = name; + + li.appendChild(a); + ul.appendChild(li); + }) + + navBox.appendChild(ul); + return navBox +} \ No newline at end of file diff --git a/src/components/top-nav/styles.css b/src/components/top-nav/styles.css new file mode 100644 index 0000000..ec7732c --- /dev/null +++ b/src/components/top-nav/styles.css @@ -0,0 +1,44 @@ +#top-nav { + position: fixed; + top: 40px; + left: 50%; + transform: translateX(-50%); + display: flex; + text-align: center; + padding: 0 50px; + z-index: 10; + + ul { + display: flex; + align-items: center; + justify-content: space-between; + gap: 50px; + height: 60px; + margin: 0; + padding: 0 35px; + list-style: none; + + border: 2px solid rgba(255, 255, 255, 0.1); + border-radius: 30px; + background-color: rgba(255, 255, 255, 0.05); + + backdrop-filter: blur(30px); + -webkit-backdrop-filter: blur(30px); + overflow: hidden; + } + + li a { + font-family: "Handjet", sans-serif; + font-size: 1.5em; + font-weight: 500; + text-transform: lowercase; + text-decoration: none; + color: #ffffff; + cursor: pointer; + transition: color 0.3s ease; + + &:hover { + color: #3BFFC5; + } + } +} \ No newline at end of file diff --git a/src/components/vertical-nav/assets/github-icon.svg b/src/components/vertical-nav/assets/github-icon.svg deleted file mode 100644 index c8ccfd2..0000000 --- a/src/components/vertical-nav/assets/github-icon.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/components/vertical-nav/assets/instagram-icon.svg b/src/components/vertical-nav/assets/instagram-icon.svg deleted file mode 100644 index d53e54b..0000000 --- a/src/components/vertical-nav/assets/instagram-icon.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/components/vertical-nav/assets/linkedin-icon.svg b/src/components/vertical-nav/assets/linkedin-icon.svg deleted file mode 100644 index 3b20022..0000000 --- a/src/components/vertical-nav/assets/linkedin-icon.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/src/components/vertical-nav/index.ts b/src/components/vertical-nav/index.ts deleted file mode 100644 index 1ba81d7..0000000 --- a/src/components/vertical-nav/index.ts +++ /dev/null @@ -1,118 +0,0 @@ -import './styles.css'; - -import cdIcon from "/img/common/cd_icon_green.png"; -import githubIcon from "./assets/github-icon.svg"; -import linkedIcon from "./assets/linkedin-icon.svg"; -import instagramIcon from "./assets/instagram-icon.svg"; -import {navLinks} from "./nav-links.ts"; - -const navTitle = "CD-BASH"; -const githubProfile: string = "https://github.com/CD-BASH" -const linkedinProfile: string = "https://www.linkedin.com/in/charlesdouc/" -const instagramProfile: string = "https://www.instagram.com/charlesdouc/" -const footerCopyrights: string = "© 2025 Charles Doucet - All Rights Reserved"; - -type SocialLink = [ - path: string, - image: string, -] - -const FOO_SOCIALS: SocialLink[] = [ - [githubProfile, githubIcon], - [linkedinProfile, linkedIcon], - [instagramProfile, instagramIcon] -] - -//----------------------------------------------------------------------- - -export function buildVerticalNav() { - const navBox = document.createElement("div"); - const navHeader = header(); - const navLinksSection = navLinks(); - const navInfo = document.createElement("div"); - const navFooter = footer(); - - navBox.id = "vertical-nav"; - navInfo.id = "nav-info"; - - navBox.appendChild(navHeader); - navHeader.appendChild(navLinksSection); - navBox.appendChild(navInfo); - navBox.appendChild(navFooter); - - return navBox; -} - - -export function renderNavInfo(info: HTMLElement) { - const navInfo = clearInfo(); - navInfo?.appendChild(info); -} - -//----------------------------------------------------------------------- - -const header = () => { - const container = document.createElement("div"); - const topTriangle = document.createElement("div"); - const logo = document.createElement("div"); - const icon = document.createElement("img"); - const title = document.createElement("h5"); - - container.className = "header"; - topTriangle.className = "top-triangle"; - - logo.className = "info"; - icon.className = "icon"; - icon.src = cdIcon; - - title.textContent = navTitle; - - container.appendChild(topTriangle); - container.appendChild(logo); - logo.appendChild(icon); - logo.appendChild(title); - - return container; -} - - -const footer = () => { - const container = document.createElement("div"); - const socials = document.createElement("ul"); - const copyrights = document.createElement("p"); - - container.className = "nav-footer"; - socials.className = "socials"; - copyrights.className = "copyrights"; - copyrights.textContent = footerCopyrights; - - container.appendChild(socials); - container.appendChild(copyrights); - - FOO_SOCIALS.forEach(social => { - const [path, image] = social; - const socialLink = document.createElement("li"); - const link = document.createElement("a"); - const icon = document.createElement("img"); - - link.href = path; - link.target = "_blank"; - icon.src = image; - - socials.appendChild(socialLink); - socialLink.appendChild(link); - link.appendChild(icon); - }) - - return container; -} - - -function clearInfo() { - const cleanInfo = document.getElementById('nav-info'); - cleanInfo?.childNodes.forEach((childNode) => { - cleanInfo.removeChild(childNode); - }); - - return cleanInfo; -} \ No newline at end of file diff --git a/src/components/vertical-nav/info-project.ts b/src/components/vertical-nav/info-project.ts deleted file mode 100644 index 0f6d00d..0000000 --- a/src/components/vertical-nav/info-project.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {threeDataViewer} from "../three-radar-chart"; -import {TechUsage} from "../three-radar-chart/radar.ts"; - - -export type ButtonLink = [ - label: string, - path: string, - highlight: boolean, -] - -//----------------------------------------------------------------------- - -export function projectInfo(buttons: ButtonLink[], techs: TechUsage[]) { - const container = document.createElement('div'); - const buttonList = document.createElement('ul'); - - container.className = "project-info"; - buttonList.className = "button-list"; - container.appendChild(dataSection(techs)); - container.appendChild(buttonList); - - buttons.forEach(button => { - buttonList.appendChild(createButton(button)); - }) - - return container; -} - -//----------------------------------------------------------------------- - - -function createButton(newButton: ButtonLink) { - const btn = document.createElement('li'); - const btnLine = document.createElement('a'); - const [label, path, highlight] = newButton; - - if (highlight) { - btn.className = "btn-highlight"; - } - - btnLine.type = "button"; - btnLine.textContent = label; - btnLine.href = path; - btnLine.target = "_blank"; - - btn.appendChild(btnLine); - return btn; -} - -function dataSection(newTechRadar: TechUsage[]) { - const detailSection = document.createElement("section"); - const detailTitle = document.createElement("h4"); - detailTitle.textContent = "Made with"; - - detailSection.appendChild(detailTitle); - detailSection.appendChild(threeDataViewer(newTechRadar)); - - return detailSection; -} - - - diff --git a/src/components/vertical-nav/nav-links.ts b/src/components/vertical-nav/nav-links.ts deleted file mode 100644 index 96d0fa9..0000000 --- a/src/components/vertical-nav/nav-links.ts +++ /dev/null @@ -1,40 +0,0 @@ -type NavLinkItem = [ - name: string, - path: string, - color: string, - textColor: string, -] - -const navLinkItems: NavLinkItem[] = [ - ['Home', '/', '#3BFFC5', 'black'], - ['Projects', '/projects', '#3B62FF', 'black'], - ['Logs', '/logs', '#1E1E1E', 'white'], - ['About', '/about', '#1E1E1E', 'white'], - ['Contact', '/contact', '#1E1E1E', 'white'], -] - -//----------------------------------------------------------------------- - -export function navLinks() { - const nav = document.createElement('nav'); - const ul = document.createElement('ul'); - - nav.className = 'nav-links'; - nav.appendChild(ul); - - navLinkItems.forEach(LinkItem => { - const [name, path, color, textColor] = LinkItem; - const li = document.createElement('li'); - const link = document.createElement('a'); - - link.href = path; - link.textContent = name; - link.style.backgroundColor = color; - link.style.color = textColor; - - ul.appendChild(li); - li.appendChild(link); - }); - - return nav; -} \ No newline at end of file diff --git a/src/components/vertical-nav/styles.css b/src/components/vertical-nav/styles.css deleted file mode 100644 index 3775620..0000000 --- a/src/components/vertical-nav/styles.css +++ /dev/null @@ -1,188 +0,0 @@ -#vertical-nav { - position: fixed; - top: 60px; - left: 30px; - width: 215px; - - .header { - background-color: #101010; - border-radius: 15px; - padding: 0 0 5px 0; - box-shadow: #030303 0px 0px 56px 0px; - - - .top-triangle { - position: relative; - width: 100%; - height: 100px; - clip-path: polygon(0 0, 100% 0, 0 100%); - background-color: #3BFFC5; - z-index: 1; - border-radius: 15px 15px 0 0; - } - - .info { - text-align: center; - margin-top: -85px; - } - - .icon { - position: relative; - width: 96px; - image-rendering: pixelated; - z-index: 2; - } - - h5 { - font-family: "Handjet", serif; - color: white; - margin: 0; - font-weight: 300; - font-size: 3em; - text-transform: uppercase; - } - } - - .nav-links { - list-style-type: none; - margin: 10px 0 30px 0; - padding: 0; - text-transform: lowercase; - - ul { - list-style-type: none; - text-align: center; - margin: 0; - padding: 0; - } - - li { - display: inline-block; - margin: 0 5px; - line-height: 210%; - color: white; - font-family: "handjet", serif; - } - - li a { - font-family: "handjet", serif; - font-weight: 700; - text-decoration: none; - color: black; - padding: 4px 6px; - margin-right: 5px; - - } - } - - #nav-info { - margin-top: 20px; - width: 100%; - background-color: #101010; - box-shadow: #030303 0px 0px 56px 0px; - border-radius: 15px; - - .project-info { - padding: 20px 15px; - } - - canvas { - width: 100%; - height: 100%; - border-radius: 5px; - } - - canvas:hover { - cursor: pointer; - } - - canvas:active { - cursor: grabbing; - } - - - section { - padding: 10px 0; - - h4 { - font-family: "Cabin", sans-serif; - color: white; - text-transform: uppercase; - font-weight: bold; - font-size: 1em; - margin: 0 0 15px 0; - padding: 0; - } - } - - .button-list { - list-style-type: none; - padding: 0; - - li { - margin: 5px 0; - - } - - a { - display: block; - width: 100%; - font-family: "Handjet", serif; - font-size: 1.2em; - padding: 10px 0; - border-radius: 5px; - border: none; - color: white; - text-decoration: none; - font-weight: bold; - text-transform: uppercase; - text-align: center; - background-color: #252525; - } - - .btn-highlight a { - background-color: #FF523B; - } - } - } - - - .nav-footer { - margin-top: 20px; - width: 100%; - text-align: center; - color: white; - font-family: "Cabin", sans-serif; - - .socials { - list-style-type: none; - margin: 0; - padding: 0; - } - - .socials li { - display: inline-block; - width: 17px; - margin: 0 5px; - } - - .socials li:hover { - opacity: 0.5; - } - - .socials img { - color: white; - z-index: 500; - - } - - .copyrights { - font-size: 0.6em; - color: #a1a1a1; - } - - .button-container { - width: 100%; - } - } -} \ No newline at end of file diff --git a/src/content/home/assets/cd-labs-home-page-hook-animation.mp4 b/src/content/home/assets/cd-labs-home-page-hook-animation.mp4 new file mode 100644 index 0000000..7bd060c Binary files /dev/null and b/src/content/home/assets/cd-labs-home-page-hook-animation.mp4 differ diff --git a/src/content/home/assets/cd-labs-home-page-hook-animation.webm b/src/content/home/assets/cd-labs-home-page-hook-animation.webm new file mode 100644 index 0000000..5fc0121 Binary files /dev/null and b/src/content/home/assets/cd-labs-home-page-hook-animation.webm differ diff --git a/src/content/home/assets/philosophy-background-temp.png b/src/content/home/assets/philosophy-background-temp.png new file mode 100644 index 0000000..e310a24 Binary files /dev/null and b/src/content/home/assets/philosophy-background-temp.png differ diff --git a/src/content/home/index.ts b/src/content/home/index.ts new file mode 100644 index 0000000..bfad40d --- /dev/null +++ b/src/content/home/index.ts @@ -0,0 +1,112 @@ +import {HomePageContentStructure} from "../../views"; + +import HOOK_VIDEO_WEBM from './assets/cd-labs-home-page-hook-animation.webm'; +import HOOK_VIDEO_MP4 from './assets/cd-labs-home-page-hook-animation.mp4'; + +import PHILOSOPHY_BG from './assets/philosophy-background-temp.png'; + +export const homePageContent: HomePageContentStructure = { + hook: { + header: "When was the last time you finished a game?", + body: "CD-Labs’ initiative is to design complete gaming experiences for busy lives.", + videoWebem: HOOK_VIDEO_WEBM, + videoMp4: HOOK_VIDEO_MP4, + }, + + // ------------------------------------------------------------------------ + philosophy: { + sectionBG: PHILOSOPHY_BG, + header: "Games that respect your time.", + + paragraphs: [ + "I believe gaming should be an escape, not a second job. But as games have gotten bigger and more demanding, it's become harder to find the time to even finish one.", + "That's why I started cd-labs. My goal is to deliver compact, complete gaming experiences that honor your schedule. Each game is a focused, handcrafted quest meant to be enjoyed in a single sitting or over a few evenings.", + ], + buttons: [ + { text: "Read More", path: "#", styleType: "secondary", contrastMode: 'dark' }, + { text: "First Production", path: "#", styleType: "primary", contrastMode: 'dark' } + ], + + alignment: 'left' + }, + + // ------------------------------------------------------------------------ + teaser: { + sectionBG: PHILOSOPHY_BG, + + introTitle: "The First Experience is Taking Shape", + header: "Project Aqua", + + paragraphs: [ + "Inspired by the frustrations of everyday bad design, Aqua places you in a sleek testing facility. Your mission: master a series of deceptively simple shower prototypes.", + "In this fast-paced puzzler, can you solve one of design's most infuriating problems—the shower interface—and calibrate each prototype?", + "A sharp puzzle and a fresh perspective distilled into a single, focused game.CD?", + + paragraphs: [ + "Hi, I'm CD. After more than a decade as a professional designer and developer in marketing, web, and the AAA games industry, I decided to take a different path. I left the world of blockbuster recipes behind to focus on what I love most: crafting truly unique gameplay ideas.", + "My goal with cd-labs is simple: to bring back that classic feeling of seeing a story through to its conclusion. I design my games to leave you feeling satisfied and inspired, not drained by an endless time commitment.", + ], + + buttons: [ + { text: "Let's connect", path: "#", styleType: "primary", contrastMode: 'dark' }, + { text: "Read my story", path: "#", styleType: "secondary", contrastMode: 'dark' }, + ], + + alignment: 'left' + }, + + // ------------------------------------------------------------------------ + sideQuests: { + sectionBG: PHILOSOPHY_BG, + + introTitle: "Collaborating on New Interactive Adventures", + header: "Side Quests", + + paragraphs: [ + "While my main quest is crafting original games for cd-labs, I also take on special contract work. These 'side quests' allow me to collaborate with innovative clients on their own interactive adventures.", + "I apply the same philosophy of focused, user-centric design to these projects, helping build everything from polished prototypes to unique web applications. It's a chance to tackle new challenges and help bring other exciting visions to life.", + ], + buttons: [ + { text: "Start a side quest", path: "#", styleType: "primary", contrastMode: 'dark' }, + { text: "See our main quest", path: "#", styleType: "secondary", contrastMode: 'dark' } + ], + + alignment: 'right' + }, + + // ------------------------------------------------------------------------ + ctaBannerB: { + header: "Ready to press start?", + body: "Follow the development of Aqua, chat with other players, and get behind-the-scenes updates in the official cd-labs Discord server.", + buttons: [ + { text: "Join the Discord", path: "#", styleType: "primary", contrastMode: 'light' }, + { text: "Learn More", path: "#", styleType: "secondary", contrastMode: 'light' } + ], + alignment: 'left' + }, +} \ No newline at end of file diff --git a/src/content/projects/index.ts b/src/content/projects/index.ts index 50e5f3b..6258d11 100644 --- a/src/content/projects/index.ts +++ b/src/content/projects/index.ts @@ -1,6 +1,4 @@ import {projectView, renderView} from "../../views"; -import {projectInfo} from "../../components/vertical-nav/info-project.ts"; -import {renderNavInfo} from "../../components/vertical-nav"; import {projectThumbnail} from "../../components/thumbnail-project"; import {archivePageReferences} from "./archives"; @@ -26,9 +24,7 @@ export function buildProjectPage(pageReference: string) { } const { content, techs, buttons } = page; const viewContent = projectView(content); - const navInfo = projectInfo(buttons, techs); - - renderNavInfo(navInfo); + renderView(viewContent); } diff --git a/src/heads/default.ts b/src/heads/default.ts index 5ea62fc..866a73c 100644 --- a/src/heads/default.ts +++ b/src/heads/default.ts @@ -5,5 +5,5 @@ - + ` \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 89d2086..7c2ae7c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,15 +1,11 @@ +import {buildMainLogo, changeLogoOnScroll} from "./components/logo"; import { router } from "./core/router"; -import {buildVerticalNav} from "./components/vertical-nav"; -import {buildProjectPage} from "./content/projects"; -import {homeView, aboutView, contactView, buildViewBase, projectCollectionView, renderView} from "./views"; +import {homeView, buildViewBase, renderView} from "./views"; +import {buildTopNav} from "./components/top-nav"; const routes = [ { path: '', handler: () => renderView(homeView()) }, - { path: '/projects', handler: () => renderView(projectCollectionView()) }, - { path: '/projects/:id', handler: (params) => buildProjectPage(params?.id) }, - { path: '/about', handler: () => renderView(aboutView()) }, - { path: '/contact', handler: () => renderView(contactView()) }, ]; routes.forEach(route => router.registerRoute(route.path, route.handler)); @@ -19,10 +15,15 @@ routes.forEach(route => router.registerRoute(route.path, route.handler)); function init() { const body = document.getElementsByTagName("body")[0]; const contentPage = buildViewBase(); - const verticalNav = buildVerticalNav(); + const mainLogo = buildMainLogo(); + const nav = buildTopNav(); + + body.appendChild(mainLogo); + body.appendChild(nav); + window.addEventListener('scroll', changeLogoOnScroll); body.appendChild(contentPage); - contentPage.appendChild(verticalNav); + router.handleRoute(window.location.pathname); } diff --git a/src/views/common/call-to-action/index.ts b/src/views/common/call-to-action/index.ts new file mode 100644 index 0000000..ae20e7d --- /dev/null +++ b/src/views/common/call-to-action/index.ts @@ -0,0 +1,66 @@ +import "./styles.css"; +import { createPixelGridBackground } from "../../utils/backgrounds-utils"; +import { writeTitle, writeParagraph, createMainButton, MainButtonOptions, createWrapper } from "../../utils"; + +export type CallToActionOptions = { + header: string; + body: string; + buttons: MainButtonOptions[]; + alignment: 'left' | 'right'; +} + +// -------------------------------------------------------------------------------- + +export function createPixelBannerCTA(content: CallToActionOptions) { + const banner = createBanner(); + banner.appendChild(createBackground(content.alignment)); + banner.appendChild(createContent(content)); + return banner; +} + +// -------------------------------------------------------------------------------- + +function createBanner() { + const banner = document.createElement('div'); + banner.className = 'cta-banner pixel-banner'; + return banner; +} + +function createBackground(alignment: 'left' | 'right') { + const background = document.createElement('div'); + background.className = 'cta-background'; + const emptyAlignment = alignment === 'right' ? 'left' : 'right'; + background.appendChild(createPixelGridBackground(emptyAlignment, { + rows: 4, + colors: ['#0f0f0f', '#2a2a2a', '#181818'] + })); + return background; +} + +function createContent(content: CallToActionOptions) { + const wrapper = createWrapper(); + const article = document.createElement('article'); + article.className = `${content.alignment}`; + + article.appendChild(createTextSection(content)); + article.appendChild(createButtonsSection(content.buttons)); + + wrapper.appendChild(article); + return wrapper; +} + +function createTextSection(content: CallToActionOptions) { + const container = document.createElement('div'); + container.className = 'text-container'; + container.appendChild(writeTitle("h4", content.header)); + container.appendChild(writeParagraph(content.body)); + return container; +} + +function createButtonsSection(buttons: MainButtonOptions[]) { + const container = document.createElement('ul'); + buttons.forEach(button => { + container.appendChild(createMainButton(button)); + }); + return container; +} \ No newline at end of file diff --git a/src/views/common/call-to-action/styles.css b/src/views/common/call-to-action/styles.css new file mode 100644 index 0000000..626bb0a --- /dev/null +++ b/src/views/common/call-to-action/styles.css @@ -0,0 +1,142 @@ +.cta-banner.pixel-banner { + position: relative; + width: 100%; + text-align: left; + overflow: hidden; +} + +.cta-banner.pixel-banner .cta-background { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: -5; + width: 100%; + height: 100%; + opacity: 0.6; +} + +.cta-banner.pixel-banner article { + z-index: 2; + padding: clamp(30px, 8vw, 50px); + background-color: white; + width: fit-content; + + display: grid; + grid-template-columns: auto auto; + gap: clamp(50px, 15vw, 150px); + align-items: center; + + p { + color: black; + } + + .text-container { + display: flex; + flex-direction: column; + gap: clamp(15px, 4vw, 20px); + max-width: clamp(400px, 80vw, 600px); + } + + ul { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: row; + gap: clamp(15px, 4vw, 20px); + flex-wrap: wrap; + } +} + +.cta-banner.pixel-banner article.right { + margin-left: auto; + justify-content: end; + + &::before { + content: ''; + position: absolute; + top: 0; + right: 0; + width: clamp(15vw, 20vw, 25vw); + height: 100%; + background-color: white; + z-index: -1; + } +} + +.cta-banner.pixel-banner article.left { + margin-right: auto; + justify-content: start; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: clamp(15vw, 20vw, 25vw); + height: 100%; + background-color: white; + z-index: -1; + } +} + +/* Media Queries for enhanced mobile experience */ +@media (max-width: 1500px) { + .cta-banner.pixel-banner { + background-color: white; + } + .cta-banner.pixel-banner .cta-background{ + display: none; + } +} + +@media (max-width: 768px) { + .cta-banner.pixel-banner article { + grid-template-columns: 1fr; + gap: clamp(30px, 8vw, 40px); + padding: clamp(25px, 6vw, 40px); + width: 90%; + margin: 0 auto; + text-align: center; + + .text-container { + max-width: 100%; + } + + ul { + justify-content: center; + flex-direction: column; + align-items: center; + gap: clamp(12px, 3vw, 15px); + } + } + + .cta-banner.pixel-banner article.right, + .cta-banner.pixel-banner article.left { + margin: 0 auto; + justify-content: center; + + &::before { + width: 100%; + left: 0; + right: 0; + } + } +} + +@media (max-width: 480px) { + .cta-banner.pixel-banner article { + width: 95%; + padding: clamp(20px, 5vw, 30px); + gap: clamp(20px, 6vw, 30px); + + ul { + width: 100%; + + li { + width: 100%; + } + } + } +} \ No newline at end of file diff --git a/src/views/home.ts b/src/views/home.ts deleted file mode 100644 index e234a44..0000000 --- a/src/views/home.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {createThreeBackground, writeParagraph, writeTitle} from "./utils"; -import {BackgroundChoice} from "../components/three-background"; -import {cdCover} from "../components/cd-cover"; - -export type HomePageContent = { - readonly title: string; - readonly introText: string; -} - -// -------------------------------------------------------------------------------- - -export function homeView() { - const article = document.createElement('article'); - const introBlock = document.createElement('div'); - const pageTitle = writeTitle("h1", "pick a track"); - const pageText = writeParagraph("Welcome to my hub! I’m CD-BASH, a creative developer based in Montreal."); - - article.id = 'home-page'; - introBlock.className = 'intro-block'; - - createThreeBackground(BackgroundChoice.Home); - introBlock.appendChild(pageTitle); - introBlock.appendChild(pageText); - article.appendChild(introBlock); - article.appendChild(cdCoverSelection()); - - return article; -} - -// -------------------------------------------------------------------------------- - -function cdCoverSelection() { - const cdCovers = document.createElement('div'); - cdCovers.className = 'cd-covers-selection'; - - const projectCover = cdCover(); - const aboutCover = cdCover(); - const logsCover = cdCover(); - - cdCovers.appendChild(projectCover); - cdCovers.appendChild(aboutCover); - cdCovers.appendChild(logsCover); - - return cdCovers; -} - diff --git a/src/views/home/contentSection.ts b/src/views/home/contentSection.ts new file mode 100644 index 0000000..b1fecd0 --- /dev/null +++ b/src/views/home/contentSection.ts @@ -0,0 +1,75 @@ +import { GRID_CONFIG } from '../../components/pixel-grid'; +import { createMainButton, MainButtonOptions } from '../utils/'; +import {createWrapper, writeParagraph, writeTitle} from "../utils"; +import { createPixelGridBackground } from '../utils/backgrounds-utils'; + +const pixelGridConfigs: GRID_CONFIG = { + rows: 6, + colors: ['#0f0f0f', '#2a2a2a', '#181818'] +} + +export type SectionContent = { + readonly sectionBG: string; + readonly introTitle?: string; + readonly header: string; + readonly paragraphs: string[]; + readonly buttons: MainButtonOptions[]; + readonly alignment: 'left' | 'right'; +} + + +// -------------------------------------------------------------------------------- + +export function createContentSection(content: SectionContent) { + const section = document.createElement('section'); + const wrapper = createWrapper(); + const article = document.createElement('article'); + + section.className = `content-section ${content.alignment}`; + section.style.backgroundImage = `url('${content.sectionBG}')`; + section.appendChild(createPixelGridBackground(content.alignment, pixelGridConfigs)); + + if (content.introTitle) { + article.appendChild(introTitle(content.introTitle)); + } + + article.appendChild(writeTitle("h2", content.header)); + article.appendChild(sectionParagraphs(content.paragraphs)); + article.appendChild(sectionButtons(content.buttons)); + + wrapper.appendChild(article); + section.appendChild(wrapper); + + return section; +} + +// -------------------------------------------------------------------------------- + +function sectionParagraphs(paragraphs: string[]) { + const paragraphsContainer = document.createElement('div'); + paragraphsContainer.className = 'paragraphs-container'; + + paragraphs.forEach(text => { + const p = writeParagraph(text); + paragraphsContainer.appendChild(p); + }); + return paragraphsContainer; +} + +function sectionButtons(contentButtons: MainButtonOptions[]) { + const buttonsContainer = document.createElement('ul'); + buttonsContainer.className = 'buttons-container'; + + contentButtons.forEach(buttonOptions => { + const button = createMainButton(buttonOptions); + buttonsContainer.appendChild(button); + }); + return buttonsContainer; +} + +function introTitle(text: string) { + const intro = document.createElement('h3'); + intro.className = 'intro-title'; + intro.innerHTML = text; + return intro; +} \ No newline at end of file diff --git a/src/views/home/index.ts b/src/views/home/index.ts new file mode 100644 index 0000000..52169c6 --- /dev/null +++ b/src/views/home/index.ts @@ -0,0 +1,59 @@ +import './styles.css'; +import { arrowButton, createVideoBackground, createWrapper, writeParagraph, writeTitle } from "../utils"; +import { CallToActionOptions, createPixelBannerCTA } from '../common/call-to-action'; +import {SectionContent, createContentSection} from "./contentSection"; +import {homePageContent} from "../../content/home"; + +export type HomePageContentStructure = { + readonly hook: HookContent; + readonly philosophy: SectionContent; + readonly teaser: SectionContent; + readonly ctaBannerA: CallToActionOptions; + readonly founder: SectionContent; + readonly sideQuests: SectionContent + readonly ctaBannerB: CallToActionOptions; +} + +type HookContent = { + readonly header: string; + readonly body: string; + readonly videoWebem: string; + readonly videoMp4: string; +} + +// -------------------------------------------------------------------------------- + +export function homeView() { + const page = document.createElement('div'); + page.id = 'home-page'; + + page.appendChild(hookSection(homePageContent.hook)); + page.appendChild(createContentSection(homePageContent.philosophy)); + page.appendChild(createContentSection(homePageContent.teaser)); + page.appendChild(createPixelBannerCTA(homePageContent.ctaBannerA)); + page.appendChild(createContentSection(homePageContent.founder)); + page.appendChild(createContentSection(homePageContent.sideQuests)); + page.appendChild(createPixelBannerCTA(homePageContent.ctaBannerB)); + + return page; +} + +// -------------------------------------------------------------------------------- + +function hookSection(content: HookContent) { + const hook = document.createElement('section'); + const videoBg = createVideoBackground(content.videoWebem, content.videoMp4); + const wrapper = createWrapper(); + const article = document.createElement('article'); + + hook.className = 'hook'; + + article.appendChild(writeTitle("h1", content.header)); + article.appendChild(writeParagraph(content.body)); + article.appendChild(arrowButton()); + wrapper.appendChild(article); + hook.appendChild(videoBg); + hook.appendChild(wrapper); + + return hook; +} diff --git a/src/views/home/styles.css b/src/views/home/styles.css new file mode 100644 index 0000000..0c3c6cb --- /dev/null +++ b/src/views/home/styles.css @@ -0,0 +1,154 @@ +#home-page { + + #wrapper { + z-index: 2; + } + + h2 { + margin-bottom: clamp(30px, 5vw, 50px); + } + + section { + width: 100%; + min-height: 100vh; + height: 100vh; + margin: 0; + padding: 0 clamp(1rem, 5vw, 2rem); + box-sizing: border-box; + background-size: cover; + background-position: center; + } + + .highlight { + text-decoration: underline; + text-decoration-color: #3BFFC5; + text-underline-offset: clamp(5px, 3vw, 20px); + } + + .hook { + h1, p { + text-shadow: 0 4px 55px rgba(0, 0, 0, 0.65); + max-width: min(1160px, 90vw); + } + + article { + margin: 0 clamp(5%, 15vw, 15%); + display: flex; + text-align: center; + flex-direction: column; /* Stack children vertically */ + justify-content: center; + align-items: center; + height: 100vh; + padding: clamp(1rem, 5vw, 2rem); + + p { + font-size: clamp(1.1em, 3vw, 1.5em); + margin-top: clamp(30px, 8vw, 75px); + margin-bottom: clamp(15px, 3vw, 20px); + max-width: min(630px, 80vw); + } + } + } + + .content-section { + position: relative; /* Ensure the section is the positioning context */ + overflow: hidden; /* Hide the overflowing pixels */ + + canvas.pixel-grid { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1; /* Below the article */ + pointer-events: none; + } + + article { + position: relative; + z-index: 2; /* Above the pixel grid */ + display: flex; + width: clamp(600px, 50%, 900px); + flex-direction: column; + justify-content: center; + align-items: flex-start; + height: 100vh; + padding: clamp(1rem, 5vw, 2rem); + } + + &.right article { + margin-left: auto; + } + + p { + max-width: clamp(500px, 90%, 750px); + margin-bottom: clamp(20px, 4vw, 30px); + text-align: left; + font-size: clamp(0.9rem, 2.5vw, 1.1rem); + } + + .buttons-container { + display: flex; + flex-wrap: wrap; + gap: clamp(10px, 3vw, 20px); + list-style: none; + padding: 0; + margin: 0; + } + } + + /* Media Queries for better mobile experience */ + @media (max-width: 768px) { + section { + height: auto; + min-height: 100vh; + padding: 0; + } + + .hook article { + margin: 0 5%; + padding: 0; + } + + .content-section { + article { + width: 90%; + padding: 0; + text-align: center; + align-items: center; + } + + &.right article { + margin-left: auto; + margin-right: auto; + } + + p { + max-width: 100%; + text-align: center; + } + + .buttons-container { + justify-content: center; + width: 100%; + } + } + } + + @media (max-width: 480px) { + .hook article { + margin: 0; + padding: 0; + } + + .content-section article { + width: 100%; + padding: 0; + } + + .buttons-container { + flex-direction: column; + align-items: center; + } + } +} \ No newline at end of file diff --git a/src/views/index.ts b/src/views/index.ts index ad2998b..0447e33 100644 --- a/src/views/index.ts +++ b/src/views/index.ts @@ -1,6 +1,6 @@ import "./styles.css"; -export * from "./home"; +export * from "./home/"; export * from "./projectCollection.ts"; export * from "./project.ts"; export * from "./about.ts"; @@ -10,27 +10,23 @@ export * from "./contact.ts"; // -------------------------------------------------------------------------------- export function buildViewBase() { - const viewBox = document.createElement('div'); - const viewWrapper = document.createElement('div'); - viewBox.id = 'view-box'; - viewWrapper.id = 'view-wrapper'; - - viewBox.appendChild(viewWrapper); - return viewBox; + const view = document.createElement('div'); + view.id = 'view'; + return view; } -export function renderView(view: HTMLElement) { - const viewWrapper = clearView(); - viewWrapper.appendChild(view); +export function renderView(newView: HTMLElement) { + const cleanView = clearView(); + cleanView.appendChild(newView); } // -------------------------------------------------------------------------------- function clearView() { - const cleanViewWrapper = document.getElementById('view-wrapper')!; - cleanViewWrapper?.childNodes.forEach((childNode) => { - cleanViewWrapper.removeChild(childNode); - }); + const view = document.getElementById('view')!; + while (view.firstChild) { + view.removeChild(view.firstChild); + } - return cleanViewWrapper; + return view; } diff --git a/src/views/styles.css b/src/views/styles.css index d877835..235db25 100644 --- a/src/views/styles.css +++ b/src/views/styles.css @@ -1,238 +1,16 @@ -body { - background-color: black; -} - -h1 { - margin: 0; - max-width: 75%; - font-size: 6em; - line-height: 75%; - color: white; - text-transform: lowercase; -} - -h2 { - margin: 0 0 20px 0; - font-size: 1.2em; - color: white; - text-transform: uppercase; -} - -h3 { - font-family: "Handjet", serif; - font-size: 2.8em; - font-weight: 600; - color: #828282; -} - -h5 { - font-family: "Handjet", serif; - font-size: 1.5em; - font-weight: 600; - text-transform: lowercase; - color: #828282; -} - -h6 { - margin: 0 0 20px 0; - font-family: "Handjet", serif; - font-size: 2em; - font-weight: 600; - text-transform: lowercase; - color: #3BFFC5; -} - -p { - font-size: 2em; - font-weight: normal; - color: #828282; - line-height: 150%; - margin: 0; -} - -p.intro-text { - margin-bottom: 50px; -} - -p.description { - font-family: "Cabin", sans-serif; - color: #A1A1A1; - font-size: 0.9em; -} - -#view-box { - padding-left: 280px; + +#view { height: 100%; - font-family: "Cabin", sans-serif; - + font-family: 'Inter', sans-serif; - #view-wrapper { - width: 720px; + #wrapper { + width: 85%; margin: 0 auto; - padding-top: 60px; - - section { - margin:0; - padding: 58px 0; - clear: both; - } - - .showcase { - margin: 50px 0; - width: 100%; - border: #080808 solid 3px; - } - - .video-showcase::before, .video-showcase::after { - content: ""; - display: block; - width: 100%; - padding-top: 65px; - z-index: -2; - background-image: url("utils/assets/video-showcase-decoration.png"); - background-blend-mode: multiply; - background-repeat: repeat-x; - filter: invert(100%) sepia(100%) hue-rotate(240deg) saturate(100%); - } - - .video-showcase::before { - margin-bottom: -15px; - } - - .video-showcase::after { - margin-top: -15px; - transform: scaleY(-1); - } - - .video-showcase video { - width: 100%; - border-radius: 15px; - z-index: 5; - position: relative; - } - - .gallery-content { - padding-top: 20px; - } - - .gallery-content img { - object-fit: cover; - width: 45%; - aspect-ratio:1/1; - margin: 10px 0; - margin-right: 4%; - border: 2px solid #505050; - border-radius: 10px; - } - - .link { - font-family: "Handjet", serif; - display: inline-block; - color: #828282;; - font-size: 2.5em; - font-weight: normal; - padding: 0 30px 15px 0; - text-align: center; - text-decoration-color: #3BFFC5; - } - - #home-page { - .cd-covers-selection { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 40px; - justify-items: center; - align-items: center; - width: 170%; /* wider than wrapper */ - max-width: none; - margin-left: -35%; /* center and overflow */ - position: relative; - z-index: 1; - padding: 40px 0; - - } - } - - #about-page { - - .intro { - text-align: center; - padding-bottom: 50px; - display: block; - } - - .title { - font-family: "Handjet", serif; - font-size: 2.5em; - font-weight: 600; - color: #3BFFC5; - text-transform: lowercase; - } - - .grid-category { - display: grid; - padding: 50px 0 0 0; - margin: 0 0 25px 0; - border-top: 2px dashed #505050; - grid-template-columns: repeat(6, 1fr); - gap: 2%; - - h2 { - grid-column: span 6; - } - - .grid-item { - margin: 0 0 50px 0; - grid-column: span 3; - - - .subtitle { - color: white; - } - - .text { - font-size: 1em; - } - } - } - - .achievements, .profile-links { - border-top: 2px dashed #505050; - padding: 50px 0 0 0; - margin: 0 0 25px 0; - - .item { - margin: 0 0 50px 0; - } - } - - } - - #home-page { - - h1 { - margin: 0 auto 50px auto; - - } - - .intro-block { - text-align: center; - } - - } - } - - .three-background { - position: fixed; - background-color: #000000; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: -15; } } + + diff --git a/src/views/utils/assets/icon_arrow_down.svg b/src/views/utils/assets/icon_arrow_down.svg new file mode 100644 index 0000000..4933aba --- /dev/null +++ b/src/views/utils/assets/icon_arrow_down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/views/utils/backgrounds-utils.ts b/src/views/utils/backgrounds-utils.ts index be055b4..32a5cee 100644 --- a/src/views/utils/backgrounds-utils.ts +++ b/src/views/utils/backgrounds-utils.ts @@ -1,5 +1,5 @@ import {BackgroundChoice, threeBackground} from "../../components/three-background"; - +import { createPixelGrid, GRID_CONFIG } from "../../components/pixel-grid"; export function createThreeBackground(choice: BackgroundChoice) { const viewBox = document.getElementById('view-box')!; @@ -11,4 +11,30 @@ export function createThreeBackground(choice: BackgroundChoice) { viewBox.appendChild(background); } +} + +export function createVideoBackground(videoWebm: string, videoMp4: string) { + const background = document.createElement('video'); + background.className = 'video-background'; + background.autoplay = true; + background.loop = true; + background.muted = true; + + const sourceWebm = document.createElement('source'); + sourceWebm.src = videoWebm; + sourceWebm.type = 'video/webm'; + + const sourceMp4 = document.createElement('source'); + sourceMp4.src = videoMp4; + sourceMp4.type = 'video/mp4'; + + background.appendChild(sourceWebm); + background.appendChild(sourceMp4); + + return background; +} + +export function createPixelGridBackground(contentAlignment: 'left' | 'right', configs: GRID_CONFIG) { + const alignment = contentAlignment === 'right' ? 'left' : 'right'; + return createPixelGrid(configs, alignment); } \ No newline at end of file diff --git a/src/views/utils/buttons-utils.ts b/src/views/utils/buttons-utils.ts new file mode 100644 index 0000000..c222188 --- /dev/null +++ b/src/views/utils/buttons-utils.ts @@ -0,0 +1,30 @@ +import ARROW_ICON from './assets/icon_arrow_down.svg'; + +export type MainButtonOptions = { + text: string; + path: string; + styleType: 'primary' | 'secondary'; + contrastMode: 'light' | 'dark'; +}; + +// ------------------------------------------------------------------------ + +export function arrowButton() { + const button = document.createElement('button'); + button.className = 'arrow-button'; + button.innerHTML = `Scroll Down`; + + return button; +} + +export function createMainButton(options: MainButtonOptions) { + const { text, path, styleType, contrastMode } = options; + + const button = document.createElement('a'); + button.className = `main-button ${styleType} ${contrastMode}`; + button.innerHTML = text; + button.href = path; + button.role = 'button'; + + return button; +} \ No newline at end of file diff --git a/src/views/utils/index.ts b/src/views/utils/index.ts index dfd3651..065c5c4 100644 --- a/src/views/utils/index.ts +++ b/src/views/utils/index.ts @@ -1,7 +1,18 @@ -export * from "./text-utils.ts"; +import "./styles.css"; + +export * from "./text-utils.ts"; export * from "./visual-utils.ts"; export * from "./backgrounds-utils.ts"; +export * from "./buttons-utils.ts"; + +// ------------------------------------------------------------------------ export function scrollTop() { window.scrollTo(0, 0); +} + +export function createWrapper() { + const wrapper = document.createElement('div'); + wrapper.id = 'wrapper'; + return wrapper; } \ No newline at end of file diff --git a/src/views/utils/styles.css b/src/views/utils/styles.css new file mode 100644 index 0000000..e6a922a --- /dev/null +++ b/src/views/utils/styles.css @@ -0,0 +1,204 @@ +body { + background-color: black; + margin: 0; +} + +h1, h2 { + margin: 0; + font-family: "Inter", sans-serif; + font-size: clamp(2.5rem, 8vw, 6rem); + font-weight: 900; + line-height: 100%; + color: white; +} + +h3 { + font-family: "Inter", sans-serif; + font-size: clamp(1.25rem, 4vw, 2rem); + font-weight: 700; + color: #ffffff; +} + +h4 { + margin: 0; + font-family: "Inter", sans-serif; + font-size: clamp(1.5rem, 5vw, 3rem); + font-weight: 900; + color: #000000; +} + +h5 { + font-family: "Handjet", serif; + font-size: clamp(1rem, 3vw, 1.5rem); + font-weight: 600; + text-transform: lowercase; + color: #828282; +} + +h6 { + margin: 0 0 clamp(15px, 3vw, 20px) 0; + font-family: "Handjet", serif; + font-size: clamp(1.2rem, 4vw, 2rem); + font-weight: 600; + text-transform: lowercase; + color: #3BFFC5; +} + +p { + font-size: clamp(0.875rem, 2.5vw, 1rem); + font-weight: normal; + color: white; + line-height: 130%; + margin: 0; +} + +/* -------------------------------------------------------------------------------- */ +.arrow-button { + background: none; + border: none; + cursor: pointer; + width: clamp(60px, 15vw, 75px); + height: clamp(60px, 15vw, 75px); + padding: clamp(15px, 4vw, 20px); + background-color: rgba(255, 255, 255, 0.05); + border-radius: 50%; + border: 2px solid rgba(255, 255, 255, 0.1); + margin: clamp(15px, 4vw, 20px) auto 0 auto; + display: block; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} + + +/* -------------------------------------------------------------------------------- */ +.main-button { + display: inline-block; + min-width: clamp(180px, 45vw, 220px); + height: clamp(36px, 10vw, 40px); + + text-align: center; + line-height: clamp(32px, 8vw, 36px); + font-family: 'Handjet', sans-serif; + font-size: clamp(1.1rem, 3.5vw, 1.4rem); + text-transform: uppercase; + text-decoration: none; + + border-radius: clamp(18px, 5vw, 20px); + border: 2px solid; + + backdrop-filter: blur(30px); + -webkit-backdrop-filter: blur(30px); + overflow: hidden; + + transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease; + cursor: pointer; +} + +.main-button.primary.dark { + background-color: rgba(59, 255, 197, 0.05); + border-color: rgba(59, 255, 197, 1); + color: #ffffff; + + &:hover { + background-color: #34e6c0; + border-color: #34e6c0; + } +} + +.main-button.primary.light { + background-color: rgba(59, 255, 197, 0.15); + border-color: rgba(59, 255, 197, 1); + color: #000000; + + &:hover { + background-color: #34e6c0; + border-color: #34e6c0; + color: #ffffff; + } +} + +.main-button.secondary.dark { + background-color: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.1); + color: #ffffff; + + &:hover { + background-color: rgba(255, 255, 255, 1); + border-color: #ffffff; + color: #000000; + } +} + +.main-button.secondary.light { + background-color: rgba(0, 0, 0, 0.05); + border-color: rgba(0, 0, 0, 0.1); + color: #000000; + + &:hover { + background-color: #555555; + border-color: #555555; + color: #ffffff; + } +} + + + +/* -------------------------------------------------------------------------------- */ +.video-background { + position: absolute; + top: 50%; + left: 50%; + width: 100%; + height: 100%; + object-fit: cover; + transform: translate(-50%, -50%); + z-index: -1; + min-width: 100%; + min-height: 100%; +} + +/* Media Queries for enhanced mobile typography */ +@media (max-width: 768px) { + h1, h2 { + line-height: 110%; + } + + h3, h4, h5, h6 { + line-height: 120%; + } + + p { + line-height: 140%; + } + + .main-button { + min-width: 160px; + padding: 0 1rem; + width: 100%; + max-width: 280px; + } + + .arrow-button { + margin: 15px auto 0 auto; + } +} + +@media (max-width: 480px) { + h1, h2 { + font-size: clamp(2rem, 12vw, 3.5rem); + line-height: 105%; + } + + .main-button { + width: 100%; + max-width: 240px; + font-size: 1rem; + line-height: 32px; + height: 36px; + } +} + + + + + diff --git a/src/views/utils/text-utils.ts b/src/views/utils/text-utils.ts index f428a0c..b3ef7c2 100644 --- a/src/views/utils/text-utils.ts +++ b/src/views/utils/text-utils.ts @@ -6,14 +6,14 @@ export function writeTitle(importance: string,text: string) { const title = document.createElement(importance); - title.textContent = text; + title.innerHTML = text; return title; } export function writeParagraph(text: string) { const paragraph = document.createElement("p"); - paragraph.textContent = text; + paragraph.innerHTML = text; return paragraph; } @@ -22,7 +22,7 @@ export function writeLink(text: string, href: string) { const link = document.createElement('a'); link.className = "link"; link.href = href; - link.textContent = text; + link.innerHTML = text; link.target = "_blank"; return link; diff --git a/webhub.code-workspace b/webhub.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/webhub.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file