mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-16 21:28:06 +00:00
feat: updates
This commit is contained in:
parent
9a52681687
commit
840a5b8e9b
104 changed files with 1645 additions and 13494 deletions
|
|
@ -37,15 +37,10 @@ const AccentColor = () => {
|
|||
{Object.entries(colors).map(([color, bg]) => (
|
||||
<div
|
||||
key={color}
|
||||
className={cx(
|
||||
bg,
|
||||
'mr-2.5 flex h-5 w-5 items-center justify-center rounded-full'
|
||||
)}
|
||||
className={cx(bg, 'mr-2.5 flex h-5 w-5 items-center justify-center rounded-full')}
|
||||
onClick={() => changeColor(color)}
|
||||
>
|
||||
{color === accentColor && (
|
||||
<div className='h-1.5 w-1.5 rounded-full bg-white'></div>
|
||||
)}
|
||||
{color === accentColor && <div className='h-1.5 w-1.5 rounded-full bg-white'></div>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -55,23 +50,19 @@ const AccentColor = () => {
|
|||
|
||||
const Theme = () => {
|
||||
return (
|
||||
<div className='mt-4'>
|
||||
<div className='mb-2 dark:text-white'>主题</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<>
|
||||
<div className='text-xl font-medium text-gray-800 dark:text-white/70'>主题</div>
|
||||
<div className='mt-3 h-px w-full bg-black/5 dark:bg-white/10'></div>
|
||||
<AccentColor />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const Appearance = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className='text-xl font-medium text-gray-800 dark:text-white/70'>
|
||||
主题
|
||||
</div>
|
||||
<div className='mt-3 h-px w-full bg-black/5 dark:bg-white/10'></div>
|
||||
|
||||
<AccentColor />
|
||||
<Theme />
|
||||
<span className='text-white'>开发中</span>
|
||||
{/* <Theme /> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
108
packages/web/pages/Settings/Controls.tsx
Normal file
108
packages/web/pages/Settings/Controls.tsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import Icon from '@/web/components/Icon'
|
||||
import { cx } from '@emotion/css'
|
||||
import { motion } from 'framer-motion'
|
||||
|
||||
export function Switch({
|
||||
enabled,
|
||||
onChange,
|
||||
}: {
|
||||
enabled: boolean
|
||||
onChange: (enabled: boolean) => void
|
||||
}) {
|
||||
return (
|
||||
<motion.div
|
||||
className={cx(
|
||||
'flex w-11 items-center justify-start rounded-full p-1 transition-colors duration-500',
|
||||
enabled ? 'bg-brand-700' : 'bg-white/10'
|
||||
)}
|
||||
onClick={() => onChange(!enabled)}
|
||||
>
|
||||
<motion.div
|
||||
animate={{ x: enabled ? 16 : 0 }}
|
||||
className='h-5 w-5 rounded-full bg-white shadow-sm'
|
||||
></motion.div>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
export function Select<T extends string>({
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
options: { name: string; value: T }[]
|
||||
value: T
|
||||
onChange: (value: T) => void
|
||||
}) {
|
||||
return (
|
||||
<div className='relative inline-block rounded-md bg-neutral-800 font-medium text-neutral-400'>
|
||||
<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'
|
||||
>
|
||||
{options.map(option => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<Icon
|
||||
name='dropdown-triangle'
|
||||
className='pointer-events-none absolute right-2.5 h-2.5 w-2.5 text-white/15'
|
||||
style={{ top: '11px' }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function Input({
|
||||
value,
|
||||
onChange,
|
||||
type = 'text',
|
||||
}: {
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
type?: 'text' | 'password' | 'number'
|
||||
}) {
|
||||
return (
|
||||
<div className=''>
|
||||
<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'
|
||||
onChange={e => onChange(e.target.value)}
|
||||
{...{ type, value }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function Button({ children, onClick }: { 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'
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export function BlockTitle({ children }: { children: React.ReactNode }) {
|
||||
return <div className='text-21 font-medium text-neutral-100'>{children}</div>
|
||||
}
|
||||
|
||||
export function BlockDescription({ children }: { children: React.ReactNode }) {
|
||||
return <div className='my-1 text-16 font-medium text-white/30'>{children}</div>
|
||||
}
|
||||
|
||||
export function Option({ children }: { children: React.ReactNode }) {
|
||||
return <div className='my-3 flex items-center justify-between'>{children}</div>
|
||||
}
|
||||
|
||||
export function OptionText({ children }: { children: React.ReactNode }) {
|
||||
return <div className='text-16 font-medium text-neutral-400'>{children}</div>
|
||||
}
|
||||
86
packages/web/pages/Settings/General.tsx
Normal file
86
packages/web/pages/Settings/General.tsx
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import { SupportedLanguage } from '@/web/i18n/i18n'
|
||||
import persistedUiStates from '@/web/states/persistedUiStates'
|
||||
import settings from '@/web/states/settings'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { BlockTitle, OptionText, Select, Option, Switch } from './Controls'
|
||||
|
||||
function General() {
|
||||
return (
|
||||
<div>
|
||||
<Language />
|
||||
<AppleMusic />
|
||||
<NeteaseMusic />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Language() {
|
||||
const { t } = useTranslation()
|
||||
const supportedLanguages: { name: string; value: SupportedLanguage }[] = [
|
||||
{ name: 'English', value: 'en-US' },
|
||||
{ name: '简体中文', value: 'zh-CN' },
|
||||
]
|
||||
const { language } = useSnapshot(settings)
|
||||
const setLanguage = (language: SupportedLanguage) => {
|
||||
settings.language = language
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<BlockTitle>Language</BlockTitle>
|
||||
<Option>
|
||||
<OptionText>{t`settings.general-choose-language`}</OptionText>
|
||||
<Select options={supportedLanguages} value={language} onChange={setLanguage} />
|
||||
</Option>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function AppleMusic() {
|
||||
const { playAnimatedArtworkFromApple, priorityDisplayOfAlbumArtistDescriptionFromAppleMusic } =
|
||||
useSnapshot(settings)
|
||||
|
||||
return (
|
||||
<div className='mt-7'>
|
||||
<BlockTitle>Apple Music</BlockTitle>
|
||||
<Option>
|
||||
<OptionText>Play Animated Artwork from Apple Music</OptionText>
|
||||
<Switch
|
||||
enabled={playAnimatedArtworkFromApple}
|
||||
onChange={v => (settings.playAnimatedArtworkFromApple = v)}
|
||||
/>
|
||||
</Option>
|
||||
<Option>
|
||||
<OptionText>Priority Display of Album/Artist Description from Apple Music</OptionText>
|
||||
<Switch
|
||||
enabled={priorityDisplayOfAlbumArtistDescriptionFromAppleMusic}
|
||||
onChange={v => (settings.priorityDisplayOfAlbumArtistDescriptionFromAppleMusic = v)}
|
||||
/>
|
||||
</Option>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function NeteaseMusic() {
|
||||
const { displayPlaylistsFromNeteaseMusic } = useSnapshot(settings)
|
||||
return (
|
||||
<div className='mt-7'>
|
||||
<BlockTitle>Netease Music</BlockTitle>
|
||||
<Option>
|
||||
<OptionText>Display Playlists from Netease Music</OptionText>
|
||||
<Switch
|
||||
enabled={displayPlaylistsFromNeteaseMusic}
|
||||
onChange={v => {
|
||||
settings.displayPlaylistsFromNeteaseMusic = v
|
||||
if (persistedUiStates.librarySelectedTab === 'playlists') {
|
||||
persistedUiStates.librarySelectedTab = 'albums'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Option>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default General
|
||||
53
packages/web/pages/Settings/Player.tsx
Normal file
53
packages/web/pages/Settings/Player.tsx
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import settings from '@/web/states/settings'
|
||||
import toast from 'react-hot-toast'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { BlockDescription, BlockTitle, Button, Option, OptionText, Switch } from './Controls'
|
||||
|
||||
function Player() {
|
||||
return (
|
||||
<div>
|
||||
<FindTrackOnYouTube />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FindTrackOnYouTube() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { enableFindTrackOnYouTube, httpProxyForYouTube } = useSnapshot(settings)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BlockTitle>{t`settings.player-youtube-unlock`}</BlockTitle>
|
||||
<BlockDescription>
|
||||
Find alternative track on YouTube if not available on NetEase.
|
||||
</BlockDescription>
|
||||
|
||||
{/* Switch */}
|
||||
<Option>
|
||||
<OptionText>Enable YouTube Unlock </OptionText>
|
||||
<Switch
|
||||
enabled={enableFindTrackOnYouTube}
|
||||
onChange={value => (settings.enableFindTrackOnYouTube = value)}
|
||||
/>
|
||||
</Option>
|
||||
|
||||
{/* Proxy */}
|
||||
{/* <Option>
|
||||
<OptionText>
|
||||
HTTP Proxy config for connecting to YouTube {httpProxyForYouTube?.host && '(Configured)'}
|
||||
</OptionText>
|
||||
<Button
|
||||
onClick={() => {
|
||||
toast('开发中')
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
</Option> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Player
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,44 +0,0 @@
|
|||
const UnblockNeteaseMusic = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className='text-xl font-medium text-gray-800 dark:text-white/70'>
|
||||
UnblockNeteaseMusic
|
||||
</div>
|
||||
<div className='mt-3 h-px w-full bg-black/5 dark:bg-white/10'></div>
|
||||
|
||||
<div>
|
||||
音源:
|
||||
<div>
|
||||
<input type='checkbox' id='migu' value='migu' />
|
||||
<label htmlFor='migu'>migu</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type='checkbox' id='youtube' value='youtube' />
|
||||
<label htmlFor='youtube'>youtube</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type='checkbox' id='kugou' value='kugou' />
|
||||
<label htmlFor='kugou'>kugou</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type='checkbox' id='kuwo' value='kuwo' />
|
||||
<label htmlFor='kuwo'>kuwo</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type='checkbox' id='qq' value='qq' />
|
||||
<label htmlFor='qq'>qq</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type='checkbox' id='bilibili' value='bilibili' />
|
||||
<label htmlFor='bilibili'>bilibili</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type='checkbox' id='joox' value='joox' />
|
||||
<label htmlFor='joox'>joox</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UnblockNeteaseMusic
|
||||
44
packages/web/pages/Settings/UserCard.tsx
Normal file
44
packages/web/pages/Settings/UserCard.tsx
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue