@djangocfg/ui-nextjs 2.1.66 → 2.1.68
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 +8 -6
- package/src/stores/index.ts +8 -0
- package/src/stores/mediaCache.ts +474 -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 +35 -11
- package/src/tools/AudioPlayer/{AudioEqualizer.tsx → components/AudioEqualizer.tsx} +29 -64
- package/src/tools/AudioPlayer/{AudioPlayer.tsx → components/AudioPlayer.tsx} +22 -14
- package/src/tools/AudioPlayer/{AudioShortcutsPopover.tsx → components/AudioShortcutsPopover.tsx} +6 -2
- 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/{SimpleAudioPlayer.tsx → components/SimpleAudioPlayer.tsx} +12 -7
- package/src/tools/AudioPlayer/{VisualizationToggle.tsx → components/VisualizationToggle.tsx} +2 -6
- 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/hooks/index.ts +29 -0
- package/src/tools/AudioPlayer/hooks/useAudioAnalysis.ts +110 -0
- package/src/tools/AudioPlayer/{useAudioHotkeys.ts → hooks/useAudioHotkeys.ts} +11 -4
- package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +106 -0
- package/src/tools/AudioPlayer/{useAudioVisualization.tsx → hooks/useVisualization.tsx} +11 -5
- package/src/tools/AudioPlayer/index.ts +104 -49
- package/src/tools/AudioPlayer/types/audio.ts +107 -0
- package/src/tools/AudioPlayer/{types.ts → types/components.ts} +20 -84
- 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 +16 -3
- 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 +47 -3
- 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 +26 -10
- package/src/tools/VideoPlayer/{VideoControls.tsx → components/VideoControls.tsx} +8 -9
- package/src/tools/VideoPlayer/{VideoErrorFallback.tsx → components/VideoErrorFallback.tsx} +2 -2
- package/src/tools/VideoPlayer/{VideoPlayer.tsx → components/VideoPlayer.tsx} +4 -5
- 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 +29 -20
- package/src/tools/VideoPlayer/providers/StreamProvider.tsx +118 -28
- package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +89 -11
- 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 +10 -0
- package/src/tools/AudioPlayer/AudioReactiveCover.tsx +0 -389
- package/src/tools/AudioPlayer/context.tsx +0 -426
- package/src/tools/ImageViewer/ImageViewer.tsx +0 -416
- package/src/tools/VideoPlayer/VideoPlayerContext.tsx +0 -125
- package/src/tools/VideoPlayer/types.ts +0 -367
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* useVisualization - Hook for managing audio visualization settings
|
|
5
5
|
*
|
|
6
6
|
* Persists settings in localStorage for user preferences
|
|
7
7
|
* Uses React Context for shared state between components
|
|
@@ -29,7 +29,7 @@ export interface VisualizationSettings {
|
|
|
29
29
|
colorScheme: VisualizationColorScheme;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export interface
|
|
32
|
+
export interface UseVisualizationReturn {
|
|
33
33
|
/** Current settings */
|
|
34
34
|
settings: VisualizationSettings;
|
|
35
35
|
/** Toggle visualization on/off */
|
|
@@ -49,6 +49,9 @@ export interface UseAudioVisualizationReturn {
|
|
|
49
49
|
reset: () => void;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// Backward compatibility alias
|
|
53
|
+
export type UseAudioVisualizationReturn = UseVisualizationReturn;
|
|
54
|
+
|
|
52
55
|
// =============================================================================
|
|
53
56
|
// CONSTANTS
|
|
54
57
|
// =============================================================================
|
|
@@ -70,7 +73,7 @@ const COLOR_SCHEMES: VisualizationColorScheme[] = ['primary', 'vibrant', 'cool',
|
|
|
70
73
|
// CONTEXT
|
|
71
74
|
// =============================================================================
|
|
72
75
|
|
|
73
|
-
const VisualizationContext = createContext<
|
|
76
|
+
const VisualizationContext = createContext<UseVisualizationReturn | null>(null);
|
|
74
77
|
|
|
75
78
|
// =============================================================================
|
|
76
79
|
// PROVIDER
|
|
@@ -93,7 +96,7 @@ export function VisualizationProvider({ children }: VisualizationProviderProps)
|
|
|
93
96
|
// INTERNAL HOOK (creates the actual state)
|
|
94
97
|
// =============================================================================
|
|
95
98
|
|
|
96
|
-
function useVisualizationState():
|
|
99
|
+
function useVisualizationState(): UseVisualizationReturn {
|
|
97
100
|
const [settings, setSettings] = useLocalStorage<VisualizationSettings>(
|
|
98
101
|
STORAGE_KEY,
|
|
99
102
|
DEFAULT_SETTINGS
|
|
@@ -159,7 +162,7 @@ function useVisualizationState(): UseAudioVisualizationReturn {
|
|
|
159
162
|
// HOOK (uses context when available)
|
|
160
163
|
// =============================================================================
|
|
161
164
|
|
|
162
|
-
export function
|
|
165
|
+
export function useVisualization(): UseVisualizationReturn {
|
|
163
166
|
const context = useContext(VisualizationContext);
|
|
164
167
|
|
|
165
168
|
// Always call the fallback hooks (React hooks rules require consistent calls)
|
|
@@ -169,6 +172,9 @@ export function useAudioVisualization(): UseAudioVisualizationReturn {
|
|
|
169
172
|
return context ?? fallbackState;
|
|
170
173
|
}
|
|
171
174
|
|
|
175
|
+
// Backward compatibility alias
|
|
176
|
+
export const useAudioVisualization = useVisualization;
|
|
177
|
+
|
|
172
178
|
// =============================================================================
|
|
173
179
|
// VARIANT INFO
|
|
174
180
|
// =============================================================================
|
|
@@ -1,50 +1,114 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AudioPlayer -
|
|
2
|
+
* AudioPlayer - Complete audio playback solution with reactive visualizations
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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>
|
|
5
15
|
*/
|
|
6
16
|
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// COMPONENTS
|
|
19
|
+
// =============================================================================
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
+
// =============================================================================
|
|
17
45
|
|
|
18
|
-
// Context and hooks
|
|
19
46
|
export {
|
|
20
47
|
AudioProvider,
|
|
48
|
+
AudioPlayerContext,
|
|
21
49
|
useAudio,
|
|
22
50
|
useAudioControls,
|
|
23
51
|
useAudioState,
|
|
24
52
|
useAudioElement,
|
|
25
53
|
} from './context';
|
|
26
54
|
|
|
27
|
-
|
|
55
|
+
// =============================================================================
|
|
56
|
+
// HOOKS
|
|
57
|
+
// =============================================================================
|
|
28
58
|
|
|
29
59
|
export {
|
|
30
|
-
|
|
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
|
|
31
69
|
VisualizationProvider,
|
|
32
70
|
VARIANT_INFO,
|
|
33
71
|
INTENSITY_INFO,
|
|
34
72
|
COLOR_SCHEME_INFO,
|
|
35
|
-
} from './
|
|
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
|
+
// =============================================================================
|
|
36
109
|
|
|
37
|
-
// Effects utilities
|
|
38
110
|
export {
|
|
39
|
-
|
|
40
|
-
type EffectIntensity,
|
|
41
|
-
type EffectColorScheme,
|
|
42
|
-
type AudioLevels,
|
|
43
|
-
type EffectConfig,
|
|
44
|
-
type EffectColors,
|
|
45
|
-
type EffectLayer,
|
|
46
|
-
INTENSITY_CONFIG,
|
|
47
|
-
COLOR_SCHEMES,
|
|
111
|
+
// Utilities
|
|
48
112
|
getEffectConfig,
|
|
49
113
|
getColors,
|
|
50
114
|
prepareEffectColors,
|
|
@@ -52,33 +116,24 @@ export {
|
|
|
52
116
|
calculateOrbs,
|
|
53
117
|
calculateMeshGradients,
|
|
54
118
|
calculateSpotlight,
|
|
119
|
+
// Constants
|
|
120
|
+
INTENSITY_CONFIG,
|
|
121
|
+
COLOR_SCHEMES,
|
|
55
122
|
EFFECT_ANIMATIONS,
|
|
56
123
|
} from './effects';
|
|
57
124
|
|
|
58
|
-
// Types
|
|
59
125
|
export type {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
AudioViewerProps,
|
|
69
|
-
} from './types';
|
|
126
|
+
EffectVariant,
|
|
127
|
+
EffectIntensity,
|
|
128
|
+
EffectColorScheme,
|
|
129
|
+
AudioLevels,
|
|
130
|
+
EffectConfig,
|
|
131
|
+
EffectColors,
|
|
132
|
+
EffectLayer,
|
|
133
|
+
} from './effects';
|
|
70
134
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
VisualizationIntensity,
|
|
75
|
-
VisualizationColorScheme,
|
|
76
|
-
UseAudioVisualizationReturn,
|
|
77
|
-
VisualizationProviderProps,
|
|
78
|
-
} from './useAudioVisualization';
|
|
135
|
+
// =============================================================================
|
|
136
|
+
// UTILITIES
|
|
137
|
+
// =============================================================================
|
|
79
138
|
|
|
80
|
-
export
|
|
81
|
-
AudioHotkeyOptions,
|
|
82
|
-
ShortcutItem,
|
|
83
|
-
ShortcutGroup,
|
|
84
|
-
} from './useAudioHotkeys';
|
|
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
|
+
}
|
|
@@ -1,90 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// =============================================================================
|
|
6
|
-
// AUDIO SOURCE
|
|
7
|
-
// =============================================================================
|
|
8
|
-
|
|
9
|
-
export interface AudioSource {
|
|
10
|
-
uri: string;
|
|
11
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Component props types
|
|
3
|
+
*/
|
|
12
4
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// =============================================================================
|
|
16
|
-
|
|
17
|
-
export interface PlaybackStatus {
|
|
18
|
-
isLoaded: boolean;
|
|
19
|
-
isPlaying: boolean;
|
|
20
|
-
duration: number;
|
|
21
|
-
currentTime: number;
|
|
22
|
-
volume: number;
|
|
23
|
-
isMuted: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// =============================================================================
|
|
27
|
-
// WAVEFORM OPTIONS
|
|
28
|
-
// =============================================================================
|
|
29
|
-
|
|
30
|
-
export interface WaveformOptions {
|
|
31
|
-
waveColor?: string;
|
|
32
|
-
progressColor?: string;
|
|
33
|
-
height?: number;
|
|
34
|
-
barWidth?: number;
|
|
35
|
-
barRadius?: number;
|
|
36
|
-
barGap?: number;
|
|
37
|
-
cursorWidth?: number;
|
|
38
|
-
cursorColor?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// =============================================================================
|
|
42
|
-
// EQUALIZER OPTIONS
|
|
43
|
-
// =============================================================================
|
|
44
|
-
|
|
45
|
-
export interface EqualizerOptions {
|
|
46
|
-
barCount?: number;
|
|
47
|
-
height?: number;
|
|
48
|
-
gap?: number;
|
|
49
|
-
showPeaks?: boolean;
|
|
50
|
-
barColor?: string;
|
|
51
|
-
peakColor?: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// =============================================================================
|
|
55
|
-
// AUDIO CONTEXT STATE
|
|
56
|
-
// =============================================================================
|
|
57
|
-
|
|
58
|
-
export interface AudioContextState {
|
|
59
|
-
// Core instances
|
|
60
|
-
wavesurfer: WaveSurfer | null;
|
|
61
|
-
audioElement: HTMLMediaElement | null;
|
|
62
|
-
|
|
63
|
-
// Playback state
|
|
64
|
-
isReady: boolean;
|
|
65
|
-
isPlaying: boolean;
|
|
66
|
-
currentTime: number;
|
|
67
|
-
duration: number;
|
|
68
|
-
volume: number;
|
|
69
|
-
isMuted: boolean;
|
|
70
|
-
|
|
71
|
-
// Audio analysis (for reactive effects)
|
|
72
|
-
audioLevels: AudioLevels;
|
|
73
|
-
|
|
74
|
-
// Actions
|
|
75
|
-
play: () => Promise<void>;
|
|
76
|
-
pause: () => void;
|
|
77
|
-
togglePlay: () => void;
|
|
78
|
-
seek: (time: number) => void;
|
|
79
|
-
seekTo: (progress: number) => void;
|
|
80
|
-
skip: (seconds: number) => void;
|
|
81
|
-
setVolume: (volume: number) => void;
|
|
82
|
-
toggleMute: () => void;
|
|
83
|
-
restart: () => void;
|
|
84
|
-
}
|
|
5
|
+
import type { CSSProperties } from 'react';
|
|
6
|
+
import type { WaveformOptions, EqualizerOptions, AudioSource, PlaybackStatus } from './audio';
|
|
85
7
|
|
|
86
8
|
// =============================================================================
|
|
87
|
-
//
|
|
9
|
+
// AUDIO PLAYER PROPS
|
|
88
10
|
// =============================================================================
|
|
89
11
|
|
|
90
12
|
export interface AudioPlayerProps {
|
|
@@ -98,6 +20,8 @@ export interface AudioPlayerProps {
|
|
|
98
20
|
showTimer?: boolean;
|
|
99
21
|
/** Show volume control */
|
|
100
22
|
showVolume?: boolean;
|
|
23
|
+
/** Show loop/repeat button */
|
|
24
|
+
showLoop?: boolean;
|
|
101
25
|
/** WaveSurfer options override */
|
|
102
26
|
waveformOptions?: WaveformOptions;
|
|
103
27
|
/** Equalizer options */
|
|
@@ -108,6 +32,10 @@ export interface AudioPlayerProps {
|
|
|
108
32
|
style?: CSSProperties;
|
|
109
33
|
}
|
|
110
34
|
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// AUDIO EQUALIZER PROPS
|
|
37
|
+
// =============================================================================
|
|
38
|
+
|
|
111
39
|
export interface AudioEqualizerProps {
|
|
112
40
|
/** Number of frequency bars */
|
|
113
41
|
barCount?: number;
|
|
@@ -125,6 +53,10 @@ export interface AudioEqualizerProps {
|
|
|
125
53
|
className?: string;
|
|
126
54
|
}
|
|
127
55
|
|
|
56
|
+
// =============================================================================
|
|
57
|
+
// AUDIO REACTIVE COVER PROPS
|
|
58
|
+
// =============================================================================
|
|
59
|
+
|
|
128
60
|
export interface AudioReactiveCoverProps {
|
|
129
61
|
/** Visual variant */
|
|
130
62
|
variant?: 'glow' | 'orbs' | 'spotlight' | 'mesh';
|
|
@@ -134,6 +66,10 @@ export interface AudioReactiveCoverProps {
|
|
|
134
66
|
colorScheme?: 'primary' | 'vibrant' | 'cool' | 'warm';
|
|
135
67
|
}
|
|
136
68
|
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// AUDIO VIEWER PROPS (legacy)
|
|
71
|
+
// =============================================================================
|
|
72
|
+
|
|
137
73
|
export interface AudioViewerProps {
|
|
138
74
|
/** Audio source URL */
|
|
139
75
|
source: AudioSource;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect-related types for audio-reactive visualizations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// EFFECT TYPES
|
|
7
|
+
// =============================================================================
|
|
8
|
+
|
|
9
|
+
export type EffectVariant = 'glow' | 'orbs' | 'spotlight' | 'mesh';
|
|
10
|
+
export type EffectIntensity = 'subtle' | 'medium' | 'strong';
|
|
11
|
+
export type EffectColorScheme = 'primary' | 'vibrant' | 'cool' | 'warm';
|
|
12
|
+
|
|
13
|
+
export interface AudioLevels {
|
|
14
|
+
bass: number;
|
|
15
|
+
mid: number;
|
|
16
|
+
high: number;
|
|
17
|
+
overall: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface EffectConfig {
|
|
21
|
+
opacity: number;
|
|
22
|
+
scale: number;
|
|
23
|
+
blur: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface EffectColors {
|
|
27
|
+
colors: string[];
|
|
28
|
+
hueShift: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface EffectLayer {
|
|
32
|
+
inset: number;
|
|
33
|
+
opacity: number;
|
|
34
|
+
scale: number;
|
|
35
|
+
background: string;
|
|
36
|
+
blur: string;
|
|
37
|
+
animation?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface Orb {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
size: number;
|
|
44
|
+
color: string;
|
|
45
|
+
opacity: number;
|
|
46
|
+
scale: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface MeshGradient {
|
|
50
|
+
width: string;
|
|
51
|
+
height: string;
|
|
52
|
+
top?: string;
|
|
53
|
+
bottom?: string;
|
|
54
|
+
left?: string;
|
|
55
|
+
right?: string;
|
|
56
|
+
color: string;
|
|
57
|
+
opacity: number;
|
|
58
|
+
scale: number;
|
|
59
|
+
rotation: number;
|
|
60
|
+
blur: string;
|
|
61
|
+
isCenter?: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface SpotlightData {
|
|
65
|
+
rotation: number;
|
|
66
|
+
inset: number;
|
|
67
|
+
colors: Array<{ color: string; opacity: number }>;
|
|
68
|
+
pulseInset: number;
|
|
69
|
+
pulseOpacity: number;
|
|
70
|
+
pulseScale: number;
|
|
71
|
+
ringOpacity: number;
|
|
72
|
+
ringScale: number;
|
|
73
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AudioPlayer types - re-exports all types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Audio types
|
|
6
|
+
export type {
|
|
7
|
+
AudioSource,
|
|
8
|
+
PlaybackStatus,
|
|
9
|
+
WaveformOptions,
|
|
10
|
+
EqualizerOptions,
|
|
11
|
+
SharedWebAudioContext,
|
|
12
|
+
AudioContextState,
|
|
13
|
+
} from './audio';
|
|
14
|
+
|
|
15
|
+
// Component props
|
|
16
|
+
export type {
|
|
17
|
+
AudioPlayerProps,
|
|
18
|
+
AudioEqualizerProps,
|
|
19
|
+
AudioReactiveCoverProps,
|
|
20
|
+
AudioViewerProps,
|
|
21
|
+
} from './components';
|
|
22
|
+
|
|
23
|
+
// Effect types
|
|
24
|
+
export type {
|
|
25
|
+
EffectVariant,
|
|
26
|
+
EffectIntensity,
|
|
27
|
+
EffectColorScheme,
|
|
28
|
+
AudioLevels,
|
|
29
|
+
EffectConfig,
|
|
30
|
+
EffectColors,
|
|
31
|
+
EffectLayer,
|
|
32
|
+
Orb,
|
|
33
|
+
MeshGradient,
|
|
34
|
+
SpotlightData,
|
|
35
|
+
} from './effects';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* formatTime - Format seconds to mm:ss string
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function formatTime(seconds: number): string {
|
|
6
|
+
if (!seconds || !isFinite(seconds) || seconds < 0) return '0:00';
|
|
7
|
+
const mins = Math.floor(seconds / 60);
|
|
8
|
+
const secs = Math.floor(seconds % 60);
|
|
9
|
+
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
10
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# ImageViewer Refactoring Plan
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Decompose the monolithic 589-line `ImageViewer.tsx` into a well-organized module structure similar to AudioPlayer.
|
|
6
|
+
|
|
7
|
+
## Current Structure (Before)
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
ImageViewer/
|
|
11
|
+
├── ImageViewer.tsx (589 lines) - Everything in one file
|
|
12
|
+
├── index.ts (16 lines)
|
|
13
|
+
└── README.md
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Issues:**
|
|
17
|
+
- Single 589-line file with mixed concerns
|
|
18
|
+
- 2 sub-components inline (ImageToolbar, ImageInfo)
|
|
19
|
+
- 1 utility function inline (createLQIP)
|
|
20
|
+
- 8 separate useState calls
|
|
21
|
+
- Types defined inline
|
|
22
|
+
- Constants hardcoded
|
|
23
|
+
|
|
24
|
+
## Target Structure (After)
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
ImageViewer/
|
|
28
|
+
├── index.ts # Public API
|
|
29
|
+
├── README.md # Documentation
|
|
30
|
+
├── components/
|
|
31
|
+
│ ├── index.ts
|
|
32
|
+
│ ├── ImageViewer.tsx # Main component (~150 lines)
|
|
33
|
+
│ ├── ImageToolbar.tsx # Toolbar with zoom/rotate/flip (~130 lines)
|
|
34
|
+
│ └── ImageInfo.tsx # Dimensions display (~35 lines)
|
|
35
|
+
├── hooks/
|
|
36
|
+
│ ├── index.ts
|
|
37
|
+
│ ├── useImageTransform.ts # Rotation/flip state management
|
|
38
|
+
│ └── useImageLoading.ts # LQIP and loading state
|
|
39
|
+
├── utils/
|
|
40
|
+
│ ├── index.ts
|
|
41
|
+
│ ├── lqip.ts # LQIP generator utility
|
|
42
|
+
│ └── constants.ts # Zoom presets, size limits
|
|
43
|
+
└── types.ts # All type definitions
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Benefits
|
|
47
|
+
|
|
48
|
+
1. **Separation of Concerns** - Each file has single responsibility
|
|
49
|
+
2. **Testability** - Hooks and utils can be unit tested independently
|
|
50
|
+
3. **Reusability** - Components can be used standalone
|
|
51
|
+
4. **Maintainability** - Easier to find and modify specific functionality
|
|
52
|
+
5. **Code Organization** - Consistent with AudioPlayer structure
|
|
53
|
+
|
|
54
|
+
## Execution Phases
|
|
55
|
+
|
|
56
|
+
| Phase | Description | Files |
|
|
57
|
+
|-------|-------------|-------|
|
|
58
|
+
| 1 | Create folder structure | components/, hooks/, utils/ |
|
|
59
|
+
| 2 | Extract types | types.ts |
|
|
60
|
+
| 3 | Extract constants and utilities | utils/constants.ts, utils/lqip.ts |
|
|
61
|
+
| 4 | Extract hooks | hooks/useImageTransform.ts, hooks/useImageLoading.ts |
|
|
62
|
+
| 5 | Split components | ImageToolbar.tsx, ImageInfo.tsx |
|
|
63
|
+
| 6 | Refactor main component | ImageViewer.tsx (simplified) |
|
|
64
|
+
| 7 | Update exports | index.ts, components/index.ts, hooks/index.ts |
|
|
65
|
+
| 8 | Cleanup and verify | Delete old file, run pnpm check |
|
|
66
|
+
|
|
67
|
+
## Risk Assessment
|
|
68
|
+
|
|
69
|
+
- **Low Risk**: Pure extraction with no logic changes
|
|
70
|
+
- **Testing**: Run `pnpm check` after each phase
|
|
71
|
+
- **Rollback**: Keep old file until verification complete
|