@djangocfg/ui-tools 2.1.91
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/dist/LottiePlayer.client-LBEC2JKY.mjs +161 -0
- package/dist/LottiePlayer.client-LBEC2JKY.mjs.map +1 -0
- package/dist/LottiePlayer.client-WFMG2OOW.cjs +168 -0
- package/dist/LottiePlayer.client-WFMG2OOW.cjs.map +1 -0
- package/dist/Mermaid.client-4TU2TSH3.mjs +477 -0
- package/dist/Mermaid.client-4TU2TSH3.mjs.map +1 -0
- package/dist/Mermaid.client-SBYY364Q.cjs +483 -0
- package/dist/Mermaid.client-SBYY364Q.cjs.map +1 -0
- package/dist/PlaygroundLayout-3YVSAEAF.cjs +1003 -0
- package/dist/PlaygroundLayout-3YVSAEAF.cjs.map +1 -0
- package/dist/PlaygroundLayout-4DYBORAS.mjs +996 -0
- package/dist/PlaygroundLayout-4DYBORAS.mjs.map +1 -0
- package/dist/PrettyCode.client-LCBPPTIX.mjs +152 -0
- package/dist/PrettyCode.client-LCBPPTIX.mjs.map +1 -0
- package/dist/PrettyCode.client-PNPLXRH6.cjs +154 -0
- package/dist/PrettyCode.client-PNPLXRH6.cjs.map +1 -0
- package/dist/chunk-37ZI6VD4.mjs +12 -0
- package/dist/chunk-37ZI6VD4.mjs.map +1 -0
- package/dist/chunk-3HK2OE62.cjs +81 -0
- package/dist/chunk-3HK2OE62.cjs.map +1 -0
- package/dist/chunk-7DGDQVQW.cjs +591 -0
- package/dist/chunk-7DGDQVQW.cjs.map +1 -0
- package/dist/chunk-M6P2FU7L.mjs +572 -0
- package/dist/chunk-M6P2FU7L.mjs.map +1 -0
- package/dist/chunk-UQ3XI5MY.cjs +15 -0
- package/dist/chunk-UQ3XI5MY.cjs.map +1 -0
- package/dist/chunk-YFRNE2IR.mjs +79 -0
- package/dist/chunk-YFRNE2IR.mjs.map +1 -0
- package/dist/index.cjs +5042 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1591 -0
- package/dist/index.d.ts +1591 -0
- package/dist/index.mjs +4941 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +86 -0
- package/src/components/markdown/MarkdownMessage.tsx +340 -0
- package/src/components/markdown/index.ts +5 -0
- package/src/index.ts +26 -0
- package/src/stores/index.ts +9 -0
- package/src/stores/mediaCache.ts +534 -0
- package/src/tools/AudioPlayer/README.md +206 -0
- package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +216 -0
- package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +280 -0
- package/src/tools/AudioPlayer/components/HybridWaveform.tsx +279 -0
- package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +149 -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/index.ts +22 -0
- package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +158 -0
- package/src/tools/AudioPlayer/context/index.ts +16 -0
- package/src/tools/AudioPlayer/effects/index.ts +412 -0
- package/src/tools/AudioPlayer/hooks/index.ts +35 -0
- package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +387 -0
- package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +95 -0
- package/src/tools/AudioPlayer/hooks/useVisualization.tsx +207 -0
- package/src/tools/AudioPlayer/index.ts +133 -0
- package/src/tools/AudioPlayer/types/effects.ts +73 -0
- package/src/tools/AudioPlayer/types/index.ts +27 -0
- package/src/tools/AudioPlayer/utils/debug.ts +14 -0
- package/src/tools/AudioPlayer/utils/formatTime.ts +10 -0
- package/src/tools/AudioPlayer/utils/index.ts +6 -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 +200 -0
- package/src/tools/ImageViewer/components/ImageInfo.tsx +44 -0
- package/src/tools/ImageViewer/components/ImageToolbar.tsx +145 -0
- package/src/tools/ImageViewer/components/ImageViewer.tsx +241 -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 +204 -0
- package/src/tools/ImageViewer/hooks/useImageTransform.ts +101 -0
- package/src/tools/ImageViewer/index.ts +60 -0
- package/src/tools/ImageViewer/types.ts +81 -0
- package/src/tools/ImageViewer/utils/constants.ts +59 -0
- package/src/tools/ImageViewer/utils/debug.ts +14 -0
- package/src/tools/ImageViewer/utils/index.ts +17 -0
- package/src/tools/ImageViewer/utils/lqip.ts +47 -0
- package/src/tools/JsonForm/JsonSchemaForm.tsx +197 -0
- package/src/tools/JsonForm/examples/BotConfigExample.tsx +249 -0
- package/src/tools/JsonForm/examples/RealBotConfigExample.tsx +161 -0
- package/src/tools/JsonForm/index.ts +46 -0
- package/src/tools/JsonForm/templates/ArrayFieldItemTemplate.tsx +47 -0
- package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +74 -0
- package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +107 -0
- package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +35 -0
- package/src/tools/JsonForm/templates/FieldTemplate.tsx +62 -0
- package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +116 -0
- package/src/tools/JsonForm/templates/index.ts +12 -0
- package/src/tools/JsonForm/types.ts +83 -0
- package/src/tools/JsonForm/utils.ts +213 -0
- package/src/tools/JsonForm/widgets/CheckboxWidget.tsx +37 -0
- package/src/tools/JsonForm/widgets/ColorWidget.tsx +219 -0
- package/src/tools/JsonForm/widgets/NumberWidget.tsx +89 -0
- package/src/tools/JsonForm/widgets/SelectWidget.tsx +97 -0
- package/src/tools/JsonForm/widgets/SliderWidget.tsx +148 -0
- package/src/tools/JsonForm/widgets/SwitchWidget.tsx +35 -0
- package/src/tools/JsonForm/widgets/TextWidget.tsx +96 -0
- package/src/tools/JsonForm/widgets/index.ts +14 -0
- package/src/tools/JsonTree/index.tsx +243 -0
- package/src/tools/LottiePlayer/LottiePlayer.client.tsx +213 -0
- package/src/tools/LottiePlayer/index.tsx +56 -0
- package/src/tools/LottiePlayer/types.ts +108 -0
- package/src/tools/LottiePlayer/useLottie.ts +164 -0
- package/src/tools/Mermaid/Mermaid.client.tsx +82 -0
- package/src/tools/Mermaid/components/MermaidCodeViewer.tsx +95 -0
- package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +103 -0
- package/src/tools/Mermaid/hooks/index.ts +4 -0
- package/src/tools/Mermaid/hooks/useMermaidCleanup.ts +73 -0
- package/src/tools/Mermaid/hooks/useMermaidFullscreen.ts +46 -0
- package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +226 -0
- package/src/tools/Mermaid/hooks/useMermaidValidation.ts +29 -0
- package/src/tools/Mermaid/index.tsx +44 -0
- package/src/tools/Mermaid/utils/mermaid-helpers.ts +33 -0
- package/src/tools/OpenapiViewer/components/EndpointInfo.tsx +149 -0
- package/src/tools/OpenapiViewer/components/EndpointsLibrary.tsx +263 -0
- package/src/tools/OpenapiViewer/components/PlaygroundLayout.tsx +125 -0
- package/src/tools/OpenapiViewer/components/PlaygroundStepper.tsx +100 -0
- package/src/tools/OpenapiViewer/components/RequestBuilder.tsx +157 -0
- package/src/tools/OpenapiViewer/components/RequestParametersForm.tsx +253 -0
- package/src/tools/OpenapiViewer/components/ResponseViewer.tsx +173 -0
- package/src/tools/OpenapiViewer/components/VersionSelector.tsx +68 -0
- package/src/tools/OpenapiViewer/components/index.ts +14 -0
- package/src/tools/OpenapiViewer/constants.ts +39 -0
- package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +337 -0
- package/src/tools/OpenapiViewer/hooks/index.ts +8 -0
- package/src/tools/OpenapiViewer/hooks/useMobile.ts +10 -0
- package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +199 -0
- package/src/tools/OpenapiViewer/index.tsx +37 -0
- package/src/tools/OpenapiViewer/types.ts +151 -0
- package/src/tools/OpenapiViewer/utils/apiKeyManager.ts +149 -0
- package/src/tools/OpenapiViewer/utils/formatters.ts +71 -0
- package/src/tools/OpenapiViewer/utils/index.ts +9 -0
- package/src/tools/OpenapiViewer/utils/versionManager.ts +161 -0
- package/src/tools/PrettyCode/PrettyCode.client.tsx +208 -0
- package/src/tools/PrettyCode/index.tsx +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 +264 -0
- package/src/tools/VideoPlayer/components/VideoControls.tsx +138 -0
- package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +172 -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 +12 -0
- package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +70 -0
- package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +116 -0
- package/src/tools/VideoPlayer/index.ts +77 -0
- package/src/tools/VideoPlayer/providers/NativeProvider.tsx +284 -0
- package/src/tools/VideoPlayer/providers/StreamProvider.tsx +505 -0
- package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +400 -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/debug.ts +14 -0
- package/src/tools/VideoPlayer/utils/fileSource.ts +78 -0
- package/src/tools/VideoPlayer/utils/index.ts +12 -0
- package/src/tools/VideoPlayer/utils/resolvers.ts +75 -0
- package/src/tools/_shared.ts +29 -0
- package/src/tools/index.ts +172 -0
|
@@ -0,0 +1,207 @@
|
|
|
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 '../../_shared';
|
|
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
|
+
/** Playback volume (0-1) */
|
|
31
|
+
volume: number;
|
|
32
|
+
/** Loop playback */
|
|
33
|
+
isLooping: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface UseVisualizationReturn {
|
|
37
|
+
/** Current settings */
|
|
38
|
+
settings: VisualizationSettings;
|
|
39
|
+
/** Toggle visualization on/off */
|
|
40
|
+
toggle: () => void;
|
|
41
|
+
/** Set specific setting */
|
|
42
|
+
setSetting: <K extends keyof VisualizationSettings>(
|
|
43
|
+
key: K,
|
|
44
|
+
value: VisualizationSettings[K]
|
|
45
|
+
) => void;
|
|
46
|
+
/** Cycle to next variant */
|
|
47
|
+
nextVariant: () => void;
|
|
48
|
+
/** Cycle to next intensity */
|
|
49
|
+
nextIntensity: () => void;
|
|
50
|
+
/** Cycle to next color scheme */
|
|
51
|
+
nextColorScheme: () => void;
|
|
52
|
+
/** Reset to defaults */
|
|
53
|
+
reset: () => void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Backward compatibility alias
|
|
57
|
+
export type UseAudioVisualizationReturn = UseVisualizationReturn;
|
|
58
|
+
|
|
59
|
+
// =============================================================================
|
|
60
|
+
// CONSTANTS
|
|
61
|
+
// =============================================================================
|
|
62
|
+
|
|
63
|
+
const STORAGE_KEY = 'audio-player-settings';
|
|
64
|
+
|
|
65
|
+
const DEFAULT_SETTINGS: VisualizationSettings = {
|
|
66
|
+
enabled: true,
|
|
67
|
+
variant: 'spotlight',
|
|
68
|
+
intensity: 'medium',
|
|
69
|
+
colorScheme: 'primary',
|
|
70
|
+
volume: 1,
|
|
71
|
+
isLooping: false,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const VARIANTS: VisualizationVariant[] = ['spotlight', 'glow', 'orbs', 'mesh', 'none'];
|
|
75
|
+
const INTENSITIES: VisualizationIntensity[] = ['subtle', 'medium', 'strong'];
|
|
76
|
+
const COLOR_SCHEMES: VisualizationColorScheme[] = ['primary', 'vibrant', 'cool', 'warm'];
|
|
77
|
+
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// CONTEXT
|
|
80
|
+
// =============================================================================
|
|
81
|
+
|
|
82
|
+
const VisualizationContext = createContext<UseVisualizationReturn | null>(null);
|
|
83
|
+
|
|
84
|
+
// =============================================================================
|
|
85
|
+
// PROVIDER
|
|
86
|
+
// =============================================================================
|
|
87
|
+
|
|
88
|
+
export interface VisualizationProviderProps {
|
|
89
|
+
children: ReactNode;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function VisualizationProvider({ children }: VisualizationProviderProps) {
|
|
93
|
+
const value = useVisualizationState();
|
|
94
|
+
return (
|
|
95
|
+
<VisualizationContext.Provider value={value}>
|
|
96
|
+
{children}
|
|
97
|
+
</VisualizationContext.Provider>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// =============================================================================
|
|
102
|
+
// INTERNAL HOOK (creates the actual state)
|
|
103
|
+
// =============================================================================
|
|
104
|
+
|
|
105
|
+
function useVisualizationState(): UseVisualizationReturn {
|
|
106
|
+
const [settings, setSettings] = useLocalStorage<VisualizationSettings>(
|
|
107
|
+
STORAGE_KEY,
|
|
108
|
+
DEFAULT_SETTINGS
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const toggle = useCallback(() => {
|
|
112
|
+
setSettings((prev) => ({ ...prev, enabled: !prev.enabled }));
|
|
113
|
+
}, [setSettings]);
|
|
114
|
+
|
|
115
|
+
const setSetting = useCallback(
|
|
116
|
+
<K extends keyof VisualizationSettings>(
|
|
117
|
+
key: K,
|
|
118
|
+
value: VisualizationSettings[K]
|
|
119
|
+
) => {
|
|
120
|
+
setSettings((prev) => ({ ...prev, [key]: value }));
|
|
121
|
+
},
|
|
122
|
+
[setSettings]
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const nextVariant = useCallback(() => {
|
|
126
|
+
setSettings((prev) => {
|
|
127
|
+
const currentIndex = VARIANTS.indexOf(prev.variant);
|
|
128
|
+
const nextIndex = (currentIndex + 1) % VARIANTS.length;
|
|
129
|
+
return { ...prev, variant: VARIANTS[nextIndex] };
|
|
130
|
+
});
|
|
131
|
+
}, [setSettings]);
|
|
132
|
+
|
|
133
|
+
const nextIntensity = useCallback(() => {
|
|
134
|
+
setSettings((prev) => {
|
|
135
|
+
const currentIndex = INTENSITIES.indexOf(prev.intensity);
|
|
136
|
+
const nextIndex = (currentIndex + 1) % INTENSITIES.length;
|
|
137
|
+
return { ...prev, intensity: INTENSITIES[nextIndex] };
|
|
138
|
+
});
|
|
139
|
+
}, [setSettings]);
|
|
140
|
+
|
|
141
|
+
const nextColorScheme = useCallback(() => {
|
|
142
|
+
setSettings((prev) => {
|
|
143
|
+
const currentIndex = COLOR_SCHEMES.indexOf(prev.colorScheme);
|
|
144
|
+
const nextIndex = (currentIndex + 1) % COLOR_SCHEMES.length;
|
|
145
|
+
return { ...prev, colorScheme: COLOR_SCHEMES[nextIndex] };
|
|
146
|
+
});
|
|
147
|
+
}, [setSettings]);
|
|
148
|
+
|
|
149
|
+
const reset = useCallback(() => {
|
|
150
|
+
setSettings(DEFAULT_SETTINGS);
|
|
151
|
+
}, [setSettings]);
|
|
152
|
+
|
|
153
|
+
return useMemo(
|
|
154
|
+
() => ({
|
|
155
|
+
settings,
|
|
156
|
+
toggle,
|
|
157
|
+
setSetting,
|
|
158
|
+
nextVariant,
|
|
159
|
+
nextIntensity,
|
|
160
|
+
nextColorScheme,
|
|
161
|
+
reset,
|
|
162
|
+
}),
|
|
163
|
+
[settings, toggle, setSetting, nextVariant, nextIntensity, nextColorScheme, reset]
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// =============================================================================
|
|
168
|
+
// HOOK (uses context when available)
|
|
169
|
+
// =============================================================================
|
|
170
|
+
|
|
171
|
+
export function useVisualization(): UseVisualizationReturn {
|
|
172
|
+
const context = useContext(VisualizationContext);
|
|
173
|
+
|
|
174
|
+
// Always call the fallback hooks (React hooks rules require consistent calls)
|
|
175
|
+
const fallbackState = useVisualizationState();
|
|
176
|
+
|
|
177
|
+
// If inside a provider, use shared context; otherwise use fallback
|
|
178
|
+
return context ?? fallbackState;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Backward compatibility alias
|
|
182
|
+
export const useAudioVisualization = useVisualization;
|
|
183
|
+
|
|
184
|
+
// =============================================================================
|
|
185
|
+
// VARIANT INFO
|
|
186
|
+
// =============================================================================
|
|
187
|
+
|
|
188
|
+
export const VARIANT_INFO: Record<VisualizationVariant, { label: string; icon: string }> = {
|
|
189
|
+
spotlight: { label: 'Spotlight', icon: '💫' },
|
|
190
|
+
glow: { label: 'Glow', icon: '✨' },
|
|
191
|
+
orbs: { label: 'Orbs', icon: '🔮' },
|
|
192
|
+
mesh: { label: 'Mesh', icon: '🌈' },
|
|
193
|
+
none: { label: 'Off', icon: '⭕' },
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
export const INTENSITY_INFO: Record<VisualizationIntensity, { label: string }> = {
|
|
197
|
+
subtle: { label: 'Subtle' },
|
|
198
|
+
medium: { label: 'Medium' },
|
|
199
|
+
strong: { label: 'Strong' },
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export const COLOR_SCHEME_INFO: Record<VisualizationColorScheme, { label: string; preview: string }> = {
|
|
203
|
+
primary: { label: 'Primary', preview: '🔵' },
|
|
204
|
+
vibrant: { label: 'Vibrant', preview: '🌈' },
|
|
205
|
+
cool: { label: 'Cool', preview: '💙' },
|
|
206
|
+
warm: { label: 'Warm', preview: '🔥' },
|
|
207
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AudioPlayer - Complete audio playback solution with reactive visualizations
|
|
3
|
+
*
|
|
4
|
+
* Uses HTML5 audio for playback + Web Audio API for visualization.
|
|
5
|
+
* No crackling, native streaming support.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Simple usage
|
|
9
|
+
* import { HybridSimplePlayer } from '../../_shared';
|
|
10
|
+
* <HybridSimplePlayer src="/audio.mp3" title="Track Title" />
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // Custom setup with context
|
|
14
|
+
* import { HybridAudioProvider, HybridAudioPlayer } from '../../_shared';
|
|
15
|
+
* <HybridAudioProvider src={audioUrl}>
|
|
16
|
+
* <HybridAudioPlayer showWaveform showControls />
|
|
17
|
+
* </HybridAudioProvider>
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// COMPONENTS
|
|
22
|
+
// =============================================================================
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
HybridAudioPlayer,
|
|
26
|
+
HybridSimplePlayer,
|
|
27
|
+
HybridWaveform,
|
|
28
|
+
AudioReactiveCover,
|
|
29
|
+
// Effect components (for custom implementations)
|
|
30
|
+
GlowEffect,
|
|
31
|
+
OrbsEffect,
|
|
32
|
+
SpotlightEffect,
|
|
33
|
+
MeshEffect,
|
|
34
|
+
} from './components';
|
|
35
|
+
|
|
36
|
+
export type {
|
|
37
|
+
HybridAudioPlayerProps,
|
|
38
|
+
HybridSimplePlayerProps,
|
|
39
|
+
HybridWaveformProps,
|
|
40
|
+
AudioReactiveCoverProps,
|
|
41
|
+
GlowEffectData,
|
|
42
|
+
} from './components';
|
|
43
|
+
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// CONTEXT
|
|
46
|
+
// =============================================================================
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
HybridAudioProvider,
|
|
50
|
+
useHybridAudioContext,
|
|
51
|
+
useHybridAudioState,
|
|
52
|
+
useHybridAudioControls,
|
|
53
|
+
useHybridAudioLevels,
|
|
54
|
+
useHybridWebAudio,
|
|
55
|
+
} from './context';
|
|
56
|
+
|
|
57
|
+
export type {
|
|
58
|
+
HybridAudioContextValue,
|
|
59
|
+
HybridAudioProviderProps,
|
|
60
|
+
} from './context';
|
|
61
|
+
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// HOOKS
|
|
64
|
+
// =============================================================================
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
// Core hooks
|
|
68
|
+
useHybridAudio,
|
|
69
|
+
useHybridAudioAnalysis,
|
|
70
|
+
// Visualization settings
|
|
71
|
+
useVisualization,
|
|
72
|
+
useAudioVisualization,
|
|
73
|
+
VisualizationProvider,
|
|
74
|
+
VARIANT_INFO,
|
|
75
|
+
INTENSITY_INFO,
|
|
76
|
+
COLOR_SCHEME_INFO,
|
|
77
|
+
} from './hooks';
|
|
78
|
+
|
|
79
|
+
export type {
|
|
80
|
+
UseHybridAudioOptions,
|
|
81
|
+
HybridAudioState,
|
|
82
|
+
HybridAudioControls,
|
|
83
|
+
HybridWebAudioAPI,
|
|
84
|
+
UseHybridAudioReturn,
|
|
85
|
+
VisualizationSettings,
|
|
86
|
+
VisualizationVariant,
|
|
87
|
+
VisualizationIntensity,
|
|
88
|
+
VisualizationColorScheme,
|
|
89
|
+
UseVisualizationReturn,
|
|
90
|
+
UseAudioVisualizationReturn,
|
|
91
|
+
VisualizationProviderProps,
|
|
92
|
+
} from './hooks';
|
|
93
|
+
|
|
94
|
+
// =============================================================================
|
|
95
|
+
// TYPES
|
|
96
|
+
// =============================================================================
|
|
97
|
+
|
|
98
|
+
export type { EqualizerOptions } from './types';
|
|
99
|
+
|
|
100
|
+
// =============================================================================
|
|
101
|
+
// EFFECTS
|
|
102
|
+
// =============================================================================
|
|
103
|
+
|
|
104
|
+
export {
|
|
105
|
+
// Utilities
|
|
106
|
+
getEffectConfig,
|
|
107
|
+
getColors,
|
|
108
|
+
prepareEffectColors,
|
|
109
|
+
calculateGlowLayers,
|
|
110
|
+
calculateOrbs,
|
|
111
|
+
calculateMeshGradients,
|
|
112
|
+
calculateSpotlight,
|
|
113
|
+
// Constants
|
|
114
|
+
INTENSITY_CONFIG,
|
|
115
|
+
COLOR_SCHEMES,
|
|
116
|
+
EFFECT_ANIMATIONS,
|
|
117
|
+
} from './effects';
|
|
118
|
+
|
|
119
|
+
export type {
|
|
120
|
+
EffectVariant,
|
|
121
|
+
EffectIntensity,
|
|
122
|
+
EffectColorScheme,
|
|
123
|
+
AudioLevels,
|
|
124
|
+
EffectConfig,
|
|
125
|
+
EffectColors,
|
|
126
|
+
EffectLayer,
|
|
127
|
+
} from './effects';
|
|
128
|
+
|
|
129
|
+
// =============================================================================
|
|
130
|
+
// UTILITIES
|
|
131
|
+
// =============================================================================
|
|
132
|
+
|
|
133
|
+
export { formatTime } from './utils';
|
|
@@ -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,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AudioPlayer types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Equalizer options
|
|
6
|
+
export interface EqualizerOptions {
|
|
7
|
+
barCount?: number;
|
|
8
|
+
height?: number;
|
|
9
|
+
gap?: number;
|
|
10
|
+
showPeaks?: boolean;
|
|
11
|
+
barColor?: string;
|
|
12
|
+
peakColor?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Effect types
|
|
16
|
+
export type {
|
|
17
|
+
EffectVariant,
|
|
18
|
+
EffectIntensity,
|
|
19
|
+
EffectColorScheme,
|
|
20
|
+
AudioLevels,
|
|
21
|
+
EffectConfig,
|
|
22
|
+
EffectColors,
|
|
23
|
+
EffectLayer,
|
|
24
|
+
Orb,
|
|
25
|
+
MeshGradient,
|
|
26
|
+
SpotlightData,
|
|
27
|
+
} from './effects';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AudioPlayer Debug Logger
|
|
5
|
+
*
|
|
6
|
+
* Uses universal logger with media-specific helpers.
|
|
7
|
+
* Logs go to both console (dev) and zustand store (for Console panel).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createMediaLogger } from '@djangocfg/ui-core/lib';
|
|
11
|
+
|
|
12
|
+
export const audioDebug = createMediaLogger('AudioPlayer');
|
|
13
|
+
|
|
14
|
+
export default audioDebug;
|
|
@@ -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
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Phase 1: Types Extraction
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Extract all type definitions from ImageViewer.tsx into a dedicated types.ts file.
|
|
6
|
+
|
|
7
|
+
## Types to Extract
|
|
8
|
+
|
|
9
|
+
### ImageFile (Props)
|
|
10
|
+
```typescript
|
|
11
|
+
export interface ImageFile {
|
|
12
|
+
/** Display name for the image */
|
|
13
|
+
name: string;
|
|
14
|
+
/** File path used for change detection and caching */
|
|
15
|
+
path: string;
|
|
16
|
+
/** Optional MIME type */
|
|
17
|
+
mimeType?: string;
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### ImageViewerProps (Props)
|
|
22
|
+
```typescript
|
|
23
|
+
export interface ImageViewerProps {
|
|
24
|
+
/** Image file metadata */
|
|
25
|
+
file: ImageFile;
|
|
26
|
+
/** Image content as string or ArrayBuffer */
|
|
27
|
+
content: string | ArrayBuffer;
|
|
28
|
+
/** Whether viewer is inside a dialog (hides expand button) */
|
|
29
|
+
inDialog?: boolean;
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### ImageTransform (State)
|
|
34
|
+
```typescript
|
|
35
|
+
export interface ImageTransform {
|
|
36
|
+
/** Rotation angle: 0, 90, 180, or 270 degrees */
|
|
37
|
+
rotation: number;
|
|
38
|
+
/** Horizontal flip state */
|
|
39
|
+
flipH: boolean;
|
|
40
|
+
/** Vertical flip state */
|
|
41
|
+
flipV: boolean;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### ZoomPreset (UI)
|
|
46
|
+
```typescript
|
|
47
|
+
export interface ZoomPreset {
|
|
48
|
+
/** Zoom level (1 = 100%) */
|
|
49
|
+
value: number;
|
|
50
|
+
/** Display label (e.g., "100%") */
|
|
51
|
+
label: string;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### ImageToolbarProps (Internal)
|
|
56
|
+
```typescript
|
|
57
|
+
export interface ImageToolbarProps {
|
|
58
|
+
/** Current zoom scale */
|
|
59
|
+
scale: number;
|
|
60
|
+
/** Expand to fullscreen callback */
|
|
61
|
+
onExpand: () => void;
|
|
62
|
+
/** Rotate image callback */
|
|
63
|
+
onRotate: () => void;
|
|
64
|
+
/** Flip horizontal callback */
|
|
65
|
+
onFlipH: () => void;
|
|
66
|
+
/** Flip vertical callback */
|
|
67
|
+
onFlipV: () => void;
|
|
68
|
+
/** Whether horizontal flip is active */
|
|
69
|
+
flipH: boolean;
|
|
70
|
+
/** Whether vertical flip is active */
|
|
71
|
+
flipV: boolean;
|
|
72
|
+
/** Whether inside dialog (hides expand) */
|
|
73
|
+
inDialog?: boolean;
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### ImageInfoProps (Internal)
|
|
78
|
+
```typescript
|
|
79
|
+
export interface ImageInfoProps {
|
|
80
|
+
/** Blob URL source of the image */
|
|
81
|
+
src: string;
|
|
82
|
+
/** Content key for cache lookup */
|
|
83
|
+
contentKey: string;
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## File Structure
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// types.ts
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* ImageViewer type definitions
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
// =============================================================================
|
|
97
|
+
// FILE TYPES
|
|
98
|
+
// =============================================================================
|
|
99
|
+
|
|
100
|
+
export interface ImageFile { ... }
|
|
101
|
+
|
|
102
|
+
// =============================================================================
|
|
103
|
+
// COMPONENT PROPS
|
|
104
|
+
// =============================================================================
|
|
105
|
+
|
|
106
|
+
export interface ImageViewerProps { ... }
|
|
107
|
+
export interface ImageToolbarProps { ... }
|
|
108
|
+
export interface ImageInfoProps { ... }
|
|
109
|
+
|
|
110
|
+
// =============================================================================
|
|
111
|
+
// STATE TYPES
|
|
112
|
+
// =============================================================================
|
|
113
|
+
|
|
114
|
+
export interface ImageTransform { ... }
|
|
115
|
+
|
|
116
|
+
// =============================================================================
|
|
117
|
+
// UI TYPES
|
|
118
|
+
// =============================================================================
|
|
119
|
+
|
|
120
|
+
export interface ZoomPreset { ... }
|
|
121
|
+
```
|