update(AudioCard): 1.添加歌词功能; 2.修复了一些bug

mack-mac
mackt 7 months ago
parent b71f20ccab
commit 4789ddf364

@ -28,7 +28,7 @@ export default function RootLayout({ children }: Readonly<{ children: React.Reac
return (
<html lang="zn-ch" className="relative">
<body>
<Header />
<Header className="absolute top-0" />
<div>{children}</div>
<Footer />
<PlayerBar />

@ -1,7 +1,7 @@
export default function Loading() {
return (
<div className="w-[100vw] h-[100vh] flex justify-center items-center">
<div>loading...</div>
<div></div>
</div>
);
}

@ -2,7 +2,7 @@
'use client';
import { useEffect, useState } from 'react';
import { useEffect, useState, useMemo } from 'react';
import { useShallow } from 'zustand/react/shallow';
@ -23,9 +23,13 @@ export default function Journal() {
const [total, setTotal] = useState<number>(0);
const [pageNum, setPageNum] = useState<number>(1);
const [pageSize] = useState<number>(6);
const [list, setList] = useState<SongInfo[]>([]); // 列表
const [list, setList] = useState<SongInfo[]>([]); // 全部收藏列表
const [loading, setLoading] = useState<boolean>(false);
const displayList = useMemo(() => {
return list.slice((pageNum - 1) * pageSize, pageNum * pageSize);
}, [pageNum, list, type]);
const handleChangeType = (type: 'single' | 'journal') => {
setList([]);
setPageNum(1);
@ -34,7 +38,7 @@ export default function Journal() {
const getList = async () => {
setLoading(true);
const result = await apiGetSongCollect({ userId: userInfo?.id, pageNum, pageSize });
const result = await apiGetSongCollect({ userId: userInfo?.id, pageNum: -1, pageSize: -1 });
if (result.code === 200) {
setList(result.data?.rows);
setTotal(result.data?.total);
@ -53,12 +57,9 @@ export default function Journal() {
},
];
useEffect(() => {
getList();
}, [type, pageNum]);
useEffect(() => {
document.title = '我的收藏 - 雀乐';
getList();
}, []);
return (
@ -80,7 +81,7 @@ export default function Journal() {
</div>
{/* List */}
<SongCardList className="w-full mt-11px mb-[56px] " songList={list} listId="mylist" />
<SongCardList className="w-full mt-11px mb-[56px]" songList={displayList} listId="mylist" />
{!!total && (
<Pagination

@ -0,0 +1,25 @@
/** 歌词 */
interface Props {
lrc: string;
className?: string;
}
import styles from './index.module.css';
export default function Lrc({ lrc, className }: Props) {
const lrcList = lrc.split('\n');
const normalClassName = 'text-[14px] leading-[36.4px] text-[rgba(0,0,0,0.7)]';
const currentClassName = 'text-[17px] leading-[44.2px] text-[rgba(0,0,0,0.95)]';
return (
<div className={`overflow-y-auto ${styles.lrc} ${className}`}>
<div className="h-auto">
{lrcList.map((item, index) => (
<p key={index} className={true ? normalClassName : currentClassName}>
{item}
</p>
))}
</div>
</div>
);
}

@ -49,16 +49,16 @@ const PlayerBar = ({ className }: { className?: string }) => {
}, []);
return (
// 注释为高斯模糊效果
// 高斯模糊效果
// <div
// className={`fixed w-[100vw] h-[130px] bg-[#000] bg-opacity-50 shadow-lg shadow-black-[0_0_10px] z-10 ${className} backdrop-blur-[4px]`}
// style={{ bottom: 0 }}
// >
<div className={`fixed w-[100vw] h-[130px] bg-[#fff] shadow-lg shadow-black-[0_0_10px] z-10 ${className}`}>
<div className={`fixed bottom-0 w-[100vw] h-auto z-10 ${className}`}>
{/* 播放器 */}
<div
className="fixed bottom-0 w-[100vw] h-[130px] m-auto bg-[#fff] shadow-lg z-10 transition-bottom duration-600"
style={{ bottom: show && audioId ? 0 : -130 }}
className="fixed bottom-0 w-[100vw] h-[130px] m-auto bg-[#fff] shadow-lg shadow-black-[0_0_10px] z-10 transition-bottom duration-600"
style={{ bottom: (show && audioId) || showCard ? 0 : -130 }}
>
<Player className="m-auto" onSwitchShowCard={handleSwitchShowCard} />
</div>

@ -1,9 +1,14 @@
import { useState, useEffect } from 'react';
import Image from 'next/image';
import { useShallow } from 'zustand/react/shallow';
import clientHttp from '@/utils/request/client';
import styles from './index.module.css';
import Lrc from './Lrc';
import { SongCardList } from '@/components';
import { Header, SongCardList } from '@/components';
import useAudioStore from '@/store/audio';
interface Prop {
@ -22,18 +27,36 @@ export default function PlayerCard({ show, className }: Prop) {
}),
);
const miniClass = 'w-100vw translate-y-100vh'; // 缩小时的样式
const largeClass = 'w-[100vw] translate-y-[-130px]'; // 放大后的样式
const [lrc, setLrc] = useState<string>('');
const miniClass = 'translate-y-100vh'; // 缩小时的样式
const largeClass = 'translate-y-[-130px]'; // 放大后的样式
const audioInfo = playQueue.find((item) => item.id === audioId);
console.log(audioInfo);
const getLrc = async (lrcUrl: string) => {
if (!lrcUrl) {
setLrc('');
return;
}
const res: FetchResponse<Promise<string>> = await clientHttp.get(lrcUrl);
if (res.code === 200) {
const lrc = (await res.data) || '';
setLrc(lrc);
}
};
useEffect(() => {
getLrc(audioInfo?.lrc ?? '');
}, [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}`}
className={`fixed left-0 bottom-0 w-[100vw] h-[calc(100vh_-_130px)] bg-[#fff] transition-all duration-300 ${show ? largeClass : miniClass} ${className}`}
>
<div className="flex justify-between w-[1200px] mx-auto">
<Header />
<div className="flex justify-between w-[1200px] mx-auto mt-[68px]">
{/* 单曲信息 */}
<div>
{/* 专辑封面 */}
@ -60,7 +83,6 @@ export default function PlayerCard({ show, className }: Prop) {
)}
<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>
{/* 歌手/专辑 */}
@ -68,13 +90,20 @@ export default function PlayerCard({ show, className }: Prop) {
<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>
{lrc ? (
<Lrc lrc={lrc} className="mt-[30px] w-[340px] h-[267px]" />
) : (
<div className="mt-[30px] w-[340px] h-[267px] text-[14px] text-[rgba(0,0,0,0.7)] text-center leading-[267px]">
</div>
)}
</div>
{/* 播放列表 */}
<div className="w-[712px]">
<button></button>
<SongCardList className="w-full mt-11px mb-[56px] " songList={playQueue} listId="single" />
<div className={`h-[620px] mt-[15px] overflow-y-auto ${styles.playQueue}`}>
<SongCardList className="w-full mt-11px" songList={playQueue} listId="single" />
</div>
</div>
</div>
</div>

@ -64,3 +64,39 @@
background: #181818;
cursor: pointer;
}
/* 歌词滚动样式 */
.lrc::-webkit-scrollbar {
width: 3px; /* 滚动条宽度 */
}
.lrc::-webkit-scrollbar-track {
opacity: 0; /* 滚动条轨道透明度 */
}
.lrc::-webkit-scrollbar-thumb {
border-radius: 3px; /* 滚动条圆角 */
background: #d9d9d9; /* 滚动条滑块颜色 */
}
.lrc::-webkit-scrollbar-thumb:hover {
background: #555; /* 滚动条滑块悬停时颜色 */
}
/* 播放列表滚动样式 */
.playQueue::-webkit-scrollbar {
width: 3px; /* 滚动条宽度 */
}
.playQueue::-webkit-scrollbar-track {
opacity: 0; /* 滚动条轨道透明度 */
}
.playQueue::-webkit-scrollbar-thumb {
border-radius: 3px; /* 滚动条圆角 */
background: #d9d9d9; /* 滚动条滑块颜色 */
}
.playQueue::-webkit-scrollbar-thumb:hover {
background: #555; /* 滚动条滑块悬停时颜色 */
}

@ -39,7 +39,9 @@ export default function ButtonCollect({
const [currentCount, setCurrentCount] = useState<number>(0);
// 收藏/取消收藏
const handleCollect = async () => {
const handleCollect = async (event: React.MouseEvent) => {
event.stopPropagation();
setState(!state); // 更新收藏状态
setCurrentCount((currentCount) => currentCount + (state ? -1 : 1)); // 如果当前为收藏状态,-1否则+1

@ -40,7 +40,6 @@ export default function Comment({ journalId, className, totalCommentReply, total
// 加载评论
const handleLoadMore = useCallback(async () => {
console.log('handleLoadMore');
if (loading || commentList.length >= totalCommentReplyInt) return;
setLoading(true);
@ -86,8 +85,8 @@ export default function Comment({ journalId, className, totalCommentReply, total
clssName="mt-[25px]"
/>
<CommentList commentList={commentList} />
<div ref={loaderRef} className="h-[200px]">
{loading && 'loading...'}
<div ref={loaderRef} className="h-[200px] leading-[200px]">
{loading && '正在加载……'}
</div>
</>
)}

@ -18,7 +18,7 @@ export default function HeaderAvatar({ className }: { className?: string }) {
return (
<div className={`${className}`}>
<HoverCard>
<HoverCard openDelay={300}>
<HoverCardTrigger>
<Avatar className="h-[36px] w-[36px] cursor-pointer">
<AvatarImage src={userInfo.avatar} alt="avatar" />

@ -9,7 +9,7 @@ import HeaderAvatar from './HeaderAvatar';
import { Logo, LoginModal } from '@/components';
import useUserStore from '@/store/user';
export default function Header() {
export default function Header({ className }: { className?: string }) {
const { userInfo, showLogin, setShowLogin } = useUserStore(
useShallow((state) => ({
userInfo: state.userInfo,
@ -34,7 +34,7 @@ export default function Header() {
];
return (
<header className="absolute top-0 w-full h-[80px] z-2">
<header className={`w-full h-[80px] z-2 ${className}`}>
<div className="relative w-[1200px] h-full mx-auto flex items-center justify-between">
<Logo />
<div className="h-full flex flex-row items-center">

@ -26,12 +26,12 @@ export default function JournalItem({ listId, songList, className }: Props) {
);
const handlePlayList = (id: string) => {
// 正在播放当前歌单
// 正在播放其他歌单
if (playListId !== listId) {
setPlayList({ id: listId, list: songList });
}
// 正在播放其他歌单
// 正在播放当前歌单
setAudioId(id);
};

Loading…
Cancel
Save