mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: translate tank search
This commit is contained in:
1 parent
c7856364ad
commit
5a65fee1d1
9 files changed
+231
-355
No files matched your search
@@ -716,6 +716,68 @@
|
||||
"common": {
|
||||
"copy_button": {
|
||||
"copied": "Copied!"
|
||||
},
|
||||
|
||||
"tank_search": {
|
||||
"search_bar_hint": "Search tanks...",
|
||||
"recent": "Recently viewed",
|
||||
"select_all": "Select all",
|
||||
"count_singular": "1 tank",
|
||||
"count_plural": "%s1 tanks",
|
||||
"sorting_by": "Sorting by %s1",
|
||||
"sort": {
|
||||
"meta.none": "none",
|
||||
"survivability.health": "health",
|
||||
"survivability.viewRange": "view range",
|
||||
"survivability.camouflageStill": "camouflage still",
|
||||
"survivability.camouflageMoving": "camouflage moving",
|
||||
"survivability.camouflageShooting": "camouflage shooting",
|
||||
"survivability.volume": "volume",
|
||||
"survivability.length": "length",
|
||||
"fire.dpm": "standard DPM",
|
||||
"fire.dpmPremium": "premium DPM",
|
||||
"fire.reload": "reload",
|
||||
"fire.caliber": "caliber",
|
||||
"fire.standardPenetration": "standard penetration",
|
||||
"fire.premiumPenetration": "premium penetration",
|
||||
"fire.damage": "damage",
|
||||
"fire.moduleDamage": "module damage",
|
||||
"fire.shellVelocity": "shell velocity",
|
||||
"fire.shellRange": "shell range",
|
||||
"fire.shellCapacity": "shell capacity",
|
||||
"fire.aimTime": "aim time",
|
||||
"fire.dispersionStill": "dispersion still",
|
||||
"fire.dispersionMoving": "dispersion moving",
|
||||
"fire.gunDepression": "gun depression",
|
||||
"fire.gunElevation": "gun elevation",
|
||||
"maneuverability.forwardsSpeed": "forwards speed",
|
||||
"maneuverability.backwardsSpeed": "backwards speed",
|
||||
"maneuverability.power": "power",
|
||||
"maneuverability.powerToWeight": "power to weight",
|
||||
"maneuverability.weight": "weight",
|
||||
"maneuverability.traverseSpeed": "traverse speed"
|
||||
},
|
||||
"sort_dropdown": {
|
||||
"label": "Sort",
|
||||
"groups": {
|
||||
"sort": {
|
||||
"no_sort": "No sort",
|
||||
"label": "Sort by",
|
||||
"fire": "Fire",
|
||||
"maneuverability": "Maneuverability",
|
||||
"survivability": "Survivability"
|
||||
},
|
||||
"direction": {
|
||||
"label": "Direction",
|
||||
"ascending": "Ascending",
|
||||
"descending": "Descending"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"warnings": {
|
||||
"test": "Tanks in testing are subject to change and may not represent the final product."
|
||||
}
|
||||
},
|
||||
|
||||
@@ -743,7 +805,24 @@
|
||||
"name": "Compare",
|
||||
"button": "Compare tanks",
|
||||
"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",
|
||||
"actions": {
|
||||
"add": {
|
||||
"button": "Add",
|
||||
"title": "Add tanks",
|
||||
"description": "Select tanks to add to comparison"
|
||||
},
|
||||
"clear": "Clear",
|
||||
"deltas": {
|
||||
"none": "No deltas",
|
||||
"percentage": "Percentage",
|
||||
"absolute": "Absolute"
|
||||
}
|
||||
},
|
||||
"no_tanks": {
|
||||
"title": "No tanks selected",
|
||||
"body": "Press the Add button to get started"
|
||||
}
|
||||
},
|
||||
"performance": {
|
||||
"name": "Performance",
|
||||
|
||||
@@ -2,6 +2,7 @@ import { PlusIcon, TrashIcon } from '@radix-ui/react-icons';
|
||||
import { Button, Dialog, Flex, SegmentedControl } from '@radix-ui/themes';
|
||||
import { awaitableProvisionDefinitions } from '../../core/awaitables/provisionDefinitions';
|
||||
import { tankToCompareMember } from '../../core/blitzkit/tankToCompareMember';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
||||
import {
|
||||
ComparePersistent,
|
||||
@@ -23,6 +24,7 @@ export function Controls({
|
||||
const deltaMode = ComparePersistent.use((state) => state.deltaMode);
|
||||
const mutateCompareEphemeral = CompareEphemeral.useMutation();
|
||||
const mutateComparePersistent = ComparePersistent.useMutation();
|
||||
const { strings } = useLocale();
|
||||
|
||||
return (
|
||||
<Flex gap="2" wrap="wrap" justify="center">
|
||||
@@ -32,14 +34,16 @@ export function Controls({
|
||||
>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="soft">
|
||||
<PlusIcon /> Add
|
||||
<PlusIcon /> {strings.website.tools.compare.actions.add.button}
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
|
||||
<Dialog.Content>
|
||||
<Dialog.Title align="center">Add tanks</Dialog.Title>
|
||||
<Dialog.Title align="center">
|
||||
{strings.website.tools.compare.actions.add.title}
|
||||
</Dialog.Title>
|
||||
<Dialog.Description align="center">
|
||||
Select tanks to add to comparison
|
||||
{strings.website.tools.compare.actions.add.description}
|
||||
</Dialog.Description>
|
||||
|
||||
<Flex gap="4" direction="column">
|
||||
@@ -87,7 +91,7 @@ export function Controls({
|
||||
});
|
||||
}}
|
||||
>
|
||||
<TrashIcon /> Clear
|
||||
<TrashIcon /> {strings.website.tools.compare.actions.clear}
|
||||
</Button>
|
||||
|
||||
<SegmentedControl.Root
|
||||
@@ -99,13 +103,13 @@ export function Controls({
|
||||
}}
|
||||
>
|
||||
<SegmentedControl.Item value={'none' satisfies DeltaMode}>
|
||||
No deltas
|
||||
{strings.website.tools.compare.actions.deltas.none}
|
||||
</SegmentedControl.Item>
|
||||
<SegmentedControl.Item value={'percentage' satisfies DeltaMode}>
|
||||
Percentage
|
||||
{strings.website.tools.compare.actions.deltas.percentage}
|
||||
</SegmentedControl.Item>
|
||||
<SegmentedControl.Item value={'absolute' satisfies DeltaMode}>
|
||||
Absolute
|
||||
{strings.website.tools.compare.actions.deltas.absolute}
|
||||
</SegmentedControl.Item>
|
||||
</SegmentedControl.Root>
|
||||
</Flex>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { createDefaultSkills } from '@blitzkit/core';
|
||||
import { PlusIcon } from '@radix-ui/react-icons';
|
||||
import { Flex, Heading, Text } from '@radix-ui/themes';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { CompareTable } from '../../../../components/Compare/CompareTable';
|
||||
@@ -13,6 +12,11 @@ import { awaitableSkillDefinitions } from '../../../../core/awaitables/skillDefi
|
||||
import { awaitableTankDefinitions } from '../../../../core/awaitables/tankDefinitions';
|
||||
import { tankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics';
|
||||
import { tankToCompareMember } from '../../../../core/blitzkit/tankToCompareMember';
|
||||
import {
|
||||
LocaleProvider,
|
||||
useLocale,
|
||||
type LocaleAcceptorProps,
|
||||
} from '../../../../hooks/useLocale';
|
||||
import { App } from '../../../../stores/app';
|
||||
import { CompareEphemeral } from '../../../../stores/compareEphemeral';
|
||||
import { ComparePersistent } from '../../../../stores/comparePersistent';
|
||||
@@ -32,19 +36,21 @@ const [
|
||||
awaitableTankDefinitions,
|
||||
]);
|
||||
|
||||
export function Page() {
|
||||
export function Page({ locale }: LocaleAcceptorProps) {
|
||||
return (
|
||||
<App.Provider>
|
||||
<TankopediaPersistent.Provider>
|
||||
<ComparePersistent.Provider>
|
||||
<CompareEphemeral.Provider
|
||||
data={createDefaultSkills(skillDefinitions)}
|
||||
>
|
||||
<Content />
|
||||
</CompareEphemeral.Provider>
|
||||
</ComparePersistent.Provider>
|
||||
</TankopediaPersistent.Provider>
|
||||
</App.Provider>
|
||||
<LocaleProvider locale={locale}>
|
||||
<App.Provider>
|
||||
<TankopediaPersistent.Provider>
|
||||
<ComparePersistent.Provider>
|
||||
<CompareEphemeral.Provider
|
||||
data={createDefaultSkills(skillDefinitions)}
|
||||
>
|
||||
<Content />
|
||||
</CompareEphemeral.Provider>
|
||||
</ComparePersistent.Provider>
|
||||
</TankopediaPersistent.Provider>
|
||||
</App.Provider>
|
||||
</LocaleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,6 +58,7 @@ function Content() {
|
||||
const members = CompareEphemeral.use((state) => state.members);
|
||||
const [addTankDialogOpen, setAddTankDialogOpen] = useState(false);
|
||||
const crewSkills = CompareEphemeral.use((state) => state.crewSkills);
|
||||
const { strings } = useLocale();
|
||||
const stats = useMemo<ReturnType<typeof tankCharacteristics>[]>(
|
||||
() =>
|
||||
members.map((thisMember) =>
|
||||
@@ -136,19 +143,6 @@ function Content() {
|
||||
{members.length > 0 && (
|
||||
<Flex justify="center" flexGrow="1" position="relative">
|
||||
<CompareTable stats={stats} />
|
||||
|
||||
{/* <IconButton
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 73,
|
||||
transform: 'translate(50%, -50%)',
|
||||
zIndex: 1,
|
||||
}}
|
||||
onClick={() => setAddTankDialogOpen(true)}
|
||||
>
|
||||
<PlusIcon />
|
||||
</IconButton> */}
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
@@ -159,9 +153,11 @@ function Content() {
|
||||
direction="column"
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<Heading color="gray">No tanks selected</Heading>
|
||||
<Heading color="gray">
|
||||
{strings.website.tools.compare.no_tanks.title}
|
||||
</Heading>
|
||||
<Text color="gray">
|
||||
Press the <PlusIcon /> Add button to get started
|
||||
{strings.website.tools.compare.no_tanks.body}
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
@@ -5,10 +5,12 @@ import BaseLayout from '../../../../layouts/BaseLayout.astro';
|
||||
import { Page } from './_index';
|
||||
|
||||
export { getStaticPaths } from '../../index.astro';
|
||||
|
||||
const { locale } = Astro.params;
|
||||
---
|
||||
|
||||
<ToolOpenGraph tool={compareTool} />
|
||||
|
||||
<BaseLayout noFooter>
|
||||
<Page client:load />
|
||||
<Page {locale} client:load />
|
||||
</BaseLayout>
|
||||
@@ -32,38 +32,7 @@ export const SORT_UNITS: Record<TankopediaSortBy, string | undefined> = {
|
||||
'survivability.viewRange': 'm',
|
||||
'survivability.volume': 'm^3',
|
||||
};
|
||||
export const SORT_NAMES = {
|
||||
'meta.none': 'none',
|
||||
'survivability.health': 'health',
|
||||
'survivability.viewRange': 'view range',
|
||||
'survivability.camouflageStill': 'camouflage still',
|
||||
'survivability.camouflageMoving': 'camouflage moving',
|
||||
'survivability.camouflageShooting': 'camouflage shooting',
|
||||
'survivability.volume': 'volume',
|
||||
'survivability.length': 'length',
|
||||
'fire.dpm': 'standard DPM',
|
||||
'fire.dpmPremium': 'premium DPM',
|
||||
'fire.reload': 'reload',
|
||||
'fire.caliber': 'caliber',
|
||||
'fire.standardPenetration': 'standard penetration',
|
||||
'fire.premiumPenetration': 'premium penetration',
|
||||
'fire.damage': 'damage',
|
||||
'fire.moduleDamage': 'module damage',
|
||||
'fire.shellVelocity': 'shell velocity',
|
||||
'fire.shellRange': 'shell range',
|
||||
'fire.shellCapacity': 'shell capacity',
|
||||
'fire.aimTime': 'aim time',
|
||||
'fire.dispersionStill': 'dispersion still',
|
||||
'fire.dispersionMoving': 'dispersion moving',
|
||||
'fire.gunDepression': 'gun depression',
|
||||
'fire.gunElevation': 'gun elevation',
|
||||
'maneuverability.forwardsSpeed': 'forwards speed',
|
||||
'maneuverability.backwardsSpeed': 'backwards speed',
|
||||
'maneuverability.power': 'power',
|
||||
'maneuverability.powerToWeight': 'power to weight',
|
||||
'maneuverability.weight': 'weight',
|
||||
'maneuverability.traverseSpeed': 'traverse speed',
|
||||
} as const;
|
||||
|
||||
export enum TankopediaDisplay {
|
||||
Model,
|
||||
DynamicArmor,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type en from '@blitzkit/core/lang/en.json';
|
||||
import * as lodash from 'lodash-es';
|
||||
import { create } from 'zustand';
|
||||
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||
import { SORT_NAMES } from './constants';
|
||||
|
||||
export type TankopediaSortBy = keyof typeof SORT_NAMES;
|
||||
export type TankopediaSortBy = keyof typeof en.website.common.tank_search.sort;
|
||||
export type TankopediaSortDirection = 'ascending' | 'descending';
|
||||
export type TankopediaTestTankDisplay = 'include' | 'exclude' | 'only';
|
||||
|
||||
|
||||
Reference in new issue
Block a user