feat: progress on compare

This commit is contained in:
TrèsAbhi committed 2024-09-23 10:49:54 -05:00
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 { usePathname, useRouter, useSearchParams } from 'next/navigation';
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 { tankCharacteristics } from '../../../core/blitzkit/tankCharacteristics';
import { tankToCompareMember } from '../../../core/blitzkit/tankToCompareMember';
import * as CompareEphemeral from '../../../stores/compareEphemeral';
import { CompareTable } from './components/CompareTable';
import { Controls } from './components/Controls';
import { DamageWarning } from './components/DamageWarning';
import { CompareTable } from '../../../../../website/src/components/Compare/CompareTable';
export default function Page() {
const pathname = usePathname();
@@ -116,7 +116,7 @@ export default function Page() {
<PageWrapper color="crimson" size="100%">
<Flex justify="center" gap="4" align="center" direction="column">
<DamageWarning />
<Controls
<CompareControls
addTankDialogOpen={addTankDialogOpen}
onAddTankDialogOpenChange={setAddTankDialogOpen}
/>
+1 -1
View File
@@ -18,5 +18,5 @@
"../website/src/components/Tankopedia/HistorySection.tsx",
"../website/src/components/Tankopedia/CalloutsSection.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" ]
}
+1 -1
View File
@@ -4,7 +4,7 @@
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro"
},
@@ -1,8 +1,8 @@
import { asset } from '@blitzkit/core';
import { Flex, Heading, IconButton, Table } from '@radix-ui/themes';
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
import { TankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics';
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
import type { TankCharacteristics } from '../../core/blitzkit/tankCharacteristics';
import { CompareEphemeral } from '../../stores/compareEphemeral';
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
import { CompareRow } from './CompareRow';
import { CompareSectionTitle } from './CompareSectionTitle';
@@ -4,11 +4,11 @@ import {
CaretSortIcon,
} from '@radix-ui/react-icons';
import { Flex, IconButton, Table, Text } from '@radix-ui/themes';
import { StickyRowHeaderCell } from '../../../../components/StickyRowHeaderCell';
import { TankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics';
import { Var } from '../../../../core/radix/var';
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
import * as ComparePersistent from '../../../../stores/comparePersistent';
import type { TankCharacteristics } from '../../core/blitzkit/tankCharacteristics';
import { Var } from '../../core/radix/var';
import { CompareEphemeral } from '../../stores/compareEphemeral';
import { ComparePersistent } from '../../stores/comparePersistent';
import { StickyRowHeaderCell } from '../StickyRowHeaderCell';
interface CompareRowProps {
name: string;
@@ -1,7 +1,7 @@
import { Heading, Table } from '@radix-ui/themes';
import { times } from 'lodash-es';
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
import { CompareEphemeral } from '../../stores/compareEphemeral';
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
export function CompareSectionTitle({ children }: { children: string }) {
const memberCount = CompareEphemeral.use((state) => state.members.length);
@@ -1,29 +1,28 @@
import {
asset,
availableProvisions,
checkConsumableProvisionInclusivity,
consumableDefinitions,
equipmentDefinitions,
permanentSkills,
provisionDefinitions,
skillDefinitions,
} from '@blitzkit/core';
import { checkConsumableProvisionInclusivity } from '@blitzkit/core/src/blitzkit/checkConsumableProvisionInclusivity';
import { ComponentPlaceholderIcon } from '@radix-ui/react-icons';
import { Button, Flex, Popover, Slider, Table, Text } from '@radix-ui/themes';
import { debounce, times } from 'lodash-es';
import { use } from 'react';
import { BlitzkitButtonGrayIcon } from '../../../../components/BlitzkitButtonGrayIcon';
import { ConsumablesManager } from '../../../../components/ConsumablesManager';
import { CrewSkillManager } from '../../../../components/CrewSkillManager';
import { EquipmentManager } from '../../../../components/EquipmentManager';
import { ModuleManager } from '../../../../components/ModuleManager';
import { ProvisionsManager } from '../../../../components/ProvisionsManager';
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
import { StickyTableRoot } from '../../../../components/StickyTableRoot';
import { TankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics';
import { Var } from '../../../../core/radix/var';
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
import { EquipmentMatrix } from '../../../../stores/duel';
import type { TankCharacteristics } from '../../core/blitzkit/tankCharacteristics';
import { Var } from '../../core/radix/var';
import { CompareEphemeral } from '../../stores/compareEphemeral';
import type { EquipmentMatrix } from '../../stores/duel';
import { BlitzkitButtonGrayIcon } from '../BlitzkitButtonGrayIcon';
import { ConsumablesManager } from '../ConsumablesManager';
import { CrewSkillManager } from '../CrewSkillManager';
import { EquipmentManager } from '../EquipmentManager';
import { ModuleManager } from '../ModuleManager';
import { ProvisionsManager } from '../ProvisionsManager';
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
import { StickyTableRoot } from '../StickyTableRoot';
import { Body } from './Body';
import { InsertionMarker } from './IntersectionMarker';
import { TankCard } from './TankCard';
@@ -32,14 +31,15 @@ interface CompareTableProps {
stats: TankCharacteristics[];
}
const awaitedSkillDefinitions = await skillDefinitions;
const awaitedEquipmentDefinitions = await equipmentDefinitions;
const awaitedConsumableDefinitions = await consumableDefinitions;
const awaitedProvisionDefinitions = await provisionDefinitions;
export function CompareTable({ stats }: CompareTableProps) {
const crewSkills = CompareEphemeral.use((state) => state.crewSkills);
const members = CompareEphemeral.use((state) => state.members);
const awaitedSkillDefinitions = use(skillDefinitions);
const mutateCompareEphemeral = CompareEphemeral.useMutation();
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
const awaitedConsumableDefinitions = use(consumableDefinitions);
const awaitedProvisionDefinitions = use(provisionDefinitions);
return (
<StickyTableRoot
@@ -1,23 +1,26 @@
import { provisionDefinitions } from '@blitzkit/core';
import { PlusIcon, TrashIcon } from '@radix-ui/react-icons';
import { Button, Dialog, Flex, SegmentedControl } from '@radix-ui/themes';
import { use } from 'react';
import { tankToCompareMember } from '../../../../core/blitzkit/tankToCompareMember';
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
import * as ComparePersistent from '../../../../stores/comparePersistent';
import { TankSearch } from '../../tankopedia/components/TankSearch';
import { tankToCompareMember } from '../../core/blitzkit/tankToCompareMember';
import { CompareEphemeral } from '../../stores/compareEphemeral';
import {
ComparePersistent,
type DeltaMode,
} from '../../stores/comparePersistent';
import { TankSearch } from '../TankSearch';
interface ControlsProps {
addTankDialogOpen: boolean;
onAddTankDialogOpenChange: (open: boolean) => void;
}
const awaitedProvisionDefinitions = await provisionDefinitions;
export function Controls({
addTankDialogOpen,
onAddTankDialogOpenChange,
}: ControlsProps) {
const deltaMode = ComparePersistent.use((state) => state.deltaMode);
const awaitedProvisionDefinitions = use(provisionDefinitions);
const mutateCompareEphemeral = CompareEphemeral.useMutation();
const mutateComparePersistent = ComparePersistent.useMutation();
@@ -88,23 +91,17 @@ export function Controls({
value={deltaMode}
onValueChange={(value) => {
mutateComparePersistent((draft) => {
draft.deltaMode = value as ComparePersistent.DeltaMode;
draft.deltaMode = value as DeltaMode;
});
}}
>
<SegmentedControl.Item
value={'none' satisfies ComparePersistent.DeltaMode}
>
<SegmentedControl.Item value={'none' satisfies DeltaMode}>
No deltas
</SegmentedControl.Item>
<SegmentedControl.Item
value={'percentage' satisfies ComparePersistent.DeltaMode}
>
<SegmentedControl.Item value={'percentage' satisfies DeltaMode}>
Percentage
</SegmentedControl.Item>
<SegmentedControl.Item
value={'absolute' satisfies ComparePersistent.DeltaMode}
>
<SegmentedControl.Item value={'absolute' satisfies DeltaMode}>
Absolute
</SegmentedControl.Item>
</SegmentedControl.Root>
@@ -1,5 +1,5 @@
import { useEffect, useRef } from 'react';
import { Var } from '../../../../../core/radix/var';
import { Var } from '../../../core/radix/var';
import { insertionMarkers } from './constants';
export function InsertionMarker({ index }: { index: number }) {
@@ -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 { useEffect, useRef } from 'react';
import { Vector2 } from 'three';
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
import { CompareEphemeral } from '../../stores/compareEphemeral';
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
import { InsertionMarker } from './IntersectionMarker';
import { insertionMarkers } from './IntersectionMarker/constants';
import { TankControl } from './TankControl';
@@ -2,18 +2,19 @@ import { provisionDefinitions } from '@blitzkit/core';
import { ExternalLinkIcon, LoopIcon, TrashIcon } from '@radix-ui/react-icons';
import { Dialog, Flex, IconButton } from '@radix-ui/themes';
import Link from 'next/link';
import { use, useState } from 'react';
import { tankToCompareMember } from '../../../../core/blitzkit/tankToCompareMember';
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
import { TankSearch } from '../../tankopedia/components/TankSearch';
import { useState } from 'react';
import { tankToCompareMember } from '../../core/blitzkit/tankToCompareMember';
import { CompareEphemeral } from '../../stores/compareEphemeral';
import { TankSearch } from '../TankSearch';
interface TankControlProps {
index: number;
id: number;
}
const awaitedProvisionDefinitions = await provisionDefinitions;
export function TankControl({ index, id }: TankControlProps) {
const awaitedProvisionDefinitions = use(provisionDefinitions);
const [switchTankDialogOpen, setSwitchTankDialogOpen] = useState(false);
const mutateCompareEphemeral = CompareEphemeral.useMutation();
@@ -1,6 +1,6 @@
import { InfoCircledIcon } from '@radix-ui/react-icons';
import { Callout } from '@radix-ui/themes';
import * as CompareEphemeral from '../../../../stores/compareEphemeral';
import { CompareEphemeral } from '../stores/compareEphemeral';
export function DamageWarning() {
const members = CompareEphemeral.use((state) => state.members);
@@ -1,11 +1,11 @@
import {
EngineDefinition,
GunDefinition,
ShellDefinition,
TankDefinition,
TIER_ROMAN_NUMERALS,
TrackDefinition,
TurretDefinition,
type EngineDefinition,
type GunDefinition,
type ShellDefinition,
type TankDefinition,
type TrackDefinition,
type TurretDefinition,
} from '@blitzkit/core';
import { DropdownMenu, Flex } from '@radix-ui/themes';
import { useState } from 'react';
@@ -32,7 +32,6 @@ const isBranchNamed =
<style>
.navbar {
height: var(--navbar-height);
margin-bottom: -1px;
position: sticky;
top: 0;
z-index: 1;
@@ -1,5 +1,5 @@
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 {
top?: number | string;
@@ -1,5 +1,5 @@
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) {
return (
@@ -1,5 +1,5 @@
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';
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 { ExperimentIcon } from './ExperimentIcon';
import { Link } from './Link';
import { StickyRowHeaderCell } from './StickyRowHeaderCell';
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 { CompareMember } from '../../stores/compareEphemeral';
import type { CompareMember } from '../../stores/compareEphemeral';
import { tankToDuelMember } from './tankToDuelMember';
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(
() =>
create<CompareEphemeral>()(() => ({
crewSkills: {},
members: [],
})),
export const CompareEphemeral = createContextualStore(() =>
create<CompareEphemeral>()(() => ({
crewSkills: {},
members: [],
})),
);
@@ -1,4 +1,4 @@
import lodash from 'lodash-es';
import * as lodash from 'lodash-es';
import { create } from 'zustand';
import { persist, subscribeWithSelector } from 'zustand/middleware';
import { createContextualStore } from '../core/zustand/createContextualStore';
@@ -8,17 +8,16 @@ export interface ComparePersistent {
deltaMode: DeltaMode;
}
export const { Provider, use, useMutation, useStore } = createContextualStore(
() =>
create<ComparePersistent>()(
persist(
subscribeWithSelector<ComparePersistent>(() => ({
deltaMode: 'none',
})),
{
name: 'compare',
merge: (a, b) => lodash.merge(b, a),
},
),
export const ComparePersistent = createContextualStore(() =>
create<ComparePersistent>()(
persist(
subscribeWithSelector<ComparePersistent>(() => ({
deltaMode: 'none',
})),
{
name: 'compare',
merge: (a, b) => lodash.merge(b, a),
},
),
),
);