After Width: | Height: | Size: 313 B |
After Width: | Height: | Size: 313 B |
After Width: | Height: | Size: 917 B |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 264 B After Width: | Height: | Size: 272 B |
Before Width: | Height: | Size: 303 B After Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 341 B |
After Width: | Height: | Size: 1.8 KiB |
@ -0,0 +1,114 @@
|
||||
'use client';
|
||||
|
||||
import Image from 'next/image';
|
||||
|
||||
import { secondToDate } from '@/utils/timeFormat';
|
||||
|
||||
import { AutoScrollContainer } from '@/components';
|
||||
|
||||
interface Props {
|
||||
audio: SongInfo | null;
|
||||
playStatus: boolean;
|
||||
onPlay: () => void;
|
||||
onPrev: () => void;
|
||||
onNext: () => void;
|
||||
onChangeProgress: (value: string) => void;
|
||||
trackProgress: number;
|
||||
duration: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function AudioPlayer({
|
||||
audio,
|
||||
playStatus,
|
||||
onPlay,
|
||||
onPrev,
|
||||
onNext,
|
||||
onChangeProgress,
|
||||
trackProgress,
|
||||
duration,
|
||||
className,
|
||||
}: Props) {
|
||||
const currentPercentage = duration ? `${(trackProgress / duration) * 100}%` : '0%';
|
||||
const trackStyling: string = `
|
||||
-webkit-gradient(linear, 0% 0%, 100% 0%, color-stop(${currentPercentage}, rgb(24,24,24)), color-stop(${currentPercentage}, rgba(0,0,0,0.1)))
|
||||
`; // 进度条样式
|
||||
|
||||
return (
|
||||
<div className={`flex flex-row w-[1200px] pt-[29px] ${className}`}>
|
||||
{/* 专辑封面 */}
|
||||
<div className="w-[72px] h-[72px] rounded-[3px] bg-[#000]">
|
||||
{audio?.pic && (
|
||||
<Image src={audio?.pic} alt="music" width={72} height={72} unoptimized className="w-full h-full" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* title & author */}
|
||||
<div className="h-full ml-[27px] mr-[44px] py-[14px]">
|
||||
<AutoScrollContainer auto hover width="140px" speed={50}>
|
||||
<div className="w-auto h-auto">
|
||||
<p className="text-[17px] leading-[23.8px] text-[rgba(0,0,0,0.95)]">{audio?.title}</p>
|
||||
<p className="text-[13px] leading-[18.2px] text-[rgba(0,0,0,0.7)]">{`${audio?.artist}/${audio?.album}`}</p>
|
||||
</div>
|
||||
</AutoScrollContainer>
|
||||
</div>
|
||||
|
||||
{/* progress bar */}
|
||||
<div className="h-full mt-[29px]">
|
||||
{/* bar */}
|
||||
<div className="h-full cursor-pointer">
|
||||
<input
|
||||
type="range"
|
||||
value={trackProgress}
|
||||
step="1"
|
||||
min="0"
|
||||
max={duration ? duration : `${duration}`}
|
||||
className="w-[600px] h-[3px]"
|
||||
onChange={(e) => onChangeProgress(e.target.value)}
|
||||
style={{ background: trackStyling }}
|
||||
/>
|
||||
</div>
|
||||
{/* time */}
|
||||
<p className="texe-[12px] leading[16.8px]">
|
||||
<span>{`${secondToDate(trackProgress)}`}</span>
|
||||
<span className="text-[rgba(0,0,0,0.4)]">{` /${secondToDate(duration)}`}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* control */}
|
||||
<div className="flex flex-row items-center">
|
||||
<button>
|
||||
{/* 随机播放 */}
|
||||
<Image
|
||||
src={'/img/audio-player/random.svg'}
|
||||
alt="random"
|
||||
width={28}
|
||||
height={28}
|
||||
className="ml-[55px] mr-[60px]"
|
||||
/>
|
||||
</button>
|
||||
{/* 上一首 */}
|
||||
<button onClick={onPrev}>
|
||||
<Image src={'/img/audio-player/next.svg'} alt="pre" width={28} height={28} className="rotate-180" />
|
||||
</button>
|
||||
{/* 播放/暂停 */}
|
||||
<button
|
||||
className="flex justify-center items-center w-[54px] h-[54px] mx-[35px] rounded-[50%] bg-[rgba(180,67,67,1)] overflow-hidden"
|
||||
onClick={onPlay}
|
||||
>
|
||||
{/* <Image src={'/img/audio-player/play.svg'} alt="play" width={28} height={28} /> */}
|
||||
<Image
|
||||
src={playStatus ? '/img/audio-player/pause.svg' : '/img/audio-player/play.svg'}
|
||||
alt="pause"
|
||||
width={28}
|
||||
height={28}
|
||||
/>
|
||||
</button>
|
||||
{/* 下一首 */}
|
||||
<button onClick={onNext}>
|
||||
<Image src={'/img/audio-player/next.svg'} alt="next" width={28} height={28} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
export const secondToDate: (v: number) => string = (second) => {
|
||||
const hourNum = Math.floor(second / 3600);
|
||||
const minuteNum = Math.floor((second / 60) % 60);
|
||||
const secondNum = Math.floor(second % 60);
|
||||
|
||||
const h = hourNum ? `${hourNum}:` : '';
|
||||
const m = minuteNum ? `${unitAddZero(minuteNum)}:` : `00:`;
|
||||
const s = unitAddZero(secondNum);
|
||||
|
||||
return `${h}${m}${s}`;
|
||||
};
|
||||
|
||||
// 格式化个位数
|
||||
const unitAddZero: (v: number) => string = (v) => {
|
||||
return v < 10 ? `0${v}` : `${v}`;
|
||||
};
|