136 lines
3.7 KiB
TypeScript
Raw Normal View History

2022-05-12 02:45:43 +08:00
import { player } from '@/web/store'
import { resizeImage } from '@/web/utils/common'
2022-05-29 17:53:27 +08:00
import Icon from './Icon'
2022-04-09 00:28:37 +08:00
import ArtistInline from './ArtistsInline'
2022-05-29 17:53:27 +08:00
import { State as PlayerState, Mode as PlayerMode } from '@/web/utils/player'
2022-04-17 12:46:20 +08:00
import useCoverColor from '../hooks/useCoverColor'
2022-05-29 17:53:27 +08:00
import { cx } from '@emotion/css'
2022-05-12 02:45:43 +08:00
import { useNavigate } from 'react-router-dom'
import { useSnapshot } from 'valtio'
import { useMemo } from 'react'
2022-03-13 14:40:38 +08:00
const MediaControls = () => {
const classes =
'btn-pressed-animation btn-hover-animation mr-1 cursor-default rounded-lg p-1.5 transition duration-200 after:bg-white/10'
const playerSnapshot = useSnapshot(player)
const state = useMemo(() => playerSnapshot.state, [playerSnapshot.state])
const playOrPause = () => {
if (playerSnapshot.mode === PlayerMode.FM) {
player.playOrPause()
} else {
player.playFM()
}
}
return (
<div>
<button
key='dislike'
className={classes}
onClick={() => player.fmTrash()}
>
2022-05-29 17:53:27 +08:00
<Icon name='dislike' className='h-6 w-6' />
</button>
<button key='play' className={classes} onClick={playOrPause}>
2022-05-29 17:53:27 +08:00
<Icon
className='h-6 w-6'
name={
playerSnapshot.mode === PlayerMode.FM &&
[PlayerState.Playing, PlayerState.Loading].includes(state)
? 'pause'
: 'play'
}
/>
</button>
<button
key='next'
className={classes}
onClick={() => player.nextTrack(true)}
>
2022-05-29 17:53:27 +08:00
<Icon name='next' className='h-6 w-6' />
</button>
</div>
)
2022-03-13 14:40:38 +08:00
}
const FMCard = () => {
2022-04-05 02:32:13 +08:00
const navigate = useNavigate()
2022-03-13 14:40:38 +08:00
2022-06-11 00:19:07 +08:00
const { track } = useSnapshot(player)
const coverUrl = useMemo(
2022-04-08 01:02:25 +08:00
() => resizeImage(track?.al?.picUrl ?? '', 'md'),
[track?.al?.picUrl]
)
2022-04-17 12:46:20 +08:00
const bgColor = useCoverColor(track?.al?.picUrl ?? '')
2022-03-13 14:40:38 +08:00
return (
<div
2022-04-02 16:54:37 +08:00
className='relative flex h-[198px] overflow-hidden rounded-2xl bg-gray-100 p-4 dark:bg-gray-800'
2022-04-12 01:48:14 +08:00
style={{
background: `linear-gradient(to bottom, ${bgColor.from}, ${bgColor.to})`,
}}
2022-03-13 14:40:38 +08:00
>
2022-04-02 16:54:37 +08:00
{coverUrl ? (
2022-04-05 02:32:13 +08:00
<img
onClick={() => track?.al?.id && navigate(`/album/${track.al.id}`)}
className='rounded-lg shadow-2xl'
src={coverUrl}
/>
2022-04-02 16:54:37 +08:00
) : (
<div className='aspect-square h-full rounded-lg bg-gray-200 dark:bg-white/5'></div>
)}
2022-03-13 14:40:38 +08:00
2022-03-17 19:30:43 +08:00
<div className='ml-5 flex w-full flex-col justify-between text-white'>
2022-03-13 14:40:38 +08:00
{/* Track info */}
<div>
2022-04-02 16:54:37 +08:00
{track ? (
<div className='line-clamp-2 text-xl font-semibold'>
{track?.name}
</div>
2022-04-02 16:54:37 +08:00
) : (
<div className='flex'>
<div className='bg-gray-200 text-xl text-transparent dark:bg-white/5'>
PLACEHOLDER12345
</div>
</div>
)}
{track ? (
<ArtistInline
className='line-clamp-2 opacity-75'
artists={track?.ar ?? []}
/>
) : (
<div className='mt-1 flex'>
<div className='bg-gray-200 text-transparent dark:bg-white/5'>
PLACEHOLDER
</div>
</div>
)}
2022-03-13 14:40:38 +08:00
</div>
2022-03-21 02:03:25 +08:00
<div className='-mb-1 flex items-center justify-between'>
2022-04-02 16:54:37 +08:00
{track ? <MediaControls /> : <div className='h-9'></div>}
2022-03-13 14:40:38 +08:00
{/* FM logo */}
2022-04-02 16:54:37 +08:00
<div
2022-05-12 02:45:43 +08:00
className={cx(
2022-04-02 16:54:37 +08:00
'right-4 bottom-5 flex opacity-20',
track ? 'text-white ' : 'text-gray-700 dark:text-white'
)}
>
2022-05-29 17:53:27 +08:00
<Icon name='fm' className='mr-1 h-6 w-6' />
2022-03-17 19:30:43 +08:00
<span className='font-semibold'>FM</span>
2022-03-13 14:40:38 +08:00
</div>
</div>
</div>
</div>
)
}
export default FMCard