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