Use custom themes

This commit is contained in:
schroda
2024-09-05 12:20:21 +02:00
parent ce3de56fcd
commit 12d12ccc48
16 changed files with 869 additions and 357 deletions

View File

@@ -6,120 +6,165 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { PaletteOptions } from '@mui/material/styles';
import { ThemeOptions } from '@mui/material/styles';
import { t as translate } from 'i18next';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
type Theme = { getName: () => string; palette: PaletteOptions };
type Theme = { isCustom: boolean; getName: () => string; muiTheme: ThemeOptions };
const themes = {
default: {
isCustom: false,
getName: () => translate('global.label.default'),
palette: {
primary: {
main: '#5b74ef',
},
secondary: {
main: '#efd65b',
muiTheme: {
palette: {
primary: {
main: '#5b74ef',
},
secondary: {
main: '#efd65b',
},
},
},
},
lavender: {
getName: () => translate('settings.appearance.themes.lavendar'),
palette: {
primary: {
main: '#5c58dc',
},
secondary: {
main: '#d8dc58',
isCustom: false,
getName: () => translate('settings.appearance.theme.themes.lavender'),
muiTheme: {
palette: {
primary: {
main: '#5c58dc',
},
secondary: {
main: '#d8dc58',
},
},
},
},
dune: {
getName: () => translate('settings.appearance.themes.dune'),
palette: {
primary: {
main: '#897869',
},
secondary: {
main: '#697a89',
isCustom: false,
getName: () => translate('settings.appearance.theme.themes.dune'),
muiTheme: {
palette: {
primary: {
main: '#897869',
},
secondary: {
main: '#697a89',
},
},
},
},
rosegold: {
getName: () => translate('settings.appearance.themes.rosegold'),
palette: {
primary: {
main: '#f1a886',
},
secondary: {
main: '#86cff1',
isCustom: false,
getName: () => translate('settings.appearance.theme.themes.rosegold'),
muiTheme: {
palette: {
primary: {
main: '#f1a886',
},
secondary: {
main: '#86cff1',
},
},
},
},
forestDew: {
getName: () => translate('settings.appearance.themes.forest_dew'),
palette: {
primary: {
main: '#53a584',
},
secondary: {
main: '#a55374',
'forest dew': {
isCustom: false,
getName: () => translate('settings.appearance.theme.themes.forest_dew'),
muiTheme: {
palette: {
primary: {
main: '#53a584',
},
secondary: {
main: '#a55374',
},
},
},
},
mountainSunset: {
getName: () => translate('settings.appearance.themes.mountain_sunset'),
palette: {
primary: {
main: '#c55a77',
},
secondary: {
main: '#5ac5a8',
'montain sunset': {
isCustom: false,
getName: () => translate('settings.appearance.theme.themes.mountain_sunset'),
muiTheme: {
palette: {
primary: {
main: '#c55a77',
},
secondary: {
main: '#5ac5a8',
},
},
},
},
crimson: {
getName: () => translate('settings.appearance.themes.crimson'),
palette: {
primary: {
main: '#ff0033',
},
secondary: {
main: '#00ffcc',
isCustom: false,
getName: () => translate('settings.appearance.theme.themes.crimson'),
muiTheme: {
palette: {
primary: {
main: '#ff0033',
},
secondary: {
main: '#00ffcc',
},
},
},
},
mintyMiracles: {
getName: () => translate('settings.appearance.themes.minty_miracles'),
palette: {
primary: {
main: '#9defc3',
},
secondary: {
main: '#ef9dc9',
'minty miracles': {
isCustom: false,
getName: () => translate('settings.appearance.theme.themes.minty_miracles'),
muiTheme: {
palette: {
primary: {
main: '#9defc3',
},
secondary: {
main: '#ef9dc9',
},
},
},
},
orangeJuice: {
getName: () => translate('settings.appearance.themes.orange_juice'),
palette: {
primary: {
main: '#ffb546',
},
secondary: {
main: '#4690ff',
'orange juice': {
isCustom: false,
getName: () => translate('settings.appearance.theme.themes.orange_juice'),
muiTheme: {
palette: {
primary: {
main: '#ffb546',
},
secondary: {
main: '#4690ff',
},
},
},
},
} as const satisfies Record<string, Theme>;
export type AppThemes = keyof typeof themes;
export type AppThemes = keyof typeof themes | string;
export type AppTheme = Theme & { id: AppThemes };
export type AppTheme = Theme & { id: AppThemes; isCustom: boolean };
export const appThemes = (Object.entries(themes) as [AppThemes, Theme][]).map(([id, theme]) => ({
id,
...theme,
})) satisfies AppTheme[];
export const getTheme = (id: AppThemes): AppTheme => ({ id, ...themes[id] });
export const getTheme = (id: AppThemes, customThemes: Record<string, AppTheme> = {}): AppTheme => {
try {
const allThemes = { ...themes, ...customThemes };
const theme = (allThemes[id as keyof typeof themes] as AppTheme) ?? themes.default;
return {
// @ts-ignore - custom themes do not have a "getName" function
getName: () => id,
...theme,
};
} catch (e) {
defaultPromiseErrorHandler('getTheme')(e);
}
return { id, ...themes[id as keyof typeof themes] };
};
export const isThemeNameUnique = (id: string, customThemes: Record<string, AppTheme>): boolean =>
Object.keys({ ...themes, ...customThemes }).every((themeId) => themeId.toLowerCase() !== id.toLowerCase());