feat: updates

This commit is contained in:
qier222 2023-01-24 16:29:33 +08:00
parent c6c59b2cd9
commit 7ce516877e
No known key found for this signature in database
63 changed files with 6591 additions and 1107 deletions

View file

@ -1,10 +1,7 @@
import useAlbum from '@/web/api/hooks/useAlbum'
import useUserAlbums, {
useMutationLikeAAlbum,
} from '@/web/api/hooks/useUserAlbums'
import useUserAlbums, { useMutationLikeAAlbum } from '@/web/api/hooks/useUserAlbums'
import Icon from '@/web/components/Icon'
import TrackListHeader from '@/web/components/TrackListHeader'
import useAppleMusicAlbum from '@/web/hooks/useAppleMusicAlbum'
import useVideoCover from '@/web/hooks/useVideoCover'
import player from '@/web/states/player'
import { formatDuration } from '@/web/utils/common'
@ -13,6 +10,7 @@ import { useMemo } from 'react'
import toast from 'react-hot-toast'
import { useParams } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import useAppleMusicAlbum from '@/web/api/hooks/useAppleMusicAlbum'
const Header = () => {
const { t, i18n } = useTranslation()
@ -25,51 +23,31 @@ const Header = () => {
})
const album = useMemo(() => albumRaw?.album, [albumRaw])
const { data: albumFromApple, isLoading: isLoadingAlbumFromApple } =
useAppleMusicAlbum({
id: album?.id,
name: album?.name,
artist: album?.artist.name,
})
const { data: videoCoverFromRemote } = useVideoCover({
id: album?.id,
name: album?.name,
artist: album?.artist.name,
enabled: !window.env?.isElectron,
})
const { data: appleMusicAlbum, isLoading: isLoadingAppleMusicAlbum } = useAppleMusicAlbum(
album?.id || 0
)
// For <Cover />
const cover = album?.picUrl
const videoCover =
albumFromApple?.attributes?.editorialVideo?.motionSquareVideo1x1?.video ||
videoCoverFromRemote?.video
const videoCover = appleMusicAlbum?.editorialVideo
// For <Info />
const title = album?.name
const creatorName = album?.artist.name
const creatorLink = `/artist/${album?.artist.id}`
const description = isLoadingAlbumFromApple
const description = isLoadingAppleMusicAlbum
? ''
: albumFromApple?.attributes?.editorialNotes?.standard || album?.description
: appleMusicAlbum?.editorialNote?.[i18n.language.replace('-', '_')] || album?.description
const extraInfo = useMemo(() => {
const duration = album?.songs?.reduce((acc, cur) => acc + cur.dt, 0) || 0
const albumDuration = formatDuration(
duration,
i18n.language,
'hh[hr] mm[min]'
)
const albumDuration = formatDuration(duration, i18n.language, 'hh[hr] mm[min]')
return (
<>
{album?.mark === 1056768 && (
<Icon
name='explicit'
className='mb-px mr-1 h-3 w-3 lg:h-3.5 lg:w-3.5'
/>
<Icon name='explicit' className='mb-px mr-1 h-3 w-3 lg:h-3.5 lg:w-3.5' />
)}{' '}
{dayjs(album?.publishTime || 0).year()} ·{' '}
{t('common.track-with-count', { count: album?.songs?.length })},{' '}
{albumDuration}
{t('common.track-with-count', { count: album?.songs?.length })}, {albumDuration}
</>
)
}, [album?.mark, album?.publishTime, album?.songs, i18n.language, t])

View file

@ -8,6 +8,8 @@ const ArtistVideos = () => {
const params = useParams()
const { data: videos } = useArtistMV({ id: Number(params.id) || 0 })
if (!videos?.mvs?.length) return null
return (
<div>
<div className='mb-6 mt-10 text-12 font-medium uppercase text-neutral-300'>
@ -16,17 +18,12 @@ const ArtistVideos = () => {
<div className='grid grid-cols-3 gap-6'>
{videos?.mvs?.slice(0, 6)?.map(video => (
<div
key={video.id}
onClick={() => (uiStates.playingVideoID = video.id)}
>
<div key={video.id} onClick={() => (uiStates.playingVideoID = video.id)}>
<img
src={video.imgurl16v9}
className='aspect-video w-full rounded-24 border border-white/5 object-contain'
/>
<div className='mt-2 text-12 font-medium text-neutral-600'>
{video.name}
</div>
<div className='mt-2 text-12 font-medium text-neutral-600'>{video.name}</div>
</div>
))}
</div>

View file

@ -1,23 +1,16 @@
import useIsMobile from '@/web/hooks/useIsMobile'
import useAppleMusicArtist from '@/web/hooks/useAppleMusicArtist'
import useAppleMusicArtist from '@/web/api/hooks/useAppleMusicArtist'
import { cx, css } from '@emotion/css'
import { useTranslation } from 'react-i18next'
import i18next from 'i18next'
const ArtistInfo = ({
artist,
isLoading,
}: {
artist?: Artist
isLoading: boolean
}) => {
const { t } = useTranslation()
const ArtistInfo = ({ artist, isLoading }: { artist?: Artist; isLoading: boolean }) => {
const { t, i18n } = useTranslation()
const isMobile = useIsMobile()
const { data: artistFromApple, isLoading: isLoadingArtistFromApple } =
useAppleMusicArtist({
id: artist?.id,
name: artist?.name,
})
const { data: artistFromApple, isLoading: isLoadingArtistFromApple } = useAppleMusicArtist(
artist?.id || 0
)
return (
<div>
@ -27,9 +20,7 @@ const ArtistInfo = ({
<span className='rounded-full bg-white/10'>PLACEHOLDER</span>
</div>
) : (
<div className='text-28 font-semibold text-white/70 lg:text-32'>
{artist?.name}
</div>
<div className='text-28 font-semibold text-white/70 lg:text-32'>{artist?.name}</div>
)}
{/* Type */}
@ -38,9 +29,7 @@ const ArtistInfo = ({
<span className='rounded-full bg-white/10'>Artist</span>
</div>
) : (
<div className='mt-2.5 text-24 font-medium text-white/40 lg:mt-6'>
Artist
</div>
<div className='mt-2.5 text-24 font-medium text-white/40 lg:mt-6'>Artist</div>
)}
{/* Counts */}
@ -67,9 +56,7 @@ const ArtistInfo = ({
`
)}
>
<span className='rounded-full bg-white/10'>
PLACEHOLDER1234567890
</span>
<span className='rounded-full bg-white/10'>PLACEHOLDER1234567890</span>
</div>
) : (
<div
@ -80,7 +67,7 @@ const ArtistInfo = ({
`
)}
>
{artistFromApple?.attributes?.artistBio || artist?.briefDesc}
{artistFromApple?.artistBio?.[i18n.language.replace('-', '_')] || artist?.briefDesc}
</div>
))}
</div>

View file

@ -1,25 +1,18 @@
import { isIOS, isSafari, resizeImage } from '@/web/utils/common'
import { resizeImage } from '@/web/utils/common'
import Image from '@/web/components/Image'
import { cx, css } from '@emotion/css'
import useAppleMusicArtist from '@/web/hooks/useAppleMusicArtist'
import { useEffect, useRef, useState } from 'react'
import Hls from 'hls.js'
import { motion } from 'framer-motion'
import useAppleMusicArtist from '@/web/api/hooks/useAppleMusicArtist'
import { useEffect } from 'react'
import uiStates from '@/web/states/uiStates'
import VideoCover from '@/web/components/VideoCover'
const Cover = ({ artist }: { artist?: Artist }) => {
const { data: artistFromApple, isLoading: isLoadingArtistFromApple } =
useAppleMusicArtist({
id: artist?.id,
name: artist?.name,
})
const { data: artistFromApple, isLoading: isLoadingArtistFromApple } = useAppleMusicArtist(
artist?.id || 0
)
const video =
artistFromApple?.attributes?.editorialVideo?.motionArtistSquare1x1?.video
const cover = isLoadingArtistFromApple
? ''
: artistFromApple?.attributes?.artwork?.url || artist?.img1v1Url
const video = artistFromApple?.editorialVideo
const cover = isLoadingArtistFromApple ? '' : artistFromApple?.artwork || artist?.img1v1Url || ''
useEffect(() => {
if (cover) uiStates.blurBackgroundImage = cover
@ -40,14 +33,7 @@ const Cover = ({ artist }: { artist?: Artist }) => {
'aspect-square h-full w-full lg:z-10',
video ? 'opacity-0' : 'opacity-100'
)}
src={resizeImage(
isLoadingArtistFromApple
? ''
: artistFromApple?.attributes?.artwork?.url ||
artist?.img1v1Url ||
'',
'lg'
)}
src={resizeImage(isLoadingArtistFromApple ? '' : cover, 'lg')}
/>
{video && <VideoCover source={video} />}

View file

@ -1,8 +1,5 @@
import Tabs from '@/web/components/Tabs'
import {
fetchDailyRecommendPlaylists,
fetchRecommendedPlaylists,
} from '@/web/api/playlist'
import { fetchDailyRecommendPlaylists, fetchRecommendedPlaylists } from '@/web/api/playlist'
import { PlaylistApiNames } from '@/shared/api/Playlists'
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
@ -33,10 +30,7 @@ const Recommend = () => {
const playlists =
isLoadingDaily || isLoading
? []
: [
...(dailyRecommendPlaylists?.recommend || []),
...(recommendedPlaylists?.result || []),
]
: [...(dailyRecommendPlaylists?.recommend || []), ...(recommendedPlaylists?.result || [])]
return <CoverRowVirtual playlists={playlists} />
@ -69,10 +63,12 @@ const Browse = () => {
'pointer-events-none fixed top-0 left-10 z-10 hidden lg:block',
css`
height: 230px;
right: ${playerWidth + 32}px;
background-image: url(${topbarBackground});
`
)}
style={{
right: `${playerWidth + 32}px`,
backgroundImage: `url(${topbarBackground})`,
}}
></div>
<Tabs

View file

@ -17,13 +17,12 @@ import { throttle } from 'lodash-es'
import { useTranslation } from 'react-i18next'
import VideoRow from '@/web/components/VideoRow'
import useUserVideos from '@/web/api/hooks/useUserVideos'
import persistedUiStates from '@/web/states/persistedUiStates'
const Albums = () => {
const { data: albums } = useUserAlbums()
return (
<CoverRow albums={albums?.data} itemTitle='name' itemSubtitle='artist' />
)
return <CoverRow albums={albums?.data} itemTitle='name' itemSubtitle='artist' />
}
const Playlists = () => {
@ -65,9 +64,8 @@ const CollectionTabs = ({ showBg }: { showBg: boolean }) => {
]
const { librarySelectedTab: selectedTab } = useSnapshot(uiStates)
const setSelectedTab = (
id: 'playlists' | 'albums' | 'artists' | 'videos'
) => {
const { minimizePlayer } = useSnapshot(persistedUiStates)
const setSelectedTab = (id: 'playlists' | 'albums' | 'artists' | 'videos') => {
uiStates.librarySelectedTab = id
}
@ -81,13 +79,16 @@ const CollectionTabs = ({ showBg }: { showBg: boolean }) => {
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className={cx(
'pointer-events-none fixed top-0 left-10 z-10 hidden lg:block',
'pointer-events-none fixed top-0 right-0 left-10 z-10 hidden lg:block',
css`
height: 230px;
right: ${playerWidth + 32}px;
background-image: url(${topbarBackground});
background-repeat: repeat;
`
)}
style={{
right: `${minimizePlayer ? 0 : playerWidth + 32}px`,
backgroundImage: `url(${topbarBackground})`,
}}
></motion.div>
)}
</AnimatePresence>
@ -99,12 +100,10 @@ const CollectionTabs = ({ showBg }: { showBg: boolean }) => {
setSelectedTab(id)
scrollToBottom(true)
}}
className={cx(
'sticky z-10 -mb-10 px-2.5 lg:px-0',
css`
top: ${topbarHeight}px;
`
)}
className={cx('sticky z-10 -mb-10 px-2.5 lg:px-0')}
style={{
top: `${topbarHeight}px`,
}}
/>
</>
)
@ -114,8 +113,7 @@ const Collections = () => {
const { librarySelectedTab: selectedTab } = useSnapshot(uiStates)
const observePoint = useRef<HTMLDivElement | null>(null)
const { onScreen: isScrollReachBottom } =
useIntersectionObserver(observePoint)
const { onScreen: isScrollReachBottom } = useIntersectionObserver(observePoint)
const onScroll = throttle(() => {
if (isScrollReachBottom) return
@ -126,13 +124,11 @@ const Collections = () => {
<div>
<CollectionTabs showBg={isScrollReachBottom} />
<div
className={cx(
'no-scrollbar overflow-y-auto px-2.5 pt-16 pb-16 lg:px-0',
css`
height: calc(100vh - ${topbarHeight}px);
`
)}
className={cx('no-scrollbar overflow-y-auto px-2.5 pt-16 pb-16 lg:px-0')}
onScroll={onScroll}
style={{
height: `calc(100vh - ${topbarHeight}px)`,
}}
>
{selectedTab === 'albums' && <Albums />}
{selectedTab === 'playlists' && <Playlists />}