Vinh.Vu commited on
Commit
d92592b
Β·
1 Parent(s): 3b7fd58

Update layout

Browse files
Files changed (2) hide show
  1. App/static/app.jsx +19 -41
  2. App/static/style.css +2 -0
App/static/app.jsx CHANGED
@@ -46,29 +46,7 @@ function UploadArea({ file, onFileChange }) {
46
  );
47
  }
48
 
49
- /* ── Video Preview ── */
50
- function VideoPreview({ file, serverUrl }) {
51
- const [localUrl, setLocalUrl] = useState(null);
52
-
53
- useEffect(() => {
54
- if (file) {
55
- const url = URL.createObjectURL(file);
56
- setLocalUrl(url);
57
- return () => URL.revokeObjectURL(url);
58
- }
59
- setLocalUrl(null);
60
- }, [file]);
61
 
62
- const src = serverUrl || localUrl;
63
- return (
64
- <div className="video-preview">
65
- {src
66
- ? <video controls src={src} key={src} />
67
- : <div className="preview-placeholder">&#127916;</div>
68
- }
69
- </div>
70
- );
71
- }
72
 
73
  /* ── Status Spinner ── */
74
  function StatusIndicator({ status }) {
@@ -82,7 +60,8 @@ function StatusIndicator({ status }) {
82
  }
83
 
84
  /* ── Video Comparison ── */
85
- function VideoComparison({ file, processedUrl, isProcessing }) {
 
86
  const [localUrl, setLocalUrl] = useState(null);
87
 
88
  useEffect(() => {
@@ -94,31 +73,31 @@ function VideoComparison({ file, processedUrl, isProcessing }) {
94
  setLocalUrl(null);
95
  }, [file]);
96
 
97
- if (!processedUrl && !isProcessing) return null;
 
98
  return (
99
  <section className="video-compare">
100
- <h2>Face Detection</h2>
101
- <div className="compare-grid">
102
  <div className="compare-item">
103
- {localUrl
104
- ? <video controls src={localUrl} key={localUrl} />
105
- : <div className="preview-placeholder">&#127916;</div>
106
- }
107
  <div className="compare-label original">Original</div>
108
  </div>
109
- <div className="compare-item">
110
- {processedUrl
111
- ? <video controls src={processedUrl} key={processedUrl} />
112
- : <div className="preview-placeholder"><div className="spinner" /></div>
113
- }
114
- <div className="compare-label detected">
115
- {processedUrl ? 'Detected Faces' : 'Generating\u2026'}
 
 
116
  </div>
117
- </div>
118
  </div>
119
  </section>
120
  );
121
- }
122
 
123
  /* ── Face Row ── */
124
  function FaceRow({ face, index }) {
@@ -258,13 +237,12 @@ function App() {
258
  {error && <div className="error-box">{error}</div>}
259
  </div>
260
 
261
- <VideoPreview file={file} serverUrl={result?.video_url} />
262
  </section>
263
 
264
  <VideoComparison
265
  file={file}
266
  processedUrl={result?.processed_url}
267
- isProcessing={status === 'processing_video'}
268
  />
269
  <ResultsPanel data={result} />
270
  </>
 
46
  );
47
  }
48
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  /* ── Status Spinner ── */
52
  function StatusIndicator({ status }) {
 
60
  }
61
 
62
  /* ── Video Comparison ── */
63
+ const VideoComparison = React.memo(function VideoComparison({ file, processedUrl, isProcessing }) {
64
+ const videoRef = useRef(null);
65
  const [localUrl, setLocalUrl] = useState(null);
66
 
67
  useEffect(() => {
 
73
  setLocalUrl(null);
74
  }, [file]);
75
 
76
+ if (!localUrl) return null;
77
+ const showProcessed = processedUrl || isProcessing;
78
  return (
79
  <section className="video-compare">
80
+ <h2>{showProcessed ? 'Face Detection' : 'Uploaded Video'}</h2>
81
+ <div className={`compare-grid${showProcessed ? '' : ' single'}`}>
82
  <div className="compare-item">
83
+ <video ref={videoRef} controls src={localUrl} />
 
 
 
84
  <div className="compare-label original">Original</div>
85
  </div>
86
+ {showProcessed && (
87
+ <div className="compare-item">
88
+ {processedUrl
89
+ ? <video controls src={processedUrl} />
90
+ : <div className="preview-placeholder"><div className="spinner" /></div>
91
+ }
92
+ <div className="compare-label detected">
93
+ {processedUrl ? 'Detected Faces' : 'Generating\u2026'}
94
+ </div>
95
  </div>
96
+ )}
97
  </div>
98
  </section>
99
  );
100
+ });
101
 
102
  /* ── Face Row ── */
103
  function FaceRow({ face, index }) {
 
237
  {error && <div className="error-box">{error}</div>}
238
  </div>
239
 
 
240
  </section>
241
 
242
  <VideoComparison
243
  file={file}
244
  processedUrl={result?.processed_url}
245
+ isProcessing={submitting}
246
  />
247
  <ResultsPanel data={result} />
248
  </>
App/static/style.css CHANGED
@@ -58,6 +58,8 @@ input[type="file"] { display: none; }
58
  .video-compare { max-width: 1100px; margin: 40px auto 0; padding: 0 40px; }
59
  .video-compare h2 { font-size: 20px; font-weight: 700; color: #fff; margin-bottom: 16px; }
60
  .compare-grid { display: flex; gap: 24px; }
 
 
61
  .compare-item { flex: 1; text-align: center; }
62
  .compare-item video {
63
  width: 100%; max-height: 360px; border-radius: 12px; border: 1px solid #1e1e35; background: #111122;
 
58
  .video-compare { max-width: 1100px; margin: 40px auto 0; padding: 0 40px; }
59
  .video-compare h2 { font-size: 20px; font-weight: 700; color: #fff; margin-bottom: 16px; }
60
  .compare-grid { display: flex; gap: 24px; }
61
+ .compare-grid.single { justify-content: center; }
62
+ .compare-grid.single .compare-item { max-width: 640px; }
63
  .compare-item { flex: 1; text-align: center; }
64
  .compare-item video {
65
  width: 100%; max-height: 360px; border-radius: 12px; border: 1px solid #1e1e35; background: #111122;