Show reference-data update time, location filter UI, and tile fixes

- Status gains reference_updated_at (sourced from reference.db's file
  mtime, so it needs no separate persisted state) and the sidebar's
  "Your library" panel shows it as a relative "Updated Xh ago" stamp
  that self-refreshes every minute.
- Add a Location field to the Library tab's filters panel, wired to the
  new LibraryFilter.location.
- Bump every font-size in the stylesheet up one step for a slightly
  larger, easier-to-read UI overall.
- Fix the library/deck tile view's +/- quantity overlay permanently
  covering the card art's own printed mana cost (top-right corner) —
  it now only fades in on hover/focus, like the other row actions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 21:35:09 -05:00
parent 436975f64f
commit 67c97bbd7a
5 changed files with 113 additions and 41 deletions

View File

@@ -31,6 +31,7 @@ export function LibraryBrowser() {
const [subtype, setSubtype] = useState("");
const [keyword, setKeyword] = useState("");
const [inDeck, setInDeck] = useState<number | "">("");
const [location, setLocation] = useState("");
const [decks, setDecks] = useState<Deck[]>([]);
const [rows, setRows] = useState<LibraryCard[]>([]);
@@ -59,12 +60,25 @@ export function LibraryBrowser() {
subtypes: splitCsv(subtype),
keywords: splitCsv(keyword),
in_deck: inDeck === "" ? null : Number(inDeck),
location: location.trim() || null,
};
const t = setTimeout(() => {
api.searchLibrary(filter).then(setRows).catch(() => setRows([]));
}, 120);
return () => clearTimeout(t);
}, [text, commander, colorsInclude, cmcMin, cmcMax, type, subtype, keyword, inDeck, refreshKey]);
}, [
text,
commander,
colorsInclude,
cmcMin,
cmcMax,
type,
subtype,
keyword,
inDeck,
location,
refreshKey,
]);
async function adjust(oracleId: string, delta: number) {
const qty = await api.addOwned(oracleId, delta);
@@ -261,6 +275,14 @@ export function LibraryBrowser() {
))}
</select>
</div>
<div className="field">
<label>Location</label>
<input
value={location}
onChange={(e) => setLocation(e.target.value)}
placeholder="e.g. Box 1"
/>
</div>
</div>
{rows.length === 0 ? (