mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01:00
feat: swap tanks
This commit is contained in:
1 parent
0b697a94bd
commit
785e9650e5
3 files changed
+63
-60
No files matched your search
+58
-54
@@ -2,6 +2,7 @@ import {
|
|||||||
CaretRightIcon,
|
CaretRightIcon,
|
||||||
Cross1Icon,
|
Cross1Icon,
|
||||||
MagnifyingGlassIcon,
|
MagnifyingGlassIcon,
|
||||||
|
ShuffleIcon,
|
||||||
} from '@radix-ui/react-icons';
|
} from '@radix-ui/react-icons';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -16,6 +17,7 @@ import {
|
|||||||
} from '@radix-ui/themes';
|
} from '@radix-ui/themes';
|
||||||
import { go } from 'fuzzysort';
|
import { go } from 'fuzzysort';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
import { use, useRef, useState } from 'react';
|
import { use, useRef, useState } from 'react';
|
||||||
import { ModuleButton } from '../../../../../components/ModuleButton';
|
import { ModuleButton } from '../../../../../components/ModuleButton';
|
||||||
import { SmallTankIcon } from '../../../../../components/SmallTankIcon';
|
import { SmallTankIcon } from '../../../../../components/SmallTankIcon';
|
||||||
@@ -28,25 +30,46 @@ import mutateTankopedia, {
|
|||||||
useTankopedia,
|
useTankopedia,
|
||||||
} from '../../../../../stores/tankopedia';
|
} from '../../../../../stores/tankopedia';
|
||||||
|
|
||||||
export function VersusBar() {
|
export function AntagonistBar() {
|
||||||
|
const router = useRouter();
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
const awaitedTankDefinitions = use(tankDefinitions);
|
||||||
const mode = useTankopedia((state) => state.mode);
|
const mode = useTankopedia((state) => state.mode);
|
||||||
const awaitedTankNamesDiacritics = use(tankNamesDiacritics);
|
const awaitedTankNamesDiacritics = use(tankNamesDiacritics);
|
||||||
const [versusTankTab, setVersusTankTab] = useState('search');
|
const [tab, setTab] = useState('search');
|
||||||
const versusTankSearchInput = useRef<HTMLInputElement>(null);
|
const searchInput = useRef<HTMLInputElement>(null);
|
||||||
const antagonist = useTankopedia((state) => {
|
const antagonist = useTankopedia((state) => {
|
||||||
if (!state.areTanksAssigned) return;
|
if (!state.areTanksAssigned) return;
|
||||||
return state.antagonist;
|
return state.antagonist;
|
||||||
});
|
});
|
||||||
const [versusTankSearchResults, setVersusTankSearchResults] = useState<
|
const [searchResults, setSearchResults] = useState<number[]>([]);
|
||||||
number[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
if (!antagonist || mode !== 'armor') return null;
|
if (!antagonist || mode !== 'armor') return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<Flex align="center" justify="between" gap="2">
|
<Flex align="center" justify="between" gap="2">
|
||||||
|
<Flex>
|
||||||
|
{antagonist.gun.shells.map((shell, index) => {
|
||||||
|
return (
|
||||||
|
<ModuleButton
|
||||||
|
selected={antagonist.shell.id === shell.id}
|
||||||
|
type="shell"
|
||||||
|
shell={shell.icon}
|
||||||
|
rowChild
|
||||||
|
first={index === 0}
|
||||||
|
key={shell.id}
|
||||||
|
last={index === antagonist.gun.shells.length - 1}
|
||||||
|
onClick={() => {
|
||||||
|
mutateTankopedia((draft) => {
|
||||||
|
if (!draft.areTanksAssigned) return;
|
||||||
|
draft.antagonist.shell = shell;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Flex align="center" gap="4">
|
<Flex align="center" gap="4">
|
||||||
<Text>Versus</Text>
|
<Text>Versus</Text>
|
||||||
|
|
||||||
@@ -63,8 +86,8 @@ export function VersusBar() {
|
|||||||
|
|
||||||
<Dialog.Content>
|
<Dialog.Content>
|
||||||
<Tabs.Root
|
<Tabs.Root
|
||||||
value={versusTankTab}
|
value={tab}
|
||||||
onValueChange={setVersusTankTab}
|
onValueChange={setTab}
|
||||||
style={{ position: 'relative' }}
|
style={{ position: 'relative' }}
|
||||||
>
|
>
|
||||||
<Dialog.Close>
|
<Dialog.Close>
|
||||||
@@ -94,12 +117,12 @@ export function VersusBar() {
|
|||||||
<MagnifyingGlassIcon />
|
<MagnifyingGlassIcon />
|
||||||
</TextField.Slot>
|
</TextField.Slot>
|
||||||
<TextField.Input
|
<TextField.Input
|
||||||
ref={versusTankSearchInput}
|
ref={searchInput}
|
||||||
placeholder="Search tank..."
|
placeholder="Search tank..."
|
||||||
onChange={debounce(() => {
|
onChange={debounce(() => {
|
||||||
setVersusTankSearchResults(
|
setSearchResults(
|
||||||
go(
|
go(
|
||||||
versusTankSearchInput.current!.value,
|
searchInput.current!.value,
|
||||||
awaitedTankNamesDiacritics,
|
awaitedTankNamesDiacritics,
|
||||||
{ key: 'combined', limit: 8 },
|
{ key: 'combined', limit: 8 },
|
||||||
).map((item) => item.obj.id),
|
).map((item) => item.obj.id),
|
||||||
@@ -109,10 +132,10 @@ export function VersusBar() {
|
|||||||
</TextField.Root>
|
</TextField.Root>
|
||||||
|
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
{(versusTankSearchResults.length > 0 ||
|
{(searchResults.length > 0 ||
|
||||||
versusTankSearchInput.current?.value) && (
|
searchInput.current?.value) && (
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
{versusTankSearchResults
|
{searchResults
|
||||||
.map((id) => awaitedTankDefinitions[id])
|
.map((id) => awaitedTankDefinitions[id])
|
||||||
.map((tank) => (
|
.map((tank) => (
|
||||||
<Button
|
<Button
|
||||||
@@ -137,18 +160,18 @@ export function VersusBar() {
|
|||||||
draft.antagonist.shell =
|
draft.antagonist.shell =
|
||||||
draft.antagonist.gun.shells[0];
|
draft.antagonist.gun.shells[0];
|
||||||
});
|
});
|
||||||
setVersusTankSearchResults([]);
|
setSearchResults([]);
|
||||||
versusTankSearchInput.current!.value = '';
|
searchInput.current!.value = '';
|
||||||
setVersusTankTab('configure');
|
setTab('configure');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{tank.name}
|
{tank.name}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{versusTankSearchResults.length === 0 &&
|
{searchResults.length === 0 &&
|
||||||
(versusTankSearchInput.current
|
(searchInput.current
|
||||||
? versusTankSearchInput.current.value.length > 0
|
? searchInput.current.value.length > 0
|
||||||
: false) && (
|
: false) && (
|
||||||
<Button disabled variant="ghost">
|
<Button disabled variant="ghost">
|
||||||
No search results
|
No search results
|
||||||
@@ -253,40 +276,21 @@ export function VersusBar() {
|
|||||||
</Dialog.Root>
|
</Dialog.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex>
|
<Button
|
||||||
{antagonist.gun.shells.map((shell, index) => {
|
variant="ghost"
|
||||||
return (
|
onClick={() => {
|
||||||
<ModuleButton
|
mutateTankopedia((draft) => {
|
||||||
selected={antagonist.shell.id === shell.id}
|
if (!draft.areTanksAssigned) return;
|
||||||
type="shell"
|
|
||||||
shell={shell.icon}
|
[draft.antagonist, draft.protagonist] = [
|
||||||
rowChild
|
draft.protagonist,
|
||||||
first={index === 0}
|
draft.antagonist,
|
||||||
key={shell.id}
|
];
|
||||||
last={index === antagonist.gun.shells.length - 1}
|
});
|
||||||
onClick={() => {
|
}}
|
||||||
mutateTankopedia((draft) => {
|
>
|
||||||
if (!draft.areTanksAssigned) return;
|
<ShuffleIcon /> Swap tanks
|
||||||
draft.antagonist.shell = shell;
|
</Button>
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{/* <Button variant="solid" radius="small">
|
|
||||||
<img src={asset('icons/shells/ap.webp')} width={24} height={24} />
|
|
||||||
</Button>
|
|
||||||
<Button variant="soft" radius="small" color="gray">
|
|
||||||
<img
|
|
||||||
src={asset('icons/shells/hc_premium.webp')}
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
<Button variant="soft" radius="small" color="gray">
|
|
||||||
<img src={asset('icons/shells/he.webp')} width={24} height={24} />
|
|
||||||
</Button> */}
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
@@ -12,8 +12,8 @@ import {
|
|||||||
tankDefinitions,
|
tankDefinitions,
|
||||||
} from '../../../../core/blitzkrieg/tankDefinitions';
|
} from '../../../../core/blitzkrieg/tankDefinitions';
|
||||||
import mutateTankopedia, { useTankopedia } from '../../../../stores/tankopedia';
|
import mutateTankopedia, { useTankopedia } from '../../../../stores/tankopedia';
|
||||||
|
import { AntagonistBar } from './components/AntagonistBar';
|
||||||
import { TankDisplay } from './components/Model/TankDisplay';
|
import { TankDisplay } from './components/Model/TankDisplay';
|
||||||
import { VersusBar } from './components/VersusBar';
|
|
||||||
|
|
||||||
export default function Page({ params }: { params: { id: string } }) {
|
export default function Page({ params }: { params: { id: string } }) {
|
||||||
const id = parseInt(params.id);
|
const id = parseInt(params.id);
|
||||||
@@ -33,10 +33,8 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
draft.protagonist.tank = awaitedTankDefinitions[id];
|
draft.protagonist.tank = awaitedTankDefinitions[id];
|
||||||
draft.protagonist.turret = draft.protagonist.tank.turrets.at(-1)!;
|
draft.protagonist.turret = draft.protagonist.tank.turrets.at(-1)!;
|
||||||
draft.protagonist.gun = draft.protagonist.turret.guns.at(-1)!;
|
draft.protagonist.gun = draft.protagonist.turret.guns.at(-1)!;
|
||||||
draft.antagonist = {
|
draft.protagonist.shell = draft.protagonist.gun.shells[0];
|
||||||
...draft.protagonist,
|
draft.antagonist = draft.protagonist;
|
||||||
shell: draft.protagonist.gun.shells[0],
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleKeyDown(event: KeyboardEvent) {
|
function handleKeyDown(event: KeyboardEvent) {
|
||||||
@@ -101,7 +99,7 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<TankDisplay />
|
<TankDisplay />
|
||||||
<VersusBar />
|
<AntagonistBar />
|
||||||
|
|
||||||
<Theme radius="small">
|
<Theme radius="small">
|
||||||
<Flex gap="4">
|
<Flex gap="4">
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ type Tankopedia = {
|
|||||||
tank: TankDefinition;
|
tank: TankDefinition;
|
||||||
turret: TurretDefinition;
|
turret: TurretDefinition;
|
||||||
gun: GunDefinition;
|
gun: GunDefinition;
|
||||||
|
shell: ShellDefinition;
|
||||||
};
|
};
|
||||||
antagonist: {
|
antagonist: {
|
||||||
tank: TankDefinition;
|
tank: TankDefinition;
|
||||||
|
|||||||
Reference in new issue
Block a user