add functionality, without user exposure yet
This commit is contained in:
parent
d81e6b3a2c
commit
eacab6ae04
@ -9,9 +9,9 @@ import { GlobalStyle } from '@/styles/globalStyle';
|
||||
|
||||
import { SelectMenu, SelectItem } from '@/components/SelectMenu';
|
||||
|
||||
import { AppThemeProvider } from '@/hooks/useAppTheme';
|
||||
import { AppThemeAndColorModeProvider } from '@/hooks/useAppThemeAndColorMode';
|
||||
|
||||
import { AppTheme, setAppTheme } from '@/state/configs';
|
||||
import { AppTheme, AppColorMode, setAppTheme, setAppColorMode } from '@/state/configs';
|
||||
import { setLocaleLoaded } from '@/state/localization';
|
||||
|
||||
import '@/index.css';
|
||||
@ -19,9 +19,12 @@ import './ladle.css';
|
||||
|
||||
export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [theme, setTheme] = useState(AppTheme.Classic);
|
||||
const [colorMode, setColorMode] = useState(AppColorMode.GreenUp);
|
||||
|
||||
useEffect(() => {
|
||||
store.dispatch(setAppTheme(theme));
|
||||
store.dispatch(setAppColorMode(colorMode));
|
||||
|
||||
switch (theme) {
|
||||
case AppTheme.Dark: {
|
||||
document?.documentElement?.classList.remove('theme-light');
|
||||
@ -38,7 +41,7 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [theme]);
|
||||
}, [theme, colorMode]);
|
||||
|
||||
useEffect(() => {
|
||||
store.dispatch(setLocaleLoaded(true));
|
||||
@ -48,10 +51,7 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
<Provider store={store}>
|
||||
<StoryHeader>
|
||||
<h4>Active Theme:</h4>
|
||||
<SelectMenu
|
||||
value={theme}
|
||||
onValueChange={setTheme}
|
||||
>
|
||||
<SelectMenu value={theme} onValueChange={setTheme}>
|
||||
{[
|
||||
{
|
||||
value: AppTheme.Classic,
|
||||
@ -66,20 +66,31 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
label: 'Light theme',
|
||||
},
|
||||
].map(({ value, label }) => (
|
||||
<SelectItem
|
||||
key={value}
|
||||
value={value}
|
||||
label={label}
|
||||
/>
|
||||
<SelectItem key={value} value={value} label={label} />
|
||||
))}
|
||||
</SelectMenu>
|
||||
<h4>Active Color Mode:</h4>
|
||||
<SelectMenu value={colorMode} onValueChange={setColorMode}>
|
||||
{[
|
||||
{
|
||||
value: AppColorMode.GreenUp,
|
||||
label: 'Green up',
|
||||
},
|
||||
{
|
||||
value: AppColorMode.RedUp,
|
||||
label: 'Red up',
|
||||
},
|
||||
].map(({ value, label }) => (
|
||||
<SelectItem key={value} value={value} label={label} />
|
||||
))}
|
||||
</SelectMenu>
|
||||
</StoryHeader>
|
||||
<hr />
|
||||
<AppThemeProvider>
|
||||
<AppThemeAndColorModeProvider>
|
||||
<GlobalStyle />
|
||||
<StoryContent>{children}</StoryContent>
|
||||
</AppThemeProvider>
|
||||
</Provider>
|
||||
</AppThemeAndColorModeProvider>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ import {
|
||||
} from '@/hooks';
|
||||
import { DydxProvider } from '@/hooks/useDydxClient';
|
||||
import { AccountsProvider } from '@/hooks/useAccounts';
|
||||
import { AppThemeProvider } from '@/hooks/useAppTheme';
|
||||
import { AppThemeAndColorModeProvider } from '@/hooks/useAppThemeAndColorMode';
|
||||
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
|
||||
import { LocaleProvider } from '@/hooks/useLocaleSeparators';
|
||||
import { NotificationsProvider } from '@/hooks/useNotifications';
|
||||
@ -141,8 +141,7 @@ const providers = [
|
||||
wrapProvider(LocalNotificationsProvider),
|
||||
wrapProvider(NotificationsProvider),
|
||||
wrapProvider(DialogAreaProvider),
|
||||
wrapProvider(PotentialMarketsProvider),
|
||||
wrapProvider(AppThemeProvider),
|
||||
wrapProvider(AppThemeAndColorModeProvider),
|
||||
];
|
||||
|
||||
const App = () => {
|
||||
|
||||
@ -20,6 +20,7 @@ export enum LocalStorageKey {
|
||||
SelectedLocale = 'dydx.SelectedLocale',
|
||||
SelectedNetwork = 'dydx.SelectedNetwork',
|
||||
SelectedTheme = 'dydx.SelectedTheme',
|
||||
SelectedColorMode = 'dydx.SelectedColorMode',
|
||||
SelectedTradeLayout = 'dydx.SelectedTradeLayout',
|
||||
TradingViewChartConfig = 'dydx.TradingViewChartConfig',
|
||||
HasSeenLaunchIncentives = 'dydx.HasSeenLaunchIncentives',
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
export type ThemeColors = LayerColors &
|
||||
import { AppColorMode } from '@/state/configs';
|
||||
|
||||
export type Theme = {
|
||||
[AppColorMode.GreenUp]: ThemeColorBase;
|
||||
[AppColorMode.RedUp]: ThemeColorBase;
|
||||
};
|
||||
|
||||
export type ThemeColorBase = LayerColors &
|
||||
BorderColors &
|
||||
TextColors &
|
||||
GradientColors &
|
||||
@ -49,6 +56,8 @@ type StatusColors = {
|
||||
error: string;
|
||||
};
|
||||
|
||||
/** ##InvertDirectionalColors
|
||||
* When adding colors here, make sure to update linked function to invert colors for AppColorMode. */
|
||||
type DirectionalColors = {
|
||||
positive: string;
|
||||
negative: string;
|
||||
|
||||
@ -12,8 +12,9 @@ import {
|
||||
ORDERBOOK_WIDTH,
|
||||
} from '@/constants/orderbook';
|
||||
|
||||
import { useAppThemeAndColorModeContext } from '@/hooks/useAppThemeAndColorMode';
|
||||
|
||||
import { getCurrentMarketConfig, getCurrentMarketOrderbookMap } from '@/state/perpetualsSelectors';
|
||||
import { getAppTheme } from '@/state/configsSelectors';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
|
||||
@ -23,7 +24,6 @@ import {
|
||||
getXByColumn,
|
||||
getYForElements,
|
||||
} from '@/lib/orderbookHelpers';
|
||||
import { useAppThemeContext } from '../useAppTheme';
|
||||
|
||||
type ElementProps = {
|
||||
data: Array<PerpetualMarketOrderbookLevel | undefined>;
|
||||
@ -53,7 +53,7 @@ export const useDrawOrderbook = ({
|
||||
const { stepSizeDecimals = TOKEN_DECIMALS, tickSizeDecimals = SMALL_USD_DECIMALS } =
|
||||
useSelector(getCurrentMarketConfig, shallowEqual) || {};
|
||||
const prevData = useRef<typeof data>(data);
|
||||
const theme = useAppThemeContext();
|
||||
const theme = useAppThemeAndColorModeContext();
|
||||
|
||||
/**
|
||||
* Scale canvas using device pixel ratio to unblur drawn text
|
||||
|
||||
@ -11,7 +11,7 @@ import { useDydxClient, useLocalStorage } from '@/hooks';
|
||||
import { store } from '@/state/_store';
|
||||
|
||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||
import { getAppTheme } from '@/state/configsSelectors';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
import { getSelectedLocale } from '@/state/localizationSelectors';
|
||||
import { getCurrentMarketId, getMarketIds } from '@/state/perpetualsSelectors';
|
||||
|
||||
@ -30,6 +30,7 @@ export const useTradingView = ({
|
||||
}) => {
|
||||
const marketId = useSelector(getCurrentMarketId);
|
||||
const appTheme = useSelector(getAppTheme);
|
||||
const appColorMode = useSelector(getAppColorMode);
|
||||
const marketIds = useSelector(getMarketIds, shallowEqual);
|
||||
const selectedLocale = useSelector(getSelectedLocale);
|
||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||
@ -46,7 +47,7 @@ export const useTradingView = ({
|
||||
useEffect(() => {
|
||||
if (hasMarkets && isClientConnected && marketId) {
|
||||
const widgetOptions = getWidgetOptions();
|
||||
const widgetOverrides = getWidgetOverrides(appTheme);
|
||||
const widgetOverrides = getWidgetOverrides({ appTheme, appColorMode });
|
||||
const options = {
|
||||
// debug: true,
|
||||
...widgetOptions,
|
||||
@ -75,7 +76,14 @@ export const useTradingView = ({
|
||||
tvWidgetRef.current = null;
|
||||
setIsChartReady(false);
|
||||
};
|
||||
}, [getCandlesForDatafeed, isClientConnected, hasMarkets, selectedLocale, selectedNetwork, !!marketId]);
|
||||
}, [
|
||||
getCandlesForDatafeed,
|
||||
isClientConnected,
|
||||
hasMarkets,
|
||||
selectedLocale,
|
||||
selectedNetwork,
|
||||
!!marketId,
|
||||
]);
|
||||
|
||||
return { savedResolution };
|
||||
};
|
||||
|
||||
@ -3,8 +3,8 @@ import { useSelector } from 'react-redux';
|
||||
|
||||
import type { IChartingLibraryWidget, ThemeName } from 'public/tradingview/charting_library';
|
||||
|
||||
import { AppTheme } from '@/state/configs';
|
||||
import { getAppTheme } from '@/state/configsSelectors';
|
||||
import { AppColorMode, AppTheme } from '@/state/configs';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
|
||||
import { getWidgetOverrides } from '@/lib/tradingView/utils';
|
||||
|
||||
@ -29,6 +29,7 @@ export const useTradingViewTheme = ({
|
||||
isWidgetReady?: boolean;
|
||||
}) => {
|
||||
const appTheme: AppTheme = useSelector(getAppTheme);
|
||||
const appColorMode: AppColorMode = useSelector(getAppColorMode);
|
||||
|
||||
useEffect(() => {
|
||||
if (tvWidget && isWidgetReady) {
|
||||
@ -55,10 +56,24 @@ export const useTradingViewTheme = ({
|
||||
}
|
||||
}
|
||||
|
||||
const { overrides, studies_overrides } = getWidgetOverrides(appTheme);
|
||||
const { overrides, studies_overrides } = getWidgetOverrides({ appTheme, appColorMode });
|
||||
tvWidget?.applyOverrides(overrides);
|
||||
tvWidget?.applyStudiesOverrides(studies_overrides);
|
||||
|
||||
// Necessary to update existing indicators
|
||||
const volumeStudyId = tvWidget
|
||||
?.activeChart()
|
||||
?.getAllStudies()
|
||||
?.find((x) => x.name === 'Volume')?.id;
|
||||
|
||||
if (volumeStudyId) {
|
||||
const volume = tvWidget?.activeChart()?.getStudyById(volumeStudyId);
|
||||
volume.applyOverrides({
|
||||
'volume.color.0': studies_overrides['volume.volume.color.0'],
|
||||
'volume.color.1': studies_overrides['volume.volume.color.1'],
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [appTheme]);
|
||||
}, [appTheme, appColorMode]);
|
||||
};
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
|
||||
import { AppTheme } from '@/state/configs';
|
||||
import { getAppTheme } from '@/state/configsSelectors';
|
||||
|
||||
import { Themes } from '@/styles/themes';
|
||||
|
||||
export const AppThemeProvider = ({ ...props }) => {
|
||||
return <ThemeProvider theme={useAppThemeContext()} {...props} />
|
||||
};
|
||||
|
||||
export const useAppThemeContext = () => {
|
||||
const theme: AppTheme = useSelector(getAppTheme);
|
||||
return Themes[theme];
|
||||
}
|
||||
18
src/hooks/useAppThemeAndColorMode.tsx
Normal file
18
src/hooks/useAppThemeAndColorMode.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
|
||||
import { AppTheme, AppColorMode } from '@/state/configs';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
|
||||
import { Themes } from '@/styles/themes';
|
||||
|
||||
export const AppThemeAndColorModeProvider = ({ ...props }) => {
|
||||
return <ThemeProvider theme={useAppThemeAndColorModeContext()} {...props} />;
|
||||
};
|
||||
|
||||
export const useAppThemeAndColorModeContext = () => {
|
||||
const theme: AppTheme = useSelector(getAppTheme);
|
||||
const colorMode: AppColorMode = useSelector(getAppColorMode);
|
||||
|
||||
return Themes[theme][colorMode];
|
||||
};
|
||||
@ -1,7 +1,7 @@
|
||||
import { useAppThemeContext } from '@/hooks/useAppTheme';
|
||||
import { useAppThemeAndColorModeContext } from '@/hooks/useAppThemeAndColorMode';
|
||||
|
||||
const LogoShortIcon: React.FC<{ id?: string }> = ({ id }: { id?: string }) => {
|
||||
const theme = useAppThemeContext();
|
||||
const theme = useAppThemeAndColorModeContext();
|
||||
const fill = theme.logoFill;
|
||||
|
||||
return (
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Candle, TradingViewBar, TradingViewSymbol } from '@/constants/candles';
|
||||
|
||||
import { AppTheme } from '@/state/configs';
|
||||
import { AppTheme, AppColorMode } from '@/state/configs';
|
||||
|
||||
import { Themes } from '@/styles/themes';
|
||||
|
||||
@ -47,8 +47,14 @@ export const getHistorySlice = ({
|
||||
return bars.filter(({ time }) => time >= fromMs);
|
||||
};
|
||||
|
||||
export const getWidgetOverrides = (appTheme: AppTheme) => {
|
||||
const theme = Themes[appTheme];
|
||||
export const getWidgetOverrides = ({
|
||||
appTheme,
|
||||
appColorMode,
|
||||
}: {
|
||||
appTheme: AppTheme;
|
||||
appColorMode: AppColorMode;
|
||||
}) => {
|
||||
const theme = Themes[appTheme][appColorMode];
|
||||
|
||||
return {
|
||||
overrides: {
|
||||
|
||||
@ -12,8 +12,14 @@ export enum AppTheme {
|
||||
Light = 'Light',
|
||||
}
|
||||
|
||||
export enum AppColorMode {
|
||||
GreenUp = 'GreenUp',
|
||||
RedUp = 'RedUp',
|
||||
}
|
||||
|
||||
export interface ConfigsState {
|
||||
appTheme: AppTheme;
|
||||
appColorMode: AppColorMode;
|
||||
feeTiers?: kollections.List<FeeTier>;
|
||||
feeDiscounts?: FeeDiscount[];
|
||||
network?: NetworkConfigs;
|
||||
@ -41,6 +47,10 @@ const initialState: ConfigsState = {
|
||||
key: LocalStorageKey.SelectedTheme,
|
||||
defaultValue: AppTheme.Classic,
|
||||
}),
|
||||
appColorMode: getLocalStorage({
|
||||
key: LocalStorageKey.SelectedColorMode,
|
||||
defaultValue: AppColorMode.GreenUp,
|
||||
}),
|
||||
feeDiscounts: undefined,
|
||||
feeTiers: undefined,
|
||||
network: undefined,
|
||||
@ -61,6 +71,10 @@ export const configsSlice = createSlice({
|
||||
changeTheme(payload);
|
||||
state.appTheme = payload;
|
||||
},
|
||||
setAppColorMode: (state: ConfigsState, { payload }: PayloadAction<AppColorMode>) => {
|
||||
setLocalStorage({ key: LocalStorageKey.SelectedColorMode, value: payload });
|
||||
state.appColorMode = payload;
|
||||
},
|
||||
setConfigs: (state: ConfigsState, action: PayloadAction<Nullable<Configs>>) => ({
|
||||
...state,
|
||||
...action.payload,
|
||||
@ -72,4 +86,5 @@ export const configsSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const { setAppTheme, setConfigs, markLaunchIncentivesSeen } = configsSlice.actions;
|
||||
export const { setAppTheme, setAppColorMode, setConfigs, markLaunchIncentivesSeen } =
|
||||
configsSlice.actions;
|
||||
|
||||
@ -2,6 +2,8 @@ import type { RootState } from './_store';
|
||||
|
||||
export const getAppTheme = (state: RootState) => state.configs.appTheme;
|
||||
|
||||
export const getAppColorMode = (state: RootState) => state.configs.appColorMode;
|
||||
|
||||
export const getFeeTiers = (state: RootState) => state.configs.feeTiers?.toArray();
|
||||
|
||||
export const getFeeDiscounts = (state: RootState) => state.configs.feeDiscounts;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { AppTheme } from '@/state/configs';
|
||||
import type { ThemeColors } from '@/constants/styles/colors';
|
||||
import { AppTheme, AppColorMode } from '@/state/configs';
|
||||
import type { Theme, ThemeColorBase } from '@/constants/styles/colors';
|
||||
import { ColorToken, OpacityToken } from '@/constants/styles/base';
|
||||
import { generateFadedColorVariant } from '@/lib/styles';
|
||||
|
||||
const ClassicTheme: ThemeColors = {
|
||||
const ClassicThemeBase: ThemeColorBase = {
|
||||
layer0: ColorToken.GrayBlue7,
|
||||
layer1: ColorToken.GrayBlue6,
|
||||
layer2: ColorToken.GrayBlue5,
|
||||
@ -52,7 +52,7 @@ const ClassicTheme: ThemeColors = {
|
||||
tooltipBackground: generateFadedColorVariant(ColorToken.GrayBlue3, OpacityToken.Opacity66),
|
||||
};
|
||||
|
||||
const DarkTheme: ThemeColors = {
|
||||
const DarkThemeBase: ThemeColorBase = {
|
||||
layer0: ColorToken.Black,
|
||||
layer1: ColorToken.DarkGray11,
|
||||
layer2: ColorToken.DarkGray13,
|
||||
@ -101,7 +101,7 @@ const DarkTheme: ThemeColors = {
|
||||
tooltipBackground: generateFadedColorVariant(ColorToken.DarkGray6, OpacityToken.Opacity66),
|
||||
};
|
||||
|
||||
const LightTheme: ThemeColors = {
|
||||
const LightThemeBase: ThemeColorBase = {
|
||||
layer0: ColorToken.White,
|
||||
layer1: ColorToken.LightGray6,
|
||||
layer2: ColorToken.White,
|
||||
@ -150,8 +150,22 @@ const LightTheme: ThemeColors = {
|
||||
tooltipBackground: generateFadedColorVariant(ColorToken.LightGray7, OpacityToken.Opacity66),
|
||||
};
|
||||
|
||||
export const Themes = {
|
||||
[AppTheme.Classic]: ClassicTheme,
|
||||
[AppTheme.Dark]: DarkTheme,
|
||||
[AppTheme.Light]: LightTheme,
|
||||
const generateTheme = (themeBase: ThemeColorBase): Theme => {
|
||||
return {
|
||||
[AppColorMode.GreenUp]: themeBase,
|
||||
[AppColorMode.RedUp]: {
|
||||
...themeBase,
|
||||
// #InvertDirectionalColors
|
||||
positive: themeBase.negative,
|
||||
negative: themeBase.positive,
|
||||
positiveFaded: themeBase.negativeFaded,
|
||||
negativeFaded: themeBase.positiveFaded,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const Themes = {
|
||||
[AppTheme.Classic]: generateTheme(ClassicThemeBase),
|
||||
[AppTheme.Dark]: generateTheme(DarkThemeBase),
|
||||
[AppTheme.Light]: generateTheme(LightThemeBase),
|
||||
};
|
||||
|
||||
@ -5,8 +5,8 @@ import { Root, Item, Indicator } from '@radix-ui/react-radio-group';
|
||||
|
||||
import { useStringGetter } from '@/hooks';
|
||||
|
||||
import { AppTheme, setAppTheme } from '@/state/configs';
|
||||
import { getAppTheme } from '@/state/configsSelectors';
|
||||
import { AppTheme, AppColorMode, setAppTheme } from '@/state/configs';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { Themes } from '@/styles/themes';
|
||||
@ -26,6 +26,7 @@ export const DisplaySettingsDialog = ({ setIsOpen }: ElementProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
const currentTheme: AppTheme = useSelector(getAppTheme);
|
||||
const currentColorMode: AppColorMode = useSelector(getAppColorMode);
|
||||
|
||||
const sectionHeader = (heading: string) => {
|
||||
return (
|
||||
@ -56,13 +57,13 @@ export const DisplaySettingsDialog = ({ setIsOpen }: ElementProps) => {
|
||||
<Styled.AppThemeItem
|
||||
key={theme}
|
||||
value={theme}
|
||||
backgroundcolor={Themes[theme].layer2}
|
||||
gridcolor={Themes[theme].borderDefault}
|
||||
backgroundcolor={Themes[theme][currentColorMode].layer2}
|
||||
gridcolor={Themes[theme][currentColorMode].borderDefault}
|
||||
onClick={() => {
|
||||
dispatch(setAppTheme(theme));
|
||||
}}
|
||||
>
|
||||
<Styled.AppThemeHeader textcolor={Themes[theme].textPrimary}>
|
||||
<Styled.AppThemeHeader textcolor={Themes[theme][currentColorMode].textPrimary}>
|
||||
{stringGetter({ key: label })}
|
||||
</Styled.AppThemeHeader>
|
||||
<Styled.Image src="/chart-bars.svg" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user