2022-04-09 00:28:37 +08:00
|
|
|
import Button, { Color as ButtonColor } from '@/renderer/components/Button'
|
|
|
|
import SvgIcon from '@/renderer/components/SvgIcon'
|
|
|
|
import Cover from '@/renderer/components/Cover'
|
|
|
|
import useArtist from '@/renderer/hooks/useArtist'
|
|
|
|
import useArtistAlbums from '@/renderer/hooks/useArtistAlbums'
|
|
|
|
import { resizeImage } from '@/renderer/utils/common'
|
2022-03-23 01:21:22 +08:00
|
|
|
import dayjs from 'dayjs'
|
2022-04-09 00:28:37 +08:00
|
|
|
import TracksGrid from '@/renderer/components/TracksGrid'
|
|
|
|
import CoverRow, { Subtitle } from '@/renderer/components/CoverRow'
|
|
|
|
import Skeleton from '@/renderer/components/Skeleton'
|
|
|
|
import useTracks from '@/renderer/hooks/useTracks'
|
|
|
|
import { player } from '@/renderer/store'
|
2022-03-23 01:21:22 +08:00
|
|
|
|
2022-03-27 15:21:48 +08:00
|
|
|
const Header = ({ artist }: { artist: Artist | undefined }) => {
|
|
|
|
const coverImage = resizeImage(artist?.img1v1Url || '', 'md')
|
|
|
|
|
|
|
|
return (
|
2022-03-29 00:11:05 +08:00
|
|
|
<>
|
2022-03-27 15:21:48 +08:00
|
|
|
<div className='absolute top-0 left-0 z-0 h-[24rem] w-full overflow-hidden'>
|
|
|
|
{coverImage && (
|
2022-03-29 00:11:05 +08:00
|
|
|
<>
|
2022-04-02 16:54:37 +08:00
|
|
|
<img src={coverImage} className='absolute w-full blur-[100px]' />
|
2022-03-29 00:11:05 +08:00
|
|
|
<img src={coverImage} className='absolute w-full blur-[100px]' />
|
|
|
|
</>
|
2022-03-27 15:21:48 +08:00
|
|
|
)}
|
2022-03-30 16:54:11 +08:00
|
|
|
<div className='absolute top-0 h-full w-full bg-gradient-to-b from-white/[.85] to-white dark:from-black/50 dark:to-[#1d1d1d]'></div>
|
2022-03-27 15:21:48 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className='relative mt-6 overflow-hidden rounded-2xl bg-gray-500/10 dark:bg-gray-800/20'>
|
|
|
|
<div className='flex h-[26rem] justify-center overflow-hidden'>
|
|
|
|
<img src={coverImage} className='aspect-square brightness-[.5]' />
|
|
|
|
<img src={coverImage} className='aspect-square brightness-[.5]' />
|
|
|
|
<img src={coverImage} />
|
|
|
|
<img src={coverImage} className='aspect-square brightness-[.5]' />
|
|
|
|
<img src={coverImage} className='aspect-square brightness-[.5]' />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className='absolute right-0 left-0 top-[18rem] h-32 bg-gradient-to-t from-[#222]/60 to-transparent'></div>
|
|
|
|
|
|
|
|
<div className='absolute top-0 right-0 left-0 flex h-[26rem] items-end justify-between p-8 pb-6'>
|
|
|
|
<div className='text-7xl font-bold text-white'>{artist?.name}</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-03-29 00:11:05 +08:00
|
|
|
</>
|
2022-03-27 15:21:48 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const LatestRelease = ({
|
|
|
|
album,
|
|
|
|
isLoading,
|
|
|
|
}: {
|
|
|
|
album: Album | undefined
|
|
|
|
isLoading: boolean
|
|
|
|
}) => {
|
2022-04-02 18:46:08 +08:00
|
|
|
const navigate = useNavigate()
|
|
|
|
const toAlbum = () => navigate(`/album/${album?.id}`)
|
2022-03-27 15:21:48 +08:00
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
|
|
|
|
最新发行
|
|
|
|
</div>
|
2022-04-02 18:46:08 +08:00
|
|
|
<div className='flex-grow rounded-xl'>
|
2022-03-27 15:21:48 +08:00
|
|
|
{isLoading ? (
|
|
|
|
<Skeleton className='aspect-square w-full rounded-xl'></Skeleton>
|
|
|
|
) : (
|
2022-04-02 18:46:08 +08:00
|
|
|
<Cover
|
2022-04-05 23:02:59 +08:00
|
|
|
imageUrl={resizeImage(album?.picUrl ?? '', 'md')}
|
2022-04-02 18:46:08 +08:00
|
|
|
showPlayButton={true}
|
|
|
|
onClick={toAlbum}
|
|
|
|
/>
|
2022-03-27 15:21:48 +08:00
|
|
|
)}
|
2022-04-02 18:46:08 +08:00
|
|
|
<div
|
|
|
|
onClick={toAlbum}
|
|
|
|
className='line-clamp-2 line-clamp-1 mt-2 font-semibold leading-tight decoration-gray-600 decoration-2 hover:underline dark:text-white dark:decoration-gray-200'
|
|
|
|
>
|
2022-03-27 15:21:48 +08:00
|
|
|
{album?.name}
|
|
|
|
</div>
|
|
|
|
<div className='text-[12px] text-gray-500 dark:text-gray-400'>
|
|
|
|
{album?.type} · {dayjs(album?.publishTime || 0).year()}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const PopularTracks = ({
|
|
|
|
tracks,
|
|
|
|
isLoadingArtist,
|
|
|
|
}: {
|
|
|
|
tracks: Track[] | undefined
|
|
|
|
isLoadingArtist: boolean
|
|
|
|
}) => {
|
|
|
|
const { data: tracksWithExtraInfo } = useTracks({
|
|
|
|
ids: tracks?.slice(0, 10)?.map(t => t.id) ?? [],
|
|
|
|
})
|
|
|
|
|
2022-04-02 18:46:08 +08:00
|
|
|
const handlePlay = useCallback(
|
|
|
|
(trackID: number | null = null) => {
|
|
|
|
if (!tracks?.length) {
|
|
|
|
toast('无法播放歌单')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
player.playAList(
|
|
|
|
tracks.map(t => t.id),
|
|
|
|
trackID
|
|
|
|
)
|
|
|
|
},
|
|
|
|
[tracks]
|
|
|
|
)
|
|
|
|
|
2022-03-27 15:21:48 +08:00
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
|
|
|
|
热门歌曲
|
|
|
|
</div>
|
|
|
|
<div className='rounded-xl'>
|
|
|
|
<TracksGrid
|
|
|
|
tracks={tracksWithExtraInfo?.songs ?? tracks?.slice(0, 10) ?? []}
|
|
|
|
isSkeleton={isLoadingArtist}
|
2022-04-02 18:46:08 +08:00
|
|
|
onTrackDoubleClick={handlePlay}
|
2022-03-27 15:21:48 +08:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-03-23 01:21:22 +08:00
|
|
|
const Artist = () => {
|
|
|
|
const params = useParams()
|
|
|
|
|
2022-03-27 15:21:48 +08:00
|
|
|
const { data: artist, isLoading: isLoadingArtist } = useArtist({
|
2022-03-23 01:21:22 +08:00
|
|
|
id: Number(params.id) || 0,
|
|
|
|
})
|
|
|
|
|
2022-03-27 15:21:48 +08:00
|
|
|
const { data: albumsRaw, isLoading: isLoadingAlbums } = useArtistAlbums({
|
2022-03-23 01:21:22 +08:00
|
|
|
id: Number(params.id) || 0,
|
|
|
|
limit: 1000,
|
|
|
|
})
|
|
|
|
|
|
|
|
const albums = useMemo(() => {
|
|
|
|
if (!albumsRaw?.hotAlbums) return []
|
2022-03-24 14:23:04 +08:00
|
|
|
const albums: Album[] = []
|
|
|
|
albumsRaw.hotAlbums.forEach(album => {
|
|
|
|
if (album.type !== '专辑') return false
|
|
|
|
if (['混音版', '精选集', 'Remix'].includes(album.subType)) return false
|
|
|
|
|
|
|
|
// No singles
|
|
|
|
if (album.size <= 1) return false
|
|
|
|
|
|
|
|
// No remixes
|
|
|
|
if (
|
|
|
|
/(\(|\[)(.*)(Remix|remix)(.*)(\)|\])/.test(
|
|
|
|
album.name.toLocaleLowerCase()
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// If have same name album only keep the Explicit version
|
|
|
|
const sameNameAlbumIndex = albums.findIndex(a => a.name === album.name)
|
|
|
|
if (sameNameAlbumIndex !== -1) {
|
|
|
|
if (album.mark === 1056768) albums[sameNameAlbumIndex] = album
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
albums.push(album)
|
|
|
|
})
|
|
|
|
return albums
|
2022-03-23 01:21:22 +08:00
|
|
|
}, [albumsRaw?.hotAlbums])
|
|
|
|
|
|
|
|
const singles = useMemo(() => {
|
|
|
|
if (!albumsRaw?.hotAlbums) return []
|
2022-03-24 14:23:04 +08:00
|
|
|
const albumsIds = albums.map(album => album.id)
|
2022-03-23 01:21:22 +08:00
|
|
|
return albumsRaw.hotAlbums.filter(
|
2022-03-24 14:23:04 +08:00
|
|
|
album => albumsIds.includes(album.id) === false
|
2022-03-23 01:21:22 +08:00
|
|
|
)
|
2022-03-24 14:23:04 +08:00
|
|
|
}, [albums, albumsRaw?.hotAlbums])
|
2022-03-23 01:21:22 +08:00
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
2022-03-27 15:21:48 +08:00
|
|
|
<Header artist={artist?.artist} />
|
2022-03-23 01:21:22 +08:00
|
|
|
|
2022-04-02 23:26:33 +08:00
|
|
|
<div
|
|
|
|
className={classNames(
|
|
|
|
'mt-12 px-2',
|
|
|
|
albumsRaw?.hotAlbums?.length !== 0 &&
|
|
|
|
'grid h-[20rem] grid-cols-[14rem,_auto] grid-rows-1 gap-16'
|
|
|
|
)}
|
|
|
|
>
|
|
|
|
{albumsRaw?.hotAlbums?.length !== 0 && (
|
|
|
|
<LatestRelease
|
|
|
|
album={albumsRaw?.hotAlbums[0]}
|
|
|
|
isLoading={isLoadingAlbums}
|
|
|
|
/>
|
|
|
|
)}
|
2022-03-23 01:21:22 +08:00
|
|
|
|
2022-03-27 15:21:48 +08:00
|
|
|
<PopularTracks
|
|
|
|
tracks={artist?.hotSongs}
|
|
|
|
isLoadingArtist={isLoadingArtist}
|
|
|
|
/>
|
2022-03-23 01:21:22 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
{/* Albums */}
|
2022-03-24 11:52:55 +08:00
|
|
|
{albums.length !== 0 && (
|
|
|
|
<div className='mt-20 px-2'>
|
2022-03-24 14:23:04 +08:00
|
|
|
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
|
2022-03-24 11:52:55 +08:00
|
|
|
专辑
|
|
|
|
</div>
|
|
|
|
<CoverRow
|
|
|
|
albums={albums.slice(0, 10)}
|
2022-04-16 22:39:51 +08:00
|
|
|
subtitle={Subtitle.TypeReleaseYear}
|
2022-03-24 11:52:55 +08:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
2022-03-23 01:21:22 +08:00
|
|
|
|
|
|
|
{/* Singles/EP */}
|
2022-04-02 23:26:33 +08:00
|
|
|
{singles.length !== 0 && (
|
|
|
|
<div className='mt-16 px-2'>
|
|
|
|
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
|
|
|
|
单曲和EP
|
|
|
|
</div>
|
|
|
|
<CoverRow
|
|
|
|
albums={singles.slice(0, 5)}
|
2022-04-16 22:39:51 +08:00
|
|
|
subtitle={Subtitle.TypeReleaseYear}
|
2022-04-02 23:26:33 +08:00
|
|
|
/>
|
2022-03-23 01:21:22 +08:00
|
|
|
</div>
|
2022-04-02 23:26:33 +08:00
|
|
|
)}
|
2022-03-23 01:21:22 +08:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default Artist
|