@djangocfg/ui-nextjs 2.1.66 → 2.1.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -6
- package/src/stores/index.ts +8 -0
- package/src/stores/mediaCache.ts +474 -0
- package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +148 -0
- package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +301 -0
- package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +281 -0
- package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +328 -0
- package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +251 -0
- package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +427 -0
- package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +193 -0
- package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +146 -0
- package/src/tools/AudioPlayer/README.md +35 -11
- package/src/tools/AudioPlayer/{AudioEqualizer.tsx → components/AudioEqualizer.tsx} +29 -64
- package/src/tools/AudioPlayer/{AudioPlayer.tsx → components/AudioPlayer.tsx} +22 -14
- package/src/tools/AudioPlayer/{AudioShortcutsPopover.tsx → components/AudioShortcutsPopover.tsx} +6 -2
- package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +147 -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/{SimpleAudioPlayer.tsx → components/SimpleAudioPlayer.tsx} +12 -7
- package/src/tools/AudioPlayer/{VisualizationToggle.tsx → components/VisualizationToggle.tsx} +2 -6
- package/src/tools/AudioPlayer/components/index.ts +21 -0
- package/src/tools/AudioPlayer/context/AudioProvider.tsx +292 -0
- package/src/tools/AudioPlayer/context/index.ts +11 -0
- package/src/tools/AudioPlayer/context/selectors.ts +96 -0
- package/src/tools/AudioPlayer/hooks/index.ts +29 -0
- package/src/tools/AudioPlayer/hooks/useAudioAnalysis.ts +110 -0
- package/src/tools/AudioPlayer/{useAudioHotkeys.ts → hooks/useAudioHotkeys.ts} +11 -4
- package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +106 -0
- package/src/tools/AudioPlayer/{useAudioVisualization.tsx → hooks/useVisualization.tsx} +11 -5
- package/src/tools/AudioPlayer/index.ts +104 -49
- package/src/tools/AudioPlayer/types/audio.ts +107 -0
- package/src/tools/AudioPlayer/{types.ts → types/components.ts} +20 -84
- package/src/tools/AudioPlayer/types/effects.ts +73 -0
- package/src/tools/AudioPlayer/types/index.ts +35 -0
- package/src/tools/AudioPlayer/utils/formatTime.ts +10 -0
- package/src/tools/AudioPlayer/utils/index.ts +5 -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 +16 -3
- package/src/tools/ImageViewer/components/ImageInfo.tsx +44 -0
- package/src/tools/ImageViewer/components/ImageToolbar.tsx +150 -0
- package/src/tools/ImageViewer/components/ImageViewer.tsx +235 -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 +153 -0
- package/src/tools/ImageViewer/hooks/useImageTransform.ts +101 -0
- package/src/tools/ImageViewer/index.ts +47 -3
- package/src/tools/ImageViewer/types.ts +75 -0
- package/src/tools/ImageViewer/utils/constants.ts +59 -0
- package/src/tools/ImageViewer/utils/index.ts +16 -0
- package/src/tools/ImageViewer/utils/lqip.ts +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 +26 -10
- package/src/tools/VideoPlayer/{VideoControls.tsx → components/VideoControls.tsx} +8 -9
- package/src/tools/VideoPlayer/{VideoErrorFallback.tsx → components/VideoErrorFallback.tsx} +2 -2
- package/src/tools/VideoPlayer/{VideoPlayer.tsx → components/VideoPlayer.tsx} +4 -5
- 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 +9 -0
- package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +109 -0
- package/src/tools/VideoPlayer/index.ts +29 -20
- package/src/tools/VideoPlayer/providers/StreamProvider.tsx +118 -28
- package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +89 -11
- 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/fileSource.ts +78 -0
- package/src/tools/VideoPlayer/utils/index.ts +11 -0
- package/src/tools/VideoPlayer/utils/resolvers.ts +75 -0
- package/src/tools/index.ts +10 -0
- package/src/tools/AudioPlayer/AudioReactiveCover.tsx +0 -389
- package/src/tools/AudioPlayer/context.tsx +0 -426
- package/src/tools/ImageViewer/ImageViewer.tsx +0 -416
- package/src/tools/VideoPlayer/VideoPlayerContext.tsx +0 -125
- package/src/tools/VideoPlayer/types.ts +0 -367
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
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';
|
|
@@ -37,13 +37,13 @@ import { useRef, type ReactNode } from 'react';
|
|
|
37
37
|
import { Music } from 'lucide-react';
|
|
38
38
|
import { cn } from '@djangocfg/ui-core';
|
|
39
39
|
|
|
40
|
-
import { AudioProvider } from '
|
|
40
|
+
import { AudioProvider } from '../context';
|
|
41
41
|
import { AudioPlayer } from './AudioPlayer';
|
|
42
|
-
import { AudioReactiveCover } from './
|
|
43
|
-
import { VisualizationProvider,
|
|
44
|
-
import type { WaveformOptions, EqualizerOptions } from '
|
|
45
|
-
import type { EffectIntensity, EffectColorScheme } from '
|
|
46
|
-
import type { VisualizationVariant } from '
|
|
42
|
+
import { AudioReactiveCover } from './ReactiveCover';
|
|
43
|
+
import { VisualizationProvider, useVisualization } from '../hooks';
|
|
44
|
+
import type { WaveformOptions, EqualizerOptions } from '../types';
|
|
45
|
+
import type { EffectIntensity, EffectColorScheme } from '../effects';
|
|
46
|
+
import type { VisualizationVariant } from '../hooks';
|
|
47
47
|
|
|
48
48
|
// =============================================================================
|
|
49
49
|
// TYPES
|
|
@@ -77,6 +77,9 @@ export interface SimpleAudioPlayerProps {
|
|
|
77
77
|
/** Show volume control */
|
|
78
78
|
showVolume?: boolean;
|
|
79
79
|
|
|
80
|
+
/** Show loop/repeat button */
|
|
81
|
+
showLoop?: boolean;
|
|
82
|
+
|
|
80
83
|
/** Enable audio-reactive cover effects */
|
|
81
84
|
reactiveCover?: boolean;
|
|
82
85
|
|
|
@@ -137,6 +140,7 @@ function SimpleAudioPlayerContent({
|
|
|
137
140
|
showEqualizer = false,
|
|
138
141
|
showTimer = true,
|
|
139
142
|
showVolume = true,
|
|
143
|
+
showLoop = true,
|
|
140
144
|
reactiveCover = true,
|
|
141
145
|
variant,
|
|
142
146
|
intensity,
|
|
@@ -148,7 +152,7 @@ function SimpleAudioPlayerContent({
|
|
|
148
152
|
className,
|
|
149
153
|
}: SimpleAudioPlayerProps) {
|
|
150
154
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
151
|
-
const { settings: vizSettings, nextVariant } =
|
|
155
|
+
const { settings: vizSettings, nextVariant } = useVisualization();
|
|
152
156
|
|
|
153
157
|
// Determine effective variant (from props or localStorage settings)
|
|
154
158
|
const effectiveVariant = variant ?? (vizSettings.variant !== 'none' ? vizSettings.variant : 'spotlight');
|
|
@@ -263,6 +267,7 @@ function SimpleAudioPlayerContent({
|
|
|
263
267
|
showEqualizer={showEqualizer}
|
|
264
268
|
showTimer={showTimer}
|
|
265
269
|
showVolume={showVolume}
|
|
270
|
+
showLoop={showLoop}
|
|
266
271
|
equalizerOptions={equalizerOptions}
|
|
267
272
|
className="border-0 bg-transparent"
|
|
268
273
|
/>
|
package/src/tools/AudioPlayer/{VisualizationToggle.tsx → components/VisualizationToggle.tsx}
RENAMED
|
@@ -9,11 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { Sparkles } from 'lucide-react';
|
|
11
11
|
import { Button, cn } from '@djangocfg/ui-nextjs';
|
|
12
|
-
import {
|
|
13
|
-
useAudioVisualization,
|
|
14
|
-
VARIANT_INFO,
|
|
15
|
-
type VisualizationVariant,
|
|
16
|
-
} from './useAudioVisualization';
|
|
12
|
+
import { useVisualization, VARIANT_INFO } from '../hooks';
|
|
17
13
|
|
|
18
14
|
// =============================================================================
|
|
19
15
|
// TYPES
|
|
@@ -34,7 +30,7 @@ export function VisualizationToggle({
|
|
|
34
30
|
compact = false,
|
|
35
31
|
className,
|
|
36
32
|
}: VisualizationToggleProps) {
|
|
37
|
-
const { settings, nextVariant } =
|
|
33
|
+
const { settings, nextVariant } = useVisualization();
|
|
38
34
|
|
|
39
35
|
const currentInfo = VARIANT_INFO[settings.variant];
|
|
40
36
|
const isEnabled = settings.variant !== 'none';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AudioPlayer components - Public API
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Main components
|
|
6
|
+
export { AudioPlayer } from './AudioPlayer';
|
|
7
|
+
export { SimpleAudioPlayer, type SimpleAudioPlayerProps } from './SimpleAudioPlayer';
|
|
8
|
+
export { AudioEqualizer } from './AudioEqualizer';
|
|
9
|
+
export { AudioShortcutsPopover } from './AudioShortcutsPopover';
|
|
10
|
+
export { VisualizationToggle, type VisualizationToggleProps } from './VisualizationToggle';
|
|
11
|
+
|
|
12
|
+
// ReactiveCover
|
|
13
|
+
export {
|
|
14
|
+
AudioReactiveCover,
|
|
15
|
+
type AudioReactiveCoverProps,
|
|
16
|
+
GlowEffect,
|
|
17
|
+
OrbsEffect,
|
|
18
|
+
SpotlightEffect,
|
|
19
|
+
MeshEffect,
|
|
20
|
+
type GlowEffectData,
|
|
21
|
+
} from './ReactiveCover';
|