mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-16 13:17:46 +00:00
update
This commit is contained in:
parent
32050e4553
commit
6aee8ae38e
41 changed files with 523 additions and 415 deletions
|
|
@ -9,7 +9,7 @@ const Artist = () => {
|
|||
<div>
|
||||
<Header />
|
||||
{/* Dividing line */}
|
||||
<div className='mt-10 mb-7.5 h-px w-full bg-white/20'></div>
|
||||
<div className='mb-7.5 mt-10 h-px w-full bg-white/20'></div>
|
||||
<Popular />
|
||||
<ArtistAlbum />
|
||||
<ArtistVideos />
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ const ArtistInfo = ({ artist, isLoading }: { artist?: Artist; isLoading: boolean
|
|||
(isLoading || isLoadingArtistFromApple ? (
|
||||
<div
|
||||
className={cx(
|
||||
'line-clamp-5 mt-6 text-14 font-bold text-transparent',
|
||||
'mt-6 line-clamp-5 text-14 font-bold text-transparent',
|
||||
css`
|
||||
min-height: 85px;
|
||||
`
|
||||
|
|
@ -68,7 +68,7 @@ const ArtistInfo = ({ artist, isLoading }: { artist?: Artist; isLoading: boolean
|
|||
) : (
|
||||
<div
|
||||
className={cx(
|
||||
'line-clamp-5 mt-6 overflow-hidden whitespace-pre-wrap text-14 font-bold text-white/40 transition-colors duration-500 hover:text-white/60',
|
||||
'mt-6 line-clamp-5 overflow-hidden whitespace-pre-wrap text-14 font-bold text-white/40 transition-colors duration-500 hover:text-white/60',
|
||||
css`
|
||||
height: 85px;
|
||||
`
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ const Track = ({
|
|||
>
|
||||
{track?.name}
|
||||
</div>
|
||||
<div className='line-clamp-1 mt-1 text-14 font-bold text-neutral-200 dark:text-neutral-700'>
|
||||
<div className='mt-1 line-clamp-1 text-14 font-bold text-neutral-200 dark:text-neutral-700'>
|
||||
{track?.ar.map(a => a.name).join(', ')}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ const categories = [
|
|||
{ id: 'charts', name: 'Charts', component: <Recommend /> },
|
||||
]
|
||||
const categoriesKeys = categories.map(c => c.id)
|
||||
type Key = typeof categoriesKeys[number]
|
||||
type Key = (typeof categoriesKeys)[number]
|
||||
|
||||
const Browse = () => {
|
||||
const [active, setActive] = useState<Key>('recommend')
|
||||
|
|
@ -60,7 +60,7 @@ const Browse = () => {
|
|||
{/* Topbar background */}
|
||||
<div
|
||||
className={cx(
|
||||
'pointer-events-none fixed top-0 left-10 z-10 hidden lg:block',
|
||||
'pointer-events-none fixed left-10 top-0 z-10 hidden lg:block',
|
||||
css`
|
||||
height: 230px;
|
||||
`
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import settings from '@/web/states/settings'
|
|||
import useUser from '@/web/api/hooks/useUser'
|
||||
|
||||
const collections = ['playlists', 'albums', 'artists', 'videos'] as const
|
||||
type Collection = typeof collections[number]
|
||||
type Collection = (typeof collections)[number]
|
||||
|
||||
const Albums = () => {
|
||||
const { data: albums } = useUserAlbums()
|
||||
|
|
@ -114,7 +114,7 @@ const CollectionTabs = ({ showBg }: { showBg: boolean }) => {
|
|||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className={cx(
|
||||
'pointer-events-none absolute right-0 left-0 z-10',
|
||||
'pointer-events-none absolute left-0 right-0 z-10',
|
||||
css`
|
||||
height: 230px;
|
||||
background-repeat: repeat;
|
||||
|
|
@ -164,7 +164,7 @@ const Collections = () => {
|
|||
<motion.div layout>
|
||||
<CollectionTabs showBg={isScrollReachBottom} />
|
||||
<div
|
||||
className={cx('no-scrollbar overflow-y-auto px-2.5 pt-16 pb-16 lg:px-0')}
|
||||
className={cx('no-scrollbar overflow-y-auto px-2.5 pb-16 pt-16 lg:px-0')}
|
||||
onScroll={onScroll}
|
||||
style={{
|
||||
height: `calc(100vh - ${topbarHeight}px)`,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ const Lyrics = ({ tracksIDs }: { tracksIDs: number[] }) => {
|
|||
const Covers = memo(({ tracks }: { tracks: Track[] }) => {
|
||||
const navigate = useNavigate()
|
||||
return (
|
||||
<div className='mt-6 grid w-full flex-shrink-0 grid-cols-3 gap-2.5 lg:mt-0 lg:ml-8 lg:w-auto'>
|
||||
<div className='mt-6 grid w-full flex-shrink-0 grid-cols-3 gap-2.5 lg:ml-8 lg:mt-0 lg:w-auto'>
|
||||
{tracks.map(track => (
|
||||
<Image
|
||||
src={resizeImage(track.al.picUrl || '', 'md')}
|
||||
|
|
@ -127,7 +127,7 @@ const PlayLikedSongsCard = () => {
|
|||
<div className='flex justify-between'>
|
||||
<button
|
||||
onClick={handlePlay}
|
||||
className='rounded-full bg-brand-700 py-5 px-6 text-16 font-medium text-white'
|
||||
className='rounded-full bg-brand-700 px-6 py-5 text-16 font-medium text-white'
|
||||
>
|
||||
{t`my.playNow`}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -55,10 +55,10 @@ const Track = ({
|
|||
{track?.name}
|
||||
|
||||
{[1318912, 1310848].includes(track?.mark || 0) && (
|
||||
<Icon name='explicit' className='ml-2 mt-px mr-4 h-3.5 w-3.5 text-white/20' />
|
||||
<Icon name='explicit' className='ml-2 mr-4 mt-px h-3.5 w-3.5 text-white/20' />
|
||||
)}
|
||||
</div>
|
||||
<div className='line-clamp-1 mt-1 text-14 font-bold text-white/30'>
|
||||
<div className='mt-1 line-clamp-1 text-14 font-bold text-white/30'>
|
||||
{track?.ar.map((a, index) => (
|
||||
<Fragment key={a.id}>
|
||||
{index > 0 && ', '}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ const Track = ({
|
|||
>
|
||||
{track?.name}
|
||||
</div>
|
||||
<div className='line-clamp-1 mt-1 text-14 font-bold text-neutral-200 text-white/30'>
|
||||
<div className='mt-1 line-clamp-1 text-14 font-bold text-neutral-200 text-white/30'>
|
||||
{track?.ar.map(a => a.name).join(', ')}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -151,7 +151,7 @@ const Search = () => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className='mt-6 mb-8 text-4xl font-semibold dark:text-white'>
|
||||
<div className='mb-8 mt-6 text-4xl font-semibold dark:text-white'>
|
||||
<span className='text-white/40'>搜索</span> "{keywords}"
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function Select<T extends string>({
|
|||
<select
|
||||
onChange={e => onChange(e.target.value as T)}
|
||||
value={value}
|
||||
className='h-full w-full appearance-none bg-transparent py-1 pr-7 pl-3 focus:outline-none'
|
||||
className='h-full w-full appearance-none bg-transparent py-1 pl-3 pr-7 focus:outline-none'
|
||||
>
|
||||
{options.map(option => (
|
||||
<option key={option.value} value={option.value}>
|
||||
|
|
@ -71,7 +71,7 @@ export function Input({
|
|||
<div className='mb-1 text-14 font-medium text-white/30'>Host</div>
|
||||
<div className='inline-block rounded-md bg-neutral-800 font-medium text-neutral-400'>
|
||||
<input
|
||||
className='appearance-none bg-transparent py-1 px-3'
|
||||
className='appearance-none bg-transparent px-3 py-1'
|
||||
onChange={e => onChange(e.target.value)}
|
||||
{...{ type, value }}
|
||||
/>
|
||||
|
|
@ -80,11 +80,20 @@ export function Input({
|
|||
)
|
||||
}
|
||||
|
||||
export function Button({ children, onClick }: { children: React.ReactNode; onClick: () => void }) {
|
||||
export function Button({
|
||||
disalbed: disabled,
|
||||
children,
|
||||
onClick,
|
||||
}: {
|
||||
disalbed?: boolean
|
||||
children: React.ReactNode
|
||||
onClick: () => void
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
className='rounded-md bg-neutral-800 py-1 px-3 font-medium text-neutral-400 transition-colors duration-300 hover:bg-neutral-700 hover:text-neutral-300'
|
||||
disabled={disabled}
|
||||
className='rounded-md bg-neutral-800 px-3 py-1 font-medium text-neutral-400 transition-colors duration-300 hover:bg-neutral-700 hover:text-neutral-300 disabled:opacity-10'
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
|
|
@ -104,5 +113,9 @@ export function Option({ children }: { children: React.ReactNode }) {
|
|||
}
|
||||
|
||||
export function OptionText({ children }: { children: React.ReactNode }) {
|
||||
return <div className='text-16 font-medium text-neutral-400'>{children}</div>
|
||||
return (
|
||||
<div className='line-clamp-1 flex-shrink-0 text-16 font-medium text-neutral-400'>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ import Slider from '@/web/components/Slider'
|
|||
import { cx } from '@emotion/css'
|
||||
import player from '@/web/states/player'
|
||||
import { ceil } from 'lodash'
|
||||
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { useCopyToClipboard } from 'react-use'
|
||||
|
||||
function Player() {
|
||||
return (
|
||||
<div className={cx(`space-y-7`)}>
|
||||
<FindTrackOnYouTube />
|
||||
<VolumeSlider />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -59,31 +61,4 @@ function FindTrackOnYouTube() {
|
|||
)
|
||||
}
|
||||
|
||||
function VolumeSlider() {
|
||||
const { t } = useTranslation()
|
||||
const { volume } = useSnapshot(player)
|
||||
const onChange = (volume: number) => {
|
||||
player.volume = volume
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<BlockTitle>{t(`settings.volume-control`)}</BlockTitle>
|
||||
<div className='pt-2 pr-1'>
|
||||
<Slider
|
||||
value={volume}
|
||||
min={0}
|
||||
max={1}
|
||||
onChange={onChange}
|
||||
alwaysShowTrack
|
||||
alwaysShowThumb
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-1 flex justify-between text-14 font-bold text-neutral-100'>
|
||||
<span>0</span>
|
||||
<span>{ceil(volume * 100)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Player
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import PageTransition from '@/web/components/PageTransition'
|
|||
import { ease } from '@/web/utils/const'
|
||||
|
||||
export const categoryIds = ['general', 'appearance', 'player', 'lab', 'about'] as const
|
||||
export type Category = typeof categoryIds[number]
|
||||
export type Category = (typeof categoryIds)[number]
|
||||
|
||||
const Sidebar = ({
|
||||
activeCategory,
|
||||
|
|
@ -42,7 +42,7 @@ const Sidebar = ({
|
|||
initial={{ y: 11.5 }}
|
||||
animate={indicatorAnimation}
|
||||
transition={{ type: 'spring', duration: 0.6, bounce: 0.36 }}
|
||||
className='absolute top-0 left-3 mr-2 h-4 w-1 rounded-full bg-brand-700'
|
||||
className='absolute left-3 top-0 mr-2 h-4 w-1 rounded-full bg-brand-700'
|
||||
></motion.div>
|
||||
|
||||
{categories.map(category => (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue