From 1b88773e28b1672ab9cce7e8714cb8bf8f19811d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 5 Apr 2024 13:59:30 -0500 Subject: [PATCH] feat: nominal deltas --- .../tools/compare/components/TankControl.tsx | 13 ++-- src/app/tools/compare/page.tsx | 61 ++++++++++++++++--- src/components/EquipmentMatrixCompact.ts | 1 + src/stores/compare.ts | 32 ++++++++-- 4 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 src/components/EquipmentMatrixCompact.ts diff --git a/src/app/tools/compare/components/TankControl.tsx b/src/app/tools/compare/components/TankControl.tsx index 1dbe085b9..772e1cd41 100644 --- a/src/app/tools/compare/components/TankControl.tsx +++ b/src/app/tools/compare/components/TankControl.tsx @@ -8,7 +8,10 @@ import { Dialog, Flex, IconButton } from '@radix-ui/themes'; import { useState } from 'react'; import { TankDefinition } from '../../../../core/blitzkrieg/tankDefinitions'; import { tankToDuelMember } from '../../../../core/blitzkrieg/tankToDuelMember'; -import mutateCompare, { CompareMember } from '../../../../stores/compare'; +import { + CompareMember, + mutateCompareTemporary, +} from '../../../../stores/compare'; import { TankSearch } from '../../tankopedia/components/TankSearch'; interface TankControlProps { @@ -26,7 +29,7 @@ export function TankControl({ index, tank, members }: TankControlProps) { { - mutateCompare((draft) => { + mutateCompareTemporary((draft) => { const item = draft.members[index]; draft.members.splice(index, 1); draft.members.splice(index - 1, 0, item); @@ -39,7 +42,7 @@ export function TankControl({ index, tank, members }: TankControlProps) { { - mutateCompare((draft) => { + mutateCompareTemporary((draft) => { draft.members.splice(index, 1); }); }} @@ -67,7 +70,7 @@ export function TankControl({ index, tank, members }: TankControlProps) { { - mutateCompare((draft) => { + mutateCompareTemporary((draft) => { draft.members[index] = { ...tankToDuelMember(tank), crewSkills: {}, @@ -84,7 +87,7 @@ export function TankControl({ index, tank, members }: TankControlProps) { { - mutateCompare((draft) => { + mutateCompareTemporary((draft) => { const item = draft.members[index]; draft.members.splice(index, 1); draft.members.splice(index + 1, 0, item); diff --git a/src/app/tools/compare/page.tsx b/src/app/tools/compare/page.tsx index 81753e69c..0678f5864 100644 --- a/src/app/tools/compare/page.tsx +++ b/src/app/tools/compare/page.tsx @@ -22,7 +22,13 @@ import { tankDefinitions } from '../../../core/blitzkrieg/tankDefinitions'; import { tankIcon } from '../../../core/blitzkrieg/tankIcon'; import { tankToCompareMember } from '../../../core/blitzkrieg/tankToCompareMember'; import { theme } from '../../../stitches.config'; -import mutateCompare, { useCompare } from '../../../stores/compare'; +import { + DeltaMode, + mutateComparePersistent, + mutateCompareTemporary, + useComparePersistent, + useCompareTemporary, +} from '../../../stores/compare'; import { TankSearch } from '../tankopedia/components/TankSearch'; import { TankControl } from './components/TankControl'; @@ -32,11 +38,12 @@ export default function Page() { const awaitedTankDefinitions = use(tankDefinitions); const awaitedSkillDefinitions = use(skillDefinitions); const searchParams = useSearchParams(); - const members = useCompare((state) => state.members); + const members = useCompareTemporary((state) => state.members); const [addTankDialogOpen, setAddTankDialogOpen] = useState(false); const awaitedModelDefinitions = use(modelDefinitions); const awaitedEquipmentDefinitions = use(equipmentDefinitions); const awaitedProvisionDefinitions = use(provisionDefinitions); + const deltaMode = useComparePersistent((state) => state.deltaMode); const stats = useMemo( () => members.map((item) => @@ -84,7 +91,7 @@ export default function Page() { const tanksParam = searchParams.get('tanks'); if (tanksParam) { - mutateCompare((draft) => { + mutateCompareTemporary((draft) => { draft.members = tanksParam .split(',') .map(Number) @@ -104,6 +111,7 @@ export default function Page() { display, deltaType = 'higherIsBetter', decimals, + deltaNominalDisplay, }: { name: string; value: @@ -116,6 +124,7 @@ export default function Page() { ) => number | string | undefined; deltaType?: 'higherIsBetter' | 'lowerIsBetter'; decimals?: number; + deltaNominalDisplay?: (delta: number) => string | number; }) { const values = stats.map((stat) => typeof value === 'function' ? value(stat) : (stat[value] as number), @@ -136,6 +145,7 @@ export default function Page() { {values.map((value, index) => { + const delta = (value ?? 0) - (values[0] ?? 0); const deltaPercentage = (value ?? 1) / (values[0] ?? 1) - 1; const normalizedDeltaPercentage = Math.round( Math.min(100, Math.abs(deltaPercentage) * 2 * 100 + 25), @@ -163,6 +173,7 @@ export default function Page() { + + {delta !== 0 && ( + <> + {deltaMode === 'nominal' && ( + + ( + {`${delta > 0 ? '+' : ''}${ + deltaNominalDisplay + ? deltaNominalDisplay(delta) + : decimals === undefined + ? delta + : delta.toFixed(decimals) + }`} + ) + + )} + + )} ); @@ -208,12 +237,21 @@ export default function Page() { Delta:{' '} - - None - + { + mutateComparePersistent((draft) => { + draft.deltaMode = value as DeltaMode; + }); + }} + > + + None + + Percentage - + Nominal @@ -240,7 +278,7 @@ export default function Page() { { - mutateCompare((draft) => { + mutateCompareTemporary((draft) => { draft.members.push( tankToCompareMember(tank, awaitedSkillDefinitions), ); @@ -311,6 +349,7 @@ export default function Page() { .shellReloads!.map((reload) => reload.toFixed(2)) .join(', ') } + deltaNominalDisplay={(delta) => delta.toFixed(2)} /> {hasNonRegularGun && ( (stats.fireChance * 100).toFixed(0)} + deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)} /> (stats.camouflageStill * 100).toFixed(0)} + deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)} /> (stats.camouflageMoving * 100).toFixed(0)} + deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)} /> (stats.camouflageShootingStill * 100).toFixed(0) } + deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)} /> (stats.camouflageShootingMoving * 100).toFixed(0) } + deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)} /> (stats.camouflageCaughtOnFire * 100).toFixed(0) } + deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)} /> ; } -export interface Compare { +export interface CompareTemporary { members: CompareMember[]; } -export const useCompare = create()(() => ({ +export type DeltaMode = 'none' | 'percentage' | 'nominal'; +export interface ComparePersistent { + deltaMode: DeltaMode; +} + +export const useCompareTemporary = create()(() => ({ members: [], })); -export default function mutateCompare(recipe: (draft: Compare) => void) { - useCompare.setState(produce(recipe)); +export const useComparePersistent = create()( + persist( + subscribeWithSelector(() => ({ + deltaMode: 'none', + })), + { name: 'compare', merge: (a, b) => merge(b, a) }, + ), +); + +export function mutateCompareTemporary( + recipe: (draft: CompareTemporary) => void, +) { + useCompareTemporary.setState(produce(recipe)); +} + +export function mutateComparePersistent( + recipe: (draft: ComparePersistent) => void, +) { + useComparePersistent.setState(produce(recipe)); }