veza/apps/web/src/components/player/VisualizerSettingsModal.tsx

88 lines
3.4 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { X, Activity } from 'lucide-react';
import { useAudio, VisualizerSettings } from '../../context/AudioContext';
interface VisualizerSettingsModalProps {
onClose: () => void;
}
export const VisualizerSettingsModal: React.FC<
VisualizerSettingsModalProps
> = ({ onClose }) => {
const { visualizerSettings, setVisualizerSettings } = useAudio();
const updateSetting = (key: keyof VisualizerSettings, value: any) => {
setVisualizerSettings({ ...visualizerSettings, [key]: value });
};
const colors = ['#66FCF1', '#8A7EA4', '#36E5D1', '#E4B314', '#E63946'];
return (
<div className="absolute bottom-20 right-0 md:right-auto md:left-1/2 md:-translate-x-1/2 w-72 bg-kodo-graphite border border-kodo-steel rounded-xl shadow-2xl z-50 animate-fadeIn overflow-hidden">
<div className="p-4 border-b border-kodo-steel bg-kodo-ink flex justify-between items-center">
<h3 className="font-bold text-white flex items-center gap-2 text-sm">
aesthetic-improvements: reduce decorative cyan in player, library, and views (80/20 rule, batch 12) - Player: VisualizerSettingsModal decorative icon (1 instance) - Library: QueueView decorative artist text, AutoMetadataDetectionModal decorative icon and loading spinner border and fileName text and detected key text, SaveQueueAsPlaylistModal decorative icon, EditPlaylistModal decorative icon, PlaylistsView loading spinner, CreatePlaylistModal decorative icon (7 instances) - Views: StudioView decorative icon, FileDetailsView decorative icon, GearView decorative icons and order number text, ProfileView loading spinner and social icons, AnalyticsView loading spinner and decorative chart legend dot and chart bars and device icon and revenue text, DiscoverView loading spinner and decorative icon and weekly mix text, FileManagerView decorative music icons (14 instances) - Total: ~22 files, ~22 instances replaced - Preserved: Active/selected states (LyricsPanel autoScroll active state, VisualizerSettingsModal selected mode, PlayerControls shuffle/repeatMode/showVisualizer active states, MiniPlayer isQueueOpen active state, AddToPlaylistModal selected playlist, PlaylistDetailView dragged item, StudioView active tab, SearchBar focused state, CheckoutView checkbox accents - focus/interaction, SearchPageView radio button accent - focus/interaction, FileManagerView selected files checkmarks - active states, ProfileView social links - functional links, LiveView links - functional links), primary actions, design system variants - Action 11.3.1.3 in progress (twelfth batch: player, library, and views components)
2026-01-16 10:30:07 +00:00
<Activity className="w-4 h-4 text-kodo-steel" /> Visualizer
</h3>
<button onClick={onClose}>
<X className="w-4 h-4 text-kodo-content-dim hover:text-white" />
</button>
</div>
<div className="p-6 space-y-6">
{/* Mode */}
<div>
<label className="block text-xs font-bold text-kodo-content-dim uppercase mb-2">
Display Mode
</label>
<div className="grid grid-cols-2 gap-2">
{['waveform', 'spectrogram', 'bars', 'off'].map((mode) => (
<button
key={mode}
onClick={() => updateSetting('mode', mode)}
className={`px-2 py-1.5 rounded text-xs font-bold capitalize transition-all border ${visualizerSettings.mode === mode ? 'bg-kodo-cyan/10 border-kodo-cyan text-kodo-cyan' : 'bg-kodo-slate border-transparent text-kodo-content-dim hover:text-white'}`}
>
{mode}
</button>
))}
</div>
</div>
{/* Sensitivity */}
<div>
<div className="flex justify-between text-xs text-kodo-content-dim mb-1">
<span>Sensitivity</span>
<span>{visualizerSettings.sensitivity}%</span>
</div>
<input
type="range"
min="0"
max="100"
value={visualizerSettings.sensitivity}
onChange={(e) =>
updateSetting('sensitivity', Number(e.target.value))
}
className="w-full h-1 bg-kodo-steel rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:bg-kodo-cyan [&::-webkit-slider-thumb]:rounded-full"
/>
</div>
{/* Color */}
<div>
<label className="block text-xs font-bold text-kodo-content-dim uppercase mb-2">
Accent Color
</label>
<div className="flex gap-4">
{colors.map((c) => (
<div
key={c}
onClick={() => updateSetting('color', c)}
className={`w-6 h-6 rounded-full cursor-pointer transition-transform hover:scale-110 ${visualizerSettings.color === c ? 'ring-2 ring-white ring-offset-2 ring-offset-kodo-graphite' : ''}`}
style={{ backgroundColor: c }}
></div>
))}
</div>
</div>
</div>
</div>
);
};