mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-27 04:29:50 +01:00
feat: swap button
This commit is contained in:
1 parent
ee9dbdaf74
commit
13faad0977
3 files changed
+81
-31
No files matched your search
@@ -12,11 +12,7 @@ import { TankSandbox } from './TankSandbox';
|
|||||||
import { TankSandboxLoader } from './TankSandboxLoader';
|
import { TankSandboxLoader } from './TankSandboxLoader';
|
||||||
import { Options } from './components/Options';
|
import { Options } from './components/Options';
|
||||||
|
|
||||||
interface HeroSectionProps {
|
export function HeroSection() {
|
||||||
id: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function HeroSection({ id }: HeroSectionProps) {
|
|
||||||
const canvas = useRef<HTMLCanvasElement>(null);
|
const canvas = useRef<HTMLCanvasElement>(null);
|
||||||
const isFullScreen = useFullScreen();
|
const isFullScreen = useFullScreen();
|
||||||
const protagonist = Duel.use((state) => state.protagonist.tank);
|
const protagonist = Duel.use((state) => state.protagonist.tank);
|
||||||
@@ -29,10 +25,11 @@ export function HeroSection({ id }: HeroSectionProps) {
|
|||||||
? 'amber'
|
? 'amber'
|
||||||
: undefined;
|
: undefined;
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
const awaitedTankDefinitions = use(tankDefinitions);
|
||||||
const tank = awaitedTankDefinitions[id];
|
|
||||||
const thicknessRange = useMemo(() => {
|
const thicknessRange = useMemo(() => {
|
||||||
const entries = Object.values(awaitedTankDefinitions);
|
const entries = Object.values(awaitedTankDefinitions);
|
||||||
const filtered = entries.filter((thisTank) => thisTank.tier === tank.tier);
|
const filtered = entries.filter(
|
||||||
|
(thisTank) => thisTank.tier === protagonist.tier,
|
||||||
|
);
|
||||||
const value =
|
const value =
|
||||||
(filtered.reduce((accumulator, thisTank) => {
|
(filtered.reduce((accumulator, thisTank) => {
|
||||||
return (
|
return (
|
||||||
@@ -46,7 +43,7 @@ export function HeroSection({ id }: HeroSectionProps) {
|
|||||||
(3 / 4);
|
(3 / 4);
|
||||||
|
|
||||||
return { value } satisfies ThicknessRange;
|
return { value } satisfies ThicknessRange;
|
||||||
}, [tank.tier]);
|
}, [protagonist]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDummyLoader(false);
|
setDummyLoader(false);
|
||||||
@@ -90,7 +87,7 @@ export function HeroSection({ id }: HeroSectionProps) {
|
|||||||
>
|
>
|
||||||
<Flex align="center" gap="3">
|
<Flex align="center" gap="3">
|
||||||
<Icon width="0.8em" height="0.8em" />
|
<Icon width="0.8em" height="0.8em" />
|
||||||
{tank.name}
|
{protagonist.name}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Heading>
|
</Heading>
|
||||||
|
|
||||||
@@ -114,14 +111,14 @@ export function HeroSection({ id }: HeroSectionProps) {
|
|||||||
<Box width="100%" height="100%" position="absolute">
|
<Box width="100%" height="100%" position="absolute">
|
||||||
<Box width="100%" height="100%">
|
<Box width="100%" height="100%">
|
||||||
<TankSandboxLoader
|
<TankSandboxLoader
|
||||||
id={id}
|
id={protagonist.id}
|
||||||
display={dummyLoader ? 'flex' : 'none'}
|
display={dummyLoader ? 'flex' : 'none'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
<TankSandboxLoader
|
<TankSandboxLoader
|
||||||
id={id}
|
id={protagonist.id}
|
||||||
display={dummyLoader ? 'none' : 'flex'}
|
display={dummyLoader ? 'none' : 'flex'}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import { ChevronLeftIcon, MixIcon } from '@radix-ui/react-icons';
|
import { ChevronLeftIcon, MixIcon, UpdateIcon } from '@radix-ui/react-icons';
|
||||||
import { Button, Code, Flex } from '@radix-ui/themes';
|
import { Button, Code, Dialog, Flex } from '@radix-ui/themes';
|
||||||
|
import { use, useState } from 'react';
|
||||||
import { classIcons } from '../../../../../../../components/ClassIcon';
|
import { classIcons } from '../../../../../../../components/ClassIcon';
|
||||||
import { Link } from '../../../../../../../components/Link';
|
import { Link } from '../../../../../../../components/Link';
|
||||||
import { asset } from '../../../../../../../core/blitzkit/asset';
|
import { asset } from '../../../../../../../core/blitzkit/asset';
|
||||||
|
import { modelDefinitions } from '../../../../../../../core/blitzkit/modelDefinitions';
|
||||||
|
import { provisionDefinitions } from '../../../../../../../core/blitzkit/provisionDefinitions';
|
||||||
|
import { tankToDuelMember } from '../../../../../../../core/blitzkit/tankToDuelMember';
|
||||||
import strings from '../../../../../../../lang/en-US.json';
|
import strings from '../../../../../../../lang/en-US.json';
|
||||||
import * as App from '../../../../../../../stores/app';
|
import * as App from '../../../../../../../stores/app';
|
||||||
import * as Duel from '../../../../../../../stores/duel';
|
import * as Duel from '../../../../../../../stores/duel';
|
||||||
|
import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral';
|
||||||
|
import { TankSearch } from '../../../../components/TankSearch';
|
||||||
import { Listing } from './components/Listing';
|
import { Listing } from './components/Listing';
|
||||||
import { Votes } from './components/Votes';
|
import { Votes } from './components/Votes';
|
||||||
|
|
||||||
@@ -18,6 +24,11 @@ export function MetaSection() {
|
|||||||
protagonist.id === antagonist.id
|
protagonist.id === antagonist.id
|
||||||
? [protagonist.id]
|
? [protagonist.id]
|
||||||
: [protagonist.id, antagonist.id];
|
: [protagonist.id, antagonist.id];
|
||||||
|
const mutateDuel = Duel.useMutation();
|
||||||
|
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||||
|
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
||||||
|
const [showSwapDialog, setShowSwapDialog] = useState(false);
|
||||||
|
const awaitedModelDefinitions = use(modelDefinitions);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex justify="center" align="center">
|
<Flex justify="center" align="center">
|
||||||
@@ -31,11 +42,44 @@ export function MetaSection() {
|
|||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link href={`/tools/compare?tanks=${compareTanks.join('%2C')}`}>
|
<Link href={`/tools/compare?tanks=${compareTanks.join('%2C')}`}>
|
||||||
<Button>
|
<Button variant="outline">
|
||||||
<MixIcon />
|
<MixIcon />
|
||||||
Compare
|
Compare
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
<Dialog.Root open={showSwapDialog} onOpenChange={setShowSwapDialog}>
|
||||||
|
<Dialog.Trigger>
|
||||||
|
<Button>
|
||||||
|
<UpdateIcon />
|
||||||
|
Swap
|
||||||
|
</Button>
|
||||||
|
</Dialog.Trigger>
|
||||||
|
|
||||||
|
<Dialog.Content>
|
||||||
|
<TankSearch
|
||||||
|
compact
|
||||||
|
onSelect={(tank) => {
|
||||||
|
setShowSwapDialog(false);
|
||||||
|
mutateTankopediaEphemeral((draft) => {
|
||||||
|
draft.model = awaitedModelDefinitions[tank.id];
|
||||||
|
});
|
||||||
|
mutateDuel((draft) => {
|
||||||
|
draft.protagonist = tankToDuelMember(
|
||||||
|
tank,
|
||||||
|
awaitedProvisionDefinitions,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.history.replaceState(
|
||||||
|
null,
|
||||||
|
'',
|
||||||
|
`/tools/tankopedia/${tank.id}`,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import { invalidate } from '@react-three/fiber';
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { AdMidSectionResponsive } from '../../../../components/AdMidSectionResponsive';
|
import { AdMidSectionResponsive } from '../../../../components/AdMidSectionResponsive';
|
||||||
import PageWrapper from '../../../../components/PageWrapper';
|
import PageWrapper from '../../../../components/PageWrapper';
|
||||||
|
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { useAdExempt } from '../../../../hooks/useAdExempt';
|
import { useAdExempt } from '../../../../hooks/useAdExempt';
|
||||||
|
import strings from '../../../../lang/en-US.json';
|
||||||
import * as Duel from '../../../../stores/duel';
|
import * as Duel from '../../../../stores/duel';
|
||||||
import * as TankopediaEphemeral from '../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../stores/tankopediaEphemeral';
|
||||||
import { CalloutsSection } from './components/CalloutsSection';
|
import { CalloutsSection } from './components/CalloutsSection';
|
||||||
@@ -14,14 +16,18 @@ import { GameModeSection } from './components/Model/GameModeSection';
|
|||||||
import { HeroSection } from './components/Model/HeroSection';
|
import { HeroSection } from './components/Model/HeroSection';
|
||||||
import { MetaSection } from './components/Model/MetaSection';
|
import { MetaSection } from './components/Model/MetaSection';
|
||||||
import { TechTreeSection } from './components/Model/TechTreeSection';
|
import { TechTreeSection } from './components/Model/TechTreeSection';
|
||||||
|
import { ShotDisplaySection } from './components/ShotDisplaySection';
|
||||||
import { VideoSection } from './components/VideoSection';
|
import { VideoSection } from './components/VideoSection';
|
||||||
|
|
||||||
export default function Page({ params }: { params: { id: string } }) {
|
export default function Page() {
|
||||||
const id = Number(params.id);
|
|
||||||
const exempt = useAdExempt();
|
const exempt = useAdExempt();
|
||||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||||
const mutateDuel = Duel.useMutation();
|
const mutateDuel = Duel.useMutation();
|
||||||
const duelStore = Duel.useStore();
|
const duelStore = Duel.useStore();
|
||||||
|
const tank = Duel.use((state) => state.protagonist.tank);
|
||||||
|
const title = `${tank.name} - Tier ${TIER_ROMAN_NUMERALS[tank.tier]} ${
|
||||||
|
(strings.common.nations_adjectives as Record<string, string>)[tank.nation]
|
||||||
|
} ${strings.common.tank_class_short[tank.class]}`;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleKeyDown(event: KeyboardEvent) {
|
function handleKeyDown(event: KeyboardEvent) {
|
||||||
@@ -79,20 +85,23 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper p="0" noMaxWidth color="purple" size={1600} gap="9">
|
<>
|
||||||
<HeroSection id={id} />
|
<title>{title}</title>
|
||||||
<CalloutsSection />
|
|
||||||
<MetaSection />
|
<PageWrapper p="0" noMaxWidth color="purple" size={1600} gap="9">
|
||||||
{/* <VotingSection /> */}
|
<HeroSection />
|
||||||
{/* <ShotDisplaySection /> */}
|
<MetaSection />
|
||||||
<TechTreeSection />
|
<ShotDisplaySection />
|
||||||
{!exempt && <AdMidSectionResponsive />}
|
<TechTreeSection />
|
||||||
<CharacteristicsSection />
|
{!exempt && <AdMidSectionResponsive />}
|
||||||
{!exempt && <AdMidSectionResponsive />}
|
<CalloutsSection />
|
||||||
<GameModeSection />
|
<CharacteristicsSection />
|
||||||
<VideoSection />
|
{!exempt && <AdMidSectionResponsive />}
|
||||||
<HistorySection />
|
<GameModeSection />
|
||||||
{!exempt && <AdMidSectionResponsive mb="6" />}
|
<VideoSection />
|
||||||
</PageWrapper>
|
<HistorySection />
|
||||||
|
{!exempt && <AdMidSectionResponsive mb="6" />}
|
||||||
|
</PageWrapper>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user