@djangocfg/ui-nextjs 2.1.81 → 2.1.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/tools/AudioPlayer/@refactoring3/00-IMPLEMENTATION-ROADMAP.md +1146 -0
- package/src/tools/AudioPlayer/@refactoring3/01-WAVESURFER-STREAMING-ANALYSIS.md +611 -0
- package/src/tools/AudioPlayer/@refactoring3/02-MEDIA-VIEWER-ANALYSIS.md +560 -0
- package/src/tools/AudioPlayer/@refactoring3/03-HYBRID-ARCHITECTURE-PROPOSAL.md +769 -0
- package/src/tools/AudioPlayer/@refactoring3/04-CRACKLING-ISSUE-DIAGNOSIS.md +373 -0
- package/src/tools/AudioPlayer/README.md +177 -205
- package/src/tools/AudioPlayer/components/AudioPlayer.tsx +9 -4
- package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +251 -0
- package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +291 -0
- package/src/tools/AudioPlayer/components/HybridWaveform.tsx +279 -0
- package/src/tools/AudioPlayer/components/SimpleAudioPlayer.tsx +16 -26
- package/src/tools/AudioPlayer/components/index.ts +6 -1
- package/src/tools/AudioPlayer/context/AudioProvider.tsx +16 -8
- package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +121 -0
- package/src/tools/AudioPlayer/context/index.ts +14 -2
- package/src/tools/AudioPlayer/hooks/index.ts +11 -0
- package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +387 -0
- package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +95 -0
- package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +6 -3
- package/src/tools/AudioPlayer/index.ts +31 -0
- package/src/tools/AudioPlayer/progressive/ProgressiveAudioPlayer.tsx +8 -0
- package/src/tools/ImageViewer/hooks/useImageLoading.ts +33 -9
- package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +13 -6
- package/src/tools/VideoPlayer/providers/StreamProvider.tsx +38 -22
- package/src/tools/index.ts +22 -0
- package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +0 -148
- package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +0 -301
- package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +0 -281
- package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +0 -328
- package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +0 -251
- package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +0 -427
- package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +0 -193
- package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +0 -146
- package/src/tools/AudioPlayer/@refactoring2/ISSUE_ANALYSIS.md +0 -187
- package/src/tools/AudioPlayer/@refactoring2/PLAN.md +0 -372
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { useRef, useEffect, useCallback } from 'react';
|
|
10
|
-
import {
|
|
10
|
+
import { useMediaCacheStore } from '../../../stores/mediaCache';
|
|
11
11
|
|
|
12
12
|
// =============================================================================
|
|
13
13
|
// TYPES
|
|
@@ -54,7 +54,10 @@ export function useVideoPositionCache(
|
|
|
54
54
|
): UseVideoPositionCacheReturn {
|
|
55
55
|
const { cacheKey, currentTime, duration, isPlaying, isReady, onSeek } = options;
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
// Get stable function references from store
|
|
58
|
+
const saveVideoPosition = useMediaCacheStore.getState().saveVideoPosition;
|
|
59
|
+
const getVideoPosition = useMediaCacheStore.getState().getVideoPosition;
|
|
60
|
+
|
|
58
61
|
const lastSavedTimeRef = useRef<number>(0);
|
|
59
62
|
const hasRestoredRef = useRef<boolean>(false);
|
|
60
63
|
|
|
@@ -70,7 +73,8 @@ export function useVideoPositionCache(
|
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
hasRestoredRef.current = true;
|
|
73
|
-
|
|
76
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
77
|
+
}, [isReady, cacheKey, duration, onSeek]);
|
|
74
78
|
|
|
75
79
|
// Reset restored flag when cache key changes
|
|
76
80
|
useEffect(() => {
|
|
@@ -87,20 +91,23 @@ export function useVideoPositionCache(
|
|
|
87
91
|
saveVideoPosition(cacheKey, currentTime);
|
|
88
92
|
lastSavedTimeRef.current = currentTime;
|
|
89
93
|
}
|
|
90
|
-
|
|
94
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
95
|
+
}, [cacheKey, isPlaying, currentTime]);
|
|
91
96
|
|
|
92
97
|
const savePosition = useCallback(() => {
|
|
93
98
|
if (cacheKey && currentTime > 0) {
|
|
94
99
|
saveVideoPosition(cacheKey, currentTime);
|
|
95
100
|
lastSavedTimeRef.current = currentTime;
|
|
96
101
|
}
|
|
97
|
-
|
|
102
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
103
|
+
}, [cacheKey, currentTime]);
|
|
98
104
|
|
|
99
105
|
const clearPosition = useCallback(() => {
|
|
100
106
|
if (cacheKey) {
|
|
101
107
|
saveVideoPosition(cacheKey, 0);
|
|
102
108
|
}
|
|
103
|
-
|
|
109
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
110
|
+
}, [cacheKey]);
|
|
104
111
|
|
|
105
112
|
return {
|
|
106
113
|
savePosition,
|
|
@@ -14,7 +14,7 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef,
|
|
|
14
14
|
|
|
15
15
|
import { cn } from '@djangocfg/ui-core/lib';
|
|
16
16
|
import { Preloader, AspectRatio } from '@djangocfg/ui-core';
|
|
17
|
-
import {
|
|
17
|
+
import { useMediaCacheStore, generateContentKey } from '../../../stores/mediaCache';
|
|
18
18
|
|
|
19
19
|
import type { StreamProviderProps, VideoPlayerRef, StreamSource, BlobSource, DataUrlSource, ErrorFallbackProps } from '../types';
|
|
20
20
|
import { videoDebug } from '../utils/debug';
|
|
@@ -77,14 +77,12 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
|
|
|
77
77
|
const contentKeyRef = useRef<string | null>(null);
|
|
78
78
|
const lastSavedTimeRef = useRef<number>(0);
|
|
79
79
|
|
|
80
|
-
//
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
getVideoPosition,
|
|
87
|
-
} = useVideoCache();
|
|
80
|
+
// Get stable function references from store (not from hook to avoid re-renders)
|
|
81
|
+
const getOrCreateBlobUrl = useMediaCacheStore.getState().getOrCreateBlobUrl;
|
|
82
|
+
const releaseBlobUrl = useMediaCacheStore.getState().releaseBlobUrl;
|
|
83
|
+
const getOrCreateStreamUrl = useMediaCacheStore.getState().getOrCreateStreamUrl;
|
|
84
|
+
const saveVideoPosition = useMediaCacheStore.getState().saveVideoPosition;
|
|
85
|
+
const getVideoPosition = useMediaCacheStore.getState().getVideoPosition;
|
|
88
86
|
|
|
89
87
|
// Retry function for error fallback
|
|
90
88
|
// Regenerates URL for stream sources to get fresh token/session
|
|
@@ -143,12 +141,31 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
|
|
|
143
141
|
[]
|
|
144
142
|
);
|
|
145
143
|
|
|
144
|
+
// Track unmount for cleanup
|
|
145
|
+
const isMountedRef = useRef(true);
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
isMountedRef.current = true;
|
|
148
|
+
return () => {
|
|
149
|
+
isMountedRef.current = false;
|
|
150
|
+
// Release blob URL only on actual unmount
|
|
151
|
+
if (contentKeyRef.current) {
|
|
152
|
+
useMediaCacheStore.getState().releaseBlobUrl(contentKeyRef.current);
|
|
153
|
+
contentKeyRef.current = null;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}, []);
|
|
157
|
+
|
|
146
158
|
// Create video URL based on source type with caching
|
|
147
159
|
useEffect(() => {
|
|
148
|
-
//
|
|
160
|
+
// Release previous blob URL if source changed
|
|
149
161
|
if (contentKeyRef.current) {
|
|
150
|
-
|
|
151
|
-
|
|
162
|
+
const newKey = source.type === 'blob'
|
|
163
|
+
? generateContentKey((source as BlobSource).data)
|
|
164
|
+
: null;
|
|
165
|
+
if (newKey !== contentKeyRef.current) {
|
|
166
|
+
releaseBlobUrl(contentKeyRef.current);
|
|
167
|
+
contentKeyRef.current = null;
|
|
168
|
+
}
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
setHasError(false);
|
|
@@ -198,13 +215,9 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
|
|
|
198
215
|
setErrorMessage('Invalid video source');
|
|
199
216
|
}
|
|
200
217
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
contentKeyRef.current = null;
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
}, [source, getOrCreateBlobUrl, getOrCreateStreamUrl, releaseBlobUrl]);
|
|
218
|
+
// No cleanup here - cleanup happens in unmount effect above
|
|
219
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
220
|
+
}, [source]);
|
|
208
221
|
|
|
209
222
|
// Get source key for position caching
|
|
210
223
|
const getSourceKey = useCallback(() => {
|
|
@@ -244,7 +257,8 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
|
|
|
244
257
|
}
|
|
245
258
|
|
|
246
259
|
onCanPlay?.();
|
|
247
|
-
|
|
260
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
261
|
+
}, [getSourceKey, onCanPlay]);
|
|
248
262
|
|
|
249
263
|
// Save playback position periodically
|
|
250
264
|
const handleTimeUpdate = useCallback(() => {
|
|
@@ -262,7 +276,8 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
|
|
|
262
276
|
}
|
|
263
277
|
|
|
264
278
|
onTimeUpdate?.(video.currentTime, video.duration);
|
|
265
|
-
|
|
279
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
280
|
+
}, [getSourceKey, onTimeUpdate]);
|
|
266
281
|
|
|
267
282
|
// Save position on pause
|
|
268
283
|
const handlePause = useCallback(() => {
|
|
@@ -273,7 +288,8 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
|
|
|
273
288
|
lastSavedTimeRef.current = video.currentTime;
|
|
274
289
|
}
|
|
275
290
|
onPause?.();
|
|
276
|
-
|
|
291
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
292
|
+
}, [getSourceKey, onPause]);
|
|
277
293
|
|
|
278
294
|
// Handle buffer progress
|
|
279
295
|
const handleProgress = useCallback(() => {
|
package/src/tools/index.ts
CHANGED
|
@@ -110,6 +110,18 @@ export {
|
|
|
110
110
|
mergePeaks,
|
|
111
111
|
resamplePeaks,
|
|
112
112
|
smoothPeaks,
|
|
113
|
+
// Hybrid Audio Player (HTML5 audio + Web Audio visualization)
|
|
114
|
+
HybridSimplePlayer,
|
|
115
|
+
HybridAudioPlayer,
|
|
116
|
+
HybridWaveform,
|
|
117
|
+
HybridAudioProvider,
|
|
118
|
+
useHybridAudioContext,
|
|
119
|
+
useHybridAudioState,
|
|
120
|
+
useHybridAudioControls,
|
|
121
|
+
useHybridAudioLevels,
|
|
122
|
+
useHybridWebAudio,
|
|
123
|
+
useHybridAudio,
|
|
124
|
+
useHybridAudioAnalysis,
|
|
113
125
|
} from './AudioPlayer';
|
|
114
126
|
export type {
|
|
115
127
|
SimpleAudioPlayerProps,
|
|
@@ -136,6 +148,16 @@ export type {
|
|
|
136
148
|
LoadedRange,
|
|
137
149
|
ProgressiveAudioState,
|
|
138
150
|
ProgressiveAudioControls,
|
|
151
|
+
// Hybrid types
|
|
152
|
+
HybridSimplePlayerProps,
|
|
153
|
+
HybridAudioPlayerProps,
|
|
154
|
+
HybridWaveformProps,
|
|
155
|
+
HybridAudioProviderProps,
|
|
156
|
+
HybridAudioContextValue,
|
|
157
|
+
UseHybridAudioOptions,
|
|
158
|
+
HybridAudioState,
|
|
159
|
+
HybridAudioControls,
|
|
160
|
+
HybridWebAudioAPI,
|
|
139
161
|
} from './AudioPlayer';
|
|
140
162
|
|
|
141
163
|
// Export ImageViewer
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# AudioPlayer Refactoring Plan
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
Decompose the AudioPlayer module into a clean, maintainable folder structure with proper separation of concerns.
|
|
6
|
-
|
|
7
|
-
## Current Issues
|
|
8
|
-
|
|
9
|
-
1. **`context.tsx` is too large (574 lines)** - contains 4 different hooks and provider
|
|
10
|
-
2. **`types.ts` is monolithic (185 lines)** - mixes audio, component, and effect types
|
|
11
|
-
3. **`effects/index.ts` is overloaded (413 lines)** - types, constants, and calculations together
|
|
12
|
-
4. **`AudioReactiveCover.tsx` has inline effect components** - harder to maintain
|
|
13
|
-
|
|
14
|
-
## Target Structure
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
AudioPlayer/
|
|
18
|
-
├── index.ts # Public API (re-exports)
|
|
19
|
-
│
|
|
20
|
-
├── types/
|
|
21
|
-
│ ├── index.ts # Re-exports all types
|
|
22
|
-
│ ├── audio.ts # Core audio types
|
|
23
|
-
│ ├── components.ts # Component props
|
|
24
|
-
│ └── effects.ts # Effect-related types
|
|
25
|
-
│
|
|
26
|
-
├── hooks/
|
|
27
|
-
│ ├── index.ts # Re-exports all hooks
|
|
28
|
-
│ ├── useSharedWebAudio.ts # Web Audio API management
|
|
29
|
-
│ ├── useAudioAnalysis.ts # Frequency analysis
|
|
30
|
-
│ ├── useAudioHotkeys.ts # Keyboard shortcuts (existing)
|
|
31
|
-
│ └── useVisualization.tsx # Settings + Provider (renamed)
|
|
32
|
-
│
|
|
33
|
-
├── context/
|
|
34
|
-
│ ├── index.ts # Re-exports
|
|
35
|
-
│ ├── AudioProvider.tsx # Provider component only
|
|
36
|
-
│ └── selectors.ts # useAudio, useAudioControls, useAudioState, useAudioElement
|
|
37
|
-
│
|
|
38
|
-
├── components/
|
|
39
|
-
│ ├── index.ts # Re-exports
|
|
40
|
-
│ ├── AudioPlayer.tsx # Main player UI
|
|
41
|
-
│ ├── AudioEqualizer.tsx # Equalizer visualization
|
|
42
|
-
│ ├── SimpleAudioPlayer.tsx # Easy-to-use wrapper
|
|
43
|
-
│ ├── ShortcutsPopover.tsx # Keyboard shortcuts popover
|
|
44
|
-
│ ├── VisualizationToggle.tsx # Effect toggle button
|
|
45
|
-
│ └── ReactiveCover/ # Cover with effects
|
|
46
|
-
│ ├── index.tsx # Main component
|
|
47
|
-
│ ├── GlowEffect.tsx # Glow effect
|
|
48
|
-
│ ├── OrbsEffect.tsx # Orbs effect
|
|
49
|
-
│ ├── SpotlightEffect.tsx # Spotlight effect
|
|
50
|
-
│ └── MeshEffect.tsx # Mesh gradient effect
|
|
51
|
-
│
|
|
52
|
-
├── effects/
|
|
53
|
-
│ ├── index.ts # Re-exports
|
|
54
|
-
│ ├── constants.ts # INTENSITY_CONFIG, COLOR_SCHEMES
|
|
55
|
-
│ ├── calculations.ts # calculateGlowLayers, calculateOrbs, etc.
|
|
56
|
-
│ └── animations.ts # EFFECT_ANIMATIONS CSS string
|
|
57
|
-
│
|
|
58
|
-
└── utils/
|
|
59
|
-
├── index.ts # Re-exports
|
|
60
|
-
└── formatTime.ts # Time formatting helper
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Migration Steps
|
|
64
|
-
|
|
65
|
-
### Phase 1: Create folder structure
|
|
66
|
-
- [ ] Create `types/`, `hooks/`, `context/`, `components/`, `effects/`, `utils/` folders
|
|
67
|
-
|
|
68
|
-
### Phase 2: Split types
|
|
69
|
-
- [ ] Create `types/audio.ts` - AudioSource, PlaybackStatus, SharedWebAudioContext, AudioContextState
|
|
70
|
-
- [ ] Create `types/components.ts` - AudioPlayerProps, AudioEqualizerProps, etc.
|
|
71
|
-
- [ ] Create `types/effects.ts` - EffectVariant, AudioLevels, EffectConfig, etc.
|
|
72
|
-
- [ ] Create `types/index.ts` - re-export all
|
|
73
|
-
|
|
74
|
-
### Phase 3: Extract hooks from context.tsx
|
|
75
|
-
- [ ] Create `hooks/useSharedWebAudio.ts` - extract from context.tsx
|
|
76
|
-
- [ ] Create `hooks/useAudioAnalysis.ts` - extract from context.tsx
|
|
77
|
-
- [ ] Move `useAudioHotkeys.ts` to `hooks/`
|
|
78
|
-
- [ ] Move `useAudioVisualization.tsx` to `hooks/useVisualization.tsx`
|
|
79
|
-
- [ ] Create `hooks/index.ts`
|
|
80
|
-
|
|
81
|
-
### Phase 4: Refactor context
|
|
82
|
-
- [ ] Create `context/AudioProvider.tsx` - provider only
|
|
83
|
-
- [ ] Create `context/selectors.ts` - useAudio, useAudioControls, useAudioState, useAudioElement
|
|
84
|
-
- [ ] Create `context/index.ts`
|
|
85
|
-
|
|
86
|
-
### Phase 5: Reorganize components
|
|
87
|
-
- [ ] Move `AudioPlayer.tsx` to `components/`
|
|
88
|
-
- [ ] Move `AudioEqualizer.tsx` to `components/`
|
|
89
|
-
- [ ] Move `SimpleAudioPlayer.tsx` to `components/`
|
|
90
|
-
- [ ] Rename and move `AudioShortcutsPopover.tsx` to `components/ShortcutsPopover.tsx`
|
|
91
|
-
- [ ] Move `VisualizationToggle.tsx` to `components/`
|
|
92
|
-
- [ ] Split `AudioReactiveCover.tsx` into `components/ReactiveCover/`
|
|
93
|
-
|
|
94
|
-
### Phase 6: Refactor effects
|
|
95
|
-
- [ ] Create `effects/constants.ts` - INTENSITY_CONFIG, COLOR_SCHEMES
|
|
96
|
-
- [ ] Create `effects/calculations.ts` - all calculate* functions
|
|
97
|
-
- [ ] Create `effects/animations.ts` - EFFECT_ANIMATIONS
|
|
98
|
-
- [ ] Update `effects/index.ts`
|
|
99
|
-
|
|
100
|
-
### Phase 7: Create utils
|
|
101
|
-
- [ ] Create `utils/formatTime.ts` - extract from AudioPlayer.tsx
|
|
102
|
-
- [ ] Create `utils/index.ts`
|
|
103
|
-
|
|
104
|
-
### Phase 8: Update main index.ts
|
|
105
|
-
- [ ] Update `index.ts` to re-export from new locations
|
|
106
|
-
- [ ] Ensure backward compatibility of public API
|
|
107
|
-
|
|
108
|
-
### Phase 9: Cleanup
|
|
109
|
-
- [ ] Delete old files
|
|
110
|
-
- [ ] Run type check
|
|
111
|
-
- [ ] Test imports
|
|
112
|
-
|
|
113
|
-
## File Size Targets
|
|
114
|
-
|
|
115
|
-
| File | Current | Target |
|
|
116
|
-
|------|---------|--------|
|
|
117
|
-
| context.tsx | 574 lines | Split into 4 files (~100-150 each) |
|
|
118
|
-
| types.ts | 185 lines | Split into 3 files (~60 each) |
|
|
119
|
-
| effects/index.ts | 413 lines | Split into 3 files (~100-150 each) |
|
|
120
|
-
| AudioReactiveCover.tsx | 390 lines | Split into 5 files (~80 each) |
|
|
121
|
-
|
|
122
|
-
## Public API (must remain unchanged)
|
|
123
|
-
|
|
124
|
-
```typescript
|
|
125
|
-
// Components
|
|
126
|
-
export { SimpleAudioPlayer } from './components';
|
|
127
|
-
export { AudioPlayer } from './components';
|
|
128
|
-
export { AudioEqualizer } from './components';
|
|
129
|
-
export { AudioReactiveCover } from './components';
|
|
130
|
-
export { AudioShortcutsPopover } from './components'; // alias for backward compat
|
|
131
|
-
|
|
132
|
-
// Context & Hooks
|
|
133
|
-
export { AudioProvider, useAudio, useAudioControls, useAudioState, useAudioElement } from './context';
|
|
134
|
-
export { useAudioHotkeys, AUDIO_SHORTCUTS } from './hooks';
|
|
135
|
-
export { useAudioVisualization, VisualizationProvider } from './hooks'; // alias
|
|
136
|
-
|
|
137
|
-
// Effects utilities
|
|
138
|
-
export { INTENSITY_CONFIG, COLOR_SCHEMES, ... } from './effects';
|
|
139
|
-
|
|
140
|
-
// Types (all existing types)
|
|
141
|
-
export type { AudioSource, PlaybackStatus, ... } from './types';
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## Notes
|
|
145
|
-
|
|
146
|
-
- Keep backward compatibility for all public exports
|
|
147
|
-
- Internal imports will change but external API stays the same
|
|
148
|
-
- Run `pnpm check` after each phase to catch issues early
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
# Phase 2: Types Split
|
|
2
|
-
|
|
3
|
-
## Source: `types.ts` (185 lines)
|
|
4
|
-
|
|
5
|
-
Split into 3 files by domain.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## `types/audio.ts`
|
|
10
|
-
|
|
11
|
-
Core audio-related types.
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import type WaveSurfer from 'wavesurfer.js';
|
|
15
|
-
import type { AudioLevels } from '../effects';
|
|
16
|
-
|
|
17
|
-
// =============================================================================
|
|
18
|
-
// AUDIO SOURCE
|
|
19
|
-
// =============================================================================
|
|
20
|
-
|
|
21
|
-
export interface AudioSource {
|
|
22
|
-
uri: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// =============================================================================
|
|
26
|
-
// PLAYBACK STATE
|
|
27
|
-
// =============================================================================
|
|
28
|
-
|
|
29
|
-
export interface PlaybackStatus {
|
|
30
|
-
isLoaded: boolean;
|
|
31
|
-
isPlaying: boolean;
|
|
32
|
-
duration: number;
|
|
33
|
-
currentTime: number;
|
|
34
|
-
volume: number;
|
|
35
|
-
isMuted: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// =============================================================================
|
|
39
|
-
// WAVEFORM OPTIONS
|
|
40
|
-
// =============================================================================
|
|
41
|
-
|
|
42
|
-
export interface WaveformOptions {
|
|
43
|
-
waveColor?: string;
|
|
44
|
-
progressColor?: string;
|
|
45
|
-
height?: number;
|
|
46
|
-
barWidth?: number;
|
|
47
|
-
barRadius?: number;
|
|
48
|
-
barGap?: number;
|
|
49
|
-
cursorWidth?: number;
|
|
50
|
-
cursorColor?: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// =============================================================================
|
|
54
|
-
// EQUALIZER OPTIONS
|
|
55
|
-
// =============================================================================
|
|
56
|
-
|
|
57
|
-
export interface EqualizerOptions {
|
|
58
|
-
barCount?: number;
|
|
59
|
-
height?: number;
|
|
60
|
-
gap?: number;
|
|
61
|
-
showPeaks?: boolean;
|
|
62
|
-
barColor?: string;
|
|
63
|
-
peakColor?: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// =============================================================================
|
|
67
|
-
// SHARED WEB AUDIO CONTEXT
|
|
68
|
-
// =============================================================================
|
|
69
|
-
|
|
70
|
-
export interface SharedWebAudioContext {
|
|
71
|
-
audioContext: AudioContext | null;
|
|
72
|
-
sourceNode: MediaElementAudioSourceNode | null;
|
|
73
|
-
createAnalyser: (options?: { fftSize?: number; smoothing?: number }) => AnalyserNode | null;
|
|
74
|
-
disconnectAnalyser: (analyser: AnalyserNode) => void;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// =============================================================================
|
|
78
|
-
// AUDIO CONTEXT STATE
|
|
79
|
-
// =============================================================================
|
|
80
|
-
|
|
81
|
-
export interface AudioContextState {
|
|
82
|
-
// Core instances
|
|
83
|
-
wavesurfer: WaveSurfer | null;
|
|
84
|
-
audioElement: HTMLMediaElement | null;
|
|
85
|
-
sharedAudio: SharedWebAudioContext;
|
|
86
|
-
|
|
87
|
-
// Playback state
|
|
88
|
-
isReady: boolean;
|
|
89
|
-
isPlaying: boolean;
|
|
90
|
-
currentTime: number;
|
|
91
|
-
duration: number;
|
|
92
|
-
volume: number;
|
|
93
|
-
isMuted: boolean;
|
|
94
|
-
isLooping: boolean;
|
|
95
|
-
|
|
96
|
-
// Audio analysis
|
|
97
|
-
audioLevels: AudioLevels;
|
|
98
|
-
|
|
99
|
-
// Actions
|
|
100
|
-
play: () => Promise<void>;
|
|
101
|
-
pause: () => void;
|
|
102
|
-
togglePlay: () => void;
|
|
103
|
-
seek: (time: number) => void;
|
|
104
|
-
seekTo: (progress: number) => void;
|
|
105
|
-
skip: (seconds: number) => void;
|
|
106
|
-
setVolume: (volume: number) => void;
|
|
107
|
-
toggleMute: () => void;
|
|
108
|
-
toggleLoop: () => void;
|
|
109
|
-
setLoop: (enabled: boolean) => void;
|
|
110
|
-
restart: () => void;
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## `types/components.ts`
|
|
117
|
-
|
|
118
|
-
Component props types.
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
import type { CSSProperties } from 'react';
|
|
122
|
-
import type { WaveformOptions, EqualizerOptions, AudioSource, PlaybackStatus } from './audio';
|
|
123
|
-
|
|
124
|
-
// =============================================================================
|
|
125
|
-
// AUDIO PLAYER PROPS
|
|
126
|
-
// =============================================================================
|
|
127
|
-
|
|
128
|
-
export interface AudioPlayerProps {
|
|
129
|
-
showControls?: boolean;
|
|
130
|
-
showWaveform?: boolean;
|
|
131
|
-
showEqualizer?: boolean;
|
|
132
|
-
showTimer?: boolean;
|
|
133
|
-
showVolume?: boolean;
|
|
134
|
-
showLoop?: boolean;
|
|
135
|
-
waveformOptions?: WaveformOptions;
|
|
136
|
-
equalizerOptions?: EqualizerOptions;
|
|
137
|
-
className?: string;
|
|
138
|
-
style?: CSSProperties;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// =============================================================================
|
|
142
|
-
// AUDIO EQUALIZER PROPS
|
|
143
|
-
// =============================================================================
|
|
144
|
-
|
|
145
|
-
export interface AudioEqualizerProps {
|
|
146
|
-
barCount?: number;
|
|
147
|
-
height?: number;
|
|
148
|
-
gap?: number;
|
|
149
|
-
showPeaks?: boolean;
|
|
150
|
-
barColor?: string;
|
|
151
|
-
peakColor?: string;
|
|
152
|
-
className?: string;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// =============================================================================
|
|
156
|
-
// AUDIO REACTIVE COVER PROPS
|
|
157
|
-
// =============================================================================
|
|
158
|
-
|
|
159
|
-
export interface AudioReactiveCoverProps {
|
|
160
|
-
variant?: 'glow' | 'orbs' | 'spotlight' | 'mesh';
|
|
161
|
-
intensity?: 'subtle' | 'medium' | 'strong';
|
|
162
|
-
colorScheme?: 'primary' | 'vibrant' | 'cool' | 'warm';
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// =============================================================================
|
|
166
|
-
// AUDIO VIEWER PROPS (legacy)
|
|
167
|
-
// =============================================================================
|
|
168
|
-
|
|
169
|
-
export interface AudioViewerProps {
|
|
170
|
-
source: AudioSource;
|
|
171
|
-
autoPlay?: boolean;
|
|
172
|
-
showControls?: boolean;
|
|
173
|
-
showWaveform?: boolean;
|
|
174
|
-
showEqualizer?: boolean;
|
|
175
|
-
showTimer?: boolean;
|
|
176
|
-
showVolume?: boolean;
|
|
177
|
-
waveformOptions?: WaveformOptions;
|
|
178
|
-
equalizerOptions?: EqualizerOptions;
|
|
179
|
-
onPlaybackStatusUpdate?: (status: PlaybackStatus) => void;
|
|
180
|
-
className?: string;
|
|
181
|
-
style?: CSSProperties;
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## `types/effects.ts`
|
|
188
|
-
|
|
189
|
-
Effect-related types (moved from effects/index.ts).
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
// =============================================================================
|
|
193
|
-
// EFFECT TYPES
|
|
194
|
-
// =============================================================================
|
|
195
|
-
|
|
196
|
-
export type EffectVariant = 'glow' | 'orbs' | 'spotlight' | 'mesh';
|
|
197
|
-
export type EffectIntensity = 'subtle' | 'medium' | 'strong';
|
|
198
|
-
export type EffectColorScheme = 'primary' | 'vibrant' | 'cool' | 'warm';
|
|
199
|
-
|
|
200
|
-
export interface AudioLevels {
|
|
201
|
-
bass: number;
|
|
202
|
-
mid: number;
|
|
203
|
-
high: number;
|
|
204
|
-
overall: number;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export interface EffectConfig {
|
|
208
|
-
opacity: number;
|
|
209
|
-
scale: number;
|
|
210
|
-
blur: string;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export interface EffectColors {
|
|
214
|
-
colors: string[];
|
|
215
|
-
hueShift: number;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
export interface EffectLayer {
|
|
219
|
-
inset: number;
|
|
220
|
-
opacity: number;
|
|
221
|
-
scale: number;
|
|
222
|
-
background: string;
|
|
223
|
-
blur: string;
|
|
224
|
-
animation?: string;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export interface Orb {
|
|
228
|
-
x: number;
|
|
229
|
-
y: number;
|
|
230
|
-
size: number;
|
|
231
|
-
color: string;
|
|
232
|
-
opacity: number;
|
|
233
|
-
scale: number;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export interface MeshGradient {
|
|
237
|
-
width: string;
|
|
238
|
-
height: string;
|
|
239
|
-
top?: string;
|
|
240
|
-
bottom?: string;
|
|
241
|
-
left?: string;
|
|
242
|
-
right?: string;
|
|
243
|
-
color: string;
|
|
244
|
-
opacity: number;
|
|
245
|
-
scale: number;
|
|
246
|
-
rotation: number;
|
|
247
|
-
blur: string;
|
|
248
|
-
isCenter?: boolean;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
export interface SpotlightData {
|
|
252
|
-
rotation: number;
|
|
253
|
-
inset: number;
|
|
254
|
-
colors: Array<{ color: string; opacity: number }>;
|
|
255
|
-
pulseInset: number;
|
|
256
|
-
pulseOpacity: number;
|
|
257
|
-
pulseScale: number;
|
|
258
|
-
ringOpacity: number;
|
|
259
|
-
ringScale: number;
|
|
260
|
-
}
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
---
|
|
264
|
-
|
|
265
|
-
## `types/index.ts`
|
|
266
|
-
|
|
267
|
-
Re-export all types.
|
|
268
|
-
|
|
269
|
-
```typescript
|
|
270
|
-
// Audio types
|
|
271
|
-
export type {
|
|
272
|
-
AudioSource,
|
|
273
|
-
PlaybackStatus,
|
|
274
|
-
WaveformOptions,
|
|
275
|
-
EqualizerOptions,
|
|
276
|
-
SharedWebAudioContext,
|
|
277
|
-
AudioContextState,
|
|
278
|
-
} from './audio';
|
|
279
|
-
|
|
280
|
-
// Component props
|
|
281
|
-
export type {
|
|
282
|
-
AudioPlayerProps,
|
|
283
|
-
AudioEqualizerProps,
|
|
284
|
-
AudioReactiveCoverProps,
|
|
285
|
-
AudioViewerProps,
|
|
286
|
-
} from './components';
|
|
287
|
-
|
|
288
|
-
// Effect types
|
|
289
|
-
export type {
|
|
290
|
-
EffectVariant,
|
|
291
|
-
EffectIntensity,
|
|
292
|
-
EffectColorScheme,
|
|
293
|
-
AudioLevels,
|
|
294
|
-
EffectConfig,
|
|
295
|
-
EffectColors,
|
|
296
|
-
EffectLayer,
|
|
297
|
-
Orb,
|
|
298
|
-
MeshGradient,
|
|
299
|
-
SpotlightData,
|
|
300
|
-
} from './effects';
|
|
301
|
-
```
|