Files
GearBox/.planning/phases/35-bug-fixes/35-03-PLAN.md

225 lines
10 KiB
Markdown

---
phase: 35-bug-fixes
plan: 03
type: execute
wave: 1
depends_on: []
files_modified:
- src/client/components/ItemCard.tsx
- src/client/components/FabMenu.tsx
- src/client/components/BottomTabBar.tsx
autonomous: true
requirements:
- FIX-05
must_haves:
truths:
- "ItemCard outer button shows cursor-pointer when linkTo is not null"
- "ItemCard outer button shows cursor-default when linkTo === null (existing correct behavior, preserved)"
- "FabMenu menu item buttons explicitly have cursor-pointer"
- "FabMenu main FAB button explicitly has cursor-pointer"
- "BottomTabBar anonymous tab buttons have cursor-pointer"
artifacts:
- path: "src/client/components/ItemCard.tsx"
provides: "ItemCard with correct conditional cursor"
contains: "cursor-pointer"
- path: "src/client/components/FabMenu.tsx"
provides: "FabMenu buttons with explicit cursor-pointer"
contains: "cursor-pointer"
- path: "src/client/components/BottomTabBar.tsx"
provides: "BottomTabBar buttons with cursor-pointer"
contains: "cursor-pointer"
key_links:
- from: "ItemCard outer button"
to: "cursor-pointer class"
via: "linkTo !== null conditional class"
pattern: "cursor-pointer.*hover:border-gray-200"
---
<objective>
Audit and fix cursor-pointer coverage across interactive elements. The Tailwind utility cursor-pointer must be explicitly applied to all clickable elements that currently lack it.
Purpose: Resolve FIX-05 — the pointer cursor must appear on hover over every interactive element to meet basic UX expectations.
Output: Updated ItemCard, FabMenu, BottomTabBar with explicit cursor-pointer.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/phases/35-bug-fixes/35-CONTEXT.md
@.planning/phases/35-bug-fixes/35-UI-SPEC.md
</context>
<interfaces>
<!-- Key contracts the executor needs. Extracted from codebase. -->
Current cursor state by component (from codebase audit):
ItemCard (src/client/components/ItemCard.tsx, line 76):
```tsx
// Current — missing cursor-pointer in the navigable case:
className={`relative w-full text-left bg-white rounded-xl border border-gray-100 transition-all overflow-hidden group ${
linkTo === null
? "cursor-default"
: "hover:border-gray-200 hover:shadow-sm" // ← cursor-pointer MISSING here
}`}
// Target — add cursor-pointer to the navigable case:
className={`relative w-full text-left bg-white rounded-xl border border-gray-100 transition-all overflow-hidden group ${
linkTo === null
? "cursor-default"
: "cursor-pointer hover:border-gray-200 hover:shadow-sm"
}`}
```
ItemCard action span buttons (lines 106, 138, 170): already have cursor-pointer — DO NOT CHANGE.
ClassificationBadge: already has cursor-pointer — DO NOT CHANGE.
CandidateCard action spans: already have cursor-pointer — DO NOT CHANGE.
FabMenu (src/client/components/FabMenu.tsx):
- Line 85: menu item `motion.button` className — `"flex items-center gap-3 bg-white shadow-lg rounded-full px-4 py-3 hover:bg-gray-50 transition-colors"` — missing cursor-pointer
- Line 108: main FAB `motion.button` className — `"fixed bottom-6 right-6 z-20 w-14 h-14 bg-gray-700 hover:bg-gray-800 text-white rounded-full shadow-lg hover:shadow-xl transition-colors flex items-center justify-center"` — missing cursor-pointer
BottomTabBar (src/client/components/BottomTabBar.tsx):
- Lines 68, 87, 97: `<button type="button">` wrappers — no explicit cursor-pointer class
- Link elements (lines 50, 60, 79): Links get pointer from browser default — add cursor-pointer explicitly for consistency
Already correct (no changes needed):
- StatusBadge: has cursor-pointer
- CategoryPicker: has cursor-pointer
- PublicSetupCard: has cursor-pointer
- CategoryFilterDropdown: has cursor-pointer
- CatalogSearchOverlay interactive items: has cursor-pointer where needed
- ImageUpload: has cursor-pointer
- ProfileSection avatar: has cursor-pointer
</interfaces>
<tasks>
<task type="auto">
<name>Task 1: Add cursor-pointer to ItemCard navigable case (FIX-05)</name>
<files>src/client/components/ItemCard.tsx</files>
<read_first>
- src/client/components/ItemCard.tsx (read the outer button element at line 73-77 to confirm the current conditional class string)
</read_first>
<action>
In src/client/components/ItemCard.tsx, update the outer `<button>` element's className conditional string (per D-11, D-12, UI-SPEC Cursor Contract).
Find the className on the outer button (line ~76):
```tsx
className={`relative w-full text-left bg-white rounded-xl border border-gray-100 transition-all overflow-hidden group ${linkTo === null ? "cursor-default" : "hover:border-gray-200 hover:shadow-sm"}`}
```
Change to:
```tsx
className={`relative w-full text-left bg-white rounded-xl border border-gray-100 transition-all overflow-hidden group ${linkTo === null ? "cursor-default" : "cursor-pointer hover:border-gray-200 hover:shadow-sm"}`}
```
The only change is adding `cursor-pointer ` before `hover:border-gray-200` in the non-null branch.
Do NOT change:
- The `cursor-default` branch (correct behavior when `linkTo === null`)
- Any action span buttons on the card (lines 106, 138, 170 — already have cursor-pointer)
</action>
<verify>
<automated>cd /home/jlmak/Projects/jlmak/GearBox && grep -n "cursor-pointer hover:border-gray-200" src/client/components/ItemCard.tsx</automated>
</verify>
<acceptance_criteria>
- `grep -n "cursor-pointer hover:border-gray-200" src/client/components/ItemCard.tsx` returns exactly one match on the outer button className
- `grep -n "cursor-default" src/client/components/ItemCard.tsx` still returns one match (the linkTo === null branch is preserved)
- `bun run lint` passes with no errors
</acceptance_criteria>
<done>ItemCard outer button shows cursor-pointer when linkTo is not null, and cursor-default when linkTo === null. Both branches are correctly covered.</done>
</task>
<task type="auto">
<name>Task 2: Add cursor-pointer to FabMenu and BottomTabBar buttons (FIX-05)</name>
<files>
src/client/components/FabMenu.tsx,
src/client/components/BottomTabBar.tsx
</files>
<read_first>
- src/client/components/FabMenu.tsx (read fully — locate motion.button at lines 82-99 and 106-114)
- src/client/components/BottomTabBar.tsx (read fully — locate button elements at lines 68, 87, 97)
</read_first>
<action>
**FabMenu changes** (per D-12, UI-SPEC Cursor Contract §FAB menu items):
1. Menu item buttons (motion.button, currently line ~85) — add `cursor-pointer` to className:
Current: `"flex items-center gap-3 bg-white shadow-lg rounded-full px-4 py-3 hover:bg-gray-50 transition-colors"`
Target: `"flex items-center gap-3 bg-white shadow-lg rounded-full px-4 py-3 hover:bg-gray-50 transition-colors cursor-pointer"`
2. Main FAB button (motion.button, currently line ~108) — add `cursor-pointer` to className:
Current: `"fixed bottom-6 right-6 z-20 w-14 h-14 bg-gray-700 hover:bg-gray-800 text-white rounded-full shadow-lg hover:shadow-xl transition-colors flex items-center justify-center"`
Target: `"fixed bottom-6 right-6 z-20 w-14 h-14 bg-gray-700 hover:bg-gray-800 text-white rounded-full shadow-lg hover:shadow-xl transition-colors flex items-center justify-center cursor-pointer"`
**BottomTabBar changes** (per D-12, UI-SPEC Cursor Contract §All role="button" elements):
For all three `<button type="button">` elements (anonymous user collection tab at line ~68, anonymous setups tab at ~87, search tab at ~97), add `cursor-pointer` to each button element:
Line ~68:
```tsx
<button type="button" onClick={openAuthPrompt} className="cursor-pointer">
```
Line ~87:
```tsx
<button type="button" onClick={openAuthPrompt} className="cursor-pointer">
```
Line ~97:
```tsx
<button type="button" onClick={() => openCatalogSearch("collection")} className="cursor-pointer">
```
</action>
<verify>
<automated>cd /home/jlmak/Projects/jlmak/GearBox && grep -c "cursor-pointer" src/client/components/FabMenu.tsx src/client/components/BottomTabBar.tsx</automated>
</verify>
<acceptance_criteria>
- `grep -c "cursor-pointer" src/client/components/FabMenu.tsx` outputs `2` (menu items button + main FAB button)
- `grep -c "cursor-pointer" src/client/components/BottomTabBar.tsx` outputs `3` (one per anonymous button)
- `bun run lint` passes with no errors across both files
</acceptance_criteria>
<done>FabMenu menu item buttons and main FAB button have explicit cursor-pointer. BottomTabBar's three button elements each have cursor-pointer. All known interactive elements now have correct cursor behavior.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| none | Pure CSS/class changes — no trust boundary implications |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-35-04 | none | cursor-pointer audit | accept | CSS-only change. No logic, data flow, or auth boundary touched. No threat surface. |
</threat_model>
<verification>
After both tasks complete:
1. Open collection overview — hover over an item card (with linkTo set): cursor must be pointer
2. Hover over a card in a setup (linkTo === null): cursor must be default (not pointer) — preserved
3. Open FAB menu — hover over menu items and FAB button: cursor must be pointer
4. On mobile viewport (or DevTools mobile mode), hover/tap BottomTabBar anonymous tabs: buttons must show pointer
Run: `bun run lint` — zero errors
Run: `bun test` — all existing tests pass
</verification>
<success_criteria>
- ItemCard outer button has cursor-pointer in the non-null linkTo branch, cursor-default in the null branch
- FabMenu has cursor-pointer on both motion.button elements (menu items + FAB)
- BottomTabBar has cursor-pointer on all three button elements
- No previously-correct cursor-pointer usage is removed
- bun run lint passes with zero errors
</success_criteria>
<output>
After completion, create `.planning/phases/35-bug-fixes/35-03-SUMMARY.md`
</output>