mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-16 05:08:04 +00:00
feat: 增加设置页面和支持自定义强调色
This commit is contained in:
parent
7e892997bd
commit
bc696ca59f
14 changed files with 499 additions and 41 deletions
|
|
@ -1,6 +1,41 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { colord } = require('colord')
|
||||
const colors = require('tailwindcss/colors')
|
||||
|
||||
const replaceBrandColorWithCssVar = () => {
|
||||
const blues = Object.entries(colors.blue).map(([key, value]) => {
|
||||
const c = colord(value).toRgb()
|
||||
return {
|
||||
key,
|
||||
rgb: `${c.r} ${c.g} ${c.b}`,
|
||||
}
|
||||
})
|
||||
return {
|
||||
postcssPlugin: 'replaceBrandColorWithCssVar',
|
||||
Declaration(decl) {
|
||||
let value = decl.value
|
||||
blues.forEach(blue => {
|
||||
value = value.replace(
|
||||
`rgb(${blue.rgb}`,
|
||||
`rgb(var(--brand-color-${blue.key})`
|
||||
)
|
||||
})
|
||||
// if (decl.value !== value) {
|
||||
// console.log({
|
||||
// before: decl.value,
|
||||
// after: value,
|
||||
// })
|
||||
// }
|
||||
decl.value = value
|
||||
},
|
||||
}
|
||||
}
|
||||
replaceBrandColorWithCssVar.postcss = true
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('tailwindcss'),
|
||||
require('autoprefixer'),
|
||||
replaceBrandColorWithCssVar,
|
||||
],
|
||||
}
|
||||
|
|
|
|||
48
scripts/generate.accent.color.css.js
Normal file
48
scripts/generate.accent.color.css.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const colors = require('tailwindcss/colors')
|
||||
const { colord } = require('colord')
|
||||
const prettier = require('prettier')
|
||||
const fs = require('fs')
|
||||
const prettierConfig = require('../prettier.config.js')
|
||||
|
||||
const pickedColors = {
|
||||
blue: colors.blue,
|
||||
red: colors.red,
|
||||
orange: colors.orange,
|
||||
amber: colors.amber,
|
||||
yellow: colors.yellow,
|
||||
lime: colors.lime,
|
||||
green: colors.green,
|
||||
emerald: colors.emerald,
|
||||
teal: colors.teal,
|
||||
cyan: colors.cyan,
|
||||
sky: colors.sky,
|
||||
indigo: colors.indigo,
|
||||
violet: colors.violet,
|
||||
purple: colors.purple,
|
||||
fuchsia: colors.fuchsia,
|
||||
pink: colors.pink,
|
||||
rose: colors.rose,
|
||||
}
|
||||
|
||||
const colorsCss = {}
|
||||
Object.entries(pickedColors).forEach(([name, colors]) => {
|
||||
let tmp = ''
|
||||
Object.entries(colors).map(([key, value]) => {
|
||||
const c = colord(value).toRgb()
|
||||
tmp = `${tmp}
|
||||
--brand-color-${key}: ${c.r} ${c.g} ${c.b};`
|
||||
})
|
||||
colorsCss[name] = tmp
|
||||
})
|
||||
|
||||
let css = ''
|
||||
Object.entries(colorsCss).forEach(([name, color]) => {
|
||||
css = `${css}
|
||||
${name === 'blue' ? ':root' : `[data-accent-color='${name}']`} {${color}
|
||||
}
|
||||
`
|
||||
})
|
||||
|
||||
const formatted = prettier.format(css, { ...prettierConfig, parser: 'css' })
|
||||
fs.writeFileSync('./src/renderer/styles/accentColor.scss', formatted)
|
||||
39
src/renderer/components/Avatar.tsx
Normal file
39
src/renderer/components/Avatar.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { resizeImage } from '../utils/common'
|
||||
import useUser from '../hooks/useUser'
|
||||
import SvgIcon from './SvgIcon'
|
||||
|
||||
const Avatar = ({ size }: { size?: string }) => {
|
||||
const navigate = useNavigate()
|
||||
const { data: user } = useUser()
|
||||
|
||||
const avatarUrl = user?.profile?.avatarUrl
|
||||
? resizeImage(user?.profile?.avatarUrl ?? '', 'sm')
|
||||
: ''
|
||||
|
||||
return (
|
||||
<>
|
||||
{avatarUrl ? (
|
||||
<img
|
||||
src={avatarUrl}
|
||||
onClick={() => navigate('/login')}
|
||||
className={classNames(
|
||||
'app-region-no-drag rounded-full bg-gray-100 dark:bg-gray-700',
|
||||
size || 'h-9 w-9'
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<div onClick={() => navigate('/login')}>
|
||||
<SvgIcon
|
||||
name='user'
|
||||
className={classNames(
|
||||
'rounded-full bg-black/[.06] p-1 text-gray-500 dark:bg-white/5',
|
||||
size || 'h-9 w-9'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Avatar
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import SvgIcon from '@/renderer/components/SvgIcon'
|
||||
import useScroll from '@/renderer/hooks/useScroll'
|
||||
import useUser from '@/renderer/hooks/useUser'
|
||||
import { resizeImage } from '@/renderer/utils/common'
|
||||
import Avatar from './Avatar'
|
||||
|
||||
const NavigationButtons = () => {
|
||||
const navigate = useNavigate()
|
||||
|
|
@ -67,9 +66,10 @@ const SearchBox = () => {
|
|||
}
|
||||
|
||||
const Settings = () => {
|
||||
const navigate = useNavigate()
|
||||
return (
|
||||
<div
|
||||
onClick={() => toast('施工中...')}
|
||||
onClick={() => navigate('/settings')}
|
||||
className='app-region-no-drag btn-hover-animation rounded-lg p-2.5 text-gray-500 transition duration-300 after:rounded-full after:bg-black/[.06] hover:text-gray-900 dark:text-gray-300 dark:after:bg-white/10 dark:hover:text-gray-200'
|
||||
>
|
||||
<SvgIcon className='h-[1.125rem] w-[1.125rem]' name='settings' />
|
||||
|
|
@ -77,34 +77,6 @@ const Settings = () => {
|
|||
)
|
||||
}
|
||||
|
||||
const Avatar = () => {
|
||||
const navigate = useNavigate()
|
||||
const { data: user } = useUser()
|
||||
|
||||
const avatarUrl = user?.profile?.avatarUrl
|
||||
? resizeImage(user?.profile?.avatarUrl ?? '', 'sm')
|
||||
: ''
|
||||
|
||||
return (
|
||||
<>
|
||||
{avatarUrl ? (
|
||||
<img
|
||||
src={avatarUrl}
|
||||
onClick={() => navigate('/login')}
|
||||
className='app-region-no-drag h-9 w-9 rounded-full bg-gray-100 dark:bg-gray-700'
|
||||
/>
|
||||
) : (
|
||||
<div onClick={() => navigate('/login')}>
|
||||
<SvgIcon
|
||||
name='user'
|
||||
className='h-9 w-9 rounded-full bg-black/[.06] p-1 text-gray-500'
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const Topbar = () => {
|
||||
/**
|
||||
* Show topbar background when scroll down
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import './utils/initLog'
|
||||
import './utils/theme'
|
||||
import { StrictMode } from 'react'
|
||||
import * as ReactDOMClient from 'react-dom/client'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
|
|
@ -6,6 +7,7 @@ import * as Sentry from '@sentry/react'
|
|||
import { BrowserTracing } from '@sentry/tracing'
|
||||
import 'virtual:svg-icons-register'
|
||||
import './styles/global.scss'
|
||||
import './styles/accentColor.scss'
|
||||
import App from './App'
|
||||
import pkg from '../../package.json'
|
||||
import ReactGA from 'react-ga4'
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
const Settings = () => {
|
||||
return <div></div>
|
||||
}
|
||||
|
||||
export default Settings
|
||||
53
src/renderer/pages/Settings/Appearance.tsx
Normal file
53
src/renderer/pages/Settings/Appearance.tsx
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { state } from '@/renderer/store'
|
||||
import { changeAccentColor } from '@/renderer/utils/theme'
|
||||
|
||||
const AccentColor = () => {
|
||||
const colors = {
|
||||
red: 'bg-red-500',
|
||||
orange: 'bg-orange-500',
|
||||
amber: 'bg-amber-500',
|
||||
yellow: 'bg-yellow-500',
|
||||
lime: 'bg-lime-500',
|
||||
green: 'bg-green-500',
|
||||
emerald: 'bg-emerald-500',
|
||||
teal: 'bg-teal-500',
|
||||
cyan: 'bg-cyan-500',
|
||||
sky: 'bg-sky-500',
|
||||
blue: 'bg-blue-500',
|
||||
indigo: 'bg-indigo-500',
|
||||
violet: 'bg-violet-500',
|
||||
purple: 'bg-purple-500',
|
||||
fuchsia: 'bg-fuchsia-500',
|
||||
pink: 'bg-pink-500',
|
||||
rose: 'bg-rose-500',
|
||||
}
|
||||
|
||||
const changeColor = (color: string) => {
|
||||
state.settings.accentColor = color
|
||||
changeAccentColor(color)
|
||||
}
|
||||
return (
|
||||
<div className='mt-4 flex'>
|
||||
{Object.entries(colors).map(([color, bg]) => (
|
||||
<div
|
||||
key={color}
|
||||
className={classNames(bg, 'mr-3 h-6 w-6 rounded-full')}
|
||||
onClick={() => changeColor(color)}
|
||||
></div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Appearance = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className='text-xl dark:text-white/70'>主题</div>
|
||||
<div className='mt-3 h-px w-full bg-white/10'></div>
|
||||
|
||||
<AccentColor />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Appearance
|
||||
80
src/renderer/pages/Settings/Settings.tsx
Normal file
80
src/renderer/pages/Settings/Settings.tsx
Normal file
File diff suppressed because one or more lines are too long
0
src/renderer/pages/Settings/Sidebar.tsx
Normal file
0
src/renderer/pages/Settings/Sidebar.tsx
Normal file
3
src/renderer/pages/Settings/index.ts
Normal file
3
src/renderer/pages/Settings/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import Settings from './Settings'
|
||||
|
||||
export default Settings
|
||||
|
|
@ -9,6 +9,7 @@ interface Store {
|
|||
}
|
||||
settings: {
|
||||
showSidebar: boolean
|
||||
accentColor: string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -19,6 +20,7 @@ const initialState: Store = {
|
|||
},
|
||||
settings: {
|
||||
showSidebar: true,
|
||||
accentColor: 'blue',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
220
src/renderer/styles/accentColor.scss
Normal file
220
src/renderer/styles/accentColor.scss
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
:root {
|
||||
--brand-color-50: 239 246 255;
|
||||
--brand-color-100: 219 234 254;
|
||||
--brand-color-200: 191 219 254;
|
||||
--brand-color-300: 147 197 253;
|
||||
--brand-color-400: 96 165 250;
|
||||
--brand-color-500: 59 130 246;
|
||||
--brand-color-600: 37 99 235;
|
||||
--brand-color-700: 29 78 216;
|
||||
--brand-color-800: 30 64 175;
|
||||
--brand-color-900: 30 58 138;
|
||||
}
|
||||
|
||||
[data-accent-color='red'] {
|
||||
--brand-color-50: 254 242 242;
|
||||
--brand-color-100: 254 226 226;
|
||||
--brand-color-200: 254 202 202;
|
||||
--brand-color-300: 252 165 165;
|
||||
--brand-color-400: 248 113 113;
|
||||
--brand-color-500: 239 68 68;
|
||||
--brand-color-600: 220 38 38;
|
||||
--brand-color-700: 185 28 28;
|
||||
--brand-color-800: 153 27 27;
|
||||
--brand-color-900: 127 29 29;
|
||||
}
|
||||
|
||||
[data-accent-color='orange'] {
|
||||
--brand-color-50: 255 247 237;
|
||||
--brand-color-100: 255 237 213;
|
||||
--brand-color-200: 254 215 170;
|
||||
--brand-color-300: 253 186 116;
|
||||
--brand-color-400: 251 146 60;
|
||||
--brand-color-500: 249 115 22;
|
||||
--brand-color-600: 234 88 12;
|
||||
--brand-color-700: 194 65 12;
|
||||
--brand-color-800: 154 52 18;
|
||||
--brand-color-900: 124 45 18;
|
||||
}
|
||||
|
||||
[data-accent-color='amber'] {
|
||||
--brand-color-50: 255 251 235;
|
||||
--brand-color-100: 254 243 199;
|
||||
--brand-color-200: 253 230 138;
|
||||
--brand-color-300: 252 211 77;
|
||||
--brand-color-400: 251 191 36;
|
||||
--brand-color-500: 245 158 11;
|
||||
--brand-color-600: 217 119 6;
|
||||
--brand-color-700: 180 83 9;
|
||||
--brand-color-800: 146 64 14;
|
||||
--brand-color-900: 120 53 15;
|
||||
}
|
||||
|
||||
[data-accent-color='yellow'] {
|
||||
--brand-color-50: 254 252 232;
|
||||
--brand-color-100: 254 249 195;
|
||||
--brand-color-200: 254 240 138;
|
||||
--brand-color-300: 253 224 71;
|
||||
--brand-color-400: 250 204 21;
|
||||
--brand-color-500: 234 179 8;
|
||||
--brand-color-600: 202 138 4;
|
||||
--brand-color-700: 161 98 7;
|
||||
--brand-color-800: 133 77 14;
|
||||
--brand-color-900: 113 63 18;
|
||||
}
|
||||
|
||||
[data-accent-color='lime'] {
|
||||
--brand-color-50: 247 254 231;
|
||||
--brand-color-100: 236 252 203;
|
||||
--brand-color-200: 217 249 157;
|
||||
--brand-color-300: 190 242 100;
|
||||
--brand-color-400: 163 230 53;
|
||||
--brand-color-500: 132 204 22;
|
||||
--brand-color-600: 101 163 13;
|
||||
--brand-color-700: 77 124 15;
|
||||
--brand-color-800: 63 98 18;
|
||||
--brand-color-900: 54 83 20;
|
||||
}
|
||||
|
||||
[data-accent-color='green'] {
|
||||
--brand-color-50: 240 253 244;
|
||||
--brand-color-100: 220 252 231;
|
||||
--brand-color-200: 187 247 208;
|
||||
--brand-color-300: 134 239 172;
|
||||
--brand-color-400: 74 222 128;
|
||||
--brand-color-500: 34 197 94;
|
||||
--brand-color-600: 22 163 74;
|
||||
--brand-color-700: 21 128 61;
|
||||
--brand-color-800: 22 101 52;
|
||||
--brand-color-900: 20 83 45;
|
||||
}
|
||||
|
||||
[data-accent-color='emerald'] {
|
||||
--brand-color-50: 236 253 245;
|
||||
--brand-color-100: 209 250 229;
|
||||
--brand-color-200: 167 243 208;
|
||||
--brand-color-300: 110 231 183;
|
||||
--brand-color-400: 52 211 153;
|
||||
--brand-color-500: 16 185 129;
|
||||
--brand-color-600: 5 150 105;
|
||||
--brand-color-700: 4 120 87;
|
||||
--brand-color-800: 6 95 70;
|
||||
--brand-color-900: 6 78 59;
|
||||
}
|
||||
|
||||
[data-accent-color='teal'] {
|
||||
--brand-color-50: 240 253 250;
|
||||
--brand-color-100: 204 251 241;
|
||||
--brand-color-200: 153 246 228;
|
||||
--brand-color-300: 94 234 212;
|
||||
--brand-color-400: 45 212 191;
|
||||
--brand-color-500: 20 184 166;
|
||||
--brand-color-600: 13 148 136;
|
||||
--brand-color-700: 15 118 110;
|
||||
--brand-color-800: 17 94 89;
|
||||
--brand-color-900: 19 78 74;
|
||||
}
|
||||
|
||||
[data-accent-color='cyan'] {
|
||||
--brand-color-50: 236 254 255;
|
||||
--brand-color-100: 207 250 254;
|
||||
--brand-color-200: 165 243 252;
|
||||
--brand-color-300: 103 232 249;
|
||||
--brand-color-400: 34 211 238;
|
||||
--brand-color-500: 6 182 212;
|
||||
--brand-color-600: 8 145 178;
|
||||
--brand-color-700: 14 116 144;
|
||||
--brand-color-800: 21 94 117;
|
||||
--brand-color-900: 22 78 99;
|
||||
}
|
||||
|
||||
[data-accent-color='sky'] {
|
||||
--brand-color-50: 240 249 255;
|
||||
--brand-color-100: 224 242 254;
|
||||
--brand-color-200: 186 230 253;
|
||||
--brand-color-300: 125 211 252;
|
||||
--brand-color-400: 56 189 248;
|
||||
--brand-color-500: 14 165 233;
|
||||
--brand-color-600: 2 132 199;
|
||||
--brand-color-700: 3 105 161;
|
||||
--brand-color-800: 7 89 133;
|
||||
--brand-color-900: 12 74 110;
|
||||
}
|
||||
|
||||
[data-accent-color='indigo'] {
|
||||
--brand-color-50: 238 242 255;
|
||||
--brand-color-100: 224 231 255;
|
||||
--brand-color-200: 199 210 254;
|
||||
--brand-color-300: 165 180 252;
|
||||
--brand-color-400: 129 140 248;
|
||||
--brand-color-500: 99 102 241;
|
||||
--brand-color-600: 79 70 229;
|
||||
--brand-color-700: 67 56 202;
|
||||
--brand-color-800: 55 48 163;
|
||||
--brand-color-900: 49 46 129;
|
||||
}
|
||||
|
||||
[data-accent-color='violet'] {
|
||||
--brand-color-50: 245 243 255;
|
||||
--brand-color-100: 237 233 254;
|
||||
--brand-color-200: 221 214 254;
|
||||
--brand-color-300: 196 181 253;
|
||||
--brand-color-400: 167 139 250;
|
||||
--brand-color-500: 139 92 246;
|
||||
--brand-color-600: 124 58 237;
|
||||
--brand-color-700: 109 40 217;
|
||||
--brand-color-800: 91 33 182;
|
||||
--brand-color-900: 76 29 149;
|
||||
}
|
||||
|
||||
[data-accent-color='purple'] {
|
||||
--brand-color-50: 250 245 255;
|
||||
--brand-color-100: 243 232 255;
|
||||
--brand-color-200: 233 213 255;
|
||||
--brand-color-300: 216 180 254;
|
||||
--brand-color-400: 192 132 252;
|
||||
--brand-color-500: 168 85 247;
|
||||
--brand-color-600: 147 51 234;
|
||||
--brand-color-700: 126 34 206;
|
||||
--brand-color-800: 107 33 168;
|
||||
--brand-color-900: 88 28 135;
|
||||
}
|
||||
|
||||
[data-accent-color='fuchsia'] {
|
||||
--brand-color-50: 253 244 255;
|
||||
--brand-color-100: 250 232 255;
|
||||
--brand-color-200: 245 208 254;
|
||||
--brand-color-300: 240 171 252;
|
||||
--brand-color-400: 232 121 249;
|
||||
--brand-color-500: 217 70 239;
|
||||
--brand-color-600: 192 38 211;
|
||||
--brand-color-700: 162 28 175;
|
||||
--brand-color-800: 134 25 143;
|
||||
--brand-color-900: 112 26 117;
|
||||
}
|
||||
|
||||
[data-accent-color='pink'] {
|
||||
--brand-color-50: 253 242 248;
|
||||
--brand-color-100: 252 231 243;
|
||||
--brand-color-200: 251 207 232;
|
||||
--brand-color-300: 249 168 212;
|
||||
--brand-color-400: 244 114 182;
|
||||
--brand-color-500: 236 72 153;
|
||||
--brand-color-600: 219 39 119;
|
||||
--brand-color-700: 190 24 93;
|
||||
--brand-color-800: 157 23 77;
|
||||
--brand-color-900: 131 24 67;
|
||||
}
|
||||
|
||||
[data-accent-color='rose'] {
|
||||
--brand-color-50: 255 241 242;
|
||||
--brand-color-100: 255 228 230;
|
||||
--brand-color-200: 254 205 211;
|
||||
--brand-color-300: 253 164 175;
|
||||
--brand-color-400: 251 113 133;
|
||||
--brand-color-500: 244 63 94;
|
||||
--brand-color-600: 225 29 72;
|
||||
--brand-color-700: 190 18 60;
|
||||
--brand-color-800: 159 18 57;
|
||||
--brand-color-900: 136 19 55;
|
||||
}
|
||||
8
src/renderer/utils/theme.ts
Normal file
8
src/renderer/utils/theme.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export const changeAccentColor = (color: string) => {
|
||||
document.body.setAttribute('data-accent-color', color)
|
||||
}
|
||||
|
||||
const stateString = localStorage.getItem('state')
|
||||
const state = stateString ? JSON.parse(stateString) : {}
|
||||
|
||||
changeAccentColor(state.settings.accentColor || 'blue')
|
||||
|
|
@ -10,6 +10,7 @@ module.exports = {
|
|||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
...colors,
|
||||
brand: colors.blue,
|
||||
gray: colors.neutral,
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue