Files
GearBox/.planning/quick/260411-1h2-rebuild-global-items-page-with-sticky-se/260411-1h2-SUMMARY.md

89 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 (05000g, 50g steps) in a compact card popover
- Price: min/max range sliders (0100000 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