@geekapps/silo-elements-nextjs 0.2.24 → 0.2.27

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
@@ -3,7 +3,7 @@ import { useMultipartUpload, useBatchUpload, useSignedUrl, useFileStatus } from
3
3
  export { SiloProvider, useBatchUpload, useFileStatus, useMultipartUpload, useSignedUrl, useSiloClient } from '@geekapps/silo-nextjs';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import gsap from 'gsap';
6
- import { Play, Rewind, Pause, FastForward, VolumeX, Volume2, Captions, Settings, Minimize, Maximize } from 'lucide-react';
6
+ import { Play, Settings, Captions, Volume2, Pause, VolumeX, Minimize, Maximize } from 'lucide-react';
7
7
 
8
8
  // src/ImageUploader.tsx
9
9
 
@@ -1260,7 +1260,7 @@ function Video({
1260
1260
  const [audioTracks, setAudioTracks] = useState([]);
1261
1261
  const [selectedAudio, setSelectedAudio] = useState(0);
1262
1262
  const [settingsOpen, setSettingsOpen] = useState(false);
1263
- const [settingsTab, setSettingsTab] = useState("quality");
1263
+ const [settingsTab, setSettingsTab] = useState("root");
1264
1264
  const [playbackRate, setPlaybackRate] = useState(1);
1265
1265
  const [subtitleStyle, setSubtitleStyle] = useState({
1266
1266
  track: initialSubtitleMode,
@@ -1286,6 +1286,7 @@ function Video({
1286
1286
  const [volume, setVolume] = useState(defaultVolume);
1287
1287
  const [isMuted, setIsMuted] = useState(false);
1288
1288
  const [isFullscreen, setIsFullscreen] = useState(false);
1289
+ const [playerHeight, setPlayerHeight] = useState(0);
1289
1290
  const [error, setError] = useState(null);
1290
1291
  const activeSource = parsed.sources[sourceIndex] ?? parsed.sources[0] ?? null;
1291
1292
  const progressPercent = duration ? currentTime / duration * 100 : 0;
@@ -1466,6 +1467,16 @@ function Video({
1466
1467
  video?.removeEventListener("webkitendfullscreen", onFullscreenChange);
1467
1468
  };
1468
1469
  }, []);
1470
+ useEffect(() => {
1471
+ const player = playerRef.current;
1472
+ if (!player) return;
1473
+ const ro = new ResizeObserver((entries) => {
1474
+ const entry = entries[0];
1475
+ if (entry) setPlayerHeight(entry.contentRect.height);
1476
+ });
1477
+ ro.observe(player);
1478
+ return () => ro.disconnect();
1479
+ }, []);
1469
1480
  useEffect(() => {
1470
1481
  let cancelled = false;
1471
1482
  async function loadStoryboard() {
@@ -1933,132 +1944,108 @@ function Video({
1933
1944
  onClick: togglePlay,
1934
1945
  className: `absolute inset-0 z-30 flex flex-col justify-between transition-opacity duration-200 ${controlsVisible ? "opacity-100" : "opacity-0 pointer-events-none"}`,
1935
1946
  children: [
1936
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-black/70 to-transparent" }),
1947
+ 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" }),
1937
1948
  /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 h-40 bg-linear-to-t from-black/80 to-transparent" }),
1938
- /* @__PURE__ */ jsxs("header", { onClick: (e) => e.stopPropagation(), className: "relative z-10 flex items-start justify-between gap-4 px-4 pt-4 text-white @sm:px-7 @sm:pt-7 @lg:px-9 @lg:pt-8", children: [
1939
- /* @__PURE__ */ jsxs("div", { children: [
1940
- title && /* @__PURE__ */ jsx("h1", { className: "text-sm font-bold tracking-wide @sm:text-base @md:text-lg @lg:text-xl", style: { textShadow: "0 1px 6px rgba(0,0,0,0.6)" }, children: title }),
1941
- description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs font-medium text-white/85 @sm:text-sm", children: description })
1942
- ] }),
1943
- parsed.sources.length > 1 && /* @__PURE__ */ jsx(
1944
- "select",
1945
- {
1946
- value: String(sourceIndex),
1947
- onChange: (e) => setSourceIndex(Number(e.target.value)),
1948
- "aria-label": "Video source",
1949
- className: "h-8 rounded-full border border-white/15 bg-white/10 px-3 text-xs font-semibold text-white outline-none backdrop-blur-md transition hover:bg-white/15",
1950
- children: parsed.sources.map((source, index) => /* @__PURE__ */ jsx("option", { value: String(index), className: "text-black", children: source.label ?? source.type ?? `Source ${index + 1}` }, `${source.src}-${index}`))
1951
- }
1952
- )
1953
- ] }),
1954
- /* @__PURE__ */ jsxs("footer", { onClick: (e) => e.stopPropagation(), className: "relative z-10 px-3 pb-3 text-white @sm:px-5 @sm:pb-5 @lg:px-9 @lg:pb-8", children: [
1949
+ isFullscreen && /* @__PURE__ */ jsx("header", { onClick: (e) => e.stopPropagation(), 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", children: /* @__PURE__ */ jsxs("div", { children: [
1950
+ title && /* @__PURE__ */ jsx("h1", { className: "text-sm font-bold tracking-wide @sm:text-base @md:text-lg @lg:text-xl", style: { textShadow: "0 1px 6px rgba(0,0,0,0.6)" }, children: title }),
1951
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs font-medium text-white/85 @sm:text-sm", children: description })
1952
+ ] }) }),
1953
+ /* @__PURE__ */ jsxs("footer", { onClick: (e) => e.stopPropagation(), className: "relative z-10 px-4 pb-4 text-white", children: [
1955
1954
  settingsOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
1956
1955
  /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-40", onClick: () => setSettingsOpen(false) }),
1957
- /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full right-3 z-50 mb-2 w-52 overflow-hidden rounded-xl border border-white/10 bg-black/90 shadow-2xl backdrop-blur-xl @sm:right-5 @lg:right-9", children: [
1958
- /* @__PURE__ */ jsx("div", { className: "flex border-b border-white/10", children: ["quality", ...parsed.subtitles.length > 0 ? ["subtitles"] : [], ...audioTracks.length > 1 ? ["audio"] : [], "playback"].map((tab) => /* @__PURE__ */ jsx(
1959
- "button",
1960
- {
1961
- type: "button",
1962
- onClick: () => setSettingsTab(tab),
1963
- className: `flex-1 px-3 py-2.5 text-xs font-semibold capitalize transition ${settingsTab === tab ? "text-white border-b-2 border-white -mb-px" : "text-white/50 hover:text-white/80"}`,
1964
- children: tab
1965
- },
1966
- tab
1967
- )) }),
1968
- /* @__PURE__ */ jsxs("div", { className: "max-h-48 overflow-y-auto py-1", children: [
1969
- settingsTab === "quality" && /* @__PURE__ */ jsx(Fragment, { children: [...qualities].reverse().map((quality) => /* @__PURE__ */ jsxs(
1970
- SettingsItem,
1956
+ /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full right-0 z-50 mb-3 flex flex-col gap-2.5", style: { animation: "spFadeIn 0.15s ease" }, children: [
1957
+ /* @__PURE__ */ jsxs("div", { className: "w-52 overflow-hidden rounded-2xl bg-[#1a1a1a]/95 shadow-2xl backdrop-blur-xl ring-1 ring-white/8", children: [
1958
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 py-3 border-b border-white/8", children: [
1959
+ /* @__PURE__ */ jsx(Settings, { className: "size-4 text-white/60" }),
1960
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-white", children: "Video Quality" })
1961
+ ] }),
1962
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: [...qualities].reverse().map((quality) => /* @__PURE__ */ jsxs(
1963
+ "button",
1971
1964
  {
1972
- active: selectedQuality === quality.id,
1965
+ type: "button",
1973
1966
  onClick: () => changeQuality(quality.id),
1967
+ className: "flex w-full items-center gap-3 px-4 py-2 text-sm transition hover:bg-white/8",
1974
1968
  children: [
1975
- quality.label,
1976
- quality.id === "auto" && /* @__PURE__ */ jsx("span", { className: "ml-1 text-[10px] text-white/40", children: "ABR" })
1969
+ /* @__PURE__ */ jsx("span", { className: `size-4 shrink-0 ${selectedQuality === quality.id ? "text-white" : "text-transparent"}`, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M3 8l3.5 3.5L13 4.5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
1970
+ /* @__PURE__ */ jsxs("span", { className: selectedQuality === quality.id ? "font-semibold text-white" : "text-white/55", children: [
1971
+ quality.label,
1972
+ quality.id === "auto" ? " (ABR)" : ""
1973
+ ] })
1977
1974
  ]
1978
1975
  },
1979
1976
  quality.id
1980
- )) }),
1981
- settingsTab === "subtitles" && /* @__PURE__ */ jsxs("div", { className: "px-3 py-2 space-y-3", children: [
1982
- /* @__PURE__ */ jsxs("div", { children: [
1983
- /* @__PURE__ */ jsx("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wider text-white/40", children: "Track" }),
1984
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: [{ srclang: "off", label: "Off" }, ...parsed.subtitles].map((s) => /* @__PURE__ */ jsx(
1985
- "button",
1986
- {
1987
- type: "button",
1988
- onClick: () => {
1989
- const next = s.srclang === "off" ? "off" : s.srclang;
1990
- setSubtitleMode(next);
1991
- setSubtitleStyle((st) => ({ ...st, track: next }));
1992
- },
1993
- className: `rounded-md px-2 py-1 text-xs font-medium transition ${subtitleStyle.track === s.srclang ? "bg-white text-black" : "bg-white/10 text-white hover:bg-white/20"}`,
1994
- children: s.label
1995
- },
1996
- s.srclang
1997
- )) })
1977
+ )) })
1978
+ ] }),
1979
+ (parsed.subtitles.length > 0 || audioTracks.length > 1) && /* @__PURE__ */ jsx("div", { className: `overflow-hidden rounded-2xl bg-[#1a1a1a]/95 shadow-2xl backdrop-blur-xl ring-1 ring-white/8 ${parsed.subtitles.length > 0 && audioTracks.length > 1 ? "w-80" : "w-52"}`, children: /* @__PURE__ */ jsxs("div", { className: `grid ${parsed.subtitles.length > 0 && audioTracks.length > 1 ? "grid-cols-2 divide-x divide-white/8" : "grid-cols-1"}`, children: [
1980
+ parsed.subtitles.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
1981
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 py-3 border-b border-white/8", children: [
1982
+ /* @__PURE__ */ jsx(Captions, { className: "size-4 text-white/60" }),
1983
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-white", children: "Subtitles" })
1998
1984
  ] }),
1999
- /* @__PURE__ */ jsxs("div", { children: [
2000
- /* @__PURE__ */ jsx("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wider text-white/40", children: "Size" }),
2001
- /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: ["small", "medium", "large"].map((s) => /* @__PURE__ */ jsx(
2002
- "button",
2003
- {
2004
- type: "button",
2005
- onClick: () => setSubtitleStyle((st) => ({ ...st, size: s })),
2006
- className: `rounded-md px-2 py-1 text-xs font-medium capitalize transition ${subtitleStyle.size === s ? "bg-white text-black" : "bg-white/10 text-white hover:bg-white/20"}`,
2007
- children: s
1985
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: [{ srclang: "off", label: "Off" }, ...parsed.subtitles].map((s) => /* @__PURE__ */ jsxs(
1986
+ "button",
1987
+ {
1988
+ type: "button",
1989
+ onClick: () => {
1990
+ const next = s.srclang === "off" ? "off" : s.srclang;
1991
+ setSubtitleMode(next);
1992
+ setSubtitleStyle((st) => ({ ...st, track: next }));
2008
1993
  },
2009
- s
2010
- )) })
1994
+ className: "flex w-full items-center gap-3 px-4 py-2 text-sm transition hover:bg-white/8",
1995
+ children: [
1996
+ /* @__PURE__ */ jsx("span", { className: `size-4 shrink-0 ${subtitleStyle.track === s.srclang ? "text-white" : "text-transparent"}`, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M3 8l3.5 3.5L13 4.5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
1997
+ /* @__PURE__ */ jsx("span", { className: subtitleStyle.track === s.srclang ? "font-semibold text-white" : "text-white/55", children: s.label })
1998
+ ]
1999
+ },
2000
+ s.srclang
2001
+ )) })
2002
+ ] }),
2003
+ audioTracks.length > 1 && /* @__PURE__ */ jsxs("div", { children: [
2004
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 py-3 border-b border-white/8", children: [
2005
+ /* @__PURE__ */ jsx(Volume2, { className: "size-4 text-white/60" }),
2006
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-white", children: "Audio" })
2011
2007
  ] }),
2012
- /* @__PURE__ */ jsxs("div", { children: [
2013
- /* @__PURE__ */ jsx("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wider text-white/40", children: "Color" }),
2014
- /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: [["white", "#fff"], ["yellow", "#facc15"], ["cyan", "#22d3ee"]].map(([c, hex]) => /* @__PURE__ */ jsx(
2015
- "button",
2016
- {
2017
- type: "button",
2018
- onClick: () => setSubtitleStyle((st) => ({ ...st, color: c })),
2019
- className: `size-5 rounded-full ring-2 transition ${subtitleStyle.color === c ? "ring-white" : "ring-transparent"}`,
2020
- style: { backgroundColor: hex }
2021
- },
2022
- c
2023
- )) })
2008
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: audioTracks.map((track) => /* @__PURE__ */ jsxs(
2009
+ "button",
2010
+ {
2011
+ type: "button",
2012
+ onClick: () => changeAudio(track.id),
2013
+ className: "flex w-full items-center gap-3 px-4 py-2 text-sm transition hover:bg-white/8",
2014
+ children: [
2015
+ /* @__PURE__ */ jsx("span", { className: `size-4 shrink-0 ${selectedAudio === track.id ? "text-white" : "text-transparent"}`, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M3 8l3.5 3.5L13 4.5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
2016
+ /* @__PURE__ */ jsx("span", { className: selectedAudio === track.id ? "font-semibold text-white" : "text-white/55", children: track.label })
2017
+ ]
2018
+ },
2019
+ track.id
2020
+ )) })
2021
+ ] })
2022
+ ] }) }),
2023
+ /* @__PURE__ */ jsxs("div", { className: "w-64 overflow-hidden rounded-2xl bg-[#1a1a1a]/95 shadow-2xl backdrop-blur-xl ring-1 ring-white/8", children: [
2024
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 py-3 border-b border-white/8", children: [
2025
+ /* @__PURE__ */ jsxs("svg", { className: "size-4 text-white/60", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2026
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "9" }),
2027
+ /* @__PURE__ */ jsx("path", { d: "M12 12l-2-4M12 12l3.5-1.5", strokeLinecap: "round" })
2024
2028
  ] }),
2025
- /* @__PURE__ */ jsxs("div", { children: [
2026
- /* @__PURE__ */ jsx("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wider text-white/40", children: "Background" }),
2027
- /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: [["none", "None"], ["semi", "Semi"], ["solid", "Solid"]].map(([v, label]) => /* @__PURE__ */ jsx(
2028
- "button",
2029
- {
2030
- type: "button",
2031
- onClick: () => setSubtitleStyle((st) => ({ ...st, bg: v })),
2032
- className: `rounded-md px-2 py-1 text-xs font-medium transition ${subtitleStyle.bg === v ? "bg-white text-black" : "bg-white/10 text-white hover:bg-white/20"}`,
2033
- children: label
2034
- },
2035
- v
2036
- )) })
2037
- ] })
2029
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-white", children: "Playback Speed" })
2038
2030
  ] }),
2039
- settingsTab === "audio" && audioTracks.length > 1 && /* @__PURE__ */ jsx(Fragment, { children: audioTracks.map((track) => /* @__PURE__ */ jsx(
2040
- SettingsItem,
2041
- {
2042
- active: selectedAudio === track.id,
2043
- onClick: () => changeAudio(track.id),
2044
- children: track.label
2045
- },
2046
- track.id
2047
- )) }),
2048
- settingsTab === "playback" && /* @__PURE__ */ jsx(Fragment, { children: PLAYBACK_SPEEDS.map((speed) => /* @__PURE__ */ jsx(
2049
- SettingsItem,
2050
- {
2051
- active: playbackRate === speed,
2052
- onClick: () => {
2053
- setPlaybackRate(speed);
2054
- setSettingsOpen(false);
2055
- },
2056
- children: speed === 1 ? "Normal" : `${speed}x`
2057
- },
2058
- speed
2059
- )) })
2031
+ /* @__PURE__ */ jsxs("div", { className: "px-4 pb-4 pt-3", children: [
2032
+ /* @__PURE__ */ jsx(
2033
+ "input",
2034
+ {
2035
+ type: "range",
2036
+ min: 0,
2037
+ max: PLAYBACK_SPEEDS.length - 1,
2038
+ step: 1,
2039
+ value: PLAYBACK_SPEEDS.indexOf(playbackRate) === -1 ? PLAYBACK_SPEEDS.indexOf(1) : PLAYBACK_SPEEDS.indexOf(playbackRate),
2040
+ onChange: (e) => setPlaybackRate(PLAYBACK_SPEEDS[Number(e.target.value)] ?? 1),
2041
+ className: "w-full accent-white"
2042
+ }
2043
+ ),
2044
+ /* @__PURE__ */ jsx("div", { className: "mt-1.5 flex justify-between", children: PLAYBACK_SPEEDS.map((s) => /* @__PURE__ */ jsx("span", { className: `text-[10px] font-medium ${playbackRate === s ? "text-white font-bold" : "text-white/40"}`, children: s === 1 ? "1x" : `${s}x` }, s)) })
2045
+ ] })
2060
2046
  ] })
2061
- ] })
2047
+ ] }),
2048
+ /* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
2062
2049
  ] }),
2063
2050
  /* @__PURE__ */ jsxs(
2064
2051
  "div",
@@ -2067,12 +2054,12 @@ function Video({
2067
2054
  onPointerMove: handleProgressPointerMove,
2068
2055
  onPointerLeave: handleProgressPointerLeave,
2069
2056
  onPointerDown: handleProgressPointerDown,
2070
- className: "relative mb-3 h-5 cursor-pointer @sm:mb-4 @lg:mb-6",
2057
+ className: "group relative mb-2 h-5 cursor-pointer",
2071
2058
  children: [
2072
2059
  preview && /* @__PURE__ */ jsxs(
2073
2060
  "div",
2074
2061
  {
2075
- className: "pointer-events-none absolute bottom-8 z-20 -translate-x-1/2 rounded-lg bg-black/80 p-1 shadow-2xl ring-1 ring-white/15 backdrop-blur",
2062
+ className: "pointer-events-none absolute bottom-8 z-50 -translate-x-1/2 rounded-lg bg-black/80 p-1 shadow-2xl ring-1 ring-white/15 backdrop-blur",
2076
2063
  style: { left: preview.left },
2077
2064
  children: [
2078
2065
  /* @__PURE__ */ jsx(
@@ -2093,7 +2080,7 @@ function Video({
2093
2080
  ]
2094
2081
  }
2095
2082
  ),
2096
- /* @__PURE__ */ jsxs("div", { className: "absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 overflow-hidden rounded-full bg-white/22 @sm:h-1.25", children: [
2083
+ /* @__PURE__ */ jsxs("div", { className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/22 transition-[height] duration-150 group-hover:h-1", style: { height: "2px" }, children: [
2097
2084
  /* @__PURE__ */ jsx(
2098
2085
  "div",
2099
2086
  {
@@ -2112,42 +2099,27 @@ function Video({
2112
2099
  ]
2113
2100
  }
2114
2101
  ),
2115
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 @sm:gap-4 @lg:gap-5", children: [
2116
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 @sm:gap-4 @lg:gap-5", children: [
2117
- /* @__PURE__ */ jsx(
2118
- "button",
2119
- {
2120
- type: "button",
2121
- onClick: () => seekRelative(-10),
2122
- className: "grid size-6 place-items-center text-white transition hover:scale-105 hover:text-white/80 @sm:size-8",
2123
- "aria-label": "Rewind 10 seconds",
2124
- children: /* @__PURE__ */ jsx(Rewind, { className: "size-4 @sm:size-6" })
2125
- }
2126
- ),
2102
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
2103
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 @sm:gap-2", children: [
2104
+ /* @__PURE__ */ jsx(SeekButton, { seconds: 15, direction: "back", onClick: () => seekRelative(-15) }),
2127
2105
  /* @__PURE__ */ jsx(
2128
2106
  "button",
2129
2107
  {
2130
2108
  type: "button",
2131
2109
  onClick: togglePlay,
2132
- className: "grid size-6 place-items-center text-white transition hover:scale-105 hover:text-white/80 @sm:size-8",
2110
+ className: "grid size-8 place-items-center text-white transition hover:scale-110 hover:text-white/80 @sm:size-10",
2133
2111
  "aria-label": isPlaying ? "Pause" : "Play",
2134
- children: isPlaying ? /* @__PURE__ */ jsx(Pause, { className: "size-4 @sm:size-6" }) : /* @__PURE__ */ jsx(Play, { className: "size-4 @sm:size-6" })
2112
+ children: isPlaying ? /* @__PURE__ */ jsx(Pause, { className: "size-5 @sm:size-6" }) : /* @__PURE__ */ jsx(Play, { className: "ml-0.5 size-5 @sm:size-6" })
2135
2113
  }
2136
2114
  ),
2137
- /* @__PURE__ */ jsx(
2138
- "button",
2139
- {
2140
- type: "button",
2141
- onClick: () => seekRelative(10),
2142
- className: "grid size-6 place-items-center text-white transition hover:scale-105 hover:text-white/80 @sm:size-8",
2143
- "aria-label": "Forward 10 seconds",
2144
- children: /* @__PURE__ */ jsx(FastForward, { className: "size-4 @sm:size-6" })
2145
- }
2146
- ),
2147
- /* @__PURE__ */ jsxs("div", { className: "hidden items-center gap-1 text-xs font-semibold text-white/75 @sm:flex @sm:gap-2 @sm:text-sm", children: [
2115
+ /* @__PURE__ */ jsx(SeekButton, { seconds: 15, direction: "forward", onClick: () => seekRelative(15) }),
2116
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs font-semibold text-white/75 @sm:text-sm", children: [
2148
2117
  /* @__PURE__ */ jsx("span", { children: formatTime(currentTime) }),
2149
2118
  /* @__PURE__ */ jsx("span", { className: "text-white/35", children: "/" }),
2150
- /* @__PURE__ */ jsx("span", { children: formatTime(duration) })
2119
+ /* @__PURE__ */ jsxs("span", { className: "text-white/50", children: [
2120
+ "-",
2121
+ formatTime(Math.max(0, duration - currentTime))
2122
+ ] })
2151
2123
  ] })
2152
2124
  ] }),
2153
2125
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
@@ -2156,9 +2128,9 @@ function Video({
2156
2128
  {
2157
2129
  type: "button",
2158
2130
  onClick: () => setIsMuted((value) => !value),
2159
- className: "grid size-6 place-items-center text-white transition hover:scale-105 hover:text-white/80 @sm:size-8",
2131
+ className: "grid size-8 place-items-center text-white transition hover:scale-110 hover:text-white/80 @sm:size-10",
2160
2132
  "aria-label": isMuted ? "Unmute" : "Mute",
2161
- children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-6" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-6" })
2133
+ children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
2162
2134
  }
2163
2135
  ),
2164
2136
  /* @__PURE__ */ jsx(
@@ -2184,22 +2156,22 @@ function Video({
2184
2156
  {
2185
2157
  type: "button",
2186
2158
  onClick: () => setSubtitleMode((m) => m === "off" ? parsed.subtitles[0]?.srclang ?? "off" : "off"),
2187
- className: `grid size-6 place-items-center rounded transition hover:text-white/80 @sm:size-8 ${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
2159
+ className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
2188
2160
  "aria-label": "Captions",
2189
2161
  children: /* @__PURE__ */ jsx(Captions, { className: "size-4 @sm:size-5" })
2190
2162
  }
2191
2163
  ),
2192
- /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
2164
+ /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
2193
2165
  "button",
2194
2166
  {
2195
2167
  type: "button",
2196
- onClick: () => setSettingsOpen((v) => !v),
2197
- className: `flex h-6 items-center gap-1 rounded px-1.5 text-xs font-semibold transition hover:text-white/80 @sm:h-8 @sm:px-2 ${settingsOpen ? "text-white" : "text-white/60"}`,
2168
+ onClick: () => {
2169
+ setSettingsOpen((v) => !v);
2170
+ setSettingsTab("root");
2171
+ },
2172
+ className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${settingsOpen ? "text-white" : "text-white/60"}`,
2198
2173
  "aria-label": "Settings",
2199
- children: [
2200
- /* @__PURE__ */ jsx(Settings, { className: "size-3.5 @sm:size-4" }),
2201
- /* @__PURE__ */ jsx("span", { className: "hidden @sm:inline", children: qualities.find((q) => q.id === selectedQuality)?.label ?? "Auto" })
2202
- ]
2174
+ children: /* @__PURE__ */ jsx(Settings, { className: "size-4 @sm:size-5" })
2203
2175
  }
2204
2176
  ) }),
2205
2177
  /* @__PURE__ */ jsx(
@@ -2207,9 +2179,9 @@ function Video({
2207
2179
  {
2208
2180
  type: "button",
2209
2181
  onClick: toggleFullscreen,
2210
- className: "grid size-6 place-items-center text-white/60 transition hover:scale-105 hover:text-white/80 @sm:size-8",
2182
+ className: "grid size-8 place-items-center text-white/60 transition hover:scale-110 hover:text-white/80 @sm:size-10",
2211
2183
  "aria-label": isFullscreen ? "Exit fullscreen" : "Fullscreen",
2212
- children: isFullscreen ? /* @__PURE__ */ jsx(Minimize, { className: "size-5 @sm:size-7" }) : /* @__PURE__ */ jsx(Maximize, { className: "size-5 @sm:size-7" })
2184
+ children: isFullscreen ? /* @__PURE__ */ jsx(Minimize, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Maximize, { className: "size-4 @sm:size-5" })
2213
2185
  }
2214
2186
  )
2215
2187
  ] })
@@ -2229,17 +2201,23 @@ function Video({
2229
2201
  activeCue && /* @__PURE__ */ jsx(
2230
2202
  "div",
2231
2203
  {
2232
- 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"}`,
2204
+ className: `pointer-events-none absolute inset-x-0 z-35 flex justify-center px-4 transition-all duration-200 ${controlsVisible ? "bottom-20 @sm:bottom-24 @lg:bottom-28" : "bottom-4 @sm:bottom-6"}`,
2233
2205
  children: /* @__PURE__ */ jsx(
2234
2206
  "div",
2235
2207
  {
2236
- className: "max-w-3xl rounded-lg px-4 py-2 text-center font-medium leading-snug",
2208
+ className: "max-w-[80%] rounded-lg px-4 py-1.5 text-center font-medium leading-snug",
2237
2209
  style: {
2238
- fontSize: subtitleStyle.size === "small" ? "0.8rem" : subtitleStyle.size === "large" ? "1.25rem" : "1rem",
2210
+ fontSize: (() => {
2211
+ const base = Math.max(12, Math.min(playerHeight * 0.028, 32));
2212
+ if (subtitleStyle.size === "small") return `${base * 0.75}px`;
2213
+ if (subtitleStyle.size === "large") return `${base * 1.35}px`;
2214
+ if (subtitleStyle.size === "xlarge") return `${base * 1.8}px`;
2215
+ return `${base}px`;
2216
+ })(),
2239
2217
  color: subtitleStyle.color === "yellow" ? "#facc15" : subtitleStyle.color === "cyan" ? "#22d3ee" : "#ffffff",
2240
- backgroundColor: subtitleStyle.bg === "none" ? "transparent" : subtitleStyle.bg === "solid" ? "rgba(0,0,0,0.9)" : "rgba(0,0,0,0.7)",
2241
- backdropFilter: subtitleStyle.bg === "semi" ? "blur(4px)" : void 0,
2242
- textShadow: subtitleStyle.bg === "none" ? "0 1px 6px rgba(0,0,0,1), 0 0 12px rgba(0,0,0,0.8)" : "0 1px 3px rgba(0,0,0,0.6)"
2218
+ backgroundColor: subtitleStyle.bg === "none" ? "transparent" : subtitleStyle.bg === "solid" ? "rgba(0,0,0,0.9)" : "rgba(0,0,0,0.55)",
2219
+ backdropFilter: subtitleStyle.bg === "semi" ? "blur(6px)" : void 0,
2220
+ 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)"
2243
2221
  },
2244
2222
  children: activeCue
2245
2223
  }
@@ -2253,21 +2231,36 @@ function Video({
2253
2231
  );
2254
2232
  }
2255
2233
  var VideoPlayer = Video;
2256
- function SettingsItem({
2257
- children,
2258
- active,
2259
- onClick
2260
- }) {
2261
- return /* @__PURE__ */ jsxs(
2234
+ function SeekButton({ seconds, direction, onClick }) {
2235
+ return /* @__PURE__ */ jsx(
2262
2236
  "button",
2263
2237
  {
2264
2238
  type: "button",
2265
2239
  onClick,
2266
- className: `flex w-full items-center gap-2 px-4 py-2.5 text-left text-base font-medium transition hover:bg-white/10 ${active ? "text-white" : "text-white/55"}`,
2267
- children: [
2268
- /* @__PURE__ */ jsx("span", { className: `size-1.5 rounded-full ${active ? "bg-white" : "bg-transparent"}` }),
2269
- children
2270
- ]
2240
+ className: "grid size-8 place-items-center text-white transition hover:scale-110 hover:text-white/80 @sm:size-10",
2241
+ "aria-label": `${direction === "back" ? "Rewind" : "Forward"} ${seconds} seconds`,
2242
+ children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 36 36", fill: "none", className: "size-7 @sm:size-8", children: [
2243
+ /* @__PURE__ */ jsx(
2244
+ "path",
2245
+ {
2246
+ d: direction === "back" ? "M18 6C11.373 6 6 11.373 6 18s5.373 12 12 12 12-5.373 12-12" : "M18 6C24.627 6 30 11.373 30 18S24.627 30 18 30 6 24.627 6 18",
2247
+ stroke: "currentColor",
2248
+ strokeWidth: "2",
2249
+ strokeLinecap: "round"
2250
+ }
2251
+ ),
2252
+ /* @__PURE__ */ jsx(
2253
+ "path",
2254
+ {
2255
+ d: direction === "back" ? "M18 6l-4 4 4 4" : "M18 6l4 4-4 4",
2256
+ stroke: "currentColor",
2257
+ strokeWidth: "2",
2258
+ strokeLinecap: "round",
2259
+ strokeLinejoin: "round"
2260
+ }
2261
+ ),
2262
+ /* @__PURE__ */ jsx("text", { x: "18", y: "22", textAnchor: "middle", fill: "currentColor", fontSize: "9", fontWeight: "600", fontFamily: "system-ui", children: seconds })
2263
+ ] })
2271
2264
  }
2272
2265
  );
2273
2266
  }