stormcloud-video-player 0.2.9 → 0.2.10

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/lib/index.js CHANGED
@@ -42,9 +42,22 @@ function createImaController(video, options) {
42
42
  'script[data-ima="true"]'
43
43
  );
44
44
  if (existing) {
45
- return new Promise(
46
- (resolve) => existing.addEventListener("load", () => resolve())
47
- );
45
+ if (window.google?.ima) {
46
+ return Promise.resolve();
47
+ }
48
+ return new Promise((resolve, reject) => {
49
+ const timeout = setTimeout(() => {
50
+ reject(new Error("IMA SDK load timeout"));
51
+ }, 1e4);
52
+ existing.addEventListener("load", () => {
53
+ clearTimeout(timeout);
54
+ resolve();
55
+ });
56
+ existing.addEventListener("error", () => {
57
+ clearTimeout(timeout);
58
+ reject(new Error("IMA SDK load failed"));
59
+ });
60
+ });
48
61
  }
49
62
  return new Promise((resolve, reject) => {
50
63
  const script = document.createElement("script");
@@ -73,6 +86,17 @@ function createImaController(video, options) {
73
86
  adsRequest.adTagUrl = vastTagUrl;
74
87
  adsLoader.requestAds(adsRequest);
75
88
  }
89
+ function destroyAdsManager() {
90
+ if (adsManager) {
91
+ try {
92
+ console.log("[IMA] Destroying existing ads manager");
93
+ adsManager.destroy();
94
+ } catch (error) {
95
+ console.warn("[IMA] Error destroying ads manager:", error);
96
+ }
97
+ adsManager = void 0;
98
+ }
99
+ }
76
100
  return {
77
101
  initialize() {
78
102
  ensureImaLoaded().then(() => {
@@ -105,9 +129,22 @@ function createImaController(video, options) {
105
129
  },
106
130
  async requestAds(vastTagUrl) {
107
131
  console.log("[IMA] Requesting ads:", vastTagUrl);
132
+ if (adPlaying) {
133
+ console.warn(
134
+ "[IMA] Cannot request new ads while an ad is playing. Call stop() first."
135
+ );
136
+ return Promise.reject(
137
+ new Error("Ad already playing - cannot request new ads")
138
+ );
139
+ }
140
+ destroyAdsManager();
141
+ adsLoadedReject = void 0;
142
+ adsLoadedResolve = void 0;
143
+ let currentReject;
108
144
  adsLoadedPromise = new Promise((resolve, reject) => {
109
145
  adsLoadedResolve = resolve;
110
146
  adsLoadedReject = reject;
147
+ currentReject = reject;
111
148
  setTimeout(() => {
112
149
  if (adsLoadedReject) {
113
150
  adsLoadedReject(new Error("Ad request timeout"));
@@ -129,7 +166,7 @@ function createImaController(video, options) {
129
166
  container.style.top = "0";
130
167
  container.style.right = "0";
131
168
  container.style.bottom = "0";
132
- container.style.display = "flex";
169
+ container.style.display = "none";
133
170
  container.style.alignItems = "center";
134
171
  container.style.justifyContent = "center";
135
172
  container.style.pointerEvents = "none";
@@ -169,14 +206,14 @@ function createImaController(video, options) {
169
206
  AdErrorEvent.AD_ERROR,
170
207
  (errorEvent) => {
171
208
  console.error("[IMA] Ad error:", errorEvent.getError());
172
- try {
173
- adsManager?.destroy?.();
174
- } catch {
175
- }
209
+ destroyAdsManager();
176
210
  adPlaying = false;
177
211
  video.muted = originalMutedState;
178
- if (adContainerEl)
212
+ if (adContainerEl) {
179
213
  adContainerEl.style.pointerEvents = "none";
214
+ adContainerEl.style.display = "none";
215
+ console.log("[IMA] Ad container hidden after error");
216
+ }
180
217
  if (adsLoadedReject) {
181
218
  adsLoadedReject(new Error("Ad playback error"));
182
219
  adsLoadedReject = void 0;
@@ -209,10 +246,6 @@ function createImaController(video, options) {
209
246
  AdEvent.CONTENT_PAUSE_REQUESTED,
210
247
  () => {
211
248
  console.log("[IMA] Content pause requested");
212
- if (!adPlaying) {
213
- originalMutedState = video.muted;
214
- }
215
- video.muted = true;
216
249
  if (!options?.continueLiveStreamDuringAds) {
217
250
  video.pause();
218
251
  console.log("[IMA] Video paused (VOD mode)");
@@ -221,20 +254,34 @@ function createImaController(video, options) {
221
254
  "[IMA] Video continues playing but muted (Live mode)"
222
255
  );
223
256
  }
257
+ video.muted = true;
224
258
  adPlaying = true;
225
- if (adContainerEl)
226
- adContainerEl.style.pointerEvents = "auto";
227
259
  emit("content_pause");
228
260
  }
229
261
  );
262
+ adsManager.addEventListener(AdEvent.STARTED, () => {
263
+ console.log("[IMA] Ad started playing");
264
+ if (adContainerEl) {
265
+ adContainerEl.style.pointerEvents = "auto";
266
+ adContainerEl.style.display = "flex";
267
+ console.log(
268
+ "[IMA] Ad container visibility set to flex with pointer events enabled"
269
+ );
270
+ }
271
+ });
230
272
  adsManager.addEventListener(
231
273
  AdEvent.CONTENT_RESUME_REQUESTED,
232
274
  () => {
233
275
  console.log("[IMA] Content resume requested");
234
276
  adPlaying = false;
235
277
  video.muted = originalMutedState;
236
- if (adContainerEl)
278
+ if (adContainerEl) {
237
279
  adContainerEl.style.pointerEvents = "none";
280
+ adContainerEl.style.display = "none";
281
+ console.log(
282
+ "[IMA] Ad container hidden - pointer events disabled"
283
+ );
284
+ }
238
285
  if (!options?.continueLiveStreamDuringAds) {
239
286
  video.play()?.catch(() => {
240
287
  });
@@ -251,7 +298,13 @@ function createImaController(video, options) {
251
298
  console.log("[IMA] All ads completed");
252
299
  adPlaying = false;
253
300
  video.muted = originalMutedState;
254
- if (adContainerEl) adContainerEl.style.pointerEvents = "none";
301
+ if (adContainerEl) {
302
+ adContainerEl.style.pointerEvents = "none";
303
+ adContainerEl.style.display = "none";
304
+ console.log(
305
+ "[IMA] Ad container hidden after all ads completed"
306
+ );
307
+ }
255
308
  if (!options?.continueLiveStreamDuringAds) {
256
309
  video.play().catch(() => {
257
310
  });
@@ -294,6 +347,13 @@ function createImaController(video, options) {
294
347
  google.ima.AdErrorEvent.Type.AD_ERROR,
295
348
  (adErrorEvent) => {
296
349
  console.error("[IMA] Ads loader error:", adErrorEvent.getError());
350
+ adPlaying = false;
351
+ video.muted = originalMutedState;
352
+ if (adContainerEl) adContainerEl.style.pointerEvents = "none";
353
+ if (!options?.continueLiveStreamDuringAds) {
354
+ video.play().catch(() => {
355
+ });
356
+ }
297
357
  if (adsLoadedReject) {
298
358
  adsLoadedReject(new Error("Ads loader error"));
299
359
  adsLoadedReject = void 0;
@@ -309,11 +369,9 @@ function createImaController(video, options) {
309
369
  return adsLoadedPromise;
310
370
  } catch (error) {
311
371
  console.error("[IMA] Failed to request ads:", error);
312
- if (adsLoadedReject) {
313
- adsLoadedReject(error);
314
- adsLoadedReject = void 0;
315
- adsLoadedResolve = void 0;
316
- }
372
+ currentReject?.(error);
373
+ adsLoadedReject = void 0;
374
+ adsLoadedResolve = void 0;
317
375
  return Promise.reject(error);
318
376
  }
319
377
  },
@@ -350,10 +408,16 @@ function createImaController(video, options) {
350
408
  async stop() {
351
409
  adPlaying = false;
352
410
  video.muted = originalMutedState;
411
+ if (adContainerEl) {
412
+ adContainerEl.style.pointerEvents = "none";
413
+ adContainerEl.style.display = "none";
414
+ console.log("[IMA] Ad container hidden after stop");
415
+ }
353
416
  try {
354
417
  adsManager?.stop?.();
355
418
  } catch {
356
419
  }
420
+ destroyAdsManager();
357
421
  if (!options?.continueLiveStreamDuringAds) {
358
422
  video.play().catch(() => {
359
423
  });
@@ -363,12 +427,13 @@ function createImaController(video, options) {
363
427
  }
364
428
  },
365
429
  destroy() {
366
- try {
367
- adsManager?.destroy?.();
368
- } catch {
369
- }
430
+ destroyAdsManager();
370
431
  adPlaying = false;
371
432
  video.muted = originalMutedState;
433
+ if (adContainerEl) {
434
+ adContainerEl.style.pointerEvents = "none";
435
+ adContainerEl.style.display = "none";
436
+ }
372
437
  try {
373
438
  adsLoader?.destroy?.();
374
439
  } catch {
@@ -376,6 +441,9 @@ function createImaController(video, options) {
376
441
  if (adContainerEl?.parentElement) {
377
442
  adContainerEl.parentElement.removeChild(adContainerEl);
378
443
  }
444
+ adContainerEl = void 0;
445
+ adDisplayContainer = void 0;
446
+ adsLoader = void 0;
379
447
  },
380
448
  isAdPlaying() {
381
449
  return adPlaying;
@@ -853,17 +921,8 @@ var StormcloudVideoPlayer = class {
853
921
  this.video.muted = !!this.config.muted;
854
922
  this.ima.initialize();
855
923
  this.ima.on("all_ads_completed", () => {
856
- if (!this.inAdBreak) return;
857
- const remaining = this.getRemainingAdMs();
858
- if (remaining > 500 && this.adPodQueue.length > 0) {
859
- const next = this.adPodQueue.shift();
860
- this.currentAdIndex++;
861
- this.playSingleAd(next).catch(() => {
862
- });
863
- } else {
864
- this.currentAdIndex = 0;
865
- this.totalAdsInBreak = 0;
866
- this.showAds = false;
924
+ if (this.config.debugAdTiming) {
925
+ console.log("[StormcloudVideoPlayer] IMA all_ads_completed event received");
867
926
  }
868
927
  });
869
928
  this.ima.on("ad_error", () => {
@@ -894,6 +953,26 @@ var StormcloudVideoPlayer = class {
894
953
  );
895
954
  }
896
955
  this.clearAdFailsafeTimer();
956
+ if (!this.inAdBreak) return;
957
+ const remaining = this.getRemainingAdMs();
958
+ if (remaining > 500 && this.adPodQueue.length > 0) {
959
+ const next = this.adPodQueue.shift();
960
+ this.currentAdIndex++;
961
+ if (this.config.debugAdTiming) {
962
+ console.log(
963
+ `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak})`
964
+ );
965
+ }
966
+ this.playSingleAd(next).catch(() => {
967
+ });
968
+ } else {
969
+ if (this.config.debugAdTiming) {
970
+ console.log("[StormcloudVideoPlayer] Ad pod completed");
971
+ }
972
+ this.currentAdIndex = 0;
973
+ this.totalAdsInBreak = 0;
974
+ this.showAds = false;
975
+ }
897
976
  });
898
977
  this.video.addEventListener("timeupdate", () => {
899
978
  this.onTimeUpdate(this.video.currentTime);
@@ -1543,21 +1622,21 @@ var StormcloudVideoPlayer = class {
1543
1622
  if (this.config.debugAdTiming) {
1544
1623
  console.log("[StormcloudVideoPlayer] Attempting to play ad:", vastTagUrl);
1545
1624
  }
1546
- this.ima.updateOriginalMutedState(this.video.muted);
1547
- if (!this.shouldContinueLiveStreamDuringAds()) {
1548
- if (this.config.debugAdTiming) {
1549
- console.log("[StormcloudVideoPlayer] Pausing video immediately for ad (VOD mode)");
1550
- }
1551
- this.video.pause();
1552
- } else {
1625
+ if (this.ima.isAdPlaying()) {
1553
1626
  if (this.config.debugAdTiming) {
1554
- console.log("[StormcloudVideoPlayer] Muting video for ad (Live mode)");
1627
+ console.warn(
1628
+ "[StormcloudVideoPlayer] Ad already playing - skipping new ad request"
1629
+ );
1555
1630
  }
1556
- this.video.muted = true;
1631
+ return;
1557
1632
  }
1633
+ this.ima.updateOriginalMutedState(this.video.muted);
1558
1634
  this.startAdFailsafeTimer();
1559
1635
  try {
1560
1636
  await this.ima.requestAds(vastTagUrl);
1637
+ if (this.config.debugAdTiming) {
1638
+ console.log("[StormcloudVideoPlayer] Ad request successful, starting playback");
1639
+ }
1561
1640
  await this.ima.play();
1562
1641
  if (this.config.debugAdTiming) {
1563
1642
  console.log("[StormcloudVideoPlayer] Ad playback started successfully");
@@ -1585,6 +1664,13 @@ var StormcloudVideoPlayer = class {
1585
1664
  this.showAds = false;
1586
1665
  this.currentAdIndex = 0;
1587
1666
  this.totalAdsInBreak = 0;
1667
+ const originalMutedState = this.ima.getOriginalMutedState();
1668
+ this.video.muted = originalMutedState;
1669
+ if (this.config.debugAdTiming) {
1670
+ console.log(
1671
+ `[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
1672
+ );
1673
+ }
1588
1674
  if (this.video.paused) {
1589
1675
  this.video.play()?.catch(() => {
1590
1676
  if (this.config.debugAdTiming) {
@@ -2537,39 +2623,144 @@ var StormcloudVideoPlayerComponent = React.memo(
2537
2623
  left: "50%",
2538
2624
  transform: "translateX(-50%)",
2539
2625
  marginBottom: "4px",
2540
- background: "linear-gradient(135deg, rgba(0, 0, 0, 0.85) 0%, rgba(20, 20, 20, 0.9) 100%)",
2626
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.88) 0%, rgba(20, 20, 20, 0.92) 100%)",
2541
2627
  backdropFilter: "blur(15px)",
2542
- padding: "16px 12px",
2543
- borderRadius: "12px",
2544
- border: "1px solid rgba(255, 255, 255, 0.1)",
2628
+ padding: "10px 14px",
2629
+ borderRadius: "14px",
2630
+ border: "1px solid rgba(255, 255, 255, 0.15)",
2545
2631
  display: "flex",
2546
2632
  flexDirection: "column",
2547
2633
  alignItems: "center",
2548
- height: "130px",
2549
- boxShadow: "0 12px 40px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1)",
2550
- zIndex: 10
2634
+ justifyContent: "center",
2635
+ height: "128px",
2636
+ boxShadow: "0 12px 40px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.15)",
2637
+ zIndex: 10,
2638
+ transition: "transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, border-color 0.2s ease-in-out"
2551
2639
  },
2552
- onMouseEnter: () => setShowVolumeSlider(true),
2553
- onMouseLeave: () => setShowVolumeSlider(false),
2554
- children: /* @__PURE__ */ jsx(
2555
- "input",
2640
+ onMouseEnter: (e) => {
2641
+ setShowVolumeSlider(true);
2642
+ e.currentTarget.style.transform = "translateX(-50%) translateY(-2px) scale(1.02)";
2643
+ e.currentTarget.style.boxShadow = "0 16px 48px rgba(0, 0, 0, 0.6), 0 6px 16px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 0 24px rgba(59, 130, 246, 0.3)";
2644
+ e.currentTarget.style.borderColor = "rgba(59, 130, 246, 0.4)";
2645
+ },
2646
+ onMouseLeave: (e) => {
2647
+ setShowVolumeSlider(false);
2648
+ e.currentTarget.style.transform = "translateX(-50%)";
2649
+ e.currentTarget.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.15)";
2650
+ e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.15)";
2651
+ },
2652
+ children: /* @__PURE__ */ jsxs(
2653
+ "div",
2556
2654
  {
2557
- type: "range",
2558
- min: "0",
2559
- max: "1",
2560
- step: "0.01",
2561
- value: isMuted ? 0 : volume,
2562
- onChange: (e) => handleVolumeChange(parseFloat(e.target.value)),
2563
2655
  style: {
2564
- writingMode: "bt-lr",
2565
- WebkitAppearance: "slider-vertical",
2566
- width: "6px",
2567
- height: "90px",
2568
- background: "linear-gradient(180deg, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0.1) 100%)",
2569
- borderRadius: "3px",
2570
- outline: "none",
2571
- cursor: "pointer"
2572
- }
2656
+ position: "relative",
2657
+ width: "8px",
2658
+ height: "104px",
2659
+ cursor: "pointer",
2660
+ transition: "transform 0.2s ease-in-out"
2661
+ },
2662
+ onMouseEnter: (e) => {
2663
+ e.currentTarget.style.transform = "scaleX(1.2)";
2664
+ },
2665
+ onMouseLeave: (e) => {
2666
+ e.currentTarget.style.transform = "scaleX(1)";
2667
+ },
2668
+ onMouseDown: (e) => {
2669
+ e.preventDefault();
2670
+ const sliderElement = e.currentTarget;
2671
+ const handleMouseMove = (moveEvent) => {
2672
+ if (!sliderElement) return;
2673
+ const rect2 = sliderElement.getBoundingClientRect();
2674
+ const y2 = moveEvent.clientY - rect2.top;
2675
+ const percentage2 = 1 - Math.max(0, Math.min(1, y2 / rect2.height));
2676
+ handleVolumeChange(percentage2);
2677
+ };
2678
+ const handleMouseUp = () => {
2679
+ document.removeEventListener("mousemove", handleMouseMove);
2680
+ document.removeEventListener("mouseup", handleMouseUp);
2681
+ };
2682
+ document.addEventListener("mousemove", handleMouseMove);
2683
+ document.addEventListener("mouseup", handleMouseUp);
2684
+ const rect = sliderElement.getBoundingClientRect();
2685
+ const y = e.clientY - rect.top;
2686
+ const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
2687
+ handleVolumeChange(percentage);
2688
+ },
2689
+ onClick: (e) => {
2690
+ e.stopPropagation();
2691
+ const rect = e.currentTarget.getBoundingClientRect();
2692
+ const y = e.clientY - rect.top;
2693
+ const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
2694
+ handleVolumeChange(percentage);
2695
+ },
2696
+ children: [
2697
+ /* @__PURE__ */ jsx(
2698
+ "div",
2699
+ {
2700
+ style: {
2701
+ position: "absolute",
2702
+ bottom: "0",
2703
+ left: "0",
2704
+ width: "100%",
2705
+ height: "100%",
2706
+ background: "linear-gradient(180deg, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.15) 100%)",
2707
+ borderRadius: "4px",
2708
+ boxShadow: "inset 0 1px 3px rgba(0, 0, 0, 0.2)"
2709
+ }
2710
+ }
2711
+ ),
2712
+ /* @__PURE__ */ jsx(
2713
+ "div",
2714
+ {
2715
+ style: {
2716
+ position: "absolute",
2717
+ bottom: "0",
2718
+ left: "0",
2719
+ width: "100%",
2720
+ height: `${(isMuted ? 0 : volume) * 100}%`,
2721
+ background: "linear-gradient(180deg, rgba(96, 165, 250, 1) 0%, rgba(59, 130, 246, 0.95) 50%, rgba(37, 99, 235, 0.9) 100%)",
2722
+ borderRadius: "4px",
2723
+ transition: "height 0.15s ease-out, box-shadow 0.2s ease-in-out",
2724
+ boxShadow: "0 0 8px rgba(59, 130, 246, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.3)"
2725
+ }
2726
+ }
2727
+ ),
2728
+ /* @__PURE__ */ jsx(
2729
+ "div",
2730
+ {
2731
+ style: {
2732
+ position: "absolute",
2733
+ bottom: `calc(${(isMuted ? 0 : volume) * 100}% - 7px)`,
2734
+ left: "50%",
2735
+ transform: "translateX(-50%)",
2736
+ width: "14px",
2737
+ height: "14px",
2738
+ background: "linear-gradient(135deg, #ffffff 0%, #f0f9ff 100%)",
2739
+ borderRadius: "50%",
2740
+ boxShadow: "0 2px 6px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(59, 130, 246, 0.3), 0 0 12px rgba(59, 130, 246, 0.4)",
2741
+ transition: "bottom 0.15s ease-out, transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, width 0.2s ease-in-out, height 0.2s ease-in-out",
2742
+ cursor: "grab"
2743
+ },
2744
+ onMouseEnter: (e) => {
2745
+ e.currentTarget.style.transform = "translateX(-50%) scale(1.3)";
2746
+ e.currentTarget.style.boxShadow = "0 3px 10px rgba(0, 0, 0, 0.4), 0 0 0 3px rgba(59, 130, 246, 0.5), 0 0 20px rgba(59, 130, 246, 0.6)";
2747
+ e.currentTarget.style.cursor = "grab";
2748
+ },
2749
+ onMouseLeave: (e) => {
2750
+ e.currentTarget.style.transform = "translateX(-50%) scale(1)";
2751
+ e.currentTarget.style.boxShadow = "0 2px 6px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(59, 130, 246, 0.3), 0 0 12px rgba(59, 130, 246, 0.4)";
2752
+ },
2753
+ onMouseDown: (e) => {
2754
+ e.currentTarget.style.transform = "translateX(-50%) scale(1.4)";
2755
+ e.currentTarget.style.cursor = "grabbing";
2756
+ },
2757
+ onMouseUp: (e) => {
2758
+ e.currentTarget.style.transform = "translateX(-50%) scale(1.3)";
2759
+ e.currentTarget.style.cursor = "grab";
2760
+ }
2761
+ }
2762
+ )
2763
+ ]
2573
2764
  }
2574
2765
  )
2575
2766
  }
@@ -2886,40 +3077,146 @@ var StormcloudVideoPlayerComponent = React.memo(
2886
3077
  left: "50%",
2887
3078
  transform: "translateX(-50%)",
2888
3079
  marginBottom: "4px",
2889
- background: "linear-gradient(135deg, rgba(0, 0, 0, 0.95) 0%, rgba(20, 20, 20, 0.9) 100%)",
3080
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.96) 0%, rgba(20, 20, 20, 0.92) 100%)",
2890
3081
  backdropFilter: "blur(20px)",
2891
- padding: "16px 12px",
2892
- borderRadius: "12px",
2893
- border: "2px solid rgba(255, 255, 255, 0.6)",
3082
+ padding: "10px 14px",
3083
+ borderRadius: "14px",
3084
+ border: "2px solid rgba(255, 255, 255, 0.7)",
2894
3085
  display: "flex",
2895
3086
  flexDirection: "column",
2896
3087
  alignItems: "center",
2897
- height: "130px",
2898
- boxShadow: "0 12px 40px rgba(0, 0, 0, 0.8), inset 0 1px 0 rgba(255, 255, 255, 0.3)",
2899
- zIndex: 10
3088
+ justifyContent: "center",
3089
+ height: "128px",
3090
+ boxShadow: "0 12px 40px rgba(0, 0, 0, 0.85), 0 4px 12px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.35)",
3091
+ zIndex: 10,
3092
+ transition: "transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, border-color 0.2s ease-in-out"
2900
3093
  },
2901
- onMouseEnter: () => setShowVolumeSlider(true),
2902
- onMouseLeave: () => setShowVolumeSlider(false),
2903
- children: /* @__PURE__ */ jsx(
2904
- "input",
3094
+ onMouseEnter: (e) => {
3095
+ setShowVolumeSlider(true);
3096
+ e.currentTarget.style.transform = "translateX(-50%) translateY(-2px) scale(1.02)";
3097
+ e.currentTarget.style.boxShadow = "0 16px 48px rgba(0, 0, 0, 0.9), 0 6px 16px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 0 24px rgba(96, 165, 250, 0.4)";
3098
+ e.currentTarget.style.borderColor = "rgba(96, 165, 250, 0.8)";
3099
+ },
3100
+ onMouseLeave: (e) => {
3101
+ setShowVolumeSlider(false);
3102
+ e.currentTarget.style.transform = "translateX(-50%)";
3103
+ e.currentTarget.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.85), 0 4px 12px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.35)";
3104
+ e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.7)";
3105
+ },
3106
+ children: /* @__PURE__ */ jsxs(
3107
+ "div",
2905
3108
  {
2906
- type: "range",
2907
- min: "0",
2908
- max: "1",
2909
- step: "0.01",
2910
- value: isMuted ? 0 : volume,
2911
- onChange: (e) => handleVolumeChange(parseFloat(e.target.value)),
2912
3109
  style: {
2913
- writingMode: "bt-lr",
2914
- WebkitAppearance: "slider-vertical",
2915
- width: "6px",
2916
- height: "90px",
2917
- background: "linear-gradient(180deg, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.4) 100%)",
2918
- borderRadius: "3px",
2919
- outline: "none",
3110
+ position: "relative",
3111
+ width: "8px",
3112
+ height: "104px",
2920
3113
  cursor: "pointer",
2921
- border: "1px solid rgba(255, 255, 255, 0.3)"
2922
- }
3114
+ transition: "transform 0.2s ease-in-out"
3115
+ },
3116
+ onMouseEnter: (e) => {
3117
+ e.currentTarget.style.transform = "scaleX(1.2)";
3118
+ },
3119
+ onMouseLeave: (e) => {
3120
+ e.currentTarget.style.transform = "scaleX(1)";
3121
+ },
3122
+ onMouseDown: (e) => {
3123
+ e.preventDefault();
3124
+ const sliderElement = e.currentTarget;
3125
+ const handleMouseMove = (moveEvent) => {
3126
+ if (!sliderElement) return;
3127
+ const rect2 = sliderElement.getBoundingClientRect();
3128
+ const y2 = moveEvent.clientY - rect2.top;
3129
+ const percentage2 = 1 - Math.max(0, Math.min(1, y2 / rect2.height));
3130
+ handleVolumeChange(percentage2);
3131
+ };
3132
+ const handleMouseUp = () => {
3133
+ document.removeEventListener("mousemove", handleMouseMove);
3134
+ document.removeEventListener("mouseup", handleMouseUp);
3135
+ };
3136
+ document.addEventListener("mousemove", handleMouseMove);
3137
+ document.addEventListener("mouseup", handleMouseUp);
3138
+ const rect = sliderElement.getBoundingClientRect();
3139
+ const y = e.clientY - rect.top;
3140
+ const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
3141
+ handleVolumeChange(percentage);
3142
+ },
3143
+ onClick: (e) => {
3144
+ e.stopPropagation();
3145
+ const rect = e.currentTarget.getBoundingClientRect();
3146
+ const y = e.clientY - rect.top;
3147
+ const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
3148
+ handleVolumeChange(percentage);
3149
+ },
3150
+ children: [
3151
+ /* @__PURE__ */ jsx(
3152
+ "div",
3153
+ {
3154
+ style: {
3155
+ position: "absolute",
3156
+ bottom: "0",
3157
+ left: "0",
3158
+ width: "100%",
3159
+ height: "100%",
3160
+ background: "linear-gradient(180deg, rgba(255, 255, 255, 0.85) 0%, rgba(255, 255, 255, 0.5) 100%)",
3161
+ borderRadius: "4px",
3162
+ border: "1px solid rgba(255, 255, 255, 0.4)",
3163
+ boxShadow: "inset 0 1px 3px rgba(0, 0, 0, 0.3)"
3164
+ }
3165
+ }
3166
+ ),
3167
+ /* @__PURE__ */ jsx(
3168
+ "div",
3169
+ {
3170
+ style: {
3171
+ position: "absolute",
3172
+ bottom: "0",
3173
+ left: "0",
3174
+ width: "100%",
3175
+ height: `${(isMuted ? 0 : volume) * 100}%`,
3176
+ background: "linear-gradient(180deg, rgba(125, 211, 252, 1) 0%, rgba(96, 165, 250, 0.98) 50%, rgba(59, 130, 246, 0.95) 100%)",
3177
+ borderRadius: "4px",
3178
+ transition: "height 0.15s ease-out, box-shadow 0.2s ease-in-out",
3179
+ boxShadow: "0 0 12px rgba(96, 165, 250, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.4)"
3180
+ }
3181
+ }
3182
+ ),
3183
+ /* @__PURE__ */ jsx(
3184
+ "div",
3185
+ {
3186
+ style: {
3187
+ position: "absolute",
3188
+ bottom: `calc(${(isMuted ? 0 : volume) * 100}% - 8px)`,
3189
+ left: "50%",
3190
+ transform: "translateX(-50%)",
3191
+ width: "16px",
3192
+ height: "16px",
3193
+ background: "linear-gradient(135deg, #ffffff 0%, #f0f9ff 100%)",
3194
+ borderRadius: "50%",
3195
+ border: "2px solid rgba(96, 165, 250, 0.9)",
3196
+ boxShadow: "0 3px 8px rgba(0, 0, 0, 0.5), 0 0 0 2px rgba(96, 165, 250, 0.4), 0 0 16px rgba(96, 165, 250, 0.5)",
3197
+ transition: "bottom 0.15s ease-out, transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, width 0.2s ease-in-out, height 0.2s ease-in-out",
3198
+ cursor: "grab"
3199
+ },
3200
+ onMouseEnter: (e) => {
3201
+ e.currentTarget.style.transform = "translateX(-50%) scale(1.35)";
3202
+ e.currentTarget.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.6), 0 0 0 3px rgba(96, 165, 250, 0.6), 0 0 24px rgba(96, 165, 250, 0.7)";
3203
+ e.currentTarget.style.cursor = "grab";
3204
+ },
3205
+ onMouseLeave: (e) => {
3206
+ e.currentTarget.style.transform = "translateX(-50%) scale(1)";
3207
+ e.currentTarget.style.boxShadow = "0 3px 8px rgba(0, 0, 0, 0.5), 0 0 0 2px rgba(96, 165, 250, 0.4), 0 0 16px rgba(96, 165, 250, 0.5)";
3208
+ },
3209
+ onMouseDown: (e) => {
3210
+ e.currentTarget.style.transform = "translateX(-50%) scale(1.45)";
3211
+ e.currentTarget.style.cursor = "grabbing";
3212
+ },
3213
+ onMouseUp: (e) => {
3214
+ e.currentTarget.style.transform = "translateX(-50%) scale(1.35)";
3215
+ e.currentTarget.style.cursor = "grab";
3216
+ }
3217
+ }
3218
+ )
3219
+ ]
2923
3220
  }
2924
3221
  )
2925
3222
  }