import { useState } from 'react'; import { WORKSHOP_SORTS, type WorkshopModPreview, type WorkshopSort } from '@reforger-panel/shared'; import { useWorkshopSearch } from '../../api/hooks.js'; import { formatBytes } from '../../lib/format.js'; import { Badge, Button, EmptyState, ModImage, SearchInput, Skeleton } from '../ui.js'; import { Icon } from '../icons.js'; /** * The upstream index rejects comma-separated tags, so filtering is one tag at * a time. These are the tags that actually appear on Reforger Workshop mods. */ const TAGS = [ 'SCENARIOS_MP', 'SCENARIOS_SP', 'WEAPONS', 'VEHICLES', 'CHARACTERS', 'TERRAINS', 'SYSTEMS', 'PROPS', 'EFFECTS', 'MISC', ] as const; const SORT_LABELS: Record = { popularity: 'Popular', 'most-rated': 'Most rated', 'highest-rated': 'Highest rated', subscribers: 'Subscribers', newest: 'Newest', created: 'Recently created', 'recently-updated': 'Recently updated', largest: 'Largest', name: 'Name', }; export function BrowsePanel({ installedIds, canManage, onAdd, onRemove, onOpen, }: { installedIds: ReadonlySet; canManage: boolean; onAdd: (mod: WorkshopModPreview) => void; onRemove: (modId: string) => void; onOpen: (modId: string) => void; }) { const [query, setQuery] = useState(''); const [sort, setSort] = useState('popularity'); const [tag, setTag] = useState(null); const [page, setPage] = useState(1); const search = useWorkshopSearch({ query, page, sort, tag: tag ?? undefined }); const mods = search.data?.mods ?? []; const meta = search.data?.meta; const reset = (setter: (value: T) => void) => (value: T) => { setter(value); setPage(1); }; return (
{meta && ( {meta.totalMods.toLocaleString()} mods )}
{TAGS.map((value) => { const active = tag === value; return ( ); })}
{search.isLoading ? (
{Array.from({ length: 6 }, (_, index) => (
))}
) : search.error ? ( void search.refetch()}> Retry } /> ) : mods.length === 0 ? ( ) : (
{mods.map((mod) => ( onAdd(mod)} onRemove={() => onRemove(mod.id.toUpperCase())} onOpen={() => onOpen(mod.id.toUpperCase())} /> ))}
)} {meta && meta.totalPages > 1 && (
Page {meta.currentPage} of {meta.totalPages}
)}
); } function ModCard({ mod, installed, canManage, onAdd, onRemove, onOpen, }: { mod: WorkshopModPreview; installed: boolean; canManage: boolean; onAdd: () => void; onRemove: () => void; onOpen: () => void; }) { return (
{mod.version && v{mod.version}} {mod.sizeBytes ? formatBytes(mod.sizeBytes) : (mod.sizeText ?? 'size unknown')} {mod.rating !== null && mod.rating > 0 && ( {Math.round(mod.rating * 100)}% )} {mod.subscriberCount ? {mod.subscriberCount.toLocaleString()} subs : null}
{mod.obsolete && obsolete} {canManage && (installed ? ( ) : ( ))}
); }