@djangocfg/ui-tools 2.1.310 → 2.1.313

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.
Files changed (161) hide show
  1. package/README.md +38 -22
  2. package/dist/{DocsLayout-W5JLRNSZ.mjs → DocsLayout-ESVQZO3V.mjs} +3 -3
  3. package/dist/{DocsLayout-W5JLRNSZ.mjs.map → DocsLayout-ESVQZO3V.mjs.map} +1 -1
  4. package/dist/{DocsLayout-ZXD2CUOH.cjs → DocsLayout-KUPDWJ3G.cjs} +48 -48
  5. package/dist/{DocsLayout-ZXD2CUOH.cjs.map → DocsLayout-KUPDWJ3G.cjs.map} +1 -1
  6. package/dist/Player-M3GC3VPE.mjs +4 -0
  7. package/dist/Player-M3GC3VPE.mjs.map +1 -0
  8. package/dist/Player-ZGQKKOWI.css +65 -0
  9. package/dist/Player-ZGQKKOWI.css.map +1 -0
  10. package/dist/Player-ZL2X5LGG.cjs +13 -0
  11. package/dist/Player-ZL2X5LGG.cjs.map +1 -0
  12. package/dist/{chunk-CXVGN6ZW.cjs → chunk-DFTVB66S.cjs} +7 -6
  13. package/dist/chunk-DFTVB66S.cjs.map +1 -0
  14. package/dist/{chunk-2QY3LJR6.mjs → chunk-EUADAUBQ.mjs} +5 -4
  15. package/dist/chunk-EUADAUBQ.mjs.map +1 -0
  16. package/dist/chunk-FX2QFYWF.mjs +2059 -0
  17. package/dist/chunk-FX2QFYWF.mjs.map +1 -0
  18. package/dist/{chunk-6HNAPVZ2.mjs → chunk-GBLQTHWT.mjs} +11 -13
  19. package/dist/chunk-GBLQTHWT.mjs.map +1 -0
  20. package/dist/{chunk-FYLR232K.cjs → chunk-S44PW6NK.cjs} +11 -13
  21. package/dist/chunk-S44PW6NK.cjs.map +1 -0
  22. package/dist/chunk-ZLQHUZDU.cjs +2061 -0
  23. package/dist/chunk-ZLQHUZDU.cjs.map +1 -0
  24. package/dist/components-WYEZL5TE.cjs +26 -0
  25. package/dist/{components-3RTH76CV.cjs.map → components-WYEZL5TE.cjs.map} +1 -1
  26. package/dist/components-ZAGG2PBO.mjs +5 -0
  27. package/dist/{components-5GVVL2Q6.mjs.map → components-ZAGG2PBO.mjs.map} +1 -1
  28. package/dist/index.cjs +36 -220
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.css +65 -0
  31. package/dist/index.css.map +1 -1
  32. package/dist/index.d.cts +44 -500
  33. package/dist/index.d.ts +44 -500
  34. package/dist/index.mjs +16 -62
  35. package/dist/index.mjs.map +1 -1
  36. package/package.json +6 -6
  37. package/src/components/markdown/MarkdownMessage/ActionRow.tsx +48 -0
  38. package/src/components/markdown/MarkdownMessage/ChatMessageRow.tsx +97 -0
  39. package/src/components/markdown/MarkdownMessage/CodeBlock.tsx +9 -13
  40. package/src/components/markdown/MarkdownMessage/MarkdownMessage.story.tsx +77 -2
  41. package/src/components/markdown/MarkdownMessage/MarkdownMessage.tsx +2 -3
  42. package/src/components/markdown/MarkdownMessage/README.md +72 -0
  43. package/src/components/markdown/MarkdownMessage/components.tsx +3 -3
  44. package/src/components/markdown/MarkdownMessage/index.ts +6 -0
  45. package/src/index.ts +2 -11
  46. package/src/tools/AudioPlayer/AudioPlayer.story.tsx +454 -107
  47. package/src/tools/AudioPlayer/Player.tsx +80 -0
  48. package/src/tools/AudioPlayer/PlayerShell.tsx +122 -0
  49. package/src/tools/AudioPlayer/README.md +139 -204
  50. package/src/tools/AudioPlayer/audio/audioContext.ts +39 -0
  51. package/src/tools/AudioPlayer/audio/decodePeaks.ts +36 -0
  52. package/src/tools/AudioPlayer/audio/index.ts +4 -0
  53. package/src/tools/AudioPlayer/audio/mediaElementSourceCache.ts +20 -0
  54. package/src/tools/AudioPlayer/audio/peaksCache.ts +37 -0
  55. package/src/tools/AudioPlayer/context/AudioRefContext.tsx +9 -0
  56. package/src/tools/AudioPlayer/context/ControlsContext.tsx +7 -0
  57. package/src/tools/AudioPlayer/context/LevelsContext.tsx +7 -0
  58. package/src/tools/AudioPlayer/context/MetaContext.tsx +16 -0
  59. package/src/tools/AudioPlayer/context/PlayerProvider.tsx +314 -0
  60. package/src/tools/AudioPlayer/context/StateContext.tsx +7 -0
  61. package/src/tools/AudioPlayer/context/index.ts +16 -15
  62. package/src/tools/AudioPlayer/context/selectors.ts +36 -0
  63. package/src/tools/AudioPlayer/hooks/index.ts +12 -39
  64. package/src/tools/AudioPlayer/hooks/useActivePlayer.ts +31 -0
  65. package/src/tools/AudioPlayer/hooks/useAnalyser.ts +62 -0
  66. package/src/tools/AudioPlayer/hooks/useAudioElementEvents.ts +102 -0
  67. package/src/tools/AudioPlayer/hooks/useKeyboardShortcuts.ts +91 -0
  68. package/src/tools/AudioPlayer/hooks/useMediaSession.ts +74 -0
  69. package/src/tools/AudioPlayer/hooks/usePeaks.ts +83 -0
  70. package/src/tools/AudioPlayer/hooks/usePlayerPreferences.ts +21 -0
  71. package/src/tools/AudioPlayer/hooks/usePlayheadLoop.ts +77 -0
  72. package/src/tools/AudioPlayer/hooks/useResizeObserver.ts +20 -0
  73. package/src/tools/AudioPlayer/hooks/useThemeWatcher.ts +22 -0
  74. package/src/tools/AudioPlayer/index.ts +63 -134
  75. package/src/tools/AudioPlayer/lazy.tsx +8 -97
  76. package/src/tools/AudioPlayer/parts/Controls/ControlsRow.tsx +30 -0
  77. package/src/tools/AudioPlayer/parts/Controls/IconButton.tsx +62 -0
  78. package/src/tools/AudioPlayer/parts/Controls/LoopButton.tsx +33 -0
  79. package/src/tools/AudioPlayer/parts/Controls/PlayButton.tsx +86 -0
  80. package/src/tools/AudioPlayer/parts/Controls/SkipButton.tsx +17 -0
  81. package/src/tools/AudioPlayer/parts/Controls/VolumeControl.tsx +171 -0
  82. package/src/tools/AudioPlayer/parts/Controls/index.ts +6 -0
  83. package/src/tools/AudioPlayer/parts/Cover/Cover.tsx +24 -0
  84. package/src/tools/AudioPlayer/parts/Cover/CoverPlaceholder.tsx +27 -0
  85. package/src/tools/AudioPlayer/parts/Cover/ReactivePulse.tsx +66 -0
  86. package/src/tools/AudioPlayer/parts/Cover/index.ts +3 -0
  87. package/src/tools/AudioPlayer/parts/ErrorState/ErrorState.tsx +35 -0
  88. package/src/tools/AudioPlayer/parts/ErrorState/index.ts +1 -0
  89. package/src/tools/AudioPlayer/parts/Layout/CompactLayout.tsx +25 -0
  90. package/src/tools/AudioPlayer/parts/Layout/DefaultLayout.tsx +48 -0
  91. package/src/tools/AudioPlayer/parts/Layout/index.ts +2 -0
  92. package/src/tools/AudioPlayer/parts/Meta/Artist.tsx +14 -0
  93. package/src/tools/AudioPlayer/parts/Meta/TimeDisplay.tsx +49 -0
  94. package/src/tools/AudioPlayer/parts/Meta/Title.tsx +13 -0
  95. package/src/tools/AudioPlayer/parts/Meta/index.ts +3 -0
  96. package/src/tools/AudioPlayer/parts/Skeleton/CoverSkeleton.tsx +13 -0
  97. package/src/tools/AudioPlayer/parts/Skeleton/MetaSkeleton.tsx +10 -0
  98. package/src/tools/AudioPlayer/parts/Skeleton/index.ts +2 -0
  99. package/src/tools/AudioPlayer/parts/Waveform/BarsWaveform.tsx +48 -0
  100. package/src/tools/AudioPlayer/parts/Waveform/LiveWaveform.tsx +95 -0
  101. package/src/tools/AudioPlayer/parts/Waveform/PeaksWaveform.tsx +100 -0
  102. package/src/tools/AudioPlayer/parts/Waveform/ProgressBar.tsx +76 -0
  103. package/src/tools/AudioPlayer/parts/Waveform/Waveform.tsx +74 -0
  104. package/src/tools/AudioPlayer/parts/Waveform/WaveformSkeleton.tsx +16 -0
  105. package/src/tools/AudioPlayer/parts/Waveform/index.ts +8 -0
  106. package/src/tools/AudioPlayer/parts/Waveform/waveformInteraction.ts +106 -0
  107. package/src/tools/AudioPlayer/parts/Waveform/waveformRenderer.ts +91 -0
  108. package/src/tools/AudioPlayer/parts/index.ts +1 -0
  109. package/src/tools/AudioPlayer/store/activePlayerBus.ts +63 -0
  110. package/src/tools/AudioPlayer/store/createLevelsStore.ts +37 -0
  111. package/src/tools/AudioPlayer/store/index.ts +16 -0
  112. package/src/tools/AudioPlayer/store/preferencesStore.ts +104 -0
  113. package/src/tools/AudioPlayer/styles/webview-safe.css +77 -0
  114. package/src/tools/AudioPlayer/types.ts +95 -0
  115. package/src/tools/AudioPlayer/utils/bucketize.ts +27 -0
  116. package/src/tools/AudioPlayer/utils/clamp.ts +5 -0
  117. package/src/tools/AudioPlayer/utils/dpr.ts +19 -0
  118. package/src/tools/AudioPlayer/utils/formatTime.ts +12 -8
  119. package/src/tools/AudioPlayer/utils/index.ts +4 -5
  120. package/src/tools/AudioPlayer/utils/readCssVar.ts +7 -0
  121. package/src/tools/AudioPlayer/utils/resolveCanvasColor.ts +28 -0
  122. package/src/tools/index.ts +5 -75
  123. package/dist/chunk-2QY3LJR6.mjs.map +0 -1
  124. package/dist/chunk-6HNAPVZ2.mjs.map +0 -1
  125. package/dist/chunk-CXVGN6ZW.cjs.map +0 -1
  126. package/dist/chunk-F2N7P5XU.cjs +0 -30
  127. package/dist/chunk-F2N7P5XU.cjs.map +0 -1
  128. package/dist/chunk-FYLR232K.cjs.map +0 -1
  129. package/dist/chunk-HMHIVEMS.mjs +0 -1619
  130. package/dist/chunk-HMHIVEMS.mjs.map +0 -1
  131. package/dist/chunk-JWB2EWQO.mjs +0 -5
  132. package/dist/chunk-JWB2EWQO.mjs.map +0 -1
  133. package/dist/chunk-YZX6FH3H.cjs +0 -1656
  134. package/dist/chunk-YZX6FH3H.cjs.map +0 -1
  135. package/dist/components-3RTH76CV.cjs +0 -27
  136. package/dist/components-5GVVL2Q6.mjs +0 -5
  137. package/dist/components-CPHOUQ5F.cjs +0 -46
  138. package/dist/components-CPHOUQ5F.cjs.map +0 -1
  139. package/dist/components-OTK43IMD.mjs +0 -6
  140. package/dist/components-OTK43IMD.mjs.map +0 -1
  141. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +0 -225
  142. package/src/tools/AudioPlayer/components/HybridCompactPlayer.tsx +0 -163
  143. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +0 -284
  144. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +0 -286
  145. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +0 -151
  146. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +0 -110
  147. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +0 -58
  148. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +0 -45
  149. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +0 -82
  150. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +0 -8
  151. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +0 -6
  152. package/src/tools/AudioPlayer/components/index.ts +0 -23
  153. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +0 -158
  154. package/src/tools/AudioPlayer/effects/index.ts +0 -412
  155. package/src/tools/AudioPlayer/hooks/useAudioBus.ts +0 -76
  156. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +0 -403
  157. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +0 -96
  158. package/src/tools/AudioPlayer/hooks/useVisualization.tsx +0 -207
  159. package/src/tools/AudioPlayer/types/effects.ts +0 -73
  160. package/src/tools/AudioPlayer/types/index.ts +0 -27
  161. package/src/tools/AudioPlayer/utils/debug.ts +0 -14
@@ -1,1656 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkF2N7P5XU_cjs = require('./chunk-F2N7P5XU.cjs');
4
- var chunkWGEGR3DF_cjs = require('./chunk-WGEGR3DF.cjs');
5
- var react = require('react');
6
- var lucideReact = require('lucide-react');
7
- var i18n = require('@djangocfg/i18n');
8
- var zustand = require('zustand');
9
- var jsxRuntime = require('react/jsx-runtime');
10
- var lib = require('@djangocfg/ui-core/lib');
11
- var palette = require('@djangocfg/ui-core/styles/palette');
12
- var uiCore = require('@djangocfg/ui-core');
13
-
14
- var useAudioBusStore = zustand.create((set) => ({
15
- activeId: null,
16
- setActiveId: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((id) => set({ activeId: id }), "setActiveId")
17
- }));
18
- function useAudioBus(playerId, onStop) {
19
- const onStopRef = react.useRef(onStop);
20
- onStopRef.current = onStop;
21
- const setActiveId = useAudioBusStore((s) => s.setActiveId);
22
- react.useEffect(() => {
23
- return useAudioBusStore.subscribe((state) => {
24
- if (state.activeId !== null && state.activeId !== playerId) {
25
- onStopRef.current();
26
- }
27
- });
28
- }, [playerId]);
29
- const announce = react.useCallback(() => {
30
- setActiveId(playerId);
31
- }, [playerId, setActiveId]);
32
- const release = react.useCallback(() => {
33
- useAudioBusStore.setState((s) => s.activeId === playerId ? { activeId: null } : s);
34
- }, [playerId]);
35
- return { announce, release };
36
- }
37
- chunkWGEGR3DF_cjs.__name(useAudioBus, "useAudioBus");
38
-
39
- // src/tools/AudioPlayer/hooks/useHybridAudio.ts
40
- function useHybridAudio(options) {
41
- const {
42
- src,
43
- autoPlay = false,
44
- initialVolume = 1,
45
- loop = false,
46
- crossOrigin = "anonymous",
47
- excludeFromBus = false,
48
- onPlay,
49
- onPause,
50
- onEnded,
51
- onTimeUpdate,
52
- onError,
53
- onReady
54
- } = options;
55
- const playerId = react.useId();
56
- const audioRef = react.useRef(null);
57
- const audioContextRef = react.useRef(null);
58
- const sourceNodeRef = react.useRef(null);
59
- const analyserRef = react.useRef(null);
60
- const connectedElementRef = react.useRef(null);
61
- const [state, setState] = react.useState({
62
- isReady: false,
63
- isPlaying: false,
64
- currentTime: 0,
65
- duration: 0,
66
- volume: initialVolume,
67
- isMuted: false,
68
- isLooping: loop,
69
- buffered: null,
70
- error: null
71
- });
72
- const initWebAudio = react.useCallback(() => {
73
- const audio = audioRef.current;
74
- if (!audio) return;
75
- if (connectedElementRef.current === audio && audioContextRef.current) {
76
- return;
77
- }
78
- try {
79
- if (!audioContextRef.current) {
80
- const AudioContextClass = window.AudioContext || window.webkitAudioContext;
81
- audioContextRef.current = new AudioContextClass();
82
- }
83
- const ctx = audioContextRef.current;
84
- if (sourceNodeRef.current) {
85
- try {
86
- sourceNodeRef.current.disconnect();
87
- } catch {
88
- }
89
- }
90
- const source = ctx.createMediaElementSource(audio);
91
- sourceNodeRef.current = source;
92
- const analyser = ctx.createAnalyser();
93
- analyser.fftSize = 256;
94
- analyser.smoothingTimeConstant = 0.85;
95
- analyserRef.current = analyser;
96
- source.connect(ctx.destination);
97
- source.connect(analyser);
98
- connectedElementRef.current = audio;
99
- } catch (error) {
100
- console.warn("[useHybridAudio] Web Audio init failed:", error);
101
- }
102
- }, []);
103
- const { announce: busAnnounce, release: busRelease } = useAudioBus(
104
- playerId,
105
- react.useCallback(() => {
106
- if (!excludeFromBus) audioRef.current?.pause();
107
- }, [excludeFromBus])
108
- );
109
- const resumeAudioContext = react.useCallback(async () => {
110
- const ctx = audioContextRef.current;
111
- if (ctx && ctx.state === "suspended") {
112
- await ctx.resume();
113
- }
114
- }, []);
115
- const play = react.useCallback(async () => {
116
- const audio = audioRef.current;
117
- if (!audio) return;
118
- try {
119
- if (!excludeFromBus) busAnnounce();
120
- initWebAudio();
121
- await resumeAudioContext();
122
- await audio.play();
123
- } catch (error) {
124
- console.error("[useHybridAudio] Play failed:", error);
125
- onError?.(error);
126
- }
127
- }, [excludeFromBus, busAnnounce, initWebAudio, resumeAudioContext, onError]);
128
- const pause = react.useCallback(() => {
129
- audioRef.current?.pause();
130
- }, []);
131
- const togglePlay = react.useCallback(() => {
132
- if (state.isPlaying) {
133
- pause();
134
- } else {
135
- play();
136
- }
137
- }, [state.isPlaying, play, pause]);
138
- const seek = react.useCallback(
139
- (time) => {
140
- const audio = audioRef.current;
141
- if (audio && isFinite(time)) {
142
- audio.currentTime = Math.max(0, Math.min(time, state.duration || audio.duration || 0));
143
- }
144
- },
145
- [state.duration]
146
- );
147
- const seekTo = react.useCallback(
148
- (progress) => {
149
- const duration = state.duration || audioRef.current?.duration || 0;
150
- seek(duration * Math.max(0, Math.min(1, progress)));
151
- },
152
- [state.duration, seek]
153
- );
154
- const skip = react.useCallback(
155
- (seconds) => {
156
- seek(state.currentTime + seconds);
157
- },
158
- [state.currentTime, seek]
159
- );
160
- const setVolume = react.useCallback((vol) => {
161
- const audio = audioRef.current;
162
- if (audio) {
163
- const clampedVol = Math.max(0, Math.min(1, vol));
164
- audio.volume = clampedVol;
165
- setState((prev) => ({ ...prev, volume: clampedVol }));
166
- }
167
- }, []);
168
- const toggleMute = react.useCallback(() => {
169
- const audio = audioRef.current;
170
- if (audio) {
171
- audio.muted = !audio.muted;
172
- setState((prev) => ({ ...prev, isMuted: audio.muted }));
173
- }
174
- }, []);
175
- const toggleLoop = react.useCallback(() => {
176
- const audio = audioRef.current;
177
- if (audio) {
178
- audio.loop = !audio.loop;
179
- setState((prev) => ({ ...prev, isLooping: audio.loop }));
180
- }
181
- }, []);
182
- const setLoop = react.useCallback((enabled) => {
183
- const audio = audioRef.current;
184
- if (audio) {
185
- audio.loop = enabled;
186
- setState((prev) => ({ ...prev, isLooping: enabled }));
187
- }
188
- }, []);
189
- const restart = react.useCallback(() => {
190
- seek(0);
191
- play();
192
- }, [seek, play]);
193
- const controls = {
194
- play,
195
- pause,
196
- togglePlay,
197
- seek,
198
- seekTo,
199
- skip,
200
- setVolume,
201
- toggleMute,
202
- toggleLoop,
203
- setLoop,
204
- restart
205
- };
206
- react.useEffect(() => {
207
- const audio = document.createElement("audio");
208
- audio.preload = "metadata";
209
- audio.crossOrigin = crossOrigin;
210
- audio.volume = initialVolume;
211
- audio.loop = loop;
212
- audioRef.current = audio;
213
- return () => {
214
- audio.pause();
215
- audio.src = "";
216
- busRelease();
217
- if (audioContextRef.current) {
218
- audioContextRef.current.close().catch(() => {
219
- });
220
- }
221
- };
222
- }, []);
223
- react.useEffect(() => {
224
- const audio = audioRef.current;
225
- if (!audio) return;
226
- const handlers = {
227
- loadedmetadata: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
228
- setState((prev) => ({
229
- ...prev,
230
- duration: audio.duration,
231
- isReady: true
232
- }));
233
- onReady?.();
234
- }, "loadedmetadata"),
235
- canplay: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
236
- setState((prev) => ({ ...prev, isReady: true }));
237
- if (autoPlay) {
238
- play();
239
- }
240
- }, "canplay"),
241
- play: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
242
- setState((prev) => ({ ...prev, isPlaying: true }));
243
- onPlay?.();
244
- }, "play"),
245
- pause: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
246
- setState((prev) => ({ ...prev, isPlaying: false }));
247
- onPause?.();
248
- }, "pause"),
249
- ended: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
250
- setState((prev) => ({ ...prev, isPlaying: false }));
251
- onEnded?.();
252
- }, "ended"),
253
- timeupdate: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
254
- setState((prev) => ({ ...prev, currentTime: audio.currentTime }));
255
- onTimeUpdate?.(audio.currentTime);
256
- }, "timeupdate"),
257
- progress: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
258
- setState((prev) => ({ ...prev, buffered: audio.buffered }));
259
- }, "progress"),
260
- error: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
261
- const error = new Error(audio.error?.message || "Audio error");
262
- setState((prev) => ({ ...prev, error }));
263
- onError?.(error);
264
- }, "error"),
265
- volumechange: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
266
- setState((prev) => ({
267
- ...prev,
268
- volume: audio.volume,
269
- isMuted: audio.muted
270
- }));
271
- }, "volumechange")
272
- };
273
- Object.entries(handlers).forEach(([event, handler]) => {
274
- audio.addEventListener(event, handler);
275
- });
276
- return () => {
277
- Object.entries(handlers).forEach(([event, handler]) => {
278
- audio.removeEventListener(event, handler);
279
- });
280
- };
281
- }, [autoPlay, onPlay, onPause, onEnded, onTimeUpdate, onError, onReady, play]);
282
- react.useEffect(() => {
283
- const audio = audioRef.current;
284
- if (!audio || !src) return;
285
- setState((prev) => ({
286
- ...prev,
287
- isReady: false,
288
- currentTime: 0,
289
- duration: 0,
290
- error: null
291
- }));
292
- audio.src = src;
293
- audio.load();
294
- }, [src]);
295
- return {
296
- audioRef,
297
- state,
298
- controls,
299
- webAudio: {
300
- context: audioContextRef.current,
301
- analyser: analyserRef.current,
302
- sourceNode: sourceNodeRef.current
303
- }
304
- };
305
- }
306
- chunkWGEGR3DF_cjs.__name(useHybridAudio, "useHybridAudio");
307
- function useHybridAudioAnalysis(analyser, isPlaying) {
308
- const [levels, setLevels] = react.useState({ bass: 0, mid: 0, high: 0, overall: 0 });
309
- const animationRef = react.useRef(null);
310
- const dataArrayRef = react.useRef(null);
311
- const cleanup = react.useCallback(() => {
312
- if (animationRef.current) {
313
- cancelAnimationFrame(animationRef.current);
314
- animationRef.current = null;
315
- }
316
- }, []);
317
- react.useEffect(() => {
318
- if (analyser && !dataArrayRef.current) {
319
- dataArrayRef.current = new Uint8Array(analyser.frequencyBinCount);
320
- }
321
- }, [analyser]);
322
- react.useEffect(() => {
323
- if (!isPlaying || !analyser || !dataArrayRef.current) {
324
- cleanup();
325
- setLevels((prev) => ({
326
- bass: prev.bass * 0.95 < 0.01 ? 0 : prev.bass * 0.95,
327
- mid: prev.mid * 0.95 < 0.01 ? 0 : prev.mid * 0.95,
328
- high: prev.high * 0.95 < 0.01 ? 0 : prev.high * 0.95,
329
- overall: prev.overall * 0.95 < 0.01 ? 0 : prev.overall * 0.95
330
- }));
331
- return;
332
- }
333
- const dataArray = dataArrayRef.current;
334
- const animate = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
335
- analyser.getByteFrequencyData(dataArray);
336
- const binCount = dataArray.length;
337
- const bassEnd = Math.floor(binCount * 0.15);
338
- let bassSum = 0;
339
- for (let i = 0; i < bassEnd; i++) bassSum += dataArray[i];
340
- const bass = bassSum / bassEnd / 255;
341
- const midStart = bassEnd;
342
- const midEnd = Math.floor(binCount * 0.5);
343
- let midSum = 0;
344
- for (let i = midStart; i < midEnd; i++) midSum += dataArray[i];
345
- const mid = midSum / (midEnd - midStart) / 255;
346
- const highStart = midEnd;
347
- let highSum = 0;
348
- for (let i = highStart; i < binCount; i++) highSum += dataArray[i];
349
- const high = highSum / (binCount - highStart) / 255;
350
- let totalSum = 0;
351
- for (let i = 0; i < binCount; i++) totalSum += dataArray[i];
352
- const overall = totalSum / binCount / 255;
353
- setLevels((prev) => ({
354
- bass: prev.bass * 0.7 + bass * 0.3,
355
- mid: prev.mid * 0.7 + mid * 0.3,
356
- high: prev.high * 0.7 + high * 0.3,
357
- overall: prev.overall * 0.7 + overall * 0.3
358
- }));
359
- animationRef.current = requestAnimationFrame(animate);
360
- }, "animate");
361
- animationRef.current = requestAnimationFrame(animate);
362
- return cleanup;
363
- }, [analyser, isPlaying, cleanup]);
364
- return levels;
365
- }
366
- chunkWGEGR3DF_cjs.__name(useHybridAudioAnalysis, "useHybridAudioAnalysis");
367
- var STORAGE_KEY = "audio-player-settings";
368
- var DEFAULT_SETTINGS = {
369
- enabled: true,
370
- variant: "spotlight",
371
- intensity: "medium",
372
- colorScheme: "primary",
373
- volume: 1,
374
- isLooping: false
375
- };
376
- var VARIANTS = ["spotlight", "glow", "orbs", "mesh", "none"];
377
- var INTENSITIES = ["subtle", "medium", "strong"];
378
- var COLOR_SCHEMES = ["primary", "vibrant", "cool", "warm"];
379
- var VisualizationContext = react.createContext(null);
380
- function VisualizationProvider({ children }) {
381
- const value = useVisualizationState();
382
- return /* @__PURE__ */ jsxRuntime.jsx(VisualizationContext.Provider, { value, children });
383
- }
384
- chunkWGEGR3DF_cjs.__name(VisualizationProvider, "VisualizationProvider");
385
- function useVisualizationState() {
386
- const [settings, setSettings] = chunkF2N7P5XU_cjs.useLocalStorage(
387
- STORAGE_KEY,
388
- DEFAULT_SETTINGS
389
- );
390
- const toggle = react.useCallback(() => {
391
- setSettings((prev) => ({ ...prev, enabled: !prev.enabled }));
392
- }, [setSettings]);
393
- const setSetting = react.useCallback(
394
- (key, value) => {
395
- setSettings((prev) => ({ ...prev, [key]: value }));
396
- },
397
- [setSettings]
398
- );
399
- const nextVariant = react.useCallback(() => {
400
- setSettings((prev) => {
401
- const currentIndex = VARIANTS.indexOf(prev.variant);
402
- const nextIndex = (currentIndex + 1) % VARIANTS.length;
403
- return { ...prev, variant: VARIANTS[nextIndex] };
404
- });
405
- }, [setSettings]);
406
- const nextIntensity = react.useCallback(() => {
407
- setSettings((prev) => {
408
- const currentIndex = INTENSITIES.indexOf(prev.intensity);
409
- const nextIndex = (currentIndex + 1) % INTENSITIES.length;
410
- return { ...prev, intensity: INTENSITIES[nextIndex] };
411
- });
412
- }, [setSettings]);
413
- const nextColorScheme = react.useCallback(() => {
414
- setSettings((prev) => {
415
- const currentIndex = COLOR_SCHEMES.indexOf(prev.colorScheme);
416
- const nextIndex = (currentIndex + 1) % COLOR_SCHEMES.length;
417
- return { ...prev, colorScheme: COLOR_SCHEMES[nextIndex] };
418
- });
419
- }, [setSettings]);
420
- const reset = react.useCallback(() => {
421
- setSettings(DEFAULT_SETTINGS);
422
- }, [setSettings]);
423
- return react.useMemo(
424
- () => ({
425
- settings,
426
- toggle,
427
- setSetting,
428
- nextVariant,
429
- nextIntensity,
430
- nextColorScheme,
431
- reset
432
- }),
433
- [settings, toggle, setSetting, nextVariant, nextIntensity, nextColorScheme, reset]
434
- );
435
- }
436
- chunkWGEGR3DF_cjs.__name(useVisualizationState, "useVisualizationState");
437
- function useVisualization() {
438
- const context = react.useContext(VisualizationContext);
439
- const fallbackState = useVisualizationState();
440
- return context ?? fallbackState;
441
- }
442
- chunkWGEGR3DF_cjs.__name(useVisualization, "useVisualization");
443
- var useAudioVisualization = useVisualization;
444
- var VARIANT_INFO = {
445
- spotlight: { label: "Spotlight", icon: "\u{1F4AB}" },
446
- glow: { label: "Glow", icon: "\u2728" },
447
- orbs: { label: "Orbs", icon: "\u{1F52E}" },
448
- mesh: { label: "Mesh", icon: "\u{1F308}" },
449
- none: { label: "Off", icon: "\u2B55" }
450
- };
451
- var INTENSITY_INFO = {
452
- subtle: { label: "Subtle" },
453
- medium: { label: "Medium" },
454
- strong: { label: "Strong" }
455
- };
456
- var COLOR_SCHEME_INFO = {
457
- primary: { label: "Primary", preview: "\u{1F535}" },
458
- vibrant: { label: "Vibrant", preview: "\u{1F308}" },
459
- cool: { label: "Cool", preview: "\u{1F499}" },
460
- warm: { label: "Warm", preview: "\u{1F525}" }
461
- };
462
- var HybridAudioContext = react.createContext(null);
463
- function HybridAudioProvider({ children, ...options }) {
464
- const { settings: savedSettings, setSetting } = useVisualization();
465
- const effectiveOptions = {
466
- ...options,
467
- initialVolume: savedSettings.volume,
468
- loop: savedSettings.isLooping
469
- };
470
- const { audioRef, state, controls, webAudio } = useHybridAudio(effectiveOptions);
471
- const hasAppliedInitialSettings = react.useRef(false);
472
- react.useEffect(() => {
473
- if (!state.isReady || hasAppliedInitialSettings.current) return;
474
- hasAppliedInitialSettings.current = true;
475
- controls.setVolume(savedSettings.volume);
476
- controls.setLoop(savedSettings.isLooping);
477
- }, [state.isReady, savedSettings, controls]);
478
- react.useEffect(() => {
479
- if (!state.isReady) return;
480
- if (state.volume !== savedSettings.volume) {
481
- setSetting("volume", state.volume);
482
- }
483
- if (state.isLooping !== savedSettings.isLooping) {
484
- setSetting("isLooping", state.isLooping);
485
- }
486
- }, [state.isReady, state.volume, state.isLooping, savedSettings, setSetting]);
487
- const audioLevels = useHybridAudioAnalysis(webAudio.analyser, state.isPlaying);
488
- const value = react.useMemo(
489
- () => ({
490
- state,
491
- controls,
492
- webAudio,
493
- audioLevels,
494
- audioRef
495
- }),
496
- [state, controls, webAudio, audioLevels, audioRef]
497
- );
498
- return /* @__PURE__ */ jsxRuntime.jsx(HybridAudioContext.Provider, { value, children });
499
- }
500
- chunkWGEGR3DF_cjs.__name(HybridAudioProvider, "HybridAudioProvider");
501
- function useHybridAudioContext() {
502
- const context = react.useContext(HybridAudioContext);
503
- if (!context) {
504
- throw new Error("useHybridAudioContext must be used within HybridAudioProvider");
505
- }
506
- return context;
507
- }
508
- chunkWGEGR3DF_cjs.__name(useHybridAudioContext, "useHybridAudioContext");
509
- function useHybridAudioState() {
510
- const { state } = useHybridAudioContext();
511
- return state;
512
- }
513
- chunkWGEGR3DF_cjs.__name(useHybridAudioState, "useHybridAudioState");
514
- function useHybridAudioControls() {
515
- const { controls } = useHybridAudioContext();
516
- return controls;
517
- }
518
- chunkWGEGR3DF_cjs.__name(useHybridAudioControls, "useHybridAudioControls");
519
- function useHybridAudioLevels() {
520
- const { audioLevels } = useHybridAudioContext();
521
- return audioLevels;
522
- }
523
- chunkWGEGR3DF_cjs.__name(useHybridAudioLevels, "useHybridAudioLevels");
524
- function useHybridWebAudio() {
525
- const { webAudio } = useHybridAudioContext();
526
- return webAudio;
527
- }
528
- chunkWGEGR3DF_cjs.__name(useHybridWebAudio, "useHybridWebAudio");
529
- var HybridWaveform = react.memo(/* @__PURE__ */ chunkWGEGR3DF_cjs.__name(function HybridWaveform2({
530
- mode = "frequency",
531
- height = 64,
532
- barWidth = 3,
533
- barGap = 2,
534
- barRadius = 2,
535
- progressColor,
536
- waveColor,
537
- bufferedColor,
538
- className,
539
- onSeek
540
- }) {
541
- const themePrimary = palette.useThemeColor("primary");
542
- const themePrimaryWave = palette.useThemeColor("primary", 0.3);
543
- const themePrimaryBuffered = palette.useThemeColor("primary", 0.15);
544
- const resolvedProgressColor = progressColor ?? themePrimary;
545
- const resolvedWaveColor = waveColor ?? themePrimaryWave;
546
- const resolvedBufferedColor = bufferedColor ?? themePrimaryBuffered;
547
- const canvasRef = react.useRef(null);
548
- const containerRef = react.useRef(null);
549
- const animationRef = react.useRef(null);
550
- const { state, controls, webAudio } = useHybridAudioContext();
551
- const handleClick = react.useCallback(
552
- (e) => {
553
- const canvas = canvasRef.current;
554
- if (!canvas || !state.duration) return;
555
- const rect = canvas.getBoundingClientRect();
556
- const x = e.clientX - rect.left;
557
- const progress = x / rect.width;
558
- const time = state.duration * progress;
559
- controls.seek(time);
560
- onSeek?.(time);
561
- },
562
- [state.duration, controls, onSeek]
563
- );
564
- const renderFrequency = react.useCallback(() => {
565
- const canvas = canvasRef.current;
566
- const analyser = webAudio.analyser;
567
- if (!canvas) return;
568
- const ctx = canvas.getContext("2d");
569
- if (!ctx) return;
570
- const { width, height: canvasHeight } = canvas;
571
- const dpr = window.devicePixelRatio || 1;
572
- const displayWidth = width / dpr;
573
- let dataArray = null;
574
- if (analyser) {
575
- dataArray = new Uint8Array(analyser.frequencyBinCount);
576
- analyser.getByteFrequencyData(dataArray);
577
- }
578
- ctx.clearRect(0, 0, width, canvasHeight);
579
- if (state.buffered && state.duration > 0) {
580
- ctx.fillStyle = resolvedBufferedColor;
581
- for (let i = 0; i < state.buffered.length; i++) {
582
- const start = state.buffered.start(i) / state.duration * width;
583
- const end = state.buffered.end(i) / state.duration * width;
584
- ctx.fillRect(start, canvasHeight - 3 * dpr, end - start, 3 * dpr);
585
- }
586
- }
587
- const barCount = Math.floor(displayWidth / (barWidth + barGap));
588
- const progress = state.duration > 0 ? state.currentTime / state.duration : 0;
589
- const progressX = width * progress;
590
- for (let i = 0; i < barCount; i++) {
591
- let barHeight;
592
- if (dataArray && state.isPlaying) {
593
- const step = Math.floor(dataArray.length / barCount);
594
- const value = dataArray[i * step] / 255;
595
- barHeight = Math.max(4 * dpr, value * (canvasHeight - 6 * dpr) * 0.9);
596
- } else {
597
- barHeight = 8 * dpr;
598
- }
599
- const x = i * (barWidth + barGap) * dpr;
600
- const y = (canvasHeight - barHeight) / 2;
601
- ctx.fillStyle = x < progressX ? resolvedProgressColor : resolvedWaveColor;
602
- const radius = barRadius * dpr;
603
- const rectWidth = barWidth * dpr;
604
- ctx.beginPath();
605
- ctx.roundRect(x, y, rectWidth, barHeight, radius);
606
- ctx.fill();
607
- }
608
- if (state.isPlaying) {
609
- animationRef.current = requestAnimationFrame(renderFrequency);
610
- }
611
- }, [
612
- webAudio.analyser,
613
- state.buffered,
614
- state.duration,
615
- state.currentTime,
616
- state.isPlaying,
617
- barWidth,
618
- barGap,
619
- barRadius,
620
- resolvedProgressColor,
621
- resolvedWaveColor,
622
- resolvedBufferedColor
623
- ]);
624
- const renderStatic = react.useCallback(() => {
625
- const canvas = canvasRef.current;
626
- if (!canvas) return;
627
- const ctx = canvas.getContext("2d");
628
- if (!ctx) return;
629
- const { width, height: canvasHeight } = canvas;
630
- const dpr = window.devicePixelRatio || 1;
631
- ctx.clearRect(0, 0, width, canvasHeight);
632
- const progress = state.duration > 0 ? state.currentTime / state.duration : 0;
633
- const progressWidth = width * progress;
634
- ctx.fillStyle = resolvedWaveColor;
635
- ctx.fillRect(0, canvasHeight / 2 - 2 * dpr, width, 4 * dpr);
636
- if (state.buffered && state.duration > 0) {
637
- ctx.fillStyle = resolvedBufferedColor;
638
- for (let i = 0; i < state.buffered.length; i++) {
639
- const start = state.buffered.start(i) / state.duration * width;
640
- const end = state.buffered.end(i) / state.duration * width;
641
- ctx.fillRect(start, canvasHeight - 2 * dpr, end - start, 2 * dpr);
642
- }
643
- }
644
- ctx.fillStyle = resolvedProgressColor;
645
- ctx.fillRect(0, canvasHeight / 2 - 2 * dpr, progressWidth, 4 * dpr);
646
- if (progress > 0) {
647
- ctx.beginPath();
648
- ctx.arc(progressWidth, canvasHeight / 2, 6 * dpr, 0, Math.PI * 2);
649
- ctx.fill();
650
- }
651
- }, [state.buffered, state.duration, state.currentTime, resolvedProgressColor, resolvedWaveColor, resolvedBufferedColor]);
652
- react.useEffect(() => {
653
- const container = containerRef.current;
654
- const canvas = canvasRef.current;
655
- if (!container || !canvas) return;
656
- const resizeObserver = new ResizeObserver((entries) => {
657
- const entry = entries[0];
658
- if (!entry) return;
659
- const dpr = window.devicePixelRatio || 1;
660
- const displayWidth = entry.contentRect.width;
661
- const displayHeight = height;
662
- canvas.width = displayWidth * dpr;
663
- canvas.height = displayHeight * dpr;
664
- canvas.style.width = `${displayWidth}px`;
665
- canvas.style.height = `${displayHeight}px`;
666
- if (mode === "frequency") {
667
- renderFrequency();
668
- } else {
669
- renderStatic();
670
- }
671
- });
672
- resizeObserver.observe(container);
673
- return () => resizeObserver.disconnect();
674
- }, [height, mode, renderFrequency, renderStatic]);
675
- react.useEffect(() => {
676
- if (mode === "frequency") {
677
- renderFrequency();
678
- }
679
- return () => {
680
- if (animationRef.current) {
681
- cancelAnimationFrame(animationRef.current);
682
- }
683
- };
684
- }, [mode, renderFrequency]);
685
- react.useEffect(() => {
686
- if (mode === "static") {
687
- renderStatic();
688
- }
689
- }, [mode, state.currentTime, renderStatic]);
690
- react.useEffect(() => {
691
- if (mode === "frequency" && !state.isPlaying) {
692
- renderFrequency();
693
- }
694
- }, [mode, state.isPlaying, renderFrequency]);
695
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: lib.cn("w-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
696
- "canvas",
697
- {
698
- ref: canvasRef,
699
- onClick: handleClick,
700
- className: "cursor-pointer",
701
- style: { width: "100%", height }
702
- }
703
- ) });
704
- }, "HybridWaveform"));
705
-
706
- // src/tools/AudioPlayer/utils/formatTime.ts
707
- function formatTime(seconds) {
708
- if (!seconds || !isFinite(seconds) || seconds < 0) return "0:00";
709
- const mins = Math.floor(seconds / 60);
710
- const secs = Math.floor(seconds % 60);
711
- return `${mins}:${secs.toString().padStart(2, "0")}`;
712
- }
713
- chunkWGEGR3DF_cjs.__name(formatTime, "formatTime");
714
- lib.createMediaLogger("AudioPlayer");
715
- var HybridAudioPlayer = react.memo(/* @__PURE__ */ chunkWGEGR3DF_cjs.__name(function HybridAudioPlayer2({
716
- showControls = true,
717
- showWaveform = true,
718
- waveformMode = "frequency",
719
- waveformHeight = 64,
720
- showTimer = true,
721
- showVolume = true,
722
- showLoop = true,
723
- className,
724
- style
725
- }) {
726
- const t = i18n.useAppT();
727
- const { state, controls } = useHybridAudioContext();
728
- const labels = react.useMemo(() => ({
729
- restart: t("tools.audio.restart"),
730
- back: t("tools.audio.back"),
731
- forward: t("tools.audio.forward"),
732
- volume: t("tools.audio.volume")
733
- }), [t]);
734
- const isLoading = !state.isReady;
735
- const handleVolumeChange = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((value) => {
736
- controls.setVolume(value[0] / 100);
737
- }, "handleVolumeChange");
738
- return /* @__PURE__ */ jsxRuntime.jsxs(
739
- "div",
740
- {
741
- className: chunkF2N7P5XU_cjs.cn("flex flex-col gap-3 p-4 rounded-lg bg-card border", className),
742
- style,
743
- children: [
744
- showWaveform && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
745
- /* @__PURE__ */ jsxRuntime.jsx(
746
- HybridWaveform,
747
- {
748
- mode: waveformMode,
749
- height: waveformHeight,
750
- className: chunkF2N7P5XU_cjs.cn(isLoading && "opacity-50")
751
- }
752
- ),
753
- isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-6 w-6 animate-spin text-primary" }) })
754
- ] }),
755
- showTimer && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between text-xs text-muted-foreground tabular-nums px-1", children: [
756
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatTime(state.currentTime) }),
757
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatTime(state.duration) })
758
- ] }),
759
- showControls && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-1", children: [
760
- /* @__PURE__ */ jsxRuntime.jsx(
761
- chunkF2N7P5XU_cjs.Button,
762
- {
763
- variant: "ghost",
764
- size: "icon",
765
- className: "h-9 w-9",
766
- onClick: controls.restart,
767
- disabled: !state.isReady,
768
- title: labels.restart,
769
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { className: "h-4 w-4" })
770
- }
771
- ),
772
- /* @__PURE__ */ jsxRuntime.jsx(
773
- chunkF2N7P5XU_cjs.Button,
774
- {
775
- variant: "ghost",
776
- size: "icon",
777
- className: "h-9 w-9",
778
- onClick: () => controls.skip(-5),
779
- disabled: !state.isReady,
780
- title: labels.back,
781
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SkipBack, { className: "h-4 w-4" })
782
- }
783
- ),
784
- /* @__PURE__ */ jsxRuntime.jsx(
785
- chunkF2N7P5XU_cjs.Button,
786
- {
787
- variant: "default",
788
- size: "icon",
789
- className: "h-12 w-12 rounded-full",
790
- onClick: controls.togglePlay,
791
- disabled: !state.isReady && !isLoading,
792
- title: state.isPlaying ? "Pause" : "Play",
793
- children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-5 w-5 animate-spin" }) : state.isPlaying ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "h-5 w-5 ml-0.5" })
794
- }
795
- ),
796
- /* @__PURE__ */ jsxRuntime.jsx(
797
- chunkF2N7P5XU_cjs.Button,
798
- {
799
- variant: "ghost",
800
- size: "icon",
801
- className: "h-9 w-9",
802
- onClick: () => controls.skip(5),
803
- disabled: !state.isReady,
804
- title: labels.forward,
805
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SkipForward, { className: "h-4 w-4" })
806
- }
807
- ),
808
- showVolume && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
809
- /* @__PURE__ */ jsxRuntime.jsx(
810
- chunkF2N7P5XU_cjs.Button,
811
- {
812
- variant: "ghost",
813
- size: "icon",
814
- className: "h-9 w-9",
815
- onClick: controls.toggleMute,
816
- title: state.isMuted ? "Unmute" : "Mute",
817
- children: state.isMuted || state.volume === 0 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VolumeX, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Volume2, { className: "h-4 w-4" })
818
- }
819
- ),
820
- /* @__PURE__ */ jsxRuntime.jsx(
821
- chunkF2N7P5XU_cjs.Slider,
822
- {
823
- value: [state.isMuted ? 0 : state.volume * 100],
824
- max: 100,
825
- step: 1,
826
- onValueChange: handleVolumeChange,
827
- className: "w-20",
828
- "aria-label": labels.volume
829
- }
830
- )
831
- ] }),
832
- showLoop && /* @__PURE__ */ jsxRuntime.jsx(
833
- chunkF2N7P5XU_cjs.Button,
834
- {
835
- variant: "ghost",
836
- size: "icon",
837
- className: chunkF2N7P5XU_cjs.cn("h-9 w-9", state.isLooping && "text-primary"),
838
- onClick: controls.toggleLoop,
839
- disabled: !state.isReady,
840
- title: state.isLooping ? "Disable loop" : "Enable loop",
841
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Repeat, { className: "h-4 w-4" })
842
- }
843
- )
844
- ] })
845
- ]
846
- }
847
- );
848
- }, "HybridAudioPlayer"));
849
-
850
- // src/tools/AudioPlayer/effects/index.ts
851
- var INTENSITY_CONFIG = {
852
- subtle: { opacity: 0.3, scale: 0.02, blur: "blur-2xl" },
853
- medium: { opacity: 0.5, scale: 0.04, blur: "blur-xl" },
854
- strong: { opacity: 0.7, scale: 0.06, blur: "blur-lg" }
855
- };
856
- var COLOR_SCHEMES2 = {
857
- primary: ["217 91% 60%"],
858
- vibrant: ["217 91% 60%", "142 76% 36%", "262 83% 58%", "25 95% 53%"],
859
- cool: ["217 91% 60%", "262 83% 58%", "199 89% 48%"],
860
- warm: ["25 95% 53%", "0 84% 60%", "38 92% 50%"]
861
- };
862
- var DEFAULT_GLOW_COLORS = [
863
- "217 91% 60%",
864
- // Blue
865
- "262 83% 58%",
866
- // Purple
867
- "330 81% 60%",
868
- // Pink
869
- "25 95% 53%"
870
- // Orange
871
- ];
872
- function getEffectConfig(intensity) {
873
- return INTENSITY_CONFIG[intensity];
874
- }
875
- chunkWGEGR3DF_cjs.__name(getEffectConfig, "getEffectConfig");
876
- function getColors(colorScheme) {
877
- return COLOR_SCHEMES2[colorScheme];
878
- }
879
- chunkWGEGR3DF_cjs.__name(getColors, "getColors");
880
- function prepareEffectColors(colorScheme, levels) {
881
- const baseColors = COLOR_SCHEMES2[colorScheme];
882
- const colors = baseColors.length > 1 ? baseColors : DEFAULT_GLOW_COLORS;
883
- const hueShift = Math.floor(
884
- levels.bass * 30 + levels.mid * 20 + levels.high * 10
885
- );
886
- return { colors, hueShift };
887
- }
888
- chunkWGEGR3DF_cjs.__name(prepareEffectColors, "prepareEffectColors");
889
- function calculateGlowLayers(levels, config, colors) {
890
- const { bass, mid, high } = levels;
891
- return [
892
- // Layer 1: Bass glow - bottom
893
- {
894
- inset: 60 + bass * 90,
895
- opacity: 1,
896
- scale: 1 + bass * 0.5,
897
- background: `radial-gradient(ellipse 80% 60% at 50% 100%, hsl(${colors[0]} / ${0.4 + bass * 0.4}) 0%, transparent 70%)`,
898
- blur: "blur-3xl"
899
- },
900
- // Layer 2: Mid glow - top
901
- {
902
- inset: 45 + mid * 75,
903
- opacity: 1,
904
- scale: 1 + mid * 0.4,
905
- background: `radial-gradient(ellipse 70% 50% at 50% 0%, hsl(${colors[1] || colors[0]} / ${0.3 + mid * 0.5}) 0%, transparent 70%)`,
906
- blur: "blur-2xl"
907
- },
908
- // Layer 3: High glow - left
909
- {
910
- inset: 30 + high * 60,
911
- opacity: 1,
912
- scale: 1 + high * 0.3,
913
- background: `radial-gradient(ellipse 50% 80% at 0% 50%, hsl(${colors[2] || colors[0]} / ${0.3 + high * 0.4}) 0%, transparent 60%)`,
914
- blur: "blur-2xl"
915
- },
916
- // Layer 4: High glow - right
917
- {
918
- inset: 30 + high * 60,
919
- opacity: 1,
920
- scale: 1 + high * 0.3,
921
- background: `radial-gradient(ellipse 50% 80% at 100% 50%, hsl(${colors[3] || colors[0]} / ${0.3 + high * 0.4}) 0%, transparent 60%)`,
922
- blur: "blur-2xl"
923
- },
924
- // Layer 5: Center pulsing glow
925
- {
926
- inset: 24 + bass * 45,
927
- opacity: 1,
928
- scale: 1 + bass * 0.2,
929
- background: `radial-gradient(circle at 50% 50%, hsl(${colors[0]} / ${0.2 + bass * 0.3}) 0%, hsl(${colors[1] || colors[0]} / ${0.1 + mid * 0.2}) 40%, transparent 70%)`,
930
- blur: "blur-xl",
931
- animation: "glow-breathe 2s ease-in-out infinite"
932
- }
933
- ];
934
- }
935
- chunkWGEGR3DF_cjs.__name(calculateGlowLayers, "calculateGlowLayers");
936
- function calculateOrbs(levels, config, colors, baseSize = 50) {
937
- const { bass, mid, high, overall } = levels;
938
- const size = baseSize * 3;
939
- const bassMove = bass * 30;
940
- const midMove = mid * 25;
941
- const highMove = high * 20;
942
- return [
943
- // Bass orb - top left, big pulses
944
- {
945
- x: -40 + bassMove,
946
- y: -40 - bassMove * 0.5,
947
- size: size * (1 + bass * 1.2),
948
- color: colors[0],
949
- opacity: 0.5 + bass * 0.5,
950
- scale: 1 + bass * 0.6
951
- },
952
- // Mid orb - top right
953
- {
954
- x: 130 - midMove * 0.5,
955
- y: -30 + midMove,
956
- size: size * (0.9 + mid * 1),
957
- color: colors[1] || colors[0],
958
- opacity: 0.5 + mid * 0.5,
959
- scale: 1 + mid * 0.5
960
- },
961
- // High orb - bottom right
962
- {
963
- x: 140 + highMove * 0.3,
964
- y: 120 - highMove,
965
- size: size * (0.8 + high * 0.8),
966
- color: colors[2] || colors[0],
967
- opacity: 0.4 + high * 0.6,
968
- scale: 1 + high * 0.45
969
- },
970
- // Mid orb 2 - bottom left
971
- {
972
- x: -30 - midMove * 0.4,
973
- y: 130 + midMove * 0.3,
974
- size: size * (0.9 + mid * 0.9),
975
- color: colors[3] || colors[0],
976
- opacity: 0.45 + mid * 0.55,
977
- scale: 1 + mid * 0.5
978
- },
979
- // Center overall orb
980
- {
981
- x: 50,
982
- y: 50,
983
- size: size * (0.6 + overall * 1.5),
984
- color: colors[0],
985
- opacity: 0.3 + overall * 0.5,
986
- scale: 1 + overall * 0.7
987
- }
988
- ];
989
- }
990
- chunkWGEGR3DF_cjs.__name(calculateOrbs, "calculateOrbs");
991
- function calculateMeshGradients(levels, config, colors) {
992
- const { bass, mid, high, overall } = levels;
993
- const bassOffset = bass * 40;
994
- const midOffset = mid * 30;
995
- const highOffset = high * 25;
996
- return [
997
- // Large bass blob - top right, pulses hard
998
- {
999
- width: `${200 + bass * 150}%`,
1000
- height: `${200 + bass * 150}%`,
1001
- top: `${ -80 + bassOffset}%`,
1002
- right: `${ -80 - bassOffset}%`,
1003
- color: colors[0],
1004
- opacity: 0.4 + bass * 0.6,
1005
- scale: 1 + bass * 0.5,
1006
- rotation: bass * 45,
1007
- blur: "blur-2xl"
1008
- },
1009
- // Mid blob - bottom left
1010
- {
1011
- width: `${180 + mid * 120}%`,
1012
- height: `${180 + mid * 120}%`,
1013
- bottom: `${ -60 + midOffset}%`,
1014
- left: `${ -60 - midOffset}%`,
1015
- color: colors[1] || colors[0],
1016
- opacity: 0.4 + mid * 0.6,
1017
- scale: 1 + mid * 0.4,
1018
- rotation: -mid * 40,
1019
- blur: "blur-2xl"
1020
- },
1021
- // High blob - bottom right
1022
- {
1023
- width: `${140 + high * 100}%`,
1024
- height: `${140 + high * 100}%`,
1025
- top: `${70 - highOffset}%`,
1026
- right: `${ -50 + highOffset}%`,
1027
- color: colors[2] || colors[0],
1028
- opacity: 0.35 + high * 0.65,
1029
- scale: 1 + high * 0.35,
1030
- rotation: high * 35,
1031
- blur: "blur-xl"
1032
- },
1033
- // Extra bass reactive blob - top left
1034
- {
1035
- width: `${160 + bass * 140}%`,
1036
- height: `${160 + bass * 140}%`,
1037
- top: `${ -60 - bassOffset * 0.8}%`,
1038
- left: `${ -60 + bassOffset * 0.8}%`,
1039
- color: colors[3] || colors[1] || colors[0],
1040
- opacity: 0.35 + bass * 0.65,
1041
- scale: 1 + bass * 0.55,
1042
- rotation: -bass * 50,
1043
- blur: "blur-2xl"
1044
- },
1045
- // Center glow - pulses with overall
1046
- {
1047
- width: `${80 + overall * 150}%`,
1048
- height: `${80 + overall * 150}%`,
1049
- top: "50%",
1050
- left: "50%",
1051
- color: colors[0],
1052
- opacity: 0.3 + overall * 0.5,
1053
- scale: 1 + overall * 0.4,
1054
- rotation: 0,
1055
- isCenter: true,
1056
- blur: "blur-3xl"
1057
- }
1058
- ];
1059
- }
1060
- chunkWGEGR3DF_cjs.__name(calculateMeshGradients, "calculateMeshGradients");
1061
- function calculateSpotlight(levels, config, colors, rotation) {
1062
- const { bass, mid, high, overall } = levels;
1063
- return {
1064
- // Rotation speed increases with mid frequencies
1065
- rotation: rotation + mid * 180,
1066
- // Border expands with bass
1067
- inset: 12 + bass * 30,
1068
- // Color intensities react to different frequencies
1069
- colors: colors.map((c, i) => ({
1070
- color: c,
1071
- opacity: i === 0 ? 0.3 + bass * 0.7 : i === 1 ? 0.3 + mid * 0.7 : 0.3 + high * 0.7
1072
- })),
1073
- // Pulse glow - big and reactive
1074
- pulseInset: 24 + bass * 50,
1075
- pulseOpacity: 0.3 + bass * 0.7,
1076
- pulseScale: 1 + bass * 0.4,
1077
- // Extra glow ring
1078
- ringOpacity: 0.2 + overall * 0.6,
1079
- ringScale: 1 + overall * 0.3
1080
- };
1081
- }
1082
- chunkWGEGR3DF_cjs.__name(calculateSpotlight, "calculateSpotlight");
1083
- var EFFECT_ANIMATIONS = `
1084
- @keyframes spotlight-spin {
1085
- 0% { transform: rotate(0deg); }
1086
- 100% { transform: rotate(360deg); }
1087
- }
1088
-
1089
- @keyframes orb-float-1 {
1090
- 0%, 100% { transform: translate(-50%, -50%) translateY(0); }
1091
- 50% { transform: translate(-50%, -50%) translateY(-15px); }
1092
- }
1093
-
1094
- @keyframes orb-float-2 {
1095
- 0%, 100% { transform: translate(-50%, -50%) translateX(0); }
1096
- 50% { transform: translate(-50%, -50%) translateX(15px); }
1097
- }
1098
-
1099
- @keyframes orb-float-3 {
1100
- 0%, 100% { transform: translate(-50%, -50%) translate(0, 0); }
1101
- 33% { transform: translate(-50%, -50%) translate(10px, -10px); }
1102
- 66% { transform: translate(-50%, -50%) translate(-10px, 10px); }
1103
- }
1104
-
1105
- @keyframes orb-float-4 {
1106
- 0%, 100% { transform: translate(-50%, -50%) translate(0, 0); }
1107
- 50% { transform: translate(-50%, -50%) translate(-15px, -10px); }
1108
- }
1109
-
1110
- @keyframes mesh-float-1 {
1111
- 0%, 100% { transform: translate(0, 0) scale(1); }
1112
- 25% { transform: translate(-5%, 10%) scale(1.05); }
1113
- 50% { transform: translate(5%, 5%) scale(0.95); }
1114
- 75% { transform: translate(-3%, -5%) scale(1.02); }
1115
- }
1116
-
1117
- @keyframes mesh-float-2 {
1118
- 0%, 100% { transform: translate(0, 0) scale(1); }
1119
- 33% { transform: translate(8%, -8%) scale(1.08); }
1120
- 66% { transform: translate(-6%, 6%) scale(0.92); }
1121
- }
1122
-
1123
- @keyframes mesh-float-3 {
1124
- 0%, 100% { transform: translate(0, 0) scale(1); }
1125
- 50% { transform: translate(10%, 10%) scale(1.1); }
1126
- }
1127
-
1128
- @keyframes mesh-float-4 {
1129
- 0%, 100% { transform: translate(0, 0) scale(1) rotate(0deg); }
1130
- 25% { transform: translate(10%, -5%) scale(1.1) rotate(5deg); }
1131
- 50% { transform: translate(-5%, 10%) scale(0.95) rotate(-5deg); }
1132
- 75% { transform: translate(-10%, -10%) scale(1.05) rotate(3deg); }
1133
- }
1134
-
1135
- @keyframes mesh-pulse {
1136
- 0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.3; }
1137
- 50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.5; }
1138
- }
1139
-
1140
- @keyframes glow-breathe {
1141
- 0%, 100% { opacity: 0.6; transform: scale(1); }
1142
- 50% { opacity: 1; transform: scale(1.05); }
1143
- }
1144
-
1145
- @keyframes glow-rotate {
1146
- 0% { transform: rotate(0deg); }
1147
- 100% { transform: rotate(360deg); }
1148
- }
1149
-
1150
- @keyframes sparkle-move {
1151
- 0% { opacity: 0; transform: scale(0.8); }
1152
- 50% { opacity: 1; }
1153
- 100% { opacity: 0; transform: scale(1.2); }
1154
- }
1155
- `;
1156
- function GlowEffect({ data, colors, isPlaying }) {
1157
- const { layers, hueShift, showPulseRings, showSparkle } = data;
1158
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1159
- layers.map((layer, i) => /* @__PURE__ */ jsxRuntime.jsx(
1160
- "div",
1161
- {
1162
- className: chunkF2N7P5XU_cjs.cn("absolute rounded-2xl -z-10", layer.blur),
1163
- style: {
1164
- inset: `-${layer.inset}px`,
1165
- background: layer.background,
1166
- opacity: isPlaying ? layer.opacity : 0,
1167
- transform: i < 2 ? `scaleY(${layer.scale})` : `scale(${layer.scale})`,
1168
- animation: isPlaying && layer.animation ? layer.animation : "none",
1169
- transition: "opacity 0.3s"
1170
- }
1171
- },
1172
- i
1173
- )),
1174
- /* @__PURE__ */ jsxRuntime.jsx(
1175
- "div",
1176
- {
1177
- className: "absolute rounded-2xl blur-xl overflow-hidden -z-10",
1178
- style: {
1179
- inset: "-75px",
1180
- opacity: isPlaying ? 0.6 : 0,
1181
- transition: "opacity 0.5s"
1182
- },
1183
- children: /* @__PURE__ */ jsxRuntime.jsx(
1184
- "div",
1185
- {
1186
- className: "absolute inset-0",
1187
- style: {
1188
- background: `conic-gradient(
1189
- from ${hueShift}deg at 50% 50%,
1190
- hsl(${colors[0]} / 0.4) 0deg,
1191
- hsl(${colors[1] || colors[0]} / 0.3) 90deg,
1192
- hsl(${colors[2] || colors[0]} / 0.3) 180deg,
1193
- hsl(${colors[3] || colors[0]} / 0.3) 270deg,
1194
- hsl(${colors[0]} / 0.4) 360deg
1195
- )`,
1196
- animation: isPlaying ? "glow-rotate 6s linear infinite" : "none"
1197
- }
1198
- }
1199
- )
1200
- }
1201
- ),
1202
- showPulseRings && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1203
- /* @__PURE__ */ jsxRuntime.jsx(
1204
- "div",
1205
- {
1206
- className: "absolute -inset-6 rounded-xl border-2 animate-ping -z-10",
1207
- style: {
1208
- borderColor: `hsl(${colors[0]} / 0.4)`,
1209
- animationDuration: "1s"
1210
- }
1211
- }
1212
- ),
1213
- /* @__PURE__ */ jsxRuntime.jsx(
1214
- "div",
1215
- {
1216
- className: "absolute -inset-12 rounded-2xl border animate-ping -z-10",
1217
- style: {
1218
- borderColor: `hsl(${colors[1] || colors[0]} / 0.3)`,
1219
- animationDuration: "1.5s",
1220
- animationDelay: "0.2s"
1221
- }
1222
- }
1223
- )
1224
- ] }),
1225
- showSparkle && /* @__PURE__ */ jsxRuntime.jsx(
1226
- "div",
1227
- {
1228
- className: "absolute -inset-18 rounded-3xl -z-10",
1229
- style: {
1230
- background: `radial-gradient(circle at 50% 30%, hsl(${colors[2] || colors[0]} / 0.5) 0%, transparent 30%)`,
1231
- animation: "sparkle-move 0.5s ease-out"
1232
- }
1233
- }
1234
- )
1235
- ] });
1236
- }
1237
- chunkWGEGR3DF_cjs.__name(GlowEffect, "GlowEffect");
1238
- function OrbsEffect({ orbs, blur, isPlaying }) {
1239
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: orbs.map((orb, i) => /* @__PURE__ */ jsxRuntime.jsx(
1240
- "div",
1241
- {
1242
- className: chunkF2N7P5XU_cjs.cn("absolute rounded-full -z-10", blur),
1243
- style: {
1244
- width: orb.size,
1245
- height: orb.size,
1246
- left: `${orb.x}%`,
1247
- top: `${orb.y}%`,
1248
- background: `radial-gradient(circle at 30% 30%, hsl(${orb.color}) 0%, hsl(${orb.color} / 0.5) 40%, transparent 70%)`,
1249
- opacity: isPlaying ? orb.opacity : 0,
1250
- transform: `translate(-50%, -50%) scale(${orb.scale})`,
1251
- transition: "all 0.08s ease-out"
1252
- }
1253
- },
1254
- i
1255
- )) });
1256
- }
1257
- chunkWGEGR3DF_cjs.__name(OrbsEffect, "OrbsEffect");
1258
- function SpotlightEffect({ data, colors, blur, isPlaying }) {
1259
- const inset = "inset" in data ? data.inset : 12;
1260
- const pulseInset = "pulseInset" in data ? data.pulseInset : 24;
1261
- const ringOpacity = "ringOpacity" in data ? data.ringOpacity : 0.3;
1262
- const ringScale = "ringScale" in data ? data.ringScale : 1;
1263
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1264
- /* @__PURE__ */ jsxRuntime.jsx(
1265
- "div",
1266
- {
1267
- className: chunkF2N7P5XU_cjs.cn("absolute rounded-xl -z-10", blur),
1268
- style: {
1269
- inset: `-${inset}px`,
1270
- background: `conic-gradient(
1271
- from ${data.rotation}deg,
1272
- hsl(${colors[0]} / ${data.colors[0]?.opacity || 0.5}),
1273
- hsl(${colors[1] || colors[0]} / ${data.colors[1]?.opacity || 0.7}),
1274
- hsl(${colors[2] || colors[0]} / ${data.colors[2]?.opacity || 0.5}),
1275
- hsl(${colors[0]} / ${data.colors[1]?.opacity || 0.7}),
1276
- hsl(${colors[0]} / ${data.colors[0]?.opacity || 0.5})
1277
- )`,
1278
- opacity: isPlaying ? 1 : 0,
1279
- transition: "all 0.08s ease-out"
1280
- }
1281
- }
1282
- ),
1283
- /* @__PURE__ */ jsxRuntime.jsx(
1284
- "div",
1285
- {
1286
- className: "absolute -inset-1 rounded-lg bg-background -z-10",
1287
- style: { opacity: isPlaying ? 1 : 0, transition: "opacity 0.1s" }
1288
- }
1289
- ),
1290
- /* @__PURE__ */ jsxRuntime.jsx(
1291
- "div",
1292
- {
1293
- className: chunkF2N7P5XU_cjs.cn("absolute rounded-2xl -z-10", blur),
1294
- style: {
1295
- inset: `-${pulseInset}px`,
1296
- background: `radial-gradient(circle, hsl(${colors[0]} / 0.7) 0%, hsl(${colors[0]} / 0.3) 50%, transparent 70%)`,
1297
- opacity: isPlaying ? data.pulseOpacity : 0,
1298
- transform: `scale(${data.pulseScale})`,
1299
- transition: "all 0.08s ease-out"
1300
- }
1301
- }
1302
- ),
1303
- /* @__PURE__ */ jsxRuntime.jsx(
1304
- "div",
1305
- {
1306
- className: "absolute rounded-3xl -z-10 blur-2xl",
1307
- style: {
1308
- inset: `-${pulseInset + 30}px`,
1309
- background: `radial-gradient(circle, hsl(${colors[1] || colors[0]} / 0.4) 0%, transparent 60%)`,
1310
- opacity: isPlaying ? ringOpacity : 0,
1311
- transform: `scale(${ringScale})`,
1312
- transition: "all 0.08s ease-out"
1313
- }
1314
- }
1315
- )
1316
- ] });
1317
- }
1318
- chunkWGEGR3DF_cjs.__name(SpotlightEffect, "SpotlightEffect");
1319
- function MeshEffect({ gradients, isPlaying }) {
1320
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: gradients.map((g, i) => {
1321
- const isCenter = "isCenter" in g && g.isCenter;
1322
- const scale = "scale" in g ? g.scale : 1;
1323
- const rotation = "rotation" in g ? g.rotation : 0;
1324
- const itemBlur = "blur" in g ? g.blur : "blur-2xl";
1325
- return /* @__PURE__ */ jsxRuntime.jsx(
1326
- "div",
1327
- {
1328
- className: chunkF2N7P5XU_cjs.cn("absolute rounded-full -z-10", itemBlur),
1329
- style: {
1330
- width: g.width,
1331
- height: g.height,
1332
- top: "top" in g ? g.top : void 0,
1333
- bottom: "bottom" in g ? g.bottom : void 0,
1334
- left: "left" in g ? g.left : void 0,
1335
- right: "right" in g ? g.right : void 0,
1336
- background: isCenter ? `radial-gradient(circle, hsl(${g.color} / 0.6) 0%, hsl(${g.color} / 0.3) 30%, transparent 60%)` : `radial-gradient(circle, hsl(${g.color}) 0%, hsl(${g.color} / 0.5) 30%, transparent 65%)`,
1337
- opacity: isPlaying ? g.opacity : 0,
1338
- transform: isCenter ? `translate(-50%, -50%) scale(${scale})` : `scale(${scale}) rotate(${rotation}deg)`,
1339
- transition: "all 0.08s ease-out"
1340
- }
1341
- },
1342
- i
1343
- );
1344
- }) });
1345
- }
1346
- chunkWGEGR3DF_cjs.__name(MeshEffect, "MeshEffect");
1347
- var SIZES = {
1348
- sm: { container: "w-32 h-32", orbBase: 40 },
1349
- md: { container: "w-40 h-40", orbBase: 50 },
1350
- lg: { container: "w-48 h-48", orbBase: 60 },
1351
- full: { container: "w-full sm:max-w-xs aspect-square mx-auto", orbBase: 60 }
1352
- };
1353
- function AudioReactiveCover({
1354
- children,
1355
- size = "lg",
1356
- variant = "spotlight",
1357
- intensity = "medium",
1358
- colorScheme = "primary",
1359
- onClick,
1360
- className
1361
- }) {
1362
- const { isPlaying } = useHybridAudioState();
1363
- const levels = useHybridAudioLevels();
1364
- const sizeConfig = SIZES[size];
1365
- const effectConfig = getEffectConfig(intensity);
1366
- const { colors, hueShift } = prepareEffectColors(colorScheme, levels);
1367
- const containerScale = 1 + levels.overall * effectConfig.scale;
1368
- const glowData = variant === "glow" ? {
1369
- layers: calculateGlowLayers(levels, effectConfig, colors),
1370
- hueShift,
1371
- showPulseRings: levels.bass > 0.5,
1372
- showSparkle: levels.high > 0.4
1373
- } : null;
1374
- const orbsData = variant === "orbs" ? calculateOrbs(levels, effectConfig, colors, sizeConfig.orbBase) : null;
1375
- const meshData = variant === "mesh" ? calculateMeshGradients(levels, effectConfig, colors) : null;
1376
- const spotlightData = variant === "spotlight" ? calculateSpotlight(levels, effectConfig, colors, levels.mid * 360) : null;
1377
- return /* @__PURE__ */ jsxRuntime.jsxs(
1378
- "div",
1379
- {
1380
- className: chunkF2N7P5XU_cjs.cn("relative", sizeConfig.container, className),
1381
- style: {
1382
- transform: `scale(${containerScale})`,
1383
- transition: "transform 0.1s ease-out"
1384
- },
1385
- children: [
1386
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 z-0 pointer-events-none overflow-visible", children: [
1387
- glowData && /* @__PURE__ */ jsxRuntime.jsx(GlowEffect, { data: glowData, colors, isPlaying }),
1388
- orbsData && /* @__PURE__ */ jsxRuntime.jsx(OrbsEffect, { orbs: orbsData, blur: effectConfig.blur, isPlaying }),
1389
- spotlightData && /* @__PURE__ */ jsxRuntime.jsx(SpotlightEffect, { data: spotlightData, colors, blur: effectConfig.blur, isPlaying }),
1390
- meshData && /* @__PURE__ */ jsxRuntime.jsx(MeshEffect, { gradients: meshData, blur: effectConfig.blur, isPlaying })
1391
- ] }),
1392
- /* @__PURE__ */ jsxRuntime.jsx(
1393
- "div",
1394
- {
1395
- className: "relative w-full h-full rounded-lg overflow-hidden shadow-2xl z-10 bg-background cursor-pointer",
1396
- onClick,
1397
- role: onClick ? "button" : void 0,
1398
- tabIndex: onClick ? 0 : void 0,
1399
- onKeyDown: onClick ? (e) => e.key === "Enter" && onClick() : void 0,
1400
- children
1401
- }
1402
- ),
1403
- /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: EFFECT_ANIMATIONS } })
1404
- ]
1405
- }
1406
- );
1407
- }
1408
- chunkWGEGR3DF_cjs.__name(AudioReactiveCover, "AudioReactiveCover");
1409
- var COVER_SIZES = {
1410
- sm: "w-24 h-24",
1411
- md: "w-32 h-32",
1412
- lg: "w-48 h-48"
1413
- };
1414
- var COVER_SIZE_FOR_LAYOUT = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((coverSize, isHorizontal) => isHorizontal ? coverSize : "full", "COVER_SIZE_FOR_LAYOUT");
1415
- function HybridSimplePlayer(props) {
1416
- return /* @__PURE__ */ jsxRuntime.jsx(VisualizationProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(HybridSimplePlayerContent, { ...props }) });
1417
- }
1418
- chunkWGEGR3DF_cjs.__name(HybridSimplePlayer, "HybridSimplePlayer");
1419
- function HybridSimplePlayerContent({
1420
- src,
1421
- title,
1422
- artist,
1423
- coverArt,
1424
- coverSize = "md",
1425
- showWaveform = true,
1426
- waveformMode = "frequency",
1427
- waveformHeight = 64,
1428
- showTimer = true,
1429
- showVolume = true,
1430
- showLoop = true,
1431
- reactiveCover = true,
1432
- variant,
1433
- intensity,
1434
- colorScheme,
1435
- autoPlay = false,
1436
- loop = false,
1437
- initialVolume = 1,
1438
- layout = "vertical",
1439
- className,
1440
- onPlay,
1441
- onPause,
1442
- onEnded,
1443
- onError
1444
- }) {
1445
- const { settings: vizSettings, nextVariant } = useVisualization();
1446
- const effectiveVariant = variant ?? (vizSettings.variant !== "none" ? vizSettings.variant : "spotlight");
1447
- const effectiveIntensity = intensity ?? vizSettings.intensity;
1448
- const effectiveColorScheme = colorScheme ?? vizSettings.colorScheme;
1449
- const showReactiveCover = reactiveCover && effectiveVariant !== "none";
1450
- const renderCoverContent = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
1451
- if (typeof coverArt === "string") {
1452
- return /* @__PURE__ */ jsxRuntime.jsx("img", { src: coverArt, alt: title || "Album cover", className: "w-full h-full object-cover" });
1453
- }
1454
- if (coverArt) {
1455
- return coverArt;
1456
- }
1457
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full bg-muted/30 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Music, { className: "w-1/3 h-1/3 text-muted-foreground/50" }) });
1458
- }, "renderCoverContent");
1459
- const isHorizontal = layout === "horizontal";
1460
- return /* @__PURE__ */ jsxRuntime.jsx(
1461
- HybridAudioProvider,
1462
- {
1463
- src,
1464
- autoPlay,
1465
- loop,
1466
- initialVolume,
1467
- onPlay,
1468
- onPause,
1469
- onEnded,
1470
- onError,
1471
- children: /* @__PURE__ */ jsxRuntime.jsxs(
1472
- "div",
1473
- {
1474
- className: uiCore.cn(
1475
- "flex gap-4",
1476
- isHorizontal ? "flex-row items-center" : "flex-col items-center",
1477
- className
1478
- ),
1479
- children: [
1480
- (coverArt || reactiveCover) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: uiCore.cn("flex flex-col items-center gap-2", isHorizontal ? "shrink-0" : "w-full"), children: [
1481
- showReactiveCover ? /* @__PURE__ */ jsxRuntime.jsx(
1482
- AudioReactiveCover,
1483
- {
1484
- size: COVER_SIZE_FOR_LAYOUT(coverSize, isHorizontal),
1485
- variant: effectiveVariant,
1486
- intensity: effectiveIntensity,
1487
- colorScheme: effectiveColorScheme,
1488
- onClick: nextVariant,
1489
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: uiCore.cn("rounded-lg overflow-hidden", isHorizontal ? COVER_SIZES[coverSize] : "w-full h-full"), children: renderCoverContent() })
1490
- }
1491
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1492
- "div",
1493
- {
1494
- className: uiCore.cn(
1495
- "rounded-lg overflow-hidden shadow-lg cursor-pointer",
1496
- isHorizontal ? COVER_SIZES[coverSize] : "w-full sm:max-w-xs aspect-square mx-auto"
1497
- ),
1498
- onClick: nextVariant,
1499
- role: "button",
1500
- tabIndex: 0,
1501
- onKeyDown: (e) => e.key === "Enter" && nextVariant(),
1502
- children: renderCoverContent()
1503
- }
1504
- ),
1505
- reactiveCover && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider text-muted-foreground/50 select-none", children: vizSettings.variant === "none" ? "off" : vizSettings.variant })
1506
- ] }),
1507
- /* @__PURE__ */ jsxRuntime.jsxs(
1508
- "div",
1509
- {
1510
- className: uiCore.cn("flex flex-col gap-3", isHorizontal ? "flex-1 min-w-0" : "w-full"),
1511
- children: [
1512
- (title || artist) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: uiCore.cn("text-center", isHorizontal && "text-left"), children: [
1513
- title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-medium text-foreground truncate", children: title }),
1514
- artist && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground truncate", children: artist })
1515
- ] }),
1516
- /* @__PURE__ */ jsxRuntime.jsx(
1517
- HybridAudioPlayer,
1518
- {
1519
- showControls: true,
1520
- showWaveform,
1521
- waveformMode,
1522
- waveformHeight,
1523
- showTimer,
1524
- showVolume,
1525
- showLoop,
1526
- className: "border-0 bg-transparent"
1527
- }
1528
- )
1529
- ]
1530
- }
1531
- )
1532
- ]
1533
- }
1534
- )
1535
- }
1536
- );
1537
- }
1538
- chunkWGEGR3DF_cjs.__name(HybridSimplePlayerContent, "HybridSimplePlayerContent");
1539
- function HybridCompactPlayer({
1540
- src,
1541
- title,
1542
- autoPlay = false,
1543
- loop = false,
1544
- initialVolume = 1,
1545
- waveformMode = "frequency",
1546
- showTimer = true,
1547
- buttonSize = "md",
1548
- className,
1549
- onPlay,
1550
- onPause,
1551
- onEnded,
1552
- onError
1553
- }) {
1554
- return /* @__PURE__ */ jsxRuntime.jsx(
1555
- HybridAudioProvider,
1556
- {
1557
- src,
1558
- autoPlay,
1559
- loop,
1560
- initialVolume,
1561
- onPlay,
1562
- onPause,
1563
- onEnded,
1564
- onError,
1565
- children: /* @__PURE__ */ jsxRuntime.jsx(
1566
- HybridCompactPlayerInner,
1567
- {
1568
- title,
1569
- waveformMode,
1570
- showTimer,
1571
- buttonSize,
1572
- className
1573
- }
1574
- )
1575
- }
1576
- );
1577
- }
1578
- chunkWGEGR3DF_cjs.__name(HybridCompactPlayer, "HybridCompactPlayer");
1579
- var BUTTON_SIZE = {
1580
- sm: "h-6 w-6",
1581
- md: "h-8 w-8"
1582
- };
1583
- function HybridCompactPlayerInner({ title, waveformMode, showTimer, buttonSize, className }) {
1584
- const { state, controls } = useHybridAudioContext();
1585
- const isLoading = !state.isReady;
1586
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: uiCore.cn("flex items-center gap-2 w-full", className), children: [
1587
- /* @__PURE__ */ jsxRuntime.jsx(
1588
- chunkF2N7P5XU_cjs.Button,
1589
- {
1590
- variant: "ghost",
1591
- size: "icon",
1592
- className: uiCore.cn(BUTTON_SIZE[buttonSize], "flex-shrink-0"),
1593
- onClick: controls.togglePlay,
1594
- disabled: !state.isReady && !isLoading,
1595
- title: title ?? (state.isPlaying ? "Pause" : "Play"),
1596
- "aria-label": state.isPlaying ? "Pause" : "Play",
1597
- children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : state.isPlaying ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "h-3.5 w-3.5 ml-0.5" })
1598
- }
1599
- ),
1600
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(
1601
- HybridWaveform,
1602
- {
1603
- mode: waveformMode,
1604
- height: 32,
1605
- barWidth: 2,
1606
- barGap: 1,
1607
- className: uiCore.cn(isLoading && "opacity-40")
1608
- }
1609
- ) }),
1610
- showTimer && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-muted-foreground tabular-nums flex-shrink-0", children: [
1611
- formatTime(state.currentTime),
1612
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50", children: " / " }),
1613
- formatTime(state.duration)
1614
- ] })
1615
- ] });
1616
- }
1617
- chunkWGEGR3DF_cjs.__name(HybridCompactPlayerInner, "HybridCompactPlayerInner");
1618
-
1619
- exports.AudioReactiveCover = AudioReactiveCover;
1620
- exports.COLOR_SCHEMES = COLOR_SCHEMES2;
1621
- exports.COLOR_SCHEME_INFO = COLOR_SCHEME_INFO;
1622
- exports.EFFECT_ANIMATIONS = EFFECT_ANIMATIONS;
1623
- exports.GlowEffect = GlowEffect;
1624
- exports.HybridAudioPlayer = HybridAudioPlayer;
1625
- exports.HybridAudioProvider = HybridAudioProvider;
1626
- exports.HybridCompactPlayer = HybridCompactPlayer;
1627
- exports.HybridSimplePlayer = HybridSimplePlayer;
1628
- exports.HybridWaveform = HybridWaveform;
1629
- exports.INTENSITY_CONFIG = INTENSITY_CONFIG;
1630
- exports.INTENSITY_INFO = INTENSITY_INFO;
1631
- exports.MeshEffect = MeshEffect;
1632
- exports.OrbsEffect = OrbsEffect;
1633
- exports.SpotlightEffect = SpotlightEffect;
1634
- exports.VARIANT_INFO = VARIANT_INFO;
1635
- exports.VisualizationProvider = VisualizationProvider;
1636
- exports.calculateGlowLayers = calculateGlowLayers;
1637
- exports.calculateMeshGradients = calculateMeshGradients;
1638
- exports.calculateOrbs = calculateOrbs;
1639
- exports.calculateSpotlight = calculateSpotlight;
1640
- exports.formatTime = formatTime;
1641
- exports.getColors = getColors;
1642
- exports.getEffectConfig = getEffectConfig;
1643
- exports.prepareEffectColors = prepareEffectColors;
1644
- exports.useAudioBus = useAudioBus;
1645
- exports.useAudioBusStore = useAudioBusStore;
1646
- exports.useAudioVisualization = useAudioVisualization;
1647
- exports.useHybridAudio = useHybridAudio;
1648
- exports.useHybridAudioAnalysis = useHybridAudioAnalysis;
1649
- exports.useHybridAudioContext = useHybridAudioContext;
1650
- exports.useHybridAudioControls = useHybridAudioControls;
1651
- exports.useHybridAudioLevels = useHybridAudioLevels;
1652
- exports.useHybridAudioState = useHybridAudioState;
1653
- exports.useHybridWebAudio = useHybridWebAudio;
1654
- exports.useVisualization = useVisualization;
1655
- //# sourceMappingURL=chunk-YZX6FH3H.cjs.map
1656
- //# sourceMappingURL=chunk-YZX6FH3H.cjs.map