feat: refactor player component structure and introduce new player controls, progress, track info, and volume components
This commit is contained in:
248
src/components/player/PlayerControls.tsx
Normal file
248
src/components/player/PlayerControls.tsx
Normal file
@@ -0,0 +1,248 @@
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import type { PlayerMode, PlayerState } from '@/lib/api/services/player'
|
||||
import {
|
||||
ArrowRight,
|
||||
ArrowRightToLine,
|
||||
List,
|
||||
Pause,
|
||||
Play,
|
||||
Repeat,
|
||||
Repeat1,
|
||||
Shuffle,
|
||||
SkipBack,
|
||||
SkipForward,
|
||||
Square,
|
||||
} from 'lucide-react'
|
||||
import { memo, useMemo } from 'react'
|
||||
import { useRenderFlash } from '@/hooks/useRenderFlash'
|
||||
|
||||
interface PlayerControlsProps {
|
||||
status: PlayerState['status']
|
||||
mode: PlayerMode
|
||||
isLoading: boolean
|
||||
showPlaylistButton?: boolean
|
||||
onPlayPause: () => void
|
||||
onStop: () => void
|
||||
onPrevious: () => void
|
||||
onNext: () => void
|
||||
onModeChange: () => void
|
||||
onTogglePlaylist?: () => void
|
||||
variant?: 'normal' | 'maximized' | 'minimized'
|
||||
}
|
||||
|
||||
export const PlayerControls = memo(function PlayerControls({
|
||||
status,
|
||||
mode,
|
||||
isLoading,
|
||||
showPlaylistButton = false,
|
||||
onPlayPause,
|
||||
onStop,
|
||||
onPrevious,
|
||||
onNext,
|
||||
onModeChange,
|
||||
onTogglePlaylist,
|
||||
variant = 'normal',
|
||||
}: PlayerControlsProps) {
|
||||
const isMinimized = variant === 'minimized'
|
||||
const isMaximized = variant === 'maximized'
|
||||
const flashClass = useRenderFlash([status, mode], 'green')
|
||||
|
||||
const modeIcon = useMemo(() => {
|
||||
switch (mode) {
|
||||
case 'continuous':
|
||||
return <ArrowRight className="h-4 w-4" />
|
||||
case 'loop':
|
||||
return <Repeat className="h-4 w-4" />
|
||||
case 'loop_one':
|
||||
return <Repeat1 className="h-4 w-4" />
|
||||
case 'random':
|
||||
return <Shuffle className="h-4 w-4" />
|
||||
default:
|
||||
return <ArrowRightToLine className="h-4 w-4" />
|
||||
}
|
||||
}, [mode])
|
||||
|
||||
const modeLabel = useMemo(() =>
|
||||
mode.replace('_', ' '),
|
||||
[mode]
|
||||
)
|
||||
|
||||
if (isMinimized) {
|
||||
return (
|
||||
<div className={`${flashClass} flex items-center gap-1`}>
|
||||
{/* DEBUG: PlayerControls Minimized - GREEN FLASH */}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onPrevious}
|
||||
disabled={isLoading}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<SkipBack className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onPlayPause}
|
||||
disabled={isLoading}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
{status === 'playing' ? (
|
||||
<Pause className="h-4 w-4" />
|
||||
) : (
|
||||
<Play className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onStop}
|
||||
disabled={isLoading}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<Square className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onNext}
|
||||
disabled={isLoading}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<SkipForward className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (isMaximized) {
|
||||
return (
|
||||
<div className={flashClass}>
|
||||
{/* DEBUG: PlayerControls Maximized - GREEN FLASH */}
|
||||
{/* Large Controls */}
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<Button
|
||||
size="lg"
|
||||
variant="ghost"
|
||||
onClick={onPrevious}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<SkipBack className="h-6 w-6" />
|
||||
</Button>
|
||||
<Button
|
||||
size="lg"
|
||||
onClick={onPlayPause}
|
||||
disabled={isLoading}
|
||||
className="h-16 w-16 rounded-full"
|
||||
>
|
||||
{status === 'playing' ? (
|
||||
<Pause className="h-8 w-8" />
|
||||
) : (
|
||||
<Play className="h-8 w-8" />
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
size="lg"
|
||||
variant="ghost"
|
||||
onClick={onStop}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Square className="h-6 w-6" />
|
||||
</Button>
|
||||
<Button
|
||||
size="lg"
|
||||
variant="ghost"
|
||||
onClick={onNext}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<SkipForward className="h-6 w-6" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Secondary Controls */}
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="sm" variant="ghost" onClick={onModeChange}>
|
||||
{modeIcon}
|
||||
</Button>
|
||||
<Badge variant="secondary">{modeLabel}</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Normal variant
|
||||
return (
|
||||
<div className={flashClass}>
|
||||
{/* DEBUG: PlayerControls Normal - GREEN FLASH */}
|
||||
{/* Main Controls */}
|
||||
<div className="flex items-center justify-center gap-2 mb-4">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onModeChange}
|
||||
className="h-8 w-8 p-0"
|
||||
title={`Mode: ${modeLabel}`}
|
||||
>
|
||||
{modeIcon}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onPrevious}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<SkipBack className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={onPlayPause}
|
||||
disabled={isLoading}
|
||||
className="h-10 w-10 rounded-full"
|
||||
>
|
||||
{status === 'playing' ? (
|
||||
<Pause className="h-5 w-5" />
|
||||
) : (
|
||||
<Play className="h-5 w-5" />
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onStop}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Square className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onNext}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<SkipForward className="h-4 w-4" />
|
||||
</Button>
|
||||
{showPlaylistButton && onTogglePlaylist && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={onTogglePlaylist}
|
||||
className="h-8 w-8 p-0"
|
||||
title="Toggle Playlist"
|
||||
>
|
||||
<List className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Secondary Controls */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{modeLabel}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
Reference in New Issue
Block a user