Compare commits

...
14 Commits
Author SHA1 Message Date
tresabhi b400ff6d07 compiling search 2026-08-27 11:46:55 -05:00
tresabhi edc3aba545 restore banner 2026-08-27 11:23:41 -05:00
tresabhi 1e1040816b migrate tank filters 2026-08-26 14:02:44 -05:00
tresabhi d477a3a7a4 radix composing styles 2026-08-26 13:49:45 -05:00
tresabhi 37efc2b4a4 Merge branch 'main' into data-driven 2026-08-26 10:23:18 -05:00
tresabhi 5285d081e4 migrate 3 2026-08-18 13:57:01 -05:00
tresabhi de8b3959b3 simplification 2026-08-18 13:21:51 -05:00
tresabhi cfc0ebb8e5 migrate 2 2026-08-18 13:02:59 -05:00
tresabhi 9839d4eef5 migrate 1 2026-08-18 12:49:14 -05:00
tresabhi c637343593 ugh, imma remove radix 2026-08-18 12:40:46 -05:00
tresabhi f3c362dfce home page grouping 2026-08-18 12:34:27 -05:00
tresabhi 20cc6d32a4 home page list 2026-08-18 12:23:48 -05:00
tresabhi 35ed716659 simplify config 2026-08-13 13:14:41 -05:00
tresabhi bea55f1b6c clean tools 2026-08-13 13:00:36 -05:00
112 changed files with 2008 additions and 961 deletions

No files matched your search

+73 -71
View File
@@ -107,12 +107,13 @@
"@astrolib/seo": "^1.0.0-beta.8", "@astrolib/seo": "^1.0.0-beta.8",
"@blitzkit/core": "workspace:*", "@blitzkit/core": "workspace:*",
"@blitzkit/i18n": "workspace:*", "@blitzkit/i18n": "workspace:*",
"@fontsource-variable/jetbrains-mono": "^5.3.0",
"@fontsource-variable/roboto-flex": "^5.3.0",
"@fontsource/inter": "^5.2.8", "@fontsource/inter": "^5.2.8",
"@gltf-transform/core": "^4.4.2", "@gltf-transform/core": "^4.4.2",
"@gltf-transform/functions": "^4.4.2", "@gltf-transform/functions": "^4.4.2",
"@radix-ui/colors": "^3.0.0", "@radix-ui/colors": "^3.0.0",
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/themes": "^3.2.1",
"@react-three/drei": "^10.7.6", "@react-three/drei": "^10.7.6",
"@react-three/fiber": "^9.4.0", "@react-three/fiber": "^9.4.0",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
@@ -131,6 +132,7 @@
"markdown-to-jsx": "^7.7.13", "markdown-to-jsx": "^7.7.13",
"pwa-install-handler": "^2.6.3", "pwa-install-handler": "^2.6.3",
"quicklime": "^1.2.0", "quicklime": "^1.2.0",
"radix-ui": "^1.6.7",
"react": "^19.2.4", "react": "^19.2.4",
"react-dom": "^19.2.4", "react-dom": "^19.2.4",
"react-promise-suspense": "^0.3.4", "react-promise-suspense": "^0.3.4",
@@ -481,13 +483,17 @@
"@esbuild/win32-x64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="], "@esbuild/win32-x64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="],
"@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], "@floating-ui/core": ["@floating-ui/core@1.8.0", "", { "dependencies": { "@floating-ui/utils": "^0.2.12" } }, "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ=="],
"@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="], "@floating-ui/dom": ["@floating-ui/dom@1.8.0", "", { "dependencies": { "@floating-ui/core": "^1.8.0", "@floating-ui/utils": "^0.2.12" } }, "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg=="],
"@floating-ui/react-dom": ["@floating-ui/[email protected].6", "", { "dependencies": { "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw=="], "@floating-ui/react-dom": ["@floating-ui/[email protected].9", "", { "dependencies": { "@floating-ui/dom": "^1.8.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg=="],
"@floating-ui/utils": ["@floating-ui/[email protected]0", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], "@floating-ui/utils": ["@floating-ui/[email protected]2", "", {}, "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww=="],
"@fontsource-variable/jetbrains-mono": ["@fontsource-variable/[email protected]", "", {}, "sha512-F32xpS2NsGYoQi2ADSkKTgpJj7ozajsGgDJ8woTnqjmIB+dxDIqImjl4pXZVEExu8UFZ2ndhmX18EBS/hdz3Lw=="],
"@fontsource-variable/roboto-flex": ["@fontsource-variable/[email protected]", "", {}, "sha512-bOxckUy0qXNRjhV6e4pcHGSvptix4ZRD1uaj5Za8h+p3qrb2GL4U4TQdpVmPSy0SmqwldfD+JJqEKdF68EyiAw=="],
"@fontsource/inter": ["@fontsource/[email protected]", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="], "@fontsource/inter": ["@fontsource/[email protected]", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="],
@@ -677,129 +683,127 @@
"@radix-ui/colors": ["@radix-ui/[email protected]", "", {}, "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg=="], "@radix-ui/colors": ["@radix-ui/[email protected]", "", {}, "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg=="],
"@radix-ui/number": ["@radix-ui/[email protected].1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], "@radix-ui/number": ["@radix-ui/[email protected].3", "", {}, "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA=="],
"@radix-ui/primitive": ["@radix-ui/[email protected].3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], "@radix-ui/primitive": ["@radix-ui/[email protected].7", "", {}, "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q=="],
"@radix-ui/react-accessible-icon": ["@radix-ui/[email protected].7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="], "@radix-ui/react-accessible-icon": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WTQwcAvQf5sOcuUyi90lKPbhwcvQ+j55cjrSmeaN+L2vKU3DooOvlKw2MDeiJ5IkV5N905KW0/fGojKOBhD11A=="],
"@radix-ui/react-accordion": ["@radix-ui/[email protected].12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], "@radix-ui/react-accordion": ["@radix-ui/[email protected]0", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collapsible": "1.1.20", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-jDhG9FvAEnlhnjrsINbNXcUa4G+L1KqSkJSunkbKEzFRcAb52jvM0PjPxPRvhe1HNc5F5yc0yzzWeeqlH4yBIg=="],
"@radix-ui/react-alert-dialog": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="], "@radix-ui/react-alert-dialog": ["@radix-ui/[email protected].23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dialog": "1.1.23", "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VAYOiQRqj3GPpYJE0I9J+X8Ip05cyVlNdKOFeiGS2Ou1HHGfpl0BxOyZm6nmVDyU+W+NF3/XLzmjHmVGydhwgA=="],
"@radix-ui/react-arrow": ["@radix-ui/[email protected].7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], "@radix-ui/react-arrow": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA=="],
"@radix-ui/react-aspect-ratio": ["@radix-ui/[email protected].7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="], "@radix-ui/react-aspect-ratio": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-fy+dyVR+90nelK8rqIznFlxzx7uPcGbhxH8Nfr2bHb4UfSe+e3hklOC0luK0hDwVwnRX7xTRySpsrQVeW+/oNQ=="],
"@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-is-hydrated": "0.1.3", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ULOTJ/mqy2hT9GlWa/MFHxHSvH3nJzHnZM1waNsc5Bonv7i70aNenghXmD97S6OJ81ekXONGGt4nT1r0PfEdA=="],
"@radix-ui/react-checkbox": ["@radix-ui/[email protected].3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="], "@radix-ui/react-checkbox": ["@radix-ui/[email protected].11", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Gnptr9pDDQxD3hgq2dtPbtrp/c2qH1mBwIzw3X/ivrMb2e1t0jMTi606fVEqFPaQR1ggXIVQWKj3P2WW9v7zGQ=="],
"@radix-ui/react-collapsible": ["@radix-ui/[email protected].12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], "@radix-ui/react-collapsible": ["@radix-ui/[email protected]0", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mcGesGplBnzN2sbvJETzpCNfSMyPnb29q1GRLU+Ib7bJrpIG2ywmRoh2V5VbA2uNvKikKUlVbAPks7JDjz4A8Q=="],
"@radix-ui/react-collection": ["@radix-ui/[email protected].7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], "@radix-ui/react-collection": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA=="],
"@radix-ui/react-compose-refs": ["@radix-ui/[email protected].2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], "@radix-ui/react-compose-refs": ["@radix-ui/[email protected].5", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA=="],
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], "@radix-ui/react-context": ["@radix-ui/react-context@1.2.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA=="],
"@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="], "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.3.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-menu": "2.1.24", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-CtXP35dxaB5T3zXSd+E3uHe/QpXcpYnZmxp6OaIbfthtfW4wyb77M23BG+bwIJDtsMwEP/YssdsmNyZu7jhWew=="],
"@radix-ui/react-dialog": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], "@radix-ui/react-dialog": ["@radix-ui/[email protected].23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA=="],
"@radix-ui/react-direction": ["@radix-ui/[email protected].1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], "@radix-ui/react-direction": ["@radix-ui/[email protected].4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg=="],
"@radix-ui/react-dismissable-layer": ["@radix-ui/[email protected]1", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], "@radix-ui/react-dismissable-layer": ["@radix-ui/[email protected]9", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-effect-event": "0.0.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w=="],
"@radix-ui/react-dropdown-menu": ["@radix-ui/[email protected].16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="], "@radix-ui/react-dropdown-menu": ["@radix-ui/[email protected].24", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-menu": "2.1.24", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g=="],
"@radix-ui/react-focus-guards": ["@radix-ui/[email protected].3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], "@radix-ui/react-focus-guards": ["@radix-ui/[email protected].6", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ=="],
"@radix-ui/react-focus-scope": ["@radix-ui/[email protected].7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], "@radix-ui/react-focus-scope": ["@radix-ui/[email protected].16", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ=="],
"@radix-ui/react-form": ["@radix-ui/[email protected].8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="], "@radix-ui/react-form": ["@radix-ui/[email protected].16", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-label": "2.1.15", "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Q4TLEn2A7TAypxwmd6R9EwrlXDvkfYSDMrq9/887AXAGh+G1rH+kYJKSTv+Si9Y0JPKTwKYv6PviAJosysNimA=="],
"@radix-ui/react-hover-card": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], "@radix-ui/react-hover-card": ["@radix-ui/[email protected].23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-H8qONfZd3ltrU3+jHCIgITbWo6e1iTKvP9DHdrvYbX48ooRM5FjEDTn16AMwdfuOGkWdZEhpl3PLL/Wk/AnHDQ=="],
"@radix-ui/react-icons": ["@radix-ui/[email protected]", "", { "peerDependencies": { "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" } }, "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g=="], "@radix-ui/react-icons": ["@radix-ui/[email protected]", "", { "peerDependencies": { "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" } }, "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g=="],
"@radix-ui/react-id": ["@radix-ui/[email protected].1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], "@radix-ui/react-id": ["@radix-ui/[email protected].4", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA=="],
"@radix-ui/react-label": ["@radix-ui/[email protected].7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], "@radix-ui/react-label": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-o/rdYEwZTTo5tjknnPeyQFU45kUC4i/XyeDPP+HGyi6XqpOP6Zf5Ya5vh/Yfe9Id5JiuWnnAx2XqIeD3UYZt0g=="],
"@radix-ui/react-menu": ["@radix-ui/[email protected].16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], "@radix-ui/react-menu": ["@radix-ui/[email protected].24", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-callback-ref": "1.1.4", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA=="],
"@radix-ui/react-menubar": ["@radix-ui/[email protected].16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="], "@radix-ui/react-menubar": ["@radix-ui/[email protected].24", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-menu": "2.1.24", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-eeVs0vf7cuqXaM0qLQCPcufImiJNVBXdJDLu7ZGYl2732UH23Qat/foNGrr6vYV3/DdTsBqASoggUFgH14OcZA=="],
"@radix-ui/react-navigation-menu": ["@radix-ui/[email protected].14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], "@radix-ui/react-navigation-menu": ["@radix-ui/[email protected].22", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-previous": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ou7iLEJ+yrhQndkkA4U21XIdS/CS45F4iXIkTZcb6/Ne9EMsOuDudVmCwmDnfFZZ+y1FZqXRNSIgBy+YMvZVZg=="],
"@radix-ui/react-one-time-password-field": ["@radix-ui/[email protected].8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="], "@radix-ui/react-one-time-password-field": ["@radix-ui/[email protected].16", "", { "dependencies": { "@radix-ui/number": "1.1.3", "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-effect-event": "0.0.5", "@radix-ui/react-use-is-hydrated": "0.1.3", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Tj9P6ntAJEw52oq/F0AGknXR4XncxEt7XU47O3xJQOiWfLzEy3d9gtgKfvjSzGxzHkfL+VzvxGu2KTFsloJqXw=="],
"@radix-ui/react-password-toggle-field": ["@radix-ui/[email protected].3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="], "@radix-ui/react-password-toggle-field": ["@radix-ui/[email protected].11", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-effect-event": "0.0.5", "@radix-ui/react-use-is-hydrated": "0.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4gvFnmDXu3dgj21CqsufzIameRvlRd4SBqaWhcrlrNhRo0Y5i/49AmRJYe1fdAM3G2VNBbmin4b0D6cdQocwgw=="],
"@radix-ui/react-popover": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], "@radix-ui/react-popover": ["@radix-ui/[email protected].23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-controllable-state": "1.2.6", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ=="],
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], "@radix-ui/react-popper": ["@radix-ui/react-popper@1.3.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-rect": "1.1.4", "@radix-ui/react-use-size": "1.1.4", "@radix-ui/rect": "1.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg=="],
"@radix-ui/react-portal": ["@radix-ui/[email protected].9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], "@radix-ui/react-portal": ["@radix-ui/[email protected].17", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ=="],
"@radix-ui/react-presence": ["@radix-ui/[email protected].5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], "@radix-ui/react-presence": ["@radix-ui/[email protected].10", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw=="],
"@radix-ui/react-primitive": ["@radix-ui/[email protected].3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], "@radix-ui/react-primitive": ["@radix-ui/[email protected].10", "", { "dependencies": { "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg=="],
"@radix-ui/react-progress": ["@radix-ui/[email protected].7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], "@radix-ui/react-progress": ["@radix-ui/[email protected].16", "", { "dependencies": { "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5XnomAsoZZCY+KNTxbIghpGqPruZvKFNlvcAljVAOdDRDsH4/OZQxhtwo5wdtoDM5R6MhJBb2sPnDuRFep3lzg=="],
"@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="], "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.4.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-cgYFEkntCxppHZgtSZ+7vh0wbZQ+IC7PPMw8DSnRG27B6kDd32/Zw0OJt7dGDigCoprMuWHjg2PvUn3PYvPFoQ=="],
"@radix-ui/react-roving-focus": ["@radix-ui/[email protected]1", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], "@radix-ui/react-roving-focus": ["@radix-ui/[email protected]9", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-is-hydrated": "0.1.3", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ=="],
"@radix-ui/react-scroll-area": ["@radix-ui/[email protected]0", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], "@radix-ui/react-scroll-area": ["@radix-ui/[email protected]8", "", { "dependencies": { "@radix-ui/number": "1.1.3", "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Zn5Cd171wxsO3Dfg8HaW6RifTb9CYTKQJHs/G4+LN1GfmJpaQMZQyQxMprVPHpaz7QY4l9BxK2JwQuzHsXC8nA=="],
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="], "@radix-ui/react-select": ["@radix-ui/react-select@2.3.7", "", { "dependencies": { "@radix-ui/number": "1.1.3", "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-previous": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg=="],
"@radix-ui/react-separator": ["@radix-ui/[email protected].7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], "@radix-ui/react-separator": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-jOLO4lssEzWpoDu7G+Ze4VjwMRUBt291pnZD0gmalREZipnTX3wadQo7Fy48GCTfe14/YRN6rw/rOJqrE85Wxw=="],
"@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="], "@radix-ui/react-slider": ["@radix-ui/react-slider@1.4.7", "", { "dependencies": { "@radix-ui/number": "1.1.3", "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-previous": "1.1.4", "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mTSLf1GC/C0moWjTbvCM6Qn/gBjvlFt1azuWF2v7MN5C3Zq2U2J2lN3ZEYkpujuOU5Ro7A28wkviSxaKnG0BYg=="],
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], "@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q=="],
"@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], "@radix-ui/react-switch": ["@radix-ui/react-switch@1.3.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-48tB/4dn2UVLBCYhTu9AuR63IHl73l/qLbLgxd86noTUor4/K4LFDAcYjK+isP5313qxaFpjPVogE7+Y0/V3Kw=="],
"@radix-ui/react-tabs": ["@radix-ui/[email protected]3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], "@radix-ui/react-tabs": ["@radix-ui/[email protected].21", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog=="],
"@radix-ui/react-toast": ["@radix-ui/[email protected].15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="], "@radix-ui/react-toast": ["@radix-ui/[email protected].23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ofhyAsYaocRGOs/n0XWdUOSVzEAG6BfrMVM8z0c0kLEWY38w/0WuMFPTJP/HVaZPYkMvHZoKIIhNcjbTCBILPg=="],
"@radix-ui/react-toggle": ["@radix-ui/[email protected]0", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="], "@radix-ui/react-toggle": ["@radix-ui/[email protected]8", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7lonPlKfSacd20GlOBx2ltuVKz9oqWYZz+oMQyOltw6t1y2nyftj2ZmwwUHYn49kqfDWcp8dNZm5NgV+5Z+mug=="],
"@radix-ui/react-toggle-group": ["@radix-ui/[email protected]1", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="], "@radix-ui/react-toggle-group": ["@radix-ui/[email protected]9", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-toggle": "1.1.18", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-OtnwuSVjd1Ofi+AdnvhsjQdyuhCDwYs1w9RyB5BN/OavXOVQo42SYqQjwUnbPnaiPFBpQ9aX70dWeee+v2oBLA=="],
"@radix-ui/react-toolbar": ["@radix-ui/[email protected]1", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="], "@radix-ui/react-toolbar": ["@radix-ui/[email protected]9", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-separator": "1.1.15", "@radix-ui/react-toggle-group": "1.1.19" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ph0IvtYw4VB12ZnZg+YtrGs8yJQsnizwo/zu0R4Y/nWugtJzA7Pg1eWeuDR9+LSqn+xjamss+UOSOJJJ4gx8jw=="],
"@radix-ui/react-tooltip": ["@radix-ui/[email protected].8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], "@radix-ui/react-tooltip": ["@radix-ui/[email protected].16", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg=="],
"@radix-ui/react-use-callback-ref": ["@radix-ui/[email protected].1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], "@radix-ui/react-use-callback-ref": ["@radix-ui/[email protected].4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ=="],
"@radix-ui/react-use-controllable-state": ["@radix-ui/[email protected].2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], "@radix-ui/react-use-controllable-state": ["@radix-ui/[email protected].6", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-use-effect-event": "0.0.5", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ=="],
"@radix-ui/react-use-effect-event": ["@radix-ui/[email protected].2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], "@radix-ui/react-use-effect-event": ["@radix-ui/[email protected].5", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg=="],
"@radix-ui/react-use-escape-keydown": ["@radix-ui/[email protected].1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], "@radix-ui/react-use-escape-keydown": ["@radix-ui/[email protected].5", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ge3ipobwSXTj4JyVtswQ7qZj0ZHdtbGuOno/LrgAAeSxtsJ6Vs4Gz5IkPH2bmqpjcLUFoqGhA/mueuIf63UXlA=="],
"@radix-ui/react-use-is-hydrated": ["@radix-ui/[email protected].0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="], "@radix-ui/react-use-is-hydrated": ["@radix-ui/[email protected].3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw=="],
"@radix-ui/react-use-layout-effect": ["@radix-ui/[email protected].1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], "@radix-ui/react-use-layout-effect": ["@radix-ui/[email protected].4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw=="],
"@radix-ui/react-use-previous": ["@radix-ui/[email protected].1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], "@radix-ui/react-use-previous": ["@radix-ui/[email protected].4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg=="],
"@radix-ui/react-use-rect": ["@radix-ui/[email protected].1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], "@radix-ui/react-use-rect": ["@radix-ui/[email protected].4", "", { "dependencies": { "@radix-ui/rect": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ=="],
"@radix-ui/react-use-size": ["@radix-ui/[email protected].1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], "@radix-ui/react-use-size": ["@radix-ui/[email protected].4", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw=="],
"@radix-ui/react-visually-hidden": ["@radix-ui/[email protected].3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="], "@radix-ui/react-visually-hidden": ["@radix-ui/[email protected].11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ=="],
"@radix-ui/rect": ["@radix-ui/[email protected].1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], "@radix-ui/rect": ["@radix-ui/[email protected].3", "", {}, "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw=="],
"@radix-ui/themes": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/colors": "^3.0.0", "classnames": "^2.3.2", "radix-ui": "^1.1.3", "react-remove-scroll-bar": "^2.3.8" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I0/h2CRNTpYNB7Mi3xFIvSsQq5a108d7kK8dTO5zp5b9HR5QJXKag6B8tjpz2ITkVYkFdkGk45doNkSr7OxwNw=="],
"@react-three/drei": ["@react-three/[email protected]", "", { "dependencies": { "@babel/runtime": "^7.26.0", "@mediapipe/tasks-vision": "0.10.17", "@monogrid/gainmap-js": "^3.0.6", "@use-gesture/react": "^10.3.1", "camera-controls": "^3.1.0", "cross-env": "^7.0.3", "detect-gpu": "^5.0.56", "glsl-noise": "^0.0.0", "hls.js": "^1.5.17", "maath": "^0.10.8", "meshline": "^3.3.1", "stats-gl": "^2.2.8", "stats.js": "^0.17.0", "suspend-react": "^0.1.3", "three-mesh-bvh": "^0.8.3", "three-stdlib": "^2.35.6", "troika-three-text": "^0.52.4", "tunnel-rat": "^0.1.2", "use-sync-external-store": "^1.4.0", "utility-types": "^3.11.0", "zustand": "^5.0.1" }, "peerDependencies": { "@react-three/fiber": "^9.0.0", "react": "^19", "react-dom": "^19", "three": ">=0.159" }, "optionalPeers": ["react-dom"] }, "sha512-ZSFwRlRaa4zjtB7yHO6Q9xQGuyDCzE7whXBhum92JslcMRC3aouivp0rAzszcVymIoJx6PXmibyP+xr+zKdwLg=="], "@react-three/drei": ["@react-three/[email protected]", "", { "dependencies": { "@babel/runtime": "^7.26.0", "@mediapipe/tasks-vision": "0.10.17", "@monogrid/gainmap-js": "^3.0.6", "@use-gesture/react": "^10.3.1", "camera-controls": "^3.1.0", "cross-env": "^7.0.3", "detect-gpu": "^5.0.56", "glsl-noise": "^0.0.0", "hls.js": "^1.5.17", "maath": "^0.10.8", "meshline": "^3.3.1", "stats-gl": "^2.2.8", "stats.js": "^0.17.0", "suspend-react": "^0.1.3", "three-mesh-bvh": "^0.8.3", "three-stdlib": "^2.35.6", "troika-three-text": "^0.52.4", "tunnel-rat": "^0.1.2", "use-sync-external-store": "^1.4.0", "utility-types": "^3.11.0", "zustand": "^5.0.1" }, "peerDependencies": { "@react-three/fiber": "^9.0.0", "react": "^19", "react-dom": "^19", "three": ">=0.159" }, "optionalPeers": ["react-dom"] }, "sha512-ZSFwRlRaa4zjtB7yHO6Q9xQGuyDCzE7whXBhum92JslcMRC3aouivp0rAzszcVymIoJx6PXmibyP+xr+zKdwLg=="],
@@ -1151,8 +1155,6 @@
"ci-info": ["[email protected]", "", {}, "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ=="], "ci-info": ["[email protected]", "", {}, "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ=="],
"classnames": ["[email protected]", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="],
"cli-boxes": ["[email protected]", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="], "cli-boxes": ["[email protected]", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="],
"cliui": ["[email protected]", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], "cliui": ["[email protected]", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
@@ -1995,7 +1997,7 @@
"quicklime": ["[email protected]", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-uPFHeb+1L4o0D5V4TtLfvoMtLbv2dUq7d9dco47khUZilsdS0ugBD1RfhvdsdpMr4UWbOUkJOUCetUrMIDST1A=="], "quicklime": ["[email protected]", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-uPFHeb+1L4o0D5V4TtLfvoMtLbv2dUq7d9dco47khUZilsdS0ugBD1RfhvdsdpMr4UWbOUkJOUCetUrMIDST1A=="],
"radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="], "radix-ui": ["radix-ui@1.6.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-accessible-icon": "1.1.15", "@radix-ui/react-accordion": "1.2.20", "@radix-ui/react-alert-dialog": "1.1.23", "@radix-ui/react-arrow": "1.1.15", "@radix-ui/react-aspect-ratio": "1.1.15", "@radix-ui/react-avatar": "1.2.6", "@radix-ui/react-checkbox": "1.3.11", "@radix-ui/react-collapsible": "1.1.20", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-context-menu": "2.3.7", "@radix-ui/react-dialog": "1.1.23", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-dropdown-menu": "2.1.24", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-form": "0.1.16", "@radix-ui/react-hover-card": "1.1.23", "@radix-ui/react-label": "2.1.15", "@radix-ui/react-menu": "2.1.24", "@radix-ui/react-menubar": "1.1.24", "@radix-ui/react-navigation-menu": "1.2.22", "@radix-ui/react-one-time-password-field": "0.1.16", "@radix-ui/react-password-toggle-field": "0.1.11", "@radix-ui/react-popover": "1.1.23", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-progress": "1.1.16", "@radix-ui/react-radio-group": "1.4.7", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-scroll-area": "1.2.18", "@radix-ui/react-select": "2.3.7", "@radix-ui/react-separator": "1.1.15", "@radix-ui/react-slider": "1.4.7", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-switch": "1.3.7", "@radix-ui/react-tabs": "1.1.21", "@radix-ui/react-toast": "1.2.23", "@radix-ui/react-toggle": "1.1.18", "@radix-ui/react-toggle-group": "1.1.19", "@radix-ui/react-toolbar": "1.1.19", "@radix-ui/react-tooltip": "1.2.16", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-effect-event": "0.0.5", "@radix-ui/react-use-escape-keydown": "1.1.5", "@radix-ui/react-use-is-hydrated": "0.1.3", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-size": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QBdhh1arIEUvPC0dQ5+nwWAxt7+N+oP/9jPwjJkGFoSk/sqxg32gJtSXGtFh8frAIcS6oC9cx2Q+7KYCQLOAeA=="],
"radix3": ["[email protected]", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], "radix3": ["[email protected]", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
@@ -2013,7 +2015,7 @@
"react-refresh": ["[email protected]", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], "react-refresh": ["[email protected]", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
"react-remove-scroll": ["[email protected].1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="], "react-remove-scroll": ["[email protected].2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="],
"react-remove-scroll-bar": ["[email protected]", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], "react-remove-scroll-bar": ["[email protected]", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
+39 -47
View File
@@ -1,4 +1,12 @@
{ {
"home": {
"tanks": "Tanks",
"players": "Players",
"games": "Games",
"cosmetics": "Cosmetics",
"technical": "Technical"
},
"test": { "test": {
"default": "test", "default": "test",
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is {fruit} because it has the color of {color}. I like it so much that I will say its name 3 times! {fruit}! {fruit}! {fruit}! Once again, it's {color}, not {not_color}.", "long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is {fruit} because it has the color of {color}. I like it so much that I will say its name 3 times! {fruit}! {fruit}! {fruit}! Once again, it's {color}, not {not_color}.",
@@ -337,6 +345,18 @@
}, },
"tools": { "tools": {
"backgrounds": {
"name": "Backgrounds",
"description": "Profile backgrounds",
"seo_description": "World of Tanks Blitz player profile backgrounds"
},
"players": {
"name": "Players",
"description": "Player statistics",
"seo_description": "Player statistics in World of Tanks Blitz"
},
"playlist": { "playlist": {
"reset": "Reset", "reset": "Reset",
"shuffle": "Shuffle", "shuffle": "Shuffle",
@@ -370,22 +390,19 @@
"name": "Playlist", "name": "Playlist",
"description": "Tank playlist generator", "description": "Tank playlist generator",
"seo_description": "Don't know what to play in World of Tanks Blitz? Use BlitzKit Playlist to get suggestions!", "seo_description": "Don't know what to play in World of Tanks Blitz? Use BlitzKit Playlist to get suggestions!",
"button": "Generate",
"pool_size": "{count} possible tanks" "pool_size": "{count} possible tanks"
}, },
"mixer": { "mixer": {
"name": "Mixer", "name": "Mixer",
"button": "Mix and match",
"description": "Mix tank modules", "description": "Mix tank modules",
"seo_description": "Mix and match hulls, turrets, and guns of tanks in World of Tanks Blitz", "seo_description": "Mix and match hulls, turrets, and guns of tanks in World of Tanks Blitz",
"screenshot": "Screenshot", "screenshot": "Screenshot",
"randomize": "Randomize" "randomize": "Randomize"
}, },
"guess": { "guesser": {
"name": "Guess", "name": "Guesser",
"button": "What could it be?",
"description": "Silhouette mini-game", "description": "Silhouette mini-game",
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz", "seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
"search": { "search": {
@@ -407,11 +424,10 @@
"tier": "Tier {tier}" "tier": "Tier {tier}"
}, },
"tankopedia": { "tanks": {
"search": "Search a stat...", "search": "Search a stat...",
"name": "Tankopedia", "name": "Tankopedia",
"button": "Find tanks",
"description": "Blitz tank encyclopedia", "description": "Blitz tank encyclopedia",
"seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz", "seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz",
"tank_seo_title": "{name} - Tier {tier} {nationality} {class} | {website} Tankopedia | World of Tanks Blitz (WoTB)", "tank_seo_title": "{name} - Tier {tier} {nationality} {class} | {website} Tankopedia | World of Tanks Blitz (WoTB)",
@@ -721,9 +737,9 @@
"title": "Survivability" "title": "Survivability"
} }
}, },
"compare": { "compare": {
"name": "Compare", "name": "Compare",
"button": "Compare tanks",
"description": "Compare tank statistics", "description": "Compare tank statistics",
"seo_description": "Compare tanks statistics and loadouts in World of Tanks Blitz", "seo_description": "Compare tanks statistics and loadouts in World of Tanks Blitz",
@@ -770,9 +786,9 @@
} }
} }
}, },
"performance": { "performance": {
"name": "Performance", "name": "Performance",
"button": "View tanks",
"description": "Tank performance statistics", "description": "Tank performance statistics",
"seo_description": "Best tanks and their performances in World of Tanks Blitz", "seo_description": "Best tanks and their performances in World of Tanks Blitz",
"estimation": { "estimation": {
@@ -805,9 +821,9 @@
} }
} }
}, },
"gallery": {
"name": "Gallery", "avatars": {
"button": "Browse all", "name": "Avatars",
"description": "Blitz player avatars", "description": "Blitz player avatars",
"seo_description": "All World of Tanks Blitz player avatars", "seo_description": "All World of Tanks Blitz player avatars",
"last_updated": "Last updated on {time}", "last_updated": "Last updated on {time}",
@@ -816,9 +832,9 @@
"results": "{count} avatars" "results": "{count} avatars"
} }
}, },
"session": { "session": {
"name": "Session", "name": "Session",
"button": "Start tracking",
"description": "Live session stats", "description": "Live session stats",
"seo_description": "Track your stats in real time as you play World of Tanks Blitz", "seo_description": "Track your stats in real time as you play World of Tanks Blitz",
"search": { "search": {
@@ -848,9 +864,9 @@
"remove": "Remove" "remove": "Remove"
} }
}, },
"tier_list": { "tier_list": {
"name": "Tier list", "name": "Tier list",
"button": "Rank tanks",
"description": "Rank Blitz tanks", "description": "Rank Blitz tanks",
"seo_description": "Explore tier lists ranking tanks from best to worst, based on player ratings and statistical performance in World of Tanks Blitz", "seo_description": "Explore tier lists ranking tanks from best to worst, based on player ratings and statistical performance in World of Tanks Blitz",
"buttons": { "buttons": {
@@ -858,9 +874,9 @@
"share": "Share" "share": "Share"
} }
}, },
"embed": { "embed": {
"name": "Embed", "name": "Embed",
"button": "Create now",
"description": "Embeds for streaming", "description": "Embeds for streaming",
"seo_description": "Create embeds for streaming World of Tanks Blitz with extreme customization", "seo_description": "Create embeds for streaming World of Tanks Blitz with extreme customization",
"coming_soon": "More embeds coming soon.", "coming_soon": "More embeds coming soon.",
@@ -941,47 +957,23 @@
} }
} }
}, },
"charts": {
"name": "Charts",
"button": "Nerd out",
"description": "Lots of graphs",
"seo_description": "Charts and graphs on anything and everything about tanks, players, and events in World of Tanks Blitz"
},
"rating": {
"name": "Rating",
"button": "View leaderboard",
"description": "Full rating leaderboard",
"seo_description": "Live and archived full rating leaderboard for World of Tanks Blitz"
},
"discord": {
"name": "Discord bot",
"button": "Install now",
"description": "Stats right in Discord",
"seo_description": "Get stats right in Discord with BlitzKit's Discord bot"
},
"more": { "more": {
"name": "More coming soon", "name": "More coming soon",
"button": "Join Discord",
"description": "What we're making", "description": "What we're making",
"seo_description": "What we're making with BlitzKit" "seo_description": "What we're making with BlitzKit"
}, },
"players": {
"name": "Players",
"button": "Lookup player",
"description": "Periodical player statistics",
"seo_description": "Periodical player statistics in World of Tanks Blitz"
},
"home": {
"name": "Home",
"button": "Get started",
"description": "Get started with BlitzKit",
"seo_description": "Get started with BlitzKit"
},
"api": { "api": {
"name": "API", "name": "API",
"button": "To the docs",
"description": "BlitzKit hosted API", "description": "BlitzKit hosted API",
"seo_description": "BlitzKit hosted static API for World of Tanks Blitz" "seo_description": "BlitzKit hosted static API for World of Tanks Blitz"
},
"changelogs": {
"name": "Changelogs",
"description": "BlitzKit changelogs",
"seo_description": "Changelogs and patch notes for BlitzKit"
} }
}, },
-70
View File
@@ -1,13 +1,7 @@
import react from "@astrojs/react"; import react from "@astrojs/react";
import { wrapper } from "@blitzkit/i18n";
import locales from "@blitzkit/i18n/locales.json";
import strings from "@blitzkit/i18n/strings/en.json"; import strings from "@blitzkit/i18n/strings/en.json";
import { mauve, mauveDark } from "@radix-ui/colors";
import AstroPWA from "@vite-pwa/astro";
import favicons from "astro-favicons"; import favicons from "astro-favicons";
import { defineConfig } from "astro/config"; import { defineConfig } from "astro/config";
import packageJSON from "../../package.json";
import { tools } from "./src/constants/tools";
export default defineConfig({ export default defineConfig({
devToolbar: { enabled: false }, devToolbar: { enabled: false },
@@ -29,55 +23,6 @@ export default defineConfig({
name: strings.common.name, name: strings.common.name,
short_name: strings.common.name, short_name: strings.common.name,
background: mauveDark.mauve1,
themes: [mauve.mauve1, mauveDark.mauve1],
appleStatusBarStyle: "black-translucent",
version: packageJSON.version,
shortcuts: Object.values(tools)
.filter((tool) => !tool.disabled && !tool.href)
.map((tool) => {
const stringId = (tool.strings ??
tool.id) as keyof typeof strings.website.tools;
return {
name: strings.website.tools[stringId].name,
name_localized: wrapper(
(strings) => strings.website.tools[stringId].name,
),
description: strings.website.tools[stringId].description,
description_localized: wrapper(
(strings) => strings.website.tools[stringId].description,
),
short_name: strings.website.tools[stringId].name,
short_name_localized: wrapper(
(strings) => strings.website.tools[stringId].name,
),
url: `/${tool.id}`,
icon: `public/assets/images/tools/${tool.id}.webp`,
};
}),
manifest: {
description: strings.website.home.seo_description,
description_localized: wrapper(
(strings) => strings.website.home.seo_description,
),
dir: "ltr",
categories: ["utilities", "games", "developer", "developer tools"],
id: "com.tresabhi.blitzkit",
start_url: "/",
launch_handler: { client_mode: "navigate-new" },
display: "fullscreen",
display_override: ["fullscreen", "standalone", "minimal-ui"],
lang: locales.default,
orientation: "any",
},
icons: { icons: {
windows: true, windows: true,
android: true, android: true,
@@ -88,21 +33,6 @@ export default defineConfig({
}, },
}), }),
AstroPWA({
manifest: false,
devOptions: { enabled: true },
workbox: {
globPatterns: ["**/*.{html,css,js,png,webp,svg,xml,json}"],
runtimeCaching: [
{
urlPattern: ({ url }) =>
url.href.startsWith(import.meta.env.PUBLIC_ASSET_BASE),
handler: "NetworkFirst",
},
],
},
}),
react(), react(),
], ],
}); });
+3 -1
View File
@@ -15,12 +15,13 @@
"@astrolib/seo": "^1.0.0-beta.8", "@astrolib/seo": "^1.0.0-beta.8",
"@blitzkit/core": "workspace:*", "@blitzkit/core": "workspace:*",
"@blitzkit/i18n": "workspace:*", "@blitzkit/i18n": "workspace:*",
"@fontsource-variable/jetbrains-mono": "^5.3.0",
"@fontsource-variable/roboto-flex": "^5.3.0",
"@fontsource/inter": "^5.2.8", "@fontsource/inter": "^5.2.8",
"@gltf-transform/core": "^4.4.2", "@gltf-transform/core": "^4.4.2",
"@gltf-transform/functions": "^4.4.2", "@gltf-transform/functions": "^4.4.2",
"@radix-ui/colors": "^3.0.0", "@radix-ui/colors": "^3.0.0",
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/themes": "^3.2.1",
"@react-three/drei": "^10.7.6", "@react-three/drei": "^10.7.6",
"@react-three/fiber": "^9.4.0", "@react-three/fiber": "^9.4.0",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
@@ -39,6 +40,7 @@
"markdown-to-jsx": "^7.7.13", "markdown-to-jsx": "^7.7.13",
"pwa-install-handler": "^2.6.3", "pwa-install-handler": "^2.6.3",
"quicklime": "^1.2.0", "quicklime": "^1.2.0",
"radix-ui": "^1.6.7",
"react": "^19.2.4", "react": "^19.2.4",
"react-dom": "^19.2.4", "react-dom": "^19.2.4",
"react-promise-suspense": "^0.3.4", "react-promise-suspense": "^0.3.4",
@@ -0,0 +1,3 @@
<svg width="21" height="54" viewBox="0 0 21 54" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 38L10 49H0L11 38L0 27H10L21 38ZM21 1V21L20 22H10L21 11L10 0H20L21 1ZM10 11L0 21V1L10 11Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 221 B

@@ -0,0 +1,3 @@
<svg width="30" height="52" viewBox="0 0 30 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.8564 44V52H0V36L13.8564 44ZM30 52H16.1436V44L30 36V52ZM28.8564 18V34L15 42L1.14355 34V18L15 10L28.8564 18ZM13.8564 8L0 16V0H13.8564V8ZM30 16L16.1436 8V0H30V16Z" fill="#EEEEF0"/>
</svg>

After

Width:  |  Height:  |  Size: 294 B

@@ -0,0 +1,3 @@
<svg width="70" height="35" viewBox="0 0 70 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M70 32L64 35H0L70 0V32ZM0 32V0H64L0 32Z" fill="#EEEEF0"/>
</svg>

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

@@ -0,0 +1,12 @@
.plug {
display: flex;
.content {
display: flex;
flex-direction: column;
justify-content: center;
padding: var(--space-3) var(--space-5);
}
}
@@ -1,5 +1,8 @@
import { Flex, Heading, Link, Text } from '@radix-ui/themes'; import { Var } from "../../core/radix/var";
import { Var } from '../core/radix/var'; import { Heading } from "../Heading";
import { Link } from "../Link";
import { Text } from "../Text";
import styles from "./index.module.css";
export function AesonPlug() { export function AesonPlug() {
return ( return (
@@ -9,25 +12,26 @@ export function AesonPlug() {
href="https://discord.gg/WHdER7ZPAD" href="https://discord.gg/WHdER7ZPAD"
underline="hover" underline="hover"
> >
<Flex <div
className={styles.plug}
style={{ style={{
backgroundColor: Var('green-3'), backgroundColor: Var("green-3"),
borderRadius: Var('radius-3'), borderRadius: Var("radius-3"),
overflow: 'hidden', overflow: "hidden",
}} }}
> >
<img <img
src="/assets/images/third-party/wotb-news.png" src="/assets/images/third-party/wotb-news.png"
style={{ width: '6rem', height: '6rem', objectFit: 'cover' }} style={{ width: "6rem", height: "6rem", objectFit: "cover" }}
/> />
<Flex py="3" px="5" direction="column" justify="center"> <div className={styles.content}>
<Heading size="5">Preview brought to you by WoT Blitz News</Heading> <Heading size="5">Preview brought to you by WoT Blitz News</Heading>
<Text color="gray"> <Text color="gray">
Join the Discord for the absolute latest news Join the Discord for the absolute latest news
</Text> </Text>
</Flex> </div>
</Flex> </div>
</Link> </Link>
); );
} }
@@ -0,0 +1,113 @@
---
import "@fontsource-variable/jetbrains-mono";
import "@fontsource-variable/roboto-flex";
---
<style>
:root {
--space-0: 0.0625rem;
--space-1: 0.125rem;
--space-2: 0.25rem;
--space-3: 0.5rem;
--space-4: 1rem;
--space-5: 2rem;
--space-6: 4rem;
--space-7: 8rem;
--space-8: 16rem;
--space-9: 32rem;
--page-width: 64rem;
--max-size: max(100vw, 100vh);
--radius-max: var(--max-size);
--font-size-regular: 1rem;
--font-size-minor: 0.75rem;
--font-size-major: 1.25rem;
--font-size-heading-1: 3rem;
--font-size-heading-2: 2rem;
--font-size-heading-3: 1.5rem;
--font-size-heading-4: 1.25rem;
--font-size-heading-5: 1rem;
--font-size-heading-6: 0.75rem;
--font-family-regular: "Roboto Flex Variable", sans-serif;
--font-family-mono: "JetBrains Mono Variable", monospace;
--color-regular: var(--gray-12);
--color-low-contrast: var(--gray-11);
--weight-light: 300;
--weight-regular: 400;
--weight-medium: 500;
--weight-bold: 700;
--weight-black: 900;
--outline-interactive: var(--space-1) solid var(--gray-4);
--outline-focus: var(--space-1) solid var(--accent-6);
/* --shadow-cavity:
inset calc(var(--space-1) * sin(45deg)) calc(var(--space-1) * sin(45deg))
var(--space-1) var(--black-a3),
inset calc(var(--space-1) * sin(45deg) * -1)
calc(var(--space-1) * sin(45deg) * -1) var(--space-1) var(--white-a1); */
--shadow-bump:
inset calc(var(--space-1) * sin(45deg)) calc(var(--space-1) * sin(45deg))
var(--space-1) var(--white-a3),
inset calc(var(--space-1) * sin(45deg) * -1)
calc(var(--space-1) * sin(45deg) * -1) var(--space-1) var(--black-a3);
--shadow-outline-width: 1.5px;
--shadow-outline-width-negative: calc(var(--shadow-outline-width) * -1);
/* --shadow-interactive-background: 0 0 0 var(--shadow-outline-width)
var(--gray-6);
--shadow-interactive-shine: var(--shadow-outline-width-negative)
var(--shadow-outline-width-negative) var(--shadow-outline-width)
var(--white-a1);
--shadow-interactive-shadow: var(--shadow-outline-width)
var(--shadow-outline-width) var(--shadow-outline-width) var(--black-a4);
--shadow-interactive:
var(--shadow-interactive-shine), var(--shadow-interactive-shadow),
var(--shadow-interactive-background); */
--shadow-aggressive: var(--space-1) var(--space-1) var(--space-4)
var(--black-a11);
--shadow-subtle: 0 var(--space-1) var(--space-3) var(--black-a5);
--shadow-none: 0 0 0 transparent;
&.light {
--shadow-subtle: 0 var(--space-1) var(--space-3) var(--black-a2);
}
--blur-glass: blur(4rem);
--blur-tint: blur(8rem);
--duration-brief: 200ms;
--duration-subtle: 2s;
--tank-card-min-width: 8rem;
}
</style>
<style is:global>
.composable-radius {
&[data-radius="1"] {
border-radius: var(--space-3);
}
&[data-radius="2"] {
border-radius: var(--space-4);
}
&[data-radius="3"] {
border-radius: var(--space-5);
}
&[data-radius="max"] {
border-radius: var(--radius-max);
}
}
</style>
@@ -0,0 +1,86 @@
.button {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-2);
border-radius: var(--max-size);
padding: var(--space-3) var(--space-4);
border: none;
font-family: var(--font-family-regular);
font-size: 0.75rem;
color: var(--gray-1);
font-weight: var(--weight-medium);
cursor: pointer;
&[data-size="minor"] {
font-size: 0.75rem;
}
&[data-array="true"] {
&:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
&[data-parent-array="true"] {
*:first-child > & {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
*:last-child > & {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
svg,
img {
width: 1em;
height: 1em;
}
&[data-light-text="true"] {
color: var(--white-a12);
}
&[data-variant="solid"] {
background-color: var(--accent-8);
}
&[data-variant="surface"],
&[data-variant="soft"] {
background-color: var(--accent-3);
color: var(--gray-12);
}
&[data-variant="inverted"] {
background-color: var(--accent-12);
color: var(--accent-1);
}
&[data-variant="ghost"],
&[data-variant="outline"] {
background: none;
color: var(--accent-12);
}
&[data-variant="ghost"] {
padding: 0;
}
&[data-variant="surface"],
&[data-variant="outline"] {
outline: var(--space-1) solid var(--accent-6);
}
}
@@ -0,0 +1,55 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import type { Color } from "../../ui/color";
import styles from "./index.module.css";
export interface ButtonProps extends ComponentProps<"button"> {
color?: Color;
radius?: `${1 | 2 | 3}` | "max";
variant?: "solid" | "surface" | "soft" | "inverted" | "ghost" | "outline";
size?: "regular" | "minor";
array?: boolean;
parentArray?: boolean;
highContrast?: boolean; // TODO: add high contrast
}
export const LIGHT_TEXT_COLORS = new Set<Color>([
"gold",
"bronze",
"teal",
"grass",
"amber",
"plum",
"pink",
"brown",
"crimson",
"jade",
"blue",
"tomato",
]);
export function Button({
className,
color,
variant = "solid",
style,
radius = "max",
size = "regular",
array = false,
parentArray = false,
...props
}: ButtonProps) {
return (
<button
className={classNames("composable-radius", styles.button, className)}
data-accent={color}
data-variant={variant}
data-light-text={variant === "solid"}
data-radius={radius}
data-size={size}
data-array={array}
data-parent-array={parentArray}
{...props}
/>
);
}
Whitespace-only changes.
@@ -0,0 +1,10 @@
import type { ReactNode } from "react";
import styles from "./index.module.css";
interface Props {
children: ReactNode;
}
export function Callout({ children }: Props) {
return <div className={styles.callout}>{children}</div>;
}
@@ -0,0 +1,33 @@
---
import type { Color } from "../ui/color";
interface Props {
color: Color;
alias: string;
alpha?: boolean;
}
const { color, alias, alpha } = Astro.props;
let styles = "";
styles += ":root{";
for (let i = 0; i < 12; i++) {
const n = i + 1;
styles += `--${alias}-${alpha ? "a" : ""}${n}:var(--${color}-${alpha ? "a" : ""}${n});`;
}
styles += "}";
styles += `*[data-accent='${alias}']{`;
for (let i = 0; i < 12; i++) {
const n = i + 1;
styles += `--accent-${alpha ? "a" : ""}${n}:var(--${alias}-${alpha ? "a" : ""}${n});`;
}
styles += "}";
---
<style set:html={styles}></style>
@@ -0,0 +1,54 @@
---
import * as colors from "@radix-ui/colors";
import type { Color } from "../ui/color";
interface Props {
color: Color | AlphaOnlyColor;
alpha?: boolean;
}
const ALPHA_ONLY_COLORS = ["black", "white"] as const;
type AlphaOnlyColor = (typeof ALPHA_ONLY_COLORS)[number];
const { color, alpha } = Astro.props;
const nameLight = `${color}${alpha ? "A" : ""}`;
const nameDark = `${color}${
ALPHA_ONLY_COLORS.includes(color as AlphaOnlyColor) ? "" : "Dark"
}${alpha ? "A" : ""}`;
const scaleLight = colors[nameLight as keyof typeof colors];
const scaleDark = colors[nameDark as keyof typeof colors];
let styles = "";
styles += ":root.dark{";
for (let i = 0; i < 12; i++) {
const n = i + 1;
const value =
scaleDark[`${color}${alpha ? "A" : ""}${n}` as keyof typeof scaleDark];
styles += `--${color}-${alpha ? "a" : ""}${n}:${value};`;
}
styles += "}";
styles += ":root.light{";
for (let i = 0; i < 12; i++) {
const n = i + 1;
const value =
scaleLight[`${color}${alpha ? "A" : ""}${n}` as keyof typeof scaleLight];
styles += `--${color}-${alpha ? "a" : ""}${n}:${value};`;
}
styles += "}";
styles += `*[data-accent='${color}']{`;
for (let i = 0; i < 12; i++) {
const n = i + 1;
styles += `--accent-${alpha ? "a" : ""}${n}:var(--${color}-${alpha ? "a" : ""}${n});`;
}
styles += "}";
---
<style set:html={styles}></style>
@@ -18,6 +18,7 @@ import { useLocale } from "../../hooks/useLocale";
import { CompareEphemeral } from "../../stores/compareEphemeral"; import { CompareEphemeral } from "../../stores/compareEphemeral";
import type { EquipmentMatrix } from "../../stores/duel"; import type { EquipmentMatrix } from "../../stores/duel";
import { BlitzkitButtonGrayIcon } from "../BlitzkitButtonGrayIcon"; import { BlitzkitButtonGrayIcon } from "../BlitzkitButtonGrayIcon";
import { CompareTankCard } from "../CompareTankCard";
import { ConsumablesManager } from "../ConsumablesManager"; import { ConsumablesManager } from "../ConsumablesManager";
import { CrewSkillManager } from "../CrewSkillManager"; import { CrewSkillManager } from "../CrewSkillManager";
import { EquipmentManager } from "../EquipmentManager"; import { EquipmentManager } from "../EquipmentManager";
@@ -27,7 +28,6 @@ import { StickyColumnHeaderCell } from "../StickyColumnHeaderCell";
import { StickyTableRoot } from "../StickyTableRoot"; import { StickyTableRoot } from "../StickyTableRoot";
import { Body } from "./Body"; import { Body } from "./Body";
import { InsertionMarker } from "./IntersectionMarker"; import { InsertionMarker } from "./IntersectionMarker";
import { TankCard } from "./TankCard";
interface CompareTableProps { interface CompareTableProps {
stats: TankCharacteristics[]; stats: TankCharacteristics[];
@@ -77,7 +77,7 @@ export function CompareTable({ stats }: CompareTableProps) {
</StickyColumnHeaderCell> </StickyColumnHeaderCell>
{members.map(({ tank, key }, index) => { {members.map(({ tank, key }, index) => {
return <TankCard index={index} key={key} tank={tank} />; return <CompareTankCard index={index} key={key} tank={tank} />;
})} })}
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>
@@ -0,0 +1,3 @@
.name {
max-width: 8rem;
}
@@ -1,20 +1,22 @@
import { type TankDefinition, tankIcon } from "@blitzkit/core"; import { type TankDefinition, tankIcon } from "@blitzkit/core";
import { Flex, Text } from "@radix-ui/themes";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import { Vector2 } from "three"; import { Vector2 } from "three";
import { useLocale } from "../../hooks/useLocale"; import { useLocale } from "../../hooks/useLocale";
import { CompareEphemeral } from "../../stores/compareEphemeral"; import { CompareEphemeral } from "../../stores/compareEphemeral";
import { InsertionMarker } from "../Compare/IntersectionMarker";
import { insertionMarkers } from "../Compare/IntersectionMarker/constants";
import { TankControl } from "../Compare/TankControl";
import { Flex } from "../Flex";
import { StickyColumnHeaderCell } from "../StickyColumnHeaderCell"; import { StickyColumnHeaderCell } from "../StickyColumnHeaderCell";
import { InsertionMarker } from "./IntersectionMarker"; import { Text } from "../Text";
import { insertionMarkers } from "./IntersectionMarker/constants"; import styles from "./index.module.css";
import { TankControl } from "./TankControl";
interface TankCardProps { interface TankCardProps {
index: number; index: number;
tank: TankDefinition; tank: TankDefinition;
} }
export function TankCard({ index, tank }: TankCardProps) { export function CompareTankCard({ index, tank }: TankCardProps) {
const draggable = useRef<HTMLDivElement>(null); const draggable = useRef<HTMLDivElement>(null);
const { unwrap } = useLocale(); const { unwrap } = useLocale();
@@ -103,12 +105,12 @@ export function TankCard({ index, tank }: TankCardProps) {
return ( return (
<StickyColumnHeaderCell width="0"> <StickyColumnHeaderCell width="0">
<Flex direction="column" align="center" justify="between" gap="2"> <Flex column align="center" justify="between" gap="2">
<TankControl index={index} key={tank.id} slug={tank.slug} /> <TankControl index={index} key={tank.id} slug={tank.slug} />
<Flex <Flex
ref={draggable} ref={draggable}
direction="column" column
align="center" align="center"
justify="between" justify="between"
gap="2" gap="2"
@@ -129,14 +131,7 @@ export function TankCard({ index, tank }: TankCardProps) {
}} }}
/> />
<Text <Text className={styles.name} nowrap overflow="ellipsis">
style={{
whiteSpace: "nowrap",
maxWidth: 128,
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{unwrap(tank.name!)} {unwrap(tank.name!)}
</Text> </Text>
</Flex> </Flex>
Whitespace-only changes.
@@ -0,0 +1,5 @@
import { DropdownMenu as _ } from "radix-ui";
import { composeRadixComponents } from "../../ui/compose";
import styles from "./index.module.css";
export const DropdownMenu = composeRadixComponents(_, styles);
@@ -0,0 +1,7 @@
.flex {
display: flex;
&[data-column="true"] {
flex-direction: column;
}
}
@@ -0,0 +1,22 @@
import type { ComponentProps } from "react";
import type { Space } from "../../types/space";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
interface Props extends ComponentProps<"div"> {
gap?: Space;
column?: boolean;
}
export function Flex({ children, column, className, gap, ...props }: Props) {
return (
<div
{...props}
className={classNames(styles.flex, className)}
data-gap={gap}
data-column={column}
>
{children}
</div>
);
}
@@ -0,0 +1,25 @@
.heading {
&[data-size="1"] {
font-size: var(--font-size-heading-1);
}
&[data-size="2"] {
font-size: var(--font-size-heading-2);
}
&[data-size="3"] {
font-size: var(--font-size-heading-3);
}
&[data-size="4"] {
font-size: var(--font-size-heading-4);
}
&[data-size="5"] {
font-size: var(--font-size-heading-5);
}
&[data-size="6"] {
font-size: var(--font-size-heading-6);
}
}
@@ -0,0 +1,23 @@
import { classNames } from "../../ui/classNames";
import { Text, type TextProps } from "../Text";
import styles from "./index.module.css";
export interface HeadingProps extends Omit<TextProps, "size"> {
size?: `${1 | 2 | 3 | 4 | 5 | 6}`;
}
export function Heading({
className,
weight,
size = "1",
...props
}: HeadingProps) {
return (
<Text
{...props}
weight={weight ?? "medium"}
className={classNames(styles.heading, className)}
data-size={size}
/>
);
}
@@ -0,0 +1,41 @@
---
import { literals } from "@blitzkit/i18n";
import locales from "@blitzkit/i18n/locales.json";
import { getStrings } from "../core/i18n/getStrings";
import { Link } from "./Link";
interface Props {
locale: string;
}
const { locale } = Astro.props;
const strings = getStrings(locale)
---
<style>
.center {
display: flex;
justify-content: center;
}
</style>
{
locale !== locales.default && (
<div class="center">
<Link
href="https://crowdin.com/project/blitzkrieg"
target="_blank"
underline="always"
>
{literals(strings.website.home.help_translate, {
name: "BlitzKit",
language:
strings.common.locales[
locale as keyof typeof strings.common.locales
],
})}
</Link>
</div>
)
}
@@ -0,0 +1,31 @@
---
import { tools } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
import ToolCardLayoutColumn from "./ToolCardLayoutColumn.astro";
import ToolCardLayoutRoot from "./ToolCardLayoutRoot.astro";
interface Props {
locale: string;
}
const { locale } = Astro.props;
const strings = getStrings(locale);
---
<Section>
<Heading size="2">{strings.home.cosmetics}</Heading>
<ToolCardLayoutRoot minor>
<ToolCardLayoutColumn>
<ToolCard {locale} tool={tools.avatars} />
</ToolCardLayoutColumn>
<ToolCardLayoutColumn>
<ToolCard {locale} tool={tools.backgrounds} />
</ToolCardLayoutColumn>
</ToolCardLayoutRoot>
</Section>
@@ -0,0 +1,31 @@
---
import { tools } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
import ToolCardLayoutColumn from "./ToolCardLayoutColumn.astro";
import ToolCardLayoutRoot from "./ToolCardLayoutRoot.astro";
interface Props {
locale: string;
}
const { locale } = Astro.props;
const strings = getStrings(locale);
---
<Section>
<Heading size="2" className="title">{strings.home.games}</Heading>
<ToolCardLayoutRoot>
<ToolCardLayoutColumn major>
<ToolCard {locale} tool={tools.mixer} />
</ToolCardLayoutColumn>
<ToolCardLayoutColumn>
<ToolCard {locale} tool={tools.guesser} />
</ToolCardLayoutColumn>
</ToolCardLayoutRoot>
</Section>
@@ -4,6 +4,10 @@ import { resolveBranchName } from "../core/blitzkit/branches";
import { getStrings } from "../core/i18n/getStrings"; import { getStrings } from "../core/i18n/getStrings";
import { literals } from "@blitzkit/i18n/src/literals"; import { literals } from "@blitzkit/i18n/src/literals";
interface Props {
locale: string;
}
const { locale } = Astro.props; const { locale } = Astro.props;
const branchName = resolveBranchName(locale); const branchName = resolveBranchName(locale);
const isBranchNamed = branchName !== undefined; const isBranchNamed = branchName !== undefined;
@@ -0,0 +1,32 @@
---
import { tools } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
import ToolCardLayoutColumn from "./ToolCardLayoutColumn.astro";
import ToolCardLayoutRoot from "./ToolCardLayoutRoot.astro";
interface Props {
locale: string;
}
const { locale } = Astro.props;
const strings = getStrings(locale);
---
<Section>
<Heading size="2">{strings.home.players}</Heading>
<ToolCardLayoutRoot>
<ToolCardLayoutColumn>
<ToolCard {locale} minor tool={tools.session} />
<ToolCard {locale} minor tool={tools.playlist} />
</ToolCardLayoutColumn>
<ToolCardLayoutColumn major>
<ToolCard {locale} tool={tools.players} />
</ToolCardLayoutColumn>
</ToolCardLayoutRoot>
</Section>
@@ -0,0 +1,31 @@
---
import { tools } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
import ToolCardLayoutColumn from "./ToolCardLayoutColumn.astro";
import ToolCardLayoutRoot from "./ToolCardLayoutRoot.astro";
interface Props {
locale: string;
}
const { locale } = Astro.props;
const strings = getStrings(locale);
---
<Section>
<Heading size="2">{strings.home.tanks}</Heading>
<ToolCardLayoutRoot>
<ToolCardLayoutColumn major>
<ToolCard {locale} tool={tools.tanks} />
</ToolCardLayoutColumn>
<ToolCardLayoutColumn>
<ToolCard {locale} minor tool={tools.compare} />
<ToolCard {locale} minor tool={tools.performance} />
</ToolCardLayoutColumn>
</ToolCardLayoutRoot>
</Section>
@@ -0,0 +1,31 @@
---
import { tools } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
import ToolCardLayoutColumn from "./ToolCardLayoutColumn.astro";
import ToolCardLayoutRoot from "./ToolCardLayoutRoot.astro";
interface Props {
locale: string;
}
const { locale } = Astro.props;
const strings = getStrings(locale);
---
<Section>
<Heading size="2">{strings.home.technical}</Heading>
<ToolCardLayoutRoot minor>
<ToolCardLayoutColumn>
<ToolCard {locale} tool={tools.api} />
</ToolCardLayoutColumn>
<ToolCardLayoutColumn>
<ToolCard {locale} tool={tools.changelogs} />
</ToolCardLayoutColumn>
</ToolCardLayoutRoot>
</Section>
@@ -0,0 +1,5 @@
.icon-button {
padding: var(--space-3);
aspect-ratio: 1 / 1;
}
@@ -0,0 +1,12 @@
import { classNames } from "../../ui/classNames";
import { Button, type ButtonProps } from "../Button";
import styles from "./index.module.css";
export function IconButton({ className, ...props }: ButtonProps) {
return (
<Button
className={classNames(className, styles["icon-button"])}
{...props}
/>
);
}
@@ -0,0 +1,23 @@
.link {
text-decoration-color: currentColor;
cursor: pointer;
display: inline;
align-items: center;
gap: var(--space-3);
&[data-underline="hover"],
&[data-underline="never"] {
text-decoration: none;
}
&[data-underline="hover"]:hover,
&[data-underline="hover"]:focus {
text-decoration: underline;
}
svg {
width: 1.25em;
height: 1.25em;
}
}
@@ -0,0 +1,32 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import type { Color } from "../../ui/color";
import styles from "./index.module.css";
export interface LinkProps extends ComponentProps<"a"> {
underline?: "always" | "hover" | "never";
highContrast?: boolean;
color?: Color | "accent";
}
export function Link({
highContrast,
className,
underline = "always",
color = "accent",
style,
...props
}: LinkProps) {
return (
<a
className={classNames(styles.link, className)}
style={{
color: `var(--${color}-${highContrast ? 12 : 11})`,
...style,
}}
{...props}
data-underline={underline}
data-high-contrast={highContrast}
/>
);
}
+9 -8
View File
@@ -1,14 +1,15 @@
import locales from "@blitzkit/i18n/locales.json"; import locales from "@blitzkit/i18n/locales.json";
import { Link, type LinkProps } from "@radix-ui/themes"; import { Link, type LinkProps } from "./Link";
import type { LocaleAcceptorProps } from "../hooks/useLocale";
type LinkI18nProps = LinkProps & LocaleAcceptorProps; export interface LinkI18n extends LinkProps {
locale: string;
export function LinkI18n({ locale, href, ...props }: LinkI18nProps) { }
const prefix =
locale === undefined || locale === locales.default ? "" : `/${locale}`;
export function LinkI18n({ locale, href, ...props }: LinkI18n) {
return ( return (
<Link href={href?.startsWith("/") ? `${prefix}${href}` : href} {...props} /> <Link
href={`${locale === locales.default ? "" : `/${locale}`}${href}`}
{...props}
/>
); );
} }
+11 -12
View File
@@ -19,9 +19,7 @@ export interface Props {
} }
const { integrated = false } = Astro.props; const { integrated = false } = Astro.props;
const toolsFiltered = Object.values(tools).filter( const toolsFiltered = Object.entries(tools).filter(([, tool]) => !tool.href);
(tool) => !tool.href && !tool.disabled
);
const { locale } = Astro.props; const { locale } = Astro.props;
const branchName = resolveBranchName(locale); const branchName = resolveBranchName(locale);
const isBranchNamed = branchName !== undefined; const isBranchNamed = branchName !== undefined;
@@ -141,12 +139,13 @@ const strings = getStrings(locale);
className="tools" className="tools"
> >
{ {
toolsFiltered.map((tool) => { toolsFiltered.map(([id, tool]) => {
const selected = Astro.url.pathname.includes(`/${tool.id}`); const selected = Astro.url.pathname.includes(
`/${tool.path ?? id}`,
);
const toolStrings = const toolStrings =
strings.website.tools[ strings.website.tools[
(tool.strings ?? (tool.strings ?? id) as keyof typeof strings.website.tools
tool.id) as keyof typeof strings.website.tools
]; ];
return ( return (
@@ -156,7 +155,7 @@ const strings = getStrings(locale);
color="gray" color="gray"
highContrast={selected} highContrast={selected}
size={{ initial: "1", md: "2" }} size={{ initial: "1", md: "2" }}
href={`/${tool.id}`} href={`/${tool.path ?? id}`}
underline="hover" underline="hover"
> >
{toolStrings.name} {toolStrings.name}
@@ -207,10 +206,10 @@ const strings = getStrings(locale);
display={{ initial: "flex", sm: "none" }} display={{ initial: "flex", sm: "none" }}
> >
{ {
toolsFiltered.map((tool) => { toolsFiltered.map(([id, tool]) => {
const toolStrings = const toolStrings =
strings.website.tools[ strings.website.tools[
(tool.strings ?? tool.id) as keyof typeof strings.website.tools (tool.strings ?? id) as keyof typeof strings.website.tools
]; ];
return ( return (
@@ -218,12 +217,12 @@ const strings = getStrings(locale);
color="gray" color="gray"
highContrast highContrast
style={{ display: "contents" }} style={{ display: "contents" }}
href={`/${tool.id}`} href={`/${tool.path ?? id}`}
> >
<Box <Box
style={{ style={{
borderRadius: Var("radius-2"), borderRadius: Var("radius-2"),
backgroundImage: `url(/assets/images/tools/${tool.id}.webp)`, backgroundImage: `url(/assets/images/tools/${id}.webp)`,
backgroundSize: "200%", backgroundSize: "200%",
backgroundPosition: "right center", backgroundPosition: "right center",
}} }}
@@ -1,55 +0,0 @@
import { Flex, type FlexProps, Theme } from "@radix-ui/themes";
import type { ComponentProps } from "react";
import { NAVBAR_HEIGHT } from "../constants/navbar";
import type { RadixSize } from "../stores/embedState";
import { BlitzKitTheme } from "./BlitzKitTheme";
type PageWrapperProps = FlexProps & {
color?: ComponentProps<typeof Theme>["accentColor"];
containerProps?: ComponentProps<typeof Theme>;
noFlex1?: boolean;
padding?: RadixSize;
noMinHeight?: boolean;
};
export function PageWrapper({
style,
color,
children,
noFlex1 = false,
containerProps,
noMinHeight = false,
padding = "4",
...props
}: PageWrapperProps) {
return (
<BlitzKitTheme
accentColor={color}
style={{
flex: noFlex1 ? undefined : 1,
display: "flex",
minHeight: noMinHeight ? "unset" : `calc(100svh - ${NAVBAR_HEIGHT}px)`,
flexDirection: "column",
...containerProps?.style,
}}
{...containerProps}
>
<Flex
direction="column"
gap="4"
p={padding}
width="100%"
maxWidth="80rem"
style={{
margin: "auto",
boxSizing: "border-box",
flex: 1,
...style,
}}
{...props}
>
{children}
</Flex>
</BlitzKitTheme>
);
}
@@ -20,7 +20,7 @@ import { App } from "../stores/app";
import { TankFilters } from "../stores/tankFilters"; import { TankFilters } from "../stores/tankFilters";
import type { MaybeSkeletonComponentProps } from "../types/maybeSkeletonComponentProps"; import type { MaybeSkeletonComponentProps } from "../types/maybeSkeletonComponentProps";
import { LinkI18n } from "./LinkI18n"; import { LinkI18n } from "./LinkI18n";
import { FilterControl } from "./TankSearch/components/FilterControl"; import { TankSearchFilters } from "./TankSearchFilters";
const tankDefinitions = await api.tankDefinitions(); const tankDefinitions = await api.tankDefinitions();
@@ -87,7 +87,7 @@ export function PlaylistGenerator({ skeleton }: MaybeSkeletonComponentProps) {
direction={{ initial: "column-reverse", md: "row" }} direction={{ initial: "column-reverse", md: "row" }}
> >
<Flex direction="column" gap="4" align="center"> <Flex direction="column" gap="4" align="center">
<FilterControl /> <TankSearchFilters />
<Button <Button
onClick={() => { onClick={() => {
-41
View File
@@ -1,41 +0,0 @@
import { assertSecret } from "@blitzkit/core";
import { ArrowRightIcon } from "@radix-ui/react-icons";
import { Button, Code, Flex, Link, Text } from "@radix-ui/themes";
export function Plugs() {
const promoteOpentest =
assertSecret(import.meta.env.PUBLIC_PROMOTE_OPENTEST) === "true" &&
assertSecret(import.meta.env.PUBLIC_ENVIRONMENT) !== "opentest";
const promotions = [promoteOpentest];
if (promotions.every((promotion) => !promotion)) return null;
return (
<Flex
align="center"
direction="column"
justify="center"
px="4"
py="8"
gap="6"
>
{promoteOpentest && (
<Flex direction="column" gap="3" align="center">
<Text size="5">
BlitzKit{" "}
<Code variant="outline" size="4" color="gray">
opentest
</Code>{" "}
is available now{" "}
</Text>
<Link href="https://opentest.blitzkit.app/" target="_blank">
<Button color="green">
BlitzKit opentest <ArrowRightIcon />
</Button>
</Link>
</Flex>
)}
</Flex>
);
}
@@ -0,0 +1,3 @@
.recent {
/* mt="2" mb="6" */
}
@@ -1,17 +1,20 @@
import { Flex, Separator, Text } from "@radix-ui/themes";
import { isEqual } from "lodash-es"; import { isEqual } from "lodash-es";
import { useMemo } from "react"; import { useMemo } from "react";
import { api } from "../../../core/blitzkit/api"; import { api } from "../../core/blitzkit/api";
import { useLocale } from "../../../hooks/useLocale"; import { useLocale } from "../../hooks/useLocale";
import { TankFilters } from "../../../stores/tankFilters"; import { TankFilters } from "../../stores/tankFilters";
import { TankopediaPersistent } from "../../../stores/tankopediaPersistent"; import { TankopediaPersistent } from "../../stores/tankopediaPersistent";
import { TankSort } from "../../../stores/tankopediaSort"; import { TankSort } from "../../stores/tankopediaSort";
import { TankCard } from "../../TankCard"; import { Flex } from "../Flex";
import { TankCardWrapper } from "./TankCardWrapper"; import { Separator } from "../Separator";
import { TankCard } from "../TankCard";
import { TankCardWrapper } from "../TankCardWrapper";
import { Text } from "../Text";
import styles from "./index.module.css";
const tankDefinitions = await api.tankDefinitions(); const tankDefinitions = await api.tankDefinitions();
export function RecentlyViewed() { export function RecentlyViewedTanks() {
const filters = TankFilters.use(); const filters = TankFilters.use();
// non-reactive because it is a little weird that it updates instantly even before the page loads // non-reactive because it is a little weird that it updates instantly even before the page loads
const recentlyViewed = TankopediaPersistent.state.recentlyViewed.filter( const recentlyViewed = TankopediaPersistent.state.recentlyViewed.filter(
@@ -35,7 +38,7 @@ export function RecentlyViewed() {
} }
return ( return (
<Flex direction="column" gap="2" mt="2" mb="6"> <Flex column gap="2" className={styles.recent}>
<Text color="gray" align="center"> <Text color="gray" align="center">
{strings.website.common.tank_search.recent} {strings.website.common.tank_search.recent}
</Text> </Text>
@@ -45,7 +48,7 @@ export function RecentlyViewed() {
))} ))}
</TankCardWrapper> </TankCardWrapper>
<Separator size="4" /> <Separator />
</Flex> </Flex>
); );
} }
@@ -0,0 +1,14 @@
.section {
display: flex;
justify-content: center;
.content {
flex: 1;
max-width: var(--page-width);
gap: var(--space-4);
display: flex;
flex-direction: column;
}
}
@@ -0,0 +1,13 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export interface SectionProps extends ComponentProps<"div"> {}
export function Section({ className, children, ...props }: SectionProps) {
return (
<div className={classNames(styles.section, className)} {...props}>
<div className={styles.content}>{children}</div>
</div>
);
}
@@ -0,0 +1,2 @@
.separator {
}
@@ -0,0 +1,5 @@
import styles from "./index.module.css";
export function Separator() {
return <div className={styles.separator} />;
}
@@ -0,0 +1,25 @@
@keyframes skeleton-animation {
0% {
background-color: var(--color-1);
}
50% {
background-color: var(--color-2);
}
100% {
background-color: var(--color-1);
}
}
.skeleton {
--color-1: var(--black-a5);
--color-2: var(--black-a4);
:global(:root.dark) & {
--color-1: var(--white-a3);
--color-2: var(--white-a2);
}
animation: skeleton-animation var(--duration-subtle) ease infinite;
border-radius: var(--space-2);
}
@@ -0,0 +1,9 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export interface SkeletonProps extends ComponentProps<"div"> {}
export function Skeleton({ className, ...props }: SkeletonProps) {
return <div className={classNames(styles.skeleton, className)} {...props} />;
}
Whitespace-only changes.
@@ -0,0 +1,3 @@
export function Spinner() {
return null;
}
@@ -1,13 +1,14 @@
import { alias, TankType, type TankDefinition } from "@blitzkit/core"; import { alias, TankType, type TankDefinition } from "@blitzkit/core";
import { Flex, Text, type TextProps } from "@radix-ui/themes";
import { uniq } from "lodash-es"; import { uniq } from "lodash-es";
import { forwardRef, type ReactNode } from "react"; import { forwardRef, type ReactNode } from "react";
import { api } from "../../core/blitzkit/api"; import { api } from "../../core/blitzkit/api";
import { useLocale } from "../../hooks/useLocale"; import { useLocale } from "../../hooks/useLocale";
import { TankopediaPersistent } from "../../stores/tankopediaPersistent"; import { TankopediaPersistent } from "../../stores/tankopediaPersistent";
import { classIcons } from "../ClassIcon"; import { classIcons } from "../ClassIcon";
import { Flex } from "../Flex";
import { LinkI18n } from "../LinkI18n"; import { LinkI18n } from "../LinkI18n";
import { MAX_RECENTLY_VIEWED } from "../TankSearch/constants"; import { MAX_RECENTLY_VIEWED } from "../TankSearch/constants";
import { Text, type TextProps } from "../Text";
import "./index.css"; import "./index.css";
type TankCardProps = TextProps & { type TankCardProps = TextProps & {
@@ -0,0 +1,7 @@
.icon {
/* height="5rem" */
}
.name {
/* height="1em" */
}
@@ -1,12 +1,14 @@
import { Flex, Skeleton } from "@radix-ui/themes";
import { memo, useRef } from "react"; import { memo, useRef } from "react";
import { useIntersection } from "../../../hooks/useIntersection"; import { useIntersection } from "../../hooks/useIntersection";
import { Flex } from "../Flex";
import { Skeleton } from "../Skeleton";
import styles from "./index.module.css";
interface SkeletonTankCardProps { interface SkeletonTankCardProps {
onIntersection?: () => void; onIntersection?: () => void;
} }
export const SkeletonTankCard = memo( export const TankCardSkeleton = memo(
({ onIntersection }: SkeletonTankCardProps) => { ({ onIntersection }: SkeletonTankCardProps) => {
const card = useRef<HTMLDivElement>(null!); const card = useRef<HTMLDivElement>(null!);
@@ -15,11 +17,11 @@ export const SkeletonTankCard = memo(
}); });
return ( return (
<Flex direction="column" gap="2" ref={card}> <Flex column gap="2" ref={card}>
<Skeleton height="5rem" /> <Skeleton className={styles.icon} />
<Skeleton height="1em" /> <Skeleton className={styles.name} />
</Flex> </Flex>
); );
}, },
() => true () => true,
); );
@@ -0,0 +1,7 @@
.wrapper {
/* py="4"
columns="repeat(auto-fill, minmax(7rem, 1fr))"
flow="dense"
gap="4"
gapY="8" */
}
@@ -0,0 +1,10 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export function TankCardWrapper({
className,
...props
}: ComponentProps<"div">) {
return <div className={classNames(styles.wrapper, className)} {...props} />;
}
@@ -1,4 +1,3 @@
import { Flex, Link, Text } from "@radix-ui/themes";
import { useLocale } from "../../../hooks/useLocale"; import { useLocale } from "../../../hooks/useLocale";
import { TankFilters } from "../../../stores/tankFilters"; import { TankFilters } from "../../../stores/tankFilters";
@@ -1,6 +1,5 @@
import { type TankDefinition } from "@blitzkit/core"; import { type TankDefinition } from "@blitzkit/core";
import { CaretRightIcon } from "@radix-ui/react-icons"; import { CaretRightIcon } from "@radix-ui/react-icons";
import { Button, TextField } from "@radix-ui/themes";
import { useLocale } from "../../../hooks/useLocale"; import { useLocale } from "../../../hooks/useLocale";
import { TankFilters } from "../../../stores/tankFilters"; import { TankFilters } from "../../../stores/tankFilters";
import { LinkI18n } from "../../LinkI18n"; import { LinkI18n } from "../../LinkI18n";
@@ -1,11 +1,11 @@
import { CaretDownIcon } from '@radix-ui/react-icons'; import { CaretDownIcon } from "@radix-ui/react-icons";
import { Button, DropdownMenu } from '@radix-ui/themes'; import { useLocale } from "../../../hooks/useLocale";
import { useLocale } from '../../../hooks/useLocale';
import type { import type {
TankopediaSortBy, TankopediaSortBy,
TankopediaSortDirection, TankopediaSortDirection,
} from '../../../stores/tankopediaPersistent'; } from "../../../stores/tankopediaPersistent";
import { TankSort } from '../../../stores/tankopediaSort'; import { TankSort } from "../../../stores/tankopediaSort";
import { DropdownMenu } from "../../DropdownMenu";
interface ItemProps { interface ItemProps {
by: TankopediaSortBy; by: TankopediaSortBy;
@@ -38,12 +38,10 @@ export function Sort() {
const { strings } = useLocale(); const { strings } = useLocale();
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button variant="surface" color="gray"> {strings.website.common.tank_search.sort_dropdown.label}
{strings.website.common.tank_search.sort_dropdown.label} <CaretDownIcon />
<CaretDownIcon />
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content align="end"> <DropdownMenu.Content align="end">
@@ -1,14 +0,0 @@
import { Grid, type GridProps } from "@radix-ui/themes";
export function TankCardWrapper(props: GridProps) {
return (
<Grid
py="4"
columns="repeat(auto-fill, minmax(7rem, 1fr))"
flow="dense"
gap="4"
gapY="8"
{...props}
/>
);
}
@@ -0,0 +1,19 @@
.container {
display: flex;
flex-direction: column;
gap: var(--space-2);
flex-grow: 1;
.tanks {
/* mt="2" gap="1" align="center" justify="center" direction="column" */
.count {
/* gap="2" */
}
}
.test-warning {
/* justify="center" mt="4" */
}
}
@@ -7,10 +7,9 @@ import {
type TankDefinition, type TankDefinition,
} from "@blitzkit/core"; } from "@blitzkit/core";
import { literals } from "@blitzkit/i18n/src/literals"; import { literals } from "@blitzkit/i18n/src/literals";
import { Callout, Flex, Link, Text, type FlexProps } from "@radix-ui/themes";
import fuzzysort from "fuzzysort"; import fuzzysort from "fuzzysort";
import { times, uniq } from "lodash-es"; import { times, uniq } from "lodash-es";
import { memo, useEffect, useMemo, useState } from "react"; import { memo, useEffect, useMemo, useState, type ComponentProps } from "react";
import usePromise from "react-promise-suspense"; import usePromise from "react-promise-suspense";
import { awaitableTankNames } from "../../core/awaitables/tankNames"; import { awaitableTankNames } from "../../core/awaitables/tankNames";
import { api } from "../../core/blitzkit/api"; import { api } from "../../core/blitzkit/api";
@@ -23,18 +22,22 @@ import { TankopediaPersistent } from "../../stores/tankopediaPersistent";
import { SORT_UNITS } from "../../stores/tankopediaPersistent/constants"; import { SORT_UNITS } from "../../stores/tankopediaPersistent/constants";
import { TankSort } from "../../stores/tankopediaSort"; import { TankSort } from "../../stores/tankopediaSort";
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps"; import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
import { Callout } from "../Callout";
import { ExperimentIcon } from "../ExperimentIcon"; import { ExperimentIcon } from "../ExperimentIcon";
import { Link } from "../Link";
import { RecentlyViewedTanks } from "../RecentlyViewedTanks";
import { TankCardSkeleton } from "../TankCardSkeleton";
import { TankCardWrapper } from "../TankCardWrapper";
import { TankSearchBar } from "../TankSearchBar";
import { TankSearchFilters } from "../TankSearchFilters";
import { Text } from "../Text";
import { TankSearchCard } from "./components/Card"; import { TankSearchCard } from "./components/Card";
import { FilterControl } from "./components/FilterControl";
import { NoResults } from "./components/NoResults"; import { NoResults } from "./components/NoResults";
import { RecentlyViewed } from "./components/RecentlyViewed";
import { SearchBar } from "./components/SearchBar";
import { SkeletonTankCard } from "./components/SkeletonTankCard";
import { TankCardWrapper } from "./components/TankCardWrapper";
import { MAX_RECENTLY_VIEWED } from "./constants"; import { MAX_RECENTLY_VIEWED } from "./constants";
import styles from "./index.module.css";
export type TankSearchProps = MaybeSkeletonComponentProps & export type TankSearchProps = MaybeSkeletonComponentProps &
Omit<FlexProps, "onSelect"> & { ComponentProps<"div"> & {
compact?: boolean; compact?: boolean;
onSelect?: (tank: TankDefinition) => void; onSelect?: (tank: TankDefinition) => void;
onSelectAll?: (tanks: TankDefinition[]) => void; onSelectAll?: (tanks: TankDefinition[]) => void;
@@ -427,20 +430,20 @@ export const TankSearch = memo<TankSearchProps>(
}, [tankFilters, tankopediaSort]); }, [tankFilters, tankopediaSort]);
return ( return (
<Flex direction="column" gap="2" flexGrow="1" {...props}> <div className={styles.container} {...props}>
<SearchBar <TankSearchBar
skeleton={skeleton} skeleton={skeleton}
topResult={tanks?.[0]} topResult={tanks?.[0]}
onSelect={onSelect} onSelect={onSelect}
/> />
{!tankFilters.search && !tankFilters.searching && <FilterControl />} {!tankFilters.search && !tankFilters.searching && <TankSearchFilters />}
{!skeleton && !compact && <RecentlyViewed />} {!skeleton && !compact && <RecentlyViewedTanks />}
<Flex mt="2" gap="1" align="center" justify="center" direction="column"> <div className={styles.tanks}>
<Flex gap="2"> <div className={styles.count}>
<Text color="gray"> <Text lowContrast>
{sorted.length === 1 {sorted.length === 1
? strings.website.common.tank_search.count_singular ? strings.website.common.tank_search.count_singular
: literals(strings.website.common.tank_search.count_plural, { : literals(strings.website.common.tank_search.count_plural, {
@@ -468,7 +471,7 @@ export const TankSearch = memo<TankSearchProps>(
{strings.website.common.tank_search.select_all} {strings.website.common.tank_search.select_all}
</Link> </Link>
)} )}
</Flex> </div>
{tankopediaSort.by !== "meta.none" && ( {tankopediaSort.by !== "meta.none" && (
<Text color="gray"> <Text color="gray">
@@ -483,19 +486,15 @@ export const TankSearch = memo<TankSearchProps>(
, {tankopediaSort.direction} , {tankopediaSort.direction}
</Text> </Text>
)} )}
</Flex> </div>
{tankFilters.showTesting && !tankFilters.showNonTesting && ( {tankFilters.showTesting && !tankFilters.showNonTesting && (
<Flex justify="center" mt="4"> <div className={styles["test-warning"]}>
<Callout.Root color="amber"> <Callout color="amber">
<Callout.Icon> <ExperimentIcon style={{ width: "1em", height: "1em" }} />
<ExperimentIcon style={{ width: "1em", height: "1em" }} /> {strings.website.common.warnings.test}
</Callout.Icon> </Callout>
<Callout.Text> </div>
{strings.website.common.warnings.test}
</Callout.Text>
</Callout.Root>
</Flex>
)} )}
{!skeleton && !tankFilters.searching && ( {!skeleton && !tankFilters.searching && (
@@ -514,7 +513,7 @@ export const TankSearch = memo<TankSearchProps>(
Math.min(PREVIEW_COUNT, sorted.length - loadedCards), Math.min(PREVIEW_COUNT, sorted.length - loadedCards),
(index) => { (index) => {
return ( return (
<SkeletonTankCard <TankCardSkeleton
key={index} key={index}
onIntersection={() => { onIntersection={() => {
setLoadedCards((state) => setLoadedCards((state) =>
@@ -539,12 +538,12 @@ export const TankSearch = memo<TankSearchProps>(
skeleton ? DEFAULT_LOADED_CARDS : 10 + 10 * Math.random(), skeleton ? DEFAULT_LOADED_CARDS : 10 + 10 * Math.random(),
), ),
(index) => ( (index) => (
<SkeletonTankCard key={index} /> <TankCardSkeleton key={index} />
), ),
)} )}
</TankCardWrapper> </TankCardWrapper>
)} )}
</Flex> </div>
); );
}, },
); );
@@ -0,0 +1,7 @@
.search-bar {
/* justify="center" */
.wrapper {
/* gap="2" flexGrow="1" */
}
}
@@ -1,20 +1,25 @@
import type { TankDefinition } from "@blitzkit/core"; import type { TankDefinition } from "@blitzkit/core";
import { MagnifyingGlassIcon } from "@radix-ui/react-icons"; import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
import { Flex, Spinner, TextField } from "@radix-ui/themes";
import { debounce } from "lodash-es"; import { debounce } from "lodash-es";
import { type KeyboardEventHandler, useCallback, useRef } from "react"; import { type KeyboardEventHandler, useCallback, useRef } from "react";
import { useLocale } from "../../../hooks/useLocale"; import { useLocale } from "../../hooks/useLocale";
import { TankFilters } from "../../../stores/tankFilters"; import { TankFilters } from "../../stores/tankFilters";
import type { MaybeSkeletonComponentProps } from "../../../types/maybeSkeletonComponentProps"; import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
import { QuickLink } from "./QuickLink"; import { Spinner } from "../Spinner";
import { Sort } from "./Sort"; import { Sort } from "../TankSearch/components/Sort";
import { TextField } from "../TextField";
import styles from "./index.module.css";
type SearchBarProps = MaybeSkeletonComponentProps & { type SearchBarProps = MaybeSkeletonComponentProps & {
topResult?: TankDefinition; topResult?: TankDefinition;
onSelect?: (tank: TankDefinition) => void; onSelect?: (tank: TankDefinition) => void;
}; };
export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) { export function TankSearchBar({
topResult,
skeleton,
onSelect,
}: SearchBarProps) {
const { strings } = useLocale(); const { strings } = useLocale();
const search = TankFilters.use((state) => state.search); const search = TankFilters.use((state) => state.search);
const searching = TankFilters.use((state) => state.searching); const searching = TankFilters.use((state) => state.searching);
@@ -33,7 +38,7 @@ export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) {
draft.search = sanitized.length === 0 ? null : sanitized; draft.search = sanitized.length === 0 ? null : sanitized;
}); });
}, 500), }, 500),
[] [],
); );
const handleChange = useCallback(() => { const handleChange = useCallback(() => {
if (!searching) { if (!searching) {
@@ -56,14 +61,13 @@ export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) {
window.location.href = `/tanks/${topResult.slug}`; window.location.href = `/tanks/${topResult.slug}`;
} }
}, },
[topResult] [topResult],
); );
return ( return (
<Flex justify="center"> <div className={styles["search-bar"]}>
<Flex gap="2" flexGrow="1"> <div className={styles.wrapper}>
<TextField.Root <TextField
variant="classic"
disabled={skeleton} disabled={skeleton}
defaultValue={search ?? undefined} defaultValue={search ?? undefined}
style={{ flex: 1 }} style={{ flex: 1 }}
@@ -72,15 +76,11 @@ export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) {
onChange={handleChange} onChange={handleChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
> >
<TextField.Slot> {searching ? <Spinner /> : <MagnifyingGlassIcon />}
{searching ? <Spinner /> : <MagnifyingGlassIcon />} </TextField>
</TextField.Slot>
<QuickLink topResult={topResult} />
</TextField.Root>
<Sort /> <Sort />
</Flex> </div>
</Flex> </div>
); );
} }
@@ -0,0 +1,25 @@
.nation-option {
/* width="calc(100% + calc(4 * var(--space-2)))"
height="100%"
position="absolute"
right="0"
mr="-2"
style={{
backgroundImage: `url(${alias("api", `/flags/scratched/${nation}.webp`)})`,
backgroundSize: "100%",
backgroundRepeat: "no-repeat",
backgroundPosition: "5rem center",
}} */
.overlay {
/* width="100%"
height="100%"
style={{
background: `linear-gradient(90deg, var(--gray-2) 50%, transparent)`,
}} */
}
}
.overflow-plus {
/* ml="1" */
}
@@ -15,30 +15,26 @@ import {
ResetIcon, ResetIcon,
TrashIcon, TrashIcon,
} from "@radix-ui/react-icons"; } from "@radix-ui/react-icons";
import {
Box,
Button,
DropdownMenu,
Flex,
IconButton,
Text,
Tooltip,
type FlexProps,
} from "@radix-ui/themes";
import { times } from "lodash-es"; import { times } from "lodash-es";
import { Fragment, type ComponentProps, type ReactNode } from "react"; import { Fragment, type ComponentProps, type ReactNode } from "react";
import { api } from "../../../core/blitzkit/api"; import { api } from "../../core/blitzkit/api";
import { useLocale } from "../../../hooks/useLocale"; import { useLocale } from "../../hooks/useLocale";
import { App } from "../../../stores/app"; import { App } from "../../stores/app";
import { TankFilters, type CaseType } from "../../../stores/tankFilters"; import { TankFilters, type CaseType } from "../../stores/tankFilters";
import { classIcons } from "../../ClassIcon"; import { classIcons } from "../ClassIcon";
import { GunAutoloaderIcon } from "../../GunAutoloaderIcon"; import { DropdownMenu } from "../DropdownMenu";
import { GunAutoreloaderIcon } from "../../GunAutoreloaderIcon"; import { Flex } from "../Flex";
import { GunRegularIcon } from "../../GunRegularIcon"; import { GunAutoloaderIcon } from "../GunAutoloaderIcon";
import { MissingShellIcon } from "../../MissingShellIcon"; import { GunAutoreloaderIcon } from "../GunAutoreloaderIcon";
import { ResearchedIcon } from "../../ResearchedIcon"; import { GunRegularIcon } from "../GunRegularIcon";
import { ScienceIcon } from "../../ScienceIcon"; import { IconButton } from "../IconButton";
import { ScienceOffIcon } from "../../ScienceOffIcon"; import { MissingShellIcon } from "../MissingShellIcon";
import { ResearchedIcon } from "../ResearchedIcon";
import { ScienceIcon } from "../ScienceIcon";
import { ScienceOffIcon } from "../ScienceOffIcon";
import { Text } from "../Text";
import { Tooltip } from "../Tooltip";
import styles from "./index.module.css";
const gameDefinitions = await api.gameDefinitions(); const gameDefinitions = await api.gameDefinitions();
const consumableDefinitions = await api.consumableDefinitions(); const consumableDefinitions = await api.consumableDefinitions();
@@ -175,14 +171,9 @@ const MAX_ICONS = 4;
const TIERS = times(10, (i) => 10 - i); const TIERS = times(10, (i) => 10 - i);
export function FilterControl() { export function TankSearchFilters() {
return ( return (
<Flex <div className={styles.container}>
align="center"
justify={{ initial: "start", md: "center" }}
gap="2"
wrap="wrap"
>
<TiersFilter /> <TiersFilter />
<ClassFilter /> <ClassFilter />
<TypeFilter /> <TypeFilter />
@@ -198,7 +189,7 @@ export function FilterControl() {
<GameModeAbilitiesFilter /> <GameModeAbilitiesFilter />
<ResetButton /> <ResetButton />
</Flex> </div>
); );
} }
@@ -224,23 +215,21 @@ function TiersFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button color="gray" variant="surface"> <Flex gap="1">
<Flex gap="1"> {tiers.slice(0, MAX_ICONS).map((tier) => (
{tiers.slice(0, MAX_ICONS).map((tier) => ( <Text size="minor" key={tier}>
<Text size="1" key={tier}> {TIER_ROMAN_NUMERALS[tier]}
{TIER_ROMAN_NUMERALS[tier]} </Text>
</Text> ))}
))}
{tiers.length > MAX_ICONS && ( {tiers.length > MAX_ICONS && (
<Text size="1"> <Text size="minor">
{literals(strings.common.units.plus, { {literals(strings.common.units.plus, {
value: tiers.length - MAX_ICONS, value: tiers.length - MAX_ICONS,
})} })}
</Text> </Text>
)} )}
</Flex> </Flex>
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -299,22 +288,20 @@ function NationsFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button color="gray" variant="surface"> <Flex>
<Flex> {nations.map((nation, index) => (
{nations.map((nation, index) => ( <img
<img key={nation}
key={nation} style={{
style={{ filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))",
filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))", marginLeft: index > 0 ? "-0.5em" : undefined,
marginLeft: index > 0 ? "-0.5em" : undefined, width: "1.25em",
width: "1.25em", height: "1.25em",
height: "1.25em", }}
}} src={alias("api", `/flags/circle/${nation}.webp`)}
src={alias("api", `/flags/circle/${nation}.webp`)} />
/> ))}
))} </Flex>
</Flex>
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -340,27 +327,9 @@ function NationsFilter() {
position: "relative", position: "relative",
}} }}
> >
<Box <div className={styles["nation-option"]}>
width="calc(100% + calc(4 * var(--space-2)))" <div className={styles.overlay} />
height="100%" </div>
position="absolute"
right="0"
mr="-2"
style={{
backgroundImage: `url(${alias("api", `/flags/scratched/${nation}.webp`)})`,
backgroundSize: "100%",
backgroundRepeat: "no-repeat",
backgroundPosition: "5rem center",
}}
>
<Box
width="100%"
height="100%"
style={{
background: `linear-gradient(90deg, var(--gray-2) 50%, transparent)`,
}}
/>
</Box>
<Text style={{ zIndex: 1 }}> <Text style={{ zIndex: 1 }}>
{ {
@@ -401,26 +370,24 @@ function ClassFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button color="gray" variant="surface"> <Flex>
<Flex> {classes.map((tankClass, index) => {
{classes.map((tankClass, index) => { const Icon = classIcons[tankClass];
const Icon = classIcons[tankClass]; return (
return ( <Icon
<Icon key={tankClass}
key={tankClass} style={{
style={{ color: "var(--gray-12)",
color: "var(--gray-12)", opacity: 1,
opacity: 1, filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))",
filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))", marginLeft: index > 0 ? "-0.5em" : undefined,
marginLeft: index > 0 ? "-0.5em" : undefined, width: "1.25em",
width: "1.25em", height: "1.25em",
height: "1.25em", }}
}} />
/> );
); })}
})} </Flex>
</Flex>
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -481,26 +448,24 @@ function GunTypeFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button color="gray" variant="surface"> <Flex>
<Flex> {gunTypes.map((gunType) => {
{gunTypes.map((gunType) => { const Icon = GUN_TYPE_ICONS[gunType];
const Icon = GUN_TYPE_ICONS[gunType];
return ( return (
<Icon <Icon
key={gunType} key={gunType}
style={{ style={{
margin: gunType === "regular" ? "0 -0.125em" : undefined, margin: gunType === "regular" ? "0 -0.125em" : undefined,
opacity: 1, opacity: 1,
color: "var(--gray-12)", color: "var(--gray-12)",
width: "1.25em", width: "1.25em",
height: "1.25em", height: "1.25em",
}} }}
/> />
); );
})} })}
</Flex> </Flex>
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -559,26 +524,24 @@ function TypeFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button color="gray" variant="surface"> <Flex gap="1">
<Flex gap="1"> {types.map((tankType) => {
{types.map((tankType) => { return (
return ( <ResearchedIcon
<ResearchedIcon style={{
style={{ color: `var(--${TANK_TYPE_COLORS[tankType]}-${
color: `var(--${TANK_TYPE_COLORS[tankType]}-${ tankType === TankType.TANK_TYPE_RESEARCHABLE ? "12" : "11"
tankType === TankType.TANK_TYPE_RESEARCHABLE ? "12" : "11" })`,
})`, filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))",
filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))", opacity: 1,
opacity: 1, width: "1.25em",
width: "1.25em", height: "1.25em",
height: "1.25em", }}
}} key={tankType}
key={tankType} />
/> );
); })}
})} </Flex>
</Flex>
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -660,33 +623,20 @@ function IndividualShellFilter({
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<IconButton {shells[index] === null && (
ml="-0.5px" <Text color="gray" style={{ display: "contents" }}>
variant="surface" <MissingShellIcon width="1em" height="1em" />
style={{ </Text>
borderTopLeftRadius: index === 0 ? undefined : 0, )}
borderBottomLeftRadius: index === 0 ? undefined : 0, {shells[index] !== null && (
borderTopRightRadius: index === 2 ? undefined : 0, <img
borderBottomRightRadius: index === 2 ? undefined : 0, style={{ width: "1em", height: "1em" }}
}} src={alias(
color="gray" "api",
highContrast `/icons/shells/${shellTypeIcons[shells[index]]}${premium ? "_premium" : ""}.webp`,
> )}
{shells[index] === null && ( />
<Text color="gray" style={{ display: "contents" }}> )}
<MissingShellIcon width="1em" height="1em" />
</Text>
)}
{shells[index] !== null && (
<img
style={{ width: "1em", height: "1em" }}
src={alias(
"api",
`/icons/shells/${shellTypeIcons[shells[index]]}${premium ? "_premium" : ""}.webp`,
)}
/>
)}
</IconButton>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -766,19 +716,19 @@ function OwnershipFilter() {
return wargaming ? ( return wargaming ? (
<OwnershipFilterInternal /> <OwnershipFilterInternal />
) : ( ) : (
<Tooltip content={strings.website.common.tank_search.login}> <Tooltip tooltip={strings.website.common.tank_search.login}>
<OwnershipFilterInternal /> <OwnershipFilterInternal />
</Tooltip> </Tooltip>
); );
} }
function OwnershipFilterInternal(props: FlexProps) { function OwnershipFilterInternal() {
const wargaming = App.use((state) => state.logins.wargaming); const wargaming = App.use((state) => state.logins.wargaming);
const showOwned = TankFilters.use((state) => state.showOwned); const showOwned = TankFilters.use((state) => state.showOwned);
const showUnowned = TankFilters.use((state) => state.showUnowned); const showUnowned = TankFilters.use((state) => state.showUnowned);
return ( return (
<Flex {...props}> <Flex>
<IconButton <IconButton
style={{ style={{
borderTopRightRadius: 0, borderTopRightRadius: 0,
@@ -876,31 +826,29 @@ function ConsumablesFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button color="gray" variant="surface"> <Flex>
<Flex> {consumables.slice(0, MAX_ICONS).map((consumable, index) => (
{consumables.slice(0, MAX_ICONS).map((consumable, index) => ( <img
<img key={consumable}
key={consumable} style={{
style={{ filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))",
filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))", marginLeft: index > 0 ? "-0.5em" : undefined,
marginLeft: index > 0 ? "-0.5em" : undefined, width: "1.25em",
width: "1.25em", height: "1.25em",
height: "1.25em", objectFit: "contain",
objectFit: "contain", }}
}} src={alias("api", `/icons/consumables/${consumable}.webp`)}
src={alias("api", `/icons/consumables/${consumable}.webp`)} />
/> ))}
))}
{consumables.length > MAX_ICONS && ( {consumables.length > MAX_ICONS && (
<Text size="1" ml="1"> <Text size="minor" className={styles["overflow-plus"]}>
{literals(strings.common.units.plus, { {literals(strings.common.units.plus, {
value: consumables.length - MAX_ICONS, value: consumables.length - MAX_ICONS,
})} })}
</Text> </Text>
)} )}
</Flex> </Flex>
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -970,31 +918,29 @@ function ProvisionsFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button color="gray" variant="surface"> <Flex>
<Flex> {provisions.slice(0, MAX_ICONS).map((provision, index) => (
{provisions.slice(0, MAX_ICONS).map((provision, index) => ( <img
<img key={provision}
key={provision} style={{
style={{ filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))",
filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))", marginLeft: index > 0 ? "-0.5em" : undefined,
marginLeft: index > 0 ? "-0.5em" : undefined, width: "1.25em",
width: "1.25em", height: "1.25em",
height: "1.25em", objectFit: "contain",
objectFit: "contain", }}
}} src={alias("api", `/icons/provisions/${provision}.webp`)}
src={alias("api", `/icons/provisions/${provision}.webp`)} />
/> ))}
))}
{provisions.length > MAX_ICONS && ( {provisions.length > MAX_ICONS && (
<Text size="1" ml="1"> <Text size="minor" className={styles["overflow-plus"]}>
{literals(strings.common.units.plus, { {literals(strings.common.units.plus, {
value: provisions.length - MAX_ICONS, value: provisions.length - MAX_ICONS,
})} })}
</Text> </Text>
)} )}
</Flex> </Flex>
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -1079,31 +1025,29 @@ function GameModeAbilitiesFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<Button color="gray" variant="surface"> <Flex>
<Flex> {icons.slice(0, MAX_ICONS).map((icon, index) => (
{icons.slice(0, MAX_ICONS).map((icon, index) => ( <img
<img key={icon}
key={icon} style={{
style={{ filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))",
filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))", marginLeft: index > 0 ? "-0.5em" : undefined,
marginLeft: index > 0 ? "-0.5em" : undefined, width: "1.25em",
width: "1.25em", height: "1.25em",
height: "1.25em", objectFit: "contain",
objectFit: "contain", }}
}} src={icon}
src={icon} />
/> ))}
))}
{icons.length > MAX_ICONS && ( {icons.length > MAX_ICONS && (
<Text size="1" ml="1"> <Text size="minor" className={styles["overflow-plus"]}>
{literals(strings.common.units.plus, { {literals(strings.common.units.plus, {
value: icons.length - MAX_ICONS, value: icons.length - MAX_ICONS,
})} })}
</Text> </Text>
)} )}
</Flex> </Flex>
</Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
@@ -0,0 +1,33 @@
.text {
font-size: var(--font-size-regular);
&[data-size="minor"] {
font-size: var(--font-size-minor);
}
&[data-size="major"] {
font-size: var(--font-size-major);
}
&[data-weight="light"] {
font-weight: var(--weight-light);
}
&[data-weight="regular"] {
font-weight: var(--weight-regular);
}
&[data-weight="medium"] {
font-weight: var(--weight-medium);
}
&[data-weight="bold"] {
font-weight: var(--weight-bold);
}
&[data-weight="black"] {
font-weight: var(--weight-black);
}
&[data-align="center"] {
text-align: center;
}
&[data-align="right"] {
text-align: right;
}
}
@@ -0,0 +1,45 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import type { ColorWithBW } from "../../ui/color";
import styles from "./index.module.css";
export interface TextProps extends ComponentProps<"span"> {
weight?: "light" | "regular" | "medium" | "bold" | "black";
lowContrast?: boolean;
size?: "regular" | "minor" | "major";
align?: "left" | "center" | "right";
color?: ColorWithBW;
}
export function Text({
lowContrast,
className,
size = "regular",
weight,
style,
align,
color = "gray",
...props
}: TextProps) {
const scale = color === "gray" && lowContrast ? "white" : color;
const isBW = color === "black" || color === "white";
let power: string | number = isBW ? "a12" : 12;
if (lowContrast) {
power = color === "gray" ? "a9" : isBW ? "a11" : 11;
}
return (
<span
className={classNames(styles.text, className)}
data-low-contrast={lowContrast}
data-size={size}
data-weight={weight}
data-align={align === "left" ? undefined : align}
style={{
color: `var(--${scale}-${power})`,
}}
{...props}
/>
);
}
@@ -0,0 +1,88 @@
.text-field {
display: flex;
align-items: center;
box-sizing: border-box;
gap: var(--space-3);
cursor: text;
font: inherit;
color: var(--gray-11);
&[data-variant="bubble"] {
border-radius: var(--max-size);
background-color: var(--gray-1);
outline: var(--outline-interactive);
input {
padding: var(--space-3) var(--space-4);
}
}
&[data-variant="form"] {
border-bottom: var(--space-1) solid var(--gray-6);
input {
padding: var(--space-2);
}
}
&[data-has-icon="true"] {
padding-left: var(--space-3);
input {
padding-left: 0;
}
}
&:focus-within {
outline: var(--outline-focus);
box-shadow: var(--shadow-focus);
}
&[data-disabled="true"] {
cursor: not-allowed;
background-color: var(--gray-3);
color: var(--gray-9);
input::placeholder {
color: var(--gray-6);
}
}
svg {
width: 1em;
height: 1em;
}
input {
min-width: 0;
flex: 1;
background: none;
border: none;
cursor: inherit;
font: inherit;
color: var(--gray-12);
&::placeholder {
color: var(--gray-9);
}
&:focus {
outline: none;
}
&[data-align="center"] {
text-align: center;
}
&[data-align="right"] {
text-align: right;
}
}
}
@@ -0,0 +1,75 @@
import {
forwardRef,
useCallback,
useImperativeHandle,
useRef,
type ChangeEvent,
type ComponentProps,
type ReactNode,
} from "react";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export interface TextFieldProps extends ComponentProps<"input"> {
children?: ReactNode;
align?: "left" | "center" | "right";
autoWidth?: boolean;
variant?: "bubble" | "form";
}
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
(
{
children,
className,
autoWidth,
placeholder,
align,
disabled,
value,
onChange,
variant = "bubble",
...props
},
ref,
) => {
const input = useRef<HTMLInputElement>(null);
const handleChange = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
if (autoWidth && input.current) {
input.current.style.width = `${event.target.value.length || event.target.placeholder.length}ch`;
}
onChange?.(event);
},
[onChange],
);
useImperativeHandle(ref, () => input.current!, []);
return (
<div
{...props}
className={classNames(styles["text-field"], className)}
data-has-icon={children !== undefined}
data-disabled={disabled}
data-variant={variant}
>
{children}
<input
data-align={align === "left" ? undefined : align}
disabled={disabled}
ref={input}
onChange={handleChange}
placeholder={placeholder}
value={value}
style={{
width: `${value?.toString().length || placeholder?.length || 0}ch`,
}}
/>
</div>
);
},
);
@@ -6,8 +6,8 @@ import { api } from "../../core/blitzkit/api";
import { filterTanks } from "../../core/blitzkit/filterTanks"; import { filterTanks } from "../../core/blitzkit/filterTanks";
import { TankFilters } from "../../stores/tankFilters"; import { TankFilters } from "../../stores/tankFilters";
import { TierList } from "../../stores/tierList"; import { TierList } from "../../stores/tierList";
import { SkeletonTankCard } from "../TankSearch/components/SkeletonTankCard"; import { TankCardWrapper } from "../TankCardWrapper";
import { TankCardWrapper } from "../TankSearch/components/TankCardWrapper"; import { TankCardSkeleton } from "../TankCardSkeleton";
import { TierListTile } from "./Tile"; import { TierListTile } from "./Tile";
const [tankDefinitions, gameDefinitions] = await Promise.all([ const [tankDefinitions, gameDefinitions] = await Promise.all([
@@ -45,7 +45,7 @@ export function TierListTiles() {
{times(Math.min(PREVIEW_COUNT, sorted.length - loadedTiles), (index) => { {times(Math.min(PREVIEW_COUNT, sorted.length - loadedTiles), (index) => {
return ( return (
<SkeletonTankCard <TankCardSkeleton
key={index} key={index}
onIntersection={() => { onIntersection={() => {
setLoadedTiles((state) => Math.min(state + 2, sorted.length)); setLoadedTiles((state) => Math.min(state + 2, sorted.length));
@@ -0,0 +1,94 @@
---
import type { Tool } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings";
import { Heading } from "./Heading";
interface Props {
locale: string;
tool: Tool;
}
const { tool, locale } = Astro.props;
const strings = getStrings(locale);
const toolStrings =
strings.website.tools[tool.id as keyof typeof strings.website.tools];
---
<style>
.tool-banner {
background-size: cover;
.content {
width: 100%;
height: 100%;
position: relative;
display: flex;
justify-content: center;
gap: var(--space-4);
padding: var(--space-5) var(--space-4);
box-sizing: border-box;
backdrop-filter: var(--blur-tint);
:root.light & {
backdrop-filter: var(--blur-tint) invert(1) hue-rotate(180deg);
}
@media (width > 40rem) {
padding: var(--space-6) var(--space-4);
}
.centered {
flex: 1;
max-width: var(--page-width);
display: flex;
flex-direction: column;
}
.pattern {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
:root.light & {
filter: invert(1) brightness(0);
}
mask-image: linear-gradient(
90deg,
transparent 25%,
var(--black-a1),
transparent
);
mask-repeat: no-repeat;
mask-size: cover;
}
}
}
</style>
<div
class="tool-banner"
style={{
backgroundImage: `url(/media/tools/banners/${tool.id}.webp)`,
backgroundPosition: tool.banner_background_position ?? "top",
}}
>
<div class="content">
<div
class="pattern"
style={{ backgroundImage: `url(/media/patterns/${tool.id}.svg)` }}
>
</div>
<div class="centered">
<Heading weight="bold" size="2">
{toolStrings.name}
</Heading>
</div>
</div>
</div>
+57 -82
View File
@@ -1,23 +1,16 @@
--- ---
import { CaretRightIcon } from "@radix-ui/react-icons";
import {
Box,
Button,
Flex,
Heading,
Text,
type ButtonProps,
} from "@radix-ui/themes";
import type { Tool } from "../constants/tools"; import type { Tool } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings"; import { getStrings } from "../core/i18n/getStrings";
import { Heading } from "./Heading";
import { LinkI18n } from "./LinkI18n"; import { LinkI18n } from "./LinkI18n";
interface Props { interface Props {
tool: Tool; tool: Tool;
locale: string; locale: string;
minor?: boolean;
} }
const { locale, tool } = Astro.props; const { locale, tool, minor } = Astro.props;
const strings = getStrings(locale); const strings = getStrings(locale);
const toolStrings = const toolStrings =
strings.website.tools[ strings.website.tools[
@@ -27,19 +20,20 @@ const toolStrings =
<style> <style>
.container { .container {
border-radius: var(--radius-2); flex: 1;
display: flex;
border-radius: var(--space-3);
background-size: cover; background-size: cover;
background-position: center; background-position: center;
height: 16rem;
position: relative;
overflow: hidden;
&[data-disabled="true"] { &[data-disabled="true"] {
opacity: 0.25; opacity: 0.25;
} }
&[data-significant="true"] {
width: 100%;
height: min(20rem, 50vh);
}
} }
.link { .link {
@@ -48,82 +42,63 @@ const toolStrings =
height: 100%; height: 100%;
flex-direction: column; flex-direction: column;
color: inherit; color: inherit;
.background {
flex: 1;
background-size: cover;
background-position: center;
}
.content {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: var(--space-5);
box-sizing: border-box;
backdrop-filter: blur(64px);
-webkit-backdrop-filter: blur(64px);
&[data-minor="true"] {
padding: var(--space-4);
}
.wrapper {
display: flex;
flex-direction: column;
justify-content: center;
}
}
} }
</style> </style>
<Flex <div
style={{ style={{ backgroundImage: `url(/assets/images/tools/${tool.id}.webp)` }}
backgroundImage: `url(/assets/images/tools/${tool.id}.webp)`, class="container"
}}
data-significant={tool.significant}
className="container"
position="relative"
overflow="hidden"
flexGrow={tool.significant ? undefined : "1"}
flexBasis={tool.significant ? undefined : { initial: undefined, sm: "0" }}
> >
<LinkI18n <LinkI18n
{locale} {locale}
className="link" className="link"
underline="none" underline="never"
href={tool.href ?? `/${tool.id}`} href={tool.href ?? `/${tool.id}`}
target={tool.href ? "_blank" : undefined} target={tool.href ? "_blank" : undefined}
> >
<Box <div
flexGrow="1" class="background"
style={{ style={{ backgroundImage: `url(/assets/images/tools/${tool.id}.webp)` }}
backgroundImage: `url(/assets/images/tools/${tool.id}.webp)`,
backgroundSize: "cover",
backgroundPosition: "center",
}}
/>
<Flex
px={{ initial: "6", md: tool.significant ? "8" : "6" }}
py={{ initial: "4", sm: tool.significant ? "6" : "4" }}
gap="4"
align="center"
justify="between"
width="100%"
direction={{ initial: "column", xs: "row" }}
style={{
backgroundColor: "var(--color-panel-translucent)",
backdropFilter: "blur(64px)",
WebkitBackdropFilter: "blur(64px)",
}}
> >
<Flex </div>
direction="column"
justify="center" <div class="content" data-minor={minor}>
align={{ initial: "center", xs: "start" }} <div class="wrapper">
> <Heading size={minor ? "3" : "2"} weight="medium">
<Heading
align={{ initial: "center", sm: "left" }}
size={{ initial: "6", sm: tool.significant ? "7" : "5" }}
weight="medium"
>
{toolStrings.name} {toolStrings.name}
</Heading> </Heading>
<Text </div>
align={{ initial: "center", sm: "left" }} </div>
size={{ initial: "3", sm: tool.significant ? "4" : "3" }}
color="gray"
>
{toolStrings.description}
</Text>
</Flex>
<Button
size={{
initial: undefined,
sm: tool.significant ? "3" : undefined,
}}
color={tool.button as ButtonProps["color"]}
style={{ cursor: "inherit" }}
>
{toolStrings.button}
<CaretRightIcon />
</Button>
</Flex>
</LinkI18n> </LinkI18n>
</Flex> </div>
@@ -0,0 +1,26 @@
---
interface Props {
major?: boolean;
}
const { major } = Astro.props;
---
<style>
.tool-card-layout-root {
display: flex;
flex-direction: column;
flex: 1;
gap: inherit;
&[data-major="true"] {
flex: 2;
}
}
</style>
<div class="tool-card-layout-root" data-major={major}>
<slot />
</div>
@@ -0,0 +1,25 @@
---
interface Props {
minor?: boolean;
}
const { minor } = Astro.props;
---
<style>
.tool-card-layout-root {
display: flex;
height: 30rem;
gap: var(--space-4);
&[data-minor="true"] {
height: 20rem;
}
}
</style>
<div class="tool-card-layout-root" data-minor={minor}>
<slot />
</div>
@@ -0,0 +1,28 @@
.tooltip {
position: relative;
.text {
display: none;
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
z-index: 1;
background-color: var(--gray-12);
color: var(--gray-1);
border-radius: var(--space-3);
padding: var(--space-2) var(--space-3);
margin-bottom: var(--space-3);
white-space: nowrap;
}
&:hover {
.text {
display: block;
}
}
}
@@ -0,0 +1,16 @@
import type { ReactNode } from "react";
import styles from "./index.module.css";
interface Props {
children: ReactNode;
tooltip: string;
}
export function Tooltip({ children, tooltip }: Props) {
return (
<div className={styles.tooltip}>
<div className={styles.text}>{tooltip}</div>
{children}
</div>
);
}
+36 -37
View File
@@ -1,77 +1,76 @@
import type { ButtonProps } from "@radix-ui/themes";
export interface Tool { export interface Tool {
id: string; id: string;
strings?: string;
button: ButtonProps["color"]; path?: string;
significant?: boolean;
disabled?: boolean;
href?: string; href?: string;
banner_background_position: "top" | "center" | "bottom";
} }
export const tools: Record<string, Tool> = { export const tools: Record<string, Tool> = {
tanks: { tanks: {
id: "tanks", id: "tanks",
strings: "tankopedia", banner_background_position: "top",
button: "purple",
significant: true,
}, },
players: { players: {
id: "players", id: "players",
disabled: true, banner_background_position: "top",
button: "blue",
}, },
compare: { compare: {
id: "compare", id: "compare",
button: "crimson", banner_background_position: "bottom",
}, },
performance: { performance: {
id: "performance", id: "performance",
button: "jade", banner_background_position: "bottom",
},
charts: {
id: "charts",
disabled: true,
button: "bronze",
}, },
playlist: { playlist: {
id: "playlist", id: "playlist",
button: "tomato", banner_background_position: "bottom",
}, },
mixer: { mixer: {
id: "mixer", id: "mixer",
button: "gray", banner_background_position: "bottom",
}, },
guess: { guesser: {
id: "guess", id: "guesser",
button: "cyan", banner_background_position: "bottom",
}, },
gallery: { avatars: {
id: "gallery", id: "avatars",
button: "gold", banner_background_position: "bottom",
},
backgrounds: {
id: "backgrounds",
banner_background_position: "bottom",
}, },
session: { session: {
id: "session", id: "session",
button: "blue", banner_background_position: "bottom",
}, },
tier_list: { tier_list: {
id: "tier-list", id: "tier_list",
strings: "tier_list", banner_background_position: "bottom",
button: "orange",
}, },
embed: { embed: {
id: "embed", id: "embed",
button: "red", banner_background_position: "bottom",
},
api: {
id: "api",
disabled: true,
button: "bronze",
}, },
more: { more: {
id: "more", id: "more",
href: "https://discord.gg/nDt7AjGJQH", href: "https://discord.gg/nDt7AjGJQH",
button: "plum", banner_background_position: "bottom",
},
api: {
id: "api",
banner_background_position: "bottom",
},
changelogs: {
id: "changelogs",
banner_background_position: "bottom",
},
settings: {
id: "changelogs",
banner_background_position: "center",
}, },
}; };
+1 -2
View File
@@ -1,7 +1,6 @@
import { STRINGS } from "@blitzkit/i18n"; import { STRINGS } from "@blitzkit/i18n";
import locales from "@blitzkit/i18n/locales.json";
export function getStrings(locale: string = locales.default) { export function getStrings(locale: string) {
if (locale in STRINGS) return STRINGS[locale]; if (locale in STRINGS) return STRINGS[locale];
throw new Error(`Unsupported locale: ${locale}`); throw new Error(`Unsupported locale: ${locale}`);
} }
+67 -35
View File
@@ -1,52 +1,84 @@
--- ---
import strings from "@blitzkit/i18n/strings/en.json"; import BaseMeta from "../components/BaseMeta.astro";
import "@fontsource/inter"; import BaseStyles from "../components/BaseStyles.astro";
import { Flex } from "@radix-ui/themes"; import ColorAlias from "../components/ColorAlias.astro";
import Analytics from "../components/Analytics.astro"; import ColorScale from "../components/ColorScale.astro";
import { BlitzKitTheme } from "../components/BlitzKitTheme"; import type { Color } from "../ui/color";
import { Checks } from "../components/Checks";
import EasterEggs from "../components/EasterEggs.astro";
import Footer from "../components/Footer.astro";
import LocaleRedirector from "../components/LocaleRedirector.astro";
import Meta from "../components/Meta.astro";
import Navbar from "../components/Navbar.astro";
import Servicing from "../components/Servicing.astro";
import "./base.css";
export interface Props { interface Props {
noFooter?: boolean;
noNavbar?: boolean;
integrated?: boolean;
locale: string; locale: string;
accent: Color;
} }
const servicing = import.meta.env.SERVICING; const { accent, locale } = Astro.props;
const { noFooter, noNavbar, integrated, locale } = Astro.props;
--- ---
<html lang={locale}> <html lang={locale} class="dark">
<head> <head>
<meta property="og:site_name" content={strings.common.name} /> <BaseMeta />
<Meta /> <ColorScale color="mauve" />
<Analytics /> <ColorScale color="mauve" alpha />
<LocaleRedirector /> <ColorAlias color="mauve" alias="gray" />
<EasterEggs /> <ColorAlias color="mauve" alpha alias="gray" />
<ColorScale color="black" alpha />
<ColorScale color="white" alpha />
<ColorScale color={accent} />
<ColorScale color={accent} alpha />
<ColorAlias color={accent} alias="accent" />
<ColorAlias color={accent} alpha alias="accent" />
<BaseStyles />
<style>
body {
margin: 0;
display: flex;
flex-direction: column;
min-height: 100dvh;
background-color: var(--gray-1);
color: var(--gray-12);
font-family: var(--font-family-regular);
.app {
display: flex;
flex: 1;
flex-direction: column;
background-color: var(--gray-1);
padding: var(--space-5);
gap: var(--space-6);
}
}
</style>
<script>
const root = document.documentElement;
const media = window.matchMedia("(prefers-color-scheme: dark)");
function applyTheme(e: MediaQueryList | MediaQueryListEvent) {
root.classList.toggle("dark", e.matches);
root.classList.toggle("light", !e.matches);
}
applyTheme(media);
media.addEventListener("change", applyTheme);
</script>
<slot name="head" /> <slot name="head" />
</head> </head>
<body class={noNavbar ? "no-navbar" : ""}> <body>
<BlitzKitTheme> <slot name="pre-app" />
<Flex direction="column" minHeight="100vh">
<Navbar {locale} {integrated} />
<Checks {locale} client:only="react" /> <div class="app">
<slot />
</div>
{servicing ? <Servicing /> : <slot />} <!-- <Footer {locale} /> -->
{!noFooter && <Footer {locale} />}
</Flex>
</BlitzKitTheme>
</body> </body>
</html> </html>
@@ -1,47 +0,0 @@
---
import { Box, Flex, Heading, Text } from "@radix-ui/themes";
import ToolOpenGraph from "../components/ToolOpenGraph.astro";
import type { Tool } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings";
import BaseLayout from "./BaseLayout.astro";
interface Props {
tool: Tool;
locale: string;
noNavbar?: boolean;
noFooter?: boolean;
}
const { tool, locale, noNavbar, noFooter } = Astro.props;
const strings = getStrings(locale);
const toolStrings =
strings.website.tools[
(tool.strings ?? tool.id) as keyof typeof strings.website.tools
];
---
<ToolOpenGraph {locale} {tool} />
<BaseLayout {locale} {noNavbar} {noFooter}>
<Box
style={{
backgroundImage: `url(/assets/images/tools/${tool.id}.webp)`,
backgroundSize: "cover",
}}
>
<Flex
direction="column"
align="center"
py="6"
style={{
backdropFilter: "blur(4rem)",
WebkitBackdropFilter: "blur(4rem)",
}}
>
<Heading size="7">{toolStrings.name}</Heading>
<Text>{toolStrings.description}</Text>
</Flex>
</Box>
<slot />
</BaseLayout>
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff. Show more