feat(component): Single Card.

mack-mac
mackt 8 months ago
parent 4364bdf175
commit 2d24ab3993

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@ -11,15 +11,23 @@ import PlayerControl from './PlayerControl';
import useAudioStore from '@/store/audio'; import useAudioStore from '@/store/audio';
export default function AudioPlayer({ className }: { className?: string }) { export default function AudioPlayer({
const { audioId, order, playQueue, switchSongByDiff, setOrder } = useAudioStore( className,
onSwitchShowCard,
}: {
className?: string;
onSwitchShowCard: () => void;
}) {
const { audioId, order, playQueue, showCard, switchSongByDiff, setOrder, setShowCard } = useAudioStore(
useShallow((state) => { useShallow((state) => {
return { return {
audioId: state.audioId, audioId: state.audioId,
order: state.order, order: state.order,
playQueue: state.playQueue, playQueue: state.playQueue,
showCard: state.showCard,
setOrder: state.setOrder, setOrder: state.setOrder,
switchSongByDiff: state.switchSongByDiff, switchSongByDiff: state.switchSongByDiff,
setShowCard: state.setShowCard,
}; };
}), }),
); );
@ -127,6 +135,7 @@ export default function AudioPlayer({ className }: { className?: string }) {
order={order} order={order}
audio={audio} audio={audio}
duration={duration} duration={duration}
showCard={showCard}
onPlay={handlePlay} onPlay={handlePlay}
onPrev={() => handleSwitchAudio(-1)} onPrev={() => handleSwitchAudio(-1)}
onNext={() => handleSwitchAudio(1)} onNext={() => handleSwitchAudio(1)}
@ -134,6 +143,7 @@ export default function AudioPlayer({ className }: { className?: string }) {
className={className} className={className}
trackProgress={trackProgress} trackProgress={trackProgress}
onChangeProgress={handleChangeProgress} onChangeProgress={handleChangeProgress}
onSwitchShowCard={onSwitchShowCard}
/> />
); );
} }

@ -3,12 +3,32 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useShallow } from 'zustand/react/shallow';
import Player from './Player'; import Player from './Player';
import PlayerCard from './PlayerCard';
// import { debounce } from 'lodash'; import useAudioStore from '@/store/audio';
const PlayerBar = ({ className }: { className?: string }) => { const PlayerBar = ({ className }: { className?: string }) => {
const { audioId, order, playQueue, showCard, switchSongByDiff, setOrder, setShowCard } = useAudioStore(
useShallow((state) => {
return {
audioId: state.audioId,
order: state.order,
playQueue: state.playQueue,
showCard: state.showCard,
setOrder: state.setOrder,
switchSongByDiff: state.switchSongByDiff,
setShowCard: state.setShowCard,
};
}),
);
const handleSwitchShowCard = () => {
setShowCard(!showCard);
};
// let oldScrollY: number = 0; // let oldScrollY: number = 0;
// function handleScroll() { // function handleScroll() {
// if (window.scrollY > oldScrollY) { // if (window.scrollY > oldScrollY) {
@ -23,6 +43,13 @@ const PlayerBar = ({ className }: { className?: string }) => {
// oldScrollY = window.scrollY; // oldScrollY = window.scrollY;
// } // }
useEffect(() => {
// window.addEventListener('scroll', handleScroll);
// return () => {
// window.removeEventListener('scroll', handleScroll);
// };
}, []);
useEffect(() => { useEffect(() => {
// window.addEventListener('scroll', handleScroll); // window.addEventListener('scroll', handleScroll);
// return () => { // return () => {
@ -42,9 +69,12 @@ const PlayerBar = ({ className }: { className?: string }) => {
className={`fixed w-[100vw] h-[130px] bg-[#fff] shadow-lg shadow-black-[0_0_10px] z-10 ${className}`} className={`fixed w-[100vw] h-[130px] bg-[#fff] shadow-lg shadow-black-[0_0_10px] z-10 ${className}`}
style={{ bottom: 0 }} style={{ bottom: 0 }}
> >
<div className="w-[1200px] h-full m-auto"> {/* 播放器 */}
<Player className="m-auto" /> <div className="fixed bottom-0 w-[100vw] h-[130px] m-auto bg-[#fff] z-10">
<Player className="m-auto" onSwitchShowCard={handleSwitchShowCard} />
</div> </div>
{/* 单曲卡片 */}
<PlayerCard show={showCard} />
</div> </div>
); );
}; };

@ -0,0 +1,82 @@
import Image from 'next/image';
import { useShallow } from 'zustand/react/shallow';
import styles from './index.module.css';
import { SongCardList } from '@/components';
import useAudioStore from '@/store/audio';
interface Prop {
// onClose: () => void;
show: boolean;
className?: string;
}
export default function PlayerCard({ show, className }: Prop) {
const { audioId, playQueue } = useAudioStore(
useShallow((state) => {
return {
audioId: state.audioId,
playQueue: state.playQueue,
};
}),
);
const miniClass = 'w-100vw translate-y-100vh'; // 缩小时的样式
const largeClass = 'w-[100vw] translate-y-[-130px]'; // 放大后的样式
const audioInfo = playQueue.find((item) => item.id === audioId);
console.log(audioInfo);
return (
<div
className={`fixed left-0 bottom-0 w-[100vw] h-[calc(100vh_-_230px)] pt-[68px] bg-[#fff] transition-all duration-300 ${show ? largeClass : miniClass} ${className}`}
>
<div className="flex justify-between w-[1200px] mx-auto">
{/* 单曲信息 */}
<div>
{/* 专辑封面 */}
{/* 阴影 */}
<div className="relative w-[340px] h-[246px]">
<div
className={`absolute left-0 bottom-0 w-[230px] h-[230px] rounded-[3px] bg-[rgba(0, 0, 0, 0.08)] ${styles.album_shoadow}`}
style={{
background: 'rgba(0, 0, 0, 0.08)',
boxShadow: '27px 10px 30px -12px rgba(0, 0, 0, 0.25)',
borderRadius: '3px',
}}
/>
{audioInfo?.pic && (
<Image
width={246}
height={246}
unoptimized
src={audioInfo.pic}
alt="pic"
className="absolute left-[16px] rounded-[3px] z-3"
style={{ boxShadow: '27px 10px 30px -12px rgba(0, 0, 0, 0.25)' }}
/>
)}
<div className="absolute right-0 top-[13px] w-[220px] h-[220px] bg-[url(/img/audio-player/CD.png)] z-2" />
</div>
{/* 歌曲名 */}
<p className="mt-[44px] text-[20px] leading-[28px] text-base">{audioInfo?.title ?? ''}</p>
{/* 歌手/专辑 */}
{audioInfo?.artist && audioInfo?.album && (
<p className="text-[13px] leading-[18px] mt-[2px] text-[rgba(0,0,0,0.7)]">{`${audioInfo.artist}/${audioInfo.album}`}</p>
)}
{/* 歌词 */}
<div className="mt-[30px]">{audioInfo?.lrc ? <div className="mt-[30px]"></div> : <div></div>}</div>
</div>
{/* 播放列表 */}
<div className="w-[712px]">
<button></button>
<SongCardList className="w-full mt-11px mb-[56px] " songList={playQueue} listId="single" />
</div>
</div>
</div>
);
}

@ -1,5 +1,7 @@
'use client'; 'use client';
// 样式层
import Image from 'next/image'; import Image from 'next/image';
import { secondToDate } from '@/utils/time'; import { secondToDate } from '@/utils/time';
@ -12,6 +14,8 @@ interface Props {
audio: SongInfo | null; audio: SongInfo | null;
order: PlayOrder; order: PlayOrder;
playStatus: boolean; playStatus: boolean;
showCard: boolean;
onSwitchShowCard: () => void;
onPlay: () => void; onPlay: () => void;
onOrder: () => void; onOrder: () => void;
onPrev: () => void; onPrev: () => void;
@ -26,11 +30,13 @@ export default function AudioPlayer({
audio, audio,
order, order,
playStatus, playStatus,
showCard,
onPlay, onPlay,
onOrder, onOrder,
onPrev, onPrev,
onNext, onNext,
onChangeProgress, onChangeProgress,
onSwitchShowCard,
trackProgress, trackProgress,
duration, duration,
className, className,
@ -51,7 +57,8 @@ export default function AudioPlayer({
<div className={`flex w-[1200px] pt-[29px] ${className}`}> <div className={`flex w-[1200px] pt-[29px] ${className}`}>
{/* 专辑封面 */} {/* 专辑封面 */}
<div <div
className={`relative w-[72px] h-[72px] rounded-[3px] bg-[#000] overflow-hidden flex-shrink cursor-pointer ${styles.album_pic_overlay_expand}`} className={`relative w-[72px] h-[72px] rounded-[3px] bg-[#000] overflow-hidden flex-shrink cursor-pointer ${showCard ? styles.album_pic_overlay_collapse : styles.album_pic_overlay_expand}`}
onClick={onSwitchShowCard}
> >
{audio?.pic && ( {audio?.pic && (
<Image src={audio?.pic} alt="music" width={72} height={72} unoptimized className="w-full h-full" /> <Image src={audio?.pic} alt="music" width={72} height={72} unoptimized className="w-full h-full" />

@ -24,6 +24,13 @@
background-size: 28px; background-size: 28px;
} }
/* 专辑封面 阴影 */
.album_shoadow {
background: rgba(0, 0, 0, 0.08);
box-shadow: 27px 10px 30px -12px rgba(0, 0, 0, 0.25);
border-radius: 3px;
}
.range-input { .range-input {
-webkit-appearance: none; -webkit-appearance: none;
width: 100%; width: 100%;

@ -12,7 +12,11 @@ interface AuioState {
order: PlayOrder; order: PlayOrder;
/** 播放器显示状态 */ /** 播放器显示状态 */
show: boolean; show: boolean;
/** 单曲卡牌展示 */
showCard: boolean;
/** 当前音频id */
audioId: string; audioId: string;
audioInfo: SongInfo | null;
/** 歌单列表 */ /** 歌单列表 */
playList: SongInfo[]; playList: SongInfo[];
/** 播放队列 */ /** 播放队列 */
@ -21,6 +25,8 @@ interface AuioState {
setAudioId: (id: string) => void; setAudioId: (id: string) => void;
// 显示/隐藏播放器 // 显示/隐藏播放器
setShow: (value: boolean) => void; setShow: (value: boolean) => void;
// 显示/隐藏单曲卡片
setShowCard: (value: boolean) => void;
// 设置播放列表 // 设置播放列表
setPlayList: (params: { id: string; list: SongInfo[] }) => void; setPlayList: (params: { id: string; list: SongInfo[] }) => void;
// 切换歌曲 -1: 上一首 1: 下一首 // 切换歌曲 -1: 上一首 1: 下一首
@ -94,9 +100,11 @@ const useAuioState = create<AuioState>()(
order: 'list_loop', order: 'list_loop',
playStatus: false, playStatus: false,
show: false, show: false,
showCard: false,
playListId: '', playListId: '',
playList: [], playList: [],
playQueue: [], playQueue: [],
audioInfo: get()?.playList.length ? get().playList.find((item) => item.id === get().audioId) : null,
setAudioId, setAudioId,
setOrder, setOrder,
setShow: (value) => setShow: (value) =>
@ -105,6 +113,12 @@ const useAuioState = create<AuioState>()(
state.show = value; state.show = value;
}), }),
), ),
setShowCard: (value) =>
set(
produce((state) => {
state.showCard = value;
}),
),
setPlayList: (params) => { setPlayList: (params) => {
set( set(
produce((state) => { produce((state) => {

Loading…
Cancel
Save