@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,82 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * SpotlightEffect - Rotating spotlight with conic gradients
5
- */
6
-
7
- import { cn } from '@djangocfg/ui-nextjs';
8
- import type { calculateSpotlight } from '../../../effects';
9
-
10
- // =============================================================================
11
- // TYPES
12
- // =============================================================================
13
-
14
- interface SpotlightEffectProps {
15
- data: ReturnType<typeof calculateSpotlight>;
16
- colors: string[];
17
- blur: string;
18
- isPlaying: boolean;
19
- }
20
-
21
- // =============================================================================
22
- // COMPONENT
23
- // =============================================================================
24
-
25
- export function SpotlightEffect({ data, colors, blur, isPlaying }: SpotlightEffectProps) {
26
- const inset = 'inset' in data ? data.inset : 12;
27
- const pulseInset = 'pulseInset' in data ? data.pulseInset : 24;
28
- const ringOpacity = 'ringOpacity' in data ? data.ringOpacity : 0.3;
29
- const ringScale = 'ringScale' in data ? data.ringScale : 1;
30
-
31
- return (
32
- <>
33
- {/* Rotating conic gradient - reactive size */}
34
- <div
35
- className={cn('absolute rounded-xl -z-10', blur)}
36
- style={{
37
- inset: `-${inset}px`,
38
- background: `conic-gradient(
39
- from ${data.rotation}deg,
40
- hsl(${colors[0]} / ${data.colors[0]?.opacity || 0.5}),
41
- hsl(${colors[1] || colors[0]} / ${data.colors[1]?.opacity || 0.7}),
42
- hsl(${colors[2] || colors[0]} / ${data.colors[2]?.opacity || 0.5}),
43
- hsl(${colors[0]} / ${data.colors[1]?.opacity || 0.7}),
44
- hsl(${colors[0]} / ${data.colors[0]?.opacity || 0.5})
45
- )`,
46
- opacity: isPlaying ? 1 : 0,
47
- transition: 'all 0.08s ease-out',
48
- }}
49
- />
50
-
51
- {/* Inner border */}
52
- <div
53
- className="absolute -inset-1 rounded-lg bg-background -z-10"
54
- style={{ opacity: isPlaying ? 1 : 0, transition: 'opacity 0.1s' }}
55
- />
56
-
57
- {/* Bass pulse glow - reactive size */}
58
- <div
59
- className={cn('absolute rounded-2xl -z-10', blur)}
60
- style={{
61
- inset: `-${pulseInset}px`,
62
- background: `radial-gradient(circle, hsl(${colors[0]} / 0.7) 0%, hsl(${colors[0]} / 0.3) 50%, transparent 70%)`,
63
- opacity: isPlaying ? data.pulseOpacity : 0,
64
- transform: `scale(${data.pulseScale})`,
65
- transition: 'all 0.08s ease-out',
66
- }}
67
- />
68
-
69
- {/* Outer ring glow */}
70
- <div
71
- className="absolute rounded-3xl -z-10 blur-2xl"
72
- style={{
73
- inset: `-${pulseInset + 30}px`,
74
- background: `radial-gradient(circle, hsl(${colors[1] || colors[0]} / 0.4) 0%, transparent 60%)`,
75
- opacity: isPlaying ? ringOpacity : 0,
76
- transform: `scale(${ringScale})`,
77
- transition: 'all 0.08s ease-out',
78
- }}
79
- />
80
- </>
81
- );
82
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * ReactiveCover effects - Audio-reactive visual effects
3
- */
4
-
5
- export { GlowEffect, type GlowEffectData } from './GlowEffect';
6
- export { OrbsEffect } from './OrbsEffect';
7
- export { SpotlightEffect } from './SpotlightEffect';
8
- export { MeshEffect } from './MeshEffect';
@@ -1,6 +0,0 @@
1
- /**
2
- * ReactiveCover - Audio-reactive cover art component
3
- */
4
-
5
- export { AudioReactiveCover, type AudioReactiveCoverProps } from './AudioReactiveCover';
6
- export { GlowEffect, OrbsEffect, SpotlightEffect, MeshEffect, type GlowEffectData } from './effects';
@@ -1,22 +0,0 @@
1
- /**
2
- * AudioPlayer components - Public API
3
- *
4
- * Uses HTML5 audio for playback + Web Audio API for visualization.
5
- * No crackling, native streaming support.
6
- */
7
-
8
- // Player components
9
- export { HybridAudioPlayer, type HybridAudioPlayerProps } from './HybridAudioPlayer';
10
- export { HybridSimplePlayer, type HybridSimplePlayerProps } from './HybridSimplePlayer';
11
- export { HybridWaveform, type HybridWaveformProps } from './HybridWaveform';
12
-
13
- // ReactiveCover
14
- export {
15
- AudioReactiveCover,
16
- type AudioReactiveCoverProps,
17
- GlowEffect,
18
- OrbsEffect,
19
- SpotlightEffect,
20
- MeshEffect,
21
- type GlowEffectData,
22
- } from './ReactiveCover';
@@ -1,158 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * HybridAudioProvider - Context provider for hybrid audio player.
5
- *
6
- * Provides audio state, controls, and analysis data to child components.
7
- * Uses native HTML5 audio for playback with Web Audio API for visualization only.
8
- */
9
-
10
- import { createContext, useContext, useMemo, useEffect, useRef, type ReactNode } from 'react';
11
- import {
12
- useHybridAudio,
13
- type UseHybridAudioOptions,
14
- type HybridAudioState,
15
- type HybridAudioControls,
16
- type HybridWebAudioAPI,
17
- } from '../hooks/useHybridAudio';
18
- import { useHybridAudioAnalysis } from '../hooks/useHybridAudioAnalysis';
19
- import { useVisualization } from '../hooks/useVisualization';
20
- import type { AudioLevels } from '../effects';
21
-
22
- // =============================================================================
23
- // TYPES
24
- // =============================================================================
25
-
26
- export interface HybridAudioContextValue {
27
- // Audio state
28
- state: HybridAudioState;
29
-
30
- // Controls
31
- controls: HybridAudioControls;
32
-
33
- // Web Audio (for visualizations)
34
- webAudio: HybridWebAudioAPI;
35
-
36
- // Audio levels (for reactive effects)
37
- audioLevels: AudioLevels;
38
-
39
- // Audio element ref (for custom integrations)
40
- audioRef: React.RefObject<HTMLAudioElement | null>;
41
- }
42
-
43
- // =============================================================================
44
- // CONTEXT
45
- // =============================================================================
46
-
47
- const HybridAudioContext = createContext<HybridAudioContextValue | null>(null);
48
-
49
- // =============================================================================
50
- // PROVIDER
51
- // =============================================================================
52
-
53
- export interface HybridAudioProviderProps extends UseHybridAudioOptions {
54
- children: ReactNode;
55
- }
56
-
57
- export function HybridAudioProvider({ children, ...options }: HybridAudioProviderProps) {
58
- // Load persisted settings (shared with visualization)
59
- const { settings: savedSettings, setSetting } = useVisualization();
60
-
61
- // Use saved settings as initial values
62
- const effectiveOptions = {
63
- ...options,
64
- initialVolume: savedSettings.volume,
65
- loop: savedSettings.isLooping,
66
- };
67
-
68
- const { audioRef, state, controls, webAudio } = useHybridAudio(effectiveOptions);
69
-
70
- // Track if we've applied initial settings
71
- const hasAppliedInitialSettings = useRef(false);
72
-
73
- // Apply saved settings after audio is ready (for hydration timing)
74
- useEffect(() => {
75
- if (!state.isReady || hasAppliedInitialSettings.current) return;
76
- hasAppliedInitialSettings.current = true;
77
-
78
- // Apply saved volume and loop settings
79
- controls.setVolume(savedSettings.volume);
80
- controls.setLoop(savedSettings.isLooping);
81
- }, [state.isReady, savedSettings, controls]);
82
-
83
- // Persist settings when they change
84
- useEffect(() => {
85
- if (!state.isReady) return;
86
-
87
- // Only save if values actually changed
88
- if (state.volume !== savedSettings.volume) {
89
- setSetting('volume', state.volume);
90
- }
91
- if (state.isLooping !== savedSettings.isLooping) {
92
- setSetting('isLooping', state.isLooping);
93
- }
94
- }, [state.isReady, state.volume, state.isLooping, savedSettings, setSetting]);
95
-
96
- // Audio analysis for reactive effects
97
- const audioLevels = useHybridAudioAnalysis(webAudio.analyser, state.isPlaying);
98
-
99
- const value = useMemo<HybridAudioContextValue>(
100
- () => ({
101
- state,
102
- controls,
103
- webAudio,
104
- audioLevels,
105
- audioRef,
106
- }),
107
- [state, controls, webAudio, audioLevels, audioRef]
108
- );
109
-
110
- return <HybridAudioContext.Provider value={value}>{children}</HybridAudioContext.Provider>;
111
- }
112
-
113
- // =============================================================================
114
- // HOOKS
115
- // =============================================================================
116
-
117
- /**
118
- * Access full hybrid audio context
119
- */
120
- export function useHybridAudioContext(): HybridAudioContextValue {
121
- const context = useContext(HybridAudioContext);
122
- if (!context) {
123
- throw new Error('useHybridAudioContext must be used within HybridAudioProvider');
124
- }
125
- return context;
126
- }
127
-
128
- /**
129
- * Access audio state only (read-only)
130
- */
131
- export function useHybridAudioState(): HybridAudioState {
132
- const { state } = useHybridAudioContext();
133
- return state;
134
- }
135
-
136
- /**
137
- * Access audio controls only (no state re-renders)
138
- */
139
- export function useHybridAudioControls(): HybridAudioControls {
140
- const { controls } = useHybridAudioContext();
141
- return controls;
142
- }
143
-
144
- /**
145
- * Access audio levels for reactive effects
146
- */
147
- export function useHybridAudioLevels(): AudioLevels {
148
- const { audioLevels } = useHybridAudioContext();
149
- return audioLevels;
150
- }
151
-
152
- /**
153
- * Access Web Audio API for custom visualizations
154
- */
155
- export function useHybridWebAudio(): HybridWebAudioAPI {
156
- const { webAudio } = useHybridAudioContext();
157
- return webAudio;
158
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * AudioPlayer context - Public API
3
- *
4
- * HybridAudioProvider: HTML5 audio + Web Audio API for visualization
5
- */
6
-
7
- export {
8
- HybridAudioProvider,
9
- useHybridAudioContext,
10
- useHybridAudioState,
11
- useHybridAudioControls,
12
- useHybridAudioLevels,
13
- useHybridWebAudio,
14
- type HybridAudioContextValue,
15
- type HybridAudioProviderProps,
16
- } from './HybridAudioProvider';
@@ -1,412 +0,0 @@
1
- /**
2
- * Audio Reactive Effects - Common utilities and types
3
- *
4
- * Provides reusable effect calculations and configurations
5
- */
6
-
7
- // =============================================================================
8
- // TYPES
9
- // =============================================================================
10
-
11
- export type EffectVariant = 'glow' | 'orbs' | 'spotlight' | 'mesh';
12
- export type EffectIntensity = 'subtle' | 'medium' | 'strong';
13
- export type EffectColorScheme = 'primary' | 'vibrant' | 'cool' | 'warm';
14
-
15
- export interface AudioLevels {
16
- bass: number;
17
- mid: number;
18
- high: number;
19
- overall: number;
20
- }
21
-
22
- export interface EffectConfig {
23
- opacity: number;
24
- scale: number;
25
- blur: string;
26
- }
27
-
28
- export interface EffectColors {
29
- colors: string[];
30
- hueShift: number;
31
- }
32
-
33
- export interface EffectLayer {
34
- inset: number;
35
- opacity: number;
36
- scale: number;
37
- background: string;
38
- blur: string;
39
- animation?: string;
40
- }
41
-
42
- // =============================================================================
43
- // CONSTANTS
44
- // =============================================================================
45
-
46
- export const INTENSITY_CONFIG: Record<EffectIntensity, EffectConfig> = {
47
- subtle: { opacity: 0.3, scale: 0.02, blur: 'blur-2xl' },
48
- medium: { opacity: 0.5, scale: 0.04, blur: 'blur-xl' },
49
- strong: { opacity: 0.7, scale: 0.06, blur: 'blur-lg' },
50
- };
51
-
52
- export const COLOR_SCHEMES: Record<EffectColorScheme, string[]> = {
53
- primary: ['217 91% 60%'],
54
- vibrant: ['217 91% 60%', '142 76% 36%', '262 83% 58%', '25 95% 53%'],
55
- cool: ['217 91% 60%', '262 83% 58%', '199 89% 48%'],
56
- warm: ['25 95% 53%', '0 84% 60%', '38 92% 50%'],
57
- };
58
-
59
- // Default multi-color palette when single color provided
60
- const DEFAULT_GLOW_COLORS = [
61
- '217 91% 60%', // Blue
62
- '262 83% 58%', // Purple
63
- '330 81% 60%', // Pink
64
- '25 95% 53%', // Orange
65
- ];
66
-
67
- // =============================================================================
68
- // UTILITIES
69
- // =============================================================================
70
-
71
- /**
72
- * Get effect configuration from intensity setting
73
- */
74
- export function getEffectConfig(intensity: EffectIntensity): EffectConfig {
75
- return INTENSITY_CONFIG[intensity];
76
- }
77
-
78
- /**
79
- * Get color array from color scheme
80
- */
81
- export function getColors(colorScheme: EffectColorScheme): string[] {
82
- return COLOR_SCHEMES[colorScheme];
83
- }
84
-
85
- /**
86
- * Prepare colors with hue shift based on audio levels
87
- */
88
- export function prepareEffectColors(
89
- colorScheme: EffectColorScheme,
90
- levels: AudioLevels
91
- ): EffectColors {
92
- const baseColors = COLOR_SCHEMES[colorScheme];
93
- const colors = baseColors.length > 1 ? baseColors : DEFAULT_GLOW_COLORS;
94
- const hueShift = Math.floor(
95
- (levels.bass * 30) + (levels.mid * 20) + (levels.high * 10)
96
- );
97
-
98
- return { colors, hueShift };
99
- }
100
-
101
- /**
102
- * Calculate glow layer properties
103
- */
104
- export function calculateGlowLayers(
105
- levels: AudioLevels,
106
- config: EffectConfig,
107
- colors: string[]
108
- ): EffectLayer[] {
109
- const { bass, mid, high } = levels;
110
-
111
- return [
112
- // Layer 1: Bass glow - bottom
113
- {
114
- inset: 60 + bass * 90,
115
- opacity: 1,
116
- scale: 1 + bass * 0.5,
117
- background: `radial-gradient(ellipse 80% 60% at 50% 100%, hsl(${colors[0]} / ${0.4 + bass * 0.4}) 0%, transparent 70%)`,
118
- blur: 'blur-3xl',
119
- },
120
- // Layer 2: Mid glow - top
121
- {
122
- inset: 45 + mid * 75,
123
- opacity: 1,
124
- scale: 1 + mid * 0.4,
125
- background: `radial-gradient(ellipse 70% 50% at 50% 0%, hsl(${colors[1] || colors[0]} / ${0.3 + mid * 0.5}) 0%, transparent 70%)`,
126
- blur: 'blur-2xl',
127
- },
128
- // Layer 3: High glow - left
129
- {
130
- inset: 30 + high * 60,
131
- opacity: 1,
132
- scale: 1 + high * 0.3,
133
- background: `radial-gradient(ellipse 50% 80% at 0% 50%, hsl(${colors[2] || colors[0]} / ${0.3 + high * 0.4}) 0%, transparent 60%)`,
134
- blur: 'blur-2xl',
135
- },
136
- // Layer 4: High glow - right
137
- {
138
- inset: 30 + high * 60,
139
- opacity: 1,
140
- scale: 1 + high * 0.3,
141
- background: `radial-gradient(ellipse 50% 80% at 100% 50%, hsl(${colors[3] || colors[0]} / ${0.3 + high * 0.4}) 0%, transparent 60%)`,
142
- blur: 'blur-2xl',
143
- },
144
- // Layer 5: Center pulsing glow
145
- {
146
- inset: 24 + bass * 45,
147
- opacity: 1,
148
- scale: 1 + bass * 0.2,
149
- background: `radial-gradient(circle at 50% 50%, hsl(${colors[0]} / ${0.2 + bass * 0.3}) 0%, hsl(${colors[1] || colors[0]} / ${0.1 + mid * 0.2}) 40%, transparent 70%)`,
150
- blur: 'blur-xl',
151
- animation: 'glow-breathe 2s ease-in-out infinite',
152
- },
153
- ];
154
- }
155
-
156
- /**
157
- * Calculate orb positions and properties - highly reactive
158
- */
159
- export function calculateOrbs(
160
- levels: AudioLevels,
161
- config: EffectConfig,
162
- colors: string[],
163
- baseSize: number = 50
164
- ) {
165
- const { bass, mid, high, overall } = levels;
166
- const size = baseSize * 3;
167
-
168
- // Dynamic position offsets
169
- const bassMove = bass * 30;
170
- const midMove = mid * 25;
171
- const highMove = high * 20;
172
-
173
- return [
174
- // Bass orb - top left, big pulses
175
- {
176
- x: -40 + bassMove,
177
- y: -40 - bassMove * 0.5,
178
- size: size * (1 + bass * 1.2),
179
- color: colors[0],
180
- opacity: 0.5 + bass * 0.5,
181
- scale: 1 + bass * 0.6,
182
- },
183
- // Mid orb - top right
184
- {
185
- x: 130 - midMove * 0.5,
186
- y: -30 + midMove,
187
- size: size * (0.9 + mid * 1.0),
188
- color: colors[1] || colors[0],
189
- opacity: 0.5 + mid * 0.5,
190
- scale: 1 + mid * 0.5,
191
- },
192
- // High orb - bottom right
193
- {
194
- x: 140 + highMove * 0.3,
195
- y: 120 - highMove,
196
- size: size * (0.8 + high * 0.8),
197
- color: colors[2] || colors[0],
198
- opacity: 0.4 + high * 0.6,
199
- scale: 1 + high * 0.45,
200
- },
201
- // Mid orb 2 - bottom left
202
- {
203
- x: -30 - midMove * 0.4,
204
- y: 130 + midMove * 0.3,
205
- size: size * (0.9 + mid * 0.9),
206
- color: colors[3] || colors[0],
207
- opacity: 0.45 + mid * 0.55,
208
- scale: 1 + mid * 0.5,
209
- },
210
- // Center overall orb
211
- {
212
- x: 50,
213
- y: 50,
214
- size: size * (0.6 + overall * 1.5),
215
- color: colors[0],
216
- opacity: 0.3 + overall * 0.5,
217
- scale: 1 + overall * 0.7,
218
- },
219
- ];
220
- }
221
-
222
- /**
223
- * Calculate mesh gradient positions - dynamic and reactive
224
- */
225
- export function calculateMeshGradients(
226
- levels: AudioLevels,
227
- config: EffectConfig,
228
- colors: string[]
229
- ) {
230
- const { bass, mid, high, overall } = levels;
231
-
232
- // More aggressive offsets for visible movement
233
- const bassOffset = bass * 40;
234
- const midOffset = mid * 30;
235
- const highOffset = high * 25;
236
-
237
- return [
238
- // Large bass blob - top right, pulses hard
239
- {
240
- width: `${200 + bass * 150}%`,
241
- height: `${200 + bass * 150}%`,
242
- top: `${-80 + bassOffset}%`,
243
- right: `${-80 - bassOffset}%`,
244
- color: colors[0],
245
- opacity: 0.4 + bass * 0.6,
246
- scale: 1 + bass * 0.5,
247
- rotation: bass * 45,
248
- blur: 'blur-2xl',
249
- },
250
- // Mid blob - bottom left
251
- {
252
- width: `${180 + mid * 120}%`,
253
- height: `${180 + mid * 120}%`,
254
- bottom: `${-60 + midOffset}%`,
255
- left: `${-60 - midOffset}%`,
256
- color: colors[1] || colors[0],
257
- opacity: 0.4 + mid * 0.6,
258
- scale: 1 + mid * 0.4,
259
- rotation: -mid * 40,
260
- blur: 'blur-2xl',
261
- },
262
- // High blob - bottom right
263
- {
264
- width: `${140 + high * 100}%`,
265
- height: `${140 + high * 100}%`,
266
- top: `${70 - highOffset}%`,
267
- right: `${-50 + highOffset}%`,
268
- color: colors[2] || colors[0],
269
- opacity: 0.35 + high * 0.65,
270
- scale: 1 + high * 0.35,
271
- rotation: high * 35,
272
- blur: 'blur-xl',
273
- },
274
- // Extra bass reactive blob - top left
275
- {
276
- width: `${160 + bass * 140}%`,
277
- height: `${160 + bass * 140}%`,
278
- top: `${-60 - bassOffset * 0.8}%`,
279
- left: `${-60 + bassOffset * 0.8}%`,
280
- color: colors[3] || colors[1] || colors[0],
281
- opacity: 0.35 + bass * 0.65,
282
- scale: 1 + bass * 0.55,
283
- rotation: -bass * 50,
284
- blur: 'blur-2xl',
285
- },
286
- // Center glow - pulses with overall
287
- {
288
- width: `${80 + overall * 150}%`,
289
- height: `${80 + overall * 150}%`,
290
- top: '50%',
291
- left: '50%',
292
- color: colors[0],
293
- opacity: 0.3 + overall * 0.5,
294
- scale: 1 + overall * 0.4,
295
- rotation: 0,
296
- isCenter: true,
297
- blur: 'blur-3xl',
298
- },
299
- ];
300
- }
301
-
302
- /**
303
- * Calculate spotlight effect properties - highly reactive
304
- */
305
- export function calculateSpotlight(
306
- levels: AudioLevels,
307
- config: EffectConfig,
308
- colors: string[],
309
- rotation: number
310
- ) {
311
- const { bass, mid, high, overall } = levels;
312
-
313
- return {
314
- // Rotation speed increases with mid frequencies
315
- rotation: rotation + mid * 180,
316
- // Border expands with bass
317
- inset: 12 + bass * 30,
318
- // Color intensities react to different frequencies
319
- colors: colors.map((c, i) => ({
320
- color: c,
321
- opacity: i === 0
322
- ? 0.3 + bass * 0.7
323
- : i === 1
324
- ? 0.3 + mid * 0.7
325
- : 0.3 + high * 0.7,
326
- })),
327
- // Pulse glow - big and reactive
328
- pulseInset: 24 + bass * 50,
329
- pulseOpacity: 0.3 + bass * 0.7,
330
- pulseScale: 1 + bass * 0.4,
331
- // Extra glow ring
332
- ringOpacity: 0.2 + overall * 0.6,
333
- ringScale: 1 + overall * 0.3,
334
- };
335
- }
336
-
337
- /**
338
- * CSS for effect animations - can be injected once
339
- */
340
- export const EFFECT_ANIMATIONS = `
341
- @keyframes spotlight-spin {
342
- 0% { transform: rotate(0deg); }
343
- 100% { transform: rotate(360deg); }
344
- }
345
-
346
- @keyframes orb-float-1 {
347
- 0%, 100% { transform: translate(-50%, -50%) translateY(0); }
348
- 50% { transform: translate(-50%, -50%) translateY(-15px); }
349
- }
350
-
351
- @keyframes orb-float-2 {
352
- 0%, 100% { transform: translate(-50%, -50%) translateX(0); }
353
- 50% { transform: translate(-50%, -50%) translateX(15px); }
354
- }
355
-
356
- @keyframes orb-float-3 {
357
- 0%, 100% { transform: translate(-50%, -50%) translate(0, 0); }
358
- 33% { transform: translate(-50%, -50%) translate(10px, -10px); }
359
- 66% { transform: translate(-50%, -50%) translate(-10px, 10px); }
360
- }
361
-
362
- @keyframes orb-float-4 {
363
- 0%, 100% { transform: translate(-50%, -50%) translate(0, 0); }
364
- 50% { transform: translate(-50%, -50%) translate(-15px, -10px); }
365
- }
366
-
367
- @keyframes mesh-float-1 {
368
- 0%, 100% { transform: translate(0, 0) scale(1); }
369
- 25% { transform: translate(-5%, 10%) scale(1.05); }
370
- 50% { transform: translate(5%, 5%) scale(0.95); }
371
- 75% { transform: translate(-3%, -5%) scale(1.02); }
372
- }
373
-
374
- @keyframes mesh-float-2 {
375
- 0%, 100% { transform: translate(0, 0) scale(1); }
376
- 33% { transform: translate(8%, -8%) scale(1.08); }
377
- 66% { transform: translate(-6%, 6%) scale(0.92); }
378
- }
379
-
380
- @keyframes mesh-float-3 {
381
- 0%, 100% { transform: translate(0, 0) scale(1); }
382
- 50% { transform: translate(10%, 10%) scale(1.1); }
383
- }
384
-
385
- @keyframes mesh-float-4 {
386
- 0%, 100% { transform: translate(0, 0) scale(1) rotate(0deg); }
387
- 25% { transform: translate(10%, -5%) scale(1.1) rotate(5deg); }
388
- 50% { transform: translate(-5%, 10%) scale(0.95) rotate(-5deg); }
389
- 75% { transform: translate(-10%, -10%) scale(1.05) rotate(3deg); }
390
- }
391
-
392
- @keyframes mesh-pulse {
393
- 0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.3; }
394
- 50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.5; }
395
- }
396
-
397
- @keyframes glow-breathe {
398
- 0%, 100% { opacity: 0.6; transform: scale(1); }
399
- 50% { opacity: 1; transform: scale(1.05); }
400
- }
401
-
402
- @keyframes glow-rotate {
403
- 0% { transform: rotate(0deg); }
404
- 100% { transform: rotate(360deg); }
405
- }
406
-
407
- @keyframes sparkle-move {
408
- 0% { opacity: 0; transform: scale(0.8); }
409
- 50% { opacity: 1; }
410
- 100% { opacity: 0; transform: scale(1.2); }
411
- }
412
- `;