feat(frontend): inventory chips row + results table (sort, columns, paging, keyboard)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-15 06:26:38 +02:00
parent 0533e2b9ee
commit 4735aa72e9
3 changed files with 168 additions and 5 deletions

View file

@ -1,3 +1,49 @@
// Stub — replaced in Task 5
import type { InventorySearch } from './useInventorySearch';
export function ActiveChips(_: { search: InventorySearch }) { return null; }
import { RATING_DEFS } from './constants';
interface Chip { label: string; gold?: boolean; remove: () => void; }
export function ActiveChips({ search }: { search: InventorySearch }) {
const { filters: f, update } = search;
const chips: Chip[] = [];
if (f.text) chips.push({ label: `"${f.text}"`, remove: () => update({ text: '' }) });
if (f.characters !== 'all') chips.push({
label: `${f.characters.length} character${f.characters.length === 1 ? '' : 's'}`,
remove: () => update({ characters: 'all' }),
});
if (f.itemType !== 'all') chips.push({
label: f.itemType[0].toUpperCase() + f.itemType.slice(1) + (f.weaponType ? `: ${f.weaponType}` : ''),
remove: () => update({ itemType: 'all', weaponType: '' }),
});
for (const s of f.slots) chips.push({ label: `Slot: ${s}`, remove: () => update({ slots: f.slots.filter(x => x !== s) }) });
for (const c of f.cantrips) chips.push({
label: c.replace(/^Legendary /, 'Leg. '), gold: true,
remove: () => update({ cantrips: f.cantrips.filter(x => x !== c) }),
});
if (f.spellContains) chips.push({ label: `Spell: ${f.spellContains}`, remove: () => update({ spellContains: '' }) });
for (const [param, v] of Object.entries(f.ratings)) if (v !== '') {
const def = RATING_DEFS.find(r => r.param === param);
chips.push({ label: `${def?.label ?? param} ≥ ${v}`, remove: () => update({ ratings: { ...f.ratings, [param]: '' } }) });
}
if (f.itemSet) chips.push({ label: `Set: ${f.itemSet}`, remove: () => update({ itemSet: '' }) });
if (f.equippedOnly) chips.push({ label: 'Equipped', remove: () => update({ equippedOnly: false }) });
if (f.bonded) chips.push({ label: 'Bonded', remove: () => update({ bonded: false }) });
if (f.attuned) chips.push({ label: 'Attuned', remove: () => update({ attuned: false }) });
if (f.rare) chips.push({ label: 'Rare', remove: () => update({ rare: false }) });
if (f.maxLevel !== '') chips.push({ label: `Wield ≤ ${f.maxLevel}`, remove: () => update({ maxLevel: '' }) });
if (f.minValue !== '') chips.push({ label: `Value ≥ ${f.minValue}`, remove: () => update({ minValue: '' }) });
if (f.minWorkmanship !== '') chips.push({ label: `Work ≥ ${f.minWorkmanship}`, remove: () => update({ minWorkmanship: '' }) });
if (f.maxBurden !== '') chips.push({ label: `Burden ≤ ${f.maxBurden}`, remove: () => update({ maxBurden: '' }) });
if (!chips.length) return null;
return (
<div className="inv-chipsrow">
<span className="inv-chips-lbl">ACTIVE</span>
{chips.map((c, i) => (
<span className={`inv-chip${c.gold ? ' inv-chip-gold' : ''}`} key={i}>
{c.label} <span className="inv-chip-x" onClick={c.remove}>×</span>
</span>
))}
</div>
);
}