@djangocfg/ui-nextjs 2.1.82 → 2.1.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/tools/AudioPlayer/README.md +108 -242
- package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +216 -0
- package/src/tools/AudioPlayer/components/{SimpleAudioPlayer.tsx → HybridSimplePlayer.tsx} +61 -69
- package/src/tools/AudioPlayer/components/HybridWaveform.tsx +279 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +5 -5
- package/src/tools/AudioPlayer/components/index.ts +7 -6
- package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +121 -0
- package/src/tools/AudioPlayer/context/index.ts +11 -6
- package/src/tools/AudioPlayer/hooks/index.ts +14 -10
- package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +387 -0
- package/src/tools/AudioPlayer/hooks/{useAudioAnalysis.ts → useHybridAudioAnalysis.ts} +23 -38
- package/src/tools/AudioPlayer/index.ts +37 -70
- package/src/tools/AudioPlayer/types/index.ts +10 -18
- package/src/tools/index.ts +60 -43
- package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +0 -148
- package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +0 -301
- package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +0 -281
- package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +0 -328
- package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +0 -251
- package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +0 -427
- package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +0 -193
- package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +0 -146
- package/src/tools/AudioPlayer/@refactoring2/ISSUE_ANALYSIS.md +0 -187
- package/src/tools/AudioPlayer/@refactoring2/PLAN.md +0 -372
- package/src/tools/AudioPlayer/components/AudioEqualizer.tsx +0 -200
- package/src/tools/AudioPlayer/components/AudioPlayer.tsx +0 -231
- package/src/tools/AudioPlayer/components/AudioShortcutsPopover.tsx +0 -99
- package/src/tools/AudioPlayer/components/VisualizationToggle.tsx +0 -64
- package/src/tools/AudioPlayer/context/AudioProvider.tsx +0 -371
- package/src/tools/AudioPlayer/context/selectors.ts +0 -96
- package/src/tools/AudioPlayer/hooks/useAudioHotkeys.ts +0 -150
- package/src/tools/AudioPlayer/hooks/useAudioSource.ts +0 -155
- package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +0 -106
- package/src/tools/AudioPlayer/progressive/ProgressiveAudioPlayer.tsx +0 -295
- package/src/tools/AudioPlayer/progressive/WaveformCanvas.tsx +0 -381
- package/src/tools/AudioPlayer/progressive/index.ts +0 -40
- package/src/tools/AudioPlayer/progressive/peaks.ts +0 -234
- package/src/tools/AudioPlayer/progressive/types.ts +0 -179
- package/src/tools/AudioPlayer/progressive/useAudioElement.ts +0 -340
- package/src/tools/AudioPlayer/progressive/useProgressiveWaveform.ts +0 -267
- package/src/tools/AudioPlayer/types/audio.ts +0 -121
- package/src/tools/AudioPlayer/types/components.ts +0 -98
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* useProgressiveWaveform - Hook for progressive audio waveform loading
|
|
5
|
-
*
|
|
6
|
-
* Fetches audio in chunks, decodes progressively, and extracts peaks.
|
|
7
|
-
* Provides loading state and partial waveform data as it loads.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
11
|
-
import { extractPeaks, mergePeaks } from './peaks';
|
|
12
|
-
import type { LoadedRange, DecoderOptions } from './types';
|
|
13
|
-
|
|
14
|
-
// =============================================================================
|
|
15
|
-
// CONSTANTS
|
|
16
|
-
// =============================================================================
|
|
17
|
-
|
|
18
|
-
const DEFAULT_CHUNK_SIZE = 512 * 1024; // 512KB
|
|
19
|
-
const DEFAULT_PEAKS_PER_SECOND = 50;
|
|
20
|
-
const MAX_PARALLEL_FETCHES = 2;
|
|
21
|
-
|
|
22
|
-
// =============================================================================
|
|
23
|
-
// TYPES
|
|
24
|
-
// =============================================================================
|
|
25
|
-
|
|
26
|
-
interface UseProgressiveWaveformOptions extends DecoderOptions {
|
|
27
|
-
/** Audio source URL */
|
|
28
|
-
url: string;
|
|
29
|
-
/** Known duration (from metadata) - improves initial render */
|
|
30
|
-
duration?: number;
|
|
31
|
-
/** Enabled */
|
|
32
|
-
enabled?: boolean;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
interface UseProgressiveWaveformReturn {
|
|
36
|
-
/** Accumulated peaks (0-1 normalized) */
|
|
37
|
-
peaks: number[];
|
|
38
|
-
/** Loading progress (0-100) */
|
|
39
|
-
loadedPercent: number;
|
|
40
|
-
/** Is currently loading */
|
|
41
|
-
isLoading: boolean;
|
|
42
|
-
/** Is complete */
|
|
43
|
-
isComplete: boolean;
|
|
44
|
-
/** Error if any */
|
|
45
|
-
error: Error | null;
|
|
46
|
-
/** Loaded ranges (for visual indication) */
|
|
47
|
-
loadedRanges: LoadedRange[];
|
|
48
|
-
/** Detected duration */
|
|
49
|
-
detectedDuration: number;
|
|
50
|
-
/** Retry loading */
|
|
51
|
-
retry: () => void;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// =============================================================================
|
|
55
|
-
// AUDIO CONTEXT SINGLETON
|
|
56
|
-
// =============================================================================
|
|
57
|
-
|
|
58
|
-
let audioContextInstance: AudioContext | null = null;
|
|
59
|
-
|
|
60
|
-
function getAudioContext(): AudioContext {
|
|
61
|
-
if (!audioContextInstance) {
|
|
62
|
-
audioContextInstance = new (window.AudioContext || (window as any).webkitAudioContext)();
|
|
63
|
-
}
|
|
64
|
-
return audioContextInstance;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// =============================================================================
|
|
68
|
-
// HOOK
|
|
69
|
-
// =============================================================================
|
|
70
|
-
|
|
71
|
-
export function useProgressiveWaveform(
|
|
72
|
-
options: UseProgressiveWaveformOptions
|
|
73
|
-
): UseProgressiveWaveformReturn {
|
|
74
|
-
const {
|
|
75
|
-
url,
|
|
76
|
-
duration: knownDuration,
|
|
77
|
-
enabled = true,
|
|
78
|
-
chunkSize = DEFAULT_CHUNK_SIZE,
|
|
79
|
-
peaksPerSecond = DEFAULT_PEAKS_PER_SECOND,
|
|
80
|
-
parallelFetches = MAX_PARALLEL_FETCHES,
|
|
81
|
-
} = options;
|
|
82
|
-
|
|
83
|
-
// State
|
|
84
|
-
const [peaks, setPeaks] = useState<number[]>([]);
|
|
85
|
-
const [loadedPercent, setLoadedPercent] = useState(0);
|
|
86
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
87
|
-
const [isComplete, setIsComplete] = useState(false);
|
|
88
|
-
const [error, setError] = useState<Error | null>(null);
|
|
89
|
-
const [loadedRanges, setLoadedRanges] = useState<LoadedRange[]>([]);
|
|
90
|
-
const [detectedDuration, setDetectedDuration] = useState(knownDuration || 0);
|
|
91
|
-
|
|
92
|
-
// Refs
|
|
93
|
-
const abortControllerRef = useRef<AbortController | null>(null);
|
|
94
|
-
const accumulatedDataRef = useRef<ArrayBuffer[]>([]);
|
|
95
|
-
const totalSizeRef = useRef(0);
|
|
96
|
-
const loadedSizeRef = useRef(0);
|
|
97
|
-
const retryCountRef = useRef(0);
|
|
98
|
-
|
|
99
|
-
// ==========================================================================
|
|
100
|
-
// DECODE ACCUMULATED DATA
|
|
101
|
-
// ==========================================================================
|
|
102
|
-
|
|
103
|
-
const decodeAccumulated = useCallback(async () => {
|
|
104
|
-
const chunks = accumulatedDataRef.current;
|
|
105
|
-
if (chunks.length === 0) return;
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
// Combine all chunks
|
|
109
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
|
|
110
|
-
const combined = new Uint8Array(totalLength);
|
|
111
|
-
let offset = 0;
|
|
112
|
-
for (const chunk of chunks) {
|
|
113
|
-
combined.set(new Uint8Array(chunk), offset);
|
|
114
|
-
offset += chunk.byteLength;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Decode
|
|
118
|
-
const audioContext = getAudioContext();
|
|
119
|
-
const audioBuffer = await audioContext.decodeAudioData(combined.buffer.slice(0));
|
|
120
|
-
|
|
121
|
-
// Extract peaks
|
|
122
|
-
const targetPeaks = Math.ceil(audioBuffer.duration * peaksPerSecond);
|
|
123
|
-
const newPeaks = extractPeaks(audioBuffer, { length: targetPeaks });
|
|
124
|
-
|
|
125
|
-
setPeaks(newPeaks);
|
|
126
|
-
setDetectedDuration(audioBuffer.duration);
|
|
127
|
-
} catch (err) {
|
|
128
|
-
// Decoding failed - might need more data
|
|
129
|
-
// This is expected for partial MP3 data
|
|
130
|
-
console.debug('Decode attempt failed, waiting for more data');
|
|
131
|
-
}
|
|
132
|
-
}, [peaksPerSecond]);
|
|
133
|
-
|
|
134
|
-
// ==========================================================================
|
|
135
|
-
// FETCH LOGIC
|
|
136
|
-
// ==========================================================================
|
|
137
|
-
|
|
138
|
-
const loadWaveform = useCallback(async () => {
|
|
139
|
-
if (!url || !enabled) return;
|
|
140
|
-
|
|
141
|
-
// Abort previous
|
|
142
|
-
abortControllerRef.current?.abort();
|
|
143
|
-
abortControllerRef.current = new AbortController();
|
|
144
|
-
const { signal } = abortControllerRef.current;
|
|
145
|
-
|
|
146
|
-
// Reset state
|
|
147
|
-
setIsLoading(true);
|
|
148
|
-
setIsComplete(false);
|
|
149
|
-
setError(null);
|
|
150
|
-
setPeaks([]);
|
|
151
|
-
setLoadedRanges([]);
|
|
152
|
-
setLoadedPercent(0);
|
|
153
|
-
accumulatedDataRef.current = [];
|
|
154
|
-
loadedSizeRef.current = 0;
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
// Get file size with HEAD request
|
|
158
|
-
const headResponse = await fetch(url, { method: 'HEAD', signal });
|
|
159
|
-
const contentLength = headResponse.headers.get('content-length');
|
|
160
|
-
const totalSize = contentLength ? parseInt(contentLength, 10) : 0;
|
|
161
|
-
totalSizeRef.current = totalSize;
|
|
162
|
-
|
|
163
|
-
if (totalSize === 0) {
|
|
164
|
-
// Fallback: fetch entire file
|
|
165
|
-
const response = await fetch(url, { signal });
|
|
166
|
-
const data = await response.arrayBuffer();
|
|
167
|
-
accumulatedDataRef.current = [data];
|
|
168
|
-
await decodeAccumulated();
|
|
169
|
-
setIsComplete(true);
|
|
170
|
-
setLoadedPercent(100);
|
|
171
|
-
setIsLoading(false);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Fetch in chunks
|
|
176
|
-
let offset = 0;
|
|
177
|
-
const ranges: LoadedRange[] = [];
|
|
178
|
-
|
|
179
|
-
while (offset < totalSize) {
|
|
180
|
-
if (signal.aborted) return;
|
|
181
|
-
|
|
182
|
-
const end = Math.min(offset + chunkSize - 1, totalSize - 1);
|
|
183
|
-
|
|
184
|
-
const response = await fetch(url, {
|
|
185
|
-
headers: { Range: `bytes=${offset}-${end}` },
|
|
186
|
-
signal,
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
if (!response.ok && response.status !== 206) {
|
|
190
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const chunk = await response.arrayBuffer();
|
|
194
|
-
accumulatedDataRef.current.push(chunk);
|
|
195
|
-
loadedSizeRef.current += chunk.byteLength;
|
|
196
|
-
|
|
197
|
-
// Update progress
|
|
198
|
-
const progress = (loadedSizeRef.current / totalSize) * 100;
|
|
199
|
-
setLoadedPercent(progress);
|
|
200
|
-
|
|
201
|
-
// Update ranges
|
|
202
|
-
const rangeStart = offset / totalSize;
|
|
203
|
-
const rangeEnd = (offset + chunk.byteLength) / totalSize;
|
|
204
|
-
ranges.push({ start: rangeStart, end: rangeEnd });
|
|
205
|
-
setLoadedRanges([...ranges]);
|
|
206
|
-
|
|
207
|
-
// Try to decode periodically
|
|
208
|
-
if (accumulatedDataRef.current.length % 2 === 0 || offset + chunkSize >= totalSize) {
|
|
209
|
-
await decodeAccumulated();
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
offset += chunkSize;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Final decode
|
|
216
|
-
await decodeAccumulated();
|
|
217
|
-
setIsComplete(true);
|
|
218
|
-
} catch (err) {
|
|
219
|
-
if ((err as Error).name === 'AbortError') return;
|
|
220
|
-
|
|
221
|
-
const error = err instanceof Error ? err : new Error('Loading failed');
|
|
222
|
-
setError(error);
|
|
223
|
-
console.error('Waveform loading error:', error);
|
|
224
|
-
} finally {
|
|
225
|
-
setIsLoading(false);
|
|
226
|
-
}
|
|
227
|
-
}, [url, enabled, chunkSize, decodeAccumulated]);
|
|
228
|
-
|
|
229
|
-
// ==========================================================================
|
|
230
|
-
// RETRY
|
|
231
|
-
// ==========================================================================
|
|
232
|
-
|
|
233
|
-
const retry = useCallback(() => {
|
|
234
|
-
retryCountRef.current += 1;
|
|
235
|
-
loadWaveform();
|
|
236
|
-
}, [loadWaveform]);
|
|
237
|
-
|
|
238
|
-
// ==========================================================================
|
|
239
|
-
// EFFECTS
|
|
240
|
-
// ==========================================================================
|
|
241
|
-
|
|
242
|
-
useEffect(() => {
|
|
243
|
-
loadWaveform();
|
|
244
|
-
|
|
245
|
-
return () => {
|
|
246
|
-
abortControllerRef.current?.abort();
|
|
247
|
-
};
|
|
248
|
-
}, [loadWaveform]);
|
|
249
|
-
|
|
250
|
-
// Update duration from prop
|
|
251
|
-
useEffect(() => {
|
|
252
|
-
if (knownDuration && knownDuration > 0 && detectedDuration === 0) {
|
|
253
|
-
setDetectedDuration(knownDuration);
|
|
254
|
-
}
|
|
255
|
-
}, [knownDuration, detectedDuration]);
|
|
256
|
-
|
|
257
|
-
return {
|
|
258
|
-
peaks,
|
|
259
|
-
loadedPercent,
|
|
260
|
-
isLoading,
|
|
261
|
-
isComplete,
|
|
262
|
-
error,
|
|
263
|
-
loadedRanges,
|
|
264
|
-
detectedDuration,
|
|
265
|
-
retry,
|
|
266
|
-
};
|
|
267
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core audio-related types
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type WaveSurfer from 'wavesurfer.js';
|
|
6
|
-
import type { AudioLevels } from './effects';
|
|
7
|
-
|
|
8
|
-
// =============================================================================
|
|
9
|
-
// AUDIO SOURCE
|
|
10
|
-
// =============================================================================
|
|
11
|
-
|
|
12
|
-
export interface AudioSource {
|
|
13
|
-
/** Audio URL (streaming or direct) */
|
|
14
|
-
uri: string;
|
|
15
|
-
/**
|
|
16
|
-
* Pre-fetch the URL as blob before passing to WaveSurfer.
|
|
17
|
-
* Required for streaming URLs because WaveSurfer needs complete file for seek to work.
|
|
18
|
-
* When true, the URL will be fetched and converted to blob URL.
|
|
19
|
-
* @default false
|
|
20
|
-
*/
|
|
21
|
-
prefetch?: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// =============================================================================
|
|
25
|
-
// PLAYBACK STATE
|
|
26
|
-
// =============================================================================
|
|
27
|
-
|
|
28
|
-
export interface PlaybackStatus {
|
|
29
|
-
isLoaded: boolean;
|
|
30
|
-
isPlaying: boolean;
|
|
31
|
-
duration: number;
|
|
32
|
-
currentTime: number;
|
|
33
|
-
volume: number;
|
|
34
|
-
isMuted: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// =============================================================================
|
|
38
|
-
// WAVEFORM OPTIONS
|
|
39
|
-
// =============================================================================
|
|
40
|
-
|
|
41
|
-
export interface WaveformOptions {
|
|
42
|
-
waveColor?: string;
|
|
43
|
-
progressColor?: string;
|
|
44
|
-
height?: number;
|
|
45
|
-
barWidth?: number;
|
|
46
|
-
barRadius?: number;
|
|
47
|
-
barGap?: number;
|
|
48
|
-
cursorWidth?: number;
|
|
49
|
-
cursorColor?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// =============================================================================
|
|
53
|
-
// EQUALIZER OPTIONS
|
|
54
|
-
// =============================================================================
|
|
55
|
-
|
|
56
|
-
export interface EqualizerOptions {
|
|
57
|
-
barCount?: number;
|
|
58
|
-
height?: number;
|
|
59
|
-
gap?: number;
|
|
60
|
-
showPeaks?: boolean;
|
|
61
|
-
barColor?: string;
|
|
62
|
-
peakColor?: string;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// =============================================================================
|
|
66
|
-
// SHARED WEB AUDIO CONTEXT
|
|
67
|
-
// =============================================================================
|
|
68
|
-
|
|
69
|
-
export interface SharedWebAudioContext {
|
|
70
|
-
/** The Web Audio AudioContext instance */
|
|
71
|
-
audioContext: AudioContext | null;
|
|
72
|
-
/** The MediaElementSourceNode connected to the audio element */
|
|
73
|
-
sourceNode: MediaElementAudioSourceNode | null;
|
|
74
|
-
/** Create an AnalyserNode connected to the shared source */
|
|
75
|
-
createAnalyser: (options?: { fftSize?: number; smoothing?: number }) => AnalyserNode | null;
|
|
76
|
-
/** Disconnect and cleanup an AnalyserNode */
|
|
77
|
-
disconnectAnalyser: (analyser: AnalyserNode) => void;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// =============================================================================
|
|
81
|
-
// AUDIO CONTEXT STATE
|
|
82
|
-
// =============================================================================
|
|
83
|
-
|
|
84
|
-
export interface AudioContextState {
|
|
85
|
-
// Core instances
|
|
86
|
-
wavesurfer: WaveSurfer | null;
|
|
87
|
-
audioElement: HTMLMediaElement | null;
|
|
88
|
-
/** Shared Web Audio context for analyzers */
|
|
89
|
-
sharedAudio: SharedWebAudioContext;
|
|
90
|
-
|
|
91
|
-
// Playback state
|
|
92
|
-
isReady: boolean;
|
|
93
|
-
isPlaying: boolean;
|
|
94
|
-
currentTime: number;
|
|
95
|
-
duration: number;
|
|
96
|
-
volume: number;
|
|
97
|
-
isMuted: boolean;
|
|
98
|
-
isLooping: boolean;
|
|
99
|
-
|
|
100
|
-
// Prefetch state (for streaming URLs)
|
|
101
|
-
/** Whether audio is being prefetched as blob */
|
|
102
|
-
isPrefetching: boolean;
|
|
103
|
-
/** Prefetch progress (0-100) */
|
|
104
|
-
prefetchProgress: number;
|
|
105
|
-
|
|
106
|
-
// Audio analysis (for reactive effects)
|
|
107
|
-
audioLevels: AudioLevels;
|
|
108
|
-
|
|
109
|
-
// Actions
|
|
110
|
-
play: () => Promise<void>;
|
|
111
|
-
pause: () => void;
|
|
112
|
-
togglePlay: () => void;
|
|
113
|
-
seek: (time: number) => void;
|
|
114
|
-
seekTo: (progress: number) => void;
|
|
115
|
-
skip: (seconds: number) => void;
|
|
116
|
-
setVolume: (volume: number) => void;
|
|
117
|
-
toggleMute: () => void;
|
|
118
|
-
toggleLoop: () => void;
|
|
119
|
-
setLoop: (enabled: boolean) => void;
|
|
120
|
-
restart: () => void;
|
|
121
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Component props types
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { CSSProperties } from 'react';
|
|
6
|
-
import type { WaveformOptions, EqualizerOptions, AudioSource, PlaybackStatus } from './audio';
|
|
7
|
-
|
|
8
|
-
// =============================================================================
|
|
9
|
-
// AUDIO PLAYER PROPS
|
|
10
|
-
// =============================================================================
|
|
11
|
-
|
|
12
|
-
export interface AudioPlayerProps {
|
|
13
|
-
/** Show playback controls */
|
|
14
|
-
showControls?: boolean;
|
|
15
|
-
/** Show waveform visualization */
|
|
16
|
-
showWaveform?: boolean;
|
|
17
|
-
/** Show equalizer animation */
|
|
18
|
-
showEqualizer?: boolean;
|
|
19
|
-
/** Show timer (position/duration) */
|
|
20
|
-
showTimer?: boolean;
|
|
21
|
-
/** Show volume control */
|
|
22
|
-
showVolume?: boolean;
|
|
23
|
-
/** Show loop/repeat button */
|
|
24
|
-
showLoop?: boolean;
|
|
25
|
-
/** WaveSurfer options override */
|
|
26
|
-
waveformOptions?: WaveformOptions;
|
|
27
|
-
/** Equalizer options */
|
|
28
|
-
equalizerOptions?: EqualizerOptions;
|
|
29
|
-
/** Additional class name */
|
|
30
|
-
className?: string;
|
|
31
|
-
/** Additional styles */
|
|
32
|
-
style?: CSSProperties;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// =============================================================================
|
|
36
|
-
// AUDIO EQUALIZER PROPS
|
|
37
|
-
// =============================================================================
|
|
38
|
-
|
|
39
|
-
export interface AudioEqualizerProps {
|
|
40
|
-
/** Number of frequency bars */
|
|
41
|
-
barCount?: number;
|
|
42
|
-
/** Height of the equalizer in pixels */
|
|
43
|
-
height?: number;
|
|
44
|
-
/** Gap between bars in pixels */
|
|
45
|
-
gap?: number;
|
|
46
|
-
/** Show peak indicators */
|
|
47
|
-
showPeaks?: boolean;
|
|
48
|
-
/** Bar color (CSS color) */
|
|
49
|
-
barColor?: string;
|
|
50
|
-
/** Peak indicator color */
|
|
51
|
-
peakColor?: string;
|
|
52
|
-
/** Additional class name */
|
|
53
|
-
className?: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// =============================================================================
|
|
57
|
-
// AUDIO REACTIVE COVER PROPS
|
|
58
|
-
// =============================================================================
|
|
59
|
-
|
|
60
|
-
export interface AudioReactiveCoverProps {
|
|
61
|
-
/** Visual variant */
|
|
62
|
-
variant?: 'glow' | 'orbs' | 'spotlight' | 'mesh';
|
|
63
|
-
/** Intensity of effects */
|
|
64
|
-
intensity?: 'subtle' | 'medium' | 'strong';
|
|
65
|
-
/** Color scheme */
|
|
66
|
-
colorScheme?: 'primary' | 'vibrant' | 'cool' | 'warm';
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// =============================================================================
|
|
70
|
-
// AUDIO VIEWER PROPS (legacy)
|
|
71
|
-
// =============================================================================
|
|
72
|
-
|
|
73
|
-
export interface AudioViewerProps {
|
|
74
|
-
/** Audio source URL */
|
|
75
|
-
source: AudioSource;
|
|
76
|
-
/** Auto-play when loaded */
|
|
77
|
-
autoPlay?: boolean;
|
|
78
|
-
/** Show playback controls */
|
|
79
|
-
showControls?: boolean;
|
|
80
|
-
/** Show waveform visualization */
|
|
81
|
-
showWaveform?: boolean;
|
|
82
|
-
/** Show equalizer animation */
|
|
83
|
-
showEqualizer?: boolean;
|
|
84
|
-
/** Show timer */
|
|
85
|
-
showTimer?: boolean;
|
|
86
|
-
/** Show volume control */
|
|
87
|
-
showVolume?: boolean;
|
|
88
|
-
/** Waveform options */
|
|
89
|
-
waveformOptions?: WaveformOptions;
|
|
90
|
-
/** Equalizer options */
|
|
91
|
-
equalizerOptions?: EqualizerOptions;
|
|
92
|
-
/** Callback on playback status change */
|
|
93
|
-
onPlaybackStatusUpdate?: (status: PlaybackStatus) => void;
|
|
94
|
-
/** Additional class name */
|
|
95
|
-
className?: string;
|
|
96
|
-
/** Additional styles */
|
|
97
|
-
style?: CSSProperties;
|
|
98
|
-
}
|