@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.
Files changed (90) hide show
  1. package/package.json +8 -6
  2. package/src/stores/index.ts +8 -0
  3. package/src/stores/mediaCache.ts +474 -0
  4. package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +148 -0
  5. package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +301 -0
  6. package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +281 -0
  7. package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +328 -0
  8. package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +251 -0
  9. package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +427 -0
  10. package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +193 -0
  11. package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +146 -0
  12. package/src/tools/AudioPlayer/README.md +35 -11
  13. package/src/tools/AudioPlayer/{AudioEqualizer.tsx → components/AudioEqualizer.tsx} +29 -64
  14. package/src/tools/AudioPlayer/{AudioPlayer.tsx → components/AudioPlayer.tsx} +22 -14
  15. package/src/tools/AudioPlayer/{AudioShortcutsPopover.tsx → components/AudioShortcutsPopover.tsx} +6 -2
  16. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +147 -0
  17. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +110 -0
  18. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +58 -0
  19. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +45 -0
  20. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +82 -0
  21. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +8 -0
  22. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +6 -0
  23. package/src/tools/AudioPlayer/{SimpleAudioPlayer.tsx → components/SimpleAudioPlayer.tsx} +12 -7
  24. package/src/tools/AudioPlayer/{VisualizationToggle.tsx → components/VisualizationToggle.tsx} +2 -6
  25. package/src/tools/AudioPlayer/components/index.ts +21 -0
  26. package/src/tools/AudioPlayer/context/AudioProvider.tsx +292 -0
  27. package/src/tools/AudioPlayer/context/index.ts +11 -0
  28. package/src/tools/AudioPlayer/context/selectors.ts +96 -0
  29. package/src/tools/AudioPlayer/hooks/index.ts +29 -0
  30. package/src/tools/AudioPlayer/hooks/useAudioAnalysis.ts +110 -0
  31. package/src/tools/AudioPlayer/{useAudioHotkeys.ts → hooks/useAudioHotkeys.ts} +11 -4
  32. package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +106 -0
  33. package/src/tools/AudioPlayer/{useAudioVisualization.tsx → hooks/useVisualization.tsx} +11 -5
  34. package/src/tools/AudioPlayer/index.ts +104 -49
  35. package/src/tools/AudioPlayer/types/audio.ts +107 -0
  36. package/src/tools/AudioPlayer/{types.ts → types/components.ts} +20 -84
  37. package/src/tools/AudioPlayer/types/effects.ts +73 -0
  38. package/src/tools/AudioPlayer/types/index.ts +35 -0
  39. package/src/tools/AudioPlayer/utils/formatTime.ts +10 -0
  40. package/src/tools/AudioPlayer/utils/index.ts +5 -0
  41. package/src/tools/ImageViewer/@refactoring/00-PLAN.md +71 -0
  42. package/src/tools/ImageViewer/@refactoring/01-TYPES.md +121 -0
  43. package/src/tools/ImageViewer/@refactoring/02-UTILS.md +143 -0
  44. package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +261 -0
  45. package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +427 -0
  46. package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +126 -0
  47. package/src/tools/ImageViewer/README.md +16 -3
  48. package/src/tools/ImageViewer/components/ImageInfo.tsx +44 -0
  49. package/src/tools/ImageViewer/components/ImageToolbar.tsx +150 -0
  50. package/src/tools/ImageViewer/components/ImageViewer.tsx +235 -0
  51. package/src/tools/ImageViewer/components/index.ts +7 -0
  52. package/src/tools/ImageViewer/hooks/index.ts +9 -0
  53. package/src/tools/ImageViewer/hooks/useImageLoading.ts +153 -0
  54. package/src/tools/ImageViewer/hooks/useImageTransform.ts +101 -0
  55. package/src/tools/ImageViewer/index.ts +47 -3
  56. package/src/tools/ImageViewer/types.ts +75 -0
  57. package/src/tools/ImageViewer/utils/constants.ts +59 -0
  58. package/src/tools/ImageViewer/utils/index.ts +16 -0
  59. package/src/tools/ImageViewer/utils/lqip.ts +47 -0
  60. package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +91 -0
  61. package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +284 -0
  62. package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +141 -0
  63. package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +178 -0
  64. package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +95 -0
  65. package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +139 -0
  66. package/src/tools/VideoPlayer/README.md +26 -10
  67. package/src/tools/VideoPlayer/{VideoControls.tsx → components/VideoControls.tsx} +8 -9
  68. package/src/tools/VideoPlayer/{VideoErrorFallback.tsx → components/VideoErrorFallback.tsx} +2 -2
  69. package/src/tools/VideoPlayer/{VideoPlayer.tsx → components/VideoPlayer.tsx} +4 -5
  70. package/src/tools/VideoPlayer/components/index.ts +14 -0
  71. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +52 -0
  72. package/src/tools/VideoPlayer/context/index.ts +8 -0
  73. package/src/tools/VideoPlayer/hooks/index.ts +9 -0
  74. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +109 -0
  75. package/src/tools/VideoPlayer/index.ts +29 -20
  76. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +118 -28
  77. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +89 -11
  78. package/src/tools/VideoPlayer/types/index.ts +38 -0
  79. package/src/tools/VideoPlayer/types/player.ts +116 -0
  80. package/src/tools/VideoPlayer/types/provider.ts +93 -0
  81. package/src/tools/VideoPlayer/types/sources.ts +97 -0
  82. package/src/tools/VideoPlayer/utils/fileSource.ts +78 -0
  83. package/src/tools/VideoPlayer/utils/index.ts +11 -0
  84. package/src/tools/VideoPlayer/utils/resolvers.ts +75 -0
  85. package/src/tools/index.ts +10 -0
  86. package/src/tools/AudioPlayer/AudioReactiveCover.tsx +0 -389
  87. package/src/tools/AudioPlayer/context.tsx +0 -426
  88. package/src/tools/ImageViewer/ImageViewer.tsx +0 -416
  89. package/src/tools/VideoPlayer/VideoPlayerContext.tsx +0 -125
  90. package/src/tools/VideoPlayer/types.ts +0 -367
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  /**
4
- * useAudioVisualization - Hook for managing audio visualization settings
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 UseAudioVisualizationReturn {
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<UseAudioVisualizationReturn | null>(null);
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(): UseAudioVisualizationReturn {
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 useAudioVisualization(): UseAudioVisualizationReturn {
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 - Audio playback with waveform visualization
2
+ * AudioPlayer - Complete audio playback solution with reactive visualizations
3
3
  *
4
- * Built on WaveSurfer.js with audio-reactive effects
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
- // Simple wrapper (recommended for most use cases)
8
- export { SimpleAudioPlayer } from './SimpleAudioPlayer';
9
- export type { SimpleAudioPlayerProps } from './SimpleAudioPlayer';
17
+ // =============================================================================
18
+ // COMPONENTS
19
+ // =============================================================================
10
20
 
11
- // Core components (for advanced usage)
12
- export { AudioPlayer } from './AudioPlayer';
13
- export { AudioEqualizer } from './AudioEqualizer';
14
- export { AudioReactiveCover } from './AudioReactiveCover';
15
- export { AudioShortcutsPopover } from './AudioShortcutsPopover';
16
- export { VisualizationToggle } from './VisualizationToggle';
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
- export { useAudioHotkeys, AUDIO_SHORTCUTS } from './useAudioHotkeys';
55
+ // =============================================================================
56
+ // HOOKS
57
+ // =============================================================================
28
58
 
29
59
  export {
30
- useAudioVisualization,
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 './useAudioVisualization';
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
- type EffectVariant,
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
- AudioSource,
61
- PlaybackStatus,
62
- WaveformOptions,
63
- EqualizerOptions,
64
- AudioContextState,
65
- AudioPlayerProps,
66
- AudioEqualizerProps,
67
- AudioReactiveCoverProps,
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
- export type {
72
- VisualizationSettings,
73
- VisualizationVariant,
74
- VisualizationIntensity,
75
- VisualizationColorScheme,
76
- UseAudioVisualizationReturn,
77
- VisualizationProviderProps,
78
- } from './useAudioVisualization';
135
+ // =============================================================================
136
+ // UTILITIES
137
+ // =============================================================================
79
138
 
80
- export type {
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
- import type { CSSProperties } from 'react';
2
- import type WaveSurfer from 'wavesurfer.js';
3
- import type { AudioLevels } from './effects';
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
- // PLAYBACK STATE
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
- // COMPONENT PROPS
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,5 @@
1
+ /**
2
+ * AudioPlayer utilities - Public API
3
+ */
4
+
5
+ export { formatTime } from './formatTime';
@@ -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