Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions src/islands/image/CameraCapture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,37 +39,43 @@ export default function CameraCapture({

const onFallbackFile = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) onCapture(file);
if (file) { stop(); onCapture(file); }
};

const useDeviceCamera = () => fileInputRef.current?.click();

return (
<div className="space-y-3 border-2 border-border p-3">
{error ? (
<div className="space-y-2">
<Alert variant="error">{error.message}</Alert>
<div className="flex flex-wrap gap-2">
<Button variant="secondary" onClick={() => fileInputRef.current?.click()}>Use device camera</Button>
<Button variant="secondary" onClick={useDeviceCamera}>Use device camera</Button>
<Button variant="ghost" onClick={cancel}>Cancel</Button>
</div>
<input
ref={fileInputRef}
type="file"
accept="image/*"
capture="environment"
onChange={onFallbackFile}
className="hidden"
/>
</div>
) : (
<div className="space-y-3">
<video ref={videoRef} playsInline muted className="max-h-96 w-auto border-2 border-border" />
<div className="flex flex-wrap gap-2">
<Button onClick={capture} disabled={busy || !stream}>{busy ? 'Capturing…' : 'Capture'}</Button>
{hasMultiple && <Button variant="secondary" onClick={switchCamera}>Switch camera</Button>}
{/* Always available — opens the OS camera app on phones. */}
<Button variant="secondary" onClick={useDeviceCamera}>Use device camera</Button>
<Button variant="ghost" onClick={cancel}>Cancel</Button>
</div>
</div>
)}

{/* Native capture input, always mounted so it works in either state. */}
<input
ref={fileInputRef}
type="file"
accept="image/*"
capture="environment"
onChange={onFallbackFile}
className="hidden"
/>
</div>
);
}
Loading