89 lines
3.5 KiB
Markdown
89 lines
3.5 KiB
Markdown
---
|
||
phase: quick
|
||
plan: 260411-1h2
|
||
subsystem: client/routes
|
||
tags: [global-items, filters, search, ui, sticky-toolbar]
|
||
dependency_graph:
|
||
requires: []
|
||
provides: [rebuilt-global-items-page]
|
||
affects: [src/client/routes/global-items/index.tsx]
|
||
tech_stack:
|
||
added: []
|
||
patterns: [inline-filter-popovers, click-outside-useref, debounced-search, client-side-range-filter]
|
||
key_files:
|
||
created: []
|
||
modified:
|
||
- src/client/routes/global-items/index.tsx
|
||
decisions:
|
||
- Inline popovers (not sidebar) for tag/weight/price filters — matches plan spec, avoids layout shift
|
||
- click-outside via useRef + mousedown listener (3 refs) — no framer-motion needed
|
||
- GlobalItemListRow defined in same file — no new component file needed
|
||
metrics:
|
||
duration: ~15 minutes
|
||
completed: 2026-04-10T23:13:02Z
|
||
tasks_completed: 1
|
||
files_modified: 1
|
||
---
|
||
|
||
# Quick 260411-1h2: Rebuild Global Items Page with Sticky Toolbar Summary
|
||
|
||
**One-liner:** Rebuilt global items page with sticky two-row toolbar (search + view toggle + inline tag/weight/price filter popovers), grid/list view toggle using GlobalItemCard and Link-based list rows.
|
||
|
||
## Tasks Completed
|
||
|
||
| Task | Name | Commit | Files |
|
||
|------|------|--------|-------|
|
||
| 1 | Rebuild global items page with sticky toolbar, filters, and dual view | ee3b6f7 | src/client/routes/global-items/index.tsx |
|
||
|
||
## What Was Built
|
||
|
||
`src/client/routes/global-items/index.tsx` was completely rewritten from a simple 94-line grid-only page to a 640+ line full-featured catalog browsing page:
|
||
|
||
**Sticky toolbar** (`sticky top-14 z-[5]`) with two rows:
|
||
- Row 1: Back link to Discover, centered search input with clear (X) button, grid/list view toggle
|
||
- Row 2 (conditional): Tags, Weight, Price filter pills — only shown when tags exist or any filter is active
|
||
|
||
**Filter popovers:**
|
||
- Tags: dropdown listing all tags from `useTags()` — click to toggle, active tags highlighted blue, count badge on pill
|
||
- Weight: min/max range sliders (0–5000g, 50g steps) in a compact card popover
|
||
- Price: min/max range sliders (0–100000 cents, 500 cent steps) in a compact card popover
|
||
- All popovers close on click-outside via `useRef` + `mousedown` event listener
|
||
- Only one popover open at a time (opening one closes others)
|
||
|
||
**Active filter pills:**
|
||
- Selected tag names shown as removable blue pills
|
||
- Active weight/price range bounds shown as removable pills
|
||
- "Clear all" button clears all filters at once
|
||
|
||
**Results area:**
|
||
- Grid view: `GlobalItemCard` (existing component, untouched)
|
||
- List view: `GlobalItemListRow` (inline component, uses `<Link>` for navigation, no Add button)
|
||
- Loading: `SkeletonGrid` / `SkeletonList` (6-item animate-pulse layouts)
|
||
- Empty: contextual message based on whether query/filters are active
|
||
|
||
**Data flow:**
|
||
- `searchInput` debounced 300ms to `debouncedQuery` → passed to `useGlobalItems()`
|
||
- `selectedTags` passed to `useGlobalItems()` for server-side tag filtering
|
||
- Weight/price filters applied client-side via `useMemo`
|
||
- Search input pre-filled from `?q=` URL param on mount
|
||
|
||
## Deviations from Plan
|
||
|
||
None — plan executed exactly as written.
|
||
|
||
## Known Stubs
|
||
|
||
None — all functionality is wired to real data hooks.
|
||
|
||
## Self-Check
|
||
|
||
- [x] `src/client/routes/global-items/index.tsx` exists and is 640+ lines
|
||
- [x] Commit ee3b6f7 exists
|
||
- [x] `bun run lint` passes with no errors
|
||
- [x] `createFileRoute("/global-items/")` preserved
|
||
- [x] `validateSearch` with `z.object({ q: z.string().optional().catch(undefined) })` preserved
|
||
- [x] `CatalogSearchOverlay.tsx` untouched
|
||
- [x] `GlobalItemCard.tsx` untouched
|
||
|
||
## Self-Check: PASSED
|