mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: skeleton search
This commit is contained in:
1 parent
9d916a588d
commit
45938c875f
4 files changed
+36
-19
No files matched your search
@@ -6,15 +6,16 @@ import { debounce } from 'lodash-es';
|
||||
import { type KeyboardEventHandler, useCallback, useRef } from 'react';
|
||||
import { useLocale } from '../../../hooks/useLocale';
|
||||
import { $tankFilters } from '../../../stores/tankFilters';
|
||||
import type { MaybeSkeletonComponentProps } from '../../../types/maybeSkeletonComponentProps';
|
||||
import { QuickLink } from './QuickLink';
|
||||
import { Sort } from './Sort';
|
||||
|
||||
interface SearchBarProps {
|
||||
type SearchBarProps = MaybeSkeletonComponentProps & {
|
||||
topResult?: TankDefinition;
|
||||
onSelect?: (tank: TankDefinition) => void;
|
||||
}
|
||||
};
|
||||
|
||||
export function SearchBar({ topResult, onSelect }: SearchBarProps) {
|
||||
export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) {
|
||||
const { strings } = useLocale();
|
||||
const tankFilters = useStore($tankFilters);
|
||||
const input = useRef<HTMLInputElement>(null);
|
||||
@@ -66,6 +67,7 @@ export function SearchBar({ topResult, onSelect }: SearchBarProps) {
|
||||
<Flex justify="center">
|
||||
<Flex gap="2" flexGrow="1">
|
||||
<TextField.Root
|
||||
disabled={skeleton}
|
||||
defaultValue={tankFilters.search}
|
||||
style={{ flex: 1 }}
|
||||
ref={input}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { $tankFilters } from '../../stores/tankFilters';
|
||||
import { TankopediaPersistent } from '../../stores/tankopediaPersistent';
|
||||
import { SORT_UNITS } from '../../stores/tankopediaPersistent/constants';
|
||||
import { $tankopediaSort } from '../../stores/tankopediaSort';
|
||||
import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps';
|
||||
import { ExperimentIcon } from '../ExperimentIcon';
|
||||
import { TankSearchCard } from './components/Card';
|
||||
import { FilterControl } from './components/FilterControl';
|
||||
@@ -33,11 +34,12 @@ import { SkeletonTankCard } from './components/SkeletonTankCard';
|
||||
import { TankCardWrapper } from './components/TankCardWrapper';
|
||||
import { MAX_RECENTLY_VIEWED } from './constants';
|
||||
|
||||
type TankSearchProps = Omit<FlexProps, 'onSelect'> & {
|
||||
compact?: boolean;
|
||||
onSelect?: (tank: TankDefinition) => void;
|
||||
onSelectAll?: (tanks: TankDefinition[]) => void;
|
||||
};
|
||||
type TankSearchProps = MaybeSkeletonComponentProps &
|
||||
Omit<FlexProps, 'onSelect'> & {
|
||||
compact?: boolean;
|
||||
onSelect?: (tank: TankDefinition) => void;
|
||||
onSelectAll?: (tanks: TankDefinition[]) => void;
|
||||
};
|
||||
|
||||
const PREVIEW_COUNT = 20;
|
||||
const DEFAULT_LOADED_CARDS = 64;
|
||||
@@ -51,7 +53,7 @@ const [gameDefinitions, modelDefinitions, tankDefinitions, tankNames] =
|
||||
]);
|
||||
|
||||
export const TankSearch = memo<TankSearchProps>(
|
||||
({ compact, onSelect, onSelectAll, ...props }) => {
|
||||
({ compact, onSelect, onSelectAll, skeleton, ...props }) => {
|
||||
const { strings, locale } = useLocale();
|
||||
const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
|
||||
const awaitedTanksDefinitionsArray = Object.values(tankDefinitions.tanks);
|
||||
@@ -428,13 +430,17 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="4" flexGrow="1" {...props}>
|
||||
<SearchBar topResult={tanks?.[0]} onSelect={onSelect} />
|
||||
<SearchBar
|
||||
skeleton={skeleton}
|
||||
topResult={tanks?.[0]}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
|
||||
{!tankFilters.search && !tankFilters.searching && (
|
||||
<FilterControl compact={compact} />
|
||||
)}
|
||||
|
||||
{!compact && <RecentlyViewed />}
|
||||
{!skeleton && !compact && <RecentlyViewed />}
|
||||
|
||||
<Flex mt="2" gap="1" align="center" justify="center" direction="column">
|
||||
<Flex gap="2">
|
||||
@@ -494,7 +500,7 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{!tankFilters.searching && (
|
||||
{!skeleton && !tankFilters.searching && (
|
||||
<>
|
||||
{tanks.length > 0 && (
|
||||
<TankCardWrapper>
|
||||
@@ -528,11 +534,16 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
</>
|
||||
)}
|
||||
|
||||
{tankFilters.searching && (
|
||||
{(skeleton || tankFilters.searching) && (
|
||||
<TankCardWrapper>
|
||||
{times(Math.round(10 + 10 * Math.random()), (index) => (
|
||||
<SkeletonTankCard key={index} />
|
||||
))}
|
||||
{times(
|
||||
Math.round(
|
||||
skeleton ? DEFAULT_LOADED_CARDS : 10 + 10 * Math.random(),
|
||||
),
|
||||
(index) => (
|
||||
<SkeletonTankCard key={index} />
|
||||
),
|
||||
)}
|
||||
</TankCardWrapper>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
@@ -6,14 +6,18 @@ import {
|
||||
} from '../../../../hooks/useLocale';
|
||||
import { App } from '../../../../stores/app';
|
||||
import { TankopediaPersistent } from '../../../../stores/tankopediaPersistent';
|
||||
import type { MaybeSkeletonComponentProps } from '../../../../types/maybeSkeletonComponentProps';
|
||||
|
||||
export function Page({ locale }: LocaleAcceptorProps) {
|
||||
export function Page({
|
||||
locale,
|
||||
skeleton,
|
||||
}: LocaleAcceptorProps & MaybeSkeletonComponentProps) {
|
||||
return (
|
||||
<LocaleProvider locale={locale}>
|
||||
<PageWrapper color="purple" maxWidth="80rem">
|
||||
<TankopediaPersistent.Provider>
|
||||
<App.Provider>
|
||||
<TankSearch />
|
||||
<TankSearch skeleton={skeleton} />
|
||||
</App.Provider>
|
||||
</TankopediaPersistent.Provider>
|
||||
</PageWrapper>
|
||||
|
||||
@@ -10,6 +10,6 @@ const { locale } = Astro.params;
|
||||
|
||||
<ToolLayout tool={tankopediaTool}>
|
||||
<Page {locale} client:only="react">
|
||||
<Page {locale} slot="fallback" />
|
||||
<Page {locale} skeleton slot="fallback" />
|
||||
</Page>
|
||||
</ToolLayout>
|
||||
Reference in new issue
Block a user