UX overhaul: routing, accessibility, feedback, and polish
Build and push image / build (push) Successful in 50s

Add react-router-dom for URL-based navigation with browser
back/forward, deep links, and bookmarks. Replace window.confirm()
with styled ConfirmDialog. Add toast notifications and success
feedback on consume/audit/gone flows. Add escape-to-close and
focus trapping on modals. Add entrance animations for drawers,
modals, and toasts. Make grids responsive, add sortable inventory
headers, working CSV/JSON export, time-aware greeting, focus-visible
outlines, search clear button, and hover chevrons on inventory rows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 18:54:49 -04:00
parent 80034b47c5
commit a82045d1bd
21 changed files with 640 additions and 145 deletions
@@ -8,6 +8,7 @@ import { api } from "../../api.js";
import { Btn, Field, Icon, Input, Select, Textarea } from "../primitives/index.js";
import { ScanField, type ScanResult } from "../ScanField.js";
import { ModalBackdrop, ModalHeader, ModalFooter } from "./ModalChrome.js";
import { useToast } from "../Toast.js";
export function ConsumeFlow({
data,
@@ -19,12 +20,14 @@ export function ConsumeFlow({
item: Item | null;
}) {
const qc = useQueryClient();
const { toast } = useToast();
const allItems = enrichItems(data);
const active = allItems.filter((i) => i.status === "active");
const [itemId, setItemId] = useState(initialItem?.id ?? active[0]?.id ?? "");
const [rating, setRating] = useState(4);
const [notes, setNotes] = useState("");
const [date, setDate] = useState(TODAY_STR);
const [error, setError] = useState<string | null>(null);
const item = allItems.find((i) => i.id === itemId);
@@ -32,8 +35,10 @@ export function ConsumeFlow({
mutationFn: () => api.finishInventoryItem(itemId, { date, rating, notes }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["bootstrap"] });
toast(`Marked ${item?.name ?? "item"} as consumed — ${rating}/5 stars`);
onClose();
},
onError: (e: Error) => setError(e.message),
});
const handleScan = (result: ScanResult) => {
@@ -163,6 +168,10 @@ export function ConsumeFlow({
/>
</Field>
</div>
{error && (
<div style={{ marginTop: 14, fontSize: 12, color: "var(--terracotta)" }}>{error}</div>
)}
</div>
<ModalFooter>