--- 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 `` 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