Compare commits

...
19 Commits
Author SHA1 Message Date
tresabhi 8d7575815b no results 2026-08-28 17:05:15 -05:00
tresabhi 4a0fccc526 tank search 2026-08-28 16:59:07 -05:00
tresabhi 5477616917 cleanup 2026-08-28 16:37:06 -05:00
tresabhi ba1f530de7 back button 2026-08-28 13:55:05 -05:00
tresabhi 1f1c9f26f1 tank search ui rebuilt... somewhat 2026-08-28 10:42:57 -05:00
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
124 changed files with 2304 additions and 1084 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=="],
+36 -23
View File
@@ -1,6 +1,6 @@
import { BlitzKitAPI } from "@blitzkit/core"; import { BlitzKitAPI } from "@blitzkit/core/src/blitzkit/api/base";
import locales from "@blitzkit/i18n/locales.json"; import locales from "@blitzkit/i18n/locales.json";
import { deburr } from "lodash-es"; import { deburr, times } from "lodash-es";
import { I18nString } from "../protos"; import { I18nString } from "../protos";
export async function fetchTankNames(api: BlitzKitAPI) { export async function fetchTankNames(api: BlitzKitAPI) {
@@ -12,40 +12,53 @@ export async function fetchTankNames(api: BlitzKitAPI) {
return await Promise.all( return await Promise.all(
tankDefinitionsArray.map(async (tank) => { tankDefinitionsArray.map(async (tank) => {
const searchableNameDeburr: I18nString = { locales: {} }; const name_deburr: I18nString = I18nString.create();
const camouflages_deburr: I18nString[] = [];
const camouflages = tank.camouflages.map(
(id) => camouflageDefinitions.camouflages[id].name!,
);
Object.entries(tank.name!).forEach(([key, value]) => { Object.entries(tank.name!).forEach(([key, value]) => {
searchableNameDeburr.locales[key] = deburr(value); name_deburr.locales[key] = deburr(value);
});
camouflages.forEach((camouflage, index) => {
camouflages_deburr[index] = I18nString.create();
Object.entries(camouflage).forEach(([key, value]) => {
camouflages_deburr[index].locales[key] = deburr(value);
});
}); });
return { return {
id: tank.id, id: tank.id,
name: tank.name, slug: tank.slug,
searchableName: tank.name, dev_name: tank.dev_name,
searchableNameDeburr,
camouflages: tank.camouflages name: tank.name!,
?.map((id) => name_deburr,
locales.supported.map(
({ locale }) => camouflages,
camouflageDefinitions.camouflages[id]?.name!.locales[locale], camouflages_deburr,
),
)
.flat()
.filter(Boolean)
.map(deburr)
.join(" "),
treeType: tank.type,
}; };
}), }),
); );
} }
export const SEARCH_KEYS = [ export const SEARCH_KEYS = [
"id",
"slug",
"dev_name",
...locales.supported ...locales.supported
.map(({ locale }) => [ .map(({ locale }) => [
`searchableName.locales.${locale}`, `name.locales.${locale}`,
`searchableNameDeburr.locales.${locale}`, `name_deburr.locales.${locale}`,
...times(8, (index) => [
`camouflages.${index}.locales.${locale}`,
`camouflages_deburr.${index}.locales.${locale}`,
]),
]) ])
.flat(), .flat(2),
"camouflages",
]; ];
+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,3 @@
.back {
display: contents;
}
@@ -0,0 +1,21 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
interface Props extends ComponentProps<"div"> {}
export function Back({ className, onClick, ...props }: Props) {
console.log("init");
return (
<div
className={classNames(styles.back, className)}
onClick={(event) => {
console.log("back");
window.history.back();
onClick?.(event);
}}
{...props}
/>
);
}
@@ -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,87 @@
.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.8em;
color: var(--gray-1);
font-weight: var(--weight-medium);
cursor: pointer;
&[data-size="minor"] {
font-size: 0.7em;
padding: var(--space-2) var(--space-3);
}
&[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-a3);
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>
@@ -0,0 +1,2 @@
.Trigger {
}
@@ -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,64 @@
.flex {
display: flex;
&[data-column="true"] {
flex-direction: column;
}
&[data-wrap="true"] {
flex-wrap: wrap;
}
&[data-justify="start"] {
justify-content: flex-start;
}
&[data-justify="center"] {
justify-content: center;
}
&[data-justify="end"] {
justify-content: flex-end;
}
&[data-justify="between"] {
justify-content: space-between;
}
&[data-align="start"] {
align-items: flex-start;
}
&[data-align="center"] {
align-items: center;
}
&[data-align="end"] {
align-items: flex-end;
}
&[data-gap="0"] {
gap: var(--space-0);
}
&[data-gap="1"] {
gap: var(--space-1);
}
&[data-gap="2"] {
gap: var(--space-2);
}
&[data-gap="3"] {
gap: var(--space-3);
}
&[data-gap="4"] {
gap: var(--space-4);
}
&[data-gap="5"] {
gap: var(--space-5);
}
&[data-gap="6"] {
gap: var(--space-6);
}
&[data-gap="7"] {
gap: var(--space-7);
}
&[data-gap="8"] {
gap: var(--space-8);
}
&[data-gap="9"] {
gap: var(--space-9);
}
}
@@ -0,0 +1,39 @@
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"> {
column?: boolean;
wrap?: boolean;
align?: "start" | "center" | "end";
justify?: "start" | "center" | "end" | "between";
gap?: Space;
}
export function Flex({
children,
column,
className,
gap,
justify,
align,
wrap,
...props
}: Props) {
return (
<div
{...props}
className={classNames(styles.flex, className)}
data-column={column}
data-wrap={wrap}
data-gap={gap}
data-justify={justify}
data-align={align}
>
{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,27 @@
.link {
text-decoration-color: currentColor;
cursor: pointer;
display: inline;
align-items: center;
gap: var(--space-3);
&[data-underline="always"] {
text-decoration: underline;
}
&[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}
/>
); );
} }
@@ -0,0 +1,3 @@
.wrapper {
display: contents;
}
@@ -0,0 +1,21 @@
import locales from "@blitzkit/i18n/locales.json";
import { LinkWrapper, type LinkWrapperProps } from "../LinkWrapper";
import styles from "./index.module.css";
export interface LinkI18nWrapperProps extends LinkWrapperProps {
locale: string;
}
export function LinkI18nWrapper({
locale,
href,
...props
}: LinkI18nWrapperProps) {
return (
<LinkWrapper
className={styles.wrapper}
href={`${locale === locales.default ? "" : `/${locale}`}${href}`}
{...props}
/>
);
}
@@ -0,0 +1,3 @@
.wrapper {
display: contents;
}
@@ -0,0 +1,9 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export interface LinkWrapperProps extends ComponentProps<"a"> {}
export function LinkWrapper({ className, ...props }: LinkWrapperProps) {
return <a className={classNames(styles.wrapper, className)} {...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,8 @@
.recent {
margin-top: var(--space-4);
padding: var(--space-4);
background-color: var(--gray-a2);
border-radius: var(--space-3);
}
@@ -1,17 +1,19 @@
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 { 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,17 +37,16 @@ export function RecentlyViewed() {
} }
return ( return (
<Flex direction="column" gap="2" mt="2" mb="6"> <Flex column gap="4" className={styles.recent}>
<Text color="gray" align="center"> <Text color="gray" lowContrast>
{strings.website.common.tank_search.recent} {strings.website.common.tank_search.recent}
</Text> </Text>
<TankCardWrapper>
<TankCardWrapper compact>
{recentlyViewed.map((id) => ( {recentlyViewed.map((id) => (
<TankCard tank={tankDefinitions.tanks[id]} key={id} /> <TankCard compact tank={tankDefinitions.tanks[id]} key={id} />
))} ))}
</TankCardWrapper> </TankCardWrapper>
<Separator size="4" />
</Flex> </Flex>
); );
} }
@@ -0,0 +1,18 @@
.section {
display: flex;
justify-content: center;
&:last-child {
flex: 1;
}
.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,43 +0,0 @@
.tank-search-card {
user-select: none;
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-2);
background-position: top left;
background-size: contain;
background-repeat: no-repeat;
overflow: hidden;
}
.tank-search-card[data-provide-link='true'] {
cursor: pointer;
}
.tank-search-card .link {
width: 100%;
display: flex;
flex-direction: column;
color: inherit;
}
.tank-search-card .image {
width: 100%;
height: 8rem;
object-position: center right;
object-fit: contain;
filter: drop-shadow(-1px -1px 4px black);
}
.tank-search-card .class-icon {
width: 1em;
height: 1em;
min-width: 1em;
min-height: 1em;
}
.tank-search-card .name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
@@ -0,0 +1,43 @@
.wrapper {
--image-height: 6rem;
&[data-compact="true"] {
--image-height: 4rem;
.image-wrapper {
background-size: auto 75%;
}
}
.image-wrapper {
overflow: hidden;
box-sizing: border-box;
background-size: auto 100%;
background-repeat: no-repeat;
height: var(--image-height);
}
.name {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-2);
.icon {
width: 1em;
height: 1em;
min-width: 1em;
min-height: 1em;
}
.text {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
}
@@ -1,118 +1,99 @@
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 { 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 { LinkI18n } from "../LinkI18n"; import { Flex } from "../Flex";
import { LinkI18nWrapper } from "../LinkI18nWrapper";
import { MAX_RECENTLY_VIEWED } from "../TankSearch/constants"; import { MAX_RECENTLY_VIEWED } from "../TankSearch/constants";
import "./index.css"; import { Text, type TextProps } from "../Text";
import styles from "./index.module.css";
type TankCardProps = TextProps & { type TankCardProps = {
tank: TankDefinition; tank: TankDefinition;
onTankSelect?: (tank: TankDefinition) => void; onTankSelect?: (tank: TankDefinition) => void;
discriminator?: ReactNode; discriminator?: ReactNode;
noLink?: boolean; noLink?: boolean;
compact?: boolean;
}; };
const tankDefinitions = await api.tankDefinitions(); const tankDefinitions = await api.tankDefinitions();
export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>( export const TankCard = ({
( tank,
{ discriminator,
tank, onTankSelect: onSelect,
discriminator, noLink,
onTankSelect: onSelect, compact,
noLink, }: TankCardProps) => {
style, const { unwrap, locale } = useLocale();
...props
}: TankCardProps,
ref,
) => {
const { unwrap, locale } = useLocale();
const provideLink = !noLink && onSelect === undefined;
const Icon = classIcons[tank.class]; const provideLink = !noLink && onSelect === undefined;
const name = unwrap(tank.name!);
return ( const color: TextProps["color"] =
<Text tank.type === TankType.TANK_TYPE_COLLECTOR
ref={ref} ? "blue"
tabIndex={onSelect ? 0 : undefined} : tank.type === TankType.TANK_TYPE_PREMIUM
size="2" ? "amber"
color={ : "gray";
tank.type === TankType.TANK_TYPE_COLLECTOR const lowContrast = tank.type !== TankType.TANK_TYPE_RESEARCHABLE;
? "blue"
: tank.type === TankType.TANK_TYPE_PREMIUM const Icon = classIcons[tank.class];
? "amber"
: "gray" const content = (
} <Flex
highContrast={tank.type === TankType.TANK_TYPE_RESEARCHABLE} className={styles.wrapper}
onClick={() => { data-compact={compact}
onSelect?.(tank); column
TankopediaPersistent.mutate((draft) => { gap="3"
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed]) onClick={() => {
.filter((id) => id in tankDefinitions.tanks) onSelect?.(tank);
.slice(0, MAX_RECENTLY_VIEWED); TankopediaPersistent.mutate((draft) => {
}); draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
}} .filter((id) => id in tankDefinitions.tanks)
className="tank-search-card" .slice(0, MAX_RECENTLY_VIEWED);
data-provide-link={provideLink} });
}}
>
<Flex
justify="end"
className={styles["image-wrapper"]}
style={{ style={{
backgroundImage: `url(${alias( backgroundImage: `url(${alias(
"api", "api",
`/flags/scratched/${tank.nation}.webp`, `/flags/scratched/${tank.nation}.webp`,
)})`, )})`,
...style,
}} }}
{...props}
> >
<LinkI18n <img
locale={locale} alt={name}
className="link" src={alias("api", `/tanks/${tank.id}/icons/big.webp`)}
underline="hover" />
href={provideLink ? `/tanks/${tank.slug}` : "#"} </Flex>
onClick={(event) => {
if (!provideLink) event.preventDefault();
}}
>
<img
alt={unwrap(tank.name!)}
src={alias("api", `/tanks/${tank.id}/icons/big.webp`)}
className="image"
draggable={false}
/>
<Flex <Text className={styles.name} color={color} lowContrast={lowContrast}>
justify="center" <Icon className={styles.icon} />
gap="1" <span className={styles.text}>{name}</span>
align="center"
overflow="hidden"
width="100%"
mt="1"
>
<Icon className="class-icon" />
<Text align="center" className="name">
{unwrap(tank.name!)}
</Text>
</Flex>
{discriminator && (
<Text
color="gray"
align="center"
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{discriminator}
</Text>
)}
</LinkI18n>
</Text> </Text>
{discriminator && (
<Text lowContrast align="center">
{discriminator}
</Text>
)}
</Flex>
);
if (provideLink) {
return (
<LinkI18nWrapper locale={locale} href={`/tanks/${tank.slug}`}>
{content}
</LinkI18nWrapper>
); );
}, }
);
return content;
};
@@ -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,13 @@
.wrapper {
--min-size: 12rem;
display: grid;
gap: var(--space-5) var(--space-4);
grid-template-columns: repeat(auto-fill, minmax(var(--min-size), 1fr));
&[data-compact="true"] {
--min-size: 7rem;
gap: var(--space-4);
}
}
@@ -0,0 +1,17 @@
import type { ComponentProps } from "react";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
interface Props extends ComponentProps<"div"> {
compact?: boolean;
}
export function TankCardWrapper({ className, compact, ...props }: Props) {
return (
<div
className={classNames(styles.wrapper, className)}
data-compact={compact}
{...props}
/>
);
}
@@ -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,86 +0,0 @@
import type { TankDefinition } from "@blitzkit/core";
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
import { Flex, Spinner, TextField } from "@radix-ui/themes";
import { debounce } from "lodash-es";
import { type KeyboardEventHandler, useCallback, useRef } from "react";
import { useLocale } from "../../../hooks/useLocale";
import { TankFilters } from "../../../stores/tankFilters";
import type { MaybeSkeletonComponentProps } from "../../../types/maybeSkeletonComponentProps";
import { QuickLink } from "./QuickLink";
import { Sort } from "./Sort";
type SearchBarProps = MaybeSkeletonComponentProps & {
topResult?: TankDefinition;
onSelect?: (tank: TankDefinition) => void;
};
export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) {
const { strings } = useLocale();
const search = TankFilters.use((state) => state.search);
const searching = TankFilters.use((state) => state.searching);
const input = useRef<HTMLInputElement>(null);
const performSearch = useCallback(
debounce(() => {
TankFilters.mutate((draft) => {
draft.searching = false;
});
if (!input.current) return;
const sanitized = input.current.value.trim();
TankFilters.mutate((draft) => {
draft.search = sanitized.length === 0 ? null : sanitized;
});
}, 500),
[]
);
const handleChange = useCallback(() => {
if (!searching) {
TankFilters.mutate((draft) => {
draft.searching = true;
});
}
performSearch();
}, [searching]);
const handleKeyDown = useCallback<KeyboardEventHandler>(
(event) => {
if (event.key !== "Enter" || !topResult || searching) return;
event.preventDefault();
if (onSelect) {
onSelect(topResult);
} else {
window.location.href = `/tanks/${topResult.slug}`;
}
},
[topResult]
);
return (
<Flex justify="center">
<Flex gap="2" flexGrow="1">
<TextField.Root
variant="classic"
disabled={skeleton}
defaultValue={search ?? undefined}
style={{ flex: 1 }}
ref={input}
placeholder={strings.website.common.tank_search.search_bar_hint}
onChange={handleChange}
onKeyDown={handleKeyDown}
>
<TextField.Slot>
{searching ? <Spinner /> : <MagnifyingGlassIcon />}
</TextField.Slot>
<QuickLink topResult={topResult} />
</TextField.Root>
<Sort />
</Flex>
</Flex>
);
}
@@ -1,11 +1,12 @@
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 { Button } from "../../Button";
import { DropdownMenu } from "../../DropdownMenu";
interface ItemProps { interface ItemProps {
by: TankopediaSortBy; by: TankopediaSortBy;
@@ -38,8 +39,8 @@ export function Sort() {
const { strings } = useLocale(); const { strings } = useLocale();
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button variant="surface" color="gray"> <Button variant="surface" color="gray">
{strings.website.common.tank_search.sort_dropdown.label} {strings.website.common.tank_search.sort_dropdown.label}
<CaretDownIcon /> <CaretDownIcon />
@@ -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,17 @@
.container {
flex: 1;
.label {
margin: var(--space-4) 0;
/* mt="2" gap="1" align="center" justify="center" direction="column" */
.count {
/* gap="2" */
}
}
.test-warning {
/* justify="center" mt="4" */
}
}
@@ -7,7 +7,6 @@ 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 } from "react";
@@ -23,22 +22,26 @@ 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 { Flex } from "../Flex";
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 { TankSearchNoResults } from "../TankSearchNoResults";
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 { 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"> & { compact?: boolean;
compact?: boolean; onSelect?: (tank: TankDefinition) => void;
onSelect?: (tank: TankDefinition) => void; onSelectAll?: (tanks: TankDefinition[]) => void;
onSelectAll?: (tanks: TankDefinition[]) => void; };
};
const PREVIEW_COUNT = 20; const PREVIEW_COUNT = 20;
const DEFAULT_LOADED_CARDS = 64; const DEFAULT_LOADED_CARDS = 64;
@@ -52,7 +55,7 @@ const [gameDefinitions, modelDefinitions, tankDefinitions, tankNames] =
]); ]);
export const TankSearch = memo<TankSearchProps>( export const TankSearch = memo<TankSearchProps>(
({ compact, onSelect, onSelectAll, skeleton, ...props }) => { ({ compact, onSelect, onSelectAll, skeleton }) => {
const { strings, locale } = useLocale(); const { strings, locale } = useLocale();
const wargaming = App.use((state) => state.logins.wargaming); const wargaming = App.use((state) => state.logins.wargaming);
const awaitedTanksDefinitionsArray = Object.values(tankDefinitions.tanks); const awaitedTanksDefinitionsArray = Object.values(tankDefinitions.tanks);
@@ -70,9 +73,7 @@ export const TankSearch = memo<TankSearchProps>(
} else { } else {
return Promise.resolve( return Promise.resolve(
fuzzysort fuzzysort
.go(tankFilters.search, tankNames, { .go(tankFilters.search, tankNames, { keys: SEARCH_KEYS })
keys: SEARCH_KEYS,
})
.map((result) => tankDefinitions.tanks[result.obj.id]), .map((result) => tankDefinitions.tanks[result.obj.id]),
); );
} }
@@ -427,78 +428,76 @@ export const TankSearch = memo<TankSearchProps>(
}, [tankFilters, tankopediaSort]); }, [tankFilters, tankopediaSort]);
return ( return (
<Flex direction="column" gap="2" flexGrow="1" {...props}> <Flex className={styles.container} column gap="4">
<SearchBar <TankSearchBar
skeleton={skeleton} skeleton={skeleton}
topResult={tanks?.[0]} topResult={tanks?.[0]}
onSelect={onSelect} onSelect={onSelect}
/> />
{!tankFilters.search && !tankFilters.searching && <FilterControl />} {!tankFilters.search && <TankSearchFilters />}
{!skeleton && !compact && <RecentlyViewed />} {!skeleton && !compact && <RecentlyViewedTanks />}
<Flex mt="2" gap="1" align="center" justify="center" direction="column"> {tanks.length > 0 && (
<Flex gap="2"> <Flex justify="center" className={styles.label}>
<Text color="gray"> <div className={styles.count}>
{sorted.length === 1 <Text lowContrast>
? strings.website.common.tank_search.count_singular {sorted.length === 1
: literals(strings.website.common.tank_search.count_plural, { ? strings.website.common.tank_search.count_singular
count: sorted.length.toLocaleString(locale), : literals(strings.website.common.tank_search.count_plural, {
})} count: sorted.length.toLocaleString(locale),
</Text> })}
</Text>
{onSelectAll && ( {onSelectAll && (
<Link <Link
underline="always" underline="always"
href="#" href="#"
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
onSelectAll(sorted); onSelectAll(sorted);
TankopediaPersistent.mutate((draft) => { TankopediaPersistent.mutate((draft) => {
draft.recentlyViewed = uniq([ draft.recentlyViewed = uniq([
...sorted.map(({ id }) => id), ...sorted.map(({ id }) => id),
...draft.recentlyViewed, ...draft.recentlyViewed,
]) ])
.filter((id) => id in tankDefinitions.tanks) .filter((id) => id in tankDefinitions.tanks)
.slice(0, MAX_RECENTLY_VIEWED); .slice(0, MAX_RECENTLY_VIEWED);
}); });
}} }}
> >
{strings.website.common.tank_search.select_all} {strings.website.common.tank_search.select_all}
</Link> </Link>
)}
</div>
{tankopediaSort.by !== "meta.none" && (
<Text color="gray">
{literals(strings.website.common.tank_search.sorting_by, {
name: strings.website.common.tank_search.sort[
tankopediaSort.by
],
})}
{SORT_UNITS[tankopediaSort.by] === undefined
? ""
: ` (${SORT_UNITS[tankopediaSort.by]})`}
, {tankopediaSort.direction}
</Text>
)} )}
</Flex> </Flex>
{tankopediaSort.by !== "meta.none" && (
<Text color="gray">
{literals(strings.website.common.tank_search.sorting_by, {
name: strings.website.common.tank_search.sort[
tankopediaSort.by
],
})}
{SORT_UNITS[tankopediaSort.by] === undefined
? ""
: ` (${SORT_UNITS[tankopediaSort.by]})`}
, {tankopediaSort.direction}
</Text>
)}
</Flex>
{tankFilters.showTesting && !tankFilters.showNonTesting && (
<Flex justify="center" mt="4">
<Callout.Root color="amber">
<Callout.Icon>
<ExperimentIcon style={{ width: "1em", height: "1em" }} />
</Callout.Icon>
<Callout.Text>
{strings.website.common.warnings.test}
</Callout.Text>
</Callout.Root>
</Flex>
)} )}
{!skeleton && !tankFilters.searching && ( {tankFilters.showTesting && !tankFilters.showNonTesting && (
<div className={styles["test-warning"]}>
<Callout color="amber">
<ExperimentIcon style={{ width: "1em", height: "1em" }} />
{strings.website.common.warnings.test}
</Callout>
</div>
)}
{!skeleton && (
<> <>
{tanks.length > 0 && ( {tanks.length > 0 && (
<TankCardWrapper> <TankCardWrapper>
@@ -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) =>
@@ -528,22 +527,9 @@ export const TankSearch = memo<TankSearchProps>(
</TankCardWrapper> </TankCardWrapper>
)} )}
{tanks.length === 0 && <NoResults type="search" />} {tanks.length === 0 && <TankSearchNoResults type="search" />}
</> </>
)} )}
{(skeleton || tankFilters.searching) && (
<TankCardWrapper>
{times(
Math.round(
skeleton ? DEFAULT_LOADED_CARDS : 10 + 10 * Math.random(),
),
(index) => (
<SkeletonTankCard key={index} />
),
)}
</TankCardWrapper>
)}
</Flex> </Flex>
); );
}, },
Whitespace-only changes.
@@ -0,0 +1,65 @@
import type { TankDefinition } from "@blitzkit/core";
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
import { type KeyboardEventHandler, useCallback, useRef } from "react";
import { useLocale } from "../../hooks/useLocale";
import { TankFilters } from "../../stores/tankFilters";
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
import { Flex } from "../Flex";
import { Sort } from "../TankSearch/components/Sort";
import { TextField } from "../TextField";
type SearchBarProps = MaybeSkeletonComponentProps & {
topResult?: TankDefinition;
onSelect?: (tank: TankDefinition) => void;
};
export function TankSearchBar({
topResult,
skeleton,
onSelect,
}: SearchBarProps) {
const { strings } = useLocale();
const search = TankFilters.use((state) => state.search);
const input = useRef<HTMLInputElement>(null);
const handleChange = useCallback(() => {
if (!input.current) return;
const sanitized = input.current.value.trim();
TankFilters.mutate((draft) => {
draft.search = sanitized.length === 0 ? null : sanitized;
});
}, []);
const handleKeyDown = useCallback<KeyboardEventHandler>(
(event) => {
if (event.key !== "Enter" || !topResult) return;
event.preventDefault();
if (onSelect) {
onSelect(topResult);
} else {
window.location.href = `/tanks/${topResult.slug}`;
}
},
[topResult],
);
return (
<Flex gap="3">
<TextField
disabled={skeleton}
defaultValue={search ?? undefined}
style={{ flex: 1 }}
ref={input}
placeholder={strings.website.common.tank_search.search_bar_hint}
onChange={handleChange}
onKeyDown={handleKeyDown}
>
<MagnifyingGlassIcon />
</TextField>
<Sort />
</Flex>
);
}
@@ -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,27 @@ 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 { Button } from "../Button";
import { GunAutoloaderIcon } from "../../GunAutoloaderIcon"; import { classIcons } from "../ClassIcon";
import { GunAutoreloaderIcon } from "../../GunAutoreloaderIcon"; import { DropdownMenu } from "../DropdownMenu";
import { GunRegularIcon } from "../../GunRegularIcon"; import { Flex } from "../Flex";
import { MissingShellIcon } from "../../MissingShellIcon"; import { GunAutoloaderIcon } from "../GunAutoloaderIcon";
import { ResearchedIcon } from "../../ResearchedIcon"; import { GunAutoreloaderIcon } from "../GunAutoreloaderIcon";
import { ScienceIcon } from "../../ScienceIcon"; import { GunRegularIcon } from "../GunRegularIcon";
import { ScienceOffIcon } from "../../ScienceOffIcon"; import { IconButton } from "../IconButton";
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 +172,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 <Flex gap="3" wrap>
align="center"
justify={{ initial: "start", md: "center" }}
gap="2"
wrap="wrap"
>
<TiersFilter /> <TiersFilter />
<ClassFilter /> <ClassFilter />
<TypeFilter /> <TypeFilter />
@@ -223,17 +215,17 @@ function TiersFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button color="gray" variant="surface"> <Button size="minor" 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="1" key={tier}> <Text size="minor" 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,
})} })}
@@ -298,8 +290,8 @@ function NationsFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button color="gray" variant="surface"> <Button size="minor" color="gray" variant="surface">
<Flex> <Flex>
{nations.map((nation, index) => ( {nations.map((nation, index) => (
<img <img
@@ -340,27 +332,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 }}>
{ {
@@ -400,8 +374,8 @@ function ClassFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button color="gray" variant="surface"> <Button size="minor" color="gray" variant="surface">
<Flex> <Flex>
{classes.map((tankClass, index) => { {classes.map((tankClass, index) => {
const Icon = classIcons[tankClass]; const Icon = classIcons[tankClass];
@@ -480,8 +454,8 @@ function GunTypeFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button color="gray" variant="surface"> <Button size="minor" color="gray" variant="surface">
<Flex> <Flex>
{gunTypes.map((gunType) => { {gunTypes.map((gunType) => {
const Icon = GUN_TYPE_ICONS[gunType]; const Icon = GUN_TYPE_ICONS[gunType];
@@ -558,8 +532,8 @@ function TypeFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button color="gray" variant="surface"> <Button size="minor" color="gray" variant="surface">
<Flex gap="1"> <Flex gap="1">
{types.map((tankType) => { {types.map((tankType) => {
return ( return (
@@ -659,9 +633,9 @@ function IndividualShellFilter({
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<IconButton <IconButton
ml="-0.5px" size="minor"
variant="surface" variant="surface"
style={{ style={{
borderTopLeftRadius: index === 0 ? undefined : 0, borderTopLeftRadius: index === 0 ? undefined : 0,
@@ -766,19 +740,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,
@@ -875,8 +849,8 @@ function ConsumablesFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button color="gray" variant="surface"> <Button size="minor" color="gray" variant="surface">
<Flex> <Flex>
{consumables.slice(0, MAX_ICONS).map((consumable, index) => ( {consumables.slice(0, MAX_ICONS).map((consumable, index) => (
<img <img
@@ -893,7 +867,7 @@ function ConsumablesFilter() {
))} ))}
{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,
})} })}
@@ -969,8 +943,8 @@ function ProvisionsFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button color="gray" variant="surface"> <Button size="minor" color="gray" variant="surface">
<Flex> <Flex>
{provisions.slice(0, MAX_ICONS).map((provision, index) => ( {provisions.slice(0, MAX_ICONS).map((provision, index) => (
<img <img
@@ -987,7 +961,7 @@ function ProvisionsFilter() {
))} ))}
{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,
})} })}
@@ -1078,8 +1052,8 @@ function GameModeAbilitiesFilter() {
return ( return (
<DropdownMenu.Root modal={false}> <DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>
<Button color="gray" variant="surface"> <Button size="minor" color="gray" variant="surface">
<Flex> <Flex>
{icons.slice(0, MAX_ICONS).map((icon, index) => ( {icons.slice(0, MAX_ICONS).map((icon, index) => (
<img <img
@@ -1096,7 +1070,7 @@ function GameModeAbilitiesFilter() {
))} ))}
{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,
})} })}
@@ -0,0 +1,3 @@
.no-results {
flex: 1;
}
@@ -1,20 +1,22 @@
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"; import { Flex } from "../Flex";
import { Link } from "../Link";
import { Text } from "../Text";
import styles from "./index.module.css";
interface NoResultsProps { interface NoResultsProps {
type?: "filters" | "search"; type?: "filters" | "search";
} }
export function NoResults({ type = "filters" }: NoResultsProps) { export function TankSearchNoResults({ type = "filters" }: NoResultsProps) {
const { strings } = useLocale(); const { strings } = useLocale();
return ( return (
<Flex flexGrow="1" align="center" justify="center"> <Flex className={styles["no-results"]} align="center" justify="center">
<Text color="gray"> <Text lowContrast>
{strings.website.common.tank_search.no_tanks_found.body}{" "} {strings.website.common.tank_search.no_tanks_found.body}{" "}
<Link <Link
href="#"
underline="always" underline="always"
color="red" color="red"
onClick={() => { onClick={() => {
@@ -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));
Loaded 100 of 124 files, more files were not shown because too many files have changed in this diff. Show more