@geekapps/silo-elements-nextjs 0.2.52 → 0.2.54
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 +260 -121
- package/dist/VideoPlayer.js.map +1 -1
- package/dist/index.js +262 -127
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -0
- package/package.json +1 -1
- 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);
|
|
@@ -197,6 +202,16 @@ function Video({
|
|
|
197
202
|
}
|
|
198
203
|
);
|
|
199
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
|
+
}, []);
|
|
200
215
|
useEffect(() => {
|
|
201
216
|
if (sourceIndex >= parsed.sources.length) {
|
|
202
217
|
setSourceIndex(initialSourceIndex);
|
|
@@ -422,7 +437,7 @@ function Video({
|
|
|
422
437
|
setQualities([AUTO_QUALITY]);
|
|
423
438
|
setAudioTracks([]);
|
|
424
439
|
setSelectedAudio(0);
|
|
425
|
-
|
|
440
|
+
closeSettings();
|
|
426
441
|
video.pause();
|
|
427
442
|
video.removeAttribute("src");
|
|
428
443
|
video.load();
|
|
@@ -649,17 +664,17 @@ function Video({
|
|
|
649
664
|
}, []);
|
|
650
665
|
const changeAudio = useCallback((trackId) => {
|
|
651
666
|
setSelectedAudio(trackId);
|
|
652
|
-
|
|
667
|
+
closeSettings();
|
|
653
668
|
if (hlsRef.current) {
|
|
654
669
|
hlsRef.current.audioTrack = trackId;
|
|
655
670
|
}
|
|
656
|
-
}, []);
|
|
671
|
+
}, [closeSettings]);
|
|
657
672
|
const changeQuality = useCallback(
|
|
658
673
|
(qualityId) => {
|
|
659
674
|
const option = qualities.find((quality) => quality.id === qualityId);
|
|
660
675
|
if (!option) return;
|
|
661
676
|
setSelectedQuality(qualityId);
|
|
662
|
-
|
|
677
|
+
closeSettings();
|
|
663
678
|
if (option.type === "auto") {
|
|
664
679
|
if (hlsRef.current) {
|
|
665
680
|
hlsRef.current.currentLevel = -1;
|
|
@@ -694,7 +709,7 @@ function Video({
|
|
|
694
709
|
dashRef.current.setQualityFor("video", option.index);
|
|
695
710
|
}
|
|
696
711
|
},
|
|
697
|
-
[qualities]
|
|
712
|
+
[qualities, closeSettings]
|
|
698
713
|
);
|
|
699
714
|
const seekFromPointer = useCallback(
|
|
700
715
|
(clientX) => {
|
|
@@ -739,7 +754,11 @@ function Video({
|
|
|
739
754
|
},
|
|
740
755
|
[isDragging, seekFromPointer, updatePreview]
|
|
741
756
|
);
|
|
757
|
+
const handleProgressPointerEnter = useCallback(() => {
|
|
758
|
+
setIsHoveringProgress(true);
|
|
759
|
+
}, []);
|
|
742
760
|
const handleProgressPointerLeave = useCallback(() => {
|
|
761
|
+
setIsHoveringProgress(false);
|
|
743
762
|
if (!isDragging) setPreview(null);
|
|
744
763
|
}, [isDragging]);
|
|
745
764
|
const handleProgressPointerDown = useCallback(
|
|
@@ -810,10 +829,18 @@ function Video({
|
|
|
810
829
|
onKeyDown: handleKeyDown,
|
|
811
830
|
onMouseMove: showControlsTemporarily,
|
|
812
831
|
onMouseLeave: () => {
|
|
832
|
+
closeSettings();
|
|
813
833
|
if (isPlaying && autoHideControls) {
|
|
814
834
|
setControlsVisible(false);
|
|
815
835
|
}
|
|
816
836
|
},
|
|
837
|
+
onBlur: (e) => {
|
|
838
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
839
|
+
closeSettings();
|
|
840
|
+
}
|
|
841
|
+
},
|
|
842
|
+
onTouchStart: showControlsTemporarily,
|
|
843
|
+
onTouchMove: showControlsTemporarily,
|
|
817
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",
|
|
818
845
|
style: fixedHeight ? {
|
|
819
846
|
height: typeof fixedHeight === "number" ? `${fixedHeight}px` : fixedHeight
|
|
@@ -826,7 +853,7 @@ function Video({
|
|
|
826
853
|
"video",
|
|
827
854
|
{
|
|
828
855
|
ref: videoRef,
|
|
829
|
-
className:
|
|
856
|
+
className: `h-full w-full ${isFullscreen ? "object-contain" : "object-cover"}`,
|
|
830
857
|
playsInline: true,
|
|
831
858
|
preload: "metadata",
|
|
832
859
|
crossOrigin: "anonymous",
|
|
@@ -917,7 +944,7 @@ function Video({
|
|
|
917
944
|
"div",
|
|
918
945
|
{
|
|
919
946
|
className: "fixed inset-0 z-70",
|
|
920
|
-
onClick:
|
|
947
|
+
onClick: closeSettings
|
|
921
948
|
}
|
|
922
949
|
),
|
|
923
950
|
/* @__PURE__ */ jsxs(
|
|
@@ -929,7 +956,9 @@ function Video({
|
|
|
929
956
|
224,
|
|
930
957
|
Math.max(180, (playerWidth || 640) * 0.22)
|
|
931
958
|
) + "px",
|
|
932
|
-
|
|
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"
|
|
933
962
|
},
|
|
934
963
|
children: [
|
|
935
964
|
settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
|
|
@@ -1363,8 +1392,7 @@ function Video({
|
|
|
1363
1392
|
type: "button",
|
|
1364
1393
|
onClick: () => {
|
|
1365
1394
|
setPlaybackRate(speed);
|
|
1366
|
-
|
|
1367
|
-
setSettingsTab("root");
|
|
1395
|
+
closeSettings();
|
|
1368
1396
|
},
|
|
1369
1397
|
className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
|
|
1370
1398
|
children: [
|
|
@@ -1400,37 +1428,40 @@ function Video({
|
|
|
1400
1428
|
] })
|
|
1401
1429
|
]
|
|
1402
1430
|
}
|
|
1403
|
-
)
|
|
1404
|
-
/* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
|
|
1431
|
+
)
|
|
1405
1432
|
] }),
|
|
1406
1433
|
/* @__PURE__ */ jsxs(
|
|
1407
1434
|
"div",
|
|
1408
1435
|
{
|
|
1409
1436
|
ref: progressRef,
|
|
1410
1437
|
onPointerMove: handleProgressPointerMove,
|
|
1438
|
+
onPointerEnter: handleProgressPointerEnter,
|
|
1411
1439
|
onPointerLeave: handleProgressPointerLeave,
|
|
1412
1440
|
onPointerDown: handleProgressPointerDown,
|
|
1413
1441
|
onPointerUp: handleProgressPointerUp,
|
|
1414
|
-
className: "
|
|
1442
|
+
className: "relative mb-2 h-8 cursor-pointer overflow-visible",
|
|
1415
1443
|
children: [
|
|
1416
1444
|
/* @__PURE__ */ jsxs(
|
|
1417
1445
|
"div",
|
|
1418
1446
|
{
|
|
1419
|
-
className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/
|
|
1420
|
-
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
|
+
},
|
|
1421
1452
|
children: [
|
|
1422
1453
|
/* @__PURE__ */ jsx(
|
|
1423
1454
|
"div",
|
|
1424
1455
|
{
|
|
1425
|
-
className: "absolute inset-y-0 left-0 rounded-full bg-white/
|
|
1456
|
+
className: "absolute inset-y-0 left-0 rounded-full bg-white/28",
|
|
1426
1457
|
style: { width: `${bufferedPercent}%` }
|
|
1427
1458
|
}
|
|
1428
1459
|
),
|
|
1429
1460
|
/* @__PURE__ */ jsx(
|
|
1430
1461
|
"div",
|
|
1431
1462
|
{
|
|
1432
|
-
className: "absolute inset-y-0 left-0 rounded-full bg-white
|
|
1433
|
-
style: { width: `${progressPercent}
|
|
1463
|
+
className: "absolute inset-y-0 left-0 rounded-full bg-white",
|
|
1464
|
+
style: { width: `${progressPercent}%`, transition: "width 0.05s linear" }
|
|
1434
1465
|
}
|
|
1435
1466
|
)
|
|
1436
1467
|
]
|
|
@@ -1439,14 +1470,90 @@ function Video({
|
|
|
1439
1470
|
/* @__PURE__ */ jsx(
|
|
1440
1471
|
"div",
|
|
1441
1472
|
{
|
|
1442
|
-
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)]",
|
|
1443
1474
|
style: {
|
|
1475
|
+
top: "50%",
|
|
1444
1476
|
left: `${progressPercent}%`,
|
|
1445
|
-
|
|
1446
|
-
|
|
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)"
|
|
1447
1481
|
}
|
|
1448
1482
|
}
|
|
1449
|
-
)
|
|
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
|
+
})()
|
|
1450
1557
|
]
|
|
1451
1558
|
}
|
|
1452
1559
|
),
|
|
@@ -1469,44 +1576,29 @@ function Video({
|
|
|
1469
1576
|
] })
|
|
1470
1577
|
] }),
|
|
1471
1578
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
|
|
1472
|
-
/* @__PURE__ */
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
"input",
|
|
1485
|
-
{
|
|
1486
|
-
type: "range",
|
|
1487
|
-
min: "0",
|
|
1488
|
-
max: "1",
|
|
1489
|
-
step: "0.01",
|
|
1490
|
-
value: isMuted ? 0 : volume,
|
|
1491
|
-
onChange: (event) => {
|
|
1492
|
-
const nextVolume = Number(event.target.value);
|
|
1493
|
-
setVolume(nextVolume);
|
|
1494
|
-
setIsMuted(nextVolume === 0);
|
|
1495
|
-
},
|
|
1496
|
-
className: "h-1 w-14 accent-white @md:w-20",
|
|
1497
|
-
"aria-label": "Audio level"
|
|
1498
|
-
}
|
|
1499
|
-
) })
|
|
1500
|
-
] }),
|
|
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
|
+
),
|
|
1501
1591
|
/* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
|
|
1502
1592
|
captions.length > 0 && /* @__PURE__ */ jsx(
|
|
1503
1593
|
"button",
|
|
1504
1594
|
{
|
|
1505
1595
|
type: "button",
|
|
1506
|
-
onClick: () =>
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
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"}`,
|
|
1510
1602
|
"aria-label": "Captions",
|
|
1511
1603
|
children: /* @__PURE__ */ jsx(Captions$1, { className: "size-4 @sm:size-5" })
|
|
1512
1604
|
}
|
|
@@ -1515,11 +1607,8 @@ function Video({
|
|
|
1515
1607
|
"button",
|
|
1516
1608
|
{
|
|
1517
1609
|
type: "button",
|
|
1518
|
-
onClick: () =>
|
|
1519
|
-
|
|
1520
|
-
setSettingsTab("root");
|
|
1521
|
-
},
|
|
1522
|
-
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"}`,
|
|
1523
1612
|
"aria-label": "Settings",
|
|
1524
1613
|
children: /* @__PURE__ */ jsx(Settings, { className: "size-4 @sm:size-5" })
|
|
1525
1614
|
}
|
|
@@ -1542,65 +1631,6 @@ function Video({
|
|
|
1542
1631
|
]
|
|
1543
1632
|
}
|
|
1544
1633
|
),
|
|
1545
|
-
preview && (() => {
|
|
1546
|
-
const srcW = preview.cue.w ?? 160;
|
|
1547
|
-
const srcH = preview.cue.h ?? 90;
|
|
1548
|
-
const thumbW = Math.max(
|
|
1549
|
-
140,
|
|
1550
|
-
Math.round((playerWidth || 640) * 0.13)
|
|
1551
|
-
);
|
|
1552
|
-
const thumbH = Math.round(thumbW * (srcH / srcW));
|
|
1553
|
-
const scale = thumbW / srcW;
|
|
1554
|
-
const isSprite = preview.cue.x != null && preview.cue.y != null;
|
|
1555
|
-
return /* @__PURE__ */ jsx(
|
|
1556
|
-
"div",
|
|
1557
|
-
{
|
|
1558
|
-
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",
|
|
1559
|
-
style: {
|
|
1560
|
-
bottom: controlsVisible ? "80px" : "20px",
|
|
1561
|
-
left: preview.left,
|
|
1562
|
-
transition: "bottom 0.2s"
|
|
1563
|
-
},
|
|
1564
|
-
children: isSprite ? /* @__PURE__ */ jsx(
|
|
1565
|
-
"div",
|
|
1566
|
-
{
|
|
1567
|
-
style: {
|
|
1568
|
-
width: thumbW,
|
|
1569
|
-
height: thumbH,
|
|
1570
|
-
overflow: "hidden"
|
|
1571
|
-
},
|
|
1572
|
-
children: /* @__PURE__ */ jsx(
|
|
1573
|
-
"div",
|
|
1574
|
-
{
|
|
1575
|
-
style: {
|
|
1576
|
-
width: srcW,
|
|
1577
|
-
height: srcH,
|
|
1578
|
-
backgroundImage: `url(${preview.cue.image})`,
|
|
1579
|
-
backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
|
|
1580
|
-
backgroundSize: "auto",
|
|
1581
|
-
backgroundRepeat: "no-repeat",
|
|
1582
|
-
transform: `scale(${scale})`,
|
|
1583
|
-
transformOrigin: "top left"
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
)
|
|
1587
|
-
}
|
|
1588
|
-
) : /* @__PURE__ */ jsx(
|
|
1589
|
-
"div",
|
|
1590
|
-
{
|
|
1591
|
-
style: {
|
|
1592
|
-
width: thumbW,
|
|
1593
|
-
height: thumbH,
|
|
1594
|
-
backgroundImage: `url(${preview.cue.image})`,
|
|
1595
|
-
backgroundSize: "cover",
|
|
1596
|
-
backgroundPosition: "center",
|
|
1597
|
-
backgroundRepeat: "no-repeat"
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
)
|
|
1601
|
-
}
|
|
1602
|
-
);
|
|
1603
|
-
})(),
|
|
1604
1634
|
activeCue && /* @__PURE__ */ jsx(
|
|
1605
1635
|
"div",
|
|
1606
1636
|
{
|
|
@@ -1634,6 +1664,109 @@ function Video({
|
|
|
1634
1664
|
);
|
|
1635
1665
|
}
|
|
1636
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
|
+
}
|
|
1637
1770
|
function parseVideoChildren(children) {
|
|
1638
1771
|
const parsed = {
|
|
1639
1772
|
sources: []
|
|
@@ -1696,7 +1829,13 @@ function inferSourceType(source) {
|
|
|
1696
1829
|
return "file";
|
|
1697
1830
|
}
|
|
1698
1831
|
function findStoryboardCue(cues, time) {
|
|
1699
|
-
|
|
1832
|
+
if (cues.length === 0) return null;
|
|
1833
|
+
let best = null;
|
|
1834
|
+
for (const cue of cues) {
|
|
1835
|
+
if (cue.start <= time) best = cue;
|
|
1836
|
+
else break;
|
|
1837
|
+
}
|
|
1838
|
+
return best;
|
|
1700
1839
|
}
|
|
1701
1840
|
function parseStoryboardVtt(text, baseUrl) {
|
|
1702
1841
|
const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|