diff --git a/.ladle/components.tsx b/.ladle/components.tsx
index 04ee536..c6e7beb 100644
--- a/.ladle/components.tsx
+++ b/.ladle/components.tsx
@@ -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
Active Theme:
-
+
{[
{
value: AppTheme.Classic,
@@ -66,20 +66,31 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
label: 'Light theme',
},
].map(({ value, label }) => (
-
+
+ ))}
+
+ Active Color Mode:
+
+ {[
+ {
+ value: AppColorMode.GreenUp,
+ label: 'Green up',
+ },
+ {
+ value: AppColorMode.RedUp,
+ label: 'Red up',
+ },
+ ].map(({ value, label }) => (
+
))}
-
+
{children}
-
-
+
+
);
};
diff --git a/src/App.tsx b/src/App.tsx
index 23d1a39..d80de5f 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -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 = () => {
diff --git a/src/components/Button.tsx b/src/components/Button.tsx
index dff6cdb..2d03f59 100644
--- a/src/components/Button.tsx
+++ b/src/components/Button.tsx
@@ -102,13 +102,13 @@ const buttonActionVariants = {
[ButtonAction.Create]: css`
--button-textColor: var(--color-text-2);
- --button-backgroundColor: var(--color-positive);
+ --button-backgroundColor: var(--color-success);
--button-border: solid var(--border-width) var(--color-border-white);
`,
[ButtonAction.Destroy]: css`
--button-textColor: var(--color-text-2);
- --button-backgroundColor: var(--color-negative);
+ --button-backgroundColor: var(--color-error);
--button-border: solid var(--border-width) var(--color-border-white);
`,
@@ -119,7 +119,7 @@ const buttonActionVariants = {
`,
[ButtonAction.Reset]: css`
- --button-textColor: var(--color-negative);
+ --button-textColor: var(--color-error);
--button-backgroundColor: var(--color-layer-3);
--button-border: solid var(--border-width) var(--color-border-red);
`,
diff --git a/src/components/CopyButton.tsx b/src/components/CopyButton.tsx
index bff3368..33da9d1 100644
--- a/src/components/CopyButton.tsx
+++ b/src/components/CopyButton.tsx
@@ -87,7 +87,7 @@ Styled.Icon = styled(Icon)<{ copied: boolean }>`
${({ copied }) =>
copied &&
css`
- color: var(--color-positive);
+ color: var(--color-success);
`}
`;
@@ -96,7 +96,7 @@ Styled.IconButton = styled(IconButton)<{ copied: boolean }>`
copied &&
css`
svg {
- color: var(--color-positive);
+ color: var(--color-success);
}
`}
`;
diff --git a/src/components/DiffArrow.tsx b/src/components/DiffArrow.tsx
index b140042..6007683 100644
--- a/src/components/DiffArrow.tsx
+++ b/src/components/DiffArrow.tsx
@@ -62,6 +62,6 @@ Styled.DiffArrowContainer = styled.span`
`,
down: css`
transform: rotate(90deg);
- `
+ `,
}[direction || 'right'])}
`;
diff --git a/src/components/DiffOutput.tsx b/src/components/DiffOutput.tsx
index f6f52e4..665aacf 100644
--- a/src/components/DiffOutput.tsx
+++ b/src/components/DiffOutput.tsx
@@ -75,7 +75,7 @@ Styled.DiffValue = styled.div<{ hasInvalidNewValue?: boolean }>`
${({ hasInvalidNewValue }) =>
hasInvalidNewValue &&
css`
- color: var(--color-negative);
+ color: var(--color-error);
`}
`;
diff --git a/src/components/DropdownMenu.stories.tsx b/src/components/DropdownMenu.stories.tsx
index bee3c62..939ae48 100644
--- a/src/components/DropdownMenu.stories.tsx
+++ b/src/components/DropdownMenu.stories.tsx
@@ -6,29 +6,34 @@ import { StoryWrapper } from '.ladle/components';
export const DropdownMenuStory: Story> = (args) => {
const exampleItems = [
+ {
+ value: '0',
+ label: 'Item 0',
+ onSelect: () => alert('Item 0 action'),
+ },
{
value: '1',
- label: 'Item 1',
+ label: 'Item 1 (accent)',
onSelect: () => alert('Item 1 action'),
+ highlightColor: 'accent',
},
{
value: '2',
- label: 'Item 2',
+ label: 'Item 2 (create)',
onSelect: () => alert('Item 2 action'),
+ highlightColor: 'create',
},
{
value: '3',
- label: 'Item 3',
+ label: 'Item 3 (destroy)',
onSelect: () => alert('Item 3 action'),
+ highlightColor: 'destroy',
},
];
return (
-
+
Menu
diff --git a/src/components/DropdownMenu.tsx b/src/components/DropdownMenu.tsx
index 6b74602..908e3fa 100644
--- a/src/components/DropdownMenu.tsx
+++ b/src/components/DropdownMenu.tsx
@@ -13,7 +13,7 @@ export type DropdownMenuItem = {
label: React.ReactNode;
onSelect?: () => void;
separator?: boolean;
- highlightColor?: 'accent' | 'positive' | 'negative';
+ highlightColor?: 'accent' | 'create' | 'destroy';
};
type StyleProps = {
@@ -82,7 +82,7 @@ Styled.Separator = styled(Separator)`
margin: 0.25rem 1rem;
`;
-Styled.Item = styled(Item)<{ $highlightColor: 'accent' | 'positive' | 'negative' }>`
+Styled.Item = styled(Item)<{ $highlightColor: 'accent' | 'create' | 'destroy' }>`
${popoverMixins.item}
--item-font-size: var(--dropdownMenu-item-font-size);
${({ $highlightColor }) =>
@@ -90,11 +90,11 @@ Styled.Item = styled(Item)<{ $highlightColor: 'accent' | 'positive' | 'negative'
['accent']: `
--item-highlighted-textColor: var(--color-accent);
`,
- ['positive']: `
- --item-highlighted-textColor: var(--color-positive);
+ ['create']: `
+ --item-highlighted-textColor: var(--color-success);
`,
- ['negative']: `
- --item-highlighted-textColor: var(--color-negative);
+ ['destroy']: `
+ --item-highlighted-textColor: var(--color-error);
`,
}[$highlightColor])}
diff --git a/src/components/WithConfirmationPopover.tsx b/src/components/WithConfirmationPopover.tsx
index f2aabcc..b65c5a7 100644
--- a/src/components/WithConfirmationPopover.tsx
+++ b/src/components/WithConfirmationPopover.tsx
@@ -117,7 +117,7 @@ Styled.ConfirmButton = styled(Styled.IconButton)`
--button-backgroundColor: hsla(203, 25%, 19%, 1);
svg {
- color: var(--color-positive);
+ color: var(--color-success);
}
`;
@@ -125,7 +125,7 @@ Styled.CancelButton = styled(Styled.IconButton)`
--button-backgroundColor: hsla(296, 16%, 18%, 1);
svg {
- color: var(--color-negative);
+ color: var(--color-error);
width: 0.8em;
height: 0.8em;
diff --git a/src/constants/localStorage.ts b/src/constants/localStorage.ts
index 863f24e..5ac32cb 100644
--- a/src/constants/localStorage.ts
+++ b/src/constants/localStorage.ts
@@ -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',
diff --git a/src/constants/styles/colors.ts b/src/constants/styles/colors.ts
index a7c9eb1..dc9429e 100644
--- a/src/constants/styles/colors.ts
+++ b/src/constants/styles/colors.ts
@@ -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 &
@@ -47,8 +54,13 @@ type StatusColors = {
success: string;
warning: string;
error: string;
+ successFaded: string;
+ warningFaded: string;
+ errorFaded: string;
};
+/** ##InvertDirectionalColors
+ * When adding colors here, make sure to update linked function to invert colors for AppColorMode. */
type DirectionalColors = {
positive: string;
negative: string;
diff --git a/src/hooks/Orderbook/useDrawOrderbook.ts b/src/hooks/Orderbook/useDrawOrderbook.ts
index 887d3f3..7577796 100644
--- a/src/hooks/Orderbook/useDrawOrderbook.ts
+++ b/src/hooks/Orderbook/useDrawOrderbook.ts
@@ -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;
@@ -53,7 +53,7 @@ export const useDrawOrderbook = ({
const { stepSizeDecimals = TOKEN_DECIMALS, tickSizeDecimals = SMALL_USD_DECIMALS } =
useSelector(getCurrentMarketConfig, shallowEqual) || {};
const prevData = useRef(data);
- const theme = useAppThemeContext();
+ const theme = useAppThemeAndColorModeContext();
/**
* Scale canvas using device pixel ratio to unblur drawn text
diff --git a/src/hooks/tradingView/useTradingView.ts b/src/hooks/tradingView/useTradingView.ts
index 756ecc2..68065d8 100644
--- a/src/hooks/tradingView/useTradingView.ts
+++ b/src/hooks/tradingView/useTradingView.ts
@@ -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 };
};
diff --git a/src/hooks/tradingView/useTradingViewTheme.ts b/src/hooks/tradingView/useTradingViewTheme.ts
index 6436063..b0ed677 100644
--- a/src/hooks/tradingView/useTradingViewTheme.ts
+++ b/src/hooks/tradingView/useTradingViewTheme.ts
@@ -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]);
};
diff --git a/src/hooks/useAppTheme.tsx b/src/hooks/useAppTheme.tsx
deleted file mode 100644
index 790cc89..0000000
--- a/src/hooks/useAppTheme.tsx
+++ /dev/null
@@ -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
-};
-
-export const useAppThemeContext = () => {
- const theme: AppTheme = useSelector(getAppTheme);
- return Themes[theme];
-}
diff --git a/src/hooks/useAppThemeAndColorMode.tsx b/src/hooks/useAppThemeAndColorMode.tsx
new file mode 100644
index 0000000..08572fa
--- /dev/null
+++ b/src/hooks/useAppThemeAndColorMode.tsx
@@ -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 ;
+};
+
+export const useAppThemeAndColorModeContext = () => {
+ const theme: AppTheme = useSelector(getAppTheme);
+ const colorMode: AppColorMode = useSelector(getAppColorMode);
+
+ return Themes[theme][colorMode];
+};
diff --git a/src/icons/logo-short.tsx b/src/icons/logo-short.tsx
index 81ffe2f..a681fdc 100644
--- a/src/icons/logo-short.tsx
+++ b/src/icons/logo-short.tsx
@@ -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 (
diff --git a/src/layout/Footer/FooterDesktop.tsx b/src/layout/Footer/FooterDesktop.tsx
index d6f3d1c..7426cd2 100644
--- a/src/layout/Footer/FooterDesktop.tsx
+++ b/src/layout/Footer/FooterDesktop.tsx
@@ -127,7 +127,7 @@ Styled.StatusDot = styled.div<{ exchangeStatus: ExchangeStatus }>`
background-color: ${({ exchangeStatus }) =>
({
[ExchangeStatus.Degraded]: css`var(--color-warning)`,
- [ExchangeStatus.Operational]: css`var(--color-positive)`,
+ [ExchangeStatus.Operational]: css`var(--color-success)`,
}[exchangeStatus])};
`;
diff --git a/src/lib/orders.ts b/src/lib/orders.ts
index 1aeb926..55c0e46 100644
--- a/src/lib/orders.ts
+++ b/src/lib/orders.ts
@@ -43,19 +43,19 @@ export const getStatusIconInfo = ({
case AbacusOrderStatus.filled: {
return {
statusIcon: IconName.OrderFilled,
- statusIconColor: `var(--color-positive)`,
+ statusIconColor: `var(--color-success)`,
};
}
case AbacusOrderStatus.cancelled: {
return {
statusIcon: IconName.OrderCanceled,
- statusIconColor: `var(--color-negative)`,
+ statusIconColor: `var(--color-error)`,
};
}
case AbacusOrderStatus.canceling: {
return {
statusIcon: IconName.OrderPending,
- statusIconColor: `var(--color-negative)`,
+ statusIconColor: `var(--color-error)`,
};
}
case AbacusOrderStatus.untriggered: {
diff --git a/src/lib/tradingView/utils.ts b/src/lib/tradingView/utils.ts
index 5a50209..27c26b6 100644
--- a/src/lib/tradingView/utils.ts
+++ b/src/lib/tradingView/utils.ts
@@ -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: {
diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx
index ff362bd..270131b 100644
--- a/src/pages/Profile.tsx
+++ b/src/pages/Profile.tsx
@@ -286,10 +286,10 @@ Styled.ConnectedIcon = styled.div`
height: 0.5rem;
width: 0.5rem;
margin-right: 0.25rem;
- background: var(--color-positive);
+ background: var(--color-success);
border-radius: 50%;
- box-shadow: 0 0 0 0.2rem var(--color-gradient-positive);
+ box-shadow: 0 0 0 0.2rem var(--color-gradient-success);
`;
Styled.Address = styled.h1`
@@ -318,7 +318,7 @@ Styled.ActionButton = styled(IconButton)<{ iconName?: IconName }>`
${({ iconName }) =>
iconName === IconName.Close
? css`
- --button-textColor: var(--color-negative);
+ --button-textColor: var(--color-error);
--button-icon-size: 0.75em;
`
: iconName === IconName.Transfer &&
diff --git a/src/state/configs.ts b/src/state/configs.ts
index 9da0355..db1b3e7 100644
--- a/src/state/configs.ts
+++ b/src/state/configs.ts
@@ -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;
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) => {
+ setLocalStorage({ key: LocalStorageKey.SelectedColorMode, value: payload });
+ state.appColorMode = payload;
+ },
setConfigs: (state: ConfigsState, action: PayloadAction>) => ({
...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;
diff --git a/src/state/configsSelectors.ts b/src/state/configsSelectors.ts
index d83bd84..51dc198 100644
--- a/src/state/configsSelectors.ts
+++ b/src/state/configsSelectors.ts
@@ -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;
diff --git a/src/styles/globalStyle.ts b/src/styles/globalStyle.ts
index bf534cd..44b284d 100644
--- a/src/styles/globalStyle.ts
+++ b/src/styles/globalStyle.ts
@@ -29,6 +29,9 @@ export const GlobalStyle = createGlobalStyle`
--color-success: ${({ theme }) => theme.success};
--color-warning: ${({ theme }) => theme.warning};
--color-error: ${({ theme }) => theme.error};
+ --color-gradient-success: ${({ theme }) => theme.successFaded};
+ --color-gradient-warning: ${({ theme }) => theme.warningFaded};
+ --color-gradient-error: ${({ theme }) => theme.errorFaded};
--color-positive: ${({ theme }) => theme.positive};
--color-negative: ${({ theme }) => theme.negative};
diff --git a/src/styles/themes.ts b/src/styles/themes.ts
index 4b910c5..6418027 100644
--- a/src/styles/themes.ts
+++ b/src/styles/themes.ts
@@ -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,
@@ -31,6 +31,9 @@ const ClassicTheme: ThemeColors = {
success: ColorToken.Green1,
warning: ColorToken.Yellow0,
error: ColorToken.Red2,
+ successFaded: generateFadedColorVariant(ColorToken.Green1, OpacityToken.Opacity16),
+ warningFaded: generateFadedColorVariant(ColorToken.Yellow0, OpacityToken.Opacity16),
+ errorFaded: generateFadedColorVariant(ColorToken.Red2, OpacityToken.Opacity16),
positive: ColorToken.Green1,
negative: ColorToken.Red2,
@@ -52,7 +55,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,
@@ -80,6 +83,9 @@ const DarkTheme: ThemeColors = {
success: ColorToken.Green0,
warning: ColorToken.Yellow0,
error: ColorToken.Red0,
+ successFaded: generateFadedColorVariant(ColorToken.Green0, OpacityToken.Opacity16),
+ warningFaded: generateFadedColorVariant(ColorToken.Yellow0, OpacityToken.Opacity16),
+ errorFaded: generateFadedColorVariant(ColorToken.Red0, OpacityToken.Opacity16),
positive: ColorToken.Green0,
negative: ColorToken.Red0,
@@ -101,7 +107,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,
@@ -129,6 +135,9 @@ const LightTheme: ThemeColors = {
success: ColorToken.Green2,
warning: ColorToken.Yellow0,
error: ColorToken.Red1,
+ successFaded: generateFadedColorVariant(ColorToken.Green2, OpacityToken.Opacity16),
+ warningFaded: generateFadedColorVariant(ColorToken.Yellow0, OpacityToken.Opacity16),
+ errorFaded: generateFadedColorVariant(ColorToken.Red1, OpacityToken.Opacity16),
positive: ColorToken.Green2,
negative: ColorToken.Red1,
@@ -150,8 +159,22 @@ const LightTheme: ThemeColors = {
tooltipBackground: generateFadedColorVariant(ColorToken.LightGray7, OpacityToken.Opacity66),
};
+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]: ClassicTheme,
- [AppTheme.Dark]: DarkTheme,
- [AppTheme.Light]: LightTheme,
+ [AppTheme.Classic]: generateTheme(ClassicThemeBase),
+ [AppTheme.Dark]: generateTheme(DarkThemeBase),
+ [AppTheme.Light]: generateTheme(LightThemeBase),
};
diff --git a/src/views/AccountInfo/AccountInfoConnectedState.tsx b/src/views/AccountInfo/AccountInfoConnectedState.tsx
index 1627c7f..9996def 100644
--- a/src/views/AccountInfo/AccountInfoConnectedState.tsx
+++ b/src/views/AccountInfo/AccountInfoConnectedState.tsx
@@ -231,7 +231,7 @@ Styled.CircleContainer = styled.div`
`;
Styled.Icon = styled(Icon)`
- color: var(--color-negative);
+ color: var(--color-error);
`;
Styled.WithUsage = styled.div`
diff --git a/src/views/PositionInfo.tsx b/src/views/PositionInfo.tsx
index ac79452..2ea9477 100644
--- a/src/views/PositionInfo.tsx
+++ b/src/views/PositionInfo.tsx
@@ -557,11 +557,11 @@ Styled.PositionTile = styled(PositionTile)``;
Styled.ClosePositionButton = styled(Button)`
--button-border: solid var(--border-width) var(--color-border-red);
- --button-textColor: var(--color-negative);
+ --button-textColor: var(--color-error);
`;
Styled.ClosePositionToggleButton = styled(ToggleButton)`
--button-border: solid var(--border-width) var(--color-border-red);
- --button-toggle-off-textColor: var(--color-negative);
- --button-toggle-on-textColor: var(--color-negative);
+ --button-toggle-off-textColor: var(--color-error);
+ --button-toggle-on-textColor: var(--color-error);
`;
diff --git a/src/views/dialogs/DisplaySettingsDialog.tsx b/src/views/dialogs/DisplaySettingsDialog.tsx
index 1cdd030..8f8e451 100644
--- a/src/views/dialogs/DisplaySettingsDialog.tsx
+++ b/src/views/dialogs/DisplaySettingsDialog.tsx
@@ -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, setAppColorMode } 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) => {
{
dispatch(setAppTheme(theme));
}}
>
-
+
{stringGetter({ key: label })}
@@ -75,6 +76,48 @@ export const DisplaySettingsDialog = ({ setIsOpen }: ElementProps) => {
);
};
+ const colorModeOptions = () => {
+ return (
+
+ {[
+ {
+ colorMode: AppColorMode.GreenUp,
+ label: STRING_KEYS.GREEN_IS_UP,
+ },
+ {
+ colorMode: AppColorMode.RedUp,
+ label: STRING_KEYS.RED_IS_UP,
+ },
+ ].map(({ colorMode, label }) => (
+ {
+ dispatch(setAppColorMode(colorMode));
+ }}
+ >
+
+
+
+
+
+ {stringGetter({ key: label })}
+
+
+
+ ))}
+
+ );
+ };
+
return (
);
};
@@ -110,6 +157,11 @@ Styled.AppThemeRoot = styled(Root)`
grid-template-columns: 1fr 1fr;
`;
+Styled.ColorPreferenceRoot = styled(Root)`
+ ${gridStyle}
+ grid-template-columns: 1fr;
+`;
+
Styled.Item = styled(Item)`
--border-color: var(--color-border);
--item-padding: 0.75rem;
@@ -120,9 +172,19 @@ Styled.Item = styled(Item)`
border: solid var(--border-width) var(--border-color);
border-radius: 0.875rem;
+
padding: var(--item-padding);
`;
+Styled.ColorPreferenceItem = styled(Styled.Item)`
+ &[data-state='checked'] {
+ background-color: var(--color-layer-4);
+ }
+
+ ${layoutMixins.row}
+ justify-content: space-between;
+`;
+
Styled.AppThemeItem = styled(Styled.Item)<{ backgroundcolor: string; gridcolor: string }>`
${({ backgroundcolor, gridcolor }) => css`
--themePanel-backgroundColor: ${backgroundcolor};
@@ -133,6 +195,7 @@ Styled.AppThemeItem = styled(Styled.Item)<{ backgroundcolor: string; gridcolor:
flex-direction: column;
position: relative;
width: 100%;
+
background-color: var(--themePanel-backgroundColor);
&::before {
@@ -169,6 +232,43 @@ Styled.Image = styled.img`
z-index: 1;
`;
+Styled.ColorPreferenceLabel = styled.div`
+ ${layoutMixins.inlineRow};
+ gap: 1ch;
+`;
+
+Styled.ArrowIconContainer = styled.div`
+ ${layoutMixins.column}
+ gap: 0.5ch;
+
+ svg {
+ height: 0.75em;
+ width: 0.75em;
+ }
+`;
+
+Styled.ArrowIcon = styled(Icon)<{ direction: 'up' | 'down'; color: 'green' | 'red' }>`
+ ${({ direction }) =>
+ ({
+ ['up']: css`
+ transform: rotate(-90deg);
+ `,
+ ['down']: css`
+ transform: rotate(90deg);
+ `,
+ }[direction])}
+
+ ${({ color }) =>
+ ({
+ ['green']: css`
+ color: var(--color-success);
+ `,
+ ['red']: css`
+ color: var(--color-error);
+ `,
+ }[color])}
+`;
+
const indicatorStyle = css`
--indicator-size: 1.25rem;
--icon-size: 0.5rem;
@@ -182,9 +282,33 @@ const indicatorStyle = css`
justify-content: center;
`;
+Styled.DotIndicator = styled.div<{ $selected: boolean }>`
+ ${indicatorStyle}
+ --background-color: var(--color-layer-2);
+ --border-color: var(--color-border);
+
+ ${({ $selected }) =>
+ $selected &&
+ css`
+ --background-color: var(--color-accent);
+ --border-color: var(--color-accent);
+
+ &::after {
+ content: '';
+ display: block;
+ width: var(--icon-size);
+ height: var(--icon-size);
+ background-color: var(--color-layer-2);
+ border-radius: 50%;
+ }
+ `}
+
+ background-color: var(--background-color);
+ border: solid var(--border-width) var(--border-color);
+`;
+
Styled.CheckIndicator = styled(Indicator)`
${indicatorStyle}
-
position: absolute;
bottom: var(--item-padding);
right: var(--item-padding);
diff --git a/src/views/dialogs/OnboardingDialog/GenerateKeys.tsx b/src/views/dialogs/OnboardingDialog/GenerateKeys.tsx
index c65186b..ab824d5 100644
--- a/src/views/dialogs/OnboardingDialog/GenerateKeys.tsx
+++ b/src/views/dialogs/OnboardingDialog/GenerateKeys.tsx
@@ -323,7 +323,7 @@ Styled.ReceiptArea = styled.div`
`;
Styled.Green = styled.span`
- color: var(--color-positive);
+ color: var(--color-success);
`;
Styled.GreenCheckCircle = styled(GreenCheckCircle)`
diff --git a/src/views/forms/AccountManagementForms/WithdrawForm.tsx b/src/views/forms/AccountManagementForms/WithdrawForm.tsx
index 8a9d413..33f26ef 100644
--- a/src/views/forms/AccountManagementForms/WithdrawForm.tsx
+++ b/src/views/forms/AccountManagementForms/WithdrawForm.tsx
@@ -453,6 +453,6 @@ Styled.FormInputButton = styled(Button)`
Styled.CheckIcon = styled(Icon)`
margin: 0 1ch;
- color: var(--color-positive);
+ color: var(--color-success);
font-size: 0.625rem;
`;
diff --git a/src/views/forms/TransferForm.tsx b/src/views/forms/TransferForm.tsx
index 291e768..4775c85 100644
--- a/src/views/forms/TransferForm.tsx
+++ b/src/views/forms/TransferForm.tsx
@@ -441,7 +441,7 @@ Styled.DestinationInputLabel = styled.span`
${layoutMixins.inlineRow}
svg {
- color: var(--color-positive);
+ color: var(--color-success);
}
`;
diff --git a/src/views/menus/AccountMenu.tsx b/src/views/menus/AccountMenu.tsx
index b3df36d..ac7bc6f 100644
--- a/src/views/menus/AccountMenu.tsx
+++ b/src/views/menus/AccountMenu.tsx
@@ -203,7 +203,7 @@ export const AccountMenu = () => {
value: 'MnemonicExport',
icon: ,
label: {stringGetter({ key: STRING_KEYS.EXPORT_SECRET_PHRASE })},
- highlightColor: 'negative',
+ highlightColor: 'destroy',
onSelect: () => dispatch(openDialog({ type: DialogTypes.MnemonicExport })),
},
].filter(isTruthy)
@@ -212,7 +212,7 @@ export const AccountMenu = () => {
value: 'Disconnect',
icon: ,
label: stringGetter({ key: STRING_KEYS.DISCONNECT }),
- highlightColor: 'negative',
+ highlightColor: 'destroy',
onSelect: () => dispatch(openDialog({ type: DialogTypes.DisconnectWallet })),
},
].filter(isTruthy)}
diff --git a/src/views/notifications/BlockRewardNotification/index.tsx b/src/views/notifications/BlockRewardNotification/index.tsx
index 200522b..fce36ee 100644
--- a/src/views/notifications/BlockRewardNotification/index.tsx
+++ b/src/views/notifications/BlockRewardNotification/index.tsx
@@ -72,7 +72,7 @@ Styled.Notification = styled(Notification)`
Styled.Output = styled(Output)`
&:before {
content: '+';
- color: var(--color-positive);
+ color: var(--color-success);
margin-right: 0.5ch;
}
`;
diff --git a/src/views/notifications/TransferStatusNotification/TransferStatusSteps.tsx b/src/views/notifications/TransferStatusNotification/TransferStatusSteps.tsx
index 3cb050b..96c1adf 100644
--- a/src/views/notifications/TransferStatusNotification/TransferStatusSteps.tsx
+++ b/src/views/notifications/TransferStatusNotification/TransferStatusSteps.tsx
@@ -179,7 +179,7 @@ Styled.Icon = styled.div<{ state: 'complete' | 'default' }>`
${({ state }) =>
({
['complete']: css`
- color: var(--color-positive);
+ color: var(--color-success);
`,
['default']: css`
color: var(--color-text-0);
diff --git a/src/views/tables/OrdersTable/OrderActionsCell.tsx b/src/views/tables/OrdersTable/OrderActionsCell.tsx
index e2fac52..fd4c867 100644
--- a/src/views/tables/OrdersTable/OrderActionsCell.tsx
+++ b/src/views/tables/OrdersTable/OrderActionsCell.tsx
@@ -82,6 +82,6 @@ Styled.ActionButton = styled(IconButton)`
Styled.CancelButton = styled(Styled.ActionButton)`
&:not(:disabled) {
- --button-textColor: var(--color-negative);
+ --button-textColor: var(--color-error);
}
`;