LumiSign / ui /src /app /components /VideoInput.tsx
anthony01's picture
feat: add UI components including Skeleton, Slider, Sonner, Switch, Table, Tabs, Textarea, Toggle Group, Toggle, Tooltip, and utility hooks
263280b
Raw
History Blame Contribute Delete
5.28 kB
import { useEffect, useRef } from 'react';
interface VideoInputProps {
onVideoUpload: (file: File) => void;
videoFile: File | null;
isProcessing: boolean;
onToggleCamera: () => void;
cameraStream: MediaStream | null;
previewUrl: string | null;
}
export function VideoInput({
onVideoUpload,
videoFile,
isProcessing,
onToggleCamera,
cameraStream,
previewUrl,
}: VideoInputProps) {
const fileInputRef = useRef<HTMLInputElement>(null);
const previewRef = useRef<HTMLVideoElement>(null);
useEffect(() => {
const video = previewRef.current;
if (!video) return;
if (cameraStream) {
video.srcObject = cameraStream;
video.muted = true;
void video.play();
return;
}
if (previewUrl) {
video.srcObject = null;
video.src = previewUrl;
void video.play();
return;
}
video.srcObject = null;
video.removeAttribute('src');
video.load();
}, [cameraStream, previewUrl]);
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
onVideoUpload(file);
}
};
return (
<div className="bg-white rounded-lg border border-gray-200 p-6 mb-6">
<div className="flex items-center justify-between mb-4">
<div>
<h2 className="text-xl mb-1">Video Input</h2>
<p className="text-sm text-gray-600">Upload a video or use your camera to capture sign language</p>
</div>
<div className="flex gap-2">
<button
onClick={onToggleCamera}
disabled={isProcessing}
className="px-4 py-2 border border-gray-300 rounded-lg bg-white hover:bg-gray-50 flex items-center gap-2 disabled:cursor-not-allowed disabled:opacity-60"
>
<span>📹</span>
Use Camera
</button>
<button
onClick={() => fileInputRef.current?.click()}
disabled={isProcessing}
className="px-4 py-2 bg-black text-white rounded-lg hover:bg-gray-800 flex items-center gap-2 disabled:cursor-not-allowed disabled:opacity-60"
>
<span></span>
Upload Video
</button>
<input
ref={fileInputRef}
type="file"
accept="video/*"
onChange={handleFileChange}
className="hidden"
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
{/* Original Video Feed */}
<div className="bg-gray-900 rounded-lg p-8 aspect-video flex flex-col items-center justify-center">
{cameraStream || previewUrl ? (
<video
ref={previewRef}
className="h-full w-full rounded-lg object-cover"
playsInline
/>
) : (
<>
<div className="text-gray-600 mb-3">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
<rect x="2" y="7" width="20" height="14" rx="2" ry="2"></rect>
<polyline points="23 7 16 12 23 17"></polyline>
</svg>
</div>
<div className="text-gray-500 text-center">
<div className="font-medium mb-1">Original Video Feed</div>
<div className="text-sm">Camera inactive</div>
</div>
</>
)}
{videoFile && (
<div className="mt-4 text-white text-sm">
✓ {videoFile.name}
</div>
)}
<div className="mt-6 text-gray-600 text-sm">
Duration: 00:00
</div>
</div>
{/* Enhanced Video */}
<div className="bg-gray-900 rounded-lg p-8 aspect-video flex flex-col items-center justify-center">
<div className="text-gray-600 mb-3">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
<circle cx="12" cy="12" r="3"></circle>
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="2" x2="12" y2="4"></line>
<line x1="12" y1="20" x2="12" y2="22"></line>
<line x1="4.93" y1="4.93" x2="6.34" y2="6.34"></line>
<line x1="17.66" y1="17.66" x2="19.07" y2="19.07"></line>
<line x1="2" y1="12" x2="4" y2="12"></line>
<line x1="20" y1="12" x2="22" y2="12"></line>
<line x1="6.34" y1="17.66" x2="4.93" y2="19.07"></line>
<line x1="19.07" y1="4.93" x2="17.66" y2="6.34"></line>
</svg>
</div>
<div className="text-gray-500 text-center">
<div className="font-medium mb-1">Enhanced Video</div>
<div className="text-sm">Brightness correction applied</div>
</div>
<div className="mt-6 flex gap-8 text-sm">
<div className="text-gray-600">
Resolution: --
</div>
<div className="text-gray-600">
Enhancement: Pending
</div>
<div className="text-gray-600">
Quality: --
</div>
</div>
</div>
</div>
</div>
);
}