analytica-frontend-lib 1.1.9 → 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/Quiz/index.d.mts +7 -8
- package/dist/Quiz/index.d.ts +7 -8
- package/dist/Quiz/index.js +146 -99
- package/dist/Quiz/index.js.map +1 -1
- package/dist/Quiz/index.mjs +146 -99
- package/dist/Quiz/index.mjs.map +1 -1
- package/dist/Quiz/useQuizStore/index.d.mts +70 -16
- package/dist/Quiz/useQuizStore/index.d.ts +70 -16
- package/dist/Quiz/useQuizStore/index.js +45 -12
- package/dist/Quiz/useQuizStore/index.js.map +1 -1
- package/dist/Quiz/useQuizStore/index.mjs +45 -12
- package/dist/Quiz/useQuizStore/index.mjs.map +1 -1
- package/dist/VideoPlayer/index.js +358 -189
- package/dist/VideoPlayer/index.js.map +1 -1
- package/dist/VideoPlayer/index.mjs +364 -190
- 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 +504 -288
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +510 -289
- 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);
|
|
180
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;
|
|
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) {
|
|
@@ -255,39 +425,43 @@ var VideoPlayer = ({
|
|
|
255
425
|
setShowSpeedMenu(!showSpeedMenu);
|
|
256
426
|
}, [showSpeedMenu]);
|
|
257
427
|
const toggleCaptions = useCallback(() => {
|
|
258
|
-
if (!trackRef.current?.track) return;
|
|
428
|
+
if (!trackRef.current?.track || !subtitles) return;
|
|
259
429
|
const newShowCaptions = !showCaptions;
|
|
260
430
|
setShowCaptions(newShowCaptions);
|
|
261
|
-
trackRef.current.track.mode = newShowCaptions ? "showing" : "hidden";
|
|
262
|
-
}, [showCaptions]);
|
|
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
|
-
}
|
|
431
|
+
trackRef.current.track.mode = newShowCaptions && subtitles ? "showing" : "hidden";
|
|
432
|
+
}, [showCaptions, subtitles]);
|
|
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);
|
|
289
458
|
}
|
|
290
459
|
}, []);
|
|
460
|
+
useEffect(() => {
|
|
461
|
+
if (trackRef.current?.track) {
|
|
462
|
+
trackRef.current.track.mode = showCaptions && subtitles ? "showing" : "hidden";
|
|
463
|
+
}
|
|
464
|
+
}, [subtitles, showCaptions]);
|
|
291
465
|
useEffect(() => {
|
|
292
466
|
const handleVisibilityChange = () => {
|
|
293
467
|
if (document.hidden && isPlaying && videoRef.current) {
|
|
@@ -306,9 +480,78 @@ var VideoPlayer = ({
|
|
|
306
480
|
return () => {
|
|
307
481
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
308
482
|
window.removeEventListener("blur", handleBlur);
|
|
483
|
+
clearControlsTimeout();
|
|
484
|
+
clearMouseMoveTimeout();
|
|
309
485
|
};
|
|
310
|
-
}, [isPlaying]);
|
|
486
|
+
}, [isPlaying, clearControlsTimeout, clearMouseMoveTimeout]);
|
|
311
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
|
+
);
|
|
312
555
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", className), children: [
|
|
313
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: [
|
|
314
557
|
title && /* @__PURE__ */ jsx3(
|
|
@@ -335,12 +578,17 @@ var VideoPlayer = ({
|
|
|
335
578
|
)
|
|
336
579
|
] }) }),
|
|
337
580
|
/* @__PURE__ */ jsxs(
|
|
338
|
-
"
|
|
581
|
+
"section",
|
|
339
582
|
{
|
|
340
583
|
className: cn(
|
|
341
584
|
"relative w-full bg-background overflow-hidden group",
|
|
342
|
-
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"
|
|
343
588
|
),
|
|
589
|
+
"aria-label": title ? `Video player: ${title}` : "Video player",
|
|
590
|
+
onMouseMove: isFullscreen ? handleMouseMove : showControlsWithTimer,
|
|
591
|
+
onMouseEnter: showControlsWithTimer,
|
|
344
592
|
children: [
|
|
345
593
|
/* @__PURE__ */ jsx3(
|
|
346
594
|
"video",
|
|
@@ -353,39 +601,7 @@ var VideoPlayer = ({
|
|
|
353
601
|
onTimeUpdate: handleTimeUpdate,
|
|
354
602
|
onLoadedMetadata: handleLoadedMetadata,
|
|
355
603
|
onClick: togglePlayPause,
|
|
356
|
-
onKeyDown:
|
|
357
|
-
if (e.key) {
|
|
358
|
-
setShowControls(true);
|
|
359
|
-
}
|
|
360
|
-
if (e.key === " " || e.key === "Enter") {
|
|
361
|
-
e.preventDefault();
|
|
362
|
-
togglePlayPause();
|
|
363
|
-
}
|
|
364
|
-
if (e.key === "ArrowLeft" && videoRef.current) {
|
|
365
|
-
e.preventDefault();
|
|
366
|
-
videoRef.current.currentTime -= 10;
|
|
367
|
-
}
|
|
368
|
-
if (e.key === "ArrowRight" && videoRef.current) {
|
|
369
|
-
e.preventDefault();
|
|
370
|
-
videoRef.current.currentTime += 10;
|
|
371
|
-
}
|
|
372
|
-
if (e.key === "ArrowUp") {
|
|
373
|
-
e.preventDefault();
|
|
374
|
-
handleVolumeChange(Math.min(100, volume * 100 + 10));
|
|
375
|
-
}
|
|
376
|
-
if (e.key === "ArrowDown") {
|
|
377
|
-
e.preventDefault();
|
|
378
|
-
handleVolumeChange(Math.max(0, volume * 100 - 10));
|
|
379
|
-
}
|
|
380
|
-
if (e.key === "m" || e.key === "M") {
|
|
381
|
-
e.preventDefault();
|
|
382
|
-
toggleMute();
|
|
383
|
-
}
|
|
384
|
-
if (e.key === "f" || e.key === "F") {
|
|
385
|
-
e.preventDefault();
|
|
386
|
-
toggleFullscreen();
|
|
387
|
-
}
|
|
388
|
-
},
|
|
604
|
+
onKeyDown: handleVideoKeyDown,
|
|
389
605
|
tabIndex: 0,
|
|
390
606
|
"aria-label": title ? `Video: ${title}` : "Video player",
|
|
391
607
|
children: /* @__PURE__ */ jsx3(
|
|
@@ -393,9 +609,9 @@ var VideoPlayer = ({
|
|
|
393
609
|
{
|
|
394
610
|
ref: trackRef,
|
|
395
611
|
kind: "captions",
|
|
396
|
-
src: subtitles || "data:text/vtt;charset=utf-8,WEBVTT
|
|
397
|
-
srcLang: "
|
|
398
|
-
label: subtitles ? "
|
|
612
|
+
src: subtitles || "data:text/vtt;charset=utf-8,WEBVTT",
|
|
613
|
+
srcLang: "pt-br",
|
|
614
|
+
label: subtitles ? "Legendas em Portugu\xEAs" : "Sem legendas dispon\xEDveis",
|
|
399
615
|
default: false
|
|
400
616
|
}
|
|
401
617
|
)
|
|
@@ -415,9 +631,9 @@ var VideoPlayer = ({
|
|
|
415
631
|
{
|
|
416
632
|
className: cn(
|
|
417
633
|
"absolute top-0 left-0 right-0 p-4 bg-gradient-to-b from-black/70 to-transparent transition-opacity",
|
|
418
|
-
|
|
634
|
+
getTopControlsOpacity()
|
|
419
635
|
),
|
|
420
|
-
children: /* @__PURE__ */ jsx3("div", { className: "
|
|
636
|
+
children: /* @__PURE__ */ jsx3("div", { className: "flex justify-start", children: /* @__PURE__ */ jsx3(
|
|
421
637
|
IconButton_default,
|
|
422
638
|
{
|
|
423
639
|
icon: isFullscreen ? /* @__PURE__ */ jsx3(ArrowsInSimple, { size: 24 }) : /* @__PURE__ */ jsx3(ArrowsOutSimple, { size: 24 }),
|
|
@@ -433,29 +649,18 @@ var VideoPlayer = ({
|
|
|
433
649
|
{
|
|
434
650
|
className: cn(
|
|
435
651
|
"absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/90 to-transparent transition-opacity",
|
|
436
|
-
|
|
652
|
+
getBottomControlsOpacity()
|
|
437
653
|
),
|
|
438
654
|
children: [
|
|
439
|
-
/* @__PURE__ */ jsx3(
|
|
440
|
-
|
|
655
|
+
/* @__PURE__ */ jsx3(
|
|
656
|
+
ProgressBar,
|
|
441
657
|
{
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
onChange: (e) => {
|
|
447
|
-
const newTime = parseFloat(e.target.value);
|
|
448
|
-
if (videoRef.current) {
|
|
449
|
-
videoRef.current.currentTime = newTime;
|
|
450
|
-
}
|
|
451
|
-
},
|
|
452
|
-
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",
|
|
453
|
-
"aria-label": "Video progress",
|
|
454
|
-
style: {
|
|
455
|
-
background: `linear-gradient(to right, #2271C4 ${progressPercentage}%, #D5D4D4 ${progressPercentage}%)`
|
|
456
|
-
}
|
|
658
|
+
currentTime,
|
|
659
|
+
duration,
|
|
660
|
+
progressPercentage,
|
|
661
|
+
onSeek: handleSeek
|
|
457
662
|
}
|
|
458
|
-
)
|
|
663
|
+
),
|
|
459
664
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 pb-4", children: [
|
|
460
665
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
461
666
|
/* @__PURE__ */ jsx3(
|
|
@@ -467,32 +672,15 @@ var VideoPlayer = ({
|
|
|
467
672
|
className: "!bg-transparent !text-white hover:!bg-white/20"
|
|
468
673
|
}
|
|
469
674
|
),
|
|
470
|
-
/* @__PURE__ */
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
),
|
|
480
|
-
/* @__PURE__ */ jsx3(
|
|
481
|
-
"input",
|
|
482
|
-
{
|
|
483
|
-
type: "range",
|
|
484
|
-
min: 0,
|
|
485
|
-
max: 100,
|
|
486
|
-
value: Math.round(volume * 100),
|
|
487
|
-
onChange: (e) => handleVolumeChange(parseInt(e.target.value)),
|
|
488
|
-
className: "w-20 h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
489
|
-
"aria-label": "Volume control",
|
|
490
|
-
style: {
|
|
491
|
-
background: `linear-gradient(to right, #2271C4 ${volume * 100}%, #D5D4D4 ${volume * 100}%)`
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
)
|
|
495
|
-
] }),
|
|
675
|
+
/* @__PURE__ */ jsx3(
|
|
676
|
+
VolumeControls,
|
|
677
|
+
{
|
|
678
|
+
volume,
|
|
679
|
+
isMuted,
|
|
680
|
+
onVolumeChange: handleVolumeChange,
|
|
681
|
+
onToggleMute: toggleMute
|
|
682
|
+
}
|
|
683
|
+
),
|
|
496
684
|
subtitles && /* @__PURE__ */ jsx3(
|
|
497
685
|
IconButton_default,
|
|
498
686
|
{
|
|
@@ -511,29 +699,15 @@ var VideoPlayer = ({
|
|
|
511
699
|
formatTime(duration)
|
|
512
700
|
] })
|
|
513
701
|
] }),
|
|
514
|
-
/* @__PURE__ */ jsx3("div", { className: "flex items-center gap-4", children: /* @__PURE__ */
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
),
|
|
524
|
-
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(
|
|
525
|
-
"button",
|
|
526
|
-
{
|
|
527
|
-
onClick: () => handleSpeedChange(speed),
|
|
528
|
-
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"}`,
|
|
529
|
-
children: [
|
|
530
|
-
speed,
|
|
531
|
-
"x"
|
|
532
|
-
]
|
|
533
|
-
},
|
|
534
|
-
speed
|
|
535
|
-
)) })
|
|
536
|
-
] }) })
|
|
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
|
+
) })
|
|
537
711
|
] })
|
|
538
712
|
]
|
|
539
713
|
}
|