mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: optimize info lines
This commit is contained in:
1 parent
94cba0c9ba
commit
525b9377cc
1 file changed
+143
-140
+143
-140
@@ -1,7 +1,7 @@
|
||||
import { createDefaultSkills } from '@blitzkit/core';
|
||||
import { Flex, Progress, Text } from '@radix-ui/themes';
|
||||
import { clamp } from 'lodash-es';
|
||||
import { useMemo, type ComponentProps, type ReactNode } from 'react';
|
||||
import { memo, useMemo, type ComponentProps, type ReactNode } from 'react';
|
||||
import { awaitableEquipmentDefinitions } from '../../../../../../core/awaitables/equipmentDefinitions';
|
||||
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
|
||||
import { awaitableProvisionDefinitions } from '../../../../../../core/awaitables/provisionDefinitions';
|
||||
@@ -48,148 +48,151 @@ const [
|
||||
awaitableSkillDefinitions,
|
||||
]);
|
||||
|
||||
export function InfoWithDelta({
|
||||
stats,
|
||||
indent,
|
||||
noRanking,
|
||||
deltaType,
|
||||
...props
|
||||
}: InfoWithDeltaProps) {
|
||||
const { strings } = useLocale();
|
||||
const relativeAgainst = TankopediaEphemeral.use(
|
||||
(state) => state.relativeAgainst,
|
||||
);
|
||||
const uhWhatDoICallThisVariable =
|
||||
typeof props.value === 'function'
|
||||
? props.value(stats)!
|
||||
: (stats[props.value] as number);
|
||||
const delta = useDelta(uhWhatDoICallThisVariable);
|
||||
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
||||
const shellIndex = Duel.use((state) =>
|
||||
state.protagonist.gun.gun_type!.value.base.shells.indexOf(
|
||||
state.protagonist.shell,
|
||||
),
|
||||
);
|
||||
const equipmentMatrix = Duel.use(
|
||||
(state) => state.protagonist.equipmentMatrix,
|
||||
);
|
||||
const others = useMemo(() => {
|
||||
const defaultSkills = createDefaultSkills(skillDefinitions);
|
||||
|
||||
return Object.values(tankDefinitions.tanks)
|
||||
.filter(
|
||||
(tank) =>
|
||||
(relativeAgainst === TankopediaRelativeAgainst.Class &&
|
||||
tank.tier === protagonistTank.tier &&
|
||||
tank.class === protagonistTank.class) ||
|
||||
(relativeAgainst === TankopediaRelativeAgainst.Tier &&
|
||||
tank.tier === protagonistTank.tier) ||
|
||||
relativeAgainst === TankopediaRelativeAgainst.All,
|
||||
)
|
||||
.map((tank) => {
|
||||
const thisTankModel = modelDefinitions.models[tank.id];
|
||||
const member = tankToDuelMember(
|
||||
tank,
|
||||
thisTankModel,
|
||||
provisionDefinitions,
|
||||
);
|
||||
|
||||
if (member.gun.gun_type!.value.base.shells[shellIndex] === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return tankCharacteristics(
|
||||
{
|
||||
applyDynamicArmor: false,
|
||||
applyReactiveArmor: false,
|
||||
applySpallLiner: false,
|
||||
camouflage: member.camouflage,
|
||||
consumables: member.consumables,
|
||||
crewSkills: defaultSkills,
|
||||
provisions: member.provisions,
|
||||
engine: member.engine,
|
||||
gun: member.gun,
|
||||
equipmentMatrix: equipmentMatrix,
|
||||
shell: member.gun.gun_type!.value.base.shells[shellIndex],
|
||||
stockEngine: tank.engines[0],
|
||||
stockGun: tank.turrets[0].guns[0],
|
||||
stockTrack: tank.tracks[0],
|
||||
stockTurret: tank.turrets[0],
|
||||
tank,
|
||||
track: member.track,
|
||||
turret: member.turret,
|
||||
assaultDistance: member.assaultDistance,
|
||||
},
|
||||
{
|
||||
equipmentDefinitions,
|
||||
provisionDefinitions,
|
||||
tankModelDefinition: modelDefinitions.models[tank.id],
|
||||
},
|
||||
);
|
||||
})
|
||||
.filter((tank) => {
|
||||
if (tank === undefined) return false;
|
||||
|
||||
const othersValue =
|
||||
typeof props.value === 'function'
|
||||
? props.value(tank)!
|
||||
: (tank[props.value] as number);
|
||||
|
||||
return othersValue !== undefined;
|
||||
}) as TankCharacteristics[];
|
||||
}, [relativeAgainst, shellIndex, equipmentMatrix]);
|
||||
const betterTanks = others.filter((tank) => {
|
||||
const othersValue =
|
||||
export const InfoWithDelta = memo<InfoWithDeltaProps>(
|
||||
({ stats, indent, noRanking, deltaType, ...props }) => {
|
||||
const { strings } = useLocale();
|
||||
const relativeAgainst = TankopediaEphemeral.use(
|
||||
(state) => state.relativeAgainst,
|
||||
);
|
||||
const uhWhatDoICallThisVariable =
|
||||
typeof props.value === 'function'
|
||||
? props.value(tank)!
|
||||
: (tank[props.value] as number);
|
||||
? props.value(stats)!
|
||||
: (stats[props.value] as number);
|
||||
const delta = useDelta(uhWhatDoICallThisVariable);
|
||||
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
||||
const shellIndex = Duel.use((state) =>
|
||||
state.protagonist.gun.gun_type!.value.base.shells.indexOf(
|
||||
state.protagonist.shell,
|
||||
),
|
||||
);
|
||||
const equipmentMatrix = Duel.use(
|
||||
(state) => state.protagonist.equipmentMatrix,
|
||||
);
|
||||
const others = useMemo(() => {
|
||||
const defaultSkills = createDefaultSkills(skillDefinitions);
|
||||
|
||||
if (othersValue === undefined) return false;
|
||||
return deltaType === 'lowerIsBetter'
|
||||
? othersValue < uhWhatDoICallThisVariable
|
||||
: othersValue > uhWhatDoICallThisVariable;
|
||||
});
|
||||
const goodness = (others.length - betterTanks.length) / others.length;
|
||||
let color: ComponentProps<typeof Progress>['color'];
|
||||
return Object.values(tankDefinitions.tanks)
|
||||
.filter(
|
||||
(tank) =>
|
||||
(relativeAgainst === TankopediaRelativeAgainst.Class &&
|
||||
tank.tier === protagonistTank.tier &&
|
||||
tank.class === protagonistTank.class) ||
|
||||
(relativeAgainst === TankopediaRelativeAgainst.Tier &&
|
||||
tank.tier === protagonistTank.tier) ||
|
||||
relativeAgainst === TankopediaRelativeAgainst.All,
|
||||
)
|
||||
.map((tank) => {
|
||||
const thisTankModel = modelDefinitions.models[tank.id];
|
||||
const member = tankToDuelMember(
|
||||
tank,
|
||||
thisTankModel,
|
||||
provisionDefinitions,
|
||||
);
|
||||
|
||||
if (goodness <= 0.25) color = 'red';
|
||||
else if (goodness <= 0.5) color = 'orange';
|
||||
else if (goodness <= 0.75) color = 'yellow';
|
||||
else color = 'green';
|
||||
if (
|
||||
member.gun.gun_type!.value.base.shells[shellIndex] === undefined
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex direction="column">
|
||||
<Info
|
||||
deltaType={deltaType}
|
||||
indent={indent}
|
||||
name={
|
||||
'name' in props
|
||||
? props.name
|
||||
: strings.website.tools.tankopedia.characteristics.values[
|
||||
props.value
|
||||
]
|
||||
}
|
||||
delta={delta}
|
||||
{...props}
|
||||
>
|
||||
{uhWhatDoICallThisVariable}
|
||||
</Info>
|
||||
return tankCharacteristics(
|
||||
{
|
||||
applyDynamicArmor: false,
|
||||
applyReactiveArmor: false,
|
||||
applySpallLiner: false,
|
||||
camouflage: member.camouflage,
|
||||
consumables: member.consumables,
|
||||
crewSkills: defaultSkills,
|
||||
provisions: member.provisions,
|
||||
engine: member.engine,
|
||||
gun: member.gun,
|
||||
equipmentMatrix: equipmentMatrix,
|
||||
shell: member.gun.gun_type!.value.base.shells[shellIndex],
|
||||
stockEngine: tank.engines[0],
|
||||
stockGun: tank.turrets[0].guns[0],
|
||||
stockTrack: tank.tracks[0],
|
||||
stockTurret: tank.turrets[0],
|
||||
tank,
|
||||
track: member.track,
|
||||
turret: member.turret,
|
||||
assaultDistance: member.assaultDistance,
|
||||
},
|
||||
{
|
||||
equipmentDefinitions,
|
||||
provisionDefinitions,
|
||||
tankModelDefinition: modelDefinitions.models[tank.id],
|
||||
},
|
||||
);
|
||||
})
|
||||
.filter((tank) => {
|
||||
if (tank === undefined) return false;
|
||||
|
||||
{!noRanking && (
|
||||
<Flex pl={indent ? '2' : '0'} align="center" gap="2">
|
||||
<Progress
|
||||
variant="soft"
|
||||
size="1"
|
||||
value={goodness * 100}
|
||||
color={color}
|
||||
style={{ height: '0.125rem', opacity: 0.5 }}
|
||||
/>
|
||||
const othersValue =
|
||||
typeof props.value === 'function'
|
||||
? props.value(tank)!
|
||||
: (tank[props.value] as number);
|
||||
|
||||
<Text color="gray" size="1">
|
||||
{clamp(betterTanks.length + 1, 1, others.length)} / {others.length}
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
return othersValue !== undefined;
|
||||
}) as TankCharacteristics[];
|
||||
}, [relativeAgainst, shellIndex, equipmentMatrix]);
|
||||
const betterTanks = others.filter((tank) => {
|
||||
const othersValue =
|
||||
typeof props.value === 'function'
|
||||
? props.value(tank)!
|
||||
: (tank[props.value] as number);
|
||||
|
||||
if (othersValue === undefined) return false;
|
||||
return deltaType === 'lowerIsBetter'
|
||||
? othersValue < uhWhatDoICallThisVariable
|
||||
: othersValue > uhWhatDoICallThisVariable;
|
||||
});
|
||||
const goodness = (others.length - betterTanks.length) / others.length;
|
||||
let color: ComponentProps<typeof Progress>['color'];
|
||||
|
||||
if (goodness <= 0.25) color = 'red';
|
||||
else if (goodness <= 0.5) color = 'orange';
|
||||
else if (goodness <= 0.75) color = 'yellow';
|
||||
else color = 'green';
|
||||
|
||||
return (
|
||||
<Flex direction="column">
|
||||
<Info
|
||||
deltaType={deltaType}
|
||||
indent={indent}
|
||||
name={
|
||||
'name' in props
|
||||
? props.name
|
||||
: strings.website.tools.tankopedia.characteristics.values[
|
||||
props.value
|
||||
]
|
||||
}
|
||||
delta={delta}
|
||||
{...props}
|
||||
>
|
||||
{uhWhatDoICallThisVariable}
|
||||
</Info>
|
||||
|
||||
{!noRanking && (
|
||||
<Flex pl={indent ? '2' : '0'} align="center" gap="2">
|
||||
<Progress
|
||||
variant="soft"
|
||||
size="1"
|
||||
value={goodness * 100}
|
||||
color={color}
|
||||
style={{ height: '0.125rem', opacity: 0.5 }}
|
||||
/>
|
||||
|
||||
<Text color="gray" size="1">
|
||||
{clamp(betterTanks.length + 1, 1, others.length)} /{' '}
|
||||
{others.length}
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
},
|
||||
|
||||
(a, b) =>
|
||||
(typeof a.value === 'function' ? a.value(a.stats) : a.stats[a.value]) ===
|
||||
(typeof b.value === 'function' ? b.value(b.stats) : b.stats[b.value]),
|
||||
);
|
||||
Reference in new issue
Block a user