analytica-frontend-lib 1.1.10 → 1.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/VideoPlayer/index.js +347 -183
- package/dist/VideoPlayer/index.js.map +1 -1
- package/dist/VideoPlayer/index.mjs +353 -184
- package/dist/VideoPlayer/index.mjs.map +1 -1
- package/dist/index.css +3 -3
- package/dist/index.css.map +1 -1
- package/dist/index.js +347 -183
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +353 -184
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +3 -3
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
// src/components/VideoPlayer/VideoPlayer.tsx
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useRef,
|
|
4
|
+
useState,
|
|
5
|
+
useEffect,
|
|
6
|
+
useCallback
|
|
7
|
+
} from "react";
|
|
3
8
|
import {
|
|
4
9
|
Play,
|
|
5
10
|
Pause,
|
|
@@ -130,6 +135,85 @@ var formatTime = (seconds) => {
|
|
|
130
135
|
const secs = Math.floor(seconds % 60);
|
|
131
136
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
132
137
|
};
|
|
138
|
+
var ProgressBar = ({
|
|
139
|
+
currentTime,
|
|
140
|
+
duration,
|
|
141
|
+
progressPercentage,
|
|
142
|
+
onSeek
|
|
143
|
+
}) => /* @__PURE__ */ jsx3("div", { className: "px-4 pb-2", children: /* @__PURE__ */ jsx3(
|
|
144
|
+
"input",
|
|
145
|
+
{
|
|
146
|
+
type: "range",
|
|
147
|
+
min: 0,
|
|
148
|
+
max: duration || 100,
|
|
149
|
+
value: currentTime,
|
|
150
|
+
onChange: (e) => onSeek(parseFloat(e.target.value)),
|
|
151
|
+
className: "w-full h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer slider:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
152
|
+
"aria-label": "Video progress",
|
|
153
|
+
style: {
|
|
154
|
+
background: `linear-gradient(to right, var(--color-primary-700) ${progressPercentage}%, var(--color-secondary-300) ${progressPercentage}%)`
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
) });
|
|
158
|
+
var VolumeControls = ({
|
|
159
|
+
volume,
|
|
160
|
+
isMuted,
|
|
161
|
+
onVolumeChange,
|
|
162
|
+
onToggleMute
|
|
163
|
+
}) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
164
|
+
/* @__PURE__ */ jsx3(
|
|
165
|
+
IconButton_default,
|
|
166
|
+
{
|
|
167
|
+
icon: isMuted ? /* @__PURE__ */ jsx3(SpeakerSlash, { size: 24 }) : /* @__PURE__ */ jsx3(SpeakerHigh, { size: 24 }),
|
|
168
|
+
onClick: onToggleMute,
|
|
169
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
170
|
+
className: "!bg-transparent !text-white hover:!bg-white/20"
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
/* @__PURE__ */ jsx3(
|
|
174
|
+
"input",
|
|
175
|
+
{
|
|
176
|
+
type: "range",
|
|
177
|
+
min: 0,
|
|
178
|
+
max: 100,
|
|
179
|
+
value: Math.round(volume * 100),
|
|
180
|
+
onChange: (e) => onVolumeChange(parseInt(e.target.value)),
|
|
181
|
+
className: "w-20 h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
182
|
+
"aria-label": "Volume control",
|
|
183
|
+
style: {
|
|
184
|
+
background: `linear-gradient(to right, var(--color-primary-700) ${volume * 100}%, var(--color-secondary-300) ${volume * 100}%)`
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
] });
|
|
189
|
+
var SpeedMenu = ({
|
|
190
|
+
showSpeedMenu,
|
|
191
|
+
playbackRate,
|
|
192
|
+
onToggleMenu,
|
|
193
|
+
onSpeedChange
|
|
194
|
+
}) => /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
195
|
+
/* @__PURE__ */ jsx3(
|
|
196
|
+
IconButton_default,
|
|
197
|
+
{
|
|
198
|
+
icon: /* @__PURE__ */ jsx3(DotsThreeVertical, { size: 24 }),
|
|
199
|
+
onClick: onToggleMenu,
|
|
200
|
+
"aria-label": "Playback speed",
|
|
201
|
+
className: "!bg-transparent !text-white hover:!bg-white/20"
|
|
202
|
+
}
|
|
203
|
+
),
|
|
204
|
+
showSpeedMenu && /* @__PURE__ */ jsx3("div", { className: "absolute bottom-12 right-0 bg-black/90 rounded-lg p-2 min-w-20", children: [0.5, 0.75, 1, 1.25, 1.5, 2].map((speed) => /* @__PURE__ */ jsxs(
|
|
205
|
+
"button",
|
|
206
|
+
{
|
|
207
|
+
onClick: () => onSpeedChange(speed),
|
|
208
|
+
className: `block w-full text-left px-3 py-1 text-sm rounded hover:bg-white/20 transition-colors ${playbackRate === speed ? "text-primary-400" : "text-white"}`,
|
|
209
|
+
children: [
|
|
210
|
+
speed,
|
|
211
|
+
"x"
|
|
212
|
+
]
|
|
213
|
+
},
|
|
214
|
+
speed
|
|
215
|
+
)) })
|
|
216
|
+
] });
|
|
133
217
|
var VideoPlayer = ({
|
|
134
218
|
src,
|
|
135
219
|
poster,
|
|
@@ -154,10 +238,51 @@ var VideoPlayer = ({
|
|
|
154
238
|
const [showControls, setShowControls] = useState(true);
|
|
155
239
|
const [hasCompleted, setHasCompleted] = useState(false);
|
|
156
240
|
const [showCaptions, setShowCaptions] = useState(false);
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
setHasCompleted(false);
|
|
243
|
+
}, [src]);
|
|
157
244
|
const [playbackRate, setPlaybackRate] = useState(1);
|
|
158
245
|
const [showSpeedMenu, setShowSpeedMenu] = useState(false);
|
|
159
246
|
const lastSaveTimeRef = useRef(0);
|
|
160
247
|
const trackRef = useRef(null);
|
|
248
|
+
const controlsTimeoutRef = useRef(null);
|
|
249
|
+
const lastMousePositionRef = useRef({ x: 0, y: 0 });
|
|
250
|
+
const mouseMoveTimeoutRef = useRef(null);
|
|
251
|
+
const clearControlsTimeout = useCallback(() => {
|
|
252
|
+
if (controlsTimeoutRef.current) {
|
|
253
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
254
|
+
controlsTimeoutRef.current = null;
|
|
255
|
+
}
|
|
256
|
+
}, []);
|
|
257
|
+
const clearMouseMoveTimeout = useCallback(() => {
|
|
258
|
+
if (mouseMoveTimeoutRef.current) {
|
|
259
|
+
clearTimeout(mouseMoveTimeoutRef.current);
|
|
260
|
+
mouseMoveTimeoutRef.current = null;
|
|
261
|
+
}
|
|
262
|
+
}, []);
|
|
263
|
+
const showControlsWithTimer = useCallback(() => {
|
|
264
|
+
setShowControls(true);
|
|
265
|
+
clearControlsTimeout();
|
|
266
|
+
if (isPlaying) {
|
|
267
|
+
const timeout = isFullscreen ? 2e3 : 3e3;
|
|
268
|
+
controlsTimeoutRef.current = window.setTimeout(() => {
|
|
269
|
+
setShowControls(false);
|
|
270
|
+
}, timeout);
|
|
271
|
+
}
|
|
272
|
+
}, [isPlaying, isFullscreen, clearControlsTimeout]);
|
|
273
|
+
const handleMouseMove = useCallback(
|
|
274
|
+
(event) => {
|
|
275
|
+
const currentX = event.clientX;
|
|
276
|
+
const currentY = event.clientY;
|
|
277
|
+
const lastPos = lastMousePositionRef.current;
|
|
278
|
+
const hasMoved = Math.abs(currentX - lastPos.x) > 5 || Math.abs(currentY - lastPos.y) > 5;
|
|
279
|
+
if (hasMoved) {
|
|
280
|
+
lastMousePositionRef.current = { x: currentX, y: currentY };
|
|
281
|
+
showControlsWithTimer();
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
[showControlsWithTimer]
|
|
285
|
+
);
|
|
161
286
|
useEffect(() => {
|
|
162
287
|
if (videoRef.current) {
|
|
163
288
|
videoRef.current.volume = volume;
|
|
@@ -165,84 +290,129 @@ var VideoPlayer = ({
|
|
|
165
290
|
}
|
|
166
291
|
}, [volume, isMuted]);
|
|
167
292
|
useEffect(() => {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
293
|
+
const video = videoRef.current;
|
|
294
|
+
if (!video) return;
|
|
295
|
+
const onPlay = () => setIsPlaying(true);
|
|
296
|
+
const onPause = () => setIsPlaying(false);
|
|
297
|
+
const onEnded = () => setIsPlaying(false);
|
|
298
|
+
video.addEventListener("play", onPlay);
|
|
299
|
+
video.addEventListener("pause", onPause);
|
|
300
|
+
video.addEventListener("ended", onEnded);
|
|
301
|
+
return () => {
|
|
302
|
+
video.removeEventListener("play", onPlay);
|
|
303
|
+
video.removeEventListener("pause", onPause);
|
|
304
|
+
video.removeEventListener("ended", onEnded);
|
|
305
|
+
};
|
|
306
|
+
}, []);
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
if (isPlaying) {
|
|
309
|
+
showControlsWithTimer();
|
|
178
310
|
} else {
|
|
179
|
-
|
|
311
|
+
clearControlsTimeout();
|
|
312
|
+
setShowControls(true);
|
|
313
|
+
}
|
|
314
|
+
}, [isPlaying, showControlsWithTimer, clearControlsTimeout]);
|
|
315
|
+
useEffect(() => {
|
|
316
|
+
const handleFullscreenChange = () => {
|
|
317
|
+
const isCurrentlyFullscreen = !!document.fullscreenElement;
|
|
318
|
+
setIsFullscreen(isCurrentlyFullscreen);
|
|
319
|
+
if (isCurrentlyFullscreen) {
|
|
320
|
+
showControlsWithTimer();
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
|
324
|
+
return () => {
|
|
325
|
+
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
326
|
+
};
|
|
327
|
+
}, [showControlsWithTimer]);
|
|
328
|
+
const getInitialTime = useCallback(() => {
|
|
329
|
+
if (!autoSave || !storageKey) {
|
|
330
|
+
return Number.isFinite(initialTime) && initialTime >= 0 ? initialTime : void 0;
|
|
180
331
|
}
|
|
332
|
+
const saved = Number(localStorage.getItem(`${storageKey}-${src}`) || NaN);
|
|
333
|
+
const hasValidInitial = Number.isFinite(initialTime) && initialTime >= 0;
|
|
334
|
+
const hasValidSaved = Number.isFinite(saved) && saved >= 0;
|
|
335
|
+
if (hasValidInitial) return initialTime;
|
|
336
|
+
if (hasValidSaved) return saved;
|
|
337
|
+
return void 0;
|
|
338
|
+
}, [autoSave, storageKey, src, initialTime]);
|
|
339
|
+
useEffect(() => {
|
|
340
|
+
const start = getInitialTime();
|
|
181
341
|
if (start !== void 0 && videoRef.current) {
|
|
182
342
|
videoRef.current.currentTime = start;
|
|
183
343
|
setCurrentTime(start);
|
|
184
344
|
}
|
|
185
|
-
}, [
|
|
186
|
-
const saveProgress = useCallback(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}, [autoSave, storageKey, src, currentTime]);
|
|
194
|
-
const togglePlayPause = useCallback(() => {
|
|
195
|
-
if (videoRef.current) {
|
|
196
|
-
if (isPlaying) {
|
|
197
|
-
videoRef.current.pause();
|
|
198
|
-
} else {
|
|
199
|
-
videoRef.current.play();
|
|
345
|
+
}, [getInitialTime]);
|
|
346
|
+
const saveProgress = useCallback(
|
|
347
|
+
(time) => {
|
|
348
|
+
if (!autoSave || !storageKey) return;
|
|
349
|
+
const now = Date.now();
|
|
350
|
+
if (now - lastSaveTimeRef.current > 5e3) {
|
|
351
|
+
localStorage.setItem(`${storageKey}-${src}`, time.toString());
|
|
352
|
+
lastSaveTimeRef.current = now;
|
|
200
353
|
}
|
|
201
|
-
|
|
354
|
+
},
|
|
355
|
+
[autoSave, storageKey, src]
|
|
356
|
+
);
|
|
357
|
+
const togglePlayPause = useCallback(async () => {
|
|
358
|
+
const video = videoRef.current;
|
|
359
|
+
if (!video) return;
|
|
360
|
+
if (!video.paused) {
|
|
361
|
+
video.pause();
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
try {
|
|
365
|
+
await video.play();
|
|
366
|
+
} catch {
|
|
202
367
|
}
|
|
203
|
-
}, [
|
|
368
|
+
}, []);
|
|
204
369
|
const handleVolumeChange = useCallback(
|
|
205
370
|
(newVolume) => {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
371
|
+
const video = videoRef.current;
|
|
372
|
+
if (!video) return;
|
|
373
|
+
const volumeValue = newVolume / 100;
|
|
374
|
+
video.volume = volumeValue;
|
|
375
|
+
setVolume(volumeValue);
|
|
376
|
+
const shouldMute = volumeValue === 0;
|
|
377
|
+
const shouldUnmute = volumeValue > 0 && isMuted;
|
|
378
|
+
if (shouldMute) {
|
|
379
|
+
video.muted = true;
|
|
380
|
+
setIsMuted(true);
|
|
381
|
+
} else if (shouldUnmute) {
|
|
382
|
+
video.muted = false;
|
|
383
|
+
setIsMuted(false);
|
|
217
384
|
}
|
|
218
385
|
},
|
|
219
386
|
[isMuted]
|
|
220
387
|
);
|
|
221
388
|
const toggleMute = useCallback(() => {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
389
|
+
const video = videoRef.current;
|
|
390
|
+
if (!video) return;
|
|
391
|
+
if (isMuted) {
|
|
392
|
+
const restoreVolume = volume > 0 ? volume : 0.5;
|
|
393
|
+
video.volume = restoreVolume;
|
|
394
|
+
video.muted = false;
|
|
395
|
+
setVolume(restoreVolume);
|
|
396
|
+
setIsMuted(false);
|
|
397
|
+
} else {
|
|
398
|
+
video.muted = true;
|
|
399
|
+
setIsMuted(true);
|
|
233
400
|
}
|
|
234
401
|
}, [isMuted, volume]);
|
|
402
|
+
const handleSeek = useCallback((newTime) => {
|
|
403
|
+
const video = videoRef.current;
|
|
404
|
+
if (video) {
|
|
405
|
+
video.currentTime = newTime;
|
|
406
|
+
}
|
|
407
|
+
}, []);
|
|
235
408
|
const toggleFullscreen = useCallback(() => {
|
|
236
409
|
const container = videoRef.current?.parentElement;
|
|
237
410
|
if (!container) return;
|
|
238
|
-
if (!isFullscreen) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
} else if (document.exitFullscreen) {
|
|
411
|
+
if (!isFullscreen && container.requestFullscreen) {
|
|
412
|
+
container.requestFullscreen();
|
|
413
|
+
} else if (isFullscreen && document.exitFullscreen) {
|
|
243
414
|
document.exitFullscreen();
|
|
244
415
|
}
|
|
245
|
-
setIsFullscreen(!isFullscreen);
|
|
246
416
|
}, [isFullscreen]);
|
|
247
417
|
const handleSpeedChange = useCallback((speed) => {
|
|
248
418
|
if (videoRef.current) {
|
|
@@ -260,29 +430,28 @@ var VideoPlayer = ({
|
|
|
260
430
|
setShowCaptions(newShowCaptions);
|
|
261
431
|
trackRef.current.track.mode = newShowCaptions && subtitles ? "showing" : "hidden";
|
|
262
432
|
}, [showCaptions, subtitles]);
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
onTimeUpdate?.(current);
|
|
269
|
-
if (duration > 0) {
|
|
270
|
-
const progressPercent = current / duration * 100;
|
|
271
|
-
onProgress?.(progressPercent);
|
|
272
|
-
if (progressPercent >= 95 && !hasCompleted) {
|
|
273
|
-
setHasCompleted(true);
|
|
274
|
-
onVideoComplete?.();
|
|
275
|
-
}
|
|
433
|
+
const checkVideoCompletion = useCallback(
|
|
434
|
+
(progressPercent) => {
|
|
435
|
+
if (progressPercent >= 95 && !hasCompleted) {
|
|
436
|
+
setHasCompleted(true);
|
|
437
|
+
onVideoComplete?.();
|
|
276
438
|
}
|
|
439
|
+
},
|
|
440
|
+
[hasCompleted, onVideoComplete]
|
|
441
|
+
);
|
|
442
|
+
const handleTimeUpdate = useCallback(() => {
|
|
443
|
+
const video = videoRef.current;
|
|
444
|
+
if (!video) return;
|
|
445
|
+
const current = video.currentTime;
|
|
446
|
+
setCurrentTime(current);
|
|
447
|
+
saveProgress(current);
|
|
448
|
+
onTimeUpdate?.(current);
|
|
449
|
+
if (duration > 0) {
|
|
450
|
+
const progressPercent = current / duration * 100;
|
|
451
|
+
onProgress?.(progressPercent);
|
|
452
|
+
checkVideoCompletion(progressPercent);
|
|
277
453
|
}
|
|
278
|
-
}, [
|
|
279
|
-
duration,
|
|
280
|
-
saveProgress,
|
|
281
|
-
onTimeUpdate,
|
|
282
|
-
onProgress,
|
|
283
|
-
onVideoComplete,
|
|
284
|
-
hasCompleted
|
|
285
|
-
]);
|
|
454
|
+
}, [duration, saveProgress, onTimeUpdate, onProgress, checkVideoCompletion]);
|
|
286
455
|
const handleLoadedMetadata = useCallback(() => {
|
|
287
456
|
if (videoRef.current) {
|
|
288
457
|
setDuration(videoRef.current.duration);
|
|
@@ -311,9 +480,78 @@ var VideoPlayer = ({
|
|
|
311
480
|
return () => {
|
|
312
481
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
313
482
|
window.removeEventListener("blur", handleBlur);
|
|
483
|
+
clearControlsTimeout();
|
|
484
|
+
clearMouseMoveTimeout();
|
|
314
485
|
};
|
|
315
|
-
}, [isPlaying]);
|
|
486
|
+
}, [isPlaying, clearControlsTimeout, clearMouseMoveTimeout]);
|
|
316
487
|
const progressPercentage = duration > 0 ? currentTime / duration * 100 : 0;
|
|
488
|
+
const getTopControlsOpacity = useCallback(() => {
|
|
489
|
+
if (isFullscreen) {
|
|
490
|
+
return showControls ? "opacity-100" : "opacity-0";
|
|
491
|
+
}
|
|
492
|
+
return !isPlaying || showControls ? "opacity-100" : "opacity-0 group-hover:opacity-100";
|
|
493
|
+
}, [isFullscreen, showControls, isPlaying]);
|
|
494
|
+
const getBottomControlsOpacity = useCallback(() => {
|
|
495
|
+
if (isFullscreen) {
|
|
496
|
+
return showControls ? "opacity-100" : "opacity-0";
|
|
497
|
+
}
|
|
498
|
+
return !isPlaying || showControls ? "opacity-100" : "opacity-0 group-hover:opacity-100";
|
|
499
|
+
}, [isFullscreen, showControls, isPlaying]);
|
|
500
|
+
const handleVideoKeyDown = useCallback(
|
|
501
|
+
(e) => {
|
|
502
|
+
if (e.key) {
|
|
503
|
+
e.stopPropagation();
|
|
504
|
+
showControlsWithTimer();
|
|
505
|
+
}
|
|
506
|
+
switch (e.key) {
|
|
507
|
+
case " ":
|
|
508
|
+
case "Enter":
|
|
509
|
+
e.preventDefault();
|
|
510
|
+
togglePlayPause();
|
|
511
|
+
break;
|
|
512
|
+
case "ArrowLeft":
|
|
513
|
+
e.preventDefault();
|
|
514
|
+
if (videoRef.current) {
|
|
515
|
+
videoRef.current.currentTime -= 10;
|
|
516
|
+
}
|
|
517
|
+
break;
|
|
518
|
+
case "ArrowRight":
|
|
519
|
+
e.preventDefault();
|
|
520
|
+
if (videoRef.current) {
|
|
521
|
+
videoRef.current.currentTime += 10;
|
|
522
|
+
}
|
|
523
|
+
break;
|
|
524
|
+
case "ArrowUp":
|
|
525
|
+
e.preventDefault();
|
|
526
|
+
handleVolumeChange(Math.min(100, volume * 100 + 10));
|
|
527
|
+
break;
|
|
528
|
+
case "ArrowDown":
|
|
529
|
+
e.preventDefault();
|
|
530
|
+
handleVolumeChange(Math.max(0, volume * 100 - 10));
|
|
531
|
+
break;
|
|
532
|
+
case "m":
|
|
533
|
+
case "M":
|
|
534
|
+
e.preventDefault();
|
|
535
|
+
toggleMute();
|
|
536
|
+
break;
|
|
537
|
+
case "f":
|
|
538
|
+
case "F":
|
|
539
|
+
e.preventDefault();
|
|
540
|
+
toggleFullscreen();
|
|
541
|
+
break;
|
|
542
|
+
default:
|
|
543
|
+
break;
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
[
|
|
547
|
+
showControlsWithTimer,
|
|
548
|
+
togglePlayPause,
|
|
549
|
+
handleVolumeChange,
|
|
550
|
+
volume,
|
|
551
|
+
toggleMute,
|
|
552
|
+
toggleFullscreen
|
|
553
|
+
]
|
|
554
|
+
);
|
|
317
555
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", className), children: [
|
|
318
556
|
(title || subtitleText) && /* @__PURE__ */ jsx3("div", { className: "bg-subject-1 rounded-t-xl px-8 py-4 flex items-end justify-between min-h-20", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
319
557
|
title && /* @__PURE__ */ jsx3(
|
|
@@ -340,12 +578,17 @@ var VideoPlayer = ({
|
|
|
340
578
|
)
|
|
341
579
|
] }) }),
|
|
342
580
|
/* @__PURE__ */ jsxs(
|
|
343
|
-
"
|
|
581
|
+
"section",
|
|
344
582
|
{
|
|
345
583
|
className: cn(
|
|
346
584
|
"relative w-full bg-background overflow-hidden group",
|
|
347
|
-
title || subtitleText ? "rounded-b-xl" : "rounded-xl"
|
|
585
|
+
title || subtitleText ? "rounded-b-xl" : "rounded-xl",
|
|
586
|
+
// Hide cursor when controls are hidden and video is playing in fullscreen
|
|
587
|
+
isFullscreen && isPlaying && !showControls ? "cursor-none" : "cursor-default"
|
|
348
588
|
),
|
|
589
|
+
"aria-label": title ? `Video player: ${title}` : "Video player",
|
|
590
|
+
onMouseMove: isFullscreen ? handleMouseMove : showControlsWithTimer,
|
|
591
|
+
onMouseEnter: showControlsWithTimer,
|
|
349
592
|
children: [
|
|
350
593
|
/* @__PURE__ */ jsx3(
|
|
351
594
|
"video",
|
|
@@ -358,39 +601,7 @@ var VideoPlayer = ({
|
|
|
358
601
|
onTimeUpdate: handleTimeUpdate,
|
|
359
602
|
onLoadedMetadata: handleLoadedMetadata,
|
|
360
603
|
onClick: togglePlayPause,
|
|
361
|
-
onKeyDown:
|
|
362
|
-
if (e.key) {
|
|
363
|
-
setShowControls(true);
|
|
364
|
-
}
|
|
365
|
-
if (e.key === " " || e.key === "Enter") {
|
|
366
|
-
e.preventDefault();
|
|
367
|
-
togglePlayPause();
|
|
368
|
-
}
|
|
369
|
-
if (e.key === "ArrowLeft" && videoRef.current) {
|
|
370
|
-
e.preventDefault();
|
|
371
|
-
videoRef.current.currentTime -= 10;
|
|
372
|
-
}
|
|
373
|
-
if (e.key === "ArrowRight" && videoRef.current) {
|
|
374
|
-
e.preventDefault();
|
|
375
|
-
videoRef.current.currentTime += 10;
|
|
376
|
-
}
|
|
377
|
-
if (e.key === "ArrowUp") {
|
|
378
|
-
e.preventDefault();
|
|
379
|
-
handleVolumeChange(Math.min(100, volume * 100 + 10));
|
|
380
|
-
}
|
|
381
|
-
if (e.key === "ArrowDown") {
|
|
382
|
-
e.preventDefault();
|
|
383
|
-
handleVolumeChange(Math.max(0, volume * 100 - 10));
|
|
384
|
-
}
|
|
385
|
-
if (e.key === "m" || e.key === "M") {
|
|
386
|
-
e.preventDefault();
|
|
387
|
-
toggleMute();
|
|
388
|
-
}
|
|
389
|
-
if (e.key === "f" || e.key === "F") {
|
|
390
|
-
e.preventDefault();
|
|
391
|
-
toggleFullscreen();
|
|
392
|
-
}
|
|
393
|
-
},
|
|
604
|
+
onKeyDown: handleVideoKeyDown,
|
|
394
605
|
tabIndex: 0,
|
|
395
606
|
"aria-label": title ? `Video: ${title}` : "Video player",
|
|
396
607
|
children: /* @__PURE__ */ jsx3(
|
|
@@ -420,9 +631,9 @@ var VideoPlayer = ({
|
|
|
420
631
|
{
|
|
421
632
|
className: cn(
|
|
422
633
|
"absolute top-0 left-0 right-0 p-4 bg-gradient-to-b from-black/70 to-transparent transition-opacity",
|
|
423
|
-
|
|
634
|
+
getTopControlsOpacity()
|
|
424
635
|
),
|
|
425
|
-
children: /* @__PURE__ */ jsx3("div", { className: "
|
|
636
|
+
children: /* @__PURE__ */ jsx3("div", { className: "flex justify-start", children: /* @__PURE__ */ jsx3(
|
|
426
637
|
IconButton_default,
|
|
427
638
|
{
|
|
428
639
|
icon: isFullscreen ? /* @__PURE__ */ jsx3(ArrowsInSimple, { size: 24 }) : /* @__PURE__ */ jsx3(ArrowsOutSimple, { size: 24 }),
|
|
@@ -438,29 +649,18 @@ var VideoPlayer = ({
|
|
|
438
649
|
{
|
|
439
650
|
className: cn(
|
|
440
651
|
"absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/90 to-transparent transition-opacity",
|
|
441
|
-
|
|
652
|
+
getBottomControlsOpacity()
|
|
442
653
|
),
|
|
443
654
|
children: [
|
|
444
|
-
/* @__PURE__ */ jsx3(
|
|
445
|
-
|
|
655
|
+
/* @__PURE__ */ jsx3(
|
|
656
|
+
ProgressBar,
|
|
446
657
|
{
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
onChange: (e) => {
|
|
452
|
-
const newTime = parseFloat(e.target.value);
|
|
453
|
-
if (videoRef.current) {
|
|
454
|
-
videoRef.current.currentTime = newTime;
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
className: "w-full h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer slider:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
458
|
-
"aria-label": "Video progress",
|
|
459
|
-
style: {
|
|
460
|
-
background: `linear-gradient(to right, #2271C4 ${progressPercentage}%, #D5D4D4 ${progressPercentage}%)`
|
|
461
|
-
}
|
|
658
|
+
currentTime,
|
|
659
|
+
duration,
|
|
660
|
+
progressPercentage,
|
|
661
|
+
onSeek: handleSeek
|
|
462
662
|
}
|
|
463
|
-
)
|
|
663
|
+
),
|
|
464
664
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 pb-4", children: [
|
|
465
665
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
466
666
|
/* @__PURE__ */ jsx3(
|
|
@@ -472,32 +672,15 @@ var VideoPlayer = ({
|
|
|
472
672
|
className: "!bg-transparent !text-white hover:!bg-white/20"
|
|
473
673
|
}
|
|
474
674
|
),
|
|
475
|
-
/* @__PURE__ */
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
),
|
|
485
|
-
/* @__PURE__ */ jsx3(
|
|
486
|
-
"input",
|
|
487
|
-
{
|
|
488
|
-
type: "range",
|
|
489
|
-
min: 0,
|
|
490
|
-
max: 100,
|
|
491
|
-
value: Math.round(volume * 100),
|
|
492
|
-
onChange: (e) => handleVolumeChange(parseInt(e.target.value)),
|
|
493
|
-
className: "w-20 h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
494
|
-
"aria-label": "Volume control",
|
|
495
|
-
style: {
|
|
496
|
-
background: `linear-gradient(to right, #2271C4 ${volume * 100}%, #D5D4D4 ${volume * 100}%)`
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
)
|
|
500
|
-
] }),
|
|
675
|
+
/* @__PURE__ */ jsx3(
|
|
676
|
+
VolumeControls,
|
|
677
|
+
{
|
|
678
|
+
volume,
|
|
679
|
+
isMuted,
|
|
680
|
+
onVolumeChange: handleVolumeChange,
|
|
681
|
+
onToggleMute: toggleMute
|
|
682
|
+
}
|
|
683
|
+
),
|
|
501
684
|
subtitles && /* @__PURE__ */ jsx3(
|
|
502
685
|
IconButton_default,
|
|
503
686
|
{
|
|
@@ -516,29 +699,15 @@ var VideoPlayer = ({
|
|
|
516
699
|
formatTime(duration)
|
|
517
700
|
] })
|
|
518
701
|
] }),
|
|
519
|
-
/* @__PURE__ */ jsx3("div", { className: "flex items-center gap-4", children: /* @__PURE__ */
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
),
|
|
529
|
-
showSpeedMenu && /* @__PURE__ */ jsx3("div", { className: "absolute bottom-12 right-0 bg-black/90 rounded-lg p-2 min-w-20", children: [0.5, 0.75, 1, 1.25, 1.5, 2].map((speed) => /* @__PURE__ */ jsxs(
|
|
530
|
-
"button",
|
|
531
|
-
{
|
|
532
|
-
onClick: () => handleSpeedChange(speed),
|
|
533
|
-
className: `block w-full text-left px-3 py-1 text-sm rounded hover:bg-white/20 transition-colors ${playbackRate === speed ? "text-primary-400" : "text-white"}`,
|
|
534
|
-
children: [
|
|
535
|
-
speed,
|
|
536
|
-
"x"
|
|
537
|
-
]
|
|
538
|
-
},
|
|
539
|
-
speed
|
|
540
|
-
)) })
|
|
541
|
-
] }) })
|
|
702
|
+
/* @__PURE__ */ jsx3("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsx3(
|
|
703
|
+
SpeedMenu,
|
|
704
|
+
{
|
|
705
|
+
showSpeedMenu,
|
|
706
|
+
playbackRate,
|
|
707
|
+
onToggleMenu: toggleSpeedMenu,
|
|
708
|
+
onSpeedChange: handleSpeedChange
|
|
709
|
+
}
|
|
710
|
+
) })
|
|
542
711
|
] })
|
|
543
712
|
]
|
|
544
713
|
}
|