mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: progress on compare
This commit is contained in:
1 parent
53c0f48437
commit
d90a3cc010
24 files changed
+214
-93
No files matched your search
@@ -10,13 +10,13 @@ import { PlusIcon } from '@radix-ui/react-icons';
|
|||||||
import { Box, Flex, Heading, IconButton, Text } from '@radix-ui/themes';
|
import { Box, Flex, Heading, IconButton, Text } from '@radix-ui/themes';
|
||||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
||||||
import { use, useCallback, useEffect, useMemo, useState } from 'react';
|
import { use, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { CompareControls } from '../../../../../website/src/components/Controls';
|
||||||
|
import { DamageWarning } from '../../../../../website/src/components/DamageWarning';
|
||||||
import { PageWrapper } from '../../../components/PageWrapper';
|
import { PageWrapper } from '../../../components/PageWrapper';
|
||||||
import { tankCharacteristics } from '../../../core/blitzkit/tankCharacteristics';
|
import { tankCharacteristics } from '../../../core/blitzkit/tankCharacteristics';
|
||||||
import { tankToCompareMember } from '../../../core/blitzkit/tankToCompareMember';
|
import { tankToCompareMember } from '../../../core/blitzkit/tankToCompareMember';
|
||||||
import * as CompareEphemeral from '../../../stores/compareEphemeral';
|
import * as CompareEphemeral from '../../../stores/compareEphemeral';
|
||||||
import { CompareTable } from './components/CompareTable';
|
import { CompareTable } from '../../../../../website/src/components/Compare/CompareTable';
|
||||||
import { Controls } from './components/Controls';
|
|
||||||
import { DamageWarning } from './components/DamageWarning';
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
@@ -116,7 +116,7 @@ export default function Page() {
|
|||||||
<PageWrapper color="crimson" size="100%">
|
<PageWrapper color="crimson" size="100%">
|
||||||
<Flex justify="center" gap="4" align="center" direction="column">
|
<Flex justify="center" gap="4" align="center" direction="column">
|
||||||
<DamageWarning />
|
<DamageWarning />
|
||||||
<Controls
|
<CompareControls
|
||||||
addTankDialogOpen={addTankDialogOpen}
|
addTankDialogOpen={addTankDialogOpen}
|
||||||
onAddTankDialogOpenChange={setAddTankDialogOpen}
|
onAddTankDialogOpenChange={setAddTankDialogOpen}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -18,5 +18,5 @@
|
|||||||
"../website/src/components/Tankopedia/HistorySection.tsx",
|
"../website/src/components/Tankopedia/HistorySection.tsx",
|
||||||
"../website/src/components/Tankopedia/CalloutsSection.tsx",
|
"../website/src/components/Tankopedia/CalloutsSection.tsx",
|
||||||
"../website/src/components/Tankopedia/ShotDisplaySection.tsx"
|
"../website/src/components/Tankopedia/ShotDisplaySection.tsx"
|
||||||
, "../website/src/components/Tankopedia/CharacteristicsSection/components/ConfigurationChildWrapper.tsx", "../website/src/components/Tankopedia/VideoSection.tsx" ]
|
, "../website/src/components/Tankopedia/CharacteristicsSection/components/ConfigurationChildWrapper.tsx", "../website/src/components/Tankopedia/VideoSection.tsx", "../website/src/components/DamageWarning.tsx", "../website/src/components/Controls.tsx", "../website/src/components/Compare/CompareTable.tsx" ]
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro check && astro build",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
import { asset } from '@blitzkit/core';
|
import { asset } from '@blitzkit/core';
|
||||||
import { Flex, Heading, IconButton, Table } from '@radix-ui/themes';
|
import { Flex, Heading, IconButton, Table } from '@radix-ui/themes';
|
||||||
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
|
import type { TankCharacteristics } from '../../core/blitzkit/tankCharacteristics';
|
||||||
import { TankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics';
|
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
||||||
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
|
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
|
||||||
import { CompareRow } from './CompareRow';
|
import { CompareRow } from './CompareRow';
|
||||||
import { CompareSectionTitle } from './CompareSectionTitle';
|
import { CompareSectionTitle } from './CompareSectionTitle';
|
||||||
|
|
||||||
+5
-5
@@ -4,11 +4,11 @@ import {
|
|||||||
CaretSortIcon,
|
CaretSortIcon,
|
||||||
} from '@radix-ui/react-icons';
|
} from '@radix-ui/react-icons';
|
||||||
import { Flex, IconButton, Table, Text } from '@radix-ui/themes';
|
import { Flex, IconButton, Table, Text } from '@radix-ui/themes';
|
||||||
import { StickyRowHeaderCell } from '../../../../components/StickyRowHeaderCell';
|
import type { TankCharacteristics } from '../../core/blitzkit/tankCharacteristics';
|
||||||
import { TankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics';
|
import { Var } from '../../core/radix/var';
|
||||||
import { Var } from '../../../../core/radix/var';
|
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
||||||
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
|
import { ComparePersistent } from '../../stores/comparePersistent';
|
||||||
import * as ComparePersistent from '../../../../stores/comparePersistent';
|
import { StickyRowHeaderCell } from '../StickyRowHeaderCell';
|
||||||
|
|
||||||
interface CompareRowProps {
|
interface CompareRowProps {
|
||||||
name: string;
|
name: string;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import { Heading, Table } from '@radix-ui/themes';
|
import { Heading, Table } from '@radix-ui/themes';
|
||||||
import { times } from 'lodash-es';
|
import { times } from 'lodash-es';
|
||||||
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
|
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
||||||
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
|
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
|
||||||
|
|
||||||
export function CompareSectionTitle({ children }: { children: string }) {
|
export function CompareSectionTitle({ children }: { children: string }) {
|
||||||
const memberCount = CompareEphemeral.use((state) => state.members.length);
|
const memberCount = CompareEphemeral.use((state) => state.members.length);
|
||||||
+18
-18
@@ -1,29 +1,28 @@
|
|||||||
import {
|
import {
|
||||||
asset,
|
asset,
|
||||||
availableProvisions,
|
availableProvisions,
|
||||||
checkConsumableProvisionInclusivity,
|
|
||||||
consumableDefinitions,
|
consumableDefinitions,
|
||||||
equipmentDefinitions,
|
equipmentDefinitions,
|
||||||
permanentSkills,
|
permanentSkills,
|
||||||
provisionDefinitions,
|
provisionDefinitions,
|
||||||
skillDefinitions,
|
skillDefinitions,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
|
import { checkConsumableProvisionInclusivity } from '@blitzkit/core/src/blitzkit/checkConsumableProvisionInclusivity';
|
||||||
import { ComponentPlaceholderIcon } from '@radix-ui/react-icons';
|
import { ComponentPlaceholderIcon } from '@radix-ui/react-icons';
|
||||||
import { Button, Flex, Popover, Slider, Table, Text } from '@radix-ui/themes';
|
import { Button, Flex, Popover, Slider, Table, Text } from '@radix-ui/themes';
|
||||||
import { debounce, times } from 'lodash-es';
|
import { debounce, times } from 'lodash-es';
|
||||||
import { use } from 'react';
|
import type { TankCharacteristics } from '../../core/blitzkit/tankCharacteristics';
|
||||||
import { BlitzkitButtonGrayIcon } from '../../../../components/BlitzkitButtonGrayIcon';
|
import { Var } from '../../core/radix/var';
|
||||||
import { ConsumablesManager } from '../../../../components/ConsumablesManager';
|
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
||||||
import { CrewSkillManager } from '../../../../components/CrewSkillManager';
|
import type { EquipmentMatrix } from '../../stores/duel';
|
||||||
import { EquipmentManager } from '../../../../components/EquipmentManager';
|
import { BlitzkitButtonGrayIcon } from '../BlitzkitButtonGrayIcon';
|
||||||
import { ModuleManager } from '../../../../components/ModuleManager';
|
import { ConsumablesManager } from '../ConsumablesManager';
|
||||||
import { ProvisionsManager } from '../../../../components/ProvisionsManager';
|
import { CrewSkillManager } from '../CrewSkillManager';
|
||||||
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
|
import { EquipmentManager } from '../EquipmentManager';
|
||||||
import { StickyTableRoot } from '../../../../components/StickyTableRoot';
|
import { ModuleManager } from '../ModuleManager';
|
||||||
import { TankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics';
|
import { ProvisionsManager } from '../ProvisionsManager';
|
||||||
import { Var } from '../../../../core/radix/var';
|
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
|
||||||
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
|
import { StickyTableRoot } from '../StickyTableRoot';
|
||||||
import { EquipmentMatrix } from '../../../../stores/duel';
|
|
||||||
import { Body } from './Body';
|
import { Body } from './Body';
|
||||||
import { InsertionMarker } from './IntersectionMarker';
|
import { InsertionMarker } from './IntersectionMarker';
|
||||||
import { TankCard } from './TankCard';
|
import { TankCard } from './TankCard';
|
||||||
@@ -32,14 +31,15 @@ interface CompareTableProps {
|
|||||||
stats: TankCharacteristics[];
|
stats: TankCharacteristics[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const awaitedSkillDefinitions = await skillDefinitions;
|
||||||
|
const awaitedEquipmentDefinitions = await equipmentDefinitions;
|
||||||
|
const awaitedConsumableDefinitions = await consumableDefinitions;
|
||||||
|
const awaitedProvisionDefinitions = await provisionDefinitions;
|
||||||
|
|
||||||
export function CompareTable({ stats }: CompareTableProps) {
|
export function CompareTable({ stats }: CompareTableProps) {
|
||||||
const crewSkills = CompareEphemeral.use((state) => state.crewSkills);
|
const crewSkills = CompareEphemeral.use((state) => state.crewSkills);
|
||||||
const members = CompareEphemeral.use((state) => state.members);
|
const members = CompareEphemeral.use((state) => state.members);
|
||||||
const awaitedSkillDefinitions = use(skillDefinitions);
|
|
||||||
const mutateCompareEphemeral = CompareEphemeral.useMutation();
|
const mutateCompareEphemeral = CompareEphemeral.useMutation();
|
||||||
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
|
|
||||||
const awaitedConsumableDefinitions = use(consumableDefinitions);
|
|
||||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StickyTableRoot
|
<StickyTableRoot
|
||||||
+13
-16
@@ -1,23 +1,26 @@
|
|||||||
import { provisionDefinitions } from '@blitzkit/core';
|
import { provisionDefinitions } from '@blitzkit/core';
|
||||||
import { PlusIcon, TrashIcon } from '@radix-ui/react-icons';
|
import { PlusIcon, TrashIcon } from '@radix-ui/react-icons';
|
||||||
import { Button, Dialog, Flex, SegmentedControl } from '@radix-ui/themes';
|
import { Button, Dialog, Flex, SegmentedControl } from '@radix-ui/themes';
|
||||||
import { use } from 'react';
|
import { tankToCompareMember } from '../../core/blitzkit/tankToCompareMember';
|
||||||
import { tankToCompareMember } from '../../../../core/blitzkit/tankToCompareMember';
|
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
||||||
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
|
import {
|
||||||
import * as ComparePersistent from '../../../../stores/comparePersistent';
|
ComparePersistent,
|
||||||
import { TankSearch } from '../../tankopedia/components/TankSearch';
|
type DeltaMode,
|
||||||
|
} from '../../stores/comparePersistent';
|
||||||
|
import { TankSearch } from '../TankSearch';
|
||||||
|
|
||||||
interface ControlsProps {
|
interface ControlsProps {
|
||||||
addTankDialogOpen: boolean;
|
addTankDialogOpen: boolean;
|
||||||
onAddTankDialogOpenChange: (open: boolean) => void;
|
onAddTankDialogOpenChange: (open: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const awaitedProvisionDefinitions = await provisionDefinitions;
|
||||||
|
|
||||||
export function Controls({
|
export function Controls({
|
||||||
addTankDialogOpen,
|
addTankDialogOpen,
|
||||||
onAddTankDialogOpenChange,
|
onAddTankDialogOpenChange,
|
||||||
}: ControlsProps) {
|
}: ControlsProps) {
|
||||||
const deltaMode = ComparePersistent.use((state) => state.deltaMode);
|
const deltaMode = ComparePersistent.use((state) => state.deltaMode);
|
||||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
|
||||||
const mutateCompareEphemeral = CompareEphemeral.useMutation();
|
const mutateCompareEphemeral = CompareEphemeral.useMutation();
|
||||||
const mutateComparePersistent = ComparePersistent.useMutation();
|
const mutateComparePersistent = ComparePersistent.useMutation();
|
||||||
|
|
||||||
@@ -88,23 +91,17 @@ export function Controls({
|
|||||||
value={deltaMode}
|
value={deltaMode}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
mutateComparePersistent((draft) => {
|
mutateComparePersistent((draft) => {
|
||||||
draft.deltaMode = value as ComparePersistent.DeltaMode;
|
draft.deltaMode = value as DeltaMode;
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SegmentedControl.Item
|
<SegmentedControl.Item value={'none' satisfies DeltaMode}>
|
||||||
value={'none' satisfies ComparePersistent.DeltaMode}
|
|
||||||
>
|
|
||||||
No deltas
|
No deltas
|
||||||
</SegmentedControl.Item>
|
</SegmentedControl.Item>
|
||||||
<SegmentedControl.Item
|
<SegmentedControl.Item value={'percentage' satisfies DeltaMode}>
|
||||||
value={'percentage' satisfies ComparePersistent.DeltaMode}
|
|
||||||
>
|
|
||||||
Percentage
|
Percentage
|
||||||
</SegmentedControl.Item>
|
</SegmentedControl.Item>
|
||||||
<SegmentedControl.Item
|
<SegmentedControl.Item value={'absolute' satisfies DeltaMode}>
|
||||||
value={'absolute' satisfies ComparePersistent.DeltaMode}
|
|
||||||
>
|
|
||||||
Absolute
|
Absolute
|
||||||
</SegmentedControl.Item>
|
</SegmentedControl.Item>
|
||||||
</SegmentedControl.Root>
|
</SegmentedControl.Root>
|
||||||
File renamed without changes.
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { Var } from '../../../../../core/radix/var';
|
import { Var } from '../../../core/radix/var';
|
||||||
import { insertionMarkers } from './constants';
|
import { insertionMarkers } from './constants';
|
||||||
|
|
||||||
export function InsertionMarker({ index }: { index: number }) {
|
export function InsertionMarker({ index }: { index: number }) {
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
import { TankDefinition, tankIcon } from '@blitzkit/core';
|
import { type TankDefinition, tankIcon } from '@blitzkit/core';
|
||||||
import { Flex, Text } from '@radix-ui/themes';
|
import { Flex, Text } from '@radix-ui/themes';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { Vector2 } from 'three';
|
import { Vector2 } from 'three';
|
||||||
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
|
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
||||||
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
|
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
|
||||||
import { InsertionMarker } from './IntersectionMarker';
|
import { InsertionMarker } from './IntersectionMarker';
|
||||||
import { insertionMarkers } from './IntersectionMarker/constants';
|
import { insertionMarkers } from './IntersectionMarker/constants';
|
||||||
import { TankControl } from './TankControl';
|
import { TankControl } from './TankControl';
|
||||||
+6
-5
@@ -2,18 +2,19 @@ import { provisionDefinitions } from '@blitzkit/core';
|
|||||||
import { ExternalLinkIcon, LoopIcon, TrashIcon } from '@radix-ui/react-icons';
|
import { ExternalLinkIcon, LoopIcon, TrashIcon } from '@radix-ui/react-icons';
|
||||||
import { Dialog, Flex, IconButton } from '@radix-ui/themes';
|
import { Dialog, Flex, IconButton } from '@radix-ui/themes';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { use, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { tankToCompareMember } from '../../../../core/blitzkit/tankToCompareMember';
|
import { tankToCompareMember } from '../../core/blitzkit/tankToCompareMember';
|
||||||
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
|
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
||||||
import { TankSearch } from '../../tankopedia/components/TankSearch';
|
import { TankSearch } from '../TankSearch';
|
||||||
|
|
||||||
interface TankControlProps {
|
interface TankControlProps {
|
||||||
index: number;
|
index: number;
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const awaitedProvisionDefinitions = await provisionDefinitions;
|
||||||
|
|
||||||
export function TankControl({ index, id }: TankControlProps) {
|
export function TankControl({ index, id }: TankControlProps) {
|
||||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
|
||||||
const [switchTankDialogOpen, setSwitchTankDialogOpen] = useState(false);
|
const [switchTankDialogOpen, setSwitchTankDialogOpen] = useState(false);
|
||||||
const mutateCompareEphemeral = CompareEphemeral.useMutation();
|
const mutateCompareEphemeral = CompareEphemeral.useMutation();
|
||||||
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import { InfoCircledIcon } from '@radix-ui/react-icons';
|
import { InfoCircledIcon } from '@radix-ui/react-icons';
|
||||||
import { Callout } from '@radix-ui/themes';
|
import { Callout } from '@radix-ui/themes';
|
||||||
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
|
import { CompareEphemeral } from '../stores/compareEphemeral';
|
||||||
|
|
||||||
export function DamageWarning() {
|
export function DamageWarning() {
|
||||||
const members = CompareEphemeral.use((state) => state.members);
|
const members = CompareEphemeral.use((state) => state.members);
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
EngineDefinition,
|
|
||||||
GunDefinition,
|
|
||||||
ShellDefinition,
|
|
||||||
TankDefinition,
|
|
||||||
TIER_ROMAN_NUMERALS,
|
TIER_ROMAN_NUMERALS,
|
||||||
TrackDefinition,
|
type EngineDefinition,
|
||||||
TurretDefinition,
|
type GunDefinition,
|
||||||
|
type ShellDefinition,
|
||||||
|
type TankDefinition,
|
||||||
|
type TrackDefinition,
|
||||||
|
type TurretDefinition,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { DropdownMenu, Flex } from '@radix-ui/themes';
|
import { DropdownMenu, Flex } from '@radix-ui/themes';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ const isBranchNamed =
|
|||||||
<style>
|
<style>
|
||||||
.navbar {
|
.navbar {
|
||||||
height: var(--navbar-height);
|
height: var(--navbar-height);
|
||||||
margin-bottom: -1px;
|
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Table } from '@radix-ui/themes';
|
import { Table } from '@radix-ui/themes';
|
||||||
import { ColumnHeaderCellProps } from '@radix-ui/themes/dist/cjs/components/table';
|
import type { ColumnHeaderCellProps } from '@radix-ui/themes/src/components/table.js';
|
||||||
|
|
||||||
interface StickyColumnHeaderCellProps extends ColumnHeaderCellProps {
|
interface StickyColumnHeaderCellProps extends ColumnHeaderCellProps {
|
||||||
top?: number | string;
|
top?: number | string;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Table } from '@radix-ui/themes';
|
import { Table } from '@radix-ui/themes';
|
||||||
import { RowHeaderCellProps } from '@radix-ui/themes/dist/cjs/components/table';
|
import type { RowHeaderCellProps } from '@radix-ui/themes/src/components/table.js';
|
||||||
|
|
||||||
export function StickyRowHeaderCell({ style, ...props }: RowHeaderCellProps) {
|
export function StickyRowHeaderCell({ style, ...props }: RowHeaderCellProps) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Table } from '@radix-ui/themes';
|
import { Table } from '@radix-ui/themes';
|
||||||
import { RootProps } from '@radix-ui/themes/dist/cjs/components/table';
|
import type { RootProps } from '@radix-ui/themes/src/components/table.js';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
export function StickyTableRoot({ style, ...props }: RootProps) {
|
export function StickyTableRoot({ style, ...props }: RootProps) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { TankDefinition, tankIcon } from '@blitzkit/core';
|
import { type TankDefinition, tankIcon } from '@blitzkit/core';
|
||||||
|
import { Link } from '@radix-ui/themes';
|
||||||
import { classIcons } from './ClassIcon';
|
import { classIcons } from './ClassIcon';
|
||||||
import { ExperimentIcon } from './ExperimentIcon';
|
import { ExperimentIcon } from './ExperimentIcon';
|
||||||
import { Link } from './Link';
|
|
||||||
import { StickyRowHeaderCell } from './StickyRowHeaderCell';
|
import { StickyRowHeaderCell } from './StickyRowHeaderCell';
|
||||||
|
|
||||||
interface TankRowHeaderCellProps {
|
interface TankRowHeaderCellProps {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ProvisionDefinitions, TankDefinition } from '@blitzkit/core';
|
import type { ProvisionDefinitions, TankDefinition } from '@blitzkit/core';
|
||||||
import { uniqueId } from 'lodash-es';
|
import { uniqueId } from 'lodash-es';
|
||||||
import { CompareMember } from '../../stores/compareEphemeral';
|
import type { CompareMember } from '../../stores/compareEphemeral';
|
||||||
import { tankToDuelMember } from './tankToDuelMember';
|
import { tankToDuelMember } from './tankToDuelMember';
|
||||||
|
|
||||||
export function tankToCompareMember(
|
export function tankToCompareMember(
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
import ToolLayout from '../../../layouts/ToolLayout.astro';
|
||||||
|
import { Page } from './index';
|
||||||
|
---
|
||||||
|
|
||||||
|
<ToolLayout>
|
||||||
|
<Page client:load />
|
||||||
|
</ToolLayout>
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import {
|
||||||
|
equipmentDefinitions,
|
||||||
|
modelDefinitions,
|
||||||
|
provisionDefinitions,
|
||||||
|
} from '@blitzkit/core';
|
||||||
|
import { PlusIcon } from '@radix-ui/react-icons';
|
||||||
|
import { Box, Flex, Heading, IconButton, Text } from '@radix-ui/themes';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import { CompareTable } from '../../../components/Compare/CompareTable';
|
||||||
|
import { Controls } from '../../../components/Compare/Controls';
|
||||||
|
import { DamageWarning } from '../../../components/DamageWarning';
|
||||||
|
import { PageWrapper } from '../../../components/PageWrapper';
|
||||||
|
import { tankCharacteristics } from '../../../core/blitzkit/tankCharacteristics';
|
||||||
|
import { CompareEphemeral } from '../../../stores/compareEphemeral';
|
||||||
|
import { ComparePersistent } from '../../../stores/comparePersistent';
|
||||||
|
|
||||||
|
const awaitedModelDefinitions = await modelDefinitions;
|
||||||
|
const awaitedEquipmentDefinitions = await equipmentDefinitions;
|
||||||
|
const awaitedProvisionDefinitions = await provisionDefinitions;
|
||||||
|
|
||||||
|
export function Page() {
|
||||||
|
return (
|
||||||
|
<ComparePersistent.Provider>
|
||||||
|
<CompareEphemeral.Provider>
|
||||||
|
<Content />
|
||||||
|
</CompareEphemeral.Provider>
|
||||||
|
</ComparePersistent.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Content() {
|
||||||
|
const members = CompareEphemeral.use((state) => state.members);
|
||||||
|
const [addTankDialogOpen, setAddTankDialogOpen] = useState(false);
|
||||||
|
const crewSkills = CompareEphemeral.use((state) => state.crewSkills);
|
||||||
|
const stats = useMemo<ReturnType<typeof tankCharacteristics>[]>(
|
||||||
|
() =>
|
||||||
|
members.map((thisMember) =>
|
||||||
|
tankCharacteristics(
|
||||||
|
{
|
||||||
|
...thisMember,
|
||||||
|
crewSkills,
|
||||||
|
stockEngine: thisMember.tank.engines[0],
|
||||||
|
stockGun: thisMember.tank.turrets[0].guns[0],
|
||||||
|
stockTrack: thisMember.tank.tracks[0],
|
||||||
|
stockTurret: thisMember.tank.turrets[0],
|
||||||
|
applyReactiveArmor: members.some(
|
||||||
|
(member) =>
|
||||||
|
member.key !== thisMember.key &&
|
||||||
|
member.consumables.includes(33),
|
||||||
|
),
|
||||||
|
applyDynamicArmor: members.some(
|
||||||
|
(member) =>
|
||||||
|
member.key !== thisMember.key &&
|
||||||
|
member.consumables.includes(73),
|
||||||
|
),
|
||||||
|
applySpallLiner: members.some(
|
||||||
|
(member) =>
|
||||||
|
member.key !== thisMember.key &&
|
||||||
|
member.provisions.includes(101),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
equipmentDefinitions: awaitedEquipmentDefinitions,
|
||||||
|
provisionDefinitions: awaitedProvisionDefinitions,
|
||||||
|
tankModelDefinition: awaitedModelDefinitions[thisMember.tank.id],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[members, crewSkills],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageWrapper color="crimson" size="100%">
|
||||||
|
<Flex justify="center" gap="4" align="center" direction="column">
|
||||||
|
<DamageWarning />
|
||||||
|
<Controls
|
||||||
|
addTankDialogOpen={addTankDialogOpen}
|
||||||
|
onAddTankDialogOpenChange={setAddTankDialogOpen}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{members.length > 0 && (
|
||||||
|
<Flex justify="center">
|
||||||
|
<Box maxWidth="100%" position="relative">
|
||||||
|
<CompareTable stats={stats} />
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
right: 0,
|
||||||
|
top: 73,
|
||||||
|
transform: 'translate(50%, -50%)',
|
||||||
|
zIndex: 1,
|
||||||
|
}}
|
||||||
|
onClick={() => setAddTankDialogOpen(true)}
|
||||||
|
>
|
||||||
|
<PlusIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{members.length === 0 && (
|
||||||
|
<Flex
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
direction="column"
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
>
|
||||||
|
<Heading color="gray">No tanks selected</Heading>
|
||||||
|
<Text color="gray">
|
||||||
|
Press the <PlusIcon /> Add button to get started
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</PageWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -15,10 +15,9 @@ export interface CompareEphemeral {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
export const CompareEphemeral = createContextualStore(() =>
|
||||||
() =>
|
create<CompareEphemeral>()(() => ({
|
||||||
create<CompareEphemeral>()(() => ({
|
crewSkills: {},
|
||||||
crewSkills: {},
|
members: [],
|
||||||
members: [],
|
})),
|
||||||
})),
|
|
||||||
);
|
);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import lodash from 'lodash-es';
|
import * as lodash from 'lodash-es';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { createContextualStore } from '../core/zustand/createContextualStore';
|
import { createContextualStore } from '../core/zustand/createContextualStore';
|
||||||
@@ -8,17 +8,16 @@ export interface ComparePersistent {
|
|||||||
deltaMode: DeltaMode;
|
deltaMode: DeltaMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
export const ComparePersistent = createContextualStore(() =>
|
||||||
() =>
|
create<ComparePersistent>()(
|
||||||
create<ComparePersistent>()(
|
persist(
|
||||||
persist(
|
subscribeWithSelector<ComparePersistent>(() => ({
|
||||||
subscribeWithSelector<ComparePersistent>(() => ({
|
deltaMode: 'none',
|
||||||
deltaMode: 'none',
|
})),
|
||||||
})),
|
{
|
||||||
{
|
name: 'compare',
|
||||||
name: 'compare',
|
merge: (a, b) => lodash.merge(b, a),
|
||||||
merge: (a, b) => lodash.merge(b, a),
|
},
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
Reference in new issue
Block a user