Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 'use client' import { useRef } from 'react' import { useAbacusConfig } from '@soroban/abacus-react' import { useMyAbacus } from '@/contexts/MyAbacusContext' import { css } from '../../../styled-system/css' import { AbacusVisionBridge } from './AbacusVisionBridge' /** * Modal for configuring abacus vision settings * * Renders AbacusVisionBridge directly in a draggable modal. * The bridge component handles all camera/calibration configuration. */ export function VisionSetupModal() { const constraintRef = useRef<HTMLDivElement>(null) const { isVisionSetupOpen, closeVisionSetup, visionConfig, isVisionSetupComplete, setVisionEnabled, setVisionCamera, setVisionCalibration, setVisionRemoteSession, setVisionCameraSource, } = useMyAbacus() const abacusConfig = useAbacusConfig() const handleClearSettings = () => { setVisionCamera(null) setVisionCalibration(null) setVisionRemoteSession(null) setVisionCameraSource(null) setVisionEnabled(false) } const handleToggleVision = () => { setVisionEnabled(!visionConfig.enabled) } if (!isVisionSetupOpen) return null return ( <div ref={constraintRef} data-component="vision-setup-modal" className={css({ position: 'fixed', inset: 0, bg: 'rgba(0, 0, 0, 0.7)', backdropFilter: 'blur(4px)', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', paddingTop: '60px', // Ensure header is always accessible for dragging paddingBottom: '60px', overflow: 'hidden', zIndex: 10000, })} onClick={closeVisionSetup} onKeyDown={(e) => { if (e.key === 'Escape') { closeVisionSetup() } }} > {/* AbacusVisionBridge is a motion.div with drag - stopPropagation prevents backdrop close */} <div onClick={(e) => e.stopPropagation()}> <AbacusVisionBridge columnCount={abacusConfig.physicalAbacusColumns ?? 4} onValueDetected={() => { // Value detected - configuration is working }} onClose={closeVisionSetup} onConfigurationChange={(config) => { // Save configuration to context as it changes if (config.cameraDeviceId !== undefined) { setVisionCamera(config.cameraDeviceId) } if (config.calibration !== undefined) { setVisionCalibration(config.calibration) } if (config.remoteCameraSessionId !== undefined) { setVisionRemoteSession(config.remoteCameraSessionId) } if (config.activeCameraSource !== undefined) { setVisionCameraSource(config.activeCameraSource) } }} // Use saved activeCameraSource if available, otherwise infer from configs initialCameraSource={ visionConfig.activeCameraSource ?? (visionConfig.remoteCameraSessionId && !visionConfig.cameraDeviceId ? 'phone' : 'local') } // Show enable/disable and clear buttons showVisionControls={true} isVisionEnabled={visionConfig.enabled} isVisionSetupComplete={isVisionSetupComplete} onToggleVision={handleToggleVision} onClearSettings={handleClearSettings} dragConstraintRef={constraintRef} /> </div> </div> ) } |