@geekapps/silo-elements-nextjs 0.2.30 → 0.2.32

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
@@ -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) => {
@@ -1957,8 +1984,8 @@ function Video({
1957
1984
  ] }) }),
1958
1985
  /* @__PURE__ */ jsxs("footer", { onClick: (e) => e.stopPropagation(), className: "relative z-10 px-4 pb-4 text-white", children: [
1959
1986
  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: [
1987
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-70", onClick: () => setSettingsOpen(false) }),
1988
+ /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full right-0 z-70 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: [
1962
1989
  settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
1963
1990
  { id: "quality", label: "Qualidade", value: qualities.find((q) => q.id === selectedQuality)?.label ?? "Auto" },
1964
1991
  ...parsed.subtitles.length > 0 ? [{ id: "subtitles", label: "Legendas", value: subtitleStyle.track === "off" ? "Desligado" : parsed.subtitles.find((s) => s.srclang === subtitleStyle.track)?.label ?? subtitleStyle.track }] : [],
@@ -2109,30 +2136,44 @@ function Video({
2109
2136
  ] }),
2110
2137
  /* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
2111
2138
  ] }),
2112
- /* @__PURE__ */ jsx(
2139
+ /* @__PURE__ */ jsxs(
2113
2140
  "div",
2114
2141
  {
2115
2142
  ref: progressRef,
2116
2143
  onPointerMove: handleProgressPointerMove,
2117
2144
  onPointerLeave: handleProgressPointerLeave,
2118
2145
  onPointerDown: handleProgressPointerDown,
2146
+ onPointerUp: handleProgressPointerUp,
2119
2147
  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: [
2148
+ children: [
2149
+ /* @__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: isDragging ? "4px" : "2px" }, children: [
2150
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 bg-white/30", style: { width: `${bufferedPercent}%` } }),
2151
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 bg-white/85", style: { width: `${progressPercent}%` } })
2152
+ ] }),
2121
2153
  /* @__PURE__ */ jsx(
2122
2154
  "div",
2123
2155
  {
2124
- className: "absolute inset-y-0 left-0 bg-white/30",
2125
- style: { width: `${bufferedPercent}%` }
2156
+ className: "absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow transition-[width,height] duration-100",
2157
+ style: {
2158
+ left: `${progressPercent}%`,
2159
+ width: isDragging ? "14px" : "0px",
2160
+ height: isDragging ? "14px" : "0px",
2161
+ opacity: isDragging ? 1 : 0
2162
+ }
2126
2163
  }
2127
2164
  ),
2128
2165
  /* @__PURE__ */ jsx(
2129
2166
  "div",
2130
2167
  {
2131
- className: "absolute inset-y-0 left-0 bg-white/85",
2132
- style: { width: `${progressPercent}%` }
2168
+ className: "pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow opacity-0 transition-[width,height,opacity] duration-100 group-hover:opacity-100",
2169
+ style: {
2170
+ left: `${progressPercent}%`,
2171
+ width: isDragging ? "14px" : "10px",
2172
+ height: isDragging ? "14px" : "10px"
2173
+ }
2133
2174
  }
2134
2175
  )
2135
- ] })
2176
+ ]
2136
2177
  }
2137
2178
  ),
2138
2179
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
@@ -2237,40 +2278,32 @@ function Video({
2237
2278
  preview && (() => {
2238
2279
  const srcW = preview.cue.w ?? 160;
2239
2280
  const srcH = preview.cue.h ?? 90;
2240
- const thumbW = Math.max(120, Math.round((playerWidth || 640) * 0.1));
2281
+ const thumbW = Math.max(140, Math.round((playerWidth || 640) * 0.13));
2241
2282
  const thumbH = Math.round(thumbW * (srcH / srcW));
2242
2283
  const scale = thumbW / srcW;
2243
2284
  const isSprite = preview.cue.x != null && preview.cue.y != null;
2244
- return /* @__PURE__ */ jsxs(
2285
+ return /* @__PURE__ */ jsx(
2245
2286
  "div",
2246
2287
  {
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
- ]
2288
+ 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",
2289
+ style: { bottom: controlsVisible ? "80px" : "20px", left: preview.left, transition: "bottom 0.2s" },
2290
+ children: isSprite ? /* @__PURE__ */ jsx("div", { style: { width: thumbW, height: thumbH, overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: {
2291
+ width: srcW,
2292
+ height: srcH,
2293
+ backgroundImage: `url(${preview.cue.image})`,
2294
+ backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
2295
+ backgroundSize: "auto",
2296
+ backgroundRepeat: "no-repeat",
2297
+ transform: `scale(${scale})`,
2298
+ transformOrigin: "top left"
2299
+ } }) }) : /* @__PURE__ */ jsx("div", { style: {
2300
+ width: thumbW,
2301
+ height: thumbH,
2302
+ backgroundImage: `url(${preview.cue.image})`,
2303
+ backgroundSize: "cover",
2304
+ backgroundPosition: "center",
2305
+ backgroundRepeat: "no-repeat"
2306
+ } })
2274
2307
  }
2275
2308
  );
2276
2309
  })(),
@@ -2504,6 +2537,7 @@ function Thumbnail({
2504
2537
  fileKey,
2505
2538
  bucket,
2506
2539
  mimeType,
2540
+ src,
2507
2541
  width = "100%",
2508
2542
  height = 160,
2509
2543
  fit = "cover",
@@ -2513,7 +2547,9 @@ function Thumbnail({
2513
2547
  style,
2514
2548
  alt = "thumbnail"
2515
2549
  }) {
2516
- const { url, loading } = useSignedUrl(fileKey);
2550
+ const { url: signedUrl, loading: signedLoading } = useSignedUrl(src != null ? null : fileKey);
2551
+ const url = src ?? signedUrl;
2552
+ const loading = src != null ? false : signedLoading;
2517
2553
  const [error, setError] = useState(false);
2518
2554
  const isVideo = mimeType?.startsWith("video/");
2519
2555
  const wrapper = {