deckhearth/.convoys/scanner-desktop-layout/brief-2-scanner-tips.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

2.9 KiB

convoy brief_number depends_on recommended_model model_tier files cross_brief_commitments
scanner-desktop-layout 2
composer-2.5-fast fast
components/scanner/ScannerTips.js
test/components/ScannerTips.test.js
brief description
6 Brief 6 mounts `<ScannerTips />` in the desktop page header row (md+ only) beside "Card Scanner" title. This brief ships the self-contained modal + trigger button; no page wiring here.

Brief 2: Scanner Tips modal

Goal (1 sentence)

Ship a desktop Scanner Tips control that opens a glass <Modal> with five convoy-authored tips.

Files in scope (do not edit anything else)

  • components/scanner/ScannerTips.js
  • test/components/ScannerTips.test.js

Conventions to follow

  • Use Modal + Button from components/ui — no custom scrim (ui-and-theming.mdc).
  • Glass panel recipe: --glass-surface-low via GlassSurface inside modal body if needed.
  • Copy locked (Design direction + IA):
# Tip
1 Good lighting — avoid glare on foil cards.
2 Fill the frame with one card; keep corners visible.
3 Hold still until Auto-detect locks the match.
4 Use Batch Scan for a pile of photos from your gallery.
5 Switch camera if the image is dark or mirrored.
  • Modal title: Scanner Tips. Trigger: ghost Button with lightbulb SVG + label Scanner Tips (visible text for 2.5.3 Label in Name).
  • Dismiss: close control, Esc, scrim click — standard <Modal> behavior.
  • No hex in .js; tokens only.
  • Test pattern: test/components/ScannerCheckoutSheet.test.js (vitest + jsdom + RTL).

Implementation shape

export default function ScannerTips({ className = '' }) {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button variant="ghost" onClick={() => setOpen(true)} /* lightbulb + Scanner Tips */ />
      <Modal open={open} onClose={() => setOpen(false)} title="Scanner Tips" size="md">
        <ol className="space-y-4 text-sm" style={{ color: 'var(--text-secondary)' }}>
          {/* five <li> with <strong> lead + em dash body */}
        </ol>
      </Modal>
    </>
  );
}

Component is self-contained — no props required v1.

Acceptance criteria

  • Trigger shows lightbulb icon + Scanner Tips visible label
  • Modal lists exactly five tips with locked copy
  • Uses <Modal> primitive (no fixed inset-0 bg-black shell)
  • Opening/closing traps focus per existing Modal behavior
  • tests: trigger opens modal, all five tips visible, close dismisses
  • no scope expansion (do not edit files outside files: above)

Rationale (≤3 sentences)

Tips are a standalone surface (C3) with no queue or camera dependencies. Shipping the modal in isolation lets Brief 6 wire it into the header without blocking other parallel work. Five tips exceed popover length — Modal is Design-locked.