mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-29 14:37:49 +01:00
* fix(ui): make playlist toggle switches visible in all themes The Public and Auto-import switches in the playlist list did not set a color, so Material-UI used the theme's secondary color. Many themes use secondary as a surface color close to the table background, which made checked switches nearly invisible (Catppuccin, Rosé Pine, Monokai, Moonbase and others). Set color="primary" on the playlist switch, like every other switch in the app, and make primary the default MuiSwitch color in useCurrentTheme so future switches cannot regress. Fixes #6272. * refactor(ui): drop secondary switch overrides from themes Dracula, Gruvbox Dark, Tokyo Night and Tokyo Night Light styled checked MuiSwitch colorSecondary to work around the same invisible-switch problem (Gruvbox in #5064). With primary as the default switch color and every switch in the app using it, no switch renders with colorSecondary anymore, so these overrides are dead code.
74 lines
2.4 KiB
JavaScript
74 lines
2.4 KiB
JavaScript
import { useSelector } from 'react-redux'
|
|
import useMediaQuery from '@material-ui/core/useMediaQuery'
|
|
import themes from './index'
|
|
import { AUTO_THEME_ID } from '../consts'
|
|
import config from '../config'
|
|
import { useEffect, useMemo } from 'react'
|
|
|
|
const useCurrentTheme = () => {
|
|
// Runs above the ThemeProvider carrying the prop below, so it needs its own noSsr or the
|
|
// auto theme renders dark first and flips.
|
|
const prefersLightMode = useMediaQuery('(prefers-color-scheme: light)', {
|
|
noSsr: true,
|
|
})
|
|
const theme = useSelector((state) => {
|
|
if (state.theme === AUTO_THEME_ID) {
|
|
return prefersLightMode ? themes.LightTheme : themes.DarkTheme
|
|
}
|
|
const themeName =
|
|
Object.keys(themes).find((t) => t === state.theme) ||
|
|
Object.keys(themes).find(
|
|
(t) => themes[t].themeName === config.defaultTheme,
|
|
) ||
|
|
'DarkTheme'
|
|
return themes[themeName]
|
|
})
|
|
|
|
useEffect(() => {
|
|
const styles = document.getElementsByTagName('style')
|
|
let style
|
|
for (let i = 0; i < styles.length; i++) {
|
|
if (styles[i].id === 'nd-player-style-override') {
|
|
style = styles[i]
|
|
}
|
|
}
|
|
if (theme.player.stylesheet) {
|
|
if (style === undefined) {
|
|
style = document.createElement('style')
|
|
style.id = 'nd-player-style-override'
|
|
style.innerHTML = theme.player.stylesheet
|
|
document.head.appendChild(style)
|
|
} else {
|
|
style.innerHTML = theme.player.stylesheet
|
|
}
|
|
} else {
|
|
if (style !== undefined) {
|
|
document.head.removeChild(style)
|
|
}
|
|
}
|
|
|
|
// Set body background color to match theme (fixes white background on pull-to-refresh)
|
|
const isDark = theme.palette?.type === 'dark'
|
|
const bgColor =
|
|
theme.palette?.background?.default || (isDark ? '#303030' : '#fafafa')
|
|
document.body.style.backgroundColor = bgColor
|
|
}, [theme])
|
|
|
|
// We never server-render, so let media queries resolve on the first render: the default
|
|
// defers them to an effect, which makes every mount paint the wrong breakpoint and reflow.
|
|
return useMemo(
|
|
() => ({
|
|
...theme,
|
|
props: {
|
|
...theme.props,
|
|
MuiUseMediaQuery: { noSsr: true },
|
|
MuiPopover: { disableScrollLock: true },
|
|
// MUI defaults to secondary, which many themes use as a surface color
|
|
MuiSwitch: { color: 'primary' },
|
|
},
|
|
}),
|
|
[theme],
|
|
)
|
|
}
|
|
|
|
export default useCurrentTheme
|