import Cover from '@/components/Cover'
import Skeleton from '@/components/Skeleton'
import SvgIcon from '@/components/SvgIcon'
import { prefetchAlbum } from '@/hooks/useAlbum'
import { prefetchPlaylist } from '@/hooks/usePlaylist'
import { formatDate, resizeImage, scrollToTop } from '@/utils/common'
export enum Subtitle {
COPYWRITER = 'copywriter',
CREATOR = 'creator',
TYPE_RELEASE_YEAR = 'type+releaseYear',
ARTIST = 'artist',
}
const Title = ({
title,
seeMoreLink,
}: {
title: string
seeMoreLink: string
}) => {
return (
{title}
{seeMoreLink && (
See More
)}
)
}
const getSubtitleText = (
item: Album | Playlist | Artist,
subtitle: Subtitle
) => {
const nickname = 'creator' in item ? item.creator.nickname : 'someone'
const artist = 'artist' in item ? item.artist.name : 'unknown'
const copywriter = 'copywriter' in item ? item.copywriter : 'unknown'
const releaseYear =
('publishTime' in item &&
formatDate(item.publishTime ?? 0, 'en', 'YYYY')) ||
'unknown'
const type = {
playlist: 'playlist',
album: 'Album',
专辑: 'Album',
Single: 'Single',
'EP/Single': 'EP',
EP: 'EP',
unknown: 'unknown',
精选集: 'Collection',
}[('type' in item && typeof item.type !== 'number' && item.type) || 'unknown']
const table = {
[Subtitle.CREATOR]: `by ${nickname}`,
[Subtitle.TYPE_RELEASE_YEAR]: `${type} · ${releaseYear}`,
[Subtitle.ARTIST]: artist,
[Subtitle.COPYWRITER]: copywriter,
}
return table[subtitle]
}
const getImageUrl = (item: Album | Playlist | Artist) => {
let cover: string | undefined = ''
if ('coverImgUrl' in item) cover = item.coverImgUrl
if ('picUrl' in item) cover = item.picUrl
if ('img1v1Url' in item) cover = item.img1v1Url
return resizeImage(cover || '', 'md')
}
const CoverRow = ({
title,
albums,
artists,
playlists,
subtitle = Subtitle.COPYWRITER,
seeMoreLink,
isSkeleton,
className,
rows = 2,
navigateCallback, // Callback function when click on the cover/title
}: {
title?: string
albums?: Album[]
artists?: Artist[]
playlists?: Playlist[]
subtitle?: Subtitle
seeMoreLink?: string
isSkeleton?: boolean
className?: string
rows?: number
navigateCallback?: () => void
}) => {
const renderItems = useMemo(() => {
if (isSkeleton) {
return new Array(rows * 5).fill({}) as Array
}
return albums ?? playlists ?? artists ?? []
}, [albums, artists, isSkeleton, playlists, rows])
const navigate = useNavigate()
const goTo = (id: number) => {
if (isSkeleton) return
if (albums) navigate(`/album/${id}`)
if (playlists) navigate(`/playlist/${id}`)
if (artists) navigate(`/artist/${id}`)
if (navigateCallback) navigateCallback()
scrollToTop()
}
const prefetch = (id: number) => {
if (albums) prefetchAlbum({ id })
if (playlists) prefetchPlaylist({ id })
}
return (
{title &&
}
{renderItems.map((item, index) => (
prefetch(item.id)}
className='grid gap-x-[24px] gap-y-7'
>
{/* Cover */}
{isSkeleton ? (
) : (
goTo(item.id)}
imageUrl={getImageUrl(item)}
/>
)}
{/* Info */}
{/* Name */}
{isSkeleton ? (
PLACEHOLDER
PLACEHOLDER
) : (
{/* Playlist private icon */}
{(item as Playlist).privacy && (
)}
goTo(item.id)}
className='decoration-gray-600 decoration-2 hover:underline dark:text-white dark:decoration-gray-200'
>
{item.name}
)}
{/* Subtitle */}
{isSkeleton ? (
PLACEHOLDER
) : (
{getSubtitleText(item, subtitle)}
)}
))}
)
}
export default CoverRow