@djangocfg/ui-nextjs 2.1.89 → 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.
Files changed (161) hide show
  1. package/README.md +6 -15
  2. package/package.json +6 -25
  3. package/src/blocks/SplitHero/SplitHeroMedia.tsx +1 -1
  4. package/src/components/index.ts +0 -40
  5. package/src/hooks/index.ts +0 -6
  6. package/src/index.ts +2 -11
  7. package/src/components/button-download.tsx +0 -277
  8. package/src/components/markdown/MarkdownMessage.tsx +0 -340
  9. package/src/components/markdown/index.ts +0 -5
  10. package/src/components/menubar.tsx +0 -275
  11. package/src/components/multi-select-pro/async.tsx +0 -598
  12. package/src/components/multi-select-pro/helpers.tsx +0 -84
  13. package/src/components/multi-select-pro/index.tsx +0 -612
  14. package/src/components/navigation-menu.tsx +0 -154
  15. package/src/components/otp/index.tsx +0 -197
  16. package/src/components/otp/types.ts +0 -133
  17. package/src/components/otp/use-otp-input.ts +0 -225
  18. package/src/components/phone-input.tsx +0 -277
  19. package/src/components/sonner.tsx +0 -32
  20. package/src/hooks/useLocalStorage.ts +0 -300
  21. package/src/hooks/useSessionStorage.ts +0 -290
  22. package/src/lib/index.ts +0 -5
  23. package/src/lib/logger/index.ts +0 -10
  24. package/src/lib/logger/logStore.ts +0 -122
  25. package/src/lib/logger/logger.ts +0 -175
  26. package/src/lib/logger/types.ts +0 -82
  27. package/src/stores/index.ts +0 -8
  28. package/src/stores/mediaCache.ts +0 -534
  29. package/src/tools/AudioPlayer/README.md +0 -206
  30. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +0 -216
  31. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +0 -280
  32. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +0 -279
  33. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +0 -149
  34. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +0 -110
  35. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +0 -58
  36. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +0 -45
  37. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +0 -82
  38. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +0 -8
  39. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +0 -6
  40. package/src/tools/AudioPlayer/components/index.ts +0 -22
  41. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +0 -158
  42. package/src/tools/AudioPlayer/context/index.ts +0 -16
  43. package/src/tools/AudioPlayer/effects/index.ts +0 -412
  44. package/src/tools/AudioPlayer/hooks/index.ts +0 -35
  45. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +0 -387
  46. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +0 -95
  47. package/src/tools/AudioPlayer/hooks/useVisualization.tsx +0 -207
  48. package/src/tools/AudioPlayer/index.ts +0 -133
  49. package/src/tools/AudioPlayer/types/effects.ts +0 -73
  50. package/src/tools/AudioPlayer/types/index.ts +0 -27
  51. package/src/tools/AudioPlayer/utils/debug.ts +0 -14
  52. package/src/tools/AudioPlayer/utils/formatTime.ts +0 -10
  53. package/src/tools/AudioPlayer/utils/index.ts +0 -6
  54. package/src/tools/ImageViewer/@refactoring/00-PLAN.md +0 -71
  55. package/src/tools/ImageViewer/@refactoring/01-TYPES.md +0 -121
  56. package/src/tools/ImageViewer/@refactoring/02-UTILS.md +0 -143
  57. package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +0 -261
  58. package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +0 -427
  59. package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -126
  60. package/src/tools/ImageViewer/README.md +0 -200
  61. package/src/tools/ImageViewer/components/ImageInfo.tsx +0 -44
  62. package/src/tools/ImageViewer/components/ImageToolbar.tsx +0 -150
  63. package/src/tools/ImageViewer/components/ImageViewer.tsx +0 -241
  64. package/src/tools/ImageViewer/components/index.ts +0 -7
  65. package/src/tools/ImageViewer/hooks/index.ts +0 -9
  66. package/src/tools/ImageViewer/hooks/useImageLoading.ts +0 -204
  67. package/src/tools/ImageViewer/hooks/useImageTransform.ts +0 -101
  68. package/src/tools/ImageViewer/index.ts +0 -60
  69. package/src/tools/ImageViewer/types.ts +0 -81
  70. package/src/tools/ImageViewer/utils/constants.ts +0 -59
  71. package/src/tools/ImageViewer/utils/debug.ts +0 -14
  72. package/src/tools/ImageViewer/utils/index.ts +0 -17
  73. package/src/tools/ImageViewer/utils/lqip.ts +0 -47
  74. package/src/tools/JsonForm/JsonSchemaForm.tsx +0 -197
  75. package/src/tools/JsonForm/examples/BotConfigExample.tsx +0 -249
  76. package/src/tools/JsonForm/examples/RealBotConfigExample.tsx +0 -161
  77. package/src/tools/JsonForm/index.ts +0 -46
  78. package/src/tools/JsonForm/templates/ArrayFieldItemTemplate.tsx +0 -47
  79. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +0 -74
  80. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +0 -107
  81. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +0 -35
  82. package/src/tools/JsonForm/templates/FieldTemplate.tsx +0 -62
  83. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +0 -116
  84. package/src/tools/JsonForm/templates/index.ts +0 -12
  85. package/src/tools/JsonForm/types.ts +0 -83
  86. package/src/tools/JsonForm/utils.ts +0 -213
  87. package/src/tools/JsonForm/widgets/CheckboxWidget.tsx +0 -37
  88. package/src/tools/JsonForm/widgets/ColorWidget.tsx +0 -219
  89. package/src/tools/JsonForm/widgets/NumberWidget.tsx +0 -89
  90. package/src/tools/JsonForm/widgets/SelectWidget.tsx +0 -97
  91. package/src/tools/JsonForm/widgets/SliderWidget.tsx +0 -148
  92. package/src/tools/JsonForm/widgets/SwitchWidget.tsx +0 -35
  93. package/src/tools/JsonForm/widgets/TextWidget.tsx +0 -96
  94. package/src/tools/JsonForm/widgets/index.ts +0 -14
  95. package/src/tools/JsonTree/index.tsx +0 -243
  96. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +0 -213
  97. package/src/tools/LottiePlayer/index.tsx +0 -55
  98. package/src/tools/LottiePlayer/types.ts +0 -108
  99. package/src/tools/LottiePlayer/useLottie.ts +0 -164
  100. package/src/tools/Mermaid/Mermaid.client.tsx +0 -82
  101. package/src/tools/Mermaid/components/MermaidCodeViewer.tsx +0 -95
  102. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +0 -103
  103. package/src/tools/Mermaid/hooks/index.ts +0 -4
  104. package/src/tools/Mermaid/hooks/useMermaidCleanup.ts +0 -73
  105. package/src/tools/Mermaid/hooks/useMermaidFullscreen.ts +0 -46
  106. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +0 -226
  107. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +0 -29
  108. package/src/tools/Mermaid/index.tsx +0 -41
  109. package/src/tools/Mermaid/utils/mermaid-helpers.ts +0 -33
  110. package/src/tools/OpenapiViewer/components/EndpointInfo.tsx +0 -149
  111. package/src/tools/OpenapiViewer/components/EndpointsLibrary.tsx +0 -263
  112. package/src/tools/OpenapiViewer/components/PlaygroundLayout.tsx +0 -125
  113. package/src/tools/OpenapiViewer/components/PlaygroundStepper.tsx +0 -100
  114. package/src/tools/OpenapiViewer/components/RequestBuilder.tsx +0 -157
  115. package/src/tools/OpenapiViewer/components/RequestParametersForm.tsx +0 -253
  116. package/src/tools/OpenapiViewer/components/ResponseViewer.tsx +0 -173
  117. package/src/tools/OpenapiViewer/components/VersionSelector.tsx +0 -68
  118. package/src/tools/OpenapiViewer/components/index.ts +0 -14
  119. package/src/tools/OpenapiViewer/constants.ts +0 -39
  120. package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +0 -337
  121. package/src/tools/OpenapiViewer/hooks/index.ts +0 -8
  122. package/src/tools/OpenapiViewer/hooks/useMobile.ts +0 -10
  123. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +0 -199
  124. package/src/tools/OpenapiViewer/index.tsx +0 -38
  125. package/src/tools/OpenapiViewer/types.ts +0 -151
  126. package/src/tools/OpenapiViewer/utils/apiKeyManager.ts +0 -149
  127. package/src/tools/OpenapiViewer/utils/formatters.ts +0 -71
  128. package/src/tools/OpenapiViewer/utils/index.ts +0 -9
  129. package/src/tools/OpenapiViewer/utils/versionManager.ts +0 -161
  130. package/src/tools/PrettyCode/PrettyCode.client.tsx +0 -208
  131. package/src/tools/PrettyCode/index.tsx +0 -45
  132. package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +0 -91
  133. package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +0 -284
  134. package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +0 -141
  135. package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +0 -178
  136. package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +0 -95
  137. package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -139
  138. package/src/tools/VideoPlayer/README.md +0 -264
  139. package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
  140. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -174
  141. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
  142. package/src/tools/VideoPlayer/components/index.ts +0 -14
  143. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
  144. package/src/tools/VideoPlayer/context/index.ts +0 -8
  145. package/src/tools/VideoPlayer/hooks/index.ts +0 -12
  146. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -70
  147. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -116
  148. package/src/tools/VideoPlayer/index.ts +0 -77
  149. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
  150. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
  151. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -400
  152. package/src/tools/VideoPlayer/providers/index.ts +0 -8
  153. package/src/tools/VideoPlayer/types/index.ts +0 -38
  154. package/src/tools/VideoPlayer/types/player.ts +0 -116
  155. package/src/tools/VideoPlayer/types/provider.ts +0 -93
  156. package/src/tools/VideoPlayer/types/sources.ts +0 -97
  157. package/src/tools/VideoPlayer/utils/debug.ts +0 -14
  158. package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
  159. package/src/tools/VideoPlayer/utils/index.ts +0 -12
  160. package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
  161. package/src/tools/index.ts +0 -170
@@ -1,279 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * HybridWaveform - Real-time frequency visualization for hybrid player.
5
- *
6
- * Two modes:
7
- * - 'frequency': Real-time frequency bars (default, requires playing audio)
8
- * - 'static': Static progress bar (for when no analyser is available)
9
- *
10
- * Features:
11
- * - Shows buffered regions
12
- * - Click to seek
13
- * - Responsive width
14
- */
15
-
16
- import { useRef, useEffect, useCallback, memo } from 'react';
17
- import { useHybridAudioContext } from '../context/HybridAudioProvider';
18
- import { cn } from '@djangocfg/ui-core/lib';
19
-
20
- // =============================================================================
21
- // TYPES
22
- // =============================================================================
23
-
24
- export interface HybridWaveformProps {
25
- /** Visualization mode */
26
- mode?: 'frequency' | 'static';
27
- /** Canvas height in pixels */
28
- height?: number;
29
- /** Bar width in pixels */
30
- barWidth?: number;
31
- /** Gap between bars in pixels */
32
- barGap?: number;
33
- /** Bar border radius */
34
- barRadius?: number;
35
- /** Color for played portion */
36
- progressColor?: string;
37
- /** Color for unplayed portion */
38
- waveColor?: string;
39
- /** Color for buffered regions indicator */
40
- bufferedColor?: string;
41
- /** Additional CSS class */
42
- className?: string;
43
- /** Callback when user seeks */
44
- onSeek?: (time: number) => void;
45
- }
46
-
47
- // =============================================================================
48
- // COMPONENT
49
- // =============================================================================
50
-
51
- export const HybridWaveform = memo(function HybridWaveform({
52
- mode = 'frequency',
53
- height = 64,
54
- barWidth = 3,
55
- barGap = 2,
56
- barRadius = 2,
57
- progressColor = 'hsl(217 91% 60%)',
58
- waveColor = 'hsl(217 91% 60% / 0.3)',
59
- bufferedColor = 'hsl(217 91% 60% / 0.15)',
60
- className,
61
- onSeek,
62
- }: HybridWaveformProps) {
63
- const canvasRef = useRef<HTMLCanvasElement>(null);
64
- const containerRef = useRef<HTMLDivElement>(null);
65
- const animationRef = useRef<number | null>(null);
66
- const { state, controls, webAudio } = useHybridAudioContext();
67
-
68
- // Handle click to seek
69
- const handleClick = useCallback(
70
- (e: React.MouseEvent<HTMLCanvasElement>) => {
71
- const canvas = canvasRef.current;
72
- if (!canvas || !state.duration) return;
73
-
74
- const rect = canvas.getBoundingClientRect();
75
- const x = e.clientX - rect.left;
76
- const progress = x / rect.width;
77
- const time = state.duration * progress;
78
-
79
- controls.seek(time);
80
- onSeek?.(time);
81
- },
82
- [state.duration, controls, onSeek]
83
- );
84
-
85
- // Render frequency bars (real-time visualization)
86
- const renderFrequency = useCallback(() => {
87
- const canvas = canvasRef.current;
88
- const analyser = webAudio.analyser;
89
- if (!canvas) return;
90
-
91
- const ctx = canvas.getContext('2d');
92
- if (!ctx) return;
93
-
94
- const { width, height: canvasHeight } = canvas;
95
- const dpr = window.devicePixelRatio || 1;
96
- const displayWidth = width / dpr;
97
-
98
- // Get frequency data if analyser is available
99
- let dataArray: Uint8Array<ArrayBuffer> | null = null;
100
- if (analyser) {
101
- dataArray = new Uint8Array(analyser.frequencyBinCount) as Uint8Array<ArrayBuffer>;
102
- analyser.getByteFrequencyData(dataArray);
103
- }
104
-
105
- ctx.clearRect(0, 0, width, canvasHeight);
106
-
107
- // Draw buffered regions at bottom
108
- if (state.buffered && state.duration > 0) {
109
- ctx.fillStyle = bufferedColor;
110
- for (let i = 0; i < state.buffered.length; i++) {
111
- const start = (state.buffered.start(i) / state.duration) * width;
112
- const end = (state.buffered.end(i) / state.duration) * width;
113
- ctx.fillRect(start, canvasHeight - 3 * dpr, end - start, 3 * dpr);
114
- }
115
- }
116
-
117
- // Calculate bar count based on available width
118
- const barCount = Math.floor(displayWidth / (barWidth + barGap));
119
- const progress = state.duration > 0 ? state.currentTime / state.duration : 0;
120
- const progressX = width * progress;
121
-
122
- // Draw bars
123
- for (let i = 0; i < barCount; i++) {
124
- let barHeight: number;
125
-
126
- if (dataArray && state.isPlaying) {
127
- // Real-time frequency data
128
- const step = Math.floor(dataArray.length / barCount);
129
- const value = dataArray[i * step] / 255;
130
- barHeight = Math.max(4 * dpr, value * (canvasHeight - 6 * dpr) * 0.9);
131
- } else {
132
- // Static fallback - small bars
133
- barHeight = 8 * dpr;
134
- }
135
-
136
- const x = i * (barWidth + barGap) * dpr;
137
- const y = (canvasHeight - barHeight) / 2;
138
-
139
- ctx.fillStyle = x < progressX ? progressColor : waveColor;
140
-
141
- // Draw rounded rect
142
- const radius = barRadius * dpr;
143
- const rectWidth = barWidth * dpr;
144
- ctx.beginPath();
145
- ctx.roundRect(x, y, rectWidth, barHeight, radius);
146
- ctx.fill();
147
- }
148
-
149
- // Continue animation if playing
150
- if (state.isPlaying) {
151
- animationRef.current = requestAnimationFrame(renderFrequency);
152
- }
153
- }, [
154
- webAudio.analyser,
155
- state.buffered,
156
- state.duration,
157
- state.currentTime,
158
- state.isPlaying,
159
- barWidth,
160
- barGap,
161
- barRadius,
162
- progressColor,
163
- waveColor,
164
- bufferedColor,
165
- ]);
166
-
167
- // Render static progress bar
168
- const renderStatic = useCallback(() => {
169
- const canvas = canvasRef.current;
170
- if (!canvas) return;
171
-
172
- const ctx = canvas.getContext('2d');
173
- if (!ctx) return;
174
-
175
- const { width, height: canvasHeight } = canvas;
176
- const dpr = window.devicePixelRatio || 1;
177
-
178
- ctx.clearRect(0, 0, width, canvasHeight);
179
-
180
- // Draw buffered regions
181
- if (state.buffered && state.duration > 0) {
182
- ctx.fillStyle = bufferedColor;
183
- for (let i = 0; i < state.buffered.length; i++) {
184
- const start = (state.buffered.start(i) / state.duration) * width;
185
- const end = (state.buffered.end(i) / state.duration) * width;
186
- ctx.fillRect(start, 0, end - start, canvasHeight);
187
- }
188
- }
189
-
190
- // Draw progress bar
191
- const progress = state.duration > 0 ? state.currentTime / state.duration : 0;
192
- const progressWidth = width * progress;
193
-
194
- // Background
195
- ctx.fillStyle = waveColor;
196
- ctx.fillRect(0, canvasHeight / 2 - 2 * dpr, width, 4 * dpr);
197
-
198
- // Progress
199
- ctx.fillStyle = progressColor;
200
- ctx.fillRect(0, canvasHeight / 2 - 2 * dpr, progressWidth, 4 * dpr);
201
-
202
- // Handle
203
- if (progress > 0) {
204
- ctx.beginPath();
205
- ctx.arc(progressWidth, canvasHeight / 2, 6 * dpr, 0, Math.PI * 2);
206
- ctx.fill();
207
- }
208
- }, [state.buffered, state.duration, state.currentTime, progressColor, waveColor, bufferedColor]);
209
-
210
- // Resize canvas to match container
211
- useEffect(() => {
212
- const container = containerRef.current;
213
- const canvas = canvasRef.current;
214
- if (!container || !canvas) return;
215
-
216
- const resizeObserver = new ResizeObserver((entries) => {
217
- const entry = entries[0];
218
- if (!entry) return;
219
-
220
- const dpr = window.devicePixelRatio || 1;
221
- const displayWidth = entry.contentRect.width;
222
- const displayHeight = height;
223
-
224
- canvas.width = displayWidth * dpr;
225
- canvas.height = displayHeight * dpr;
226
- canvas.style.width = `${displayWidth}px`;
227
- canvas.style.height = `${displayHeight}px`;
228
-
229
- // Re-render after resize
230
- if (mode === 'frequency') {
231
- renderFrequency();
232
- } else {
233
- renderStatic();
234
- }
235
- });
236
-
237
- resizeObserver.observe(container);
238
- return () => resizeObserver.disconnect();
239
- }, [height, mode, renderFrequency, renderStatic]);
240
-
241
- // Animation loop for frequency mode
242
- useEffect(() => {
243
- if (mode === 'frequency') {
244
- renderFrequency();
245
- }
246
-
247
- return () => {
248
- if (animationRef.current) {
249
- cancelAnimationFrame(animationRef.current);
250
- }
251
- };
252
- }, [mode, renderFrequency]);
253
-
254
- // Re-render on time change for static mode
255
- useEffect(() => {
256
- if (mode === 'static') {
257
- renderStatic();
258
- }
259
- }, [mode, state.currentTime, renderStatic]);
260
-
261
- // Re-render frequency when playback state changes
262
- useEffect(() => {
263
- if (mode === 'frequency' && !state.isPlaying) {
264
- // One final render when stopped
265
- renderFrequency();
266
- }
267
- }, [mode, state.isPlaying, renderFrequency]);
268
-
269
- return (
270
- <div ref={containerRef} className={cn('w-full', className)}>
271
- <canvas
272
- ref={canvasRef}
273
- onClick={handleClick}
274
- className="cursor-pointer"
275
- style={{ width: '100%', height }}
276
- />
277
- </div>
278
- );
279
- });
@@ -1,149 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * AudioReactiveCover - Album art with audio-reactive animations
5
- *
6
- * Uses effects utilities for clean data preparation before render.
7
- * Click on cover to switch between effect variants.
8
- *
9
- * Must be used within HybridAudioProvider context.
10
- */
11
-
12
- import { type ReactNode } from 'react';
13
- import { cn } from '@djangocfg/ui-nextjs';
14
- import { useHybridAudioLevels, useHybridAudioState } from '../../context/HybridAudioProvider';
15
- import {
16
- type EffectVariant,
17
- type EffectIntensity,
18
- type EffectColorScheme,
19
- getEffectConfig,
20
- prepareEffectColors,
21
- calculateGlowLayers,
22
- calculateOrbs,
23
- calculateMeshGradients,
24
- calculateSpotlight,
25
- EFFECT_ANIMATIONS,
26
- } from '../../effects';
27
- import { GlowEffect, OrbsEffect, SpotlightEffect, MeshEffect, type GlowEffectData } from './effects';
28
-
29
- // =============================================================================
30
- // TYPES
31
- // =============================================================================
32
-
33
- export interface AudioReactiveCoverProps {
34
- children: ReactNode;
35
- size?: 'sm' | 'md' | 'lg';
36
- variant?: EffectVariant;
37
- intensity?: EffectIntensity;
38
- colorScheme?: EffectColorScheme;
39
- onClick?: () => void;
40
- className?: string;
41
- }
42
-
43
- // =============================================================================
44
- // CONSTANTS
45
- // =============================================================================
46
-
47
- const SIZES = {
48
- sm: { container: 'w-32 h-32', orbBase: 40 },
49
- md: { container: 'w-40 h-40', orbBase: 50 },
50
- lg: { container: 'w-48 h-48', orbBase: 60 },
51
- };
52
-
53
- // =============================================================================
54
- // COMPONENT
55
- // =============================================================================
56
-
57
- export function AudioReactiveCover({
58
- children,
59
- size = 'lg',
60
- variant = 'spotlight',
61
- intensity = 'medium',
62
- colorScheme = 'primary',
63
- onClick,
64
- className,
65
- }: AudioReactiveCoverProps) {
66
- // Get audio state from HybridAudioProvider context
67
- const { isPlaying } = useHybridAudioState();
68
- const levels = useHybridAudioLevels();
69
-
70
- // =========================================================================
71
- // PREPARE DATA BEFORE RENDER
72
- // =========================================================================
73
-
74
- const sizeConfig = SIZES[size];
75
- const effectConfig = getEffectConfig(intensity);
76
- const { colors, hueShift } = prepareEffectColors(colorScheme, levels);
77
-
78
- // Calculate scale based on overall level
79
- const containerScale = 1 + levels.overall * effectConfig.scale;
80
-
81
- // Prepare effect-specific data - NO memoization for real-time reactivity
82
- const glowData: GlowEffectData | null = variant === 'glow' ? {
83
- layers: calculateGlowLayers(levels, effectConfig, colors),
84
- hueShift,
85
- showPulseRings: levels.bass > 0.5,
86
- showSparkle: levels.high > 0.4,
87
- } : null;
88
-
89
- const orbsData = variant === 'orbs'
90
- ? calculateOrbs(levels, effectConfig, colors, sizeConfig.orbBase)
91
- : null;
92
-
93
- const meshData = variant === 'mesh'
94
- ? calculateMeshGradients(levels, effectConfig, colors)
95
- : null;
96
-
97
- const spotlightData = variant === 'spotlight'
98
- ? calculateSpotlight(levels, effectConfig, colors, levels.mid * 360)
99
- : null;
100
-
101
- // =========================================================================
102
- // RENDER
103
- // =========================================================================
104
-
105
- return (
106
- <div
107
- className={cn('relative', sizeConfig.container, className)}
108
- style={{
109
- transform: `scale(${containerScale})`,
110
- transition: 'transform 0.1s ease-out',
111
- }}
112
- >
113
- {/* Effect layers container - under cover, non-interactive */}
114
- <div className="absolute inset-0 z-0 pointer-events-none overflow-visible">
115
- {glowData && (
116
- <GlowEffect data={glowData} colors={colors} isPlaying={isPlaying} />
117
- )}
118
-
119
- {orbsData && (
120
- <OrbsEffect orbs={orbsData} blur={effectConfig.blur} isPlaying={isPlaying} />
121
- )}
122
-
123
- {spotlightData && (
124
- <SpotlightEffect data={spotlightData} colors={colors} blur={effectConfig.blur} isPlaying={isPlaying} />
125
- )}
126
-
127
- {meshData && (
128
- <MeshEffect gradients={meshData} blur={effectConfig.blur} isPlaying={isPlaying} />
129
- )}
130
- </div>
131
-
132
- {/* Content (cover art) */}
133
- <div
134
- className="relative w-full h-full rounded-lg overflow-hidden shadow-2xl z-10 bg-background cursor-pointer"
135
- onClick={onClick}
136
- role={onClick ? 'button' : undefined}
137
- tabIndex={onClick ? 0 : undefined}
138
- onKeyDown={onClick ? (e) => e.key === 'Enter' && onClick() : undefined}
139
- >
140
- {children}
141
- </div>
142
-
143
- {/* Inject animations once */}
144
- <style dangerouslySetInnerHTML={{ __html: EFFECT_ANIMATIONS }} />
145
- </div>
146
- );
147
- }
148
-
149
- export default AudioReactiveCover;
@@ -1,110 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * GlowEffect - Multi-layer glow effect with pulse rings
5
- */
6
-
7
- import { cn } from '@djangocfg/ui-nextjs';
8
- import type { calculateGlowLayers } from '../../../effects';
9
-
10
- // =============================================================================
11
- // TYPES
12
- // =============================================================================
13
-
14
- export interface GlowEffectData {
15
- layers: ReturnType<typeof calculateGlowLayers>;
16
- hueShift: number;
17
- showPulseRings: boolean;
18
- showSparkle: boolean;
19
- }
20
-
21
- interface GlowEffectProps {
22
- data: GlowEffectData;
23
- colors: string[];
24
- isPlaying: boolean;
25
- }
26
-
27
- // =============================================================================
28
- // COMPONENT
29
- // =============================================================================
30
-
31
- export function GlowEffect({ data, colors, isPlaying }: GlowEffectProps) {
32
- const { layers, hueShift, showPulseRings, showSparkle } = data;
33
-
34
- return (
35
- <>
36
- {/* Main glow layers */}
37
- {layers.map((layer, i) => (
38
- <div
39
- key={i}
40
- className={cn('absolute rounded-2xl -z-10', layer.blur)}
41
- style={{
42
- inset: `-${layer.inset}px`,
43
- background: layer.background,
44
- opacity: isPlaying ? layer.opacity : 0,
45
- transform: i < 2 ? `scaleY(${layer.scale})` : `scale(${layer.scale})`,
46
- animation: isPlaying && layer.animation ? layer.animation : 'none',
47
- transition: 'opacity 0.3s',
48
- }}
49
- />
50
- ))}
51
-
52
- {/* Rotating color sweep */}
53
- <div
54
- className="absolute rounded-2xl blur-xl overflow-hidden -z-10"
55
- style={{
56
- inset: '-75px',
57
- opacity: isPlaying ? 0.6 : 0,
58
- transition: 'opacity 0.5s',
59
- }}
60
- >
61
- <div
62
- className="absolute inset-0"
63
- style={{
64
- background: `conic-gradient(
65
- from ${hueShift}deg at 50% 50%,
66
- hsl(${colors[0]} / 0.4) 0deg,
67
- hsl(${colors[1] || colors[0]} / 0.3) 90deg,
68
- hsl(${colors[2] || colors[0]} / 0.3) 180deg,
69
- hsl(${colors[3] || colors[0]} / 0.3) 270deg,
70
- hsl(${colors[0]} / 0.4) 360deg
71
- )`,
72
- animation: isPlaying ? 'glow-rotate 6s linear infinite' : 'none',
73
- }}
74
- />
75
- </div>
76
-
77
- {/* Pulse rings on bass hits */}
78
- {showPulseRings && (
79
- <>
80
- <div
81
- className="absolute -inset-6 rounded-xl border-2 animate-ping -z-10"
82
- style={{
83
- borderColor: `hsl(${colors[0]} / 0.4)`,
84
- animationDuration: '1s',
85
- }}
86
- />
87
- <div
88
- className="absolute -inset-12 rounded-2xl border animate-ping -z-10"
89
- style={{
90
- borderColor: `hsl(${colors[1] || colors[0]} / 0.3)`,
91
- animationDuration: '1.5s',
92
- animationDelay: '0.2s',
93
- }}
94
- />
95
- </>
96
- )}
97
-
98
- {/* Sparkle on high frequencies */}
99
- {showSparkle && (
100
- <div
101
- className="absolute -inset-18 rounded-3xl -z-10"
102
- style={{
103
- background: `radial-gradient(circle at 50% 30%, hsl(${colors[2] || colors[0]} / 0.5) 0%, transparent 30%)`,
104
- animation: 'sparkle-move 0.5s ease-out',
105
- }}
106
- />
107
- )}
108
- </>
109
- );
110
- }
@@ -1,58 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * MeshEffect - Mesh gradient blobs that react to audio
5
- */
6
-
7
- import { cn } from '@djangocfg/ui-nextjs';
8
- import type { calculateMeshGradients } from '../../../effects';
9
-
10
- // =============================================================================
11
- // TYPES
12
- // =============================================================================
13
-
14
- interface MeshEffectProps {
15
- gradients: ReturnType<typeof calculateMeshGradients>;
16
- blur: string;
17
- isPlaying: boolean;
18
- }
19
-
20
- // =============================================================================
21
- // COMPONENT
22
- // =============================================================================
23
-
24
- export function MeshEffect({ gradients, isPlaying }: MeshEffectProps) {
25
- return (
26
- <>
27
- {gradients.map((g, i) => {
28
- const isCenter = 'isCenter' in g && g.isCenter;
29
- const scale = 'scale' in g ? g.scale : 1;
30
- const rotation = 'rotation' in g ? g.rotation : 0;
31
- const itemBlur = 'blur' in g ? g.blur : 'blur-2xl';
32
-
33
- return (
34
- <div
35
- key={i}
36
- className={cn('absolute rounded-full -z-10', itemBlur)}
37
- style={{
38
- width: g.width,
39
- height: g.height,
40
- top: 'top' in g ? g.top : undefined,
41
- bottom: 'bottom' in g ? g.bottom : undefined,
42
- left: 'left' in g ? g.left : undefined,
43
- right: 'right' in g ? g.right : undefined,
44
- background: isCenter
45
- ? `radial-gradient(circle, hsl(${g.color} / 0.6) 0%, hsl(${g.color} / 0.3) 30%, transparent 60%)`
46
- : `radial-gradient(circle, hsl(${g.color}) 0%, hsl(${g.color} / 0.5) 30%, transparent 65%)`,
47
- opacity: isPlaying ? g.opacity : 0,
48
- transform: isCenter
49
- ? `translate(-50%, -50%) scale(${scale})`
50
- : `scale(${scale}) rotate(${rotation}deg)`,
51
- transition: 'all 0.08s ease-out',
52
- }}
53
- />
54
- );
55
- })}
56
- </>
57
- );
58
- }
@@ -1,45 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * OrbsEffect - Floating orb particles that react to audio
5
- */
6
-
7
- import { cn } from '@djangocfg/ui-nextjs';
8
- import type { calculateOrbs } from '../../../effects';
9
-
10
- // =============================================================================
11
- // TYPES
12
- // =============================================================================
13
-
14
- interface OrbsEffectProps {
15
- orbs: ReturnType<typeof calculateOrbs>;
16
- blur: string;
17
- isPlaying: boolean;
18
- }
19
-
20
- // =============================================================================
21
- // COMPONENT
22
- // =============================================================================
23
-
24
- export function OrbsEffect({ orbs, blur, isPlaying }: OrbsEffectProps) {
25
- return (
26
- <>
27
- {orbs.map((orb, i) => (
28
- <div
29
- key={i}
30
- className={cn('absolute rounded-full -z-10', blur)}
31
- style={{
32
- width: orb.size,
33
- height: orb.size,
34
- left: `${orb.x}%`,
35
- top: `${orb.y}%`,
36
- background: `radial-gradient(circle at 30% 30%, hsl(${orb.color}) 0%, hsl(${orb.color} / 0.5) 40%, transparent 70%)`,
37
- opacity: isPlaying ? orb.opacity : 0,
38
- transform: `translate(-50%, -50%) scale(${orb.scale})`,
39
- transition: 'all 0.08s ease-out',
40
- }}
41
- />
42
- ))}
43
- </>
44
- );
45
- }