deckhearth/.convoys/scanner-desktop-layout/brief-3-result-inspector.md
varutasu 938c161a26
feat(scanner): add desktop workstation layout (#165)
Give /scanner a md+ camera, live match inspector, and history strip
(with device picker, batch scan, and tips) without regressing the
mobile immersive checkout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-15 17:21:23 -05:00

3.4 KiB

convoy brief_number depends_on recommended_model model_tier files cross_brief_commitments
scanner-desktop-layout 3
composer-2.5-fast fast
components/scanner/ScannerResultPanel.js
test/components/ScannerResultPanel.test.js
brief description
6 Brief 6 passes `focusedCard`, `queue`, `isIdentifying`, handlers (`onAddToOwned`, `onAddToList`, `onRescan`), and `commitError`. On successful add, Brief 6 advances `focusedCardId` to the next unprocessed entry and fires `ScannerToast` — this component calls `onAddToOwned` only.

Brief 3: Live match inspector rail

Goal (1 sentence)

Build the right-rail ScannerResultPanel that inspects the focused cart entry and commits one card via VOCAB.ADD_TO_MY_COLLECTION.

Files in scope (do not edit anything else)

  • components/scanner/ScannerResultPanel.js
  • test/components/ScannerResultPanel.test.js

Conventions to follow

  • Import VOCAB from lib/collection-vocabulary.js — never ship forbidden strings (forbidden-stale-strings CI).
  • Primitives: GlassSurface, Button from components/ui.
  • Duplicate minimally from ReviewCardItem.js: CONDITION_OPTIONS, confidencePercent, confidenceRingColor (do not edit ReviewCardItem in this brief).
  • Confidence captions (Design direction): ≥90% Excellent match. · ≥70% Good match. · <70% Low confidence — verify before adding.
  • Inspector thumbnail + tiles: solid --bg-secondaryno backdrop-filter on per-card elements.
  • Empty state: centered muted scan/camera SVG illustration + single line: Point your camera at a card or upload an image to see a match.no Upload/Batch CTAs in rail.
  • Populated: thumbnail, name (text-lg font-semibold), set · rarity · collector #, condition <select> (aria-label includes card name), foil role="switch", confidence % + horizontal bar (300ms width transition; @media (prefers-reduced-motion: reduce) → instant).
  • Actions: primary VOCAB.ADD_TO_MY_COLLECTION · ghost Rescan · ghost VOCAB.ADD_TO_LIST.
  • Primary Button uses loading when isAdding (from queue.addingCardIds.has(card.id)).
  • Commit errors: role="alert" div with color-mix(in srgb, var(--color-error) …) pattern from pages/scanner.js.
  • isIdentifying state: show Identifying… placeholder when true and no focused card yet.

Props shape (for Brief 6 wiring)

export default function ScannerResultPanel({
  focusedCard = null,
  queue,
  isIdentifying = false,
  commitError = null,
  onAddToOwned,
  onAddToList,
  onRescan,
}) {

onUpdateMetadata via queue.updateCardMetadata(focusedCard.id, patch) inline.

Acceptance criteria

  • Empty state: illustration + one line only (no duplicate Upload/Batch)
  • Populated state shows metadata, condition select, foil switch, confidence bar
  • Primary button label is VOCAB.ADD_TO_MY_COLLECTION
  • Secondary row: Rescan + VOCAB.ADD_TO_LIST (no wishlist)
  • prefers-reduced-motion disables confidence bar width animation
  • tests: empty state, populated card, add button disabled while adding
  • no scope expansion (do not edit files outside files: above)

Rationale (≤3 sentences)

The inspector replaces the 360px cart side panel as the primary right-hand surface on desktop. Keeping it a dumb view lets Brief 6 own focus/advance/toast orchestration. Confidence and condition UX matches checkout patterns users already know from ReviewCardItem.