mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: skeletons
This commit is contained in:
1 parent
fe945cced1
commit
798ef10469
8 files changed
+78
-44
No files matched your search
@@ -0,0 +1,30 @@
|
|||||||
|
import { Flex, Link, Text } from '@radix-ui/themes';
|
||||||
|
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
||||||
|
|
||||||
|
interface NoResultsProps {
|
||||||
|
type?: 'filters' | 'search';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NoResults({ type = 'filters' }: NoResultsProps) {
|
||||||
|
return (
|
||||||
|
<Flex flexGrow="1" align="center" justify="center">
|
||||||
|
<Text color="gray">
|
||||||
|
No tanks found.{' '}
|
||||||
|
<Link
|
||||||
|
href="#"
|
||||||
|
underline="always"
|
||||||
|
color="red"
|
||||||
|
onClick={() =>
|
||||||
|
useTankopediaFilters.setState(
|
||||||
|
useTankopediaFilters.getInitialState(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{type === 'filters' ? 'Try clearing filters' : 'Try searching again'}
|
||||||
|
</Link>
|
||||||
|
.
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Callout, Flex } from '@radix-ui/themes';
|
import { Callout, Flex } from '@radix-ui/themes';
|
||||||
import { go } from 'fuzzysort';
|
import { go } from 'fuzzysort';
|
||||||
|
import { times } from 'lodash';
|
||||||
import { memo, use, useMemo } from 'react';
|
import { memo, use, useMemo } from 'react';
|
||||||
import { ExperimentIcon } from '../../../../components/ExperimentIcon';
|
import { ExperimentIcon } from '../../../../components/ExperimentIcon';
|
||||||
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
||||||
@@ -16,7 +17,9 @@ import {
|
|||||||
import { unionBoundingBox } from '../../../../core/blitzkit/unionBoundingBox';
|
import { unionBoundingBox } from '../../../../core/blitzkit/unionBoundingBox';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
||||||
import { FilterControl } from './FilterControl';
|
import { FilterControl } from './FilterControl';
|
||||||
|
import { NoResults } from './NoResults';
|
||||||
import { SearchBar } from './SearchBar';
|
import { SearchBar } from './SearchBar';
|
||||||
|
import { SkeletonTankCard } from './SkeletonTankCard';
|
||||||
import { TankCard } from './TankCard';
|
import { TankCard } from './TankCard';
|
||||||
import { TankCardWrapper } from './TankCardWrapper';
|
import { TankCardWrapper } from './TankCardWrapper';
|
||||||
import { TierCard } from './TierCard';
|
import { TierCard } from './TierCard';
|
||||||
@@ -30,6 +33,7 @@ export const Results = memo(() => {
|
|||||||
const search = useTankopediaFilters((state) => state.search);
|
const search = useTankopediaFilters((state) => state.search);
|
||||||
const tier = useTankopediaFilters((state) => state.tier);
|
const tier = useTankopediaFilters((state) => state.tier);
|
||||||
const sort = useTankopediaFilters((state) => state.sort);
|
const sort = useTankopediaFilters((state) => state.sort);
|
||||||
|
const searching = useTankopediaFilters((state) => state.searching);
|
||||||
const searchedTanks = useMemo(() => {
|
const searchedTanks = useMemo(() => {
|
||||||
if (search !== undefined) {
|
if (search !== undefined) {
|
||||||
const searchedRaw = go(search, awaitedTankNames, {
|
const searchedRaw = go(search, awaitedTankNames, {
|
||||||
@@ -330,7 +334,7 @@ export const Results = memo(() => {
|
|||||||
<Flex direction="column" gap="4" flexGrow="1">
|
<Flex direction="column" gap="4" flexGrow="1">
|
||||||
<SearchBar topResult={searchedTanks?.[0]} />
|
<SearchBar topResult={searchedTanks?.[0]} />
|
||||||
|
|
||||||
{!search && <FilterControl />}
|
{!search && !searching && <FilterControl />}
|
||||||
|
|
||||||
{testing === 'only' && (
|
{testing === 'only' && (
|
||||||
<Flex justify="center" mt="4">
|
<Flex justify="center" mt="4">
|
||||||
@@ -346,11 +350,29 @@ export const Results = memo(() => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!search && sort.by === 'meta.tier' && <TierCard tier={tier} />}
|
{!search && sort.by === 'meta.tier' && !searching && (
|
||||||
|
<TierCard tier={tier} />
|
||||||
|
)}
|
||||||
|
|
||||||
{(search || sort.by !== 'meta.tier') && (
|
{(search || sort.by !== 'meta.tier') && !searching && searchedTanks && (
|
||||||
<TankCardWrapper py="4">
|
<>
|
||||||
{searchedTanks?.map((tank) => <TankCard key={tank.id} tank={tank} />)}
|
{searchedTanks.length > 0 && (
|
||||||
|
<TankCardWrapper>
|
||||||
|
{searchedTanks.map((tank) => (
|
||||||
|
<TankCard key={tank.id} tank={tank} />
|
||||||
|
))}
|
||||||
|
</TankCardWrapper>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{searchedTanks.length === 0 && <NoResults type="search" />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{searching && (
|
||||||
|
<TankCardWrapper>
|
||||||
|
{times(Math.round(10 + 10 * Math.random()), (index) => (
|
||||||
|
<SkeletonTankCard key={index} />
|
||||||
|
))}
|
||||||
</TankCardWrapper>
|
</TankCardWrapper>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { CaretRightIcon, MagnifyingGlassIcon } from '@radix-ui/react-icons';
|
|||||||
import { Button, Flex, Spinner, TextField } from '@radix-ui/themes';
|
import { Button, Flex, Spinner, TextField } from '@radix-ui/themes';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { KeyboardEventHandler, useCallback, useRef, useState } from 'react';
|
import { KeyboardEventHandler, useCallback, useRef } from 'react';
|
||||||
import { Link } from '../../../../components/Link';
|
import { Link } from '../../../../components/Link';
|
||||||
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
||||||
@@ -14,11 +14,11 @@ interface SearchBarProps {
|
|||||||
|
|
||||||
export function SearchBar({ topResult }: SearchBarProps) {
|
export function SearchBar({ topResult }: SearchBarProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [searching, setSearching] = useState(false);
|
|
||||||
const input = useRef<HTMLInputElement>(null);
|
const input = useRef<HTMLInputElement>(null);
|
||||||
|
const searching = useTankopediaFilters((state) => state.searching);
|
||||||
const search = useCallback(
|
const search = useCallback(
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
setSearching(false);
|
useTankopediaFilters.setState({ searching: false });
|
||||||
|
|
||||||
if (!input.current) return;
|
if (!input.current) return;
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export function SearchBar({ topResult }: SearchBarProps) {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
const handleChange = useCallback(() => {
|
const handleChange = useCallback(() => {
|
||||||
setSearching(true);
|
useTankopediaFilters.setState({ searching: true });
|
||||||
search();
|
search();
|
||||||
}, []);
|
}, []);
|
||||||
const handleKeyDown = useCallback<KeyboardEventHandler>(
|
const handleKeyDown = useCallback<KeyboardEventHandler>(
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Flex, Skeleton } from '@radix-ui/themes';
|
||||||
|
|
||||||
|
export function SkeletonTankCard() {
|
||||||
|
return (
|
||||||
|
<Flex direction="column" gap="2">
|
||||||
|
<Skeleton height="64px" />
|
||||||
|
<Skeleton height="1em" />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import { Grid, GridProps } from '@radix-ui/themes';
|
|||||||
export function TankCardWrapper(props: GridProps) {
|
export function TankCardWrapper(props: GridProps) {
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
|
py="4"
|
||||||
columns="repeat(auto-fill, minmax(100px, 1fr))"
|
columns="repeat(auto-fill, minmax(100px, 1fr))"
|
||||||
gap="2"
|
gap="2"
|
||||||
gapY="6"
|
gapY="6"
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { Flex, Text } from '@radix-ui/themes';
|
|
||||||
import { memo, use, useMemo } from 'react';
|
import { memo, use, useMemo } from 'react';
|
||||||
import { Link } from '../../../../components/Link';
|
|
||||||
import { TANK_CLASSES } from '../../../../components/Tanks/components/Item/constants';
|
import { TANK_CLASSES } from '../../../../components/Tanks/components/Item/constants';
|
||||||
import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions';
|
import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions';
|
||||||
import {
|
import {
|
||||||
@@ -9,6 +7,7 @@ import {
|
|||||||
} from '../../../../core/blitzkit/tankDefinitions';
|
} from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
|
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
||||||
|
import { NoResults } from './NoResults';
|
||||||
import { TankCard } from './TankCard';
|
import { TankCard } from './TankCard';
|
||||||
import { TankCardWrapper } from './TankCardWrapper';
|
import { TankCardWrapper } from './TankCardWrapper';
|
||||||
import { treeTypeOrder } from './TankSearch/constants';
|
import { treeTypeOrder } from './TankSearch/constants';
|
||||||
@@ -43,31 +42,10 @@ export const TierCard = memo(
|
|||||||
[tier, filters],
|
[tier, filters],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (tanks.length === 0)
|
if (tanks.length === 0) return <NoResults />;
|
||||||
return (
|
|
||||||
<Flex flexGrow="1" align="center" justify="center">
|
|
||||||
<Text color="gray">
|
|
||||||
No tanks found.{' '}
|
|
||||||
<Link
|
|
||||||
href="#"
|
|
||||||
underline="always"
|
|
||||||
color="red"
|
|
||||||
onClick={() =>
|
|
||||||
useTankopediaFilters.setState(
|
|
||||||
useTankopediaFilters.getInitialState(),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Try clearing filters
|
|
||||||
</Link>
|
|
||||||
.
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TankCardWrapper mt="6">
|
<TankCardWrapper>
|
||||||
{tanks.map((tank) => (
|
{tanks.map((tank) => (
|
||||||
<TankCard key={tank.id} tank={tank} />
|
<TankCard key={tank.id} tank={tank} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,21 +1,12 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Flex } from '@radix-ui/themes';
|
|
||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { Results } from './components/Results';
|
import { Results } from './components/Results';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
<PageWrapper color="purple" size={1028}>
|
<PageWrapper color="purple" size={1028}>
|
||||||
<Flex
|
<Results />
|
||||||
gap="8"
|
|
||||||
direction={{ initial: 'column', sm: 'row' }}
|
|
||||||
py="4"
|
|
||||||
flexGrow="1"
|
|
||||||
>
|
|
||||||
{/* <FilterControl /> */}
|
|
||||||
<Results />
|
|
||||||
</Flex>
|
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,7 @@ export interface TankopediaFilters {
|
|||||||
by: TankopediaSortBy;
|
by: TankopediaSortBy;
|
||||||
direction: TankopediaSortDirection;
|
direction: TankopediaSortDirection;
|
||||||
};
|
};
|
||||||
|
searching: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useTankopediaFilters = create<TankopediaFilters>()(() => ({
|
export const useTankopediaFilters = create<TankopediaFilters>()(() => ({
|
||||||
@@ -24,6 +25,7 @@ export const useTankopediaFilters = create<TankopediaFilters>()(() => ({
|
|||||||
direction: 'descending',
|
direction: 'descending',
|
||||||
},
|
},
|
||||||
tier: 10,
|
tier: 10,
|
||||||
|
searching: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export function mutateTankopediaFilters(
|
export function mutateTankopediaFilters(
|
||||||
|
|||||||
Reference in new issue
Block a user