feat: translate tank search

This commit is contained in:
tresabhi committed 2025-01-07 13:50:06 -06:00
1 parent c7856364ad
commit 5a65fee1d1
9 files changed
+231 -355

No files matched your search

@@ -4,6 +4,7 @@ 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 { QuickLink } from './QuickLink';
import { Sort } from './Sort';
@@ -14,6 +15,7 @@ interface SearchBarProps {
}
export function SearchBar({ topResult, onSelect }: SearchBarProps) {
const { strings } = useLocale();
const tankFilters = useStore($tankFilters);
const input = useRef<HTMLInputElement>(null);
const performSearch = useCallback(
@@ -67,7 +69,7 @@ export function SearchBar({ topResult, onSelect }: SearchBarProps) {
defaultValue={tankFilters.search}
style={{ flex: 1 }}
ref={input}
placeholder="Search tanks..."
placeholder={strings.website.common.tank_search.search_bar_hint}
onChange={handleChange}
onKeyDown={handleKeyDown}
>
@@ -1,308 +1,122 @@
import { useStore } from '@nanostores/react';
import { CaretDownIcon } from '@radix-ui/react-icons';
import { Button, DropdownMenu } from '@radix-ui/themes';
import type { TankopediaSortDirection } from '../../../stores/tankopediaPersistent';
import { useLocale } from '../../../hooks/useLocale';
import type {
TankopediaSortBy,
TankopediaSortDirection,
} from '../../../stores/tankopediaPersistent';
import { $tankopediaSort } from '../../../stores/tankopediaSort';
interface ItemProps {
by: TankopediaSortBy;
}
interface ItemProps {
by: TankopediaSortBy;
}
function Item({ by }: ItemProps) {
const { strings } = useLocale();
const tankopediaSort = useStore($tankopediaSort);
return (
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === by}
onClick={() => {
$tankopediaSort.setKey('by', by);
}}
>
{strings.website.common.tank_search.sort[by]}
</DropdownMenu.CheckboxItem>
);
}
export function Sort() {
const tankopediaSort = useStore($tankopediaSort);
const { strings } = useLocale();
return (
<DropdownMenu.Root modal={false}>
<DropdownMenu.Trigger>
<Button variant="surface" color="gray">
Sort
{strings.website.common.tank_search.sort_dropdown.label}
<CaretDownIcon />
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end">
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'meta.none'}
onClick={() => {
// mutateTankopediaSort((draft) => {
// draft.by = 'meta.none';
// });
$tankopediaSort.setKey('by', 'meta.none');
}}
>
No sort
</DropdownMenu.CheckboxItem>
<DropdownMenu.Label>
{strings.website.common.tank_search.sort_dropdown.groups.sort.label}
</DropdownMenu.Label>
<DropdownMenu.Label>Sort by</DropdownMenu.Label>
<Item by="meta.none" />
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger>Fire</DropdownMenu.SubTrigger>
<DropdownMenu.SubTrigger>
{strings.website.common.tank_search.sort_dropdown.groups.sort.fire}
</DropdownMenu.SubTrigger>
<DropdownMenu.SubContent>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.dpm'}
onClick={() => {
// mutateTankopediaSort((draft) => {
// draft.by = 'fire.dpm';
// });
$tankopediaSort.setKey('by', 'fire.dpm');
}}
>
Standard DPM
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.dpmPremium'}
onClick={() => {
// mutateTankopediaSort((draft) => {
// draft.by = 'fire.dpmPremium';
// });
$tankopediaSort.setKey('by', 'fire.dpmPremium');
}}
>
Premium DPM
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.reload'}
onClick={() => {
// mutateTankopediaSort((draft) => {
// draft.by = 'fire.reload';
// });
$tankopediaSort.setKey('by', 'fire.reload');
}}
>
Reload
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.caliber'}
onClick={() => {
// mutateTankopediaSort((draft) => {
// draft.by = 'fire.caliber';
// });
$tankopediaSort.setKey('by', 'fire.caliber');
}}
>
Caliber
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.standardPenetration'}
onClick={() => {
// mutateTankopediaSort((draft) => {
// draft.by = 'fire.standardPenetration';
// });
$tankopediaSort.setKey('by', 'fire.standardPenetration');
}}
>
Standard penetration
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.premiumPenetration'}
onClick={() => {
// mutateTankopediaSort((draft) => {
// draft.by = 'fire.premiumPenetration';
// });
$tankopediaSort.setKey('by', 'fire.premiumPenetration');
}}
>
Premium penetration
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.damage'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.damage');
}}
>
Damage
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.moduleDamage'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.moduleDamage');
}}
>
Module damage
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.shellVelocity'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.shellVelocity');
}}
>
Shell velocity
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.shellRange'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.shellRange');
}}
>
Shell range
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.shellCapacity'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.shellCapacity');
}}
>
Shell capacity
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.aimTime'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.aimTime');
}}
>
Aim time
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.dispersionStill'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.dispersionStill');
}}
>
Dispersion still
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.dispersionMoving'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.dispersionMoving');
}}
>
Dispersion moving
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.gunDepression'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.gunDepression');
}}
>
Gun depression
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'fire.gunElevation'}
onClick={() => {
$tankopediaSort.setKey('by', 'fire.gunElevation');
}}
>
Gun elevation
</DropdownMenu.CheckboxItem>
<Item by="fire.dpm" />
<Item by="fire.dpmPremium" />
<Item by="fire.reload" />
<Item by="fire.caliber" />
<Item by="fire.standardPenetration" />
<Item by="fire.premiumPenetration" />
<Item by="fire.damage" />
<Item by="fire.moduleDamage" />
<Item by="fire.shellVelocity" />
<Item by="fire.shellRange" />
<Item by="fire.shellCapacity" />
<Item by="fire.aimTime" />
<Item by="fire.dispersionStill" />
<Item by="fire.dispersionMoving" />
<Item by="fire.gunDepression" />
<Item by="fire.gunElevation" />
</DropdownMenu.SubContent>
</DropdownMenu.Sub>
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger>Maneuverability</DropdownMenu.SubTrigger>
<DropdownMenu.SubTrigger>
{
strings.website.common.tank_search.sort_dropdown.groups.sort
.maneuverability
}
</DropdownMenu.SubTrigger>
<DropdownMenu.SubContent>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'maneuverability.forwardsSpeed'}
onClick={() => {
$tankopediaSort.setKey('by', 'maneuverability.forwardsSpeed');
}}
>
Forwards speed
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'maneuverability.backwardsSpeed'}
onClick={() => {
$tankopediaSort.setKey('by', 'maneuverability.backwardsSpeed');
}}
>
Backwards speed
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'maneuverability.power'}
onClick={() => {
$tankopediaSort.setKey('by', 'maneuverability.power');
}}
>
Power
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'maneuverability.powerToWeight'}
onClick={() => {
$tankopediaSort.setKey('by', 'maneuverability.powerToWeight');
}}
>
Power to weight
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'maneuverability.weight'}
onClick={() => {
$tankopediaSort.setKey('by', 'maneuverability.weight');
}}
>
Weight
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'maneuverability.traverseSpeed'}
onClick={() => {
$tankopediaSort.setKey('by', 'maneuverability.traverseSpeed');
}}
>
Traverse speed
</DropdownMenu.CheckboxItem>
<Item by="maneuverability.forwardsSpeed" />
<Item by="maneuverability.backwardsSpeed" />
<Item by="maneuverability.power" />
<Item by="maneuverability.powerToWeight" />
<Item by="maneuverability.weight" />
<Item by="maneuverability.traverseSpeed" />
</DropdownMenu.SubContent>
</DropdownMenu.Sub>
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger>Survivability</DropdownMenu.SubTrigger>
<DropdownMenu.SubTrigger>
{
strings.website.common.tank_search.sort_dropdown.groups.sort
.survivability
}
</DropdownMenu.SubTrigger>
<DropdownMenu.SubContent>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'survivability.health'}
onClick={() => {
$tankopediaSort.setKey('by', 'survivability.health');
}}
>
Health
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'survivability.viewRange'}
onClick={() => {
$tankopediaSort.setKey('by', 'survivability.viewRange');
}}
>
View range
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'survivability.camouflageStill'}
onClick={() => {
$tankopediaSort.setKey('by', 'survivability.camouflageStill');
}}
>
Camouflage
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'survivability.camouflageMoving'}
onClick={() => {
$tankopediaSort.setKey('by', 'survivability.camouflageMoving');
}}
>
Camouflage moving
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'survivability.camouflageShooting'}
onClick={() => {
$tankopediaSort.setKey(
'by',
'survivability.camouflageShooting',
);
}}
>
Camouflage shooting
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'survivability.volume'}
onClick={() => {
$tankopediaSort.setKey('by', 'survivability.volume');
}}
>
Volume
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
checked={tankopediaSort.by === 'survivability.length'}
onClick={() => {
$tankopediaSort.setKey('by', 'survivability.length');
}}
>
Length
</DropdownMenu.CheckboxItem>
<Item by="survivability.health" />
<Item by="survivability.viewRange" />
<Item by="survivability.camouflageStill" />
<Item by="survivability.camouflageMoving" />
<Item by="survivability.camouflageShooting" />
<Item by="survivability.volume" />
<Item by="survivability.length" />
</DropdownMenu.SubContent>
</DropdownMenu.Sub>
<DropdownMenu.Label>Direction</DropdownMenu.Label>
<DropdownMenu.Label>
{
strings.website.common.tank_search.sort_dropdown.groups.direction
.label
}
</DropdownMenu.Label>
<DropdownMenu.RadioGroup
value={tankopediaSort.direction}
onValueChange={(value) => {
@@ -313,10 +127,16 @@ export function Sort() {
}}
>
<DropdownMenu.RadioItem value="ascending">
Ascending
{
strings.website.common.tank_search.sort_dropdown.groups.direction
.ascending
}
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="descending">
Descending
{
strings.website.common.tank_search.sort_dropdown.groups.direction
.descending
}
</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
@@ -16,12 +16,11 @@ import { awaitableTankDefinitions } from '../../core/awaitables/tankDefinitions'
import { awaitableTankNames } from '../../core/awaitables/tankNames';
import { filterTank } from '../../core/blitzkit/filterTank';
import { resolveReload } from '../../core/blitzkit/resolveReload';
import { literals } from '../../core/i18n/literals';
import { useLocale } from '../../hooks/useLocale';
import { $tankFilters } from '../../stores/tankFilters';
import { TankopediaPersistent } from '../../stores/tankopediaPersistent';
import {
SORT_NAMES,
SORT_UNITS,
} from '../../stores/tankopediaPersistent/constants';
import { SORT_UNITS } from '../../stores/tankopediaPersistent/constants';
import { $tankopediaSort } from '../../stores/tankopediaSort';
import { ExperimentIcon } from '../ExperimentIcon';
import { TankSearchCard } from './components/Card';
@@ -52,6 +51,7 @@ const [gameDefinitions, modelDefinitions, tankDefinitions, tankNames] =
export const TankSearch = memo<TankSearchProps>(
({ compact, onSelect, onSelectAll, ...props }) => {
const { strings, locale } = useLocale();
const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
const awaitedTanksDefinitionsArray = Object.values(tankDefinitions.tanks);
const tankFilters = useStore($tankFilters);
@@ -438,8 +438,11 @@ export const TankSearch = memo<TankSearchProps>(
<Flex mt="2" gap="1" align="center" justify="center" direction="column">
<Flex gap="2">
<Text color="gray">
{tanksFiltered.length} tank
{tanksFiltered.length === 1 ? '' : 's'}
{tanksFiltered.length === 1
? strings.website.common.tank_search.count_singular
: literals(strings.website.common.tank_search.count_plural, [
`${tanksFiltered.length.toLocaleString(locale)}`,
])}
</Text>
{onSelectAll && (
@@ -457,14 +460,16 @@ export const TankSearch = memo<TankSearchProps>(
});
}}
>
Select all
{strings.website.common.tank_search.select_all}
</Link>
)}
</Flex>
{tankopediaSort.by !== 'meta.none' && (
<Text color="gray">
Sorting by {SORT_NAMES[tankopediaSort.by]}
{literals(strings.website.common.tank_search.sorting_by, [
strings.website.common.tank_search.sort[tankopediaSort.by],
])}
{SORT_UNITS[tankopediaSort.by] === undefined
? ''
: ` (${SORT_UNITS[tankopediaSort.by]})`}
@@ -480,8 +485,7 @@ export const TankSearch = memo<TankSearchProps>(
<ExperimentIcon style={{ width: '1em', height: '1em' }} />
</Callout.Icon>
<Callout.Text>
Tanks in testing are subject to change and may not represent the
final product.
{strings.website.common.warnings.test}
</Callout.Text>
</Callout.Root>
</Flex>