mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-28 21:19:52 +01:00
feat: skeleton loading
This commit is contained in:
1 parent
6c6cf6b76d
commit
574c789233
11 files changed
+160
-84
No files matched your search
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,13 @@
|
|||||||
|
import { Table } from '@radix-ui/themes';
|
||||||
|
import { times } from 'lodash';
|
||||||
|
import { RowLoader } from './RowLoader';
|
||||||
|
|
||||||
|
export function BodyLoader() {
|
||||||
|
return (
|
||||||
|
<Table.Body>
|
||||||
|
{times(10, (index) => (
|
||||||
|
<RowLoader key={index} />
|
||||||
|
))}
|
||||||
|
</Table.Body>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Table } from '@radix-ui/themes';
|
||||||
|
|
||||||
|
export function Header() {
|
||||||
|
return (
|
||||||
|
<Table.Header>
|
||||||
|
<Table.Row align="end">
|
||||||
|
<Table.ColumnHeaderCell>Tank</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Winrate
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Players
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Damage
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Survival
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
XP
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Kills
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Spots
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Accuracy
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Shots
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Hits
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Damage ratio
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Damage received
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Capture points
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
<Table.ColumnHeaderCell width="0" justify="center">
|
||||||
|
Dropped capture points
|
||||||
|
</Table.ColumnHeaderCell>
|
||||||
|
</Table.Row>
|
||||||
|
</Table.Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { InfoCircledIcon } from '@radix-ui/react-icons';
|
||||||
|
import { Callout, Flex } from '@radix-ui/themes';
|
||||||
|
import { use, useMemo } from 'react';
|
||||||
|
import { averageDefinitionsArray } from '../../../../core/blitzkit/averageDefinitions';
|
||||||
|
|
||||||
|
export function Info() {
|
||||||
|
const awaitedAverageDefinitionsArray = use(averageDefinitionsArray);
|
||||||
|
const samples = useMemo(
|
||||||
|
() => awaitedAverageDefinitionsArray.reduce((a, b) => a + b.samples, 0),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex justify="center">
|
||||||
|
<Callout.Root style={{ width: 'fit-content' }}>
|
||||||
|
<Callout.Icon>
|
||||||
|
<InfoCircledIcon />
|
||||||
|
</Callout.Icon>
|
||||||
|
<Callout.Text>
|
||||||
|
Based on {samples.toLocaleString()} players with at least 5,000 career
|
||||||
|
battles and 1 battle in the past 120 days. Stats displayed as an
|
||||||
|
average per battle. Updated daily.
|
||||||
|
</Callout.Text>
|
||||||
|
</Callout.Root>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { Skeleton, Table } from '@radix-ui/themes';
|
||||||
|
import { times } from 'lodash';
|
||||||
|
|
||||||
|
export function RowLoader() {
|
||||||
|
return (
|
||||||
|
<Table.Row>
|
||||||
|
<Table.RowHeaderCell>
|
||||||
|
<Skeleton height="100%" width="128px" />
|
||||||
|
</Table.RowHeaderCell>
|
||||||
|
|
||||||
|
{times(14, (index) => (
|
||||||
|
<Table.Cell key={index}>
|
||||||
|
<Skeleton height="1em" width="32px" />
|
||||||
|
</Table.Cell>
|
||||||
|
))}
|
||||||
|
</Table.Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Table } from '@radix-ui/themes';
|
||||||
|
import { Suspense, use, useMemo } from 'react';
|
||||||
|
import { averageDefinitionsArray } from '../../../../core/blitzkit/averageDefinitions';
|
||||||
|
import { tankDefinitions } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
|
import { RowLoader } from './RowLoader';
|
||||||
|
import { TankRow } from './TankRow';
|
||||||
|
|
||||||
|
export function Tanks() {
|
||||||
|
const awaitedTankDefinitions = use(tankDefinitions);
|
||||||
|
const awaitedAverageDefinitionsArray = use(averageDefinitionsArray);
|
||||||
|
const tankAverages = useMemo(
|
||||||
|
() => awaitedAverageDefinitionsArray.sort((a, b) => b.mu.wins - a.mu.wins),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table.Body>
|
||||||
|
{tankAverages.map((averages) => {
|
||||||
|
const tank = awaitedTankDefinitions[averages.id];
|
||||||
|
return (
|
||||||
|
<Suspense key={tank.id} fallback={<RowLoader />}>
|
||||||
|
<TankRow tank={tank} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Table.Body>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,94 +1,23 @@
|
|||||||
import { InfoCircledIcon } from '@radix-ui/react-icons';
|
import { Flex, Table } from '@radix-ui/themes';
|
||||||
import { Callout, Flex, Table } from '@radix-ui/themes';
|
import { Suspense } from 'react';
|
||||||
import { use, useMemo } from 'react';
|
|
||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { averageDefinitionsArray } from '../../../core/blitzkit/averageDefinitions';
|
import { Header } from './components/Header';
|
||||||
import { tankDefinitions } from '../../../core/blitzkit/tankDefinitions';
|
import { Info } from './components/Info';
|
||||||
import { TankRow } from './components/TankRow';
|
import { Tanks } from './components/Tanks';
|
||||||
|
import { BodyLoader } from './components/BodyLoader';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
|
||||||
const awaitedAverageDefinitionsArray = use(averageDefinitionsArray);
|
|
||||||
const tankAverages = useMemo(
|
|
||||||
() => awaitedAverageDefinitionsArray.sort((a, b) => b.mu.wins - a.mu.wins),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
const samples = useMemo(
|
|
||||||
() => awaitedAverageDefinitionsArray.reduce((a, b) => a + b.samples, 0),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper color="jade" noMaxWidth>
|
<PageWrapper color="jade" noMaxWidth>
|
||||||
<Flex justify="center">
|
<Info />
|
||||||
<Callout.Root style={{ width: 'fit-content' }}>
|
|
||||||
<Callout.Icon>
|
|
||||||
<InfoCircledIcon />
|
|
||||||
</Callout.Icon>
|
|
||||||
<Callout.Text>
|
|
||||||
Based on {samples.toLocaleString()} players with at least 5,000
|
|
||||||
career battles and 1 battle in the past 120 days. Stats displayed as
|
|
||||||
an average per battle. Updated daily.
|
|
||||||
</Callout.Text>
|
|
||||||
</Callout.Root>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Flex justify="center">
|
<Flex justify="center">
|
||||||
<Table.Root variant="surface" style={{ maxWidth: '100%' }}>
|
<Table.Root variant="surface" style={{ maxWidth: '100%' }}>
|
||||||
<Table.Header>
|
<Header />
|
||||||
<Table.Row align="end">
|
|
||||||
<Table.ColumnHeaderCell>Tank</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Winrate
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Players
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Damage
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Survival
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
XP
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Kills
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Spots
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Accuracy
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Shots
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Hits
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Damage ratio
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Damage received
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Capture points
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
<Table.ColumnHeaderCell width="0" justify="center">
|
|
||||||
Dropped capture points
|
|
||||||
</Table.ColumnHeaderCell>
|
|
||||||
</Table.Row>
|
|
||||||
</Table.Header>
|
|
||||||
|
|
||||||
<Table.Body>
|
<Suspense fallback={<BodyLoader />}>
|
||||||
{tankAverages.map((averages) => {
|
<Tanks />
|
||||||
const tank = awaitedTankDefinitions[averages.id];
|
</Suspense>
|
||||||
return <TankRow tank={tank} key={tank.id} />;
|
|
||||||
})}
|
|
||||||
</Table.Body>
|
|
||||||
</Table.Root>
|
</Table.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ interface TankRowHeaderCellProps {
|
|||||||
export function TankRowHeaderCell({ tank }: TankRowHeaderCellProps) {
|
export function TankRowHeaderCell({ tank }: TankRowHeaderCellProps) {
|
||||||
return (
|
return (
|
||||||
<Table.RowHeaderCell style={{ display: 'flex' }}>
|
<Table.RowHeaderCell style={{ display: 'flex' }}>
|
||||||
<Link href={`/tools/tankopedia/${tank.id}`}>
|
<Link href={`/tools/tankopedia/${tank.id}`} tabIndex={-1}>
|
||||||
<img
|
<img
|
||||||
alt={tank.name}
|
alt={tank.name}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import { Root } from 'protobufjs';
|
import { Root } from 'protobufjs';
|
||||||
|
import { context } from '../blitzkit/context';
|
||||||
|
|
||||||
export async function lookup(proto: string) {
|
export async function lookup(proto: string) {
|
||||||
|
const name = proto.split('.')[0];
|
||||||
const root = await new Root().load(
|
const root = await new Root().load(
|
||||||
`src/protos/${proto.split('.')[0]}.proto`,
|
context === 'server'
|
||||||
|
? `public/protos/${name}.proto`
|
||||||
|
: `/protos/${name}.proto`,
|
||||||
{ keepCase: true },
|
{ keepCase: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user