@geekapps/silo-elements-nextjs 0.2.51 → 0.2.53
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.js +264 -122
- package/dist/VideoPlayer.js.map +1 -1
- package/dist/index.js +264 -122
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -3
- package/styles.css +1 -1
package/dist/VideoPlayer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useMemo, useState, useRef, useEffect, useCallback } from 'react';
|
|
2
2
|
import gsap from 'gsap';
|
|
3
|
-
import { Pause, Play,
|
|
3
|
+
import { Pause, Play, Captions as Captions$1, Settings, Minimize, Maximize, VolumeX, Volume2 } from 'lucide-react';
|
|
4
4
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
6
|
var AUTO_QUALITY = {
|
|
@@ -104,6 +104,8 @@ function Video({
|
|
|
104
104
|
const [audioTracks, setAudioTracks] = useState([]);
|
|
105
105
|
const [selectedAudio, setSelectedAudio] = useState(0);
|
|
106
106
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
107
|
+
const [settingsVisible, setSettingsVisible] = useState(false);
|
|
108
|
+
const settingsCloseTimerRef = useRef(null);
|
|
107
109
|
const [settingsTab, setSettingsTab] = useState("root");
|
|
108
110
|
const [playbackRate, setPlaybackRate] = useState(1);
|
|
109
111
|
const [subtitleStyle, setSubtitleStyle] = useState({
|
|
@@ -114,6 +116,8 @@ function Video({
|
|
|
114
116
|
});
|
|
115
117
|
const [subtitleMode, setSubtitleMode] = useState(initialSubtitleMode);
|
|
116
118
|
const [activeCue, setActiveCue] = useState(null);
|
|
119
|
+
const [storyboardSheetSize, setStoryboardSheetSize] = useState(null);
|
|
120
|
+
const storyboardSheetUrlRef = useRef("");
|
|
117
121
|
const [storyboardCues, setStoryboardCues] = useState(
|
|
118
122
|
[]
|
|
119
123
|
);
|
|
@@ -122,6 +126,7 @@ function Video({
|
|
|
122
126
|
const [currentTime, setCurrentTime] = useState(0);
|
|
123
127
|
const [bufferedTime, setBufferedTime] = useState(0);
|
|
124
128
|
const [isDragging, setIsDragging] = useState(false);
|
|
129
|
+
const [isHoveringProgress, setIsHoveringProgress] = useState(false);
|
|
125
130
|
const dragPointerIdRef = useRef(null);
|
|
126
131
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
127
132
|
const [hasPlayed, setHasPlayed] = useState(false);
|
|
@@ -150,11 +155,20 @@ function Video({
|
|
|
150
155
|
const applySubtitleMode = useCallback((mode) => {
|
|
151
156
|
const video = videoRef.current;
|
|
152
157
|
if (!video) return;
|
|
158
|
+
let activeTrack = null;
|
|
153
159
|
Array.from(video.textTracks).forEach((track) => {
|
|
154
160
|
if (track.kind === "metadata") return;
|
|
155
|
-
|
|
161
|
+
const enabled = mode !== "off" && track.language === mode;
|
|
162
|
+
track.mode = enabled ? "hidden" : "disabled";
|
|
163
|
+
if (enabled) activeTrack = track;
|
|
156
164
|
});
|
|
157
|
-
if (
|
|
165
|
+
if (!activeTrack) {
|
|
166
|
+
setActiveCue(null);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const cues = activeTrack.activeCues;
|
|
170
|
+
const cue = cues && cues.length > 0 ? cues[0] : null;
|
|
171
|
+
setActiveCue(cue ? cue.text.replace(/<[^>]*>/g, "") : null);
|
|
158
172
|
}, []);
|
|
159
173
|
const showControlsTemporarily = useCallback(() => {
|
|
160
174
|
setControlsVisible(true);
|
|
@@ -188,6 +202,16 @@ function Video({
|
|
|
188
202
|
}
|
|
189
203
|
);
|
|
190
204
|
}, []);
|
|
205
|
+
const openSettings = useCallback(() => {
|
|
206
|
+
setSettingsOpen(true);
|
|
207
|
+
setSettingsTab("root");
|
|
208
|
+
window.setTimeout(() => setSettingsVisible(true), 10);
|
|
209
|
+
}, []);
|
|
210
|
+
const closeSettings = useCallback(() => {
|
|
211
|
+
setSettingsVisible(false);
|
|
212
|
+
if (settingsCloseTimerRef.current) window.clearTimeout(settingsCloseTimerRef.current);
|
|
213
|
+
settingsCloseTimerRef.current = window.setTimeout(() => setSettingsOpen(false), 200);
|
|
214
|
+
}, []);
|
|
191
215
|
useEffect(() => {
|
|
192
216
|
if (sourceIndex >= parsed.sources.length) {
|
|
193
217
|
setSourceIndex(initialSourceIndex);
|
|
@@ -413,7 +437,7 @@ function Video({
|
|
|
413
437
|
setQualities([AUTO_QUALITY]);
|
|
414
438
|
setAudioTracks([]);
|
|
415
439
|
setSelectedAudio(0);
|
|
416
|
-
|
|
440
|
+
closeSettings();
|
|
417
441
|
video.pause();
|
|
418
442
|
video.removeAttribute("src");
|
|
419
443
|
video.load();
|
|
@@ -640,17 +664,17 @@ function Video({
|
|
|
640
664
|
}, []);
|
|
641
665
|
const changeAudio = useCallback((trackId) => {
|
|
642
666
|
setSelectedAudio(trackId);
|
|
643
|
-
|
|
667
|
+
closeSettings();
|
|
644
668
|
if (hlsRef.current) {
|
|
645
669
|
hlsRef.current.audioTrack = trackId;
|
|
646
670
|
}
|
|
647
|
-
}, []);
|
|
671
|
+
}, [closeSettings]);
|
|
648
672
|
const changeQuality = useCallback(
|
|
649
673
|
(qualityId) => {
|
|
650
674
|
const option = qualities.find((quality) => quality.id === qualityId);
|
|
651
675
|
if (!option) return;
|
|
652
676
|
setSelectedQuality(qualityId);
|
|
653
|
-
|
|
677
|
+
closeSettings();
|
|
654
678
|
if (option.type === "auto") {
|
|
655
679
|
if (hlsRef.current) {
|
|
656
680
|
hlsRef.current.currentLevel = -1;
|
|
@@ -685,7 +709,7 @@ function Video({
|
|
|
685
709
|
dashRef.current.setQualityFor("video", option.index);
|
|
686
710
|
}
|
|
687
711
|
},
|
|
688
|
-
[qualities]
|
|
712
|
+
[qualities, closeSettings]
|
|
689
713
|
);
|
|
690
714
|
const seekFromPointer = useCallback(
|
|
691
715
|
(clientX) => {
|
|
@@ -730,7 +754,11 @@ function Video({
|
|
|
730
754
|
},
|
|
731
755
|
[isDragging, seekFromPointer, updatePreview]
|
|
732
756
|
);
|
|
757
|
+
const handleProgressPointerEnter = useCallback(() => {
|
|
758
|
+
setIsHoveringProgress(true);
|
|
759
|
+
}, []);
|
|
733
760
|
const handleProgressPointerLeave = useCallback(() => {
|
|
761
|
+
setIsHoveringProgress(false);
|
|
734
762
|
if (!isDragging) setPreview(null);
|
|
735
763
|
}, [isDragging]);
|
|
736
764
|
const handleProgressPointerDown = useCallback(
|
|
@@ -801,10 +829,18 @@ function Video({
|
|
|
801
829
|
onKeyDown: handleKeyDown,
|
|
802
830
|
onMouseMove: showControlsTemporarily,
|
|
803
831
|
onMouseLeave: () => {
|
|
832
|
+
closeSettings();
|
|
804
833
|
if (isPlaying && autoHideControls) {
|
|
805
834
|
setControlsVisible(false);
|
|
806
835
|
}
|
|
807
836
|
},
|
|
837
|
+
onBlur: (e) => {
|
|
838
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
839
|
+
closeSettings();
|
|
840
|
+
}
|
|
841
|
+
},
|
|
842
|
+
onTouchStart: showControlsTemporarily,
|
|
843
|
+
onTouchMove: showControlsTemporarily,
|
|
808
844
|
className: "relative w-full overflow-hidden rounded-[14px] bg-black shadow-[0_30px_90px_rgba(15,15,15,0.22)] outline-none ring-1 ring-black/5",
|
|
809
845
|
style: fixedHeight ? {
|
|
810
846
|
height: typeof fixedHeight === "number" ? `${fixedHeight}px` : fixedHeight
|
|
@@ -817,7 +853,7 @@ function Video({
|
|
|
817
853
|
"video",
|
|
818
854
|
{
|
|
819
855
|
ref: videoRef,
|
|
820
|
-
className:
|
|
856
|
+
className: `h-full w-full ${isFullscreen ? "object-contain" : "object-cover"}`,
|
|
821
857
|
playsInline: true,
|
|
822
858
|
preload: "metadata",
|
|
823
859
|
crossOrigin: "anonymous",
|
|
@@ -908,7 +944,7 @@ function Video({
|
|
|
908
944
|
"div",
|
|
909
945
|
{
|
|
910
946
|
className: "fixed inset-0 z-70",
|
|
911
|
-
onClick:
|
|
947
|
+
onClick: closeSettings
|
|
912
948
|
}
|
|
913
949
|
),
|
|
914
950
|
/* @__PURE__ */ jsxs(
|
|
@@ -920,7 +956,9 @@ function Video({
|
|
|
920
956
|
224,
|
|
921
957
|
Math.max(180, (playerWidth || 640) * 0.22)
|
|
922
958
|
) + "px",
|
|
923
|
-
|
|
959
|
+
opacity: settingsVisible ? 1 : 0,
|
|
960
|
+
transform: settingsVisible ? "translateY(0) scale(1)" : "translateY(8px) scale(0.97)",
|
|
961
|
+
transition: "opacity 0.18s ease, transform 0.18s ease"
|
|
924
962
|
},
|
|
925
963
|
children: [
|
|
926
964
|
settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
|
|
@@ -1354,8 +1392,7 @@ function Video({
|
|
|
1354
1392
|
type: "button",
|
|
1355
1393
|
onClick: () => {
|
|
1356
1394
|
setPlaybackRate(speed);
|
|
1357
|
-
|
|
1358
|
-
setSettingsTab("root");
|
|
1395
|
+
closeSettings();
|
|
1359
1396
|
},
|
|
1360
1397
|
className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
|
|
1361
1398
|
children: [
|
|
@@ -1391,37 +1428,40 @@ function Video({
|
|
|
1391
1428
|
] })
|
|
1392
1429
|
]
|
|
1393
1430
|
}
|
|
1394
|
-
)
|
|
1395
|
-
/* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
|
|
1431
|
+
)
|
|
1396
1432
|
] }),
|
|
1397
1433
|
/* @__PURE__ */ jsxs(
|
|
1398
1434
|
"div",
|
|
1399
1435
|
{
|
|
1400
1436
|
ref: progressRef,
|
|
1401
1437
|
onPointerMove: handleProgressPointerMove,
|
|
1438
|
+
onPointerEnter: handleProgressPointerEnter,
|
|
1402
1439
|
onPointerLeave: handleProgressPointerLeave,
|
|
1403
1440
|
onPointerDown: handleProgressPointerDown,
|
|
1404
1441
|
onPointerUp: handleProgressPointerUp,
|
|
1405
|
-
className: "
|
|
1442
|
+
className: "relative mb-2 h-8 cursor-pointer overflow-visible",
|
|
1406
1443
|
children: [
|
|
1407
1444
|
/* @__PURE__ */ jsxs(
|
|
1408
1445
|
"div",
|
|
1409
1446
|
{
|
|
1410
|
-
className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/
|
|
1411
|
-
style: {
|
|
1447
|
+
className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/18",
|
|
1448
|
+
style: {
|
|
1449
|
+
height: isDragging ? "7px" : isHoveringProgress ? "5px" : "3px",
|
|
1450
|
+
transition: "height 0.15s ease"
|
|
1451
|
+
},
|
|
1412
1452
|
children: [
|
|
1413
1453
|
/* @__PURE__ */ jsx(
|
|
1414
1454
|
"div",
|
|
1415
1455
|
{
|
|
1416
|
-
className: "absolute inset-y-0 left-0 rounded-full bg-white/
|
|
1456
|
+
className: "absolute inset-y-0 left-0 rounded-full bg-white/28",
|
|
1417
1457
|
style: { width: `${bufferedPercent}%` }
|
|
1418
1458
|
}
|
|
1419
1459
|
),
|
|
1420
1460
|
/* @__PURE__ */ jsx(
|
|
1421
1461
|
"div",
|
|
1422
1462
|
{
|
|
1423
|
-
className: "absolute inset-y-0 left-0 rounded-full bg-white
|
|
1424
|
-
style: { width: `${progressPercent}
|
|
1463
|
+
className: "absolute inset-y-0 left-0 rounded-full bg-white",
|
|
1464
|
+
style: { width: `${progressPercent}%`, transition: "width 0.05s linear" }
|
|
1425
1465
|
}
|
|
1426
1466
|
)
|
|
1427
1467
|
]
|
|
@@ -1430,14 +1470,90 @@ function Video({
|
|
|
1430
1470
|
/* @__PURE__ */ jsx(
|
|
1431
1471
|
"div",
|
|
1432
1472
|
{
|
|
1433
|
-
className: "pointer-events-none absolute
|
|
1473
|
+
className: "pointer-events-none absolute rounded-full bg-white shadow-[0_1px_6px_rgba(0,0,0,0.5)]",
|
|
1434
1474
|
style: {
|
|
1475
|
+
top: "50%",
|
|
1435
1476
|
left: `${progressPercent}%`,
|
|
1436
|
-
|
|
1437
|
-
|
|
1477
|
+
transform: "translate(-50%, -50%)",
|
|
1478
|
+
width: isDragging ? "18px" : isHoveringProgress ? "14px" : "10px",
|
|
1479
|
+
height: isDragging ? "18px" : isHoveringProgress ? "14px" : "10px",
|
|
1480
|
+
transition: "width 0.2s cubic-bezier(0.34,1.56,0.64,1), height 0.2s cubic-bezier(0.34,1.56,0.64,1)"
|
|
1438
1481
|
}
|
|
1439
1482
|
}
|
|
1440
|
-
)
|
|
1483
|
+
),
|
|
1484
|
+
preview && (() => {
|
|
1485
|
+
const frameW = preview.cue.w ?? 160;
|
|
1486
|
+
const frameH = preview.cue.h ?? 90;
|
|
1487
|
+
const thumbW = 200;
|
|
1488
|
+
const thumbH = Math.round(thumbW * (frameH / frameW));
|
|
1489
|
+
const scale = thumbW / frameW;
|
|
1490
|
+
const isSprite = preview.cue.x != null && preview.cue.y != null;
|
|
1491
|
+
return /* @__PURE__ */ jsxs(
|
|
1492
|
+
"div",
|
|
1493
|
+
{
|
|
1494
|
+
className: "pointer-events-none absolute flex flex-col items-center gap-1",
|
|
1495
|
+
style: {
|
|
1496
|
+
bottom: "calc(100% + 6px)",
|
|
1497
|
+
left: preview.left,
|
|
1498
|
+
transform: "translateX(-50%)",
|
|
1499
|
+
zIndex: 80
|
|
1500
|
+
},
|
|
1501
|
+
children: [
|
|
1502
|
+
/* @__PURE__ */ jsx(
|
|
1503
|
+
"div",
|
|
1504
|
+
{
|
|
1505
|
+
className: "overflow-hidden rounded-lg shadow-2xl ring-1 ring-white/20",
|
|
1506
|
+
style: { width: thumbW, height: thumbH, flexShrink: 0 },
|
|
1507
|
+
children: isSprite ? (
|
|
1508
|
+
// Sprite: need full sheet dimensions to compute backgroundSize correctly.
|
|
1509
|
+
// Load them once from the image's natural size.
|
|
1510
|
+
(() => {
|
|
1511
|
+
const imgUrl = preview.cue.image;
|
|
1512
|
+
if (storyboardSheetUrlRef.current !== imgUrl) {
|
|
1513
|
+
storyboardSheetUrlRef.current = imgUrl;
|
|
1514
|
+
const img = new window.Image();
|
|
1515
|
+
img.onload = () => setStoryboardSheetSize({ w: img.naturalWidth, h: img.naturalHeight });
|
|
1516
|
+
img.src = imgUrl;
|
|
1517
|
+
}
|
|
1518
|
+
if (!storyboardSheetSize) return null;
|
|
1519
|
+
const bsW = storyboardSheetSize.w * scale;
|
|
1520
|
+
const bsH = storyboardSheetSize.h * scale;
|
|
1521
|
+
return /* @__PURE__ */ jsx(
|
|
1522
|
+
"div",
|
|
1523
|
+
{
|
|
1524
|
+
style: {
|
|
1525
|
+
width: thumbW,
|
|
1526
|
+
height: thumbH,
|
|
1527
|
+
backgroundImage: `url(${imgUrl})`,
|
|
1528
|
+
backgroundRepeat: "no-repeat",
|
|
1529
|
+
backgroundPosition: `-${(preview.cue.x ?? 0) * scale}px -${(preview.cue.y ?? 0) * scale}px`,
|
|
1530
|
+
backgroundSize: `${bsW}px ${bsH}px`
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
);
|
|
1534
|
+
})()
|
|
1535
|
+
) : /* @__PURE__ */ jsx(
|
|
1536
|
+
"img",
|
|
1537
|
+
{
|
|
1538
|
+
src: preview.cue.image,
|
|
1539
|
+
alt: "",
|
|
1540
|
+
style: { width: thumbW, height: thumbH, objectFit: "cover", objectPosition: "center", display: "block" }
|
|
1541
|
+
}
|
|
1542
|
+
)
|
|
1543
|
+
}
|
|
1544
|
+
),
|
|
1545
|
+
/* @__PURE__ */ jsx(
|
|
1546
|
+
"span",
|
|
1547
|
+
{
|
|
1548
|
+
className: "rounded-md px-2 py-0.5 text-[11px] font-semibold tabular-nums text-white/90",
|
|
1549
|
+
style: { background: "rgba(0,0,0,0.55)", backdropFilter: "blur(6px)" },
|
|
1550
|
+
children: formatTime(preview.time)
|
|
1551
|
+
}
|
|
1552
|
+
)
|
|
1553
|
+
]
|
|
1554
|
+
}
|
|
1555
|
+
);
|
|
1556
|
+
})()
|
|
1441
1557
|
]
|
|
1442
1558
|
}
|
|
1443
1559
|
),
|
|
@@ -1460,44 +1576,29 @@ function Video({
|
|
|
1460
1576
|
] })
|
|
1461
1577
|
] }),
|
|
1462
1578
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
|
|
1463
|
-
/* @__PURE__ */
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
"input",
|
|
1476
|
-
{
|
|
1477
|
-
type: "range",
|
|
1478
|
-
min: "0",
|
|
1479
|
-
max: "1",
|
|
1480
|
-
step: "0.01",
|
|
1481
|
-
value: isMuted ? 0 : volume,
|
|
1482
|
-
onChange: (event) => {
|
|
1483
|
-
const nextVolume = Number(event.target.value);
|
|
1484
|
-
setVolume(nextVolume);
|
|
1485
|
-
setIsMuted(nextVolume === 0);
|
|
1486
|
-
},
|
|
1487
|
-
className: "h-1 w-14 accent-white @md:w-20",
|
|
1488
|
-
"aria-label": "Audio level"
|
|
1489
|
-
}
|
|
1490
|
-
) })
|
|
1491
|
-
] }),
|
|
1579
|
+
/* @__PURE__ */ jsx(
|
|
1580
|
+
VolumeSlider,
|
|
1581
|
+
{
|
|
1582
|
+
volume: isMuted ? 0 : volume,
|
|
1583
|
+
onMuteToggle: () => setIsMuted((v) => !v),
|
|
1584
|
+
onVolumeChange: (v) => {
|
|
1585
|
+
setVolume(v);
|
|
1586
|
+
setIsMuted(v === 0);
|
|
1587
|
+
},
|
|
1588
|
+
isMuted
|
|
1589
|
+
}
|
|
1590
|
+
),
|
|
1492
1591
|
/* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
|
|
1493
1592
|
captions.length > 0 && /* @__PURE__ */ jsx(
|
|
1494
1593
|
"button",
|
|
1495
1594
|
{
|
|
1496
1595
|
type: "button",
|
|
1497
|
-
onClick: () =>
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1596
|
+
onClick: () => {
|
|
1597
|
+
const next = subtitleMode === "off" ? captions[0]?.srclang ?? "off" : "off";
|
|
1598
|
+
setSubtitleMode(next);
|
|
1599
|
+
setSubtitleStyle((st) => ({ ...st, track: next }));
|
|
1600
|
+
},
|
|
1601
|
+
className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
|
|
1501
1602
|
"aria-label": "Captions",
|
|
1502
1603
|
children: /* @__PURE__ */ jsx(Captions$1, { className: "size-4 @sm:size-5" })
|
|
1503
1604
|
}
|
|
@@ -1506,11 +1607,8 @@ function Video({
|
|
|
1506
1607
|
"button",
|
|
1507
1608
|
{
|
|
1508
1609
|
type: "button",
|
|
1509
|
-
onClick: () =>
|
|
1510
|
-
|
|
1511
|
-
setSettingsTab("root");
|
|
1512
|
-
},
|
|
1513
|
-
className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10${settingsOpen ? "text-white" : "text-white/60"}`,
|
|
1610
|
+
onClick: () => settingsOpen ? closeSettings() : openSettings(),
|
|
1611
|
+
className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${settingsOpen ? "text-white" : "text-white/60"}`,
|
|
1514
1612
|
"aria-label": "Settings",
|
|
1515
1613
|
children: /* @__PURE__ */ jsx(Settings, { className: "size-4 @sm:size-5" })
|
|
1516
1614
|
}
|
|
@@ -1533,65 +1631,6 @@ function Video({
|
|
|
1533
1631
|
]
|
|
1534
1632
|
}
|
|
1535
1633
|
),
|
|
1536
|
-
preview && (() => {
|
|
1537
|
-
const srcW = preview.cue.w ?? 160;
|
|
1538
|
-
const srcH = preview.cue.h ?? 90;
|
|
1539
|
-
const thumbW = Math.max(
|
|
1540
|
-
140,
|
|
1541
|
-
Math.round((playerWidth || 640) * 0.13)
|
|
1542
|
-
);
|
|
1543
|
-
const thumbH = Math.round(thumbW * (srcH / srcW));
|
|
1544
|
-
const scale = thumbW / srcW;
|
|
1545
|
-
const isSprite = preview.cue.x != null && preview.cue.y != null;
|
|
1546
|
-
return /* @__PURE__ */ jsx(
|
|
1547
|
-
"div",
|
|
1548
|
-
{
|
|
1549
|
-
className: "pointer-events-none absolute z-60 -translate-x-1/2 -translate-y-2 overflow-hidden rounded-xl shadow-2xl ring-1 ring-white/15",
|
|
1550
|
-
style: {
|
|
1551
|
-
bottom: controlsVisible ? "80px" : "20px",
|
|
1552
|
-
left: preview.left,
|
|
1553
|
-
transition: "bottom 0.2s"
|
|
1554
|
-
},
|
|
1555
|
-
children: isSprite ? /* @__PURE__ */ jsx(
|
|
1556
|
-
"div",
|
|
1557
|
-
{
|
|
1558
|
-
style: {
|
|
1559
|
-
width: thumbW,
|
|
1560
|
-
height: thumbH,
|
|
1561
|
-
overflow: "hidden"
|
|
1562
|
-
},
|
|
1563
|
-
children: /* @__PURE__ */ jsx(
|
|
1564
|
-
"div",
|
|
1565
|
-
{
|
|
1566
|
-
style: {
|
|
1567
|
-
width: srcW,
|
|
1568
|
-
height: srcH,
|
|
1569
|
-
backgroundImage: `url(${preview.cue.image})`,
|
|
1570
|
-
backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
|
|
1571
|
-
backgroundSize: "auto",
|
|
1572
|
-
backgroundRepeat: "no-repeat",
|
|
1573
|
-
transform: `scale(${scale})`,
|
|
1574
|
-
transformOrigin: "top left"
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
)
|
|
1578
|
-
}
|
|
1579
|
-
) : /* @__PURE__ */ jsx(
|
|
1580
|
-
"div",
|
|
1581
|
-
{
|
|
1582
|
-
style: {
|
|
1583
|
-
width: thumbW,
|
|
1584
|
-
height: thumbH,
|
|
1585
|
-
backgroundImage: `url(${preview.cue.image})`,
|
|
1586
|
-
backgroundSize: "cover",
|
|
1587
|
-
backgroundPosition: "center",
|
|
1588
|
-
backgroundRepeat: "no-repeat"
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
)
|
|
1592
|
-
}
|
|
1593
|
-
);
|
|
1594
|
-
})(),
|
|
1595
1634
|
activeCue && /* @__PURE__ */ jsx(
|
|
1596
1635
|
"div",
|
|
1597
1636
|
{
|
|
@@ -1625,6 +1664,109 @@ function Video({
|
|
|
1625
1664
|
);
|
|
1626
1665
|
}
|
|
1627
1666
|
var VideoPlayer = Video;
|
|
1667
|
+
function VolumeSlider({
|
|
1668
|
+
volume,
|
|
1669
|
+
isMuted,
|
|
1670
|
+
onMuteToggle,
|
|
1671
|
+
onVolumeChange
|
|
1672
|
+
}) {
|
|
1673
|
+
const [hovered, setHovered] = useState(false);
|
|
1674
|
+
const [dragging, setDragging] = useState(false);
|
|
1675
|
+
const trackRef = useRef(null);
|
|
1676
|
+
const expanded = hovered || dragging;
|
|
1677
|
+
const seek = useCallback((clientX) => {
|
|
1678
|
+
const track = trackRef.current;
|
|
1679
|
+
if (!track) return;
|
|
1680
|
+
const rect = track.getBoundingClientRect();
|
|
1681
|
+
const v = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
1682
|
+
onVolumeChange(v);
|
|
1683
|
+
}, [onVolumeChange]);
|
|
1684
|
+
const onPointerDown = useCallback((e) => {
|
|
1685
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1686
|
+
setDragging(true);
|
|
1687
|
+
seek(e.clientX);
|
|
1688
|
+
}, [seek]);
|
|
1689
|
+
const onPointerMove = useCallback((e) => {
|
|
1690
|
+
if (dragging) seek(e.clientX);
|
|
1691
|
+
}, [dragging, seek]);
|
|
1692
|
+
const onPointerUp = useCallback(() => setDragging(false), []);
|
|
1693
|
+
const fillPercent = volume * 100;
|
|
1694
|
+
return /* @__PURE__ */ jsxs(
|
|
1695
|
+
"div",
|
|
1696
|
+
{
|
|
1697
|
+
className: "flex items-center",
|
|
1698
|
+
onMouseEnter: () => setHovered(true),
|
|
1699
|
+
onMouseLeave: () => {
|
|
1700
|
+
if (!dragging) setHovered(false);
|
|
1701
|
+
},
|
|
1702
|
+
children: [
|
|
1703
|
+
/* @__PURE__ */ jsx(
|
|
1704
|
+
"button",
|
|
1705
|
+
{
|
|
1706
|
+
type: "button",
|
|
1707
|
+
onClick: onMuteToggle,
|
|
1708
|
+
className: "grid size-8 place-items-center text-white/70 transition hover:text-white @sm:size-9",
|
|
1709
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
1710
|
+
children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
|
|
1711
|
+
}
|
|
1712
|
+
),
|
|
1713
|
+
/* @__PURE__ */ jsx(
|
|
1714
|
+
"div",
|
|
1715
|
+
{
|
|
1716
|
+
style: {
|
|
1717
|
+
width: expanded ? "64px" : "0px",
|
|
1718
|
+
opacity: expanded ? 1 : 0,
|
|
1719
|
+
transition: "width 0.2s ease, opacity 0.2s ease",
|
|
1720
|
+
overflow: "hidden"
|
|
1721
|
+
},
|
|
1722
|
+
children: /* @__PURE__ */ jsxs(
|
|
1723
|
+
"div",
|
|
1724
|
+
{
|
|
1725
|
+
ref: trackRef,
|
|
1726
|
+
onPointerDown,
|
|
1727
|
+
onPointerMove,
|
|
1728
|
+
onPointerUp,
|
|
1729
|
+
className: "relative mx-1 flex h-7 cursor-pointer items-center",
|
|
1730
|
+
style: { width: "52px" },
|
|
1731
|
+
children: [
|
|
1732
|
+
/* @__PURE__ */ jsx(
|
|
1733
|
+
"div",
|
|
1734
|
+
{
|
|
1735
|
+
className: "absolute inset-x-0 rounded-full bg-white/20",
|
|
1736
|
+
style: {
|
|
1737
|
+
height: dragging ? "5px" : hovered ? "4px" : "3px",
|
|
1738
|
+
transition: "height 0.15s ease"
|
|
1739
|
+
},
|
|
1740
|
+
children: /* @__PURE__ */ jsx(
|
|
1741
|
+
"div",
|
|
1742
|
+
{
|
|
1743
|
+
className: "absolute inset-y-0 left-0 rounded-full bg-white",
|
|
1744
|
+
style: { width: `${fillPercent}%` }
|
|
1745
|
+
}
|
|
1746
|
+
)
|
|
1747
|
+
}
|
|
1748
|
+
),
|
|
1749
|
+
/* @__PURE__ */ jsx(
|
|
1750
|
+
"div",
|
|
1751
|
+
{
|
|
1752
|
+
className: "pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow-md",
|
|
1753
|
+
style: {
|
|
1754
|
+
left: `${fillPercent}%`,
|
|
1755
|
+
width: dragging ? "14px" : hovered ? "11px" : "0px",
|
|
1756
|
+
height: dragging ? "14px" : hovered ? "11px" : "0px",
|
|
1757
|
+
transition: "width 0.15s ease, height 0.15s ease"
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
)
|
|
1761
|
+
]
|
|
1762
|
+
}
|
|
1763
|
+
)
|
|
1764
|
+
}
|
|
1765
|
+
)
|
|
1766
|
+
]
|
|
1767
|
+
}
|
|
1768
|
+
);
|
|
1769
|
+
}
|
|
1628
1770
|
function parseVideoChildren(children) {
|
|
1629
1771
|
const parsed = {
|
|
1630
1772
|
sources: []
|