diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index 9d077301b..4ecf9071a 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -930,7 +930,10 @@ "description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!", "cancel": "Cancel", "reveal": "Reveal" - } + }, + "clear": "Clear", + "select_all": "Select all", + "tier": "Tier {tier}" }, "tankopedia": { diff --git a/packages/website/src/components/Guesser.tsx b/packages/website/src/components/Guesser.tsx index d8e8a0e6f..3600ee417 100644 --- a/packages/website/src/components/Guesser.tsx +++ b/packages/website/src/components/Guesser.tsx @@ -9,13 +9,17 @@ import { ArrowRightIcon, EyeOpenIcon, MagnifyingGlassIcon, + MixerVerticalIcon, PaperPlaneIcon, + StarFilledIcon, + TrashIcon, } from "@radix-ui/react-icons"; import { AlertDialog, Box, Button, Card, + DropdownMenu, Flex, IconButton, Spinner, @@ -23,7 +27,7 @@ import { TextField, } from "@radix-ui/themes"; import fuzzysort from "fuzzysort"; -import { debounce } from "lodash-es"; +import { debounce, times } from "lodash-es"; import { useCallback, useEffect, useRef, useState } from "react"; import { awaitableTankDefinitions } from "../core/awaitables/tankDefinitions"; import { awaitableTankNames } from "../core/awaitables/tankNames"; @@ -41,11 +45,7 @@ const [tankNames, tankDefinitions] = await Promise.all([ const ids = Object.keys(tankDefinitions.tanks); -interface GuesserProps { - selectedTiers: number[]; -} - -export function Guesser({ selectedTiers }: GuesserProps) { +export function Guesser() { const tank = Guess.use((state) => state.tank); const guessState = Guess.use((state) => state.guessState); const correctGuesses = Guess.use((state) => state.correctGuesses); @@ -57,6 +57,7 @@ export function Guesser({ selectedTiers }: GuesserProps) { const [searching, setSearching] = useState(false); const [results, setResults] = useState(null); const [selected, setSelected] = useState(null); + const tiers = Guess.use((state) => state.tiers); const requestSearch = useCallback(() => { setSelected(null); @@ -101,60 +102,60 @@ export function Guesser({ selectedTiers }: GuesserProps) { width="100%" p="4" maxWidth="25rem" - gap="4" + gap="3" > + {results !== null && ( + + + {results.length === 0 && ( + + + {strings.website.tools.guess.search.no_results} + + + )} - {results !== null && ( - - - {results.length === 0 && ( - - - {strings.website.tools.guess.search.no_results} - - - )} + + {results.map((result) => { + const Icon = classIcons[result.class]; - - {results.map((result) => { - const Icon = classIcons[result.class]; + return ( + { + if (!input.current) return; - return ( - { - if (!input.current) return; - - input.current.value = unwrap(result.name); - setSelected(result); - setResults(null); - }} - text={unwrap(result.name)} - prefix={ - - } - discriminator={ - - - {TIER_ROMAN_NUMERALS[result.tier]} - - } - /> - ); - })} - - - - )} + input.current.value = unwrap(result.name); + setSelected(result); + setResults(null); + }} + text={unwrap(result.name)} + prefix={ + + } + discriminator={ + + + {TIER_ROMAN_NUMERALS[result.tier]} + + } + /> + ); + })} + + + + )} + @@ -167,11 +168,75 @@ export function Guesser({ selectedTiers }: GuesserProps) { + + + + + + + + + {times(10, (index) => { + const tier = 10 - index; + const isSelected = tiers.includes(tier); + + return ( + { + event.preventDefault(); + + Guess.mutate((draft) => { + if (isSelected) { + draft.tiers = draft.tiers.filter((t) => t !== tier); + } else { + draft.tiers = [...draft.tiers, tier]; + } + }); + }} + > + {literals(strings.website.tools.guess.tier, { + tier: TIER_ROMAN_NUMERALS[tier], + })} + + ); + })} + + + + { + event.preventDefault(); + + Guess.mutate((draft) => { + draft.tiers = Guess.initial.tiers; + }); + }} + > + {strings.website.tools.guess.select_all} + + + { + event.preventDefault(); + + Guess.mutate((draft) => { + draft.tiers = []; + }); + }} + > + {strings.website.tools.guess.clear} + + + + { const tank = tankDefinitions.tanks[Number(id)]; - return selectedTiers.includes(tank.tier); + return tiers.includes(tank.tier); }); const id = Number( filteredIds[Math.floor(Math.random() * filteredIds.length)] @@ -283,7 +348,6 @@ export function Guesser({ selectedTiers }: GuesserProps) { )} - ); } diff --git a/packages/website/src/pages/[...locale]/guess/_index.tsx b/packages/website/src/pages/[...locale]/guess/_index.tsx index b572617ed..b549bd0bc 100644 --- a/packages/website/src/pages/[...locale]/guess/_index.tsx +++ b/packages/website/src/pages/[...locale]/guess/_index.tsx @@ -1,8 +1,5 @@ -import { Box, DropdownMenu, Flex, Heading, IconButton, Text } from "@radix-ui/themes"; -import { Suspense, useEffect, useState } from "react"; -import { MixerVerticalIcon } from "@radix-ui/react-icons"; -import { times } from "lodash-es"; -import { TIER_ROMAN_NUMERALS } from "@blitzkit/core"; +import { Box, Flex, Heading, Text } from "@radix-ui/themes"; +import { Suspense, useEffect } from "react"; import { GuessBackground } from "../../../components/GuessBackground"; import { Guesser } from "../../../components/Guesser"; import { GuessRenderer } from "../../../components/GuessRenderer"; @@ -58,26 +55,28 @@ function Container({ skeleton }: MaybeSkeletonComponentProps) { } function Content({ skeleton }: MaybeSkeletonComponentProps) { - const { unwrap, strings } = useLocale(); + const { unwrap } = useLocale(); const tank = Guess.use((state) => state.tank); const guessState = Guess.use((state) => state.guessState); const isRevealed = guessState !== GuessState.NotGuessed; const name = unwrap(tank.name); const fontSize = `min(48vh, ${55 / name.length}vw)`; const transitionDuration = isRevealed ? "2s" : undefined; - const [selectedTiers, setSelectedTiers] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + const tiers = Guess.use((state) => state.tiers); useEffect(() => { - if (selectedTiers.length === 0) return; + if (tiers.length === 0) return; const filteredIds = ids.filter((id) => { const tank = tankDefinitions.tanks[Number(id)]; - return selectedTiers.includes(tank.tier); + return tiers.includes(tank.tier); }); if (filteredIds.length === 0) return; - const id = Number(filteredIds[Math.floor(Math.random() * filteredIds.length)]); + const id = Number( + filteredIds[Math.floor(Math.random() * filteredIds.length)] + ); const newTank = tankDefinitions.tanks[id]; Guess.mutate((draft) => { @@ -85,72 +84,13 @@ function Content({ skeleton }: MaybeSkeletonComponentProps) { draft.guessState = GuessState.NotGuessed; draft.helpingReveal = false; }); - }, [selectedTiers]); + }, [tiers]); return ( - - - - - - - - - {times(10, (index) => { - const tier = 10 - index; - const isSelected = selectedTiers.includes(tier); - - return ( - { - event.preventDefault(); - setSelectedTiers((prev) => { - if (prev.includes(tier)) { - return prev.filter((t) => t !== tier); - } else { - return [...prev, tier]; - } - }); - }} - > - {TIER_ROMAN_NUMERALS[tier]} - - ); - })} - - - - setSelectedTiers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])} - > - Select All - - - setSelectedTiers([])} - > - Clear All - - - - - {selectedTiers.length === 0 && ( + {tiers.length === 0 && ( - + Select tier(s) to start playing @@ -216,7 +160,7 @@ function Content({ skeleton }: MaybeSkeletonComponentProps) { {name} - + ); } diff --git a/packages/website/src/stores/guess.ts b/packages/website/src/stores/guess.ts index 22d6a10f0..0a3e94f49 100644 --- a/packages/website/src/stores/guess.ts +++ b/packages/website/src/stores/guess.ts @@ -1,4 +1,5 @@ import type { TankDefinition } from "@blitzkit/core"; +import { times } from "lodash-es"; import { Varuna } from "varuna"; export enum GuessState { @@ -14,6 +15,7 @@ export interface Guess { correctGuesses: number; streak: number; helpingReveal: boolean; + tiers: number[]; } export const Guess = new Varuna((tank) => ({ @@ -23,4 +25,5 @@ export const Guess = new Varuna((tank) => ({ correctGuesses: 0, streak: 0, helpingReveal: false, + tiers: times(10, (index) => index + 1), }));