mirror of
https://github.com/qier222/YesPlayMusic.git
synced 2025-03-27 17:58:56 +08:00
feat: updates (#1419)
* feat: TrackList 高亮播放中Track & Track 子标题(歌名翻译) * fix: 不对id为0的歌手应用下划线 * feat: TrackList的Track支持深色模式 * fix: typo * feat: 专辑页面的subtitle支持深色模式 * fix: typo * feat: 在TrackList中高亮播放Track里的歌手信息
This commit is contained in:
parent
e3486ab550
commit
08abf8229f
@ -11,7 +11,9 @@ const ArtistInline = ({
|
||||
<div className={classNames('flex truncate', className)}>
|
||||
{artists.map((artist, index) => (
|
||||
<span key={artist.id}>
|
||||
<span className='hover:underline'>{artist.name}</span>
|
||||
<span className={classNames({ 'hover:underline': !!artist.id })}>
|
||||
{artist.name}
|
||||
</span>
|
||||
{index < artists.length - 1 ? ', ' : ''}
|
||||
</span>
|
||||
))}
|
||||
|
@ -49,12 +49,14 @@ const Track = memo(
|
||||
isLiked = false,
|
||||
isSkeleton = false,
|
||||
isHighlight = false,
|
||||
subtitle = undefined,
|
||||
onClick,
|
||||
}: {
|
||||
track: Track
|
||||
isLiked?: boolean
|
||||
isSkeleton?: boolean
|
||||
isHighlight?: boolean
|
||||
subtitle?: string
|
||||
onClick: (e: React.MouseEvent<HTMLElement>, trackID: number) => void
|
||||
}) => {
|
||||
if (enableRenderLog)
|
||||
@ -113,7 +115,17 @@ const Track = memo(
|
||||
isHighlight ? 'text-brand-500' : 'text-black dark:text-white'
|
||||
)}
|
||||
>
|
||||
{track.name}
|
||||
<span>{track.name}</span>
|
||||
{subtitle && (
|
||||
<span
|
||||
title={subtitle}
|
||||
className={classNames(
|
||||
'ml-1',
|
||||
isHighlight ? 'text-brand-500/[.8]' : 'text-gray-400'
|
||||
)}>
|
||||
({subtitle})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -238,6 +250,7 @@ const TracksAlbum = ({
|
||||
isLiked={userLikedSongs?.ids?.includes(track.id) ?? false}
|
||||
isSkeleton={false}
|
||||
isHighlight={track.id === playingTrack?.id}
|
||||
subtitle={track.tns?.at(0) ?? track.alia?.at(0)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -7,6 +7,7 @@ import { prefetchAlbum } from '@/hooks/useAlbum'
|
||||
import useUser from '@/hooks/useUser'
|
||||
import useUserLikedSongsIDs from '@/hooks/useUserLikedSongsIDs'
|
||||
import { formatDuration, resizeImage } from '@/utils/common'
|
||||
import { player } from '@/store'
|
||||
|
||||
const Track = memo(
|
||||
({
|
||||
@ -14,12 +15,14 @@ const Track = memo(
|
||||
isLiked = false,
|
||||
isSkeleton = false,
|
||||
isPlaying = false,
|
||||
subtitle = undefined,
|
||||
onClick,
|
||||
}: {
|
||||
track: Track
|
||||
isLiked?: boolean
|
||||
isSkeleton?: boolean
|
||||
isPlaying?: boolean
|
||||
subtitle?: string
|
||||
onClick: (e: React.MouseEvent<HTMLElement>, trackID: number) => void
|
||||
}) => {
|
||||
return (
|
||||
@ -28,8 +31,8 @@ const Track = memo(
|
||||
className={classNames(
|
||||
'group grid w-full rounded-xl after:scale-[.98] after:rounded-xl dark:after:bg-white/[.08]',
|
||||
'grid-cols-12 p-2 pr-4',
|
||||
!isSkeleton && !isPlaying && 'btn-hover-animation after:bg-gray-100',
|
||||
!isSkeleton && isPlaying && 'bg-brand-100'
|
||||
!isSkeleton && !isPlaying && 'btn-hover-animation after:bg-gray-100 dark:after:bg-white/[.08]',
|
||||
!isSkeleton && isPlaying && 'bg-brand-100 dark:bg-gray-800'
|
||||
)}
|
||||
>
|
||||
{/* Track info */}
|
||||
@ -51,12 +54,33 @@ const Track = memo(
|
||||
{isSkeleton ? (
|
||||
<Skeleton className='text-lg'>PLACEHOLDER12345</Skeleton>
|
||||
) : (
|
||||
<div className='line-clamp-1 break-all text-lg font-semibold dark:text-white'>
|
||||
{track.name}
|
||||
<div
|
||||
className={classNames(
|
||||
'line-clamp-1 break-all text-lg font-semibold',
|
||||
isPlaying ? 'text-brand-500' : 'text-black dark:text-white'
|
||||
)}
|
||||
>
|
||||
<span>{track.name}</span>
|
||||
{subtitle && (
|
||||
<span
|
||||
title={subtitle}
|
||||
className={classNames(
|
||||
'ml-1',
|
||||
isPlaying ? 'text-brand-500/[.8]' : 'text-gray-400'
|
||||
)}
|
||||
>
|
||||
({subtitle})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='text-sm text-gray-600 dark:text-gray-400'>
|
||||
<div
|
||||
className={classNames(
|
||||
'text-sm',
|
||||
isPlaying ? 'text-brand-500' : 'text-gray-600 dark:text-gray-400'
|
||||
)}
|
||||
>
|
||||
{isSkeleton ? (
|
||||
<Skeleton className='w-2/3 translate-y-px'>PLACE</Skeleton>
|
||||
) : (
|
||||
@ -75,7 +99,10 @@ const Track = memo(
|
||||
<NavLink
|
||||
to={`/album/${track.al.id}`}
|
||||
onMouseOver={() => prefetchAlbum({ id: track.al.id })}
|
||||
className='hover:underline'
|
||||
className={classNames(
|
||||
'hover:underline',
|
||||
isPlaying && 'text-brand-500'
|
||||
)}
|
||||
>
|
||||
{track.al.name}
|
||||
</NavLink>
|
||||
@ -107,7 +134,12 @@ const Track = memo(
|
||||
{isSkeleton ? (
|
||||
<Skeleton>0:00</Skeleton>
|
||||
) : (
|
||||
<div className='min-w-[2.5rem] text-right text-gray-600 dark:text-gray-400'>
|
||||
<div
|
||||
className={classNames(
|
||||
'min-w-[2.5rem] text-right',
|
||||
isPlaying ? 'text-brand-500' : 'text-gray-600 dark:text-gray-400'
|
||||
)}
|
||||
>
|
||||
{formatDuration(track.dt, 'en', 'hh:mm:ss')}
|
||||
</div>
|
||||
)}
|
||||
@ -143,6 +175,12 @@ const TracksList = memo(
|
||||
if (e.detail === 2) onTrackDoubleClick?.(trackID)
|
||||
}
|
||||
|
||||
const playerSnapshot = useSnapshot(player)
|
||||
const playingTrack = useMemo(
|
||||
() => playerSnapshot.track,
|
||||
[playerSnapshot.track]
|
||||
)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{/* Tracks table header */}
|
||||
@ -157,25 +195,26 @@ const TracksList = memo(
|
||||
|
||||
<div className='grid w-full gap-1'>
|
||||
{/* Tracks */}
|
||||
{!isSkeleton &&
|
||||
tracks.map(track => (
|
||||
<Track
|
||||
onClick={handleClick}
|
||||
key={track.id}
|
||||
track={track}
|
||||
isLiked={userLikedSongs?.ids?.includes(track.id) ?? false}
|
||||
isSkeleton={false}
|
||||
/>
|
||||
))}
|
||||
{isSkeleton &&
|
||||
skeletonTracks.map((track, index) => (
|
||||
<Track
|
||||
key={index}
|
||||
track={track}
|
||||
onClick={() => null}
|
||||
isSkeleton={true}
|
||||
/>
|
||||
))}
|
||||
{isSkeleton
|
||||
? skeletonTracks.map((track, index) => (
|
||||
<Track
|
||||
key={index}
|
||||
track={track}
|
||||
onClick={() => null}
|
||||
isSkeleton={true}
|
||||
/>
|
||||
))
|
||||
: tracks.map(track => (
|
||||
<Track
|
||||
onClick={handleClick}
|
||||
key={track.id}
|
||||
track={track}
|
||||
isLiked={userLikedSongs?.ids?.includes(track.id) ?? false}
|
||||
isSkeleton={false}
|
||||
isPlaying={track.id === playingTrack?.id}
|
||||
subtitle={track.tns?.at(0) ?? track.alia?.at(0)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
|
1
packages/renderer/src/interface.d.ts
vendored
1
packages/renderer/src/interface.d.ts
vendored
@ -111,6 +111,7 @@ declare interface Track {
|
||||
tagPicList: null
|
||||
v: number
|
||||
version: number
|
||||
tns: (string | null)[]
|
||||
}
|
||||
declare interface Artist {
|
||||
alias: unknown[]
|
||||
|
Loading…
x
Reference in New Issue
Block a user