nex_music/components/Controls.tsx

127 lines
4.4 KiB
TypeScript

import React from 'react';
import { Play, Pause, SkipBack, SkipForward, Volume2, Upload, Shuffle, Repeat } from 'lucide-react';
import { formatTime } from '../utils/parsers';
import { PlaybackMode } from '../types';
interface ControlsProps {
isPlaying: boolean;
currentTime: number;
duration: number;
onPlayPause: () => void;
onSeek: (time: number) => void;
onNext: () => void;
onPrev: () => void;
title: string;
artist: string;
onUploadClick: () => void;
playbackMode: PlaybackMode;
onToggleMode: () => void;
}
const Controls: React.FC<ControlsProps> = ({
isPlaying,
currentTime,
duration,
onPlayPause,
onSeek,
onNext,
onPrev,
title,
artist,
onUploadClick,
playbackMode,
onToggleMode
}) => {
const progressPercent = duration ? (currentTime / duration) * 100 : 0;
const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {
onSeek(Number(e.target.value));
};
return (
<div className="w-full glass-panel border-t border-white/10 p-6 flex flex-col gap-4 relative z-40">
{/* Progress Bar */}
<div className="flex items-center gap-3 text-xs font-mono text-neutral-400">
<span className="w-10 text-right">{formatTime(currentTime)}</span>
<div className="flex-1 relative h-1.5 bg-neutral-800 rounded-full group cursor-pointer">
<div
className="absolute top-0 left-0 h-full bg-amber-500 rounded-full"
style={{ width: `${progressPercent}%` }}
></div>
<input
type="range"
min={0}
max={duration || 100}
value={currentTime}
onChange={handleSeek}
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
/>
</div>
<span className="w-10">{formatTime(duration)}</span>
</div>
<div className="flex items-center justify-between">
{/* Track Info */}
<div className="hidden md:flex flex-col w-1/3">
<h3 className="text-white font-bold truncate">{title}</h3>
<p className="text-neutral-400 text-sm truncate">{artist}</p>
</div>
{/* Main Controls */}
<div className="flex items-center justify-center gap-6 w-full md:w-1/3">
<button
onClick={onToggleMode}
className={`transition-colors ${playbackMode === 'SHUFFLE' ? 'text-amber-500' : 'text-neutral-600 hover:text-neutral-400'}`}
title={playbackMode === 'SHUFFLE' ? "Shuffle On" : "Sequential Play"}
>
{playbackMode === 'SHUFFLE' ? <Shuffle size={20} /> : <Repeat size={20} />}
</button>
<button onClick={onPrev} className="text-neutral-400 hover:text-white transition-colors">
<SkipBack size={24} />
</button>
<button
onClick={onPlayPause}
className="w-14 h-14 rounded-full bg-white text-black flex items-center justify-center hover:scale-105 transition-transform shadow-lg shadow-white/10"
>
{isPlaying ? (
<Pause fill="currentColor" size={24} />
) : (
<Play fill="currentColor" size={24} className="ml-1" />
)}
</button>
<button onClick={onNext} className="text-neutral-400 hover:text-white transition-colors">
<SkipForward size={24} />
</button>
{/* Placeholder for symmetry or maybe Like button later */}
<div className="w-5"></div>
</div>
{/* Secondary Actions */}
<div className="flex items-center justify-end gap-4 w-1/3">
<div className="hidden sm:flex items-center gap-2 text-neutral-400">
<Volume2 size={20} />
<div className="w-20 h-1 bg-neutral-700 rounded-full overflow-hidden">
<div className="w-[70%] h-full bg-neutral-400"></div>
</div>
</div>
<div className="h-6 w-[1px] bg-neutral-700 hidden sm:block"></div>
<button
onClick={onUploadClick}
className="flex items-center gap-2 bg-neutral-800 hover:bg-neutral-700 text-white px-4 py-2 rounded-full text-xs font-medium transition-colors border border-neutral-700"
>
<Upload size={14} />
<span className="hidden sm:inline">Load / Settings</span>
</button>
</div>
</div>
</div>
);
};
export default Controls;