Files
GearBox/.planning/phases/12-comparison-view/12-CONTEXT.md
Jean-Luc Makiola 9636033361 fix(29-02): lint fixes for GearImage integration
Fix unused parameter warning and formatting issues across all
updated components.

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

5.8 KiB

Phase 12: Comparison View - Context

Gathered: 2026-03-17 Status: Ready for planning

## Phase Boundary

Users can view all candidates for a thread side-by-side in a tabular comparison layout with relative weight and price deltas. The table scrolls horizontally on narrow viewports with a sticky label column. Resolved threads display the comparison in read-only mode with the winning candidate visually marked. Impact preview (setup deltas) is a separate phase (13).

## Implementation Decisions

Compare mode entry point

  • Add a third icon to the existing list/grid toggle bar, making it list | grid | compare (three-way toggle)
  • Use candidateViewMode: 'list' | 'grid' | 'compare' in uiStore — extends the existing Zustand state
  • Compare icon only appears when 2+ candidates exist in the thread (hidden otherwise)
  • "Add Candidate" button visibility in compare mode is Claude's discretion

Table orientation and layout

  • Candidates as columns, attribute labels as rows (classic product-comparison pattern — Amazon/Wirecutter style)
  • Sticky left column for attribute labels; table scrolls horizontally on narrow viewports
  • Attribute row order: Image → Name → Rank → Weight (with delta) → Price (with delta) → Status → Product Link → Notes → Pros → Cons
  • Image row: sizing is Claude's discretion (balance compactness with product visibility)
  • Multi-line text (notes, pros, cons): rendering approach is Claude's discretion (keep table scannable)

Delta highlighting style

  • Lightest candidate's weight cell gets a subtle colored background tint (e.g., bg-green-50); cheapest similarly
  • Non-best cells show delta text in neutral gray — no colored badges for deltas, only the "best" cell gets color
  • Missing weight/price data: Claude's discretion on indicator style (must satisfy COMP-04 — no misleading zeroes)
  • Delta format (absolute + delta, or delta only): Claude's discretion based on readability

Resolved thread presentation

  • Winner column highlight and trophy/banner approach: Claude's discretion (existing resolution banner + column tint are both available patterns)
  • Interactive elements in resolved comparison (links clickable vs everything static): Claude's discretion, following the existing Phase 11 pattern where resolved threads disable mutation actions but keep read-only indicators
  • Existing resolution banner above the comparison table: Claude's discretion on whether to keep it, remove it, or adapt it

Claude's Discretion

  • "Add Candidate" button visibility when in compare view
  • Image thumbnail sizing in comparison cells (square crop vs wider aspect)
  • Multi-line text rendering strategy (clamped with expand vs full text)
  • Missing data indicator style (dash with label, empty cell, etc.)
  • Delta format: absolute value + delta underneath, or delta only for non-best cells
  • Winner column marking approach (column tint, trophy icon, or both)
  • Resolved thread interactivity (links clickable vs all read-only)
  • Resolution banner behavior in compare view
  • View mode persistence (already in Zustand — whether compare resets on navigation or persists)
  • Compare toggle icon choice (e.g., Lucide columns-3, table-2, or similar)
  • Table cell padding, border styling, and overall table chrome
  • Column minimum/maximum widths
  • Keyboard accessibility for horizontal scrolling

<code_context>

Existing Code Insights

Reusable Assets

  • candidateViewMode in uiStore (stores/uiStore.ts): Already stores 'list' | 'grid' — extend to include 'compare'
  • CandidateCard / CandidateListItem: Data shape reference for what fields are available per candidate
  • formatWeight() / formatPrice() in lib/formatters.ts: Unit-aware formatting for table cells and deltas
  • useWeightUnit() / useCurrency() hooks: Current unit/currency for display
  • RankBadge (CandidateListItem.tsx): Exported component for gold/silver/bronze medals — reuse in compare table name row
  • StatusBadge (StatusBadge.tsx): Click-to-cycle status — render as static text in compare view (no interaction needed)
  • LucideIcon helper: For compare toggle icon and any icons in the table
  • useThread(threadId) hook: Returns thread.candidates[] with all fields needed (name, weightGrams, priceCents, status, pros, cons, notes, productUrl, imageFilename, categoryName, categoryIcon)

Established Patterns

  • Three-way toggle: Extend existing bg-gray-100 rounded-lg p-0.5 toggle bar pattern from thread toolbar
  • Pill badges: blue=weight, green=price, gray=category, purple=pros/cons — table can reference these colors for consistency
  • framer-motion already installed — AnimatePresence for view transitions if desired
  • React Query for server data, Zustand for UI-only state
  • Resolution banner: amber-50 bg with amber-200 border in resolved thread header — reusable pattern for winner column

Integration Points

  • src/client/routes/threads/$threadId.tsx: Add compare view branch to the existing list/grid conditional rendering
  • src/client/stores/uiStore.ts: Extend candidateViewMode union type to include 'compare'
  • New component: ComparisonTable.tsx (or similar) — receives candidates array, renders the tabular comparison
  • No backend changes needed — all data already available from useThread hook
  • No schema changes — this is a pure frontend/UI phase

</code_context>

## Specific Ideas
  • Classic product-comparison table like Amazon or Wirecutter — candidates as columns, attributes as rows
  • Subtle green tint on the "best" cell rather than heavy badges or bold formatting — keeps the minimalist feel
  • Gray delta text for non-best values — visual hierarchy: best stands out, others recede
## Deferred Ideas

None — discussion stayed within phase scope


Phase: 12-comparison-view Context gathered: 2026-03-17