@geekapps/silo-elements-nextjs 0.2.70 → 0.3.0

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/index.js CHANGED
@@ -1245,6 +1245,7 @@ function Video({
1245
1245
  const containerRef = useRef(null);
1246
1246
  const chromeRef = useRef(null);
1247
1247
  const playerRef = useRef(null);
1248
+ const showAgeRatingRef = useRef(null);
1248
1249
  const videoRef = useRef(null);
1249
1250
  const progressRef = useRef(null);
1250
1251
  const hlsRef = useRef(null);
@@ -1257,7 +1258,6 @@ function Video({
1257
1258
  const [selectedAudio, setSelectedAudio] = useState(0);
1258
1259
  const [settingsOpen, setSettingsOpen] = useState(false);
1259
1260
  const [settingsVisible, setSettingsVisible] = useState(false);
1260
- const settingsCloseTimerRef = useRef(null);
1261
1261
  const [settingsTab, setSettingsTab] = useState("root");
1262
1262
  const [playbackRate, setPlaybackRate] = useState(1);
1263
1263
  const [subtitleStyle, setSubtitleStyle] = useState({
@@ -1305,13 +1305,20 @@ function Video({
1305
1305
  const dragPointerIdRef = useRef(null);
1306
1306
  const [isPlaying, setIsPlaying] = useState(false);
1307
1307
  const [hasPlayed, setHasPlayed] = useState(false);
1308
- const [ageRatingOverlay, setAgeRatingOverlay] = useState(false);
1309
- const ageRatingTimerRef = useRef(null);
1308
+ const ageRatingTlRef = useRef(null);
1310
1309
  const ageRatingPauseTimerRef = useRef(null);
1310
+ const ageRatingWrapRef = useRef(null);
1311
+ const ageRatingIconRef = useRef(null);
1312
+ const ageRatingTextRef = useRef(null);
1311
1313
  const [clickIcon, setClickIcon] = useState(null);
1312
1314
  const clickIconTimerRef = useRef(null);
1315
+ const clickIconRef = useRef(null);
1313
1316
  const [isLoading, setIsLoading] = useState(true);
1314
1317
  const [controlsVisible, setControlsVisible] = useState(true);
1318
+ const settingsPanelRef = useRef(null);
1319
+ const settingsContentRef = useRef(null);
1320
+ const progressTrackRef = useRef(null);
1321
+ const progressThumbRef = useRef(null);
1315
1322
  const [volume, setVolume] = useState(defaultVolume);
1316
1323
  const [isMuted, setIsMuted] = useState(false);
1317
1324
  const [isFullscreen, setIsFullscreen] = useState(false);
@@ -1377,6 +1384,9 @@ function Video({
1377
1384
  setControlsVisible(false);
1378
1385
  }, 2400);
1379
1386
  }
1387
+ if (video?.paused) {
1388
+ showAgeRatingRef.current?.();
1389
+ }
1380
1390
  }, [autoHideControls]);
1381
1391
  useEffect(() => {
1382
1392
  if (!containerRef.current) return;
@@ -1401,13 +1411,96 @@ function Video({
1401
1411
  const openSettings = useCallback(() => {
1402
1412
  setSettingsOpen(true);
1403
1413
  setSettingsTab("root");
1404
- window.setTimeout(() => setSettingsVisible(true), 10);
1414
+ setSettingsVisible(true);
1405
1415
  }, []);
1406
1416
  const closeSettings = useCallback(() => {
1407
- setSettingsVisible(false);
1408
- if (settingsCloseTimerRef.current) window.clearTimeout(settingsCloseTimerRef.current);
1409
- settingsCloseTimerRef.current = window.setTimeout(() => setSettingsOpen(false), 200);
1417
+ const panel = settingsPanelRef.current;
1418
+ if (panel) {
1419
+ gsap.killTweensOf(panel);
1420
+ gsap.to(panel, {
1421
+ opacity: 0,
1422
+ y: 8,
1423
+ scale: 0.97,
1424
+ duration: 0.18,
1425
+ ease: "power2.in",
1426
+ onComplete: () => {
1427
+ setSettingsOpen(false);
1428
+ setSettingsVisible(false);
1429
+ }
1430
+ });
1431
+ } else {
1432
+ setSettingsOpen(false);
1433
+ setSettingsVisible(false);
1434
+ }
1410
1435
  }, []);
1436
+ useEffect(() => {
1437
+ if (!settingsOpen) return;
1438
+ const panel = settingsPanelRef.current;
1439
+ if (!panel) return;
1440
+ gsap.killTweensOf(panel);
1441
+ gsap.fromTo(
1442
+ panel,
1443
+ { opacity: 0, y: 8, scale: 0.97 },
1444
+ { opacity: 1, y: 0, scale: 1, duration: 0.2, ease: "power2.out" }
1445
+ );
1446
+ }, [settingsOpen]);
1447
+ useEffect(() => {
1448
+ const el = settingsContentRef.current;
1449
+ if (!el) return;
1450
+ gsap.killTweensOf(el);
1451
+ gsap.fromTo(
1452
+ el,
1453
+ { opacity: 0, x: 12 },
1454
+ { opacity: 1, x: 0, duration: 0.18, ease: "power2.out" }
1455
+ );
1456
+ }, [settingsTab]);
1457
+ useEffect(() => {
1458
+ const el = chromeRef.current;
1459
+ const player = playerRef.current;
1460
+ if (!el) return;
1461
+ gsap.killTweensOf(el);
1462
+ gsap.to(el, {
1463
+ opacity: controlsVisible ? 1 : 0,
1464
+ duration: 0.2,
1465
+ ease: "power1.inOut"
1466
+ });
1467
+ el.style.pointerEvents = controlsVisible ? "" : "none";
1468
+ if (player) {
1469
+ player.style.cursor = controlsVisible ? "" : "none";
1470
+ }
1471
+ }, [controlsVisible]);
1472
+ useEffect(() => {
1473
+ const el = clickIconRef.current;
1474
+ if (!el) return;
1475
+ gsap.killTweensOf(el);
1476
+ if (clickIcon) {
1477
+ gsap.to(el, { opacity: 1, duration: 0.08, ease: "power1.in" });
1478
+ } else {
1479
+ gsap.to(el, { opacity: 0, duration: 0.45, ease: "power1.out" });
1480
+ }
1481
+ }, [clickIcon]);
1482
+ useEffect(() => {
1483
+ const track = progressTrackRef.current;
1484
+ const thumb = progressThumbRef.current;
1485
+ const container = progressRef.current;
1486
+ const targetH = isDragging ? 7 : isHoveringProgress ? 5 : 3;
1487
+ const targetW = isDragging ? 18 : isHoveringProgress ? 14 : 10;
1488
+ if (track) {
1489
+ gsap.killTweensOf(track);
1490
+ gsap.to(track, { height: targetH, duration: 0.15, ease: "power1.inOut" });
1491
+ }
1492
+ if (thumb) {
1493
+ gsap.killTweensOf(thumb);
1494
+ gsap.to(thumb, { width: targetW, height: targetW, duration: 0.2, ease: "back.out(1.7)" });
1495
+ }
1496
+ if (container) {
1497
+ const markers = container.querySelectorAll("[data-chapter-marker]");
1498
+ markers.forEach((el) => {
1499
+ gsap.killTweensOf(el);
1500
+ gsap.to(el, { height: targetH, duration: 0.15, ease: "power1.inOut" });
1501
+ });
1502
+ }
1503
+ }, [isDragging, isHoveringProgress]);
1411
1504
  useEffect(() => {
1412
1505
  if (sourceIndex >= parsed.sources.length) {
1413
1506
  setSourceIndex(initialSourceIndex);
@@ -1431,14 +1524,43 @@ function Video({
1431
1524
  setDuration(Number.isFinite(video.duration) ? video.duration : 0);
1432
1525
  applySubtitleMode(subtitleMode);
1433
1526
  };
1527
+ const hideAgeRating = () => {
1528
+ const wrap = ageRatingWrapRef.current;
1529
+ if (!wrap) return;
1530
+ if (ageRatingTlRef.current) ageRatingTlRef.current.kill();
1531
+ gsap.to(wrap, { opacity: 0, duration: 0.4, ease: "power2.inOut" });
1532
+ };
1434
1533
  const showAgeRating = () => {
1435
1534
  if (!parsed.ageRating?.data) return;
1436
- if (ageRatingTimerRef.current) window.clearTimeout(ageRatingTimerRef.current);
1437
- ageRatingTimerRef.current = window.setTimeout(() => {
1438
- setAgeRatingOverlay(true);
1439
- ageRatingTimerRef.current = window.setTimeout(() => setAgeRatingOverlay(false), 8e3);
1440
- }, 600);
1535
+ const wrap = ageRatingWrapRef.current;
1536
+ const icon = ageRatingIconRef.current;
1537
+ const text = ageRatingTextRef.current;
1538
+ if (!wrap) return;
1539
+ if (ageRatingTlRef.current) ageRatingTlRef.current.kill();
1540
+ const HOLD = 12;
1541
+ const tl = gsap.timeline({ delay: 0.6 });
1542
+ tl.fromTo(wrap, { opacity: 0 }, { opacity: 1, duration: 0.5, ease: "power2.out" });
1543
+ if (icon) {
1544
+ tl.fromTo(
1545
+ icon,
1546
+ { opacity: 0, scale: 0.7 },
1547
+ { opacity: 1, scale: 1, duration: 0.55, ease: "back.out(1.6)" },
1548
+ "-=0.2"
1549
+ );
1550
+ }
1551
+ if (text) {
1552
+ tl.fromTo(
1553
+ text,
1554
+ { opacity: 0, x: -10 },
1555
+ { opacity: 1, x: 0, duration: 0.4, ease: "power2.out" },
1556
+ "-=0.25"
1557
+ );
1558
+ }
1559
+ tl.to({}, { duration: HOLD });
1560
+ tl.to(wrap, { opacity: 0, duration: 0.7, ease: "power2.inOut" });
1561
+ ageRatingTlRef.current = tl;
1441
1562
  };
1563
+ showAgeRatingRef.current = showAgeRating;
1442
1564
  const onPlay = () => {
1443
1565
  setIsPlaying(true);
1444
1566
  if (ageRatingPauseTimerRef.current) {
@@ -1454,12 +1576,13 @@ function Video({
1454
1576
  const onPause = () => {
1455
1577
  setIsPlaying(false);
1456
1578
  setControlsVisible(true);
1579
+ hideAgeRating();
1457
1580
  if (parsed.ageRating?.data) {
1458
1581
  if (ageRatingPauseTimerRef.current) window.clearTimeout(ageRatingPauseTimerRef.current);
1459
1582
  ageRatingPauseTimerRef.current = window.setTimeout(() => {
1460
1583
  showAgeRating();
1461
1584
  ageRatingPauseTimerRef.current = null;
1462
- }, 5 * 60 * 1e3);
1585
+ }, 60 * 1e3);
1463
1586
  }
1464
1587
  };
1465
1588
  const onWaiting = () => setIsLoading(true);
@@ -1484,7 +1607,7 @@ function Video({
1484
1607
  video.removeEventListener("waiting", onWaiting);
1485
1608
  video.removeEventListener("canplay", onCanPlay);
1486
1609
  video.removeEventListener("ended", onEnded);
1487
- if (ageRatingTimerRef.current) window.clearTimeout(ageRatingTimerRef.current);
1610
+ if (ageRatingTlRef.current) ageRatingTlRef.current.kill();
1488
1611
  if (ageRatingPauseTimerRef.current) window.clearTimeout(ageRatingPauseTimerRef.current);
1489
1612
  };
1490
1613
  }, [applySubtitleMode, subtitleMode, showControlsTemporarily]);
@@ -2137,949 +2260,940 @@ function Video({
2137
2260
  "."
2138
2261
  ] });
2139
2262
  }
2140
- return /* @__PURE__ */ jsxs(
2263
+ return /* @__PURE__ */ jsx(
2141
2264
  "div",
2142
2265
  {
2143
2266
  ref: containerRef,
2144
2267
  className: `@container mx-auto w-full max-w-6xl${className ?? ""}`,
2145
- children: [
2146
- /* @__PURE__ */ jsx("style", { children: `
2147
- @keyframes silo-ar-bg{0%{opacity:0}10%{opacity:1}80%{opacity:1}100%{opacity:0}}
2148
- @keyframes silo-ar-icon{0%,8%{opacity:0;transform:scale(0.82)}18%{opacity:1;transform:scale(1)}80%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(1)}}
2149
- @keyframes silo-ar-text{0%,18%{opacity:0;transform:translateX(-6px)}30%{opacity:1;transform:translateX(0)}80%{opacity:1;transform:translateX(0)}100%{opacity:0;transform:translateX(0)}}
2150
- ` }),
2151
- /* @__PURE__ */ jsxs(
2152
- "div",
2153
- {
2154
- ref: playerRef,
2155
- tabIndex: 0,
2156
- onKeyDown: handleKeyDown,
2157
- onMouseMove: showControlsTemporarily,
2158
- onMouseLeave: () => {
2268
+ children: /* @__PURE__ */ jsxs(
2269
+ "div",
2270
+ {
2271
+ ref: playerRef,
2272
+ tabIndex: 0,
2273
+ onKeyDown: handleKeyDown,
2274
+ onMouseMove: showControlsTemporarily,
2275
+ onMouseLeave: () => {
2276
+ closeSettings();
2277
+ if (isPlaying && autoHideControls) {
2278
+ setControlsVisible(false);
2279
+ }
2280
+ },
2281
+ onBlur: (e) => {
2282
+ if (!e.currentTarget.contains(e.relatedTarget)) {
2159
2283
  closeSettings();
2160
- if (isPlaying && autoHideControls) {
2161
- setControlsVisible(false);
2284
+ }
2285
+ },
2286
+ onTouchStart: showControlsTemporarily,
2287
+ onTouchMove: showControlsTemporarily,
2288
+ 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",
2289
+ style: fixedHeight ? {
2290
+ height: typeof fixedHeight === "number" ? `${fixedHeight}px` : fixedHeight
2291
+ } : maxHeight ? {
2292
+ maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
2293
+ aspectRatio: "16/9"
2294
+ } : { aspectRatio: "16/9" },
2295
+ children: [
2296
+ /* @__PURE__ */ jsxs(
2297
+ "video",
2298
+ {
2299
+ ref: videoRef,
2300
+ className: `h-full w-full ${isFullscreen ? "object-contain" : "object-cover"}`,
2301
+ playsInline: true,
2302
+ preload: "metadata",
2303
+ crossOrigin: "anonymous",
2304
+ children: [
2305
+ captions.map((subtitle) => /* @__PURE__ */ jsx(
2306
+ "track",
2307
+ {
2308
+ kind: "subtitles",
2309
+ src: subtitle.src,
2310
+ srcLang: subtitle.srclang,
2311
+ label: subtitle.label,
2312
+ default: subtitle.default
2313
+ },
2314
+ `${activeSource.src}-${subtitle.srclang}-${subtitle.src}`
2315
+ )),
2316
+ parsed.storyboard?.src && /* @__PURE__ */ jsx(
2317
+ "track",
2318
+ {
2319
+ kind: "metadata",
2320
+ label: "thumbnails",
2321
+ src: parsed.storyboard.src
2322
+ }
2323
+ )
2324
+ ]
2162
2325
  }
2163
- },
2164
- onBlur: (e) => {
2165
- if (!e.currentTarget.contains(e.relatedTarget)) {
2166
- closeSettings();
2326
+ ),
2327
+ poster && !hasPlayed && /* @__PURE__ */ jsx(
2328
+ "img",
2329
+ {
2330
+ src: poster,
2331
+ "aria-hidden": true,
2332
+ className: "pointer-events-none absolute inset-0 h-full w-full object-contain bg-black"
2167
2333
  }
2168
- },
2169
- onTouchStart: showControlsTemporarily,
2170
- onTouchMove: showControlsTemporarily,
2171
- 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",
2172
- style: fixedHeight ? {
2173
- height: typeof fixedHeight === "number" ? `${fixedHeight}px` : fixedHeight
2174
- } : maxHeight ? {
2175
- maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
2176
- aspectRatio: "16/9"
2177
- } : { aspectRatio: "16/9" },
2178
- children: [
2179
- /* @__PURE__ */ jsxs(
2180
- "video",
2181
- {
2182
- ref: videoRef,
2183
- className: `h-full w-full ${isFullscreen ? "object-contain" : "object-cover"}`,
2184
- playsInline: true,
2185
- preload: "metadata",
2186
- crossOrigin: "anonymous",
2187
- children: [
2188
- captions.map((subtitle) => /* @__PURE__ */ jsx(
2189
- "track",
2190
- {
2191
- kind: "subtitles",
2192
- src: subtitle.src,
2193
- srcLang: subtitle.srclang,
2194
- label: subtitle.label,
2195
- default: subtitle.default
2196
- },
2197
- `${activeSource.src}-${subtitle.srclang}-${subtitle.src}`
2198
- )),
2199
- parsed.storyboard?.src && /* @__PURE__ */ jsx(
2200
- "track",
2201
- {
2202
- kind: "metadata",
2203
- label: "thumbnails",
2204
- src: parsed.storyboard.src
2205
- }
2206
- )
2207
- ]
2208
- }
2209
- ),
2210
- poster && !hasPlayed && /* @__PURE__ */ jsx(
2211
- "img",
2212
- {
2213
- src: poster,
2214
- "aria-hidden": true,
2215
- className: "pointer-events-none absolute inset-0 h-full w-full object-contain bg-black"
2216
- }
2217
- ),
2218
- ageRatingOverlay && parsed.ageRating?.data && (() => {
2219
- const ar = parsed.ageRating;
2220
- const regionKey = resolveAgeRatingRegion(ar.locale, ar.data);
2221
- if (!regionKey) return null;
2222
- const code = ar.data[regionKey];
2223
- const lookupKey = `${regionKey}:${code}`;
2224
- const info = ar.lookup?.[lookupKey];
2225
- const dur = "8s";
2226
- return /* @__PURE__ */ jsx(
2227
- "div",
2228
- {
2229
- className: "pointer-events-none absolute inset-0 z-40 flex items-end justify-start",
2230
- style: {
2231
- background: "linear-gradient(to right, rgba(0,0,0,0.82) 0%, rgba(0,0,0,0.45) 38%, transparent 62%)",
2232
- animation: `silo-ar-bg ${dur} forwards`
2233
- },
2234
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3.5 px-6 py-6 @sm:px-8 @sm:py-8", children: [
2235
- /* @__PURE__ */ jsx("div", { style: { animation: `silo-ar-icon ${dur} forwards` }, children: info?.imageUrl ? /* @__PURE__ */ jsx("img", { src: info.imageUrl, alt: code, className: "h-14 w-auto object-contain @sm:h-16 drop-shadow-[0_2px_8px_rgba(0,0,0,0.6)]" }) : /* @__PURE__ */ jsx("span", { className: "flex h-14 min-w-14 items-center justify-center rounded-md border-2 border-white/40 px-2 text-lg font-bold text-white @sm:h-16 @sm:min-w-16 @sm:text-xl drop-shadow-[0_2px_8px_rgba(0,0,0,0.6)]", children: code }) }),
2236
- (info?.title || info?.description) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", style: { animation: `silo-ar-text ${dur} forwards` }, children: [
2237
- info.title && /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-white @sm:text-base drop-shadow-[0_1px_4px_rgba(0,0,0,0.8)]", children: info.title }),
2238
- info.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-white/70 leading-snug max-w-56 @sm:text-sm @sm:max-w-72 drop-shadow-[0_1px_4px_rgba(0,0,0,0.8)]", children: info.description })
2239
- ] })
2240
- ] })
2241
- }
2242
- );
2243
- })(),
2244
- /* @__PURE__ */ jsx(
2334
+ ),
2335
+ parsed.ageRating?.data && (() => {
2336
+ const ar = parsed.ageRating;
2337
+ const regionKey = resolveAgeRatingRegion(ar.locale, ar.data);
2338
+ if (!regionKey) return null;
2339
+ const code = ar.data[regionKey];
2340
+ const lookupKey = `${regionKey}:${code}`;
2341
+ const info = ar.lookup?.[lookupKey];
2342
+ return /* @__PURE__ */ jsx(
2245
2343
  "div",
2246
2344
  {
2247
- className: "pointer-events-none absolute inset-0 z-10 grid place-items-center",
2345
+ ref: ageRatingWrapRef,
2346
+ className: "pointer-events-none absolute inset-0 z-20 flex items-start justify-start",
2248
2347
  style: {
2249
- opacity: clickIcon ? 1 : 0,
2250
- transition: clickIcon ? "opacity 0.08s ease-in" : "opacity 0.45s ease-out"
2348
+ opacity: 0,
2349
+ background: "linear-gradient(135deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.4) 40%, transparent 65%)"
2251
2350
  },
2252
- children: /* @__PURE__ */ jsx("span", { className: "grid size-10 place-items-center text-white drop-shadow-[0_2px_12px_rgba(0,0,0,0.8)] @sm:size-14 @lg:size-16", children: clickIcon === "pause" ? /* @__PURE__ */ jsx(Pause, { className: "size-7 @sm:size-9 @lg:size-11", fill: "white" }) : /* @__PURE__ */ jsx(
2253
- Play,
2351
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3.5 px-5 pt-5 @sm:px-7 @sm:pt-7", children: [
2352
+ /* @__PURE__ */ jsx("div", { ref: ageRatingIconRef, style: { opacity: 0 }, children: info?.imageUrl ? /* @__PURE__ */ jsx("img", { src: info.imageUrl, alt: code, className: "h-14 w-auto object-contain @sm:h-16 drop-shadow-[0_2px_8px_rgba(0,0,0,0.6)]" }) : /* @__PURE__ */ jsx("span", { className: "flex h-14 min-w-14 items-center justify-center rounded-md border-2 border-white/40 px-2 text-lg font-bold text-white @sm:h-16 @sm:min-w-16 @sm:text-xl drop-shadow-[0_2px_8px_rgba(0,0,0,0.6)]", children: code }) }),
2353
+ (info?.title || info?.description) && /* @__PURE__ */ jsxs("div", { ref: ageRatingTextRef, className: "flex flex-col gap-0.5", style: { opacity: 0 }, children: [
2354
+ info.title && /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-white @sm:text-base drop-shadow-[0_1px_4px_rgba(0,0,0,0.8)]", children: info.title }),
2355
+ info.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-white/70 leading-snug max-w-56 @sm:text-sm @sm:max-w-72 drop-shadow-[0_1px_4px_rgba(0,0,0,0.8)]", children: info.description })
2356
+ ] })
2357
+ ] })
2358
+ }
2359
+ );
2360
+ })(),
2361
+ /* @__PURE__ */ jsx(
2362
+ "div",
2363
+ {
2364
+ ref: clickIconRef,
2365
+ className: "pointer-events-none absolute inset-0 z-10 grid place-items-center",
2366
+ style: { opacity: 0 },
2367
+ children: /* @__PURE__ */ jsx("span", { className: "grid size-10 place-items-center text-white drop-shadow-[0_2px_12px_rgba(0,0,0,0.8)] @sm:size-14 @lg:size-16", children: clickIcon === "pause" ? /* @__PURE__ */ jsx(Pause, { className: "size-7 @sm:size-9 @lg:size-11", fill: "white" }) : /* @__PURE__ */ jsx(
2368
+ Play,
2369
+ {
2370
+ className: "ml-0.5 size-7 @sm:size-9 @lg:size-11",
2371
+ fill: "white"
2372
+ }
2373
+ ) })
2374
+ }
2375
+ ),
2376
+ isLoading && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 z-20 grid place-items-center bg-black/10", children: /* @__PURE__ */ jsx("div", { className: "size-9 animate-spin rounded-full border-2 border-white/25 border-t-white" }) }),
2377
+ /* @__PURE__ */ jsxs(
2378
+ "div",
2379
+ {
2380
+ ref: chromeRef,
2381
+ onClick: togglePlay,
2382
+ className: `absolute inset-0 z-30 flex flex-col ${isFullscreen ? "justify-between" : "justify-end"}`,
2383
+ children: [
2384
+ isFullscreen && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-black/70 to-transparent" }),
2385
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 h-40 bg-linear-to-t from-black/80 to-transparent" }),
2386
+ isFullscreen && /* @__PURE__ */ jsx(
2387
+ "header",
2254
2388
  {
2255
- className: "ml-0.5 size-7 @sm:size-9 @lg:size-11",
2256
- fill: "white"
2389
+ onClick: (e) => e.stopPropagation(),
2390
+ className: "relative z-10 flex items-start px-4 pt-4 text-white @sm:px-7 @sm:pt-7 @lg:px-9 @lg:pt-8",
2391
+ children: /* @__PURE__ */ jsxs("div", { children: [
2392
+ title && /* @__PURE__ */ jsx(
2393
+ "h1",
2394
+ {
2395
+ className: "text-sm font-bold tracking-wide @sm:text-base @md:text-lg @lg:text-xl",
2396
+ style: { textShadow: "0 1px 6px rgba(0,0,0,0.6)" },
2397
+ children: title
2398
+ }
2399
+ ),
2400
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs font-medium text-white/85 @sm:text-sm", children: description })
2401
+ ] })
2257
2402
  }
2258
- ) })
2259
- }
2260
- ),
2261
- isLoading && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 z-20 grid place-items-center bg-black/10", children: /* @__PURE__ */ jsx("div", { className: "size-9 animate-spin rounded-full border-2 border-white/25 border-t-white" }) }),
2262
- /* @__PURE__ */ jsxs(
2263
- "div",
2264
- {
2265
- ref: chromeRef,
2266
- onClick: togglePlay,
2267
- className: `absolute inset-0 z-30 flex flex-col transition-opacity duration-200 ${isFullscreen ? "justify-between" : "justify-end"} ${controlsVisible ? "opacity-100" : "opacity-0 pointer-events-none"}`,
2268
- children: [
2269
- isFullscreen && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-black/70 to-transparent" }),
2270
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 h-40 bg-linear-to-t from-black/80 to-transparent" }),
2271
- isFullscreen && /* @__PURE__ */ jsx(
2272
- "header",
2273
- {
2274
- onClick: (e) => e.stopPropagation(),
2275
- className: "relative z-10 flex items-start px-4 pt-4 text-white @sm:px-7 @sm:pt-7 @lg:px-9 @lg:pt-8",
2276
- children: /* @__PURE__ */ jsxs("div", { children: [
2277
- title && /* @__PURE__ */ jsx(
2278
- "h1",
2403
+ ),
2404
+ /* @__PURE__ */ jsxs(
2405
+ "footer",
2406
+ {
2407
+ onClick: (e) => e.stopPropagation(),
2408
+ className: "relative z-10 px-4 pb-4 text-white",
2409
+ children: [
2410
+ settingsOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
2411
+ /* @__PURE__ */ jsx(
2412
+ "div",
2279
2413
  {
2280
- className: "text-sm font-bold tracking-wide @sm:text-base @md:text-lg @lg:text-xl",
2281
- style: { textShadow: "0 1px 6px rgba(0,0,0,0.6)" },
2282
- children: title
2414
+ className: "fixed inset-0 z-70",
2415
+ onClick: closeSettings
2283
2416
  }
2284
2417
  ),
2285
- description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs font-medium text-white/85 @sm:text-sm", children: description })
2286
- ] })
2287
- }
2288
- ),
2289
- /* @__PURE__ */ jsxs(
2290
- "footer",
2291
- {
2292
- onClick: (e) => e.stopPropagation(),
2293
- className: "relative z-10 px-4 pb-4 text-white",
2294
- children: [
2295
- settingsOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
2296
- /* @__PURE__ */ jsx(
2297
- "div",
2298
- {
2299
- className: "fixed inset-0 z-70",
2300
- onClick: closeSettings
2301
- }
2302
- ),
2303
- /* @__PURE__ */ jsxs(
2304
- "div",
2305
- {
2306
- className: "absolute bottom-full right-2 z-70 mb-2 overflow-hidden rounded-2xl bg-[#1c1c1e]/95 shadow-2xl backdrop-blur-xl ring-1 ring-white/10",
2307
- style: {
2308
- width: Math.min(
2309
- 224,
2310
- Math.max(180, (playerWidth || 640) * 0.22)
2311
- ) + "px",
2312
- opacity: settingsVisible ? 1 : 0,
2313
- transform: settingsVisible ? "translateY(0) scale(1)" : "translateY(8px) scale(0.97)",
2314
- transition: "opacity 0.18s ease, transform 0.18s ease"
2315
- },
2316
- children: [
2317
- settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
2418
+ /* @__PURE__ */ jsx(
2419
+ "div",
2420
+ {
2421
+ ref: settingsPanelRef,
2422
+ className: "absolute bottom-full right-2 z-70 mb-2 overflow-hidden rounded-2xl bg-[#1c1c1e]/95 shadow-2xl backdrop-blur-xl ring-1 ring-white/10",
2423
+ style: {
2424
+ width: Math.min(
2425
+ 224,
2426
+ Math.max(180, (playerWidth || 640) * 0.22)
2427
+ ) + "px",
2428
+ opacity: 0
2429
+ },
2430
+ children: /* @__PURE__ */ jsxs("div", { ref: settingsContentRef, children: [
2431
+ settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
2432
+ {
2433
+ id: "quality",
2434
+ label: "Qualidade",
2435
+ value: qualities.find((q) => q.id === selectedQuality)?.label ?? "Auto"
2436
+ },
2437
+ ...captions.length > 0 ? [
2438
+ {
2439
+ id: "subtitles",
2440
+ label: "Legendas",
2441
+ value: subtitleStyle.track === "off" ? "Desligado" : captions.find(
2442
+ (s) => s.srclang === subtitleStyle.track
2443
+ )?.label ?? subtitleStyle.track
2444
+ }
2445
+ ] : [],
2446
+ ...audioTracks.length > 1 ? [
2447
+ {
2448
+ id: "audio",
2449
+ label: "\xC1udio",
2450
+ value: audioTracks.find(
2451
+ (t) => t.id === selectedAudio
2452
+ )?.label ?? ""
2453
+ }
2454
+ ] : [],
2455
+ {
2456
+ id: "playback",
2457
+ label: "Velocidade",
2458
+ value: playbackRate === 1 ? "Normal" : `${playbackRate}\xD7`
2459
+ }
2460
+ ].map((item) => /* @__PURE__ */ jsxs(
2461
+ "button",
2462
+ {
2463
+ type: "button",
2464
+ onClick: () => setSettingsTab(item.id),
2465
+ className: "flex w-full items-center justify-between gap-3 px-4 py-3 text-sm transition hover:bg-white/8 first:pt-3.5 last:pb-3.5",
2466
+ children: [
2467
+ /* @__PURE__ */ jsx("span", { className: "text-white/80", children: item.label }),
2468
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-xs text-white/40", children: [
2469
+ item.value,
2470
+ /* @__PURE__ */ jsx(
2471
+ "svg",
2472
+ {
2473
+ className: "size-3 opacity-50",
2474
+ viewBox: "0 0 12 12",
2475
+ fill: "none",
2476
+ children: /* @__PURE__ */ jsx(
2477
+ "path",
2478
+ {
2479
+ d: "M4.5 3l3 3-3 3",
2480
+ stroke: "currentColor",
2481
+ strokeWidth: "1.5",
2482
+ strokeLinecap: "round",
2483
+ strokeLinejoin: "round"
2484
+ }
2485
+ )
2486
+ }
2487
+ )
2488
+ ] })
2489
+ ]
2490
+ },
2491
+ item.id
2492
+ )) }),
2493
+ settingsTab === "quality" && /* @__PURE__ */ jsxs("div", { children: [
2494
+ /* @__PURE__ */ jsxs(
2495
+ "button",
2318
2496
  {
2319
- id: "quality",
2320
- label: "Qualidade",
2321
- value: qualities.find((q) => q.id === selectedQuality)?.label ?? "Auto"
2497
+ type: "button",
2498
+ onClick: () => setSettingsTab("root"),
2499
+ className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2500
+ children: [
2501
+ /* @__PURE__ */ jsx(
2502
+ "svg",
2503
+ {
2504
+ className: "size-3.5",
2505
+ viewBox: "0 0 12 12",
2506
+ fill: "none",
2507
+ children: /* @__PURE__ */ jsx(
2508
+ "path",
2509
+ {
2510
+ d: "M7.5 3L4.5 6l3 3",
2511
+ stroke: "currentColor",
2512
+ strokeWidth: "1.5",
2513
+ strokeLinecap: "round",
2514
+ strokeLinejoin: "round"
2515
+ }
2516
+ )
2517
+ }
2518
+ ),
2519
+ "Qualidade"
2520
+ ]
2521
+ }
2522
+ ),
2523
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: [...qualities].reverse().map((quality) => /* @__PURE__ */ jsxs(
2524
+ "button",
2525
+ {
2526
+ type: "button",
2527
+ onClick: () => {
2528
+ changeQuality(quality.id);
2529
+ setSettingsTab("root");
2530
+ },
2531
+ className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2532
+ children: [
2533
+ /* @__PURE__ */ jsx(
2534
+ "svg",
2535
+ {
2536
+ className: `size-4 shrink-0 ${selectedQuality === quality.id ? "text-white" : "text-transparent"}`,
2537
+ viewBox: "0 0 16 16",
2538
+ fill: "none",
2539
+ children: /* @__PURE__ */ jsx(
2540
+ "path",
2541
+ {
2542
+ d: "M3 8l3.5 3.5L13 4.5",
2543
+ stroke: "currentColor",
2544
+ strokeWidth: "1.8",
2545
+ strokeLinecap: "round",
2546
+ strokeLinejoin: "round"
2547
+ }
2548
+ )
2549
+ }
2550
+ ),
2551
+ /* @__PURE__ */ jsxs(
2552
+ "span",
2553
+ {
2554
+ className: selectedQuality === quality.id ? "font-semibold text-white" : "text-white/55",
2555
+ children: [
2556
+ quality.label,
2557
+ quality.id === "auto" ? " (ABR)" : ""
2558
+ ]
2559
+ }
2560
+ )
2561
+ ]
2322
2562
  },
2323
- ...captions.length > 0 ? [
2324
- {
2325
- id: "subtitles",
2326
- label: "Legendas",
2327
- value: subtitleStyle.track === "off" ? "Desligado" : captions.find(
2328
- (s) => s.srclang === subtitleStyle.track
2329
- )?.label ?? subtitleStyle.track
2330
- }
2331
- ] : [],
2332
- ...audioTracks.length > 1 ? [
2333
- {
2334
- id: "audio",
2335
- label: "\xC1udio",
2336
- value: audioTracks.find(
2337
- (t) => t.id === selectedAudio
2338
- )?.label ?? ""
2339
- }
2340
- ] : [],
2563
+ quality.id
2564
+ )) })
2565
+ ] }),
2566
+ settingsTab === "subtitles" && /* @__PURE__ */ jsxs("div", { children: [
2567
+ /* @__PURE__ */ jsxs(
2568
+ "button",
2341
2569
  {
2342
- id: "playback",
2343
- label: "Velocidade",
2344
- value: playbackRate === 1 ? "Normal" : `${playbackRate}\xD7`
2570
+ type: "button",
2571
+ onClick: () => setSettingsTab("root"),
2572
+ className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2573
+ children: [
2574
+ /* @__PURE__ */ jsx(
2575
+ "svg",
2576
+ {
2577
+ className: "size-3.5",
2578
+ viewBox: "0 0 12 12",
2579
+ fill: "none",
2580
+ children: /* @__PURE__ */ jsx(
2581
+ "path",
2582
+ {
2583
+ d: "M7.5 3L4.5 6l3 3",
2584
+ stroke: "currentColor",
2585
+ strokeWidth: "1.5",
2586
+ strokeLinecap: "round",
2587
+ strokeLinejoin: "round"
2588
+ }
2589
+ )
2590
+ }
2591
+ ),
2592
+ "Legendas"
2593
+ ]
2345
2594
  }
2346
- ].map((item) => /* @__PURE__ */ jsxs(
2595
+ ),
2596
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: [
2597
+ { srclang: "off", label: "Desligado" },
2598
+ ...captions
2599
+ ].map((s) => /* @__PURE__ */ jsxs(
2347
2600
  "button",
2348
2601
  {
2349
2602
  type: "button",
2350
- onClick: () => setSettingsTab(item.id),
2351
- className: "flex w-full items-center justify-between gap-3 px-4 py-3 text-sm transition hover:bg-white/8 first:pt-3.5 last:pb-3.5",
2603
+ onClick: () => {
2604
+ const next = s.srclang === "off" ? "off" : s.srclang;
2605
+ setSubtitleMode(next);
2606
+ setSubtitleStyle((st) => ({
2607
+ ...st,
2608
+ track: next
2609
+ }));
2610
+ },
2611
+ className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2352
2612
  children: [
2353
- /* @__PURE__ */ jsx("span", { className: "text-white/80", children: item.label }),
2354
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-xs text-white/40", children: [
2355
- item.value,
2356
- /* @__PURE__ */ jsx(
2357
- "svg",
2358
- {
2359
- className: "size-3 opacity-50",
2360
- viewBox: "0 0 12 12",
2361
- fill: "none",
2362
- children: /* @__PURE__ */ jsx(
2363
- "path",
2364
- {
2365
- d: "M4.5 3l3 3-3 3",
2366
- stroke: "currentColor",
2367
- strokeWidth: "1.5",
2368
- strokeLinecap: "round",
2369
- strokeLinejoin: "round"
2370
- }
2371
- )
2372
- }
2373
- )
2374
- ] })
2613
+ /* @__PURE__ */ jsx(
2614
+ "svg",
2615
+ {
2616
+ className: `size-4 shrink-0 ${subtitleStyle.track === s.srclang ? "text-white" : "text-transparent"}`,
2617
+ viewBox: "0 0 16 16",
2618
+ fill: "none",
2619
+ children: /* @__PURE__ */ jsx(
2620
+ "path",
2621
+ {
2622
+ d: "M3 8l3.5 3.5L13 4.5",
2623
+ stroke: "currentColor",
2624
+ strokeWidth: "1.8",
2625
+ strokeLinecap: "round",
2626
+ strokeLinejoin: "round"
2627
+ }
2628
+ )
2629
+ }
2630
+ ),
2631
+ /* @__PURE__ */ jsx(
2632
+ "span",
2633
+ {
2634
+ className: subtitleStyle.track === s.srclang ? "font-semibold text-white" : "text-white/55",
2635
+ children: s.label
2636
+ }
2637
+ )
2375
2638
  ]
2376
2639
  },
2377
- item.id
2640
+ s.srclang
2378
2641
  )) }),
2379
- settingsTab === "quality" && /* @__PURE__ */ jsxs("div", { children: [
2380
- /* @__PURE__ */ jsxs(
2381
- "button",
2382
- {
2383
- type: "button",
2384
- onClick: () => setSettingsTab("root"),
2385
- className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2386
- children: [
2387
- /* @__PURE__ */ jsx(
2388
- "svg",
2389
- {
2390
- className: "size-3.5",
2391
- viewBox: "0 0 12 12",
2392
- fill: "none",
2393
- children: /* @__PURE__ */ jsx(
2394
- "path",
2395
- {
2396
- d: "M7.5 3L4.5 6l3 3",
2397
- stroke: "currentColor",
2398
- strokeWidth: "1.5",
2399
- strokeLinecap: "round",
2400
- strokeLinejoin: "round"
2401
- }
2402
- )
2403
- }
2404
- ),
2405
- "Qualidade"
2406
- ]
2407
- }
2408
- ),
2409
- /* @__PURE__ */ jsx("div", { className: "py-1.5", children: [...qualities].reverse().map((quality) => /* @__PURE__ */ jsxs(
2410
- "button",
2411
- {
2412
- type: "button",
2413
- onClick: () => {
2414
- changeQuality(quality.id);
2415
- setSettingsTab("root");
2642
+ subtitleStyle.track !== "off" && /* @__PURE__ */ jsxs(
2643
+ "button",
2644
+ {
2645
+ type: "button",
2646
+ onClick: () => setSettingsTab("subtitles-style"),
2647
+ className: "flex w-full items-center justify-between gap-3 border-t border-white/8 px-4 py-3 text-sm transition hover:bg-white/8",
2648
+ children: [
2649
+ /* @__PURE__ */ jsx("span", { className: "text-white/60", children: "Apar\xEAncia" }),
2650
+ /* @__PURE__ */ jsx(
2651
+ "svg",
2652
+ {
2653
+ className: "size-3 opacity-50",
2654
+ viewBox: "0 0 12 12",
2655
+ fill: "none",
2656
+ children: /* @__PURE__ */ jsx(
2657
+ "path",
2658
+ {
2659
+ d: "M4.5 3l3 3-3 3",
2660
+ stroke: "currentColor",
2661
+ strokeWidth: "1.5",
2662
+ strokeLinecap: "round",
2663
+ strokeLinejoin: "round"
2664
+ }
2665
+ )
2666
+ }
2667
+ )
2668
+ ]
2669
+ }
2670
+ )
2671
+ ] }),
2672
+ settingsTab === "subtitles-style" && /* @__PURE__ */ jsxs("div", { children: [
2673
+ /* @__PURE__ */ jsxs(
2674
+ "button",
2675
+ {
2676
+ type: "button",
2677
+ onClick: () => setSettingsTab("subtitles"),
2678
+ className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2679
+ children: [
2680
+ /* @__PURE__ */ jsx(
2681
+ "svg",
2682
+ {
2683
+ className: "size-3.5",
2684
+ viewBox: "0 0 12 12",
2685
+ fill: "none",
2686
+ children: /* @__PURE__ */ jsx(
2687
+ "path",
2688
+ {
2689
+ d: "M7.5 3L4.5 6l3 3",
2690
+ stroke: "currentColor",
2691
+ strokeWidth: "1.5",
2692
+ strokeLinecap: "round",
2693
+ strokeLinejoin: "round"
2694
+ }
2695
+ )
2696
+ }
2697
+ ),
2698
+ "Apar\xEAncia"
2699
+ ]
2700
+ }
2701
+ ),
2702
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 flex flex-col gap-3", children: [
2703
+ /* @__PURE__ */ jsxs("div", { children: [
2704
+ /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Tamanho" }),
2705
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: ["small", "medium", "large", "xlarge"].map((s) => /* @__PURE__ */ jsx(
2706
+ "button",
2707
+ {
2708
+ type: "button",
2709
+ onClick: () => setSubtitleStyle((st) => ({ ...st, size: s })),
2710
+ className: `flex-1 rounded-lg py-1.5 text-xs font-medium transition${subtitleStyle.size === s ? "bg-white/20 text-white" : "text-white/45 hover:bg-white/10"}`,
2711
+ children: s === "small" ? "P" : s === "medium" ? "M" : s === "large" ? "G" : "GG"
2416
2712
  },
2417
- className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2418
- children: [
2419
- /* @__PURE__ */ jsx(
2420
- "svg",
2421
- {
2422
- className: `size-4 shrink-0 ${selectedQuality === quality.id ? "text-white" : "text-transparent"}`,
2423
- viewBox: "0 0 16 16",
2424
- fill: "none",
2425
- children: /* @__PURE__ */ jsx(
2426
- "path",
2427
- {
2428
- d: "M3 8l3.5 3.5L13 4.5",
2429
- stroke: "currentColor",
2430
- strokeWidth: "1.8",
2431
- strokeLinecap: "round",
2432
- strokeLinejoin: "round"
2433
- }
2434
- )
2435
- }
2436
- ),
2437
- /* @__PURE__ */ jsxs(
2438
- "span",
2439
- {
2440
- className: selectedQuality === quality.id ? "font-semibold text-white" : "text-white/55",
2441
- children: [
2442
- quality.label,
2443
- quality.id === "auto" ? " (ABR)" : ""
2444
- ]
2445
- }
2446
- )
2447
- ]
2448
- },
2449
- quality.id
2450
- )) })
2451
- ] }),
2452
- settingsTab === "subtitles" && /* @__PURE__ */ jsxs("div", { children: [
2453
- /* @__PURE__ */ jsxs(
2454
- "button",
2455
- {
2456
- type: "button",
2457
- onClick: () => setSettingsTab("root"),
2458
- className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2459
- children: [
2460
- /* @__PURE__ */ jsx(
2461
- "svg",
2462
- {
2463
- className: "size-3.5",
2464
- viewBox: "0 0 12 12",
2465
- fill: "none",
2466
- children: /* @__PURE__ */ jsx(
2467
- "path",
2468
- {
2469
- d: "M7.5 3L4.5 6l3 3",
2470
- stroke: "currentColor",
2471
- strokeWidth: "1.5",
2472
- strokeLinecap: "round",
2473
- strokeLinejoin: "round"
2474
- }
2475
- )
2476
- }
2477
- ),
2478
- "Legendas"
2479
- ]
2480
- }
2481
- ),
2482
- /* @__PURE__ */ jsx("div", { className: "py-1.5", children: [
2483
- { srclang: "off", label: "Desligado" },
2484
- ...captions
2485
- ].map((s) => /* @__PURE__ */ jsxs(
2486
- "button",
2487
- {
2488
- type: "button",
2489
- onClick: () => {
2490
- const next = s.srclang === "off" ? "off" : s.srclang;
2491
- setSubtitleMode(next);
2492
- setSubtitleStyle((st) => ({
2713
+ s
2714
+ )) })
2715
+ ] }),
2716
+ /* @__PURE__ */ jsxs("div", { children: [
2717
+ /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Cor" }),
2718
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: [
2719
+ ["white", "Branco", "#fff"],
2720
+ ["yellow", "Amarelo", "#facc15"],
2721
+ ["cyan", "Ciano", "#22d3ee"]
2722
+ ].map(([val, label, color]) => /* @__PURE__ */ jsx(
2723
+ "button",
2724
+ {
2725
+ type: "button",
2726
+ onClick: () => setSubtitleStyle((st) => ({
2493
2727
  ...st,
2494
- track: next
2495
- }));
2728
+ color: val
2729
+ })),
2730
+ className: `flex-1 rounded-lg py-1.5 text-xs font-medium transition ring-1${subtitleStyle.color === val ? "ring-white/40" : "ring-transparent hover:ring-white/15"}`,
2731
+ style: { color },
2732
+ children: label
2496
2733
  },
2497
- className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2498
- children: [
2499
- /* @__PURE__ */ jsx(
2500
- "svg",
2501
- {
2502
- className: `size-4 shrink-0 ${subtitleStyle.track === s.srclang ? "text-white" : "text-transparent"}`,
2503
- viewBox: "0 0 16 16",
2504
- fill: "none",
2505
- children: /* @__PURE__ */ jsx(
2506
- "path",
2507
- {
2508
- d: "M3 8l3.5 3.5L13 4.5",
2509
- stroke: "currentColor",
2510
- strokeWidth: "1.8",
2511
- strokeLinecap: "round",
2512
- strokeLinejoin: "round"
2513
- }
2514
- )
2515
- }
2516
- ),
2517
- /* @__PURE__ */ jsx(
2518
- "span",
2519
- {
2520
- className: subtitleStyle.track === s.srclang ? "font-semibold text-white" : "text-white/55",
2521
- children: s.label
2522
- }
2523
- )
2524
- ]
2734
+ val
2735
+ )) })
2736
+ ] }),
2737
+ /* @__PURE__ */ jsxs("div", { children: [
2738
+ /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Fundo" }),
2739
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: [
2740
+ ["none", "Nenhum"],
2741
+ ["semi", "Semi"],
2742
+ ["solid", "S\xF3lido"]
2743
+ ].map(([val, label]) => /* @__PURE__ */ jsx(
2744
+ "button",
2745
+ {
2746
+ type: "button",
2747
+ onClick: () => setSubtitleStyle((st) => ({ ...st, bg: val })),
2748
+ className: `flex-1 rounded-lg py-1.5 text-xs font-medium transition${subtitleStyle.bg === val ? "bg-white/20 text-white" : "text-white/45 hover:bg-white/10"}`,
2749
+ children: label
2750
+ },
2751
+ val
2752
+ )) })
2753
+ ] })
2754
+ ] })
2755
+ ] }),
2756
+ settingsTab === "audio" && /* @__PURE__ */ jsxs("div", { children: [
2757
+ /* @__PURE__ */ jsxs(
2758
+ "button",
2759
+ {
2760
+ type: "button",
2761
+ onClick: () => setSettingsTab("root"),
2762
+ className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2763
+ children: [
2764
+ /* @__PURE__ */ jsx(
2765
+ "svg",
2766
+ {
2767
+ className: "size-3.5",
2768
+ viewBox: "0 0 12 12",
2769
+ fill: "none",
2770
+ children: /* @__PURE__ */ jsx(
2771
+ "path",
2772
+ {
2773
+ d: "M7.5 3L4.5 6l3 3",
2774
+ stroke: "currentColor",
2775
+ strokeWidth: "1.5",
2776
+ strokeLinecap: "round",
2777
+ strokeLinejoin: "round"
2778
+ }
2779
+ )
2780
+ }
2781
+ ),
2782
+ "\xC1udio"
2783
+ ]
2784
+ }
2785
+ ),
2786
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: audioTracks.map((track) => /* @__PURE__ */ jsxs(
2787
+ "button",
2788
+ {
2789
+ type: "button",
2790
+ onClick: () => {
2791
+ changeAudio(track.id);
2792
+ setSettingsTab("root");
2525
2793
  },
2526
- s.srclang
2527
- )) }),
2528
- subtitleStyle.track !== "off" && /* @__PURE__ */ jsxs(
2529
- "button",
2530
- {
2531
- type: "button",
2532
- onClick: () => setSettingsTab("subtitles-style"),
2533
- className: "flex w-full items-center justify-between gap-3 border-t border-white/8 px-4 py-3 text-sm transition hover:bg-white/8",
2534
- children: [
2535
- /* @__PURE__ */ jsx("span", { className: "text-white/60", children: "Apar\xEAncia" }),
2536
- /* @__PURE__ */ jsx(
2537
- "svg",
2538
- {
2539
- className: "size-3 opacity-50",
2540
- viewBox: "0 0 12 12",
2541
- fill: "none",
2542
- children: /* @__PURE__ */ jsx(
2543
- "path",
2544
- {
2545
- d: "M4.5 3l3 3-3 3",
2546
- stroke: "currentColor",
2547
- strokeWidth: "1.5",
2548
- strokeLinecap: "round",
2549
- strokeLinejoin: "round"
2550
- }
2551
- )
2552
- }
2553
- )
2554
- ]
2555
- }
2556
- )
2557
- ] }),
2558
- settingsTab === "subtitles-style" && /* @__PURE__ */ jsxs("div", { children: [
2559
- /* @__PURE__ */ jsxs(
2560
- "button",
2561
- {
2562
- type: "button",
2563
- onClick: () => setSettingsTab("subtitles"),
2564
- className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2565
- children: [
2566
- /* @__PURE__ */ jsx(
2567
- "svg",
2568
- {
2569
- className: "size-3.5",
2570
- viewBox: "0 0 12 12",
2571
- fill: "none",
2572
- children: /* @__PURE__ */ jsx(
2573
- "path",
2574
- {
2575
- d: "M7.5 3L4.5 6l3 3",
2576
- stroke: "currentColor",
2577
- strokeWidth: "1.5",
2578
- strokeLinecap: "round",
2579
- strokeLinejoin: "round"
2580
- }
2581
- )
2582
- }
2583
- ),
2584
- "Apar\xEAncia"
2585
- ]
2586
- }
2587
- ),
2588
- /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 flex flex-col gap-3", children: [
2589
- /* @__PURE__ */ jsxs("div", { children: [
2590
- /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Tamanho" }),
2591
- /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: ["small", "medium", "large", "xlarge"].map((s) => /* @__PURE__ */ jsx(
2592
- "button",
2794
+ className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2795
+ children: [
2796
+ /* @__PURE__ */ jsx(
2797
+ "svg",
2593
2798
  {
2594
- type: "button",
2595
- onClick: () => setSubtitleStyle((st) => ({ ...st, size: s })),
2596
- className: `flex-1 rounded-lg py-1.5 text-xs font-medium transition${subtitleStyle.size === s ? "bg-white/20 text-white" : "text-white/45 hover:bg-white/10"}`,
2597
- children: s === "small" ? "P" : s === "medium" ? "M" : s === "large" ? "G" : "GG"
2598
- },
2599
- s
2600
- )) })
2601
- ] }),
2602
- /* @__PURE__ */ jsxs("div", { children: [
2603
- /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Cor" }),
2604
- /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: [
2605
- ["white", "Branco", "#fff"],
2606
- ["yellow", "Amarelo", "#facc15"],
2607
- ["cyan", "Ciano", "#22d3ee"]
2608
- ].map(([val, label, color]) => /* @__PURE__ */ jsx(
2609
- "button",
2799
+ className: `size-4 shrink-0 ${selectedAudio === track.id ? "text-white" : "text-transparent"}`,
2800
+ viewBox: "0 0 16 16",
2801
+ fill: "none",
2802
+ children: /* @__PURE__ */ jsx(
2803
+ "path",
2804
+ {
2805
+ d: "M3 8l3.5 3.5L13 4.5",
2806
+ stroke: "currentColor",
2807
+ strokeWidth: "1.8",
2808
+ strokeLinecap: "round",
2809
+ strokeLinejoin: "round"
2810
+ }
2811
+ )
2812
+ }
2813
+ ),
2814
+ /* @__PURE__ */ jsx(
2815
+ "span",
2610
2816
  {
2611
- type: "button",
2612
- onClick: () => setSubtitleStyle((st) => ({
2613
- ...st,
2614
- color: val
2615
- })),
2616
- className: `flex-1 rounded-lg py-1.5 text-xs font-medium transition ring-1${subtitleStyle.color === val ? "ring-white/40" : "ring-transparent hover:ring-white/15"}`,
2617
- style: { color },
2618
- children: label
2619
- },
2620
- val
2621
- )) })
2622
- ] }),
2623
- /* @__PURE__ */ jsxs("div", { children: [
2624
- /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Fundo" }),
2625
- /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: [
2626
- ["none", "Nenhum"],
2627
- ["semi", "Semi"],
2628
- ["solid", "S\xF3lido"]
2629
- ].map(([val, label]) => /* @__PURE__ */ jsx(
2630
- "button",
2817
+ className: selectedAudio === track.id ? "font-semibold text-white" : "text-white/55",
2818
+ children: track.label
2819
+ }
2820
+ )
2821
+ ]
2822
+ },
2823
+ track.id
2824
+ )) })
2825
+ ] }),
2826
+ settingsTab === "playback" && /* @__PURE__ */ jsxs("div", { children: [
2827
+ /* @__PURE__ */ jsxs(
2828
+ "button",
2829
+ {
2830
+ type: "button",
2831
+ onClick: () => setSettingsTab("root"),
2832
+ className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2833
+ children: [
2834
+ /* @__PURE__ */ jsx(
2835
+ "svg",
2631
2836
  {
2632
- type: "button",
2633
- onClick: () => setSubtitleStyle((st) => ({ ...st, bg: val })),
2634
- className: `flex-1 rounded-lg py-1.5 text-xs font-medium transition${subtitleStyle.bg === val ? "bg-white/20 text-white" : "text-white/45 hover:bg-white/10"}`,
2635
- children: label
2636
- },
2637
- val
2638
- )) })
2639
- ] })
2640
- ] })
2641
- ] }),
2642
- settingsTab === "audio" && /* @__PURE__ */ jsxs("div", { children: [
2643
- /* @__PURE__ */ jsxs(
2644
- "button",
2645
- {
2646
- type: "button",
2647
- onClick: () => setSettingsTab("root"),
2648
- className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2649
- children: [
2650
- /* @__PURE__ */ jsx(
2651
- "svg",
2652
- {
2653
- className: "size-3.5",
2654
- viewBox: "0 0 12 12",
2655
- fill: "none",
2656
- children: /* @__PURE__ */ jsx(
2657
- "path",
2658
- {
2659
- d: "M7.5 3L4.5 6l3 3",
2660
- stroke: "currentColor",
2661
- strokeWidth: "1.5",
2662
- strokeLinecap: "round",
2663
- strokeLinejoin: "round"
2664
- }
2665
- )
2666
- }
2667
- ),
2668
- "\xC1udio"
2669
- ]
2670
- }
2671
- ),
2672
- /* @__PURE__ */ jsx("div", { className: "py-1.5", children: audioTracks.map((track) => /* @__PURE__ */ jsxs(
2673
- "button",
2674
- {
2675
- type: "button",
2676
- onClick: () => {
2677
- changeAudio(track.id);
2678
- setSettingsTab("root");
2679
- },
2680
- className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2681
- children: [
2682
- /* @__PURE__ */ jsx(
2683
- "svg",
2684
- {
2685
- className: `size-4 shrink-0 ${selectedAudio === track.id ? "text-white" : "text-transparent"}`,
2686
- viewBox: "0 0 16 16",
2687
- fill: "none",
2688
- children: /* @__PURE__ */ jsx(
2689
- "path",
2690
- {
2691
- d: "M3 8l3.5 3.5L13 4.5",
2692
- stroke: "currentColor",
2693
- strokeWidth: "1.8",
2694
- strokeLinecap: "round",
2695
- strokeLinejoin: "round"
2696
- }
2697
- )
2698
- }
2699
- ),
2700
- /* @__PURE__ */ jsx(
2701
- "span",
2702
- {
2703
- className: selectedAudio === track.id ? "font-semibold text-white" : "text-white/55",
2704
- children: track.label
2705
- }
2706
- )
2707
- ]
2837
+ className: "size-3.5",
2838
+ viewBox: "0 0 12 12",
2839
+ fill: "none",
2840
+ children: /* @__PURE__ */ jsx(
2841
+ "path",
2842
+ {
2843
+ d: "M7.5 3L4.5 6l3 3",
2844
+ stroke: "currentColor",
2845
+ strokeWidth: "1.5",
2846
+ strokeLinecap: "round",
2847
+ strokeLinejoin: "round"
2848
+ }
2849
+ )
2850
+ }
2851
+ ),
2852
+ "Velocidade"
2853
+ ]
2854
+ }
2855
+ ),
2856
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: PLAYBACK_SPEEDS.map((speed) => /* @__PURE__ */ jsxs(
2857
+ "button",
2858
+ {
2859
+ type: "button",
2860
+ onClick: () => {
2861
+ setPlaybackRate(speed);
2862
+ closeSettings();
2708
2863
  },
2709
- track.id
2710
- )) })
2711
- ] }),
2712
- settingsTab === "playback" && /* @__PURE__ */ jsxs("div", { children: [
2713
- /* @__PURE__ */ jsxs(
2714
- "button",
2864
+ className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2865
+ children: [
2866
+ /* @__PURE__ */ jsx(
2867
+ "svg",
2868
+ {
2869
+ className: `size-4 shrink-0 ${playbackRate === speed ? "text-white" : "text-transparent"}`,
2870
+ viewBox: "0 0 16 16",
2871
+ fill: "none",
2872
+ children: /* @__PURE__ */ jsx(
2873
+ "path",
2874
+ {
2875
+ d: "M3 8l3.5 3.5L13 4.5",
2876
+ stroke: "currentColor",
2877
+ strokeWidth: "1.8",
2878
+ strokeLinecap: "round",
2879
+ strokeLinejoin: "round"
2880
+ }
2881
+ )
2882
+ }
2883
+ ),
2884
+ /* @__PURE__ */ jsx(
2885
+ "span",
2886
+ {
2887
+ className: playbackRate === speed ? "font-semibold text-white" : "text-white/55",
2888
+ children: speed === 1 ? "Normal" : `${speed}\xD7`
2889
+ }
2890
+ )
2891
+ ]
2892
+ },
2893
+ speed
2894
+ )) })
2895
+ ] })
2896
+ ] })
2897
+ }
2898
+ )
2899
+ ] }),
2900
+ /* @__PURE__ */ jsxs(
2901
+ "div",
2902
+ {
2903
+ ref: progressRef,
2904
+ onPointerMove: handleProgressPointerMove,
2905
+ onPointerEnter: handleProgressPointerEnter,
2906
+ onPointerLeave: handleProgressPointerLeave,
2907
+ onPointerDown: handleProgressPointerDown,
2908
+ onPointerUp: handleProgressPointerUp,
2909
+ className: "relative mb-2 h-8 cursor-pointer overflow-visible",
2910
+ children: [
2911
+ /* @__PURE__ */ jsxs(
2912
+ "div",
2913
+ {
2914
+ ref: progressTrackRef,
2915
+ className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/18",
2916
+ style: {
2917
+ height: "3px"
2918
+ },
2919
+ children: [
2920
+ /* @__PURE__ */ jsx(
2921
+ "div",
2715
2922
  {
2716
- type: "button",
2717
- onClick: () => setSettingsTab("root"),
2718
- className: "flex w-full items-center gap-2 border-b border-white/8 px-4 py-3 text-xs font-semibold text-white/50 transition hover:text-white",
2719
- children: [
2720
- /* @__PURE__ */ jsx(
2721
- "svg",
2722
- {
2723
- className: "size-3.5",
2724
- viewBox: "0 0 12 12",
2725
- fill: "none",
2726
- children: /* @__PURE__ */ jsx(
2727
- "path",
2728
- {
2729
- d: "M7.5 3L4.5 6l3 3",
2730
- stroke: "currentColor",
2731
- strokeWidth: "1.5",
2732
- strokeLinecap: "round",
2733
- strokeLinejoin: "round"
2734
- }
2735
- )
2736
- }
2737
- ),
2738
- "Velocidade"
2739
- ]
2923
+ className: "absolute inset-y-0 left-0 rounded-full bg-white/28",
2924
+ style: { width: `${bufferedPercent}%` }
2740
2925
  }
2741
2926
  ),
2742
- /* @__PURE__ */ jsx("div", { className: "py-1.5", children: PLAYBACK_SPEEDS.map((speed) => /* @__PURE__ */ jsxs(
2743
- "button",
2927
+ /* @__PURE__ */ jsx(
2928
+ "div",
2744
2929
  {
2745
- type: "button",
2746
- onClick: () => {
2747
- setPlaybackRate(speed);
2748
- closeSettings();
2749
- },
2750
- className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2751
- children: [
2752
- /* @__PURE__ */ jsx(
2753
- "svg",
2754
- {
2755
- className: `size-4 shrink-0 ${playbackRate === speed ? "text-white" : "text-transparent"}`,
2756
- viewBox: "0 0 16 16",
2757
- fill: "none",
2758
- children: /* @__PURE__ */ jsx(
2759
- "path",
2760
- {
2761
- d: "M3 8l3.5 3.5L13 4.5",
2762
- stroke: "currentColor",
2763
- strokeWidth: "1.8",
2764
- strokeLinecap: "round",
2765
- strokeLinejoin: "round"
2766
- }
2767
- )
2768
- }
2769
- ),
2770
- /* @__PURE__ */ jsx(
2771
- "span",
2772
- {
2773
- className: playbackRate === speed ? "font-semibold text-white" : "text-white/55",
2774
- children: speed === 1 ? "Normal" : `${speed}\xD7`
2775
- }
2776
- )
2777
- ]
2778
- },
2779
- speed
2780
- )) })
2781
- ] })
2782
- ]
2783
- }
2784
- )
2785
- ] }),
2786
- /* @__PURE__ */ jsxs(
2787
- "div",
2788
- {
2789
- ref: progressRef,
2790
- onPointerMove: handleProgressPointerMove,
2791
- onPointerEnter: handleProgressPointerEnter,
2792
- onPointerLeave: handleProgressPointerLeave,
2793
- onPointerDown: handleProgressPointerDown,
2794
- onPointerUp: handleProgressPointerUp,
2795
- className: "relative mb-2 h-8 cursor-pointer overflow-visible",
2796
- children: [
2797
- /* @__PURE__ */ jsxs(
2930
+ className: "absolute inset-y-0 left-0 rounded-full bg-white",
2931
+ style: { width: `${progressPercent}%`, transition: "width 0.05s linear" }
2932
+ }
2933
+ )
2934
+ ]
2935
+ }
2936
+ ),
2937
+ /* @__PURE__ */ jsx(
2938
+ "div",
2939
+ {
2940
+ ref: progressThumbRef,
2941
+ className: "pointer-events-none absolute rounded-full bg-white shadow-[0_1px_6px_rgba(0,0,0,0.5)]",
2942
+ style: {
2943
+ top: "50%",
2944
+ left: `${progressPercent}%`,
2945
+ transform: "translate(-50%, -50%)",
2946
+ width: "10px",
2947
+ height: "10px"
2948
+ }
2949
+ }
2950
+ ),
2951
+ chapters.length > 0 && duration > 0 && chapters.map((ch, i) => /* @__PURE__ */ jsx(
2952
+ "div",
2953
+ {
2954
+ "data-chapter-marker": true,
2955
+ className: "pointer-events-none absolute top-1/2 -translate-y-1/2 w-0.5 rounded-full bg-white/50",
2956
+ style: { left: `${ch.startTime / duration * 100}%`, height: "3px" }
2957
+ },
2958
+ i
2959
+ )),
2960
+ preview && (() => {
2961
+ const frameW = preview.cue.w ?? 160;
2962
+ const frameH = preview.cue.h ?? 90;
2963
+ const thumbW = 200;
2964
+ const thumbH = Math.round(thumbW * (frameH / frameW));
2965
+ const scale = thumbW / frameW;
2966
+ const isSprite = preview.cue.x != null && preview.cue.y != null;
2967
+ return /* @__PURE__ */ jsxs(
2798
2968
  "div",
2799
2969
  {
2800
- className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/18",
2970
+ className: "pointer-events-none absolute flex flex-col items-center gap-1",
2801
2971
  style: {
2802
- height: isDragging ? "7px" : isHoveringProgress ? "5px" : "3px",
2803
- transition: "height 0.15s ease"
2972
+ bottom: "calc(100% + 6px)",
2973
+ left: preview.left,
2974
+ transform: "translateX(-50%)",
2975
+ zIndex: 80
2804
2976
  },
2805
2977
  children: [
2806
2978
  /* @__PURE__ */ jsx(
2807
2979
  "div",
2808
2980
  {
2809
- className: "absolute inset-y-0 left-0 rounded-full bg-white/28",
2810
- style: { width: `${bufferedPercent}%` }
2981
+ className: "overflow-hidden rounded-lg shadow-2xl ring-1 ring-white/20",
2982
+ style: { width: thumbW, height: thumbH, flexShrink: 0 },
2983
+ children: isSprite ? (
2984
+ // Sprite: need full sheet dimensions to compute backgroundSize correctly.
2985
+ // Load them once from the image's natural size.
2986
+ (() => {
2987
+ const imgUrl = preview.cue.image;
2988
+ if (storyboardSheetUrlRef.current !== imgUrl) {
2989
+ storyboardSheetUrlRef.current = imgUrl;
2990
+ const img = new window.Image();
2991
+ img.onload = () => setStoryboardSheetSize({ w: img.naturalWidth, h: img.naturalHeight });
2992
+ img.src = imgUrl;
2993
+ }
2994
+ if (!storyboardSheetSize) return null;
2995
+ const bsW = storyboardSheetSize.w * scale;
2996
+ const bsH = storyboardSheetSize.h * scale;
2997
+ return /* @__PURE__ */ jsx(
2998
+ "div",
2999
+ {
3000
+ style: {
3001
+ width: thumbW,
3002
+ height: thumbH,
3003
+ backgroundImage: `url(${imgUrl})`,
3004
+ backgroundRepeat: "no-repeat",
3005
+ backgroundPosition: `-${(preview.cue.x ?? 0) * scale}px -${(preview.cue.y ?? 0) * scale}px`,
3006
+ backgroundSize: `${bsW}px ${bsH}px`
3007
+ }
3008
+ }
3009
+ );
3010
+ })()
3011
+ ) : /* @__PURE__ */ jsx(
3012
+ "img",
3013
+ {
3014
+ src: preview.cue.image,
3015
+ alt: "",
3016
+ style: { width: thumbW, height: thumbH, objectFit: "cover", objectPosition: "center", display: "block" }
3017
+ }
3018
+ )
2811
3019
  }
2812
3020
  ),
2813
- /* @__PURE__ */ jsx(
3021
+ /* @__PURE__ */ jsxs(
2814
3022
  "div",
2815
3023
  {
2816
- className: "absolute inset-y-0 left-0 rounded-full bg-white",
2817
- style: { width: `${progressPercent}%`, transition: "width 0.05s linear" }
3024
+ className: "flex items-center gap-1.5 rounded-md px-2 py-0.5 text-[11px] font-semibold text-white/90",
3025
+ style: { background: "rgba(0,0,0,0.55)", backdropFilter: "blur(6px)" },
3026
+ children: [
3027
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formatTime(preview.time) }),
3028
+ (() => {
3029
+ const ch = [...chapters].reverse().find((c) => c.startTime <= preview.time);
3030
+ return ch ? /* @__PURE__ */ jsxs(Fragment, { children: [
3031
+ /* @__PURE__ */ jsx("span", { className: "text-white/40", children: "\xB7" }),
3032
+ /* @__PURE__ */ jsx("span", { className: "max-w-36 truncate", children: ch.title })
3033
+ ] }) : null;
3034
+ })()
3035
+ ]
2818
3036
  }
2819
3037
  )
2820
3038
  ]
2821
3039
  }
2822
- ),
2823
- /* @__PURE__ */ jsx(
2824
- "div",
2825
- {
2826
- className: "pointer-events-none absolute rounded-full bg-white shadow-[0_1px_6px_rgba(0,0,0,0.5)]",
2827
- style: {
2828
- top: "50%",
2829
- left: `${progressPercent}%`,
2830
- transform: "translate(-50%, -50%)",
2831
- width: isDragging ? "18px" : isHoveringProgress ? "14px" : "10px",
2832
- height: isDragging ? "18px" : isHoveringProgress ? "14px" : "10px",
2833
- 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)"
2834
- }
2835
- }
2836
- ),
2837
- chapters.length > 0 && duration > 0 && chapters.map((ch, i) => /* @__PURE__ */ jsx(
2838
- "div",
2839
- {
2840
- className: "pointer-events-none absolute top-1/2 -translate-y-1/2 w-0.5 rounded-full bg-white/50",
2841
- style: { left: `${ch.startTime / duration * 100}%`, height: isDragging ? "7px" : isHoveringProgress ? "5px" : "3px", transition: "height 0.15s ease" }
2842
- },
2843
- i
2844
- )),
2845
- preview && (() => {
2846
- const frameW = preview.cue.w ?? 160;
2847
- const frameH = preview.cue.h ?? 90;
2848
- const thumbW = 200;
2849
- const thumbH = Math.round(thumbW * (frameH / frameW));
2850
- const scale = thumbW / frameW;
2851
- const isSprite = preview.cue.x != null && preview.cue.y != null;
3040
+ );
3041
+ })()
3042
+ ]
3043
+ }
3044
+ ),
3045
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
3046
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 @sm:gap-2", children: [
3047
+ /* @__PURE__ */ jsx(
3048
+ "button",
3049
+ {
3050
+ type: "button",
3051
+ onClick: togglePlay,
3052
+ className: "grid size-8 place-items-center rounded-full text-white transition hover:bg-white/10 @sm:size-9",
3053
+ "aria-label": isPlaying ? "Pause" : "Play",
3054
+ children: isPlaying ? /* @__PURE__ */ jsx(Pause, { className: "size-4 @sm:size-5", fill: "white" }) : /* @__PURE__ */ jsx(Play, { className: "ml-0.5 size-4 @sm:size-5", fill: "white" })
3055
+ }
3056
+ ),
3057
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-medium tabular-nums text-white/80", children: [
3058
+ formatTime(currentTime),
3059
+ /* @__PURE__ */ jsx("span", { className: "text-white/30", children: "/" }),
3060
+ /* @__PURE__ */ jsx("span", { className: "text-white/45", children: formatTime(duration) })
3061
+ ] }),
3062
+ (() => {
3063
+ if (chapters.length === 0) return null;
3064
+ const ch = [...chapters].reverse().find((c) => currentTime >= c.startTime);
3065
+ return ch ? /* @__PURE__ */ jsx("span", { className: "hidden max-w-40 truncate text-[11px] text-white/50 @sm:block", children: ch.title }) : null;
3066
+ })()
3067
+ ] }),
3068
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
3069
+ parsed.rating && (() => {
3070
+ const REACTIONS = [
3071
+ { key: "LOVE", emoji: "\u2764\uFE0F" },
3072
+ { key: "LIKE", emoji: "\u{1F44D}" },
3073
+ { key: "DISLIKE", emoji: "\u{1F44E}" }
3074
+ ];
3075
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3076
+ REACTIONS.map(({ key, emoji }) => {
3077
+ const count = ratingCounts[key] ?? 0;
3078
+ const active = userReaction === key;
2852
3079
  return /* @__PURE__ */ jsxs(
2853
- "div",
3080
+ "button",
2854
3081
  {
2855
- className: "pointer-events-none absolute flex flex-col items-center gap-1",
2856
- style: {
2857
- bottom: "calc(100% + 6px)",
2858
- left: preview.left,
2859
- transform: "translateX(-50%)",
2860
- zIndex: 80
3082
+ type: "button",
3083
+ onClick: (e) => {
3084
+ e.stopPropagation();
3085
+ const next = active ? null : key;
3086
+ setUserReaction(next);
3087
+ setRatingCounts((prev) => {
3088
+ const updated = { ...prev };
3089
+ const prev_reaction = userReactionRef.current;
3090
+ if (active) updated[key] = Math.max(0, (updated[key] ?? 0) - 1);
3091
+ else {
3092
+ if (prev_reaction) updated[prev_reaction] = Math.max(0, (updated[prev_reaction] ?? 0) - 1);
3093
+ updated[key] = (updated[key] ?? 0) + 1;
3094
+ }
3095
+ return updated;
3096
+ });
3097
+ onReactRef.current?.(next);
2861
3098
  },
3099
+ className: `flex items-center gap-0.5 rounded px-1.5 py-1 text-[11px] transition hover:bg-white/10 ${active ? "opacity-100" : "opacity-50 hover:opacity-80"}`,
3100
+ "aria-label": key.toLowerCase(),
3101
+ "aria-pressed": active,
2862
3102
  children: [
2863
- /* @__PURE__ */ jsx(
2864
- "div",
2865
- {
2866
- className: "overflow-hidden rounded-lg shadow-2xl ring-1 ring-white/20",
2867
- style: { width: thumbW, height: thumbH, flexShrink: 0 },
2868
- children: isSprite ? (
2869
- // Sprite: need full sheet dimensions to compute backgroundSize correctly.
2870
- // Load them once from the image's natural size.
2871
- (() => {
2872
- const imgUrl = preview.cue.image;
2873
- if (storyboardSheetUrlRef.current !== imgUrl) {
2874
- storyboardSheetUrlRef.current = imgUrl;
2875
- const img = new window.Image();
2876
- img.onload = () => setStoryboardSheetSize({ w: img.naturalWidth, h: img.naturalHeight });
2877
- img.src = imgUrl;
2878
- }
2879
- if (!storyboardSheetSize) return null;
2880
- const bsW = storyboardSheetSize.w * scale;
2881
- const bsH = storyboardSheetSize.h * scale;
2882
- return /* @__PURE__ */ jsx(
2883
- "div",
2884
- {
2885
- style: {
2886
- width: thumbW,
2887
- height: thumbH,
2888
- backgroundImage: `url(${imgUrl})`,
2889
- backgroundRepeat: "no-repeat",
2890
- backgroundPosition: `-${(preview.cue.x ?? 0) * scale}px -${(preview.cue.y ?? 0) * scale}px`,
2891
- backgroundSize: `${bsW}px ${bsH}px`
2892
- }
2893
- }
2894
- );
2895
- })()
2896
- ) : /* @__PURE__ */ jsx(
2897
- "img",
2898
- {
2899
- src: preview.cue.image,
2900
- alt: "",
2901
- style: { width: thumbW, height: thumbH, objectFit: "cover", objectPosition: "center", display: "block" }
2902
- }
2903
- )
2904
- }
2905
- ),
2906
- /* @__PURE__ */ jsxs(
2907
- "div",
2908
- {
2909
- className: "flex items-center gap-1.5 rounded-md px-2 py-0.5 text-[11px] font-semibold text-white/90",
2910
- style: { background: "rgba(0,0,0,0.55)", backdropFilter: "blur(6px)" },
2911
- children: [
2912
- /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formatTime(preview.time) }),
2913
- (() => {
2914
- const ch = [...chapters].reverse().find((c) => c.startTime <= preview.time);
2915
- return ch ? /* @__PURE__ */ jsxs(Fragment, { children: [
2916
- /* @__PURE__ */ jsx("span", { className: "text-white/40", children: "\xB7" }),
2917
- /* @__PURE__ */ jsx("span", { className: "max-w-36 truncate", children: ch.title })
2918
- ] }) : null;
2919
- })()
2920
- ]
2921
- }
2922
- )
3103
+ /* @__PURE__ */ jsx("span", { children: emoji }),
3104
+ count > 0 && /* @__PURE__ */ jsx("span", { className: "text-white/70 tabular-nums", children: count })
2923
3105
  ]
2924
- }
3106
+ },
3107
+ key
2925
3108
  );
2926
- })()
2927
- ]
2928
- }
2929
- ),
2930
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
2931
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 @sm:gap-2", children: [
2932
- /* @__PURE__ */ jsx(
2933
- "button",
2934
- {
2935
- type: "button",
2936
- onClick: togglePlay,
2937
- className: "grid size-8 place-items-center rounded-full text-white transition hover:bg-white/10 @sm:size-9",
2938
- "aria-label": isPlaying ? "Pause" : "Play",
2939
- children: isPlaying ? /* @__PURE__ */ jsx(Pause, { className: "size-4 @sm:size-5", fill: "white" }) : /* @__PURE__ */ jsx(Play, { className: "ml-0.5 size-4 @sm:size-5", fill: "white" })
2940
- }
2941
- ),
2942
- /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-medium tabular-nums text-white/80", children: [
2943
- formatTime(currentTime),
2944
- /* @__PURE__ */ jsx("span", { className: "text-white/30", children: "/" }),
2945
- /* @__PURE__ */ jsx("span", { className: "text-white/45", children: formatTime(duration) })
2946
- ] }),
2947
- (() => {
2948
- if (chapters.length === 0) return null;
2949
- const ch = [...chapters].reverse().find((c) => currentTime >= c.startTime);
2950
- return ch ? /* @__PURE__ */ jsx("span", { className: "hidden max-w-40 truncate text-[11px] text-white/50 @sm:block", children: ch.title }) : null;
2951
- })()
2952
- ] }),
2953
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
2954
- parsed.rating && (() => {
2955
- const REACTIONS = [
2956
- { key: "LOVE", emoji: "\u2764\uFE0F" },
2957
- { key: "LIKE", emoji: "\u{1F44D}" },
2958
- { key: "DISLIKE", emoji: "\u{1F44E}" }
2959
- ];
2960
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2961
- REACTIONS.map(({ key, emoji }) => {
2962
- const count = ratingCounts[key] ?? 0;
2963
- const active = userReaction === key;
2964
- return /* @__PURE__ */ jsxs(
2965
- "button",
2966
- {
2967
- type: "button",
2968
- onClick: (e) => {
2969
- e.stopPropagation();
2970
- const next = active ? null : key;
2971
- setUserReaction(next);
2972
- setRatingCounts((prev) => {
2973
- const updated = { ...prev };
2974
- const prev_reaction = userReactionRef.current;
2975
- if (active) updated[key] = Math.max(0, (updated[key] ?? 0) - 1);
2976
- else {
2977
- if (prev_reaction) updated[prev_reaction] = Math.max(0, (updated[prev_reaction] ?? 0) - 1);
2978
- updated[key] = (updated[key] ?? 0) + 1;
2979
- }
2980
- return updated;
2981
- });
2982
- onReactRef.current?.(next);
2983
- },
2984
- className: `flex items-center gap-0.5 rounded px-1.5 py-1 text-[11px] transition hover:bg-white/10 ${active ? "opacity-100" : "opacity-50 hover:opacity-80"}`,
2985
- "aria-label": key.toLowerCase(),
2986
- "aria-pressed": active,
2987
- children: [
2988
- /* @__PURE__ */ jsx("span", { children: emoji }),
2989
- count > 0 && /* @__PURE__ */ jsx("span", { className: "text-white/70 tabular-nums", children: count })
2990
- ]
2991
- },
2992
- key
2993
- );
2994
- }),
2995
- /* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" })
2996
- ] });
2997
- })(),
2998
- /* @__PURE__ */ jsx(
2999
- VolumeSlider,
3000
- {
3001
- volume: isMuted ? 0 : volume,
3002
- onMuteToggle: () => setIsMuted((v) => !v),
3003
- onVolumeChange: (v) => {
3004
- setVolume(v);
3005
- setIsMuted(v === 0);
3006
- },
3007
- isMuted
3008
- }
3009
- ),
3010
- /* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
3011
- captions.length > 0 && /* @__PURE__ */ jsx(
3012
- "button",
3013
- {
3014
- type: "button",
3015
- onClick: () => {
3016
- const next = subtitleMode === "off" ? captions[0]?.srclang ?? "off" : "off";
3017
- setSubtitleMode(next);
3018
- setSubtitleStyle((st) => ({ ...st, track: next }));
3019
- },
3020
- className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
3021
- "aria-label": "Captions",
3022
- children: /* @__PURE__ */ jsx(Captions$1, { className: "size-4 @sm:size-5" })
3023
- }
3024
- ),
3025
- /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
3026
- "button",
3027
- {
3028
- type: "button",
3029
- onClick: () => settingsOpen ? closeSettings() : openSettings(),
3030
- className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${settingsOpen ? "text-white" : "text-white/60"}`,
3031
- "aria-label": "Settings",
3032
- children: /* @__PURE__ */ jsx(Settings, { className: "size-4 @sm:size-5" })
3033
- }
3034
- ) }),
3035
- /* @__PURE__ */ jsx(
3036
- "button",
3037
- {
3038
- type: "button",
3039
- onClick: toggleFullscreen,
3040
- className: "grid size-8 place-items-center text-white/60 transition hover:scale-110 hover:text-white/80 @sm:size-10",
3041
- "aria-label": isFullscreen ? "Exit fullscreen" : "Fullscreen",
3042
- children: isFullscreen ? /* @__PURE__ */ jsx(Minimize, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Maximize, { className: "size-4 @sm:size-5" })
3043
- }
3044
- )
3045
- ] })
3109
+ }),
3110
+ /* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" })
3111
+ ] });
3112
+ })(),
3113
+ /* @__PURE__ */ jsx(
3114
+ VolumeSlider,
3115
+ {
3116
+ volume: isMuted ? 0 : volume,
3117
+ onMuteToggle: () => setIsMuted((v) => !v),
3118
+ onVolumeChange: (v) => {
3119
+ setVolume(v);
3120
+ setIsMuted(v === 0);
3121
+ },
3122
+ isMuted
3123
+ }
3124
+ ),
3125
+ /* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
3126
+ captions.length > 0 && /* @__PURE__ */ jsx(
3127
+ "button",
3128
+ {
3129
+ type: "button",
3130
+ onClick: () => {
3131
+ const next = subtitleMode === "off" ? captions[0]?.srclang ?? "off" : "off";
3132
+ setSubtitleMode(next);
3133
+ setSubtitleStyle((st) => ({ ...st, track: next }));
3134
+ },
3135
+ className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
3136
+ "aria-label": "Captions",
3137
+ children: /* @__PURE__ */ jsx(Captions$1, { className: "size-4 @sm:size-5" })
3138
+ }
3139
+ ),
3140
+ /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
3141
+ "button",
3142
+ {
3143
+ type: "button",
3144
+ onClick: () => settingsOpen ? closeSettings() : openSettings(),
3145
+ className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${settingsOpen ? "text-white" : "text-white/60"}`,
3146
+ "aria-label": "Settings",
3147
+ children: /* @__PURE__ */ jsx(Settings, { className: "size-4 @sm:size-5" })
3148
+ }
3149
+ ) }),
3150
+ /* @__PURE__ */ jsx(
3151
+ "button",
3152
+ {
3153
+ type: "button",
3154
+ onClick: toggleFullscreen,
3155
+ className: "grid size-8 place-items-center text-white/60 transition hover:scale-110 hover:text-white/80 @sm:size-10",
3156
+ "aria-label": isFullscreen ? "Exit fullscreen" : "Fullscreen",
3157
+ children: isFullscreen ? /* @__PURE__ */ jsx(Minimize, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Maximize, { className: "size-4 @sm:size-5" })
3158
+ }
3159
+ )
3046
3160
  ] })
3047
- ]
3048
- }
3049
- )
3050
- ]
3051
- }
3052
- ),
3053
- activeCue && /* @__PURE__ */ jsx(
3054
- "div",
3055
- {
3056
- className: `pointer-events-none absolute inset-x-0 z-40 flex justify-center px-4 transition-all duration-200${controlsVisible ? "bottom-20 @sm:bottom-24 @lg:bottom-28" : "bottom-4 @sm:bottom-6"}`,
3057
- children: /* @__PURE__ */ jsx(
3058
- "div",
3059
- {
3060
- className: "max-w-[80%] rounded-lg px-4 py-1.5 text-center font-medium leading-snug",
3061
- style: {
3062
- fontSize: (() => {
3063
- const base = Math.max(12, Math.min(playerHeight * 0.028, 32));
3064
- if (subtitleStyle.size === "small") return `${base * 0.75}px`;
3065
- if (subtitleStyle.size === "large") return `${base * 1.35}px`;
3066
- if (subtitleStyle.size === "xlarge") return `${base * 1.8}px`;
3067
- return `${base}px`;
3068
- })(),
3069
- color: subtitleStyle.color === "yellow" ? "#facc15" : subtitleStyle.color === "cyan" ? "#22d3ee" : "#ffffff",
3070
- backgroundColor: subtitleStyle.bg === "none" ? "transparent" : subtitleStyle.bg === "solid" ? "rgba(0,0,0,0.9)" : "rgba(0,0,0,0.55)",
3071
- backdropFilter: subtitleStyle.bg === "semi" ? "blur(6px)" : void 0,
3072
- textShadow: subtitleStyle.bg === "none" ? "0 1px 8px rgba(0,0,0,1), 0 0 16px rgba(0,0,0,0.9)" : "0 1px 3px rgba(0,0,0,0.5)"
3073
- },
3074
- children: activeCue
3161
+ ] })
3162
+ ]
3075
3163
  }
3076
3164
  )
3077
- }
3078
- )
3079
- ]
3080
- }
3081
- )
3082
- ]
3165
+ ]
3166
+ }
3167
+ ),
3168
+ activeCue && /* @__PURE__ */ jsx(
3169
+ "div",
3170
+ {
3171
+ className: `pointer-events-none absolute inset-x-0 z-40 flex justify-center px-4 transition-all duration-200${controlsVisible ? "bottom-20 @sm:bottom-24 @lg:bottom-28" : "bottom-4 @sm:bottom-6"}`,
3172
+ children: /* @__PURE__ */ jsx(
3173
+ "div",
3174
+ {
3175
+ className: "max-w-[80%] rounded-lg px-4 py-1.5 text-center font-medium leading-snug",
3176
+ style: {
3177
+ fontSize: (() => {
3178
+ const base = Math.max(12, Math.min(playerHeight * 0.028, 32));
3179
+ if (subtitleStyle.size === "small") return `${base * 0.75}px`;
3180
+ if (subtitleStyle.size === "large") return `${base * 1.35}px`;
3181
+ if (subtitleStyle.size === "xlarge") return `${base * 1.8}px`;
3182
+ return `${base}px`;
3183
+ })(),
3184
+ color: subtitleStyle.color === "yellow" ? "#facc15" : subtitleStyle.color === "cyan" ? "#22d3ee" : "#ffffff",
3185
+ backgroundColor: subtitleStyle.bg === "none" ? "transparent" : subtitleStyle.bg === "solid" ? "rgba(0,0,0,0.9)" : "rgba(0,0,0,0.55)",
3186
+ backdropFilter: subtitleStyle.bg === "semi" ? "blur(6px)" : void 0,
3187
+ textShadow: subtitleStyle.bg === "none" ? "0 1px 8px rgba(0,0,0,1), 0 0 16px rgba(0,0,0,0.9)" : "0 1px 3px rgba(0,0,0,0.5)"
3188
+ },
3189
+ children: activeCue
3190
+ }
3191
+ )
3192
+ }
3193
+ )
3194
+ ]
3195
+ }
3196
+ )
3083
3197
  }
3084
3198
  );
3085
3199
  }
@@ -3093,6 +3207,9 @@ function VolumeSlider({
3093
3207
  const [hovered, setHovered] = useState(false);
3094
3208
  const [dragging, setDragging] = useState(false);
3095
3209
  const trackRef = useRef(null);
3210
+ const sliderWrapRef = useRef(null);
3211
+ const railRef = useRef(null);
3212
+ const thumbRef = useRef(null);
3096
3213
  const expanded = hovered || dragging;
3097
3214
  const seek = useCallback((clientX) => {
3098
3215
  const track = trackRef.current;
@@ -3110,6 +3227,31 @@ function VolumeSlider({
3110
3227
  if (dragging) seek(e.clientX);
3111
3228
  }, [dragging, seek]);
3112
3229
  const onPointerUp = useCallback(() => setDragging(false), []);
3230
+ useEffect(() => {
3231
+ const wrap = sliderWrapRef.current;
3232
+ if (!wrap) return;
3233
+ gsap.killTweensOf(wrap);
3234
+ gsap.to(wrap, {
3235
+ width: expanded ? 64 : 0,
3236
+ opacity: expanded ? 1 : 0,
3237
+ duration: 0.2,
3238
+ ease: "power2.inOut"
3239
+ });
3240
+ }, [expanded]);
3241
+ useEffect(() => {
3242
+ const rail = railRef.current;
3243
+ const thumb = thumbRef.current;
3244
+ const targetRailH = dragging ? 5 : hovered ? 4 : 3;
3245
+ const targetThumbSize = dragging ? 14 : hovered ? 11 : 0;
3246
+ if (rail) {
3247
+ gsap.killTweensOf(rail);
3248
+ gsap.to(rail, { height: targetRailH, duration: 0.15, ease: "power1.inOut" });
3249
+ }
3250
+ if (thumb) {
3251
+ gsap.killTweensOf(thumb);
3252
+ gsap.to(thumb, { width: targetThumbSize, height: targetThumbSize, duration: 0.15, ease: "power1.inOut" });
3253
+ }
3254
+ }, [dragging, hovered]);
3113
3255
  const fillPercent = volume * 100;
3114
3256
  return /* @__PURE__ */ jsxs(
3115
3257
  "div",
@@ -3133,10 +3275,10 @@ function VolumeSlider({
3133
3275
  /* @__PURE__ */ jsx(
3134
3276
  "div",
3135
3277
  {
3278
+ ref: sliderWrapRef,
3136
3279
  style: {
3137
- width: expanded ? "64px" : "0px",
3138
- opacity: expanded ? 1 : 0,
3139
- transition: "width 0.2s ease, opacity 0.2s ease",
3280
+ width: "0px",
3281
+ opacity: 0,
3140
3282
  overflow: "hidden"
3141
3283
  },
3142
3284
  children: /* @__PURE__ */ jsxs(
@@ -3152,11 +3294,9 @@ function VolumeSlider({
3152
3294
  /* @__PURE__ */ jsx(
3153
3295
  "div",
3154
3296
  {
3297
+ ref: railRef,
3155
3298
  className: "absolute inset-x-0 rounded-full bg-white/20",
3156
- style: {
3157
- height: dragging ? "5px" : hovered ? "4px" : "3px",
3158
- transition: "height 0.15s ease"
3159
- },
3299
+ style: { height: "3px" },
3160
3300
  children: /* @__PURE__ */ jsx(
3161
3301
  "div",
3162
3302
  {
@@ -3169,12 +3309,12 @@ function VolumeSlider({
3169
3309
  /* @__PURE__ */ jsx(
3170
3310
  "div",
3171
3311
  {
3312
+ ref: thumbRef,
3172
3313
  className: "pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow-md",
3173
3314
  style: {
3174
3315
  left: `${fillPercent}%`,
3175
- width: dragging ? "14px" : hovered ? "11px" : "0px",
3176
- height: dragging ? "14px" : hovered ? "11px" : "0px",
3177
- transition: "width 0.15s ease, height 0.15s ease"
3316
+ width: "0px",
3317
+ height: "0px"
3178
3318
  }
3179
3319
  }
3180
3320
  )