Files
GearBox/.planning/milestones/v2.2-phases/31-mobile-polish/31-RESEARCH.md
Jean-Luc Makiola 2853477a75
All checks were successful
CI / ci (push) Successful in 1m15s
CI / e2e (push) Has been skipped
CI / deploy (push) Has been skipped
chore: archive v2.2 User Experience Polish milestone
Phases 28-31 archived to milestones/v2.2-phases/
Requirements and roadmap snapshots archived to milestones/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:00:35 +02:00

6.6 KiB

Phase 31: Mobile Polish — Research

Researched: 2026-04-12 Status: Complete Focus: Icon-based action buttons on mobile detail pages

Standard Stack

  • Component library: None (plain Tailwind CSS v4)
  • Icon library: lucide-react via LucideIcon component (src/client/lib/iconData.tsx)
  • Styling: Tailwind CSS v4 with @import "tailwindcss" (no custom tokens, no config file)
  • Responsive pattern: md: breakpoint (768px) — matches BottomTabBar (md:hidden) and TopNav (hidden md:flex)

Action Button Inventory

1. Item Detail (src/client/routes/items/$itemId.tsx)

Location: Top bar, right side (lines ~190-213) Current pattern: Text-only buttons in a flex items-center gap-2 container Edit mode: Visible when !isEditing

Button Text Current Classes Icon Candidate
Duplicate "Duplicate" px-3 py-1.5 text-sm text-gray-500 hover:text-gray-700 hover:bg-gray-50 rounded-lg copy (16px)
Delete/Remove "Delete" or "Remove from Collection" px-3 py-1.5 text-sm text-red-400 hover:text-red-600 hover:bg-red-50 rounded-lg trash-2 (16px)
Edit "Edit" px-4 py-1.5 text-sm font-medium text-white bg-gray-700 hover:bg-gray-800 rounded-lg pencil (16px)

Edit mode buttons (Cancel/Save): These should remain text buttons even on mobile — users need clear text feedback during edit operations.

2. Candidate Detail (src/client/routes/threads/$threadId/candidates/$candidateId.tsx)

Location 1: Header area — Edit button inline with heading (line ~282-289) Current pattern: Small text+icon button (LucideIcon name="pencil" size={14} + "Edit" text)

Location 2: Bottom actions area (lines ~530-548) Current pattern: Text+icon buttons in flex gap-3 pt-4 border-t border-gray-100

Button Text Current Pattern Icon Candidate
Edit (header) "Edit" px-3 py-1.5 text-sm + pencil icon 14px Already has icon — hide text on mobile
Pick as Winner "Pick as winner" px-4 py-2 + trophy icon 14px trophy (16px)
Delete "Delete" px-4 py-2 + trash-2 icon 14px Already has icon — hide text on mobile

3. Setup Detail (src/client/routes/setups/$setupId.tsx)

Location: Toolbar area below header (lines ~155-210) Current pattern: Mixed text+icon and text-only buttons in flex items-center gap-3

Button Text Current Pattern Icon Candidate
Add Items "Add Items" px-4 py-2 + inline SVG plus icon plus (16px) via LucideIcon
Public toggle "Public"/"Private" px-3 py-2 + inline SVG globe globe (16px) via LucideIcon
Delete Setup "Delete Setup" px-4 py-2 text-red-600 bg-red-50 trash-2 (16px)

Note: Setup page uses inline SVGs instead of LucideIcon — migration to LucideIcon is a natural cleanup.

4. Global Item Detail (src/client/routes/global-items/$globalItemId.tsx)

Location: Action buttons below image (lines ~167-193) Current pattern: Text-only buttons in flex gap-3 mb-6

Button Text Current Pattern Icon Candidate
Add to Collection "Add to Collection" px-5 py-2.5 bg-gray-700 text-white plus (16px)
Add to Thread "Add to Thread" px-5 py-2.5 bg-white border message-square-plus (16px)

Architecture Patterns

Use paired hidden/visible elements with responsive Tailwind classes:

{/* Desktop: text + optional icon */}
<button className="hidden md:inline-flex items-center gap-1.5 px-3 py-1.5 text-sm ...">
  <LucideIcon name="pencil" size={14} />
  Edit
</button>

{/* Mobile: icon-only with touch target */}
<button
  className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 rounded-lg ..."
  aria-label="Edit"
  title="Edit"
>
  <LucideIcon name="pencil" size={16} />
</button>

Alternative: Single Element with Responsive Text Hiding

<button className="inline-flex items-center gap-1.5 px-2 md:px-3 py-1.5 min-w-[44px] min-h-[44px] md:min-w-0 md:min-h-0 justify-center md:justify-start ..." aria-label="Edit">
  <LucideIcon name="pencil" size={16} className="md:w-3.5 md:h-3.5" />
  <span className="hidden md:inline text-sm">Edit</span>
</button>

Recommendation: Use the paired-element approach for cleaner code and independent styling control. The single-element approach has too many responsive overrides.

Alternative considered and rejected: A shared IconActionButton component. The action buttons across pages have different styling (primary, secondary, destructive), different sizes, and different hover states. A shared component would need too many props and wouldn't simplify the code meaningfully for just 4 pages.

LucideIcon Migration for Setup Page

The setup detail page uses inline SVGs for the plus icon and globe icon. These should be migrated to LucideIcon for consistency:

  • Plus SVG → <LucideIcon name="plus" size={16} />
  • Globe SVG → <LucideIcon name="globe" size={16} />

Touch Target Sizing

  • Minimum 44x44px per WCAG 2.5.5 (AAA) / Apple HIG
  • Achieved with min-w-[44px] min-h-[44px] on mobile icon buttons
  • Desktop buttons keep current sizing (no min-width needed)

Edit Mode Buttons

Cancel and Save buttons during edit mode should remain text buttons on both mobile and desktop:

  • These are contextual actions that need clear text labels
  • Edit mode is a temporary state — users need to see "Cancel" and "Save" text clearly
  • No risk of button crowding since they replace the action buttons

Dependencies

None. This phase is self-contained — only modifies existing button rendering in 4 route files.

Risks

  1. Low risk: Button group layout may need adjustment on very small screens (< 375px) if multiple icon buttons overflow. Mitigation: test at 320px width.
  2. Low risk: Missing aria-label would make icon buttons inaccessible. Mitigation: acceptance criteria require aria-label on every icon button.

Validation Architecture

Validation Strategy

Dimension What to Validate How
Visual Icon buttons render on mobile, text on desktop E2E viewport test or manual check
Accessibility All icon buttons have aria-label Grep for aria-label on new button elements
Touch targets Minimum 44px on mobile CSS class inspection (min-w-[44px] min-h-[44px])
Consistency Same breakpoint (md:) across all pages Grep for breakpoint usage
No regression Desktop buttons unchanged Visual comparison

RESEARCH COMPLETE