Files
suwayomi-material-you-webui/src/theme.tsx

162 lines
6.5 KiB
TypeScript
Raw Normal View History

/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
2024-05-20 16:28:36 +02:00
import {
createTheme as createMuiTheme,
darken,
Direction,
lighten,
2024-09-04 22:26:40 +02:00
Palette,
2024-08-31 22:42:06 +02:00
responsiveFontSizes,
2024-05-20 16:28:36 +02:00
Theme,
useTheme,
2024-05-20 16:28:36 +02:00
} from '@mui/material/styles';
import { useCallback } from 'react';
2024-09-04 23:46:04 +02:00
import { ThemeMode } from '@/components/context/ThemeModeContext.tsx';
import { MediaQuery } from '@/lib/ui/MediaQuery.tsx';
2024-09-07 01:07:02 +02:00
import { AppTheme, loadThemeFonts } from '@/lib/ui/AppThemes.ts';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
2024-09-06 23:50:38 +02:00
const SCROLLBAR_SIZE = 14;
2024-08-30 15:52:02 +02:00
2024-09-04 22:26:40 +02:00
export const createTheme = (
2024-09-04 23:46:04 +02:00
themeMode: ThemeMode,
2024-09-05 12:20:21 +02:00
appTheme: AppTheme,
2024-09-04 22:26:40 +02:00
pureBlackMode: boolean = false,
2024-09-05 02:35:08 +02:00
direction: Direction = 'ltr',
2024-09-04 22:26:40 +02:00
) => {
2024-09-04 23:46:04 +02:00
const systemMode = MediaQuery.getSystemThemeMode();
2024-09-05 12:20:21 +02:00
const appThemeType = (appTheme.muiTheme.palette as any)?.type ?? appTheme.muiTheme.palette?.mode;
const isStaticThemeMode = !!appThemeType;
const appThemeMode = appThemeType === 'dark' ? ThemeMode.DARK : ThemeMode.LIGHT;
2024-09-05 12:20:21 +02:00
const staticThemeMode = isStaticThemeMode ? appThemeMode : undefined;
const mode = staticThemeMode ?? (themeMode === ThemeMode.SYSTEM ? systemMode : themeMode);
2024-09-04 23:46:04 +02:00
const isDarkMode = mode === ThemeMode.DARK;
2024-09-05 00:08:23 +02:00
const setPureBlackMode = isDarkMode && pureBlackMode;
2024-09-04 22:26:40 +02:00
const baseTheme = createMuiTheme({
2024-04-25 14:07:59 +02:00
direction,
2024-09-05 12:20:21 +02:00
...appTheme.muiTheme,
palette: {
2024-09-04 23:46:04 +02:00
mode,
2024-09-05 12:20:21 +02:00
...(appTheme.muiTheme.palette ?? {}),
},
2024-09-04 22:26:40 +02:00
});
const backgroundTrueBlack: Palette['background'] = {
paper: '#111',
default: '#000',
};
const backgroundDark: Palette['background'] = {
paper: darken(baseTheme.palette.primary.main, 0.75),
default: darken(baseTheme.palette.primary.main, 0.85),
};
const backgroundLight: Palette['background'] = {
paper: lighten(baseTheme.palette.primary.dark, 0.8),
default: lighten(baseTheme.palette.primary.dark, 0.9),
2024-09-04 22:26:40 +02:00
};
const backgroundThemeMode = isDarkMode ? backgroundDark : backgroundLight;
2024-09-05 12:20:21 +02:00
const automaticBackground = setPureBlackMode ? backgroundTrueBlack : backgroundThemeMode;
const appThemeBackground = appTheme.muiTheme.palette?.background;
const requiresAutomaticBackground = setPureBlackMode || !appThemeBackground;
const background = requiresAutomaticBackground ? automaticBackground : appThemeBackground;
2024-09-04 22:26:40 +02:00
const colorTheme = createMuiTheme(baseTheme, {
palette: {
background,
},
});
const suwayomiTheme = createMuiTheme(colorTheme, {
components: {
...appTheme.muiTheme.components,
2024-09-04 22:26:40 +02:00
MuiUseMediaQuery: {
defaultProps: {
noSsr: true,
},
},
2024-09-04 22:26:40 +02:00
MuiCssBaseline: {
...appTheme.muiTheme.components?.MuiCssBaseline,
styleOverrides:
typeof appTheme.muiTheme.components?.MuiCssBaseline?.styleOverrides === 'object'
? {
...appTheme.muiTheme.components?.MuiCssBaseline?.styleOverrides,
'*::-webkit-scrollbar': {
width: `${SCROLLBAR_SIZE}px`,
height: `${SCROLLBAR_SIZE}px`,
// @ts-ignore - '*::-webkit-scrollbar' is a valid key
...appTheme.muiTheme.components?.MuiCssBaseline?.styleOverrides?.[
'*::-webkit-scrollbar'
],
},
'*::-webkit-scrollbar-thumb': {
border: '4px solid rgba(0, 0, 0, 0)',
backgroundClip: 'padding-box',
borderRadius: '9999px',
backgroundColor: `${colorTheme.palette.primary[isDarkMode ? 'dark' : 'light']}`,
// @ts-ignore - '*::-webkit-scrollbar-thumb' is a valid key
...appTheme.muiTheme.components?.MuiCssBaseline?.styleOverrides?.[
'*::-webkit-scrollbar-thumb'
],
},
'*::-webkit-scrollbar-thumb:hover': {
borderWidth: '2px',
// @ts-ignore - '*::-webkit-scrollbar-thumb:hover' is a valid key
...appTheme.muiTheme.components?.MuiCssBaseline?.styleOverrides?.[
'*::-webkit-scrollbar-thumb:hover'
],
},
}
: `
2024-05-20 16:28:36 +02:00
*::-webkit-scrollbar {
2024-09-06 23:32:42 +02:00
width: ${SCROLLBAR_SIZE}px;
height: ${SCROLLBAR_SIZE}px;
2024-05-20 16:28:36 +02:00
}
*::-webkit-scrollbar-thumb {
border: 4px solid rgba(0, 0, 0, 0);
background-clip: padding-box;
border-radius: 9999px;
2024-09-04 22:26:40 +02:00
background-color: ${colorTheme.palette.primary[isDarkMode ? 'dark' : 'light']};
2024-05-20 16:28:36 +02:00
}
*::-webkit-scrollbar-thumb:hover {
border-width: 2px;
}
${appTheme.muiTheme.components?.MuiCssBaseline?.styleOverrides ?? ''}
2024-05-20 16:28:36 +02:00
`,
},
},
2024-09-04 22:26:40 +02:00
});
2024-09-05 02:35:08 +02:00
return responsiveFontSizes(suwayomiTheme);
};
2024-09-05 02:35:08 +02:00
let theme: Theme;
export const getCurrentTheme = () => theme;
export const createAndSetTheme = (...args: Parameters<typeof createTheme>) => {
theme = createTheme(...args);
2024-09-07 01:07:02 +02:00
loadThemeFonts(theme).catch(defaultPromiseErrorHandler('theme::createAndSetTheme'));
2024-08-31 22:42:06 +02:00
return theme;
};
export const getOptionForDirection = <T,>(ltrOption: T, rtlOption: T): T =>
(theme?.direction ?? 'ltr') === 'ltr' ? ltrOption : rtlOption;
export const useGetOptionForDirection = (): typeof getOptionForDirection => {
const muiTheme = useTheme();
return useCallback(
<T,>(...args: Parameters<typeof getOptionForDirection<T>>) => getOptionForDirection(...args),
[muiTheme.direction],
);
};