feat: perf

This commit is contained in:
TrèsAbhi committed 2024-06-21 14:03:20 -05:00
1 parent df8b32b7cd
commit a57734cdee
6 files changed
+225 -158

No files matched your search

+9 -122
View File
@@ -1,50 +1,25 @@
import {
Callout,
Flex,
Grid,
Heading,
Link,
Separator,
Text,
} from '@radix-ui/themes';
import { Callout, Flex } from '@radix-ui/themes';
import { range } from 'lodash';
import { memo, use } from 'react';
import { classIcons } from '../../../../components/ClassIcon';
import { ExperimentIcon } from '../../../../components/ExperimentIcon';
import { TANK_CLASSES } from '../../../../components/Tanks/components/Item/constants';
import { asset } from '../../../../core/blitzkit/asset';
import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions';
import {
Tier,
tanksDefinitionsArray,
} from '../../../../core/blitzkit/tankDefinitions';
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
import { TankopediaSearchPageFilters } from '../page';
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
import { treeTypeOrder } from './TankSearch/constants';
import { TierCard } from './TierCard';
interface ResultsProps {
filters: TankopediaSearchPageFilters;
}
export const Results = memo<ResultsProps>(({ filters }) => {
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
const tanksFiltered = awaitedTanksDefinitionsArray.filter((tank) => {
return (
(filters.tier === undefined || filters.tier === tank.tier) &&
(filters.nation === undefined || filters.nation === tank.nation) &&
(filters.class === undefined || filters.class === tank.class) &&
(filters.type === undefined || filters.type === tank.treeType) &&
(filters.testing === 'include' ||
(filters.testing === 'only' && tank.testing) ||
(filters.testing === 'exclude' && !tank.testing))
);
});
export const Results = memo(() => {
const tanks = use(tanksDefinitionsArray);
const awaitedGameDefinitions = use(gameDefinitions);
const testing = useTankopediaFilters((state) => state.testing);
return (
<Flex direction="column" gap="8" flexGrow="1">
{filters.testing === 'only' && (
{testing === 'only' && (
<Callout.Root color="amber" style={{ width: 'fit-content' }}>
<Callout.Icon>
<ExperimentIcon style={{ width: '1em', height: '1em' }} />
@@ -58,7 +33,7 @@ export const Results = memo<ResultsProps>(({ filters }) => {
{range(10, 0).map((tierUntyped) => {
const tier = tierUntyped as Tier;
const tierTanks = tanksFiltered
const tierTanks = tanks
.filter((tank) => tank.tier === tier)
.sort(
(a, b) =>
@@ -75,95 +50,7 @@ export const Results = memo<ResultsProps>(({ filters }) => {
awaitedGameDefinitions.nations.indexOf(b.nation),
);
if (tierTanks.length === 0) return null;
return (
<Flex key={tier} direction="column" gap="4">
<Flex align="center" mb="4" gap="4">
<Heading weight="regular">
Tier {TIER_ROMAN_NUMERALS[tier]}
</Heading>
<Separator style={{ flex: 1 }} />
</Flex>
<Grid
flexGrow="1"
columns="repeat(auto-fill, minmax(100px, 1fr))"
gap="2"
gapY="6"
>
{tierTanks.map((tank) => {
const Icon = classIcons[tank.class];
return (
<Link
key={tank.id}
size="1"
color={
tank.treeType === 'collector'
? 'blue'
: tank.treeType === 'premium'
? 'amber'
: 'gray'
}
highContrast={tank.treeType === 'researchable'}
underline="hover"
href={`/tools/tankopedia/${tank.id}`}
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 'var(--space-2)',
background: `url(${asset(`flags/scratched/${tank.nation}.webp`)})`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'top left',
}}
>
<img
alt={tank.name}
src={tankIcon(tank.id)}
height={64}
style={{
width: '100%',
objectPosition: 'center right',
objectFit: 'contain',
}}
/>
<Flex
justify="center"
gap="1"
align="center"
overflow="hidden"
width="100%"
maxWidth="100%"
>
<Icon
style={{
width: '1em',
height: '1em',
minWidth: '1em',
minHeight: '1em',
}}
/>
<Text
align="center"
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{tank.name}
</Text>
</Flex>
</Link>
);
})}
</Grid>
</Flex>
);
return <TierCard tanks={tierTanks} key={tier} tier={tier} />;
})}
</Flex>
);
@@ -0,0 +1,94 @@
import { Flex, Link, Text } from '@radix-ui/themes';
import { useEffect, useRef } from 'react';
import { classIcons } from '../../../../components/ClassIcon';
import { asset } from '../../../../core/blitzkit/asset';
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
interface TankCardProps {
tank: TankDefinition;
}
export function TankCard({ tank }: TankCardProps) {
const Icon = classIcons[tank.class];
const link = useRef<HTMLAnchorElement>(null);
useEffect(() => {
const unsubscribe = useTankopediaFilters.subscribe((filters) => {
if (!link.current) return;
const visible = tankopediaFilterTank(filters, tank);
link.current.style.display = visible ? 'flex' : 'none';
});
return unsubscribe;
}, []);
return (
<Link
ref={link}
size="1"
color={
tank.treeType === 'collector'
? 'blue'
: tank.treeType === 'premium'
? 'amber'
: 'gray'
}
highContrast={tank.treeType === 'researchable'}
underline="hover"
href={`/tools/tankopedia/${tank.id}`}
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 'var(--space-2)',
background: `url(${asset(`flags/scratched/${tank.nation}.webp`)})`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'top left',
}}
>
<img
alt={tank.name}
src={tankIcon(tank.id)}
height={64}
style={{
width: '100%',
objectPosition: 'center right',
objectFit: 'contain',
}}
/>
<Flex
justify="center"
gap="1"
align="center"
overflow="hidden"
width="100%"
maxWidth="100%"
>
<Icon
style={{
width: '1em',
height: '1em',
minWidth: '1em',
minHeight: '1em',
}}
/>
<Text
align="center"
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{tank.name}
</Text>
</Flex>
</Link>
);
}
@@ -0,0 +1,55 @@
import { Flex, Grid, Heading, Separator } from '@radix-ui/themes';
import { useEffect, useRef } from 'react';
import {
TankDefinition,
Tier,
} from '../../../../core/blitzkit/tankDefinitions';
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
import { TankCard } from './TankCard';
interface TierCardProps {
tier: Tier;
tanks: TankDefinition[];
}
export function TierCard({ tier, tanks }: TierCardProps) {
const container = useRef<HTMLDivElement>(null);
useEffect(() => {
const unsubscribe = useTankopediaFilters.subscribe((filters) => {
if (!container.current) return;
const visible = tanks.some((tank) => tankopediaFilterTank(filters, tank));
container.current.style.display = visible ? 'flex' : 'none';
});
return unsubscribe;
}, []);
return (
<Flex
ref={container}
direction="column"
gap="4"
display={tanks.length === 0 ? 'none' : 'flex'}
>
<Flex align="center" mb="4" gap="4">
<Heading weight="regular">Tier {TIER_ROMAN_NUMERALS[tier]}</Heading>
<Separator style={{ flex: 1 }} />
</Flex>
<Grid
flexGrow="1"
columns="repeat(auto-fill, minmax(100px, 1fr))"
gap="2"
gapY="6"
>
{tanks.map((tank) => (
<TankCard key={tank.id} tank={tank} />
))}
</Grid>
</Flex>
);
}