mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Add support for user themes for mui components
This commit is contained in:
parent
3dcb42daac
commit
b5fda71a27
16 changed files with 298 additions and 62 deletions
43
src/themes/UserThemeProvider.tsx
Normal file
43
src/themes/UserThemeProvider.tsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { ThemeProvider } from '@mui/material';
|
||||
import React, { type FC, useState, useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { DASHBOARD_APP_PATHS } from 'apps/dashboard/routes/routes';
|
||||
import { useUserTheme } from 'hooks/useUserTheme';
|
||||
|
||||
import { DEFAULT_THEME, getTheme } from './themes';
|
||||
|
||||
const isDashboardThemePage = (pathname: string) => [
|
||||
// NOTE: The metadata manager doesn't seem to use the dashboard theme
|
||||
DASHBOARD_APP_PATHS.Dashboard,
|
||||
DASHBOARD_APP_PATHS.PluginConfig
|
||||
].some(path => pathname.startsWith(`/${path}`));
|
||||
|
||||
const UserThemeProvider: FC = ({ children }) => {
|
||||
const [ isDashboard, setIsDashboard ] = useState(false);
|
||||
const [ muiTheme, setMuiTheme ] = useState(DEFAULT_THEME);
|
||||
|
||||
const location = useLocation();
|
||||
const { theme, dashboardTheme } = useUserTheme();
|
||||
|
||||
// Check if we are on a dashboard page when the path changes
|
||||
useEffect(() => {
|
||||
setIsDashboard(isDashboardThemePage(location.pathname));
|
||||
}, [ location.pathname ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDashboard) {
|
||||
setMuiTheme(getTheme(dashboardTheme));
|
||||
} else {
|
||||
setMuiTheme(getTheme(theme));
|
||||
}
|
||||
}, [ dashboardTheme, isDashboard, theme ]);
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={muiTheme}>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserThemeProvider;
|
27
src/themes/appletv/index.ts
Normal file
27
src/themes/appletv/index.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import createTheme, { type ThemeOptions } from '@mui/material/styles/createTheme';
|
||||
import merge from 'lodash-es/merge';
|
||||
|
||||
import { DEFAULT_THEME_OPTIONS } from 'themes/defaults';
|
||||
|
||||
const themeOptions: ThemeOptions = {
|
||||
palette: {
|
||||
mode: 'light',
|
||||
background: {
|
||||
default: '#d5e9f2',
|
||||
paper: '#fff'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
MuiAppBar: {
|
||||
styleOverrides: {
|
||||
colorPrimary: {
|
||||
backgroundColor: '#bcbcbc'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const theme = createTheme(merge({}, DEFAULT_THEME_OPTIONS, themeOptions));
|
||||
|
||||
export default theme;
|
16
src/themes/blueradiance/index.ts
Normal file
16
src/themes/blueradiance/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import createTheme, { type ThemeOptions } from '@mui/material/styles/createTheme';
|
||||
import merge from 'lodash-es/merge';
|
||||
|
||||
import { DEFAULT_THEME_OPTIONS } from 'themes/defaults';
|
||||
|
||||
const options: ThemeOptions = {
|
||||
palette: {
|
||||
background: {
|
||||
paper: '#011432'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const theme = createTheme(merge({}, DEFAULT_THEME_OPTIONS, options));
|
||||
|
||||
export default theme;
|
7
src/themes/dark/index.ts
Normal file
7
src/themes/dark/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import createTheme from '@mui/material/styles/createTheme';
|
||||
|
||||
import { DEFAULT_THEME_OPTIONS } from 'themes/defaults';
|
||||
|
||||
const theme = createTheme(DEFAULT_THEME_OPTIONS);
|
||||
|
||||
export default theme;
|
|
@ -1,19 +1,8 @@
|
|||
import { createTheme } from '@mui/material/styles';
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
interface Palette {
|
||||
starIcon: Palette['primary'];
|
||||
}
|
||||
|
||||
interface PaletteOptions {
|
||||
starIcon?: PaletteOptions['primary'];
|
||||
}
|
||||
}
|
||||
import type { ThemeOptions } from '@mui/material/styles/createTheme';
|
||||
|
||||
const LIST_ICON_WIDTH = 36;
|
||||
|
||||
/** The default Jellyfin app theme for mui */
|
||||
const theme = createTheme({
|
||||
export const DEFAULT_THEME_OPTIONS: ThemeOptions = {
|
||||
palette: {
|
||||
mode: 'dark',
|
||||
primary: {
|
||||
|
@ -109,6 +98,4 @@ const theme = createTheme({
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default theme;
|
||||
};
|
30
src/themes/light/index.ts
Normal file
30
src/themes/light/index.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import createTheme, { type ThemeOptions } from '@mui/material/styles/createTheme';
|
||||
import merge from 'lodash-es/merge';
|
||||
|
||||
import { DEFAULT_THEME_OPTIONS } from 'themes/defaults';
|
||||
|
||||
const options: ThemeOptions = {
|
||||
palette: {
|
||||
mode: 'light',
|
||||
background: {
|
||||
default: '#f2f2f2',
|
||||
// NOTE: The original theme uses #303030 for the drawer and app bar but we would need the drawer to use
|
||||
// dark mode for a color that dark to work properly which would require a separate ThemeProvider just for
|
||||
// the drawer... which is not worth the trouble in my opinion
|
||||
paper: '#e8e8e8'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
MuiAppBar: {
|
||||
styleOverrides: {
|
||||
colorPrimary: {
|
||||
backgroundColor: '#e8e8e8'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const theme = createTheme(merge({}, DEFAULT_THEME_OPTIONS, options));
|
||||
|
||||
export default theme;
|
22
src/themes/purplehaze/index.ts
Normal file
22
src/themes/purplehaze/index.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import createTheme, { type ThemeOptions } from '@mui/material/styles/createTheme';
|
||||
import merge from 'lodash-es/merge';
|
||||
|
||||
import { DEFAULT_THEME_OPTIONS } from 'themes/defaults';
|
||||
|
||||
const options: ThemeOptions = {
|
||||
palette: {
|
||||
background: {
|
||||
paper: '#000420'
|
||||
},
|
||||
primary: {
|
||||
main: '#48c3c8'
|
||||
},
|
||||
secondary: {
|
||||
main: '#ff77f1'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const theme = createTheme(merge({}, DEFAULT_THEME_OPTIONS, options));
|
||||
|
||||
export default theme;
|
48
src/themes/themes.ts
Normal file
48
src/themes/themes.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { type Theme } from '@mui/material/styles';
|
||||
|
||||
import appletv from './appletv';
|
||||
import blueradiance from './blueradiance';
|
||||
import dark from './dark';
|
||||
import light from './light';
|
||||
import purplehaze from './purplehaze';
|
||||
import wmc from './wmc';
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
interface Palette {
|
||||
starIcon: Palette['primary'];
|
||||
}
|
||||
|
||||
interface PaletteOptions {
|
||||
starIcon?: PaletteOptions['primary'];
|
||||
}
|
||||
}
|
||||
|
||||
const ALL_THEMES = {
|
||||
appletv,
|
||||
blueradiance,
|
||||
dark,
|
||||
light,
|
||||
purplehaze,
|
||||
wmc
|
||||
};
|
||||
|
||||
/** The default theme if a user has not selected a preferred theme. */
|
||||
export const DEFAULT_THEME = dark;
|
||||
|
||||
/**
|
||||
* Gets a MUI Theme by its string id. Returns the default theme if no matching theme is found.
|
||||
*/
|
||||
export function getTheme(id?: string): Theme {
|
||||
if (!id) {
|
||||
console.info('[getTheme] no theme id; returning default theme');
|
||||
return DEFAULT_THEME;
|
||||
}
|
||||
|
||||
console.info('[getTheme] getting theme "%s"', id);
|
||||
if (Object.keys(ALL_THEMES).includes(id)) {
|
||||
return ALL_THEMES[id as keyof typeof ALL_THEMES];
|
||||
}
|
||||
|
||||
console.warn('[getTheme] theme "%s" not found; returning default theme', id);
|
||||
return DEFAULT_THEME;
|
||||
}
|
16
src/themes/wmc/index.ts
Normal file
16
src/themes/wmc/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import createTheme, { type ThemeOptions } from '@mui/material/styles/createTheme';
|
||||
import merge from 'lodash-es/merge';
|
||||
|
||||
import { DEFAULT_THEME_OPTIONS } from 'themes/defaults';
|
||||
|
||||
const options: ThemeOptions = {
|
||||
palette: {
|
||||
background: {
|
||||
paper: '#0c2450'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const theme = createTheme(merge({}, DEFAULT_THEME_OPTIONS, options));
|
||||
|
||||
export default theme;
|
Loading…
Add table
Add a link
Reference in a new issue