@geekapps/silo-elements-nextjs 0.2.31 → 0.2.33

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, Pause, VolumeX, Volume2, Captions, Settings, Minimize, Maximize } from 'lucide-react';
6
+ import { Pause, Play, VolumeX, Volume2, Captions, Settings, Minimize, Maximize } from 'lucide-react';
7
7
 
8
8
  // src/ImageUploader.tsx
9
9
 
@@ -1278,6 +1278,8 @@ function Video({
1278
1278
  const [duration, setDuration] = useState(0);
1279
1279
  const [currentTime, setCurrentTime] = useState(0);
1280
1280
  const [bufferedTime, setBufferedTime] = useState(0);
1281
+ const [isDragging, setIsDragging] = useState(false);
1282
+ const dragPointerIdRef = useRef(null);
1281
1283
  const [isPlaying, setIsPlaying] = useState(false);
1282
1284
  const [hasPlayed, setHasPlayed] = useState(false);
1283
1285
  const [clickIcon, setClickIcon] = useState(null);
@@ -1801,44 +1803,69 @@ function Video({
1801
1803
  },
1802
1804
  [qualities]
1803
1805
  );
1804
- const handleProgressPointerMove = useCallback(
1805
- (event) => {
1806
+ const seekFromPointer = useCallback(
1807
+ (clientX) => {
1808
+ const video = videoRef.current;
1809
+ const progress = progressRef.current;
1810
+ if (!video || !progress || !duration) return;
1811
+ const rect = progress.getBoundingClientRect();
1812
+ const x = Math.max(0, Math.min(clientX - rect.left, rect.width));
1813
+ const nextTime = x / rect.width * duration;
1814
+ video.currentTime = nextTime;
1815
+ setCurrentTime(nextTime);
1816
+ },
1817
+ [duration]
1818
+ );
1819
+ const updatePreview = useCallback(
1820
+ (clientX) => {
1806
1821
  const progress = progressRef.current;
1807
1822
  if (!progress || !duration || storyboardCues.length === 0) {
1808
1823
  setPreview(null);
1809
1824
  return;
1810
1825
  }
1811
1826
  const rect = progress.getBoundingClientRect();
1812
- const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
1827
+ const x = Math.max(0, Math.min(clientX - rect.left, rect.width));
1813
1828
  const time = x / rect.width * duration;
1814
1829
  const cue = findStoryboardCue(storyboardCues, time);
1815
1830
  if (!cue) {
1816
1831
  setPreview(null);
1817
1832
  return;
1818
1833
  }
1819
- setPreview({
1820
- cue,
1821
- time,
1822
- left: Math.max(80, Math.min(x, rect.width - 80))
1823
- });
1834
+ setPreview({ cue, time, left: Math.max(80, Math.min(x, rect.width - 80)) });
1824
1835
  },
1825
1836
  [duration, storyboardCues]
1826
1837
  );
1838
+ const handleProgressPointerMove = useCallback(
1839
+ (event) => {
1840
+ updatePreview(event.clientX);
1841
+ if (isDragging) seekFromPointer(event.clientX);
1842
+ },
1843
+ [isDragging, seekFromPointer, updatePreview]
1844
+ );
1827
1845
  const handleProgressPointerLeave = useCallback(() => {
1828
- setPreview(null);
1829
- }, []);
1846
+ if (!isDragging) setPreview(null);
1847
+ }, [isDragging]);
1830
1848
  const handleProgressPointerDown = useCallback(
1831
1849
  (event) => {
1832
- const video = videoRef.current;
1833
1850
  const progress = progressRef.current;
1834
- if (!video || !progress || !duration) return;
1835
- const rect = progress.getBoundingClientRect();
1836
- const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
1837
- const nextTime = x / rect.width * duration;
1838
- video.currentTime = nextTime;
1839
- setCurrentTime(nextTime);
1851
+ if (!progress) return;
1852
+ progress.setPointerCapture(event.pointerId);
1853
+ dragPointerIdRef.current = event.pointerId;
1854
+ setIsDragging(true);
1855
+ seekFromPointer(event.clientX);
1856
+ updatePreview(event.clientX);
1840
1857
  },
1841
- [duration]
1858
+ [seekFromPointer, updatePreview]
1859
+ );
1860
+ const handleProgressPointerUp = useCallback(
1861
+ (event) => {
1862
+ if (dragPointerIdRef.current === event.pointerId) {
1863
+ setIsDragging(false);
1864
+ dragPointerIdRef.current = null;
1865
+ setPreview(null);
1866
+ }
1867
+ },
1868
+ []
1842
1869
  );
1843
1870
  const handleKeyDown = useCallback(
1844
1871
  (event) => {
@@ -1936,8 +1963,9 @@ function Video({
1936
1963
  /* @__PURE__ */ jsx(
1937
1964
  "div",
1938
1965
  {
1939
- className: `pointer-events-none absolute inset-0 z-10 grid place-items-center transition ${isPlaying ? "opacity-0" : "opacity-100"}`,
1940
- children: /* @__PURE__ */ jsx("span", { className: "grid size-10 place-items-center rounded-full bg-white/15 text-white backdrop-blur-xl ring-1 ring-white/20 @sm:size-14 @lg:size-16", children: /* @__PURE__ */ jsx(Play, { className: "ml-0.5 size-4 @sm:size-6 @lg:size-7" }) })
1966
+ className: "pointer-events-none absolute inset-0 z-10 grid place-items-center",
1967
+ style: { opacity: clickIcon ? 1 : 0, transition: clickIcon ? "opacity 0.08s ease-in" : "opacity 0.45s ease-out" },
1968
+ 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-5 @sm:size-7 @lg:size-8" }) : /* @__PURE__ */ jsx(Play, { className: "ml-0.5 size-5 @sm:size-7 @lg:size-8" }) })
1941
1969
  }
1942
1970
  ),
1943
1971
  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" }) }),
@@ -1957,8 +1985,8 @@ function Video({
1957
1985
  ] }) }),
1958
1986
  /* @__PURE__ */ jsxs("footer", { onClick: (e) => e.stopPropagation(), className: "relative z-10 px-4 pb-4 text-white", children: [
1959
1987
  settingsOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
1960
- /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-40", onClick: () => setSettingsOpen(false) }),
1961
- /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full right-0 z-50 mb-2 w-56 overflow-hidden rounded-2xl bg-[#1c1c1e]/95 shadow-2xl backdrop-blur-xl ring-1 ring-white/10", style: { animation: "spFadeIn 0.15s ease" }, children: [
1988
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-70", onClick: () => setSettingsOpen(false) }),
1989
+ /* @__PURE__ */ jsxs("div", { 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", style: { width: Math.min(224, Math.max(180, (playerWidth || 640) * 0.22)) + "px", animation: "spFadeIn 0.15s ease" }, children: [
1962
1990
  settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
1963
1991
  { id: "quality", label: "Qualidade", value: qualities.find((q) => q.id === selectedQuality)?.label ?? "Auto" },
1964
1992
  ...parsed.subtitles.length > 0 ? [{ id: "subtitles", label: "Legendas", value: subtitleStyle.track === "off" ? "Desligado" : parsed.subtitles.find((s) => s.srclang === subtitleStyle.track)?.label ?? subtitleStyle.track }] : [],
@@ -2034,7 +2062,6 @@ function Video({
2034
2062
  const next = s.srclang === "off" ? "off" : s.srclang;
2035
2063
  setSubtitleMode(next);
2036
2064
  setSubtitleStyle((st) => ({ ...st, track: next }));
2037
- setSettingsTab("root");
2038
2065
  },
2039
2066
  className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2040
2067
  children: [
@@ -2043,7 +2070,75 @@ function Video({
2043
2070
  ]
2044
2071
  },
2045
2072
  s.srclang
2046
- )) })
2073
+ )) }),
2074
+ subtitleStyle.track !== "off" && /* @__PURE__ */ jsxs(
2075
+ "button",
2076
+ {
2077
+ type: "button",
2078
+ onClick: () => setSettingsTab("subtitles-style"),
2079
+ 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",
2080
+ children: [
2081
+ /* @__PURE__ */ jsx("span", { className: "text-white/60", children: "Apar\xEAncia" }),
2082
+ /* @__PURE__ */ jsx("svg", { className: "size-3 opacity-50", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M4.5 3l3 3-3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
2083
+ ]
2084
+ }
2085
+ )
2086
+ ] }),
2087
+ settingsTab === "subtitles-style" && /* @__PURE__ */ jsxs("div", { children: [
2088
+ /* @__PURE__ */ jsxs(
2089
+ "button",
2090
+ {
2091
+ type: "button",
2092
+ onClick: () => setSettingsTab("subtitles"),
2093
+ 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",
2094
+ children: [
2095
+ /* @__PURE__ */ jsx("svg", { className: "size-3.5", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M7.5 3L4.5 6l3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2096
+ "Apar\xEAncia"
2097
+ ]
2098
+ }
2099
+ ),
2100
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 flex flex-col gap-3", children: [
2101
+ /* @__PURE__ */ jsxs("div", { children: [
2102
+ /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Tamanho" }),
2103
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: ["small", "medium", "large", "xlarge"].map((s) => /* @__PURE__ */ jsx(
2104
+ "button",
2105
+ {
2106
+ type: "button",
2107
+ onClick: () => setSubtitleStyle((st) => ({ ...st, size: s })),
2108
+ 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"}`,
2109
+ children: s === "small" ? "P" : s === "medium" ? "M" : s === "large" ? "G" : "GG"
2110
+ },
2111
+ s
2112
+ )) })
2113
+ ] }),
2114
+ /* @__PURE__ */ jsxs("div", { children: [
2115
+ /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Cor" }),
2116
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: [["white", "Branco", "#fff"], ["yellow", "Amarelo", "#facc15"], ["cyan", "Ciano", "#22d3ee"]].map(([val, label, color]) => /* @__PURE__ */ jsx(
2117
+ "button",
2118
+ {
2119
+ type: "button",
2120
+ onClick: () => setSubtitleStyle((st) => ({ ...st, color: val })),
2121
+ 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"}`,
2122
+ style: { color },
2123
+ children: label
2124
+ },
2125
+ val
2126
+ )) })
2127
+ ] }),
2128
+ /* @__PURE__ */ jsxs("div", { children: [
2129
+ /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold text-white/40 uppercase tracking-wide", children: "Fundo" }),
2130
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: [["none", "Nenhum"], ["semi", "Semi"], ["solid", "S\xF3lido"]].map(([val, label]) => /* @__PURE__ */ jsx(
2131
+ "button",
2132
+ {
2133
+ type: "button",
2134
+ onClick: () => setSubtitleStyle((st) => ({ ...st, bg: val })),
2135
+ 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"}`,
2136
+ children: label
2137
+ },
2138
+ val
2139
+ )) })
2140
+ ] })
2141
+ ] })
2047
2142
  ] }),
2048
2143
  settingsTab === "audio" && /* @__PURE__ */ jsxs("div", { children: [
2049
2144
  /* @__PURE__ */ jsxs(
@@ -2109,84 +2204,90 @@ function Video({
2109
2204
  ] }),
2110
2205
  /* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
2111
2206
  ] }),
2112
- /* @__PURE__ */ jsx(
2207
+ /* @__PURE__ */ jsxs(
2113
2208
  "div",
2114
2209
  {
2115
2210
  ref: progressRef,
2116
2211
  onPointerMove: handleProgressPointerMove,
2117
2212
  onPointerLeave: handleProgressPointerLeave,
2118
2213
  onPointerDown: handleProgressPointerDown,
2119
- className: "group relative mb-2 h-5 cursor-pointer",
2120
- children: /* @__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: [
2121
- /* @__PURE__ */ jsx(
2214
+ onPointerUp: handleProgressPointerUp,
2215
+ className: "group relative mb-3 h-7 cursor-pointer",
2216
+ children: [
2217
+ /* @__PURE__ */ jsxs(
2122
2218
  "div",
2123
2219
  {
2124
- className: "absolute inset-y-0 left-0 bg-white/30",
2125
- style: { width: `${bufferedPercent}%` }
2220
+ className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/22 transition-[height] duration-150",
2221
+ style: { height: isDragging ? "6px" : "3px" },
2222
+ children: [
2223
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 rounded-full bg-white/30", style: { width: `${bufferedPercent}%` } }),
2224
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 rounded-full bg-white/90", style: { width: `${progressPercent}%` } })
2225
+ ]
2126
2226
  }
2127
2227
  ),
2128
2228
  /* @__PURE__ */ jsx(
2129
2229
  "div",
2130
2230
  {
2131
- className: "absolute inset-y-0 left-0 bg-white/85",
2132
- style: { width: `${progressPercent}%` }
2231
+ className: "pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow-md transition-[width,height] duration-100 group-hover:size-4",
2232
+ style: {
2233
+ left: `${progressPercent}%`,
2234
+ width: isDragging ? "16px" : "10px",
2235
+ height: isDragging ? "16px" : "10px"
2236
+ }
2133
2237
  }
2134
2238
  )
2135
- ] })
2239
+ ]
2136
2240
  }
2137
2241
  ),
2138
2242
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
2139
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 @sm:gap-2", children: [
2140
- /* @__PURE__ */ jsx(SeekButton, { seconds: 15, direction: "back", onClick: () => seekRelative(-15) }),
2243
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 @sm:gap-2", children: [
2141
2244
  /* @__PURE__ */ jsx(
2142
2245
  "button",
2143
2246
  {
2144
2247
  type: "button",
2145
2248
  onClick: togglePlay,
2146
- className: "grid size-8 place-items-center text-white transition hover:scale-110 hover:text-white/80 @sm:size-10",
2249
+ className: "grid size-8 place-items-center rounded-full bg-white/15 text-white backdrop-blur-sm ring-1 ring-white/15 transition hover:bg-white/25 @sm:size-9",
2147
2250
  "aria-label": isPlaying ? "Pause" : "Play",
2148
- children: isPlaying ? /* @__PURE__ */ jsx(Pause, { className: "size-5 @sm:size-6" }) : /* @__PURE__ */ jsx(Play, { className: "ml-0.5 size-5 @sm:size-6" })
2251
+ children: isPlaying ? /* @__PURE__ */ jsx(Pause, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Play, { className: "ml-0.5 size-4 @sm:size-5" })
2149
2252
  }
2150
2253
  ),
2151
- /* @__PURE__ */ jsx(SeekButton, { seconds: 15, direction: "forward", onClick: () => seekRelative(15) }),
2152
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs font-semibold text-white/75 @sm:text-sm", children: [
2153
- /* @__PURE__ */ jsx("span", { children: formatTime(currentTime) }),
2154
- /* @__PURE__ */ jsx("span", { className: "text-white/35", children: "/" }),
2155
- /* @__PURE__ */ jsxs("span", { className: "text-white/50", children: [
2156
- "-",
2157
- formatTime(Math.max(0, duration - currentTime))
2158
- ] })
2254
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-medium tabular-nums text-white/80", children: [
2255
+ formatTime(currentTime),
2256
+ /* @__PURE__ */ jsx("span", { className: "text-white/30", children: "/" }),
2257
+ /* @__PURE__ */ jsx("span", { className: "text-white/45", children: formatTime(duration) })
2159
2258
  ] })
2160
2259
  ] }),
2161
2260
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
2162
- /* @__PURE__ */ jsx(
2163
- "button",
2164
- {
2165
- type: "button",
2166
- onClick: () => setIsMuted((value) => !value),
2167
- className: "grid size-8 place-items-center text-white transition hover:scale-110 hover:text-white/80 @sm:size-10",
2168
- "aria-label": isMuted ? "Unmute" : "Mute",
2169
- children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
2170
- }
2171
- ),
2172
- /* @__PURE__ */ jsx(
2173
- "input",
2174
- {
2175
- type: "range",
2176
- min: "0",
2177
- max: "1",
2178
- step: "0.01",
2179
- value: isMuted ? 0 : volume,
2180
- onChange: (event) => {
2181
- const nextVolume = Number(event.target.value);
2182
- setVolume(nextVolume);
2183
- setIsMuted(nextVolume === 0);
2184
- },
2185
- className: "hidden h-1 w-14 accent-white @md:block @md:w-20",
2186
- "aria-label": "Audio level"
2187
- }
2188
- ),
2189
- /* @__PURE__ */ jsx("div", { className: "mx-0.5 hidden h-4 w-px bg-white/20 @md:mx-1 @md:block" }),
2261
+ /* @__PURE__ */ jsxs("div", { className: "group flex items-center", children: [
2262
+ /* @__PURE__ */ jsx(
2263
+ "button",
2264
+ {
2265
+ type: "button",
2266
+ onClick: () => setIsMuted((value) => !value),
2267
+ className: "grid size-8 place-items-center text-white/70 transition hover:text-white @sm:size-9",
2268
+ "aria-label": isMuted ? "Unmute" : "Mute",
2269
+ children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
2270
+ }
2271
+ ),
2272
+ /* @__PURE__ */ jsx("div", { className: "w-0 overflow-hidden transition-all duration-200 group-hover:w-16 @md:group-hover:w-20", children: /* @__PURE__ */ jsx(
2273
+ "input",
2274
+ {
2275
+ type: "range",
2276
+ min: "0",
2277
+ max: "1",
2278
+ step: "0.01",
2279
+ value: isMuted ? 0 : volume,
2280
+ onChange: (event) => {
2281
+ const nextVolume = Number(event.target.value);
2282
+ setVolume(nextVolume);
2283
+ setIsMuted(nextVolume === 0);
2284
+ },
2285
+ className: "h-1 w-14 accent-white @md:w-20",
2286
+ "aria-label": "Audio level"
2287
+ }
2288
+ ) })
2289
+ ] }),
2290
+ /* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
2190
2291
  parsed.subtitles.length > 0 && /* @__PURE__ */ jsx(
2191
2292
  "button",
2192
2293
  {
@@ -2226,51 +2327,35 @@ function Video({
2226
2327
  ]
2227
2328
  }
2228
2329
  ),
2229
- /* @__PURE__ */ jsx(
2230
- "div",
2231
- {
2232
- className: "pointer-events-none absolute inset-0 z-50 grid place-items-center",
2233
- style: { opacity: clickIcon ? 1 : 0, transition: clickIcon ? "opacity 0.08s ease-in" : "opacity 0.45s ease-out" },
2234
- children: /* @__PURE__ */ jsx("span", { className: "grid size-10 place-items-center rounded-full bg-black/40 text-white backdrop-blur-sm ring-1 ring-white/20 @sm:size-14 @lg:size-16", children: clickIcon === "pause" ? /* @__PURE__ */ jsx(Pause, { className: "size-4 @sm:size-6 @lg:size-7" }) : /* @__PURE__ */ jsx(Play, { className: "ml-0.5 size-4 @sm:size-6 @lg:size-7" }) })
2235
- }
2236
- ),
2237
2330
  preview && (() => {
2238
2331
  const srcW = preview.cue.w ?? 160;
2239
2332
  const srcH = preview.cue.h ?? 90;
2240
- const thumbW = Math.max(120, Math.round((playerWidth || 640) * 0.1));
2333
+ const thumbW = Math.max(140, Math.round((playerWidth || 640) * 0.13));
2241
2334
  const thumbH = Math.round(thumbW * (srcH / srcW));
2242
2335
  const scale = thumbW / srcW;
2243
2336
  const isSprite = preview.cue.x != null && preview.cue.y != null;
2244
- return /* @__PURE__ */ jsxs(
2337
+ return /* @__PURE__ */ jsx(
2245
2338
  "div",
2246
2339
  {
2247
- className: "pointer-events-none absolute z-50 -translate-x-1/2 rounded-xl bg-black/75 p-1 shadow-2xl ring-1 ring-white/15 backdrop-blur-sm",
2248
- style: { bottom: controlsVisible ? "72px" : "16px", left: preview.left, transition: "bottom 0.2s" },
2249
- children: [
2250
- /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-lg", style: { width: thumbW, height: thumbH }, children: isSprite ? (
2251
- // Inner div at native tile size, positioned to show the right sprite cell,
2252
- // then scaled up to fill thumbW×thumbH. transformOrigin top-left ensures
2253
- // the clip window aligns correctly.
2254
- /* @__PURE__ */ jsx("div", { style: {
2255
- width: srcW,
2256
- height: srcH,
2257
- backgroundImage: `url(${preview.cue.image})`,
2258
- backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
2259
- backgroundSize: "auto",
2260
- backgroundRepeat: "no-repeat",
2261
- transform: `scale(${scale})`,
2262
- transformOrigin: "top left"
2263
- } })
2264
- ) : /* @__PURE__ */ jsx("div", { style: {
2265
- width: thumbW,
2266
- height: thumbH,
2267
- backgroundImage: `url(${preview.cue.image})`,
2268
- backgroundSize: "cover",
2269
- backgroundPosition: "center",
2270
- backgroundRepeat: "no-repeat"
2271
- } }) }),
2272
- /* @__PURE__ */ jsx("div", { className: "pt-1 text-center text-[11px] font-semibold text-white/75", children: formatTime(preview.time) })
2273
- ]
2340
+ className: "pointer-events-none absolute z-60 -translate-x-1/2 -translate-y-2 overflow-hidden rounded-xl shadow-2xl ring-1 ring-white/15",
2341
+ style: { bottom: controlsVisible ? "80px" : "20px", left: preview.left, transition: "bottom 0.2s" },
2342
+ children: isSprite ? /* @__PURE__ */ jsx("div", { style: { width: thumbW, height: thumbH, overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: {
2343
+ width: srcW,
2344
+ height: srcH,
2345
+ backgroundImage: `url(${preview.cue.image})`,
2346
+ backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
2347
+ backgroundSize: "auto",
2348
+ backgroundRepeat: "no-repeat",
2349
+ transform: `scale(${scale})`,
2350
+ transformOrigin: "top left"
2351
+ } }) }) : /* @__PURE__ */ jsx("div", { style: {
2352
+ width: thumbW,
2353
+ height: thumbH,
2354
+ backgroundImage: `url(${preview.cue.image})`,
2355
+ backgroundSize: "cover",
2356
+ backgroundPosition: "center",
2357
+ backgroundRepeat: "no-repeat"
2358
+ } })
2274
2359
  }
2275
2360
  );
2276
2361
  })(),
@@ -2307,39 +2392,6 @@ function Video({
2307
2392
  );
2308
2393
  }
2309
2394
  var VideoPlayer = Video;
2310
- function SeekButton({ seconds, direction, onClick }) {
2311
- return /* @__PURE__ */ jsx(
2312
- "button",
2313
- {
2314
- type: "button",
2315
- onClick,
2316
- className: "grid size-8 place-items-center text-white transition hover:scale-110 hover:text-white/80 @sm:size-10",
2317
- "aria-label": `${direction === "back" ? "Rewind" : "Forward"} ${seconds} seconds`,
2318
- children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 36 36", fill: "none", className: "size-7 @sm:size-8", children: [
2319
- /* @__PURE__ */ jsx(
2320
- "path",
2321
- {
2322
- 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",
2323
- stroke: "currentColor",
2324
- strokeWidth: "2",
2325
- strokeLinecap: "round"
2326
- }
2327
- ),
2328
- /* @__PURE__ */ jsx(
2329
- "path",
2330
- {
2331
- d: direction === "back" ? "M18 6l-4 4 4 4" : "M18 6l4 4-4 4",
2332
- stroke: "currentColor",
2333
- strokeWidth: "2",
2334
- strokeLinecap: "round",
2335
- strokeLinejoin: "round"
2336
- }
2337
- ),
2338
- /* @__PURE__ */ jsx("text", { x: "18", y: "22", textAnchor: "middle", fill: "currentColor", fontSize: "9", fontWeight: "600", fontFamily: "system-ui", children: seconds })
2339
- ] })
2340
- }
2341
- );
2342
- }
2343
2395
  function parseVideoChildren(children) {
2344
2396
  const parsed = {
2345
2397
  sources: [],
@@ -2444,18 +2496,15 @@ function parseVttTimestamp(value) {
2444
2496
  return Number(normalized) || 0;
2445
2497
  }
2446
2498
  function formatTime(seconds) {
2447
- if (!Number.isFinite(seconds)) return "00:00";
2499
+ if (!Number.isFinite(seconds)) return "0:00";
2448
2500
  const safeSeconds = Math.max(0, Math.floor(seconds));
2449
2501
  const hours = Math.floor(safeSeconds / 3600);
2450
2502
  const minutes = Math.floor(safeSeconds % 3600 / 60);
2451
2503
  const secs = safeSeconds % 60;
2452
2504
  if (hours > 0) {
2453
- return `${hours}:${String(minutes).padStart(2, "0")}:${String(secs).padStart(
2454
- 2,
2455
- "0"
2456
- )}`;
2505
+ return `${hours}:${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
2457
2506
  }
2458
- return `${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
2507
+ return `${minutes}:${String(secs).padStart(2, "0")}`;
2459
2508
  }
2460
2509
  var RADIUS = { full: "50%", md: "12px", sm: "6px" };
2461
2510
  function Avatar({