import { memo, useCallback, useMemo } from 'react' import ArtistInline from '@/web/components/ArtistsInline' import Skeleton from '@/web/components/Skeleton' import Icon from '@/web/components/Icon' import useUserLikedTracksIDs, { useMutationLikeATrack, } from '@/web/api/hooks/useUserLikedTracksIDs' import { player } from '@/web/store' import { formatDuration } from '@/web/utils/common' import { State as PlayerState } from '@/web/utils/player' import { cx } from '@emotion/css' import { useSnapshot } from 'valtio' const PlayOrPauseButtonInTrack = memo( ({ isHighlight, trackID }: { isHighlight: boolean; trackID: number }) => { const playerSnapshot = useSnapshot(player) const isPlaying = useMemo( () => playerSnapshot.state === PlayerState.Playing, [playerSnapshot.state] ) const onClick = () => { isHighlight ? player.playOrPause() : player.playTrack(trackID) } return (
) } ) PlayOrPauseButtonInTrack.displayName = 'PlayOrPauseButtonInTrack' const Track = memo( ({ track, isLiked = false, isSkeleton = false, isHighlight = false, onClick, }: { track: Track isLiked?: boolean isSkeleton?: boolean isHighlight?: boolean onClick: (e: React.MouseEvent, trackID: number) => void }) => { const subtitle = useMemo( () => track.tns?.at(0) ?? track.alia?.at(0), [track.alia, track.tns] ) const mutationLikeATrack = useMutationLikeATrack() return (
onClick(e, track.id)} className={cx( 'group grid w-full rounded-xl after:scale-[.98] after:rounded-xl', 'grid-cols-12 py-2.5 px-4', !isSkeleton && { 'btn-hover-animation after:bg-gray-100 dark:after:bg-white/10': !isHighlight, 'bg-brand-50 dark:bg-gray-800': isHighlight, } )} > {/* Track name and number */}
{/* Track number */} {isSkeleton ? ( ) : ( !isHighlight && (
{track.no}
) )} {/* Play or pause button for playing track */} {!isSkeleton && ( )} {/* Track name */}
{isSkeleton ? ( PLACEHOLDER123456789012345 ) : (
{track.name} {track.mark === 1318912 && ( )} {subtitle && ( ({subtitle}) )}
)}
{/* Artists */}
{isSkeleton ? ( PLACEHOLDER1234 ) : ( )}
{/* Actions & Track duration */}
{/* Like button */} {!isSkeleton && ( )} {/* Track duration */} {isSkeleton ? ( 0:00 ) : (
{formatDuration(track.dt, 'en', 'hh:mm:ss')}
)}
) } ) Track.displayName = 'Track' const TracksAlbum = ({ tracks, isSkeleton = false, onTrackDoubleClick, }: { tracks: Track[] isSkeleton?: boolean onTrackDoubleClick?: (trackID: number) => void }) => { // Fake data when isSkeleton is true const skeletonTracks: Track[] = new Array(1).fill({}) // Liked songs ids const { data: userLikedSongs } = useUserLikedTracksIDs() const handleClick = useCallback( (e: React.MouseEvent, trackID: number) => { if (e.detail === 2) onTrackDoubleClick?.(trackID) }, [onTrackDoubleClick] ) const { track } = useSnapshot(player) return (
{/* Tracks table header */}
#
标题
艺人
时长
{/* Tracks */} {isSkeleton ? skeletonTracks.map((track, index) => ( null} isSkeleton={true} /> )) : tracks.map(track => ( ))}
) } export default TracksAlbum