2025-09-01 22:58:26 -05:00
|
|
|
import locales from "@blitzkit/i18n/locales.json";
|
|
|
|
|
import { literals } from "@blitzkit/i18n/src/literals";
|
|
|
|
|
import { Flex, Text } from "@radix-ui/themes";
|
|
|
|
|
import fuzzysort from "fuzzysort";
|
|
|
|
|
import { times } from "lodash-es";
|
|
|
|
|
import { useMemo, useState } from "react";
|
2026-08-05 13:01:51 -05:00
|
|
|
import { api } from "../../core/blitzkit/api";
|
2025-09-01 22:58:26 -05:00
|
|
|
import { useLocale } from "../../hooks/useLocale";
|
|
|
|
|
import { Gallery } from "../../stores/gallery";
|
|
|
|
|
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
|
|
|
|
import { InlineSkeleton } from "../InlineSkeleton";
|
|
|
|
|
import { GalleryCard } from "./Card";
|
2024-10-24 17:32:46 -05:00
|
|
|
|
|
|
|
|
export interface Avatar {
|
|
|
|
|
name: string;
|
|
|
|
|
id: string;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-05 13:01:51 -05:00
|
|
|
const gallery = await api.galleryDefinitions();
|
2025-04-19 00:47:28 -05:00
|
|
|
|
2024-10-24 17:50:18 -05:00
|
|
|
const DEFAULT_LOADED = 42;
|
2024-11-24 20:39:21 -06:00
|
|
|
const PREVIEW_COUNT = 28;
|
2024-10-24 17:46:02 -05:00
|
|
|
|
2025-04-20 20:49:54 -05:00
|
|
|
export function GalleryList({ skeleton }: MaybeSkeletonComponentProps) {
|
2025-09-01 22:58:26 -05:00
|
|
|
const search = Gallery.use((state) => state.search);
|
2024-10-24 17:46:02 -05:00
|
|
|
const [loadedCards, setLoadedCards] = useState(DEFAULT_LOADED);
|
2025-04-20 21:27:00 -05:00
|
|
|
const { locale, strings } = useLocale();
|
2024-10-24 17:32:46 -05:00
|
|
|
const filtered = useMemo(() => {
|
2024-10-24 17:46:02 -05:00
|
|
|
setLoadedCards(DEFAULT_LOADED);
|
|
|
|
|
|
2024-10-24 17:32:46 -05:00
|
|
|
if (search === undefined) {
|
2025-04-19 00:47:28 -05:00
|
|
|
return gallery.avatars;
|
2024-10-24 17:32:46 -05:00
|
|
|
} else {
|
|
|
|
|
return fuzzysort
|
2025-04-19 00:47:28 -05:00
|
|
|
.go(search, gallery.avatars, {
|
|
|
|
|
keys: [
|
|
|
|
|
...locales.supported.map(
|
2026-08-05 13:01:51 -05:00
|
|
|
(supported) => `name.locales.${supported.locale}`,
|
2025-04-19 00:47:28 -05:00
|
|
|
),
|
2025-09-01 22:58:26 -05:00
|
|
|
"id",
|
2025-04-19 00:47:28 -05:00
|
|
|
],
|
|
|
|
|
})
|
2024-10-24 17:32:46 -05:00
|
|
|
.map((result) => result.obj);
|
|
|
|
|
}
|
|
|
|
|
}, [search]);
|
|
|
|
|
|
|
|
|
|
return (
|
2024-10-24 17:50:18 -05:00
|
|
|
<>
|
|
|
|
|
<Text align="center" color="gray">
|
2025-04-20 20:49:54 -05:00
|
|
|
{skeleton ? (
|
|
|
|
|
<InlineSkeleton width="7rem" />
|
|
|
|
|
) : (
|
2025-10-02 10:15:38 -05:00
|
|
|
literals(strings.website.tools.gallery.search.results, {
|
|
|
|
|
count: filtered.length.toLocaleString(locale),
|
|
|
|
|
})
|
2025-04-20 20:49:54 -05:00
|
|
|
)}
|
2024-10-24 17:50:18 -05:00
|
|
|
</Text>
|
2024-10-24 17:46:02 -05:00
|
|
|
|
2024-10-24 17:52:23 -05:00
|
|
|
<Flex wrap="wrap" gap="4" justify="center">
|
2025-04-20 20:49:54 -05:00
|
|
|
{!skeleton &&
|
|
|
|
|
filtered
|
|
|
|
|
.slice(0, loadedCards)
|
|
|
|
|
.map((avatar) => <GalleryCard key={avatar.id} avatar={avatar} />)}
|
2024-10-24 17:50:18 -05:00
|
|
|
|
|
|
|
|
{times(
|
2025-04-20 20:49:54 -05:00
|
|
|
skeleton
|
|
|
|
|
? DEFAULT_LOADED + PREVIEW_COUNT
|
|
|
|
|
: Math.min(PREVIEW_COUNT, filtered.length - loadedCards),
|
2024-10-24 17:50:18 -05:00
|
|
|
(index) => (
|
|
|
|
|
<GalleryCard
|
|
|
|
|
key={index}
|
|
|
|
|
skeleton
|
|
|
|
|
onIntersection={() => setLoadedCards((state) => state + 2)}
|
|
|
|
|
/>
|
2026-08-05 13:01:51 -05:00
|
|
|
),
|
2024-10-24 17:50:18 -05:00
|
|
|
)}
|
|
|
|
|
</Flex>
|
|
|
|
|
</>
|
2024-10-24 17:32:46 -05:00
|
|
|
);
|
|
|
|
|
}
|