Changes
This commit is contained in:
+64
-13
@@ -1,9 +1,12 @@
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Play, Pause, Volume2, Radio, Search, Loader2, ChevronDown, Link2, SkipBack, SkipForward, Zap } from 'lucide-react';
|
||||
import { Play, Pause, Volume2, Radio, Search, Loader2, ChevronDown, Link2, SkipBack, SkipForward, Zap, Settings, Youtube, Music2 } from 'lucide-react';
|
||||
import { useSettings } from '@/contexts/SettingsContext';
|
||||
import { useMusic, Station } from '@/contexts/MusicContext';
|
||||
|
||||
import { ApiKeySettings } from '@/components/music/ApiKeySettings';
|
||||
import { YouTubePlayer } from '@/components/music/YouTubePlayer';
|
||||
import { SoundCloudPlayer } from '@/components/music/SoundCloudPlayer';
|
||||
import { useMusicApiKeys } from '@/hooks/useMusicApiKeys';
|
||||
const CATEGORIES = [
|
||||
{ value: '', label: 'All Genres' },
|
||||
{ value: 'pop', label: 'Pop' },
|
||||
@@ -134,9 +137,11 @@ const Music = () => {
|
||||
const [selectedCategory, setSelectedCategory] = useState('');
|
||||
const [customUrl, setCustomUrl] = useState('');
|
||||
const [customUrlError, setCustomUrlError] = useState<string | null>(null);
|
||||
const [activeTab, setActiveTab] = useState<'browse' | 'presets' | 'custom'>('browse');
|
||||
const [activeTab, setActiveTab] = useState<'browse' | 'presets' | 'custom' | 'youtube' | 'soundcloud'>('browse');
|
||||
const [filteredStations, setFilteredStations] = useState<Station[]>([]);
|
||||
const [showApiSettings, setShowApiSettings] = useState(false);
|
||||
const { playSound } = useSettings();
|
||||
const { hasYoutubeKey, hasSoundcloudKey } = useMusicApiKeys();
|
||||
|
||||
const {
|
||||
isPlaying,
|
||||
@@ -253,9 +258,34 @@ const Music = () => {
|
||||
</h1>
|
||||
|
||||
<p className="font-pixel text-foreground/80">
|
||||
Stream radio stations from around the world or add your own stream URL.
|
||||
Stream radio stations, YouTube music, or SoundCloud mixes.
|
||||
</p>
|
||||
|
||||
{/* API Settings Button */}
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
onClick={() => {
|
||||
playSound('click');
|
||||
setShowApiSettings(true);
|
||||
}}
|
||||
className={`flex items-center gap-2 px-3 py-1.5 border font-pixel text-xs transition-all ${
|
||||
hasYoutubeKey || hasSoundcloudKey
|
||||
? 'border-primary/30 text-primary/70 hover:border-primary hover:text-primary'
|
||||
: 'border-primary text-primary animate-pulse'
|
||||
}`}
|
||||
>
|
||||
<Settings size={14} />
|
||||
API Keys
|
||||
{hasYoutubeKey && hasSoundcloudKey && <span className="text-primary">●</span>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ApiKeySettings
|
||||
isOpen={showApiSettings}
|
||||
onClose={() => setShowApiSettings(false)}
|
||||
playSound={playSound}
|
||||
/>
|
||||
|
||||
{/* Now Playing */}
|
||||
{selectedStation && (
|
||||
<motion.div
|
||||
@@ -339,23 +369,28 @@ const Music = () => {
|
||||
)}
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="flex gap-2 border-b border-primary/30">
|
||||
{(['browse', 'presets', 'custom'] as const).map((tab) => (
|
||||
<div className="flex gap-1 border-b border-primary/30 overflow-x-auto pb-px">
|
||||
{([
|
||||
{ key: 'browse', label: 'Radio', icon: Radio },
|
||||
{ key: 'youtube', label: 'YouTube', icon: Youtube },
|
||||
{ key: 'soundcloud', label: 'SoundCloud', icon: Music2 },
|
||||
{ key: 'presets', label: 'Electronic', icon: Zap },
|
||||
{ key: 'custom', label: 'Custom', icon: Link2 },
|
||||
] as const).map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
key={tab.key}
|
||||
onClick={() => {
|
||||
playSound('click');
|
||||
setActiveTab(tab);
|
||||
setActiveTab(tab.key);
|
||||
}}
|
||||
className={`px-4 py-2 font-pixel text-sm transition-all ${
|
||||
activeTab === tab
|
||||
className={`px-3 py-2 font-pixel text-xs transition-all flex items-center gap-1.5 whitespace-nowrap ${
|
||||
activeTab === tab.key
|
||||
? 'text-primary border-b-2 border-primary text-glow'
|
||||
: 'text-foreground/60 hover:text-primary'
|
||||
}`}
|
||||
>
|
||||
{tab === 'browse' && 'Browse'}
|
||||
{tab === 'presets' && 'Electronic'}
|
||||
{tab === 'custom' && 'Custom URL'}
|
||||
<tab.icon size={14} />
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -487,6 +522,22 @@ const Music = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* YouTube Tab */}
|
||||
{activeTab === 'youtube' && (
|
||||
<YouTubePlayer
|
||||
playSound={playSound}
|
||||
onOpenSettings={() => setShowApiSettings(true)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* SoundCloud Tab */}
|
||||
{activeTab === 'soundcloud' && (
|
||||
<SoundCloudPlayer
|
||||
playSound={playSound}
|
||||
onOpenSettings={() => setShowApiSettings(true)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Custom URL Tab */}
|
||||
{activeTab === 'custom' && (
|
||||
<div className="space-y-4">
|
||||
|
||||
Reference in New Issue
Block a user