mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
feat: cached styling
This commit is contained in:
1 parent
1d65dc755f
commit
ff4be57faf
5 files changed
+97
-89
No files matched your search
@@ -40,6 +40,7 @@
|
|||||||
"@resvg/resvg-js": "^2.4.1",
|
"@resvg/resvg-js": "^2.4.1",
|
||||||
"@types/three": "^0.160.0",
|
"@types/three": "^0.160.0",
|
||||||
"@vanilla-extract/css": "^1.13.0",
|
"@vanilla-extract/css": "^1.13.0",
|
||||||
|
"@vanilla-extract/dynamic": "^2.1.1",
|
||||||
"adm-zip": "^0.5.12",
|
"adm-zip": "^0.5.12",
|
||||||
"bepaint": "^0.1.0-beta.3",
|
"bepaint": "^0.1.0-beta.3",
|
||||||
"csv-parse": "^5.5.6",
|
"csv-parse": "^5.5.6",
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { createVar, style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const cardBackgroundVar = createVar();
|
||||||
|
|
||||||
|
export const card = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 'var(--space-2)',
|
||||||
|
background: cardBackgroundVar,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const image = style({
|
||||||
|
height: 64,
|
||||||
|
width: '100%',
|
||||||
|
objectPosition: 'center right',
|
||||||
|
objectFit: 'contain',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const classIcon = style({
|
||||||
|
width: '1em',
|
||||||
|
height: '1em',
|
||||||
|
minWidth: '1em',
|
||||||
|
minHeight: '1em',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const name = style({
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
});
|
||||||
@@ -1,49 +1,50 @@
|
|||||||
import { Flex, Link, Text } from '@radix-ui/themes';
|
import { Flex, Text } from '@radix-ui/themes';
|
||||||
import { use, useEffect, useMemo, useRef } from 'react';
|
import { Icon } from '@radix-ui/themes/dist/cjs/components/callout';
|
||||||
import { classIcons } from '../../../../components/ClassIcon';
|
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { Link } from '../../../../components/Link';
|
||||||
import { asset } from '../../../../core/blitzkit/asset';
|
import { asset } from '../../../../core/blitzkit/asset';
|
||||||
import { modelDefinitions } from '../../../../core/blitzkit/modelDefinitions';
|
|
||||||
import { resolveDpm } from '../../../../core/blitzkit/resolveDpm';
|
|
||||||
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
|
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
|
||||||
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
|
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
||||||
|
import * as styles from './TankCard.css';
|
||||||
|
|
||||||
interface TankCardProps {
|
interface TankCardProps {
|
||||||
tank: TankDefinition;
|
tank: TankDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TankCard({ tank }: TankCardProps) {
|
export function TankCard({ tank }: TankCardProps) {
|
||||||
const awaitedModelDefinitions = use(modelDefinitions);
|
// const awaitedModelDefinitions = use(modelDefinitions);
|
||||||
const Icon = classIcons[tank.class];
|
// const Icon = classIcons[tank.class];
|
||||||
const link = useRef<HTMLAnchorElement>(null);
|
const link = useRef<HTMLAnchorElement>(null);
|
||||||
const sortBy = useTankopediaFilters((state) => state.sort.by);
|
// const sortBy = useTankopediaFilters((state) => state.sort.by);
|
||||||
const discriminator = useMemo(() => {
|
// const discriminator = useMemo(() => {
|
||||||
if (sortBy.startsWith('meta')) return undefined;
|
// if (sortBy.startsWith('meta')) return undefined;
|
||||||
|
|
||||||
const turret = tank.turrets.at(-1)!;
|
// const turret = tank.turrets.at(-1)!;
|
||||||
const gun = turret.guns.at(-1)!;
|
// const gun = turret.guns.at(-1)!;
|
||||||
const shell = gun.shells[0];
|
// const shell = gun.shells[0];
|
||||||
const tracks = tank.tracks.at(-1)!;
|
// const tracks = tank.tracks.at(-1)!;
|
||||||
const tankModelDefinition = awaitedModelDefinitions[tank.id];
|
// const tankModelDefinition = awaitedModelDefinitions[tank.id];
|
||||||
|
|
||||||
switch (sortBy) {
|
// switch (sortBy) {
|
||||||
case 'fire.aimTime':
|
// case 'fire.aimTime':
|
||||||
return `${gun.aimTime.toFixed(2)}s`;
|
// return `${gun.aimTime.toFixed(2)}s`;
|
||||||
case 'fire.caliber':
|
// case 'fire.caliber':
|
||||||
return `${shell.caliber.toFixed(0)}mm`;
|
// return `${shell.caliber.toFixed(0)}mm`;
|
||||||
case 'fire.damage':
|
// case 'fire.damage':
|
||||||
return `${shell.damage.armor.toFixed(0)}hp`;
|
// return `${shell.damage.armor.toFixed(0)}hp`;
|
||||||
case 'fire.dispersionMoving':
|
// case 'fire.dispersionMoving':
|
||||||
return `+ ${tracks.dispersion.move.toFixed(3)}`;
|
// return `+ ${tracks.dispersion.move.toFixed(3)}`;
|
||||||
case 'fire.dispersionStill':
|
// case 'fire.dispersionStill':
|
||||||
return gun.dispersion.base.toFixed(3);
|
// return gun.dispersion.base.toFixed(3);
|
||||||
case 'fire.dpm':
|
// case 'fire.dpm':
|
||||||
return resolveDpm(gun, shell).toFixed(0);
|
// return resolveDpm(gun, shell).toFixed(0);
|
||||||
case 'fire.gunDepression':
|
// case 'fire.gunDepression':
|
||||||
return awaitedModelDefinitions;
|
// return awaitedModelDefinitions;
|
||||||
}
|
// }
|
||||||
}, [sortBy]);
|
// }, [sortBy]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = useTankopediaFilters.subscribe((filters) => {
|
const unsubscribe = useTankopediaFilters.subscribe((filters) => {
|
||||||
@@ -70,27 +71,12 @@ export function TankCard({ tank }: TankCardProps) {
|
|||||||
highContrast={tank.treeType === 'researchable'}
|
highContrast={tank.treeType === 'researchable'}
|
||||||
underline="hover"
|
underline="hover"
|
||||||
href={`/tools/tankopedia/${tank.id}`}
|
href={`/tools/tankopedia/${tank.id}`}
|
||||||
style={{
|
className={styles.card}
|
||||||
display: 'flex',
|
style={assignInlineVars({
|
||||||
flexDirection: 'column',
|
[styles.cardBackgroundVar]: `top left / contain no-repeat url(${asset(`flags/scratched/${tank.nation}.webp`)})`,
|
||||||
alignItems: 'center',
|
})}
|
||||||
gap: 'var(--space-2)',
|
|
||||||
background: `url(${asset(`flags/scratched/${tank.nation}.webp`)})`,
|
|
||||||
backgroundSize: 'contain',
|
|
||||||
backgroundRepeat: 'no-repeat',
|
|
||||||
backgroundPosition: 'top left',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<img
|
<img alt={tank.name} src={tankIcon(tank.id)} className={styles.image} />
|
||||||
alt={tank.name}
|
|
||||||
src={tankIcon(tank.id)}
|
|
||||||
height={64}
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
objectPosition: 'center right',
|
|
||||||
objectFit: 'contain',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
justify="center"
|
justify="center"
|
||||||
@@ -100,27 +86,13 @@ export function TankCard({ tank }: TankCardProps) {
|
|||||||
width="100%"
|
width="100%"
|
||||||
maxWidth="100%"
|
maxWidth="100%"
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon className={styles.classIcon} />
|
||||||
style={{
|
<Text align="center" className={styles.name}>
|
||||||
width: '1em',
|
|
||||||
height: '1em',
|
|
||||||
minWidth: '1em',
|
|
||||||
minHeight: '1em',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
align="center"
|
|
||||||
style={{
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{tank.name}
|
{tank.name}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{discriminator && (
|
{/* {discriminator && (
|
||||||
<Text
|
<Text
|
||||||
mt="-2"
|
mt="-2"
|
||||||
color="gray"
|
color="gray"
|
||||||
@@ -133,7 +105,7 @@ export function TankCard({ tank }: TankCardProps) {
|
|||||||
>
|
>
|
||||||
{discriminator}
|
{discriminator}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)} */}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+23
-19
@@ -2,25 +2,29 @@
|
|||||||
|
|
||||||
import { LinkProps, Link as RadixLink } from '@radix-ui/themes';
|
import { LinkProps, Link as RadixLink } from '@radix-ui/themes';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { forwardRef } from 'react';
|
||||||
|
|
||||||
export function Link({ href, onClick, ...props }: LinkProps) {
|
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
||||||
const router = useRouter();
|
({ href, onClick, ...props }, ref) => {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RadixLink
|
<RadixLink
|
||||||
href={href}
|
ref={ref}
|
||||||
onClick={(event) => {
|
href={href}
|
||||||
event.preventDefault();
|
onClick={(event) => {
|
||||||
if (href) {
|
event.preventDefault();
|
||||||
if (event.ctrlKey || event.metaKey) {
|
if (href) {
|
||||||
window.open(href);
|
if (event.ctrlKey || event.metaKey) {
|
||||||
} else {
|
window.open(href);
|
||||||
router.push(href);
|
} else {
|
||||||
|
router.push(href);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
onClick?.(event);
|
||||||
onClick?.(event);
|
}}
|
||||||
}}
|
{...props}
|
||||||
{...props}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
},
|
||||||
}
|
);
|
||||||
Reference in new issue
Block a user