Add themes
This commit is contained in:
@@ -386,6 +386,7 @@
|
|||||||
"client": "Client",
|
"client": "Client",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"copied": "Copied",
|
"copied": "Copied",
|
||||||
|
"default": "Default",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"discord": "Discord",
|
"discord": "Discord",
|
||||||
"display": "Display",
|
"display": "Display",
|
||||||
@@ -820,6 +821,16 @@
|
|||||||
"device_theme": "Device theme",
|
"device_theme": "Device theme",
|
||||||
"pure_black_mode": "Pure black dark mode",
|
"pure_black_mode": "Pure black dark mode",
|
||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
|
"themes": {
|
||||||
|
"crimson": "Crimson",
|
||||||
|
"dune": "Dune",
|
||||||
|
"forest_dew": "Forest dew",
|
||||||
|
"lavendar": "Lavendar",
|
||||||
|
"minty_miracles": "Minty Miracles",
|
||||||
|
"mountain_sunset": "Mountain sunset",
|
||||||
|
"orange_juice": "Orange juice",
|
||||||
|
"rosegold": "Rosegold"
|
||||||
|
},
|
||||||
"title": "Appearance"
|
"title": "Appearance"
|
||||||
},
|
},
|
||||||
"backup": {
|
"backup": {
|
||||||
|
|||||||
@@ -16,13 +16,14 @@ import { CacheProvider, EmotionCache } from '@emotion/react';
|
|||||||
import createCache from '@emotion/cache';
|
import createCache from '@emotion/cache';
|
||||||
import { prefixer } from 'stylis';
|
import { prefixer } from 'stylis';
|
||||||
import rtlPlugin from 'stylis-plugin-rtl';
|
import rtlPlugin from 'stylis-plugin-rtl';
|
||||||
import { createTheme } from '@/theme';
|
import { createAndSetTheme } from '@/theme';
|
||||||
import { useLocalStorage } from '@/util/useStorage.tsx';
|
import { useLocalStorage } from '@/util/useStorage.tsx';
|
||||||
import { ThemeMode, ThemeModeContext } from '@/components/context/ThemeModeContext.tsx';
|
import { ThemeMode, ThemeModeContext } from '@/components/context/ThemeModeContext.tsx';
|
||||||
import { NavBarContextProvider } from '@/components/navbar/NavBarContextProvider';
|
import { NavBarContextProvider } from '@/components/navbar/NavBarContextProvider';
|
||||||
import { LibraryOptionsContextProvider } from '@/components/library/LibraryOptionsProvider';
|
import { LibraryOptionsContextProvider } from '@/components/library/LibraryOptionsProvider';
|
||||||
import { ActiveDevice, DEFAULT_DEVICE, setActiveDevice } from '@/util/device.ts';
|
import { ActiveDevice, DEFAULT_DEVICE, setActiveDevice } from '@/util/device.ts';
|
||||||
import { MediaQuery } from '@/lib/ui/MediaQuery.tsx';
|
import { MediaQuery } from '@/lib/ui/MediaQuery.tsx';
|
||||||
|
import { AppThemes } from '@/lib/ui/AppThemes.ts';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -56,18 +57,21 @@ export const AppContext: React.FC<Props> = ({ children }) => {
|
|||||||
return () => unsubscribe();
|
return () => unsubscribe();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const [appTheme, setAppTheme] = useLocalStorage<AppThemes>('appTheme', 'default');
|
||||||
const [themeMode, setThemeMode] = useLocalStorage<ThemeMode>('themeMode', ThemeMode.SYSTEM);
|
const [themeMode, setThemeMode] = useLocalStorage<ThemeMode>('themeMode', ThemeMode.SYSTEM);
|
||||||
const [pureBlackMode, setPureBlackMode] = useLocalStorage<boolean>('pureBlackMode', false);
|
const [pureBlackMode, setPureBlackMode] = useLocalStorage<boolean>('pureBlackMode', false);
|
||||||
const [activeDevice, setActiveDeviceContext] = useLocalStorage('activeDevice', DEFAULT_DEVICE);
|
const [activeDevice, setActiveDeviceContext] = useLocalStorage('activeDevice', DEFAULT_DEVICE);
|
||||||
|
|
||||||
const darkThemeContext = useMemo(
|
const darkThemeContext = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
appTheme,
|
||||||
|
setAppTheme,
|
||||||
themeMode,
|
themeMode,
|
||||||
setThemeMode,
|
setThemeMode,
|
||||||
pureBlackMode,
|
pureBlackMode,
|
||||||
setPureBlackMode,
|
setPureBlackMode,
|
||||||
}),
|
}),
|
||||||
[themeMode, pureBlackMode],
|
[themeMode, pureBlackMode, appTheme],
|
||||||
);
|
);
|
||||||
|
|
||||||
const activeDeviceContext = useMemo(
|
const activeDeviceContext = useMemo(
|
||||||
@@ -76,8 +80,8 @@ export const AppContext: React.FC<Props> = ({ children }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const theme = useMemo(
|
const theme = useMemo(
|
||||||
() => createTheme(themeMode, currentDirection, undefined, pureBlackMode),
|
() => createAndSetTheme(themeMode, appTheme, pureBlackMode, currentDirection),
|
||||||
[themeMode, currentDirection, systemThemeMode, pureBlackMode],
|
[themeMode, currentDirection, systemThemeMode, pureBlackMode, appTheme],
|
||||||
);
|
);
|
||||||
|
|
||||||
setActiveDevice(activeDevice);
|
setActiveDevice(activeDevice);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { AppThemes } from '@/lib/ui/AppThemes.ts';
|
||||||
|
|
||||||
export enum ThemeMode {
|
export enum ThemeMode {
|
||||||
SYSTEM = 'system',
|
SYSTEM = 'system',
|
||||||
@@ -15,6 +16,8 @@ export enum ThemeMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ContextType = {
|
type ContextType = {
|
||||||
|
appTheme: AppThemes;
|
||||||
|
setAppTheme: React.Dispatch<React.SetStateAction<AppThemes>>;
|
||||||
themeMode: ThemeMode;
|
themeMode: ThemeMode;
|
||||||
setThemeMode: React.Dispatch<React.SetStateAction<ThemeMode>>;
|
setThemeMode: React.Dispatch<React.SetStateAction<ThemeMode>>;
|
||||||
pureBlackMode: boolean;
|
pureBlackMode: boolean;
|
||||||
@@ -22,6 +25,8 @@ type ContextType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ThemeModeContext = React.createContext<ContextType>({
|
export const ThemeModeContext = React.createContext<ContextType>({
|
||||||
|
appTheme: 'default',
|
||||||
|
setAppTheme: (): void => {},
|
||||||
themeMode: ThemeMode.SYSTEM,
|
themeMode: ThemeMode.SYSTEM,
|
||||||
setThemeMode: (): void => {},
|
setThemeMode: (): void => {},
|
||||||
pureBlackMode: false,
|
pureBlackMode: false,
|
||||||
|
|||||||
@@ -74,18 +74,19 @@ export const MangaBadges = ({
|
|||||||
{inLibraryIndicator && isInLibrary && (
|
{inLibraryIndicator && isInLibrary && (
|
||||||
<Typography
|
<Typography
|
||||||
className="source-manga-library-state-indicator"
|
className="source-manga-library-state-indicator"
|
||||||
sx={{ backgroundColor: 'primary.dark', p: 0.3 }}
|
sx={{ backgroundColor: 'primary.dark', color: 'primary.contrastText', p: 0.3 }}
|
||||||
>
|
>
|
||||||
{t('manga.button.in_library')}
|
{t('manga.button.in_library')}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{((showUnreadBadge && mode === 'default') || mode === 'duplicate') && (unread ?? 0) > 0 && (
|
{((showUnreadBadge && mode === 'default') || mode === 'duplicate') && (unread ?? 0) > 0 && (
|
||||||
<Badge sx={{ backgroundColor: 'primary.dark' }}>{unread}</Badge>
|
<Badge sx={{ backgroundColor: 'primary.main', color: 'primary.contrastText' }}>{unread}</Badge>
|
||||||
)}
|
)}
|
||||||
{((showDownloadBadge && mode === 'default') || mode === 'duplicate') && (downloadCount ?? 0) > 0 && (
|
{((showDownloadBadge && mode === 'default') || mode === 'duplicate') && (downloadCount ?? 0) > 0 && (
|
||||||
<Badge
|
<Badge
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: 'primary.light',
|
backgroundColor: 'secondary.main',
|
||||||
|
color: 'secondary.contrastText',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{downloadCount}
|
{downloadCount}
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ const Thumbnail = ({ manga }: { manga: Partial<MangaThumbnailInfo> }) => {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<OpenInFullIcon fontSize="large" />
|
<OpenInFullIcon fontSize="large" color="primary" />
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Modal {...bindPopover(popupState)} sx={{ outline: 0 }}>
|
<Modal {...bindPopover(popupState)} sx={{ outline: 0 }}>
|
||||||
|
|||||||
125
src/lib/ui/AppThemes.ts
Normal file
125
src/lib/ui/AppThemes.ts
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { PaletteOptions } from '@mui/material/styles';
|
||||||
|
import { t as translate } from 'i18next';
|
||||||
|
|
||||||
|
type Theme = { getName: () => string; palette: PaletteOptions };
|
||||||
|
|
||||||
|
const themes = {
|
||||||
|
default: {
|
||||||
|
getName: () => translate('global.label.default'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#5b74ef',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#efd65b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lavender: {
|
||||||
|
getName: () => translate('settings.appearance.themes.lavendar'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#5c58dc',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#d8dc58',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dune: {
|
||||||
|
getName: () => translate('settings.appearance.themes.dune'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#897869',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#697a89',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rosegold: {
|
||||||
|
getName: () => translate('settings.appearance.themes.rosegold'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#f1a886',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#86cff1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
forestDew: {
|
||||||
|
getName: () => translate('settings.appearance.themes.forest_dew'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#53a584',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#a55374',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mountainSunset: {
|
||||||
|
getName: () => translate('settings.appearance.themes.mountain_sunset'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#c55a77',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#5ac5a8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
crimson: {
|
||||||
|
getName: () => translate('settings.appearance.themes.crimson'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#ff0033',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#00ffcc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mintyMiracles: {
|
||||||
|
getName: () => translate('settings.appearance.themes.minty_miracles'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#9defc3',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#ef9dc9',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
orangeJuice: {
|
||||||
|
getName: () => translate('settings.appearance.themes.orange_juice'),
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#ffb546',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#4690ff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const satisfies Record<string, Theme>;
|
||||||
|
|
||||||
|
export type AppThemes = keyof typeof themes;
|
||||||
|
|
||||||
|
export type AppTheme = Theme & { id: AppThemes };
|
||||||
|
|
||||||
|
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] });
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useContext, useEffect } from 'react';
|
import { useContext, useEffect, useMemo } from 'react';
|
||||||
import List from '@mui/material/List';
|
import List from '@mui/material/List';
|
||||||
import ListItem from '@mui/material/ListItem';
|
import ListItem from '@mui/material/ListItem';
|
||||||
import ListItemText from '@mui/material/ListItemText';
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
@@ -15,6 +15,11 @@ import MenuItem from '@mui/material/MenuItem';
|
|||||||
import ListSubheader from '@mui/material/ListSubheader';
|
import ListSubheader from '@mui/material/ListSubheader';
|
||||||
import Switch from '@mui/material/Switch';
|
import Switch from '@mui/material/Switch';
|
||||||
import Link from '@mui/material/Link';
|
import Link from '@mui/material/Link';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import Stack from '@mui/material/Stack';
|
||||||
|
import { styled, ThemeProvider } from '@mui/material/styles';
|
||||||
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||||
import { NavBarContext } from '@/components/context/NavbarContext.tsx';
|
import { NavBarContext } from '@/components/context/NavbarContext.tsx';
|
||||||
import { ThemeMode, ThemeModeContext } from '@/components/context/ThemeModeContext.tsx';
|
import { ThemeMode, ThemeModeContext } from '@/components/context/ThemeModeContext.tsx';
|
||||||
import { Select } from '@/components/atoms/Select.tsx';
|
import { Select } from '@/components/atoms/Select.tsx';
|
||||||
@@ -23,6 +28,112 @@ import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
|||||||
import { useLocalStorage } from '@/util/useStorage.tsx';
|
import { useLocalStorage } from '@/util/useStorage.tsx';
|
||||||
import { I18nResourceCode, i18nResources } from '@/i18n';
|
import { I18nResourceCode, i18nResources } from '@/i18n';
|
||||||
import { langCodeToName } from '@/util/language.tsx';
|
import { langCodeToName } from '@/util/language.tsx';
|
||||||
|
import { AppTheme, appThemes } from '@/lib/ui/AppThemes.ts';
|
||||||
|
import { createTheme } from '@/theme.ts';
|
||||||
|
|
||||||
|
const ThemePreviewBage = styled(Box)(({ theme }) => ({
|
||||||
|
width: '15px',
|
||||||
|
height: '20px',
|
||||||
|
borderRadius: theme.shape.borderRadius,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ThemePreview = ({ theme }: { theme: AppTheme }) => {
|
||||||
|
const { getName } = theme;
|
||||||
|
|
||||||
|
const { themeMode, setAppTheme, appTheme, pureBlackMode } = useContext(ThemeModeContext);
|
||||||
|
|
||||||
|
const isSelected = theme.id === appTheme;
|
||||||
|
|
||||||
|
const muiTheme = useMemo(
|
||||||
|
() => createTheme(themeMode, theme.id, pureBlackMode),
|
||||||
|
[theme.id, themeMode, pureBlackMode],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
padding: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
minWidth: '150px',
|
||||||
|
maxWidth: '150px',
|
||||||
|
gap: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ThemeProvider theme={muiTheme}>
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
backgroundColor: 'background.default',
|
||||||
|
width: '100%',
|
||||||
|
height: '225px',
|
||||||
|
outline: '4px solid',
|
||||||
|
outlineColor: isSelected ? muiTheme.palette.primary.light : muiTheme.palette.background.paper,
|
||||||
|
borderRadius: 1,
|
||||||
|
}}
|
||||||
|
onClick={() => setAppTheme(theme.id)}
|
||||||
|
>
|
||||||
|
<Stack sx={{ height: '100%', gap: 2, p: 1 }}>
|
||||||
|
<Stack sx={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||||
|
<Box
|
||||||
|
sx={{ width: '65%', height: '20px', backgroundColor: 'primary.dark', borderRadius: 1 }}
|
||||||
|
/>
|
||||||
|
{isSelected && (
|
||||||
|
<CheckCircleIcon
|
||||||
|
sx={{ visibility: isSelected ? 'visible' : 'hidden', color: 'primary.light' }}
|
||||||
|
// color="primary"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
width: '55%',
|
||||||
|
height: '65%',
|
||||||
|
backgroundColor: 'background.paper',
|
||||||
|
borderRadius: 1,
|
||||||
|
p: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ThemePreviewBage sx={{ backgroundColor: 'primary.main' }} />
|
||||||
|
<ThemePreviewBage sx={{ backgroundColor: 'secondary.main' }} />
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
height: '80px',
|
||||||
|
backgroundColor: muiTheme.palette.background.paper,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{ width: '20px', height: '20px', borderRadius: '50%', backgroundColor: 'primary.main' }}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
flexGrow: 0.75,
|
||||||
|
height: '20px',
|
||||||
|
borderRadius: 1,
|
||||||
|
backgroundColor: 'primary.light',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</ThemeProvider>
|
||||||
|
<Typography>{getName()}</Typography>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ThemePicker = () => (
|
||||||
|
<Stack sx={{ flexDirection: 'row', flexWrap: 'no-wrap', overflowX: 'auto', gap: 3, mx: 1 }}>
|
||||||
|
{appThemes.map((theme) => (
|
||||||
|
<ThemePreview key={theme.id} theme={theme} />
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
|
||||||
export const Appearance = () => {
|
export const Appearance = () => {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
@@ -65,6 +176,7 @@ export const Appearance = () => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
<ThemePicker />
|
||||||
{isDarkMode && (
|
{isDarkMode && (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText primary={t('settings.appearance.pure_black_mode')} />
|
<ListItemText primary={t('settings.appearance.pure_black_mode')} />
|
||||||
|
|||||||
20
src/theme.ts
20
src/theme.ts
@@ -17,17 +17,18 @@ import {
|
|||||||
} from '@mui/material/styles';
|
} from '@mui/material/styles';
|
||||||
import { ThemeMode } from '@/components/context/ThemeModeContext.tsx';
|
import { ThemeMode } from '@/components/context/ThemeModeContext.tsx';
|
||||||
import { MediaQuery } from '@/lib/ui/MediaQuery.tsx';
|
import { MediaQuery } from '@/lib/ui/MediaQuery.tsx';
|
||||||
|
import { AppThemes, getTheme } from '@/lib/ui/AppThemes.ts';
|
||||||
|
|
||||||
export const SCROLLBAR_WIDTH = 14;
|
export const SCROLLBAR_WIDTH = 14;
|
||||||
|
|
||||||
let theme: Theme;
|
|
||||||
export const getCurrentTheme = () => theme;
|
|
||||||
export const createTheme = (
|
export const createTheme = (
|
||||||
themeMode: ThemeMode,
|
themeMode: ThemeMode,
|
||||||
direction: Direction = 'ltr',
|
appThemeId: AppThemes,
|
||||||
color: string = '#5b74ef',
|
|
||||||
pureBlackMode: boolean = false,
|
pureBlackMode: boolean = false,
|
||||||
|
direction: Direction = 'ltr',
|
||||||
) => {
|
) => {
|
||||||
|
const appTheme = getTheme(appThemeId);
|
||||||
|
|
||||||
const systemMode = MediaQuery.getSystemThemeMode();
|
const systemMode = MediaQuery.getSystemThemeMode();
|
||||||
const mode = themeMode === ThemeMode.SYSTEM ? systemMode : themeMode;
|
const mode = themeMode === ThemeMode.SYSTEM ? systemMode : themeMode;
|
||||||
const isDarkMode = mode === ThemeMode.DARK;
|
const isDarkMode = mode === ThemeMode.DARK;
|
||||||
@@ -37,9 +38,7 @@ export const createTheme = (
|
|||||||
direction,
|
direction,
|
||||||
palette: {
|
palette: {
|
||||||
mode,
|
mode,
|
||||||
primary: {
|
...appTheme.palette,
|
||||||
main: color,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,8 +89,13 @@ export const createTheme = (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
theme = responsiveFontSizes(suwayomiTheme);
|
return responsiveFontSizes(suwayomiTheme);
|
||||||
|
};
|
||||||
|
|
||||||
|
let theme: Theme;
|
||||||
|
export const getCurrentTheme = () => theme;
|
||||||
|
export const createAndSetTheme = (...args: Parameters<typeof createTheme>) => {
|
||||||
|
theme = createTheme(...args);
|
||||||
return theme;
|
return theme;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user