From 7b650bf39bd8c6ca07e04a05420ec8e9b81bbe93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 28 Apr 2026 15:31:21 -0500 Subject: [PATCH] feat: incremental loader Co-authored-by: Copilot --- .../src/components/Skeleton/index.css | 4 +- .../src/components/TankCard/index.module.css | 12 ++--- .../src/components/TankCard/index.tsx | 50 ++++++++++++------- .../src/pages/[...locale]/tanks/_index.tsx | 30 ++++++++--- .../website-ue/src/types/propsWithSkeleton.ts | 2 +- 5 files changed, 62 insertions(+), 36 deletions(-) diff --git a/packages/website-ue/src/components/Skeleton/index.css b/packages/website-ue/src/components/Skeleton/index.css index 4596ff8fd..2eb07b403 100644 --- a/packages/website-ue/src/components/Skeleton/index.css +++ b/packages/website-ue/src/components/Skeleton/index.css @@ -1,12 +1,12 @@ @keyframes skeleton-animation { 0% { - background-color: var(--black-a8); + background-color: var(--black-a6); } 50% { background-color: var(--black-a5); } 100% { - background-color: var(--black-a8); + background-color: var(--black-a6); } } diff --git a/packages/website-ue/src/components/TankCard/index.module.css b/packages/website-ue/src/components/TankCard/index.module.css index 7f2e31dcf..9c3555cb4 100644 --- a/packages/website-ue/src/components/TankCard/index.module.css +++ b/packages/website-ue/src/components/TankCard/index.module.css @@ -31,19 +31,17 @@ background-size: 140%; background-position: 40% center; - - .cover { - width: 100%; - height: 100%; - background: linear-gradient(transparent 75%, var(--gray-1)); - } } } .name { white-space: nowrap; overflow: hidden; - max-width: 100%; + width: 100%; text-overflow: ellipsis; + + .skeleton { + width: 100%; + } } } diff --git a/packages/website-ue/src/components/TankCard/index.tsx b/packages/website-ue/src/components/TankCard/index.tsx index fb110e90e..9241bc4f7 100644 --- a/packages/website-ue/src/components/TankCard/index.tsx +++ b/packages/website-ue/src/components/TankCard/index.tsx @@ -2,7 +2,10 @@ import { api } from "../../core/api/dynamic"; import { useAwait } from "../../hooks/useAwait"; import { useGameStrings } from "../../hooks/useGameStrings"; import { useLocale } from "../../hooks/useLocale"; +import type { PropsWithSkeleton } from "../../types/propsWithSkeleton"; +import { InlineSkeleton } from "../InlineSkeleton"; import { LinkI18n } from "../LinkI18n"; +import { Skeleton } from "../Skeleton"; import { Text } from "../Text"; import styles from "./index.module.css"; @@ -11,37 +14,46 @@ interface TankCardProps { subtitle?: string; } -export function TankCard({ id }: TankCardProps) { - const tank = useAwait(() => api.tank(id), `tank-${id}`); - const gameStrings = useGameStrings("TankEntity"); +export function TankCard(props: PropsWithSkeleton) { + const tank = props.skeleton + ? undefined + : useAwait(() => api.tank(props.id), `tank-${props.id}`); + const gameStrings = props.skeleton ? undefined : useGameStrings("TankEntity"); const locale = useLocale(); return (
-
+ {!props.skeleton && ( +
+ )} -
-
-
+ {!props.skeleton && ( +
+ )} + + {props.skeleton && }
- {gameStrings[tank.tank!.name!.value]} + + {props.skeleton && } + {!props.skeleton && gameStrings![tank!.tank!.name!.value]} + ); } diff --git a/packages/website-ue/src/pages/[...locale]/tanks/_index.tsx b/packages/website-ue/src/pages/[...locale]/tanks/_index.tsx index ccbaf2fb5..70d04d200 100644 --- a/packages/website-ue/src/pages/[...locale]/tanks/_index.tsx +++ b/packages/website-ue/src/pages/[...locale]/tanks/_index.tsx @@ -1,5 +1,6 @@ import fuzzysort from "fuzzysort"; import { useMemo } from "react"; +import { IncrementalLoader } from "../../../components/IncrementalLoader"; import { TankCard } from "../../../components/TankCard"; import { TankCards } from "../../../components/TankCards"; import { TankSearch } from "../../../components/TankSearch"; @@ -41,7 +42,7 @@ function Content() { compareTiers(a.tank!.tier_catalog_id, b.tank!.tier_catalog_id), ); - return list; + return list.map(({ id }) => id); }, []); const tanksFiltered = useMemo(() => { if (!search) return tanksOrdered; @@ -50,17 +51,32 @@ function Content() { keys: ["id", "name", "deburred"], }); - return results.map(({ obj }) => obj); + return results.map(({ obj }) => obj.id); }, [search]); return ( <> - - {tanksFiltered.slice(0, 32).map(({ id }) => ( - - ))} - + ); } + +interface ListProps { + tanks: string[]; +} + +function List({ tanks }: ListProps) { + const data = useMemo(() => tanks.map((id) => ({ key: id, id })), [tanks]); + + return ( + + + + ); +} diff --git a/packages/website-ue/src/types/propsWithSkeleton.ts b/packages/website-ue/src/types/propsWithSkeleton.ts index c367c9c52..9ab5a307c 100644 --- a/packages/website-ue/src/types/propsWithSkeleton.ts +++ b/packages/website-ue/src/types/propsWithSkeleton.ts @@ -1,3 +1,3 @@ export type PropsWithSkeleton = - | { skeleton: true } + | { skeleton: true; onIntersection?: () => void } | (Props & { skeleton?: false });