@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.
@@ -78,6 +78,8 @@ function Video({
78
78
  const [duration, setDuration] = useState(0);
79
79
  const [currentTime, setCurrentTime] = useState(0);
80
80
  const [bufferedTime, setBufferedTime] = useState(0);
81
+ const [isDragging, setIsDragging] = useState(false);
82
+ const dragPointerIdRef = useRef(null);
81
83
  const [isPlaying, setIsPlaying] = useState(false);
82
84
  const [hasPlayed, setHasPlayed] = useState(false);
83
85
  const [clickIcon, setClickIcon] = useState(null);
@@ -601,44 +603,69 @@ function Video({
601
603
  },
602
604
  [qualities]
603
605
  );
604
- const handleProgressPointerMove = useCallback(
605
- (event) => {
606
+ const seekFromPointer = useCallback(
607
+ (clientX) => {
608
+ const video = videoRef.current;
609
+ const progress = progressRef.current;
610
+ if (!video || !progress || !duration) return;
611
+ const rect = progress.getBoundingClientRect();
612
+ const x = Math.max(0, Math.min(clientX - rect.left, rect.width));
613
+ const nextTime = x / rect.width * duration;
614
+ video.currentTime = nextTime;
615
+ setCurrentTime(nextTime);
616
+ },
617
+ [duration]
618
+ );
619
+ const updatePreview = useCallback(
620
+ (clientX) => {
606
621
  const progress = progressRef.current;
607
622
  if (!progress || !duration || storyboardCues.length === 0) {
608
623
  setPreview(null);
609
624
  return;
610
625
  }
611
626
  const rect = progress.getBoundingClientRect();
612
- const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
627
+ const x = Math.max(0, Math.min(clientX - rect.left, rect.width));
613
628
  const time = x / rect.width * duration;
614
629
  const cue = findStoryboardCue(storyboardCues, time);
615
630
  if (!cue) {
616
631
  setPreview(null);
617
632
  return;
618
633
  }
619
- setPreview({
620
- cue,
621
- time,
622
- left: Math.max(80, Math.min(x, rect.width - 80))
623
- });
634
+ setPreview({ cue, time, left: Math.max(80, Math.min(x, rect.width - 80)) });
624
635
  },
625
636
  [duration, storyboardCues]
626
637
  );
638
+ const handleProgressPointerMove = useCallback(
639
+ (event) => {
640
+ updatePreview(event.clientX);
641
+ if (isDragging) seekFromPointer(event.clientX);
642
+ },
643
+ [isDragging, seekFromPointer, updatePreview]
644
+ );
627
645
  const handleProgressPointerLeave = useCallback(() => {
628
- setPreview(null);
629
- }, []);
646
+ if (!isDragging) setPreview(null);
647
+ }, [isDragging]);
630
648
  const handleProgressPointerDown = useCallback(
631
649
  (event) => {
632
- const video = videoRef.current;
633
650
  const progress = progressRef.current;
634
- if (!video || !progress || !duration) return;
635
- const rect = progress.getBoundingClientRect();
636
- const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
637
- const nextTime = x / rect.width * duration;
638
- video.currentTime = nextTime;
639
- setCurrentTime(nextTime);
651
+ if (!progress) return;
652
+ progress.setPointerCapture(event.pointerId);
653
+ dragPointerIdRef.current = event.pointerId;
654
+ setIsDragging(true);
655
+ seekFromPointer(event.clientX);
656
+ updatePreview(event.clientX);
640
657
  },
641
- [duration]
658
+ [seekFromPointer, updatePreview]
659
+ );
660
+ const handleProgressPointerUp = useCallback(
661
+ (event) => {
662
+ if (dragPointerIdRef.current === event.pointerId) {
663
+ setIsDragging(false);
664
+ dragPointerIdRef.current = null;
665
+ setPreview(null);
666
+ }
667
+ },
668
+ []
642
669
  );
643
670
  const handleKeyDown = useCallback(
644
671
  (event) => {
@@ -757,8 +784,8 @@ function Video({
757
784
  ] }) }),
758
785
  /* @__PURE__ */ jsxs("footer", { onClick: (e) => e.stopPropagation(), className: "relative z-10 px-4 pb-4 text-white", children: [
759
786
  settingsOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
760
- /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-40", onClick: () => setSettingsOpen(false) }),
761
- /* @__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: [
787
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-70", onClick: () => setSettingsOpen(false) }),
788
+ /* @__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: [
762
789
  settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
763
790
  { id: "quality", label: "Qualidade", value: qualities.find((q) => q.id === selectedQuality)?.label ?? "Auto" },
764
791
  ...parsed.subtitles.length > 0 ? [{ id: "subtitles", label: "Legendas", value: subtitleStyle.track === "off" ? "Desligado" : parsed.subtitles.find((s) => s.srclang === subtitleStyle.track)?.label ?? subtitleStyle.track }] : [],
@@ -909,30 +936,44 @@ function Video({
909
936
  ] }),
910
937
  /* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
911
938
  ] }),
912
- /* @__PURE__ */ jsx(
939
+ /* @__PURE__ */ jsxs(
913
940
  "div",
914
941
  {
915
942
  ref: progressRef,
916
943
  onPointerMove: handleProgressPointerMove,
917
944
  onPointerLeave: handleProgressPointerLeave,
918
945
  onPointerDown: handleProgressPointerDown,
946
+ onPointerUp: handleProgressPointerUp,
919
947
  className: "group relative mb-2 h-5 cursor-pointer",
920
- 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: [
948
+ children: [
949
+ /* @__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: [
950
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 bg-white/30", style: { width: `${bufferedPercent}%` } }),
951
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 bg-white/85", style: { width: `${progressPercent}%` } })
952
+ ] }),
921
953
  /* @__PURE__ */ jsx(
922
954
  "div",
923
955
  {
924
- className: "absolute inset-y-0 left-0 bg-white/30",
925
- style: { width: `${bufferedPercent}%` }
956
+ className: "absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow transition-[width,height] duration-100",
957
+ style: {
958
+ left: `${progressPercent}%`,
959
+ width: isDragging ? "14px" : "0px",
960
+ height: isDragging ? "14px" : "0px",
961
+ opacity: isDragging ? 1 : 0
962
+ }
926
963
  }
927
964
  ),
928
965
  /* @__PURE__ */ jsx(
929
966
  "div",
930
967
  {
931
- className: "absolute inset-y-0 left-0 bg-white/85",
932
- style: { width: `${progressPercent}%` }
968
+ 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",
969
+ style: {
970
+ left: `${progressPercent}%`,
971
+ width: isDragging ? "14px" : "10px",
972
+ height: isDragging ? "14px" : "10px"
973
+ }
933
974
  }
934
975
  )
935
- ] })
976
+ ]
936
977
  }
937
978
  ),
938
979
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
@@ -1037,40 +1078,32 @@ function Video({
1037
1078
  preview && (() => {
1038
1079
  const srcW = preview.cue.w ?? 160;
1039
1080
  const srcH = preview.cue.h ?? 90;
1040
- const thumbW = Math.max(120, Math.round((playerWidth || 640) * 0.1));
1081
+ const thumbW = Math.max(140, Math.round((playerWidth || 640) * 0.13));
1041
1082
  const thumbH = Math.round(thumbW * (srcH / srcW));
1042
1083
  const scale = thumbW / srcW;
1043
1084
  const isSprite = preview.cue.x != null && preview.cue.y != null;
1044
- return /* @__PURE__ */ jsxs(
1085
+ return /* @__PURE__ */ jsx(
1045
1086
  "div",
1046
1087
  {
1047
- 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",
1048
- style: { bottom: controlsVisible ? "72px" : "16px", left: preview.left, transition: "bottom 0.2s" },
1049
- children: [
1050
- /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-lg", style: { width: thumbW, height: thumbH }, children: isSprite ? (
1051
- // Inner div at native tile size, positioned to show the right sprite cell,
1052
- // then scaled up to fill thumbW×thumbH. transformOrigin top-left ensures
1053
- // the clip window aligns correctly.
1054
- /* @__PURE__ */ jsx("div", { style: {
1055
- width: srcW,
1056
- height: srcH,
1057
- backgroundImage: `url(${preview.cue.image})`,
1058
- backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
1059
- backgroundSize: "auto",
1060
- backgroundRepeat: "no-repeat",
1061
- transform: `scale(${scale})`,
1062
- transformOrigin: "top left"
1063
- } })
1064
- ) : /* @__PURE__ */ jsx("div", { style: {
1065
- width: thumbW,
1066
- height: thumbH,
1067
- backgroundImage: `url(${preview.cue.image})`,
1068
- backgroundSize: "cover",
1069
- backgroundPosition: "center",
1070
- backgroundRepeat: "no-repeat"
1071
- } }) }),
1072
- /* @__PURE__ */ jsx("div", { className: "pt-1 text-center text-[11px] font-semibold text-white/75", children: formatTime(preview.time) })
1073
- ]
1088
+ 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",
1089
+ style: { bottom: controlsVisible ? "80px" : "20px", left: preview.left, transition: "bottom 0.2s" },
1090
+ children: isSprite ? /* @__PURE__ */ jsx("div", { style: { width: thumbW, height: thumbH, overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: {
1091
+ width: srcW,
1092
+ height: srcH,
1093
+ backgroundImage: `url(${preview.cue.image})`,
1094
+ backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
1095
+ backgroundSize: "auto",
1096
+ backgroundRepeat: "no-repeat",
1097
+ transform: `scale(${scale})`,
1098
+ transformOrigin: "top left"
1099
+ } }) }) : /* @__PURE__ */ jsx("div", { style: {
1100
+ width: thumbW,
1101
+ height: thumbH,
1102
+ backgroundImage: `url(${preview.cue.image})`,
1103
+ backgroundSize: "cover",
1104
+ backgroundPosition: "center",
1105
+ backgroundRepeat: "no-repeat"
1106
+ } })
1074
1107
  }
1075
1108
  );
1076
1109
  })(),