feat(frontend): /?view=inventory route + inventory page scaffold + dark CSS

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-15 06:16:12 +02:00
parent 6fd87a3751
commit 9a9b33a528
7 changed files with 149 additions and 1 deletions

View file

@ -0,0 +1,3 @@
// Stub — replaced in Task 5
import type { InventorySearch } from './useInventorySearch';
export function ActiveChips(_: { search: InventorySearch }) { return null; }

View file

@ -0,0 +1,3 @@
// Stub — replaced in Task 6
import type { InvItem } from './types';
export function DetailPanel(_: { item: InvItem; onClose: () => void }) { return null; }

View file

@ -0,0 +1,3 @@
// Stub — replaced in Task 4
import type { InventorySearch } from './useInventorySearch';
export function FilterSidebar(_: { search: InventorySearch }) { return <div className="inv-sidebar" />; }

View file

@ -0,0 +1,40 @@
import { useState } from 'react';
import { useInventorySearch } from './useInventorySearch';
import { FilterSidebar } from './FilterSidebar';
import { ActiveChips } from './ActiveChips';
import { ResultsTable } from './ResultsTable';
import { DetailPanel } from './DetailPanel';
import type { InvItem } from './types';
export function InventorySearchPage() {
const search = useInventorySearch();
const [selected, setSelected] = useState<InvItem | null>(null);
return (
<div className="inv-page">
<div className="inv-topbar">
<span className="inv-title"> Inventory Search</span>
<input
className="inv-searchbox"
placeholder="Search name or material…"
value={search.filters.text}
onChange={e => search.update({ text: e.target.value })}
/>
<button className="inv-btn" onClick={() => { search.reset(); setSelected(null); }}>Reset</button>
<span className="inv-count">
{search.error ? <span className="inv-error">{search.error}</span>
: search.result ? <><b>{search.result.total_count.toLocaleString()}</b> items
{search.queryMs != null && <> · {search.queryMs} ms</>}
{search.loading && ' · …'}</>
: 'loading…'}
</span>
</div>
<ActiveChips search={search} />
<div className="inv-main">
<FilterSidebar search={search} />
<ResultsTable search={search} selected={selected} onSelect={setSelected} />
{selected && <DetailPanel item={selected} onClose={() => setSelected(null)} />}
</div>
</div>
);
}

View file

@ -0,0 +1,6 @@
// Stub — replaced in Task 5
import type { InventorySearch } from './useInventorySearch';
import type { InvItem } from './types';
export function ResultsTable(_: { search: InventorySearch; selected: InvItem | null; onSelect: (i: InvItem | null) => void }) {
return <div className="inv-results" />;
}