@djangocfg/ui-nextjs 2.1.65 → 2.1.67
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 +13 -8
- package/src/blocks/SplitHero/SplitHeroMedia.tsx +2 -1
- package/src/stores/index.ts +8 -0
- package/src/stores/mediaCache.ts +464 -0
- package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +148 -0
- package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +301 -0
- package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +281 -0
- package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +328 -0
- package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +251 -0
- package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +427 -0
- package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +193 -0
- package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +146 -0
- package/src/tools/AudioPlayer/README.md +325 -0
- package/src/tools/AudioPlayer/components/AudioEqualizer.tsx +200 -0
- package/src/tools/AudioPlayer/components/AudioPlayer.tsx +231 -0
- package/src/tools/AudioPlayer/components/AudioShortcutsPopover.tsx +99 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +147 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +110 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +58 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +45 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +82 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +8 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +6 -0
- package/src/tools/AudioPlayer/components/SimpleAudioPlayer.tsx +280 -0
- package/src/tools/AudioPlayer/components/VisualizationToggle.tsx +64 -0
- package/src/tools/AudioPlayer/components/index.ts +21 -0
- package/src/tools/AudioPlayer/context/AudioProvider.tsx +292 -0
- package/src/tools/AudioPlayer/context/index.ts +11 -0
- package/src/tools/AudioPlayer/context/selectors.ts +96 -0
- package/src/tools/AudioPlayer/effects/index.ts +412 -0
- package/src/tools/AudioPlayer/hooks/index.ts +29 -0
- package/src/tools/AudioPlayer/hooks/useAudioAnalysis.ts +110 -0
- package/src/tools/AudioPlayer/hooks/useAudioHotkeys.ts +149 -0
- package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +106 -0
- package/src/tools/AudioPlayer/hooks/useVisualization.tsx +201 -0
- package/src/tools/AudioPlayer/index.ts +139 -0
- package/src/tools/AudioPlayer/types/audio.ts +107 -0
- package/src/tools/AudioPlayer/types/components.ts +98 -0
- package/src/tools/AudioPlayer/types/effects.ts +73 -0
- package/src/tools/AudioPlayer/types/index.ts +35 -0
- package/src/tools/AudioPlayer/utils/formatTime.ts +10 -0
- package/src/tools/AudioPlayer/utils/index.ts +5 -0
- package/src/tools/ImageViewer/@refactoring/00-PLAN.md +71 -0
- package/src/tools/ImageViewer/@refactoring/01-TYPES.md +121 -0
- package/src/tools/ImageViewer/@refactoring/02-UTILS.md +143 -0
- package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +261 -0
- package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +427 -0
- package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +126 -0
- package/src/tools/ImageViewer/README.md +174 -0
- package/src/tools/ImageViewer/components/ImageInfo.tsx +44 -0
- package/src/tools/ImageViewer/components/ImageToolbar.tsx +150 -0
- package/src/tools/ImageViewer/components/ImageViewer.tsx +235 -0
- package/src/tools/ImageViewer/components/index.ts +7 -0
- package/src/tools/ImageViewer/hooks/index.ts +9 -0
- package/src/tools/ImageViewer/hooks/useImageLoading.ts +153 -0
- package/src/tools/ImageViewer/hooks/useImageTransform.ts +101 -0
- package/src/tools/ImageViewer/index.ts +60 -0
- package/src/tools/ImageViewer/types.ts +75 -0
- package/src/tools/ImageViewer/utils/constants.ts +59 -0
- package/src/tools/ImageViewer/utils/index.ts +16 -0
- package/src/tools/ImageViewer/utils/lqip.ts +47 -0
- package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +91 -0
- package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +284 -0
- package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +141 -0
- package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +178 -0
- package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +95 -0
- package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +139 -0
- package/src/tools/VideoPlayer/README.md +212 -187
- package/src/tools/VideoPlayer/{VideoControls.tsx → components/VideoControls.tsx} +8 -9
- package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +174 -0
- package/src/tools/VideoPlayer/components/VideoPlayer.tsx +201 -0
- package/src/tools/VideoPlayer/components/index.ts +14 -0
- package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +52 -0
- package/src/tools/VideoPlayer/context/index.ts +8 -0
- package/src/tools/VideoPlayer/hooks/index.ts +9 -0
- package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +109 -0
- package/src/tools/VideoPlayer/index.ts +70 -9
- package/src/tools/VideoPlayer/providers/NativeProvider.tsx +206 -0
- package/src/tools/VideoPlayer/providers/StreamProvider.tsx +401 -0
- package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +332 -0
- package/src/tools/VideoPlayer/providers/index.ts +8 -0
- package/src/tools/VideoPlayer/types/index.ts +38 -0
- package/src/tools/VideoPlayer/types/player.ts +116 -0
- package/src/tools/VideoPlayer/types/provider.ts +93 -0
- package/src/tools/VideoPlayer/types/sources.ts +97 -0
- package/src/tools/VideoPlayer/utils/fileSource.ts +78 -0
- package/src/tools/VideoPlayer/utils/index.ts +11 -0
- package/src/tools/VideoPlayer/utils/resolvers.ts +75 -0
- package/src/tools/index.ts +92 -4
- package/src/tools/VideoPlayer/NativePlayer.tsx +0 -141
- package/src/tools/VideoPlayer/VideoPlayer.tsx +0 -231
- package/src/tools/VideoPlayer/types.ts +0 -118
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useSharedWebAudio - Manages a shared Web Audio context and source node.
|
|
5
|
+
*
|
|
6
|
+
* This prevents the "InvalidStateError" from creating multiple MediaElementSourceNodes
|
|
7
|
+
* for the same audio element. All analyzers share the same source.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useRef, useEffect, useCallback } from 'react';
|
|
11
|
+
import type { SharedWebAudioContext } from '../types';
|
|
12
|
+
|
|
13
|
+
export function useSharedWebAudio(audioElement: HTMLMediaElement | null): SharedWebAudioContext {
|
|
14
|
+
const audioContextRef = useRef<AudioContext | null>(null);
|
|
15
|
+
const sourceRef = useRef<MediaElementAudioSourceNode | null>(null);
|
|
16
|
+
const connectedElementRef = useRef<HTMLMediaElement | null>(null);
|
|
17
|
+
const analyserNodesRef = useRef<Set<AnalyserNode>>(new Set());
|
|
18
|
+
|
|
19
|
+
// Initialize Web Audio on first play
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!audioElement) return;
|
|
22
|
+
|
|
23
|
+
// Already connected to this element
|
|
24
|
+
if (connectedElementRef.current === audioElement && audioContextRef.current) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const initAudio = () => {
|
|
29
|
+
try {
|
|
30
|
+
if (!audioContextRef.current) {
|
|
31
|
+
const AudioContextClass = window.AudioContext ||
|
|
32
|
+
(window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext;
|
|
33
|
+
audioContextRef.current = new AudioContextClass();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const audioContext = audioContextRef.current;
|
|
37
|
+
|
|
38
|
+
// Only create source node once per audio element
|
|
39
|
+
if (connectedElementRef.current !== audioElement) {
|
|
40
|
+
if (sourceRef.current) {
|
|
41
|
+
try { sourceRef.current.disconnect(); } catch { /* ignore */ }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
sourceRef.current = audioContext.createMediaElementSource(audioElement);
|
|
45
|
+
// Connect directly to destination (analysers will be inserted in between)
|
|
46
|
+
sourceRef.current.connect(audioContext.destination);
|
|
47
|
+
connectedElementRef.current = audioElement;
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.warn('[SharedWebAudio] Could not initialize:', error);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handlePlay = () => {
|
|
55
|
+
initAudio();
|
|
56
|
+
if (audioContextRef.current?.state === 'suspended') {
|
|
57
|
+
audioContextRef.current.resume();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
audioElement.addEventListener('play', handlePlay);
|
|
62
|
+
if (!audioElement.paused) {
|
|
63
|
+
handlePlay();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return () => {
|
|
67
|
+
audioElement.removeEventListener('play', handlePlay);
|
|
68
|
+
};
|
|
69
|
+
}, [audioElement]);
|
|
70
|
+
|
|
71
|
+
// Create an analyser connected to the shared source
|
|
72
|
+
const createAnalyser = useCallback((options?: { fftSize?: number; smoothing?: number }): AnalyserNode | null => {
|
|
73
|
+
if (!audioContextRef.current || !sourceRef.current) return null;
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const analyser = audioContextRef.current.createAnalyser();
|
|
77
|
+
analyser.fftSize = options?.fftSize ?? 256;
|
|
78
|
+
analyser.smoothingTimeConstant = options?.smoothing ?? 0.85;
|
|
79
|
+
|
|
80
|
+
// Connect: source -> analyser -> destination
|
|
81
|
+
sourceRef.current.connect(analyser);
|
|
82
|
+
analyser.connect(audioContextRef.current.destination);
|
|
83
|
+
|
|
84
|
+
analyserNodesRef.current.add(analyser);
|
|
85
|
+
return analyser;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.warn('[SharedWebAudio] Could not create analyser:', error);
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}, []);
|
|
91
|
+
|
|
92
|
+
// Disconnect an analyser
|
|
93
|
+
const disconnectAnalyser = useCallback((analyser: AnalyserNode) => {
|
|
94
|
+
try {
|
|
95
|
+
analyser.disconnect();
|
|
96
|
+
analyserNodesRef.current.delete(analyser);
|
|
97
|
+
} catch { /* ignore */ }
|
|
98
|
+
}, []);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
audioContext: audioContextRef.current,
|
|
102
|
+
sourceNode: sourceRef.current,
|
|
103
|
+
createAnalyser,
|
|
104
|
+
disconnectAnalyser,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useVisualization - Hook for managing audio visualization settings
|
|
5
|
+
*
|
|
6
|
+
* Persists settings in localStorage for user preferences
|
|
7
|
+
* Uses React Context for shared state between components
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createContext, useContext, useCallback, useMemo, type ReactNode } from 'react';
|
|
11
|
+
import { useLocalStorage } from '@djangocfg/ui-nextjs';
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// TYPES
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
export type VisualizationVariant = 'glow' | 'orbs' | 'spotlight' | 'mesh' | 'none';
|
|
18
|
+
export type VisualizationIntensity = 'subtle' | 'medium' | 'strong';
|
|
19
|
+
export type VisualizationColorScheme = 'primary' | 'vibrant' | 'cool' | 'warm';
|
|
20
|
+
|
|
21
|
+
export interface VisualizationSettings {
|
|
22
|
+
/** Enable reactive cover animation */
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
/** Visual effect variant */
|
|
25
|
+
variant: VisualizationVariant;
|
|
26
|
+
/** Effect intensity */
|
|
27
|
+
intensity: VisualizationIntensity;
|
|
28
|
+
/** Color scheme */
|
|
29
|
+
colorScheme: VisualizationColorScheme;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface UseVisualizationReturn {
|
|
33
|
+
/** Current settings */
|
|
34
|
+
settings: VisualizationSettings;
|
|
35
|
+
/** Toggle visualization on/off */
|
|
36
|
+
toggle: () => void;
|
|
37
|
+
/** Set specific setting */
|
|
38
|
+
setSetting: <K extends keyof VisualizationSettings>(
|
|
39
|
+
key: K,
|
|
40
|
+
value: VisualizationSettings[K]
|
|
41
|
+
) => void;
|
|
42
|
+
/** Cycle to next variant */
|
|
43
|
+
nextVariant: () => void;
|
|
44
|
+
/** Cycle to next intensity */
|
|
45
|
+
nextIntensity: () => void;
|
|
46
|
+
/** Cycle to next color scheme */
|
|
47
|
+
nextColorScheme: () => void;
|
|
48
|
+
/** Reset to defaults */
|
|
49
|
+
reset: () => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Backward compatibility alias
|
|
53
|
+
export type UseAudioVisualizationReturn = UseVisualizationReturn;
|
|
54
|
+
|
|
55
|
+
// =============================================================================
|
|
56
|
+
// CONSTANTS
|
|
57
|
+
// =============================================================================
|
|
58
|
+
|
|
59
|
+
const STORAGE_KEY = 'audio-visualization-settings';
|
|
60
|
+
|
|
61
|
+
const DEFAULT_SETTINGS: VisualizationSettings = {
|
|
62
|
+
enabled: true,
|
|
63
|
+
variant: 'spotlight',
|
|
64
|
+
intensity: 'medium',
|
|
65
|
+
colorScheme: 'primary',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const VARIANTS: VisualizationVariant[] = ['spotlight', 'glow', 'orbs', 'mesh', 'none'];
|
|
69
|
+
const INTENSITIES: VisualizationIntensity[] = ['subtle', 'medium', 'strong'];
|
|
70
|
+
const COLOR_SCHEMES: VisualizationColorScheme[] = ['primary', 'vibrant', 'cool', 'warm'];
|
|
71
|
+
|
|
72
|
+
// =============================================================================
|
|
73
|
+
// CONTEXT
|
|
74
|
+
// =============================================================================
|
|
75
|
+
|
|
76
|
+
const VisualizationContext = createContext<UseVisualizationReturn | null>(null);
|
|
77
|
+
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// PROVIDER
|
|
80
|
+
// =============================================================================
|
|
81
|
+
|
|
82
|
+
export interface VisualizationProviderProps {
|
|
83
|
+
children: ReactNode;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function VisualizationProvider({ children }: VisualizationProviderProps) {
|
|
87
|
+
const value = useVisualizationState();
|
|
88
|
+
return (
|
|
89
|
+
<VisualizationContext.Provider value={value}>
|
|
90
|
+
{children}
|
|
91
|
+
</VisualizationContext.Provider>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// =============================================================================
|
|
96
|
+
// INTERNAL HOOK (creates the actual state)
|
|
97
|
+
// =============================================================================
|
|
98
|
+
|
|
99
|
+
function useVisualizationState(): UseVisualizationReturn {
|
|
100
|
+
const [settings, setSettings] = useLocalStorage<VisualizationSettings>(
|
|
101
|
+
STORAGE_KEY,
|
|
102
|
+
DEFAULT_SETTINGS
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const toggle = useCallback(() => {
|
|
106
|
+
setSettings((prev) => ({ ...prev, enabled: !prev.enabled }));
|
|
107
|
+
}, [setSettings]);
|
|
108
|
+
|
|
109
|
+
const setSetting = useCallback(
|
|
110
|
+
<K extends keyof VisualizationSettings>(
|
|
111
|
+
key: K,
|
|
112
|
+
value: VisualizationSettings[K]
|
|
113
|
+
) => {
|
|
114
|
+
setSettings((prev) => ({ ...prev, [key]: value }));
|
|
115
|
+
},
|
|
116
|
+
[setSettings]
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const nextVariant = useCallback(() => {
|
|
120
|
+
setSettings((prev) => {
|
|
121
|
+
const currentIndex = VARIANTS.indexOf(prev.variant);
|
|
122
|
+
const nextIndex = (currentIndex + 1) % VARIANTS.length;
|
|
123
|
+
return { ...prev, variant: VARIANTS[nextIndex] };
|
|
124
|
+
});
|
|
125
|
+
}, [setSettings]);
|
|
126
|
+
|
|
127
|
+
const nextIntensity = useCallback(() => {
|
|
128
|
+
setSettings((prev) => {
|
|
129
|
+
const currentIndex = INTENSITIES.indexOf(prev.intensity);
|
|
130
|
+
const nextIndex = (currentIndex + 1) % INTENSITIES.length;
|
|
131
|
+
return { ...prev, intensity: INTENSITIES[nextIndex] };
|
|
132
|
+
});
|
|
133
|
+
}, [setSettings]);
|
|
134
|
+
|
|
135
|
+
const nextColorScheme = useCallback(() => {
|
|
136
|
+
setSettings((prev) => {
|
|
137
|
+
const currentIndex = COLOR_SCHEMES.indexOf(prev.colorScheme);
|
|
138
|
+
const nextIndex = (currentIndex + 1) % COLOR_SCHEMES.length;
|
|
139
|
+
return { ...prev, colorScheme: COLOR_SCHEMES[nextIndex] };
|
|
140
|
+
});
|
|
141
|
+
}, [setSettings]);
|
|
142
|
+
|
|
143
|
+
const reset = useCallback(() => {
|
|
144
|
+
setSettings(DEFAULT_SETTINGS);
|
|
145
|
+
}, [setSettings]);
|
|
146
|
+
|
|
147
|
+
return useMemo(
|
|
148
|
+
() => ({
|
|
149
|
+
settings,
|
|
150
|
+
toggle,
|
|
151
|
+
setSetting,
|
|
152
|
+
nextVariant,
|
|
153
|
+
nextIntensity,
|
|
154
|
+
nextColorScheme,
|
|
155
|
+
reset,
|
|
156
|
+
}),
|
|
157
|
+
[settings, toggle, setSetting, nextVariant, nextIntensity, nextColorScheme, reset]
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// =============================================================================
|
|
162
|
+
// HOOK (uses context when available)
|
|
163
|
+
// =============================================================================
|
|
164
|
+
|
|
165
|
+
export function useVisualization(): UseVisualizationReturn {
|
|
166
|
+
const context = useContext(VisualizationContext);
|
|
167
|
+
|
|
168
|
+
// Always call the fallback hooks (React hooks rules require consistent calls)
|
|
169
|
+
const fallbackState = useVisualizationState();
|
|
170
|
+
|
|
171
|
+
// If inside a provider, use shared context; otherwise use fallback
|
|
172
|
+
return context ?? fallbackState;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Backward compatibility alias
|
|
176
|
+
export const useAudioVisualization = useVisualization;
|
|
177
|
+
|
|
178
|
+
// =============================================================================
|
|
179
|
+
// VARIANT INFO
|
|
180
|
+
// =============================================================================
|
|
181
|
+
|
|
182
|
+
export const VARIANT_INFO: Record<VisualizationVariant, { label: string; icon: string }> = {
|
|
183
|
+
spotlight: { label: 'Spotlight', icon: '💫' },
|
|
184
|
+
glow: { label: 'Glow', icon: '✨' },
|
|
185
|
+
orbs: { label: 'Orbs', icon: '🔮' },
|
|
186
|
+
mesh: { label: 'Mesh', icon: '🌈' },
|
|
187
|
+
none: { label: 'Off', icon: '⭕' },
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export const INTENSITY_INFO: Record<VisualizationIntensity, { label: string }> = {
|
|
191
|
+
subtle: { label: 'Subtle' },
|
|
192
|
+
medium: { label: 'Medium' },
|
|
193
|
+
strong: { label: 'Strong' },
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
export const COLOR_SCHEME_INFO: Record<VisualizationColorScheme, { label: string; preview: string }> = {
|
|
197
|
+
primary: { label: 'Primary', preview: '🔵' },
|
|
198
|
+
vibrant: { label: 'Vibrant', preview: '🌈' },
|
|
199
|
+
cool: { label: 'Cool', preview: '💙' },
|
|
200
|
+
warm: { label: 'Warm', preview: '🔥' },
|
|
201
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AudioPlayer - Complete audio playback solution with reactive visualizations
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* // Simple usage
|
|
6
|
+
* import { SimpleAudioPlayer } from '@djangocfg/ui-nextjs';
|
|
7
|
+
* <SimpleAudioPlayer src="/audio.mp3" title="Track Title" />
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // Custom setup with context
|
|
11
|
+
* import { AudioProvider, AudioPlayer, useAudio } from '@djangocfg/ui-nextjs';
|
|
12
|
+
* <AudioProvider source={{ uri: audioUrl }} containerRef={ref}>
|
|
13
|
+
* <AudioPlayer ref={ref} />
|
|
14
|
+
* </AudioProvider>
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// COMPONENTS
|
|
19
|
+
// =============================================================================
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
AudioPlayer,
|
|
23
|
+
SimpleAudioPlayer,
|
|
24
|
+
AudioEqualizer,
|
|
25
|
+
AudioShortcutsPopover,
|
|
26
|
+
VisualizationToggle,
|
|
27
|
+
AudioReactiveCover,
|
|
28
|
+
// Effect components (for custom implementations)
|
|
29
|
+
GlowEffect,
|
|
30
|
+
OrbsEffect,
|
|
31
|
+
SpotlightEffect,
|
|
32
|
+
MeshEffect,
|
|
33
|
+
} from './components';
|
|
34
|
+
|
|
35
|
+
export type {
|
|
36
|
+
SimpleAudioPlayerProps,
|
|
37
|
+
VisualizationToggleProps,
|
|
38
|
+
AudioReactiveCoverProps,
|
|
39
|
+
GlowEffectData,
|
|
40
|
+
} from './components';
|
|
41
|
+
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// CONTEXT
|
|
44
|
+
// =============================================================================
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
AudioProvider,
|
|
48
|
+
AudioPlayerContext,
|
|
49
|
+
useAudio,
|
|
50
|
+
useAudioControls,
|
|
51
|
+
useAudioState,
|
|
52
|
+
useAudioElement,
|
|
53
|
+
} from './context';
|
|
54
|
+
|
|
55
|
+
// =============================================================================
|
|
56
|
+
// HOOKS
|
|
57
|
+
// =============================================================================
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
// Internal hooks (for custom implementations)
|
|
61
|
+
useSharedWebAudio,
|
|
62
|
+
useAudioAnalysis,
|
|
63
|
+
// Public hooks
|
|
64
|
+
useAudioHotkeys,
|
|
65
|
+
AUDIO_SHORTCUTS,
|
|
66
|
+
// Visualization
|
|
67
|
+
useVisualization,
|
|
68
|
+
useAudioVisualization, // backward compat alias
|
|
69
|
+
VisualizationProvider,
|
|
70
|
+
VARIANT_INFO,
|
|
71
|
+
INTENSITY_INFO,
|
|
72
|
+
COLOR_SCHEME_INFO,
|
|
73
|
+
} from './hooks';
|
|
74
|
+
|
|
75
|
+
export type {
|
|
76
|
+
AudioHotkeyOptions,
|
|
77
|
+
ShortcutItem,
|
|
78
|
+
ShortcutGroup,
|
|
79
|
+
VisualizationSettings,
|
|
80
|
+
VisualizationVariant,
|
|
81
|
+
VisualizationIntensity,
|
|
82
|
+
VisualizationColorScheme,
|
|
83
|
+
UseVisualizationReturn,
|
|
84
|
+
UseAudioVisualizationReturn,
|
|
85
|
+
VisualizationProviderProps,
|
|
86
|
+
} from './hooks';
|
|
87
|
+
|
|
88
|
+
// =============================================================================
|
|
89
|
+
// TYPES
|
|
90
|
+
// =============================================================================
|
|
91
|
+
|
|
92
|
+
export type {
|
|
93
|
+
// Audio types
|
|
94
|
+
AudioSource,
|
|
95
|
+
AudioContextState,
|
|
96
|
+
SharedWebAudioContext,
|
|
97
|
+
WaveformOptions,
|
|
98
|
+
PlaybackStatus,
|
|
99
|
+
// Component types
|
|
100
|
+
AudioPlayerProps,
|
|
101
|
+
AudioEqualizerProps,
|
|
102
|
+
AudioViewerProps,
|
|
103
|
+
EqualizerOptions,
|
|
104
|
+
} from './types';
|
|
105
|
+
|
|
106
|
+
// =============================================================================
|
|
107
|
+
// EFFECTS
|
|
108
|
+
// =============================================================================
|
|
109
|
+
|
|
110
|
+
export {
|
|
111
|
+
// Utilities
|
|
112
|
+
getEffectConfig,
|
|
113
|
+
getColors,
|
|
114
|
+
prepareEffectColors,
|
|
115
|
+
calculateGlowLayers,
|
|
116
|
+
calculateOrbs,
|
|
117
|
+
calculateMeshGradients,
|
|
118
|
+
calculateSpotlight,
|
|
119
|
+
// Constants
|
|
120
|
+
INTENSITY_CONFIG,
|
|
121
|
+
COLOR_SCHEMES,
|
|
122
|
+
EFFECT_ANIMATIONS,
|
|
123
|
+
} from './effects';
|
|
124
|
+
|
|
125
|
+
export type {
|
|
126
|
+
EffectVariant,
|
|
127
|
+
EffectIntensity,
|
|
128
|
+
EffectColorScheme,
|
|
129
|
+
AudioLevels,
|
|
130
|
+
EffectConfig,
|
|
131
|
+
EffectColors,
|
|
132
|
+
EffectLayer,
|
|
133
|
+
} from './effects';
|
|
134
|
+
|
|
135
|
+
// =============================================================================
|
|
136
|
+
// UTILITIES
|
|
137
|
+
// =============================================================================
|
|
138
|
+
|
|
139
|
+
export { formatTime } from './utils';
|
|
@@ -0,0 +1,107 @@
|
|
|
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
|
+
uri: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// PLAYBACK STATE
|
|
18
|
+
// =============================================================================
|
|
19
|
+
|
|
20
|
+
export interface PlaybackStatus {
|
|
21
|
+
isLoaded: boolean;
|
|
22
|
+
isPlaying: boolean;
|
|
23
|
+
duration: number;
|
|
24
|
+
currentTime: number;
|
|
25
|
+
volume: number;
|
|
26
|
+
isMuted: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// WAVEFORM OPTIONS
|
|
31
|
+
// =============================================================================
|
|
32
|
+
|
|
33
|
+
export interface WaveformOptions {
|
|
34
|
+
waveColor?: string;
|
|
35
|
+
progressColor?: string;
|
|
36
|
+
height?: number;
|
|
37
|
+
barWidth?: number;
|
|
38
|
+
barRadius?: number;
|
|
39
|
+
barGap?: number;
|
|
40
|
+
cursorWidth?: number;
|
|
41
|
+
cursorColor?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// EQUALIZER OPTIONS
|
|
46
|
+
// =============================================================================
|
|
47
|
+
|
|
48
|
+
export interface EqualizerOptions {
|
|
49
|
+
barCount?: number;
|
|
50
|
+
height?: number;
|
|
51
|
+
gap?: number;
|
|
52
|
+
showPeaks?: boolean;
|
|
53
|
+
barColor?: string;
|
|
54
|
+
peakColor?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// =============================================================================
|
|
58
|
+
// SHARED WEB AUDIO CONTEXT
|
|
59
|
+
// =============================================================================
|
|
60
|
+
|
|
61
|
+
export interface SharedWebAudioContext {
|
|
62
|
+
/** The Web Audio AudioContext instance */
|
|
63
|
+
audioContext: AudioContext | null;
|
|
64
|
+
/** The MediaElementSourceNode connected to the audio element */
|
|
65
|
+
sourceNode: MediaElementAudioSourceNode | null;
|
|
66
|
+
/** Create an AnalyserNode connected to the shared source */
|
|
67
|
+
createAnalyser: (options?: { fftSize?: number; smoothing?: number }) => AnalyserNode | null;
|
|
68
|
+
/** Disconnect and cleanup an AnalyserNode */
|
|
69
|
+
disconnectAnalyser: (analyser: AnalyserNode) => void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// =============================================================================
|
|
73
|
+
// AUDIO CONTEXT STATE
|
|
74
|
+
// =============================================================================
|
|
75
|
+
|
|
76
|
+
export interface AudioContextState {
|
|
77
|
+
// Core instances
|
|
78
|
+
wavesurfer: WaveSurfer | null;
|
|
79
|
+
audioElement: HTMLMediaElement | null;
|
|
80
|
+
/** Shared Web Audio context for analyzers */
|
|
81
|
+
sharedAudio: SharedWebAudioContext;
|
|
82
|
+
|
|
83
|
+
// Playback state
|
|
84
|
+
isReady: boolean;
|
|
85
|
+
isPlaying: boolean;
|
|
86
|
+
currentTime: number;
|
|
87
|
+
duration: number;
|
|
88
|
+
volume: number;
|
|
89
|
+
isMuted: boolean;
|
|
90
|
+
isLooping: boolean;
|
|
91
|
+
|
|
92
|
+
// Audio analysis (for reactive effects)
|
|
93
|
+
audioLevels: AudioLevels;
|
|
94
|
+
|
|
95
|
+
// Actions
|
|
96
|
+
play: () => Promise<void>;
|
|
97
|
+
pause: () => void;
|
|
98
|
+
togglePlay: () => void;
|
|
99
|
+
seek: (time: number) => void;
|
|
100
|
+
seekTo: (progress: number) => void;
|
|
101
|
+
skip: (seconds: number) => void;
|
|
102
|
+
setVolume: (volume: number) => void;
|
|
103
|
+
toggleMute: () => void;
|
|
104
|
+
toggleLoop: () => void;
|
|
105
|
+
setLoop: (enabled: boolean) => void;
|
|
106
|
+
restart: () => void;
|
|
107
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
}
|