feat: add customizations page
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
'use client';
|
||||
|
||||
import shared from '../../styles/shared.module.css';
|
||||
import styles from '../../styles/Customizations.module.css';
|
||||
import { CustomizationItem, Tab, getCosmeticIconUrl } from './types';
|
||||
|
||||
type Props = {
|
||||
tab: Tab;
|
||||
allFilteredItems: CustomizationItem[];
|
||||
pagedItems: CustomizationItem[];
|
||||
page: number;
|
||||
totalPages: number;
|
||||
search: string;
|
||||
unlockedSet: Set<string>;
|
||||
characterMap: Map<number, string>;
|
||||
onSearchChange: (s: string) => void;
|
||||
onUnlockAll: () => void;
|
||||
onLockAll: () => void;
|
||||
onUnlockPage: () => void;
|
||||
onLockPage: () => void;
|
||||
onToggle: (id: string) => void;
|
||||
onPageChange: (p: number) => void;
|
||||
};
|
||||
|
||||
export default function FlatCategory({
|
||||
tab,
|
||||
allFilteredItems,
|
||||
pagedItems,
|
||||
page,
|
||||
totalPages,
|
||||
search,
|
||||
unlockedSet,
|
||||
characterMap,
|
||||
onSearchChange,
|
||||
onUnlockAll,
|
||||
onLockAll,
|
||||
onUnlockPage,
|
||||
onLockPage,
|
||||
onToggle,
|
||||
onPageChange,
|
||||
}: Props) {
|
||||
const buildPageNumbers = () => {
|
||||
const pages: number[] = [];
|
||||
const start = Math.max(1, Math.min(page - 2, totalPages - 4));
|
||||
const end = Math.min(totalPages, start + 4);
|
||||
for (let i = start; i <= end; i++) pages.push(i);
|
||||
return pages;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={shared.toolbar}>
|
||||
<input
|
||||
className={shared.searchInput}
|
||||
type="text"
|
||||
placeholder={`Search ${tab}...`}
|
||||
value={search}
|
||||
onChange={e => onSearchChange(e.target.value)}
|
||||
/>
|
||||
<span className={shared.spacer} />
|
||||
<span className={shared.resultCount}>{allFilteredItems.length} items</span>
|
||||
<button className={shared.unlockAllBtn} onClick={onUnlockAll}>
|
||||
Unlock all ({allFilteredItems.length})
|
||||
</button>
|
||||
<button className={shared.lockAllBtn} onClick={onLockAll}>
|
||||
Lock all
|
||||
</button>
|
||||
<button className={styles.pageActionBtn} onClick={onUnlockPage}>
|
||||
Unlock visible
|
||||
</button>
|
||||
<button className={styles.pageActionBtn} onClick={onLockPage}>
|
||||
Lock visible
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{allFilteredItems.length === 0 ? (
|
||||
<div className={shared.empty}>No items found</div>
|
||||
) : (
|
||||
<>
|
||||
<div className={styles.grid}>
|
||||
{pagedItems.map(item => {
|
||||
const unlocked = unlockedSet.has(item.id);
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
className={`${shared.card} ${unlocked ? shared.cardUnlocked : ''}`}
|
||||
onClick={() => onToggle(item.id)}
|
||||
>
|
||||
<img
|
||||
className={shared.cardIcon}
|
||||
src={getCosmeticIconUrl(item, characterMap)}
|
||||
alt={item.name}
|
||||
loading="lazy"
|
||||
/>
|
||||
<span className={shared.cardName}>{item.name}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{totalPages > 1 && (
|
||||
<div className={shared.pagination}>
|
||||
<button
|
||||
className={`${shared.pageBtn} ${page === 1 ? shared.pageBtnDisabled : ''}`}
|
||||
onClick={() => onPageChange(1)}
|
||||
>«</button>
|
||||
<button
|
||||
className={`${shared.pageBtn} ${page === 1 ? shared.pageBtnDisabled : ''}`}
|
||||
onClick={() => onPageChange(page - 1)}
|
||||
>‹</button>
|
||||
|
||||
{buildPageNumbers().map(n => (
|
||||
<button
|
||||
key={n}
|
||||
className={`${shared.pageBtn} ${n === page ? shared.pageBtnActive : ''}`}
|
||||
onClick={() => onPageChange(n)}
|
||||
>{n}</button>
|
||||
))}
|
||||
|
||||
<button
|
||||
className={`${shared.pageBtn} ${page === totalPages ? shared.pageBtnDisabled : ''}`}
|
||||
onClick={() => onPageChange(page + 1)}
|
||||
>›</button>
|
||||
<button
|
||||
className={`${shared.pageBtn} ${page === totalPages ? shared.pageBtnDisabled : ''}`}
|
||||
onClick={() => onPageChange(totalPages)}
|
||||
>»</button>
|
||||
|
||||
<span className={shared.pageInfo}>{page} / {totalPages}</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user