2023-01-26 13:18:51 +01:00
|
|
|
import {createContext, useContext, useMemo, useState} from "react";
|
2022-04-06 16:37:23 +02:00
|
|
|
import {createNightModeCss, getColors} from "../util/colors";
|
|
|
|
import {getLightModeChartTheming, getNightModeChartTheming} from "../util/graphColors";
|
|
|
|
import {useMetadata} from "./metadataHook";
|
2023-01-26 13:18:51 +01:00
|
|
|
import {useLocation} from "react-router-dom";
|
2022-04-06 16:37:23 +02:00
|
|
|
|
|
|
|
const themeColors = getColors();
|
|
|
|
themeColors.splice(themeColors.length - 4, 4);
|
|
|
|
|
|
|
|
const getDefaultTheme = (metadata) => {
|
|
|
|
const defaultTheme = metadata.defaultTheme;
|
|
|
|
|
|
|
|
// Use 'plan' if default or if default is undefined.
|
|
|
|
// Avoid night mode staying on if default theme is night mode
|
|
|
|
const invalidColor = !defaultTheme
|
|
|
|
|| defaultTheme === 'default'
|
|
|
|
|| defaultTheme === 'black'
|
|
|
|
|| defaultTheme === 'white'
|
|
|
|
|| !themeColors.map(color => color.name).includes(defaultTheme)
|
|
|
|
|
|
|
|
return invalidColor ? 'plan' : defaultTheme;
|
|
|
|
}
|
|
|
|
|
|
|
|
const getStoredTheme = (defaultTheme) => {
|
|
|
|
const stored = window.localStorage.getItem('themeColor');
|
|
|
|
return stored && stored !== 'undefined' ? stored : defaultTheme;
|
|
|
|
}
|
|
|
|
|
|
|
|
const setStoredTheme = themeColor => {
|
|
|
|
if (themeColor) {
|
|
|
|
window.localStorage.setItem('themeColor', themeColor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const ThemeContext = createContext({});
|
|
|
|
|
|
|
|
export const ThemeContextProvider = ({children}) => {
|
|
|
|
const metadata = useMetadata();
|
|
|
|
|
|
|
|
const [colorChooserOpen, setColorChooserOpen] = useState(false);
|
|
|
|
const [selectedColor, setSelectedColor] = useState(getStoredTheme(getDefaultTheme(metadata)));
|
|
|
|
const [previousColor, setPreviousColor] = useState(undefined);
|
|
|
|
|
2023-01-26 13:18:51 +01:00
|
|
|
const sharedState = useMemo(() => {
|
|
|
|
return {
|
|
|
|
selectedColor, setSelectedColor,
|
|
|
|
previousColor, setPreviousColor,
|
|
|
|
colorChooserOpen, setColorChooserOpen
|
|
|
|
}
|
|
|
|
}, [selectedColor, setSelectedColor, previousColor, setPreviousColor, colorChooserOpen, setColorChooserOpen]);
|
2022-04-06 16:37:23 +02:00
|
|
|
return (<ThemeContext.Provider value={sharedState}>
|
|
|
|
{children}
|
|
|
|
</ThemeContext.Provider>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const lightModeChartTheming = getLightModeChartTheming();
|
|
|
|
const nightModeChartTheming = getNightModeChartTheming();
|
|
|
|
|
|
|
|
export const useTheme = () => {
|
|
|
|
const {
|
|
|
|
selectedColor,
|
|
|
|
setSelectedColor,
|
|
|
|
previousColor,
|
|
|
|
setPreviousColor,
|
|
|
|
colorChooserOpen,
|
|
|
|
setColorChooserOpen
|
|
|
|
} = useContext(ThemeContext);
|
|
|
|
|
|
|
|
const metadata = useMetadata();
|
|
|
|
|
|
|
|
const setTheme = color => {
|
|
|
|
setStoredTheme(color);
|
|
|
|
setSelectedColor(color);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!selectedColor) setTheme(selectedColor);
|
|
|
|
|
|
|
|
const toggleColorChooser = () => {
|
|
|
|
setColorChooserOpen(!colorChooserOpen);
|
|
|
|
}
|
|
|
|
|
|
|
|
const isNightModeEnabled = () => {
|
|
|
|
return selectedColor === 'night';
|
|
|
|
}
|
|
|
|
|
|
|
|
const toggleNightMode = () => {
|
|
|
|
if (isNightModeEnabled()) {
|
|
|
|
setTheme(previousColor ? previousColor : getDefaultTheme(metadata));
|
|
|
|
} else {
|
|
|
|
setPreviousColor(selectedColor);
|
|
|
|
setTheme('night');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const nightModeEnabled = isNightModeEnabled();
|
|
|
|
return {
|
|
|
|
color: selectedColor,
|
|
|
|
setColor: setTheme,
|
|
|
|
nightModeEnabled: nightModeEnabled,
|
|
|
|
colorChooserOpen: colorChooserOpen,
|
|
|
|
nightModeCss: nightModeEnabled ? createNightModeCss() : undefined,
|
|
|
|
toggleNightMode: toggleNightMode,
|
|
|
|
toggleColorChooser: toggleColorChooser,
|
|
|
|
themeColors: themeColors,
|
|
|
|
graphTheming: nightModeEnabled ? nightModeChartTheming : lightModeChartTheming
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-01-26 13:18:51 +01:00
|
|
|
export const ThemeCss = () => {
|
|
|
|
const {color} = useTheme();
|
|
|
|
|
|
|
|
if (!color) return <></>;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<style>
|
|
|
|
{':root {--color-theme: var(--color-' + color + ') !important;}'}
|
|
|
|
</style>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-04-06 16:37:23 +02:00
|
|
|
export const NightModeCss = () => {
|
|
|
|
const theme = useTheme();
|
2023-01-26 13:18:51 +01:00
|
|
|
const location = useLocation();
|
|
|
|
|
|
|
|
if (location.pathname.startsWith('/docs')) {
|
|
|
|
return <>
|
|
|
|
<style>
|
|
|
|
{'#wrapper {background-image: none;}'}
|
|
|
|
</style>
|
|
|
|
</>
|
|
|
|
}
|
2022-04-06 16:37:23 +02:00
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{theme.nightModeEnabled ? <style>
|
|
|
|
{theme.nightModeCss}
|
|
|
|
</style> : ''}
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|