Abdullahrasheed45 commited on
Commit
da4009c
·
verified ·
1 Parent(s): ffa32af

Create WebcamCapture.tsx

Browse files
Files changed (1) hide show
  1. src/components/WebcamCapture.tsx +147 -0
src/components/WebcamCapture.tsx ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Button from "./Button";
2
+ import { THEME } from "../constants";
3
+
4
+ interface WebcamCaptureProps {
5
+ isRunning: boolean;
6
+ onToggleRunning: () => void;
7
+ error?: string | null;
8
+ imageSize?: number;
9
+ onImageSizeChange?: (size: number) => void;
10
+ }
11
+
12
+ export default function WebcamCapture({
13
+ isRunning,
14
+ onToggleRunning,
15
+ error,
16
+ imageSize,
17
+ onImageSizeChange,
18
+ }: WebcamCaptureProps) {
19
+ const hasError = Boolean(error);
20
+
21
+ const statusConfig = hasError
22
+ ? {
23
+ text: "SIGNAL LOSS",
24
+ color: "bg-[var(--mistral-red)]",
25
+ border: "border-[var(--mistral-red)]",
26
+ }
27
+ : isRunning
28
+ ? {
29
+ text: "LIVE FEED",
30
+ color: "bg-[var(--mistral-orange)] animate-pulse",
31
+ border: "border-[var(--mistral-orange)]",
32
+ }
33
+ : {
34
+ text: "PAUSED",
35
+ color: "bg-[var(--mistral-orange-dark)]",
36
+ border: "border-[var(--mistral-beige-dark)]",
37
+ };
38
+
39
+ return (
40
+ <>
41
+ {/* Controls Layer */}
42
+ <div className="absolute inset-0 z-20 flex flex-col justify-between p-6 pointer-events-none">
43
+ {/* Top Bar */}
44
+ <div className="flex justify-between items-start pointer-events-auto">
45
+ {/* Status Indicator */}
46
+ <div
47
+ className="backdrop-blur-md border rounded-sm px-3 py-1.5 flex items-center space-x-3 shadow-sm"
48
+ style={{
49
+ backgroundColor: `${THEME.beigeLight}E6`,
50
+ borderColor: THEME.beigeDark,
51
+ }}
52
+ >
53
+ <div className="relative flex h-2.5 w-2.5">
54
+ {isRunning && !hasError && (
55
+ <span
56
+ className={`animate-ping absolute inline-flex h-full w-full rounded-full opacity-75 ${statusConfig.color}`}
57
+ ></span>
58
+ )}
59
+ <span
60
+ className={`relative inline-flex rounded-full h-2.5 w-2.5 ${statusConfig.color}`}
61
+ ></span>
62
+ </div>
63
+ <span
64
+ className="text-xs font-mono font-bold tracking-widest"
65
+ style={{ color: THEME.textBlack }}
66
+ >
67
+ {statusConfig.text}
68
+ </span>
69
+ </div>
70
+ {/* Controls */}
71
+ <div className="flex gap-2 items-center">
72
+ {/* Resolution Slider */}
73
+ {imageSize && onImageSizeChange && (
74
+ <div
75
+ className="hidden md:flex items-center gap-3 backdrop-blur-md border rounded-sm px-3 py-1.5 shadow-sm mr-2 group relative"
76
+ style={{
77
+ backgroundColor: `${THEME.beigeLight}E6`,
78
+ borderColor: THEME.beigeDark,
79
+ }}
80
+ >
81
+ <div className="flex flex-col items-start gap-1 my-1">
82
+ <span className="text-[8px] font-mono text-gray-400 uppercase tracking-wider leading-none mb-1">
83
+ Input Size: {imageSize}px
84
+ </span>
85
+ <input
86
+ type="range"
87
+ min="256"
88
+ max="960"
89
+ step="32"
90
+ value={imageSize}
91
+ onChange={(e) => onImageSizeChange(Number(e.target.value))}
92
+ className="w-24 h-1 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-[var(--mistral-orange)]"
93
+ />
94
+ </div>
95
+ {/* Tooltip */}
96
+ <div
97
+ className="absolute top-full right-0 mt-2 w-54 p-2 text-white text-[10px] rounded shadow-xl opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none z-50 font-mono"
98
+ style={{ backgroundColor: THEME.textBlack }}
99
+ >
100
+ <p className="mb-1">
101
+ <span style={{ color: THEME.mistralOrange }}>&lt;</span>{" "}
102
+ Lower = Faster (Less accurate)
103
+ </p>
104
+ <p>
105
+ <span style={{ color: THEME.mistralOrange }}>&gt;</span>{" "}
106
+ Higher = Slower (More accurate)
107
+ </p>
108
+ </div>
109
+ </div>
110
+ )}
111
+ <Button
112
+ onClick={onToggleRunning}
113
+ aria-label={isRunning ? "Pause captioning" : "Resume captioning"}
114
+ className="backdrop-blur-md bg-white/90 hover:bg-white border hover:border-[var(--mistral-orange)] hover:text-[var(--mistral-orange)] p-2.5 rounded-sm shadow-sm transition-all"
115
+ >
116
+ {isRunning ? (
117
+ <svg
118
+ className="w-6 h-6"
119
+ fill="currentColor"
120
+ viewBox="0 0 20 20"
121
+ >
122
+ <path
123
+ fillRule="evenodd"
124
+ d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z"
125
+ clipRule="evenodd"
126
+ />
127
+ </svg>
128
+ ) : (
129
+ <svg
130
+ className="w-6 h-6"
131
+ fill="currentColor"
132
+ viewBox="0 0 20 20"
133
+ >
134
+ <path
135
+ fillRule="evenodd"
136
+ d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
137
+ clipRule="evenodd"
138
+ />
139
+ </svg>
140
+ )}
141
+ </Button>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </>
146
+ );
147
+ }