add functionality, without user exposure yet

This commit is contained in:
mulan xia 2024-01-29 15:22:34 -05:00
parent d81e6b3a2c
commit eacab6ae04
No known key found for this signature in database
GPG Key ID: C6CE526613568D73
15 changed files with 148 additions and 65 deletions

View File

@ -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>
);
};

View File

@ -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 = () => {

View File

@ -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',

View File

@ -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;

View File

@ -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

View File

@ -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 };
};

View File

@ -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]);
};

View File

@ -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];
}

View 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];
};

View File

@ -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 (

View File

@ -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: {

View File

@ -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;

View File

@ -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;

View File

@ -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),
};

View File

@ -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" />