Compare commits
15 Commits
main
...
mulan-inve
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa059d79d9 | ||
|
|
53e0597fcc | ||
|
|
a4b640827e | ||
|
|
02be0ead9e | ||
|
|
ae102b8990 | ||
|
|
d72846670f | ||
|
|
93f8ef7cce | ||
|
|
4563fdab03 | ||
|
|
7309f88515 | ||
|
|
67ad0defce | ||
|
|
ea10585b89 | ||
|
|
6fc037ddeb | ||
|
|
292e16603d | ||
|
|
69d00e39ef | ||
|
|
eee19b3b93 |
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
19
public/chart-bars-background.svg
Normal file
19
public/chart-bars-background.svg
Normal file
@ -0,0 +1,19 @@
|
||||
<svg width="120" height="97" viewBox="0 0 120 97" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect y="8" width="120" height="1" fill="currentColor"/>
|
||||
<rect y="18" width="120" height="1" fill="currentColor"/>
|
||||
<rect y="28" width="120" height="1" fill="currentColor"/>
|
||||
<rect y="38" width="120" height="1" fill="currentColor"/>
|
||||
<rect y="48" width="120" height="1" fill="currentColor"/>
|
||||
<rect y="58" width="120" height="1" fill="currentColor"/>
|
||||
<rect y="68" width="120" height="1" fill="currentColor"/>
|
||||
<rect y="78" width="120" height="1" fill="currentColor"/>
|
||||
<rect y="88" width="120" height="1" fill="currentColor"/>
|
||||
<rect x="18" width="1" height="97" fill="currentColor"/>
|
||||
<rect x="32" width="1" height="97" fill="currentColor"/>
|
||||
<rect x="46" width="1" height="97" fill="currentColor"/>
|
||||
<rect x="60" width="1" height="97" fill="currentColor"/>
|
||||
<rect x="74" width="1" height="97" fill="currentColor"/>
|
||||
<rect x="88" width="1" height="97" fill="currentColor"/>
|
||||
<rect x="102" width="1" height="97" fill="currentColor"/>
|
||||
<path d="M0 0H120V97H0V0Z" fill="url(#paint0_radial_314_37586)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
20
public/chart-bars.svg
Normal file
20
public/chart-bars.svg
Normal file
@ -0,0 +1,20 @@
|
||||
<svg width="90" height="39" viewBox="0 0 90 39" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect y="31.2344" width="2.57142" height="7.71427" fill="#3ED9A4"/>
|
||||
<rect x="5.14258" y="28.6648" width="2.57142" height="5.14284" fill="#E45555"/>
|
||||
<rect x="25.7139" y="26.0923" width="2.57142" height="10.2857" fill="#E45555"/>
|
||||
<rect x="51.4283" y="28.6648" width="2.57142" height="5.14284" fill="#E45555"/>
|
||||
<rect x="56.5712" y="31.2344" width="2.57142" height="5.14284" fill="#E45555"/>
|
||||
<rect x="77.1426" y="18.3767" width="2.57142" height="5.14284" fill="#E45555"/>
|
||||
<rect x="41.1427" y="23.5198" width="2.57142" height="5.14284" fill="#E45555"/>
|
||||
<rect x="10.2856" y="28.6648" width="2.57142" height="10.2857" fill="#3ED9A4"/>
|
||||
<rect x="61.7143" y="23.5198" width="2.57142" height="10.2857" fill="#3ED9A4"/>
|
||||
<rect x="66.8569" y="20.9492" width="2.57142" height="5.14284" fill="#3ED9A4"/>
|
||||
<rect x="71.9997" y="13.2346" width="2.57142" height="7.71427" fill="#3ED9A4"/>
|
||||
<rect x="82.2856" y="10.6631" width="2.57142" height="10.2857" fill="#3ED9A4"/>
|
||||
<rect x="87.4287" y="0.37793" width="2.57142" height="15.4285" fill="#3ED9A4"/>
|
||||
<rect x="15.4284" y="26.0923" width="2.57142" height="5.14284" fill="#3ED9A4"/>
|
||||
<rect x="20.5714" y="23.5198" width="2.57142" height="5.14284" fill="#3ED9A4"/>
|
||||
<rect x="30.857" y="31.2344" width="2.57142" height="5.14284" fill="#3ED9A4"/>
|
||||
<rect x="35.9999" y="26.0923" width="2.57142" height="5.14284" fill="#3ED9A4"/>
|
||||
<rect x="46.2853" y="26.0923" width="2.57142" height="2.57142" fill="#3ED9A4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -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 = () => {
|
||||
|
||||
@ -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);
|
||||
`,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
@ -62,6 +62,6 @@ Styled.DiffArrowContainer = styled.span<DiffArrowProps>`
|
||||
`,
|
||||
down: css`
|
||||
transform: rotate(90deg);
|
||||
`
|
||||
`,
|
||||
}[direction || 'right'])}
|
||||
`;
|
||||
|
||||
@ -75,7 +75,7 @@ Styled.DiffValue = styled.div<{ hasInvalidNewValue?: boolean }>`
|
||||
${({ hasInvalidNewValue }) =>
|
||||
hasInvalidNewValue &&
|
||||
css`
|
||||
color: var(--color-negative);
|
||||
color: var(--color-error);
|
||||
`}
|
||||
`;
|
||||
|
||||
|
||||
@ -6,29 +6,34 @@ import { StoryWrapper } from '.ladle/components';
|
||||
|
||||
export const DropdownMenuStory: Story<Parameters<typeof DropdownMenu>> = (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 (
|
||||
<StoryWrapper>
|
||||
<DropdownMenu
|
||||
{...args}
|
||||
items={exampleItems}
|
||||
>
|
||||
<DropdownMenu {...args} items={exampleItems}>
|
||||
<span>Menu</span>
|
||||
</DropdownMenu>
|
||||
</StoryWrapper>
|
||||
|
||||
@ -13,7 +13,7 @@ export type DropdownMenuItem<T> = {
|
||||
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])}
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type { Story } from '@ladle/react';
|
||||
|
||||
import { Panel } from '@/components/Panel';
|
||||
import { Panel, PanelProps } from '@/components/Panel';
|
||||
|
||||
import { StoryWrapper } from '.ladle/components';
|
||||
|
||||
export const PanelStory: Story<{ slotHeader: React.ReactNode, children?: React.ReactNode }> = (args) => {
|
||||
export const PanelStory: Story<PanelProps> = (args) => {
|
||||
return (
|
||||
<StoryWrapper>
|
||||
<Panel {...args} />
|
||||
@ -13,6 +13,8 @@ export const PanelStory: Story<{ slotHeader: React.ReactNode, children?: React.R
|
||||
};
|
||||
|
||||
PanelStory.args = {
|
||||
slotHeader: 'Header',
|
||||
slotHeaderContent: 'Header',
|
||||
children: 'Content',
|
||||
slotRight: '1️⃣',
|
||||
hasSeparator: true,
|
||||
};
|
||||
|
||||
@ -6,7 +6,7 @@ import { Icon, IconName } from '@/components/Icon';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { breakpoints } from '@/styles';
|
||||
|
||||
type PanelProps = {
|
||||
type ElementProps = {
|
||||
slotHeaderContent?: React.ReactNode;
|
||||
slotHeader?: React.ReactNode;
|
||||
slotRight?: React.ReactNode;
|
||||
@ -16,11 +16,13 @@ type PanelProps = {
|
||||
onClick?: () => void;
|
||||
};
|
||||
|
||||
type PanelStyleProps = {
|
||||
type StyleProps = {
|
||||
className?: string;
|
||||
hasSeparator?: boolean;
|
||||
};
|
||||
|
||||
export type PanelProps = ElementProps & StyleProps;
|
||||
|
||||
export const Panel = ({
|
||||
slotHeaderContent,
|
||||
slotHeader,
|
||||
@ -31,7 +33,7 @@ export const Panel = ({
|
||||
onClick,
|
||||
hasSeparator,
|
||||
className,
|
||||
}: PanelProps & PanelStyleProps) => (
|
||||
}: PanelProps) => (
|
||||
<Styled.Panel onClick={onClick} className={className}>
|
||||
<Styled.Left>
|
||||
{href ? (
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ export enum DialogTypes {
|
||||
ClosePosition = 'ClosePosition',
|
||||
Deposit = 'Deposit',
|
||||
DisconnectWallet = 'DisconnectWallet',
|
||||
DisplaySettings = 'DisplaySettings',
|
||||
ExchangeOffline = 'ExchangeOffline',
|
||||
ExternalLink = 'ExternalLink',
|
||||
FillDetails = 'FillDetails',
|
||||
|
||||
@ -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 &
|
||||
@ -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;
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -9,6 +9,7 @@ import { getActiveDialog } from '@/state/dialogsSelectors';
|
||||
import { ClosePositionDialog } from '@/views/dialogs/ClosePositionDialog';
|
||||
import { DepositDialog } from '@/views/dialogs/DepositDialog';
|
||||
import { DisconnectDialog } from '@/views/dialogs/DisconnectDialog';
|
||||
import { DisplaySettingsDialog } from '@/views/dialogs/DisplaySettingsDialog';
|
||||
import { ExchangeOfflineDialog } from '@/views/dialogs/ExchangeOfflineDialog';
|
||||
import { HelpDialog } from '@/views/dialogs/HelpDialog';
|
||||
import { ExternalLinkDialog } from '@/views/dialogs/ExternalLinkDialog';
|
||||
@ -51,6 +52,7 @@ export const DialogManager = () => {
|
||||
return {
|
||||
[DialogTypes.ClosePosition]: <ClosePositionDialog {...modalProps} />,
|
||||
[DialogTypes.Deposit]: <DepositDialog {...modalProps} />,
|
||||
[DialogTypes.DisplaySettings]: <DisplaySettingsDialog {...modalProps} />,
|
||||
[DialogTypes.DisconnectWallet]: <DisconnectDialog {...modalProps} />,
|
||||
[DialogTypes.ExchangeOffline]: <ExchangeOfflineDialog {...modalProps} />,
|
||||
[DialogTypes.FillDetails]: <FillDetailsDialog {...modalProps} />,
|
||||
|
||||
@ -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])};
|
||||
`;
|
||||
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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 &&
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
@ -231,7 +231,7 @@ Styled.CircleContainer = styled.div`
|
||||
`;
|
||||
|
||||
Styled.Icon = styled(Icon)`
|
||||
color: var(--color-negative);
|
||||
color: var(--color-error);
|
||||
`;
|
||||
|
||||
Styled.WithUsage = styled.div`
|
||||
|
||||
@ -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);
|
||||
`;
|
||||
|
||||
323
src/views/dialogs/DisplaySettingsDialog.tsx
Normal file
323
src/views/dialogs/DisplaySettingsDialog.tsx
Normal file
@ -0,0 +1,323 @@
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import styled, { AnyStyledComponent, css } from 'styled-components';
|
||||
|
||||
import { Root, Item, Indicator } from '@radix-ui/react-radio-group';
|
||||
|
||||
import { useStringGetter } from '@/hooks';
|
||||
|
||||
import { AppTheme, AppColorMode, setAppTheme, setAppColorMode } from '@/state/configs';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { Themes } from '@/styles/themes';
|
||||
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { HorizontalSeparatorFiller } from '@/components/Separator';
|
||||
|
||||
type ElementProps = {
|
||||
setIsOpen: (open: boolean) => void;
|
||||
};
|
||||
|
||||
export const DisplaySettingsDialog = ({ setIsOpen }: ElementProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
const currentTheme: AppTheme = useSelector(getAppTheme);
|
||||
const currentColorMode: AppColorMode = useSelector(getAppColorMode);
|
||||
|
||||
const sectionHeader = (heading: string) => {
|
||||
return (
|
||||
<Styled.Header>
|
||||
{heading}
|
||||
<HorizontalSeparatorFiller />
|
||||
</Styled.Header>
|
||||
);
|
||||
};
|
||||
|
||||
const themePanels = () => {
|
||||
return (
|
||||
<Styled.AppThemeRoot value={currentTheme}>
|
||||
{[
|
||||
{
|
||||
theme: AppTheme.Classic,
|
||||
label: STRING_KEYS.CLASSIC_DARK,
|
||||
},
|
||||
{
|
||||
theme: AppTheme.Dark,
|
||||
label: STRING_KEYS.DARK,
|
||||
},
|
||||
{
|
||||
theme: AppTheme.Light,
|
||||
label: STRING_KEYS.LIGHT,
|
||||
},
|
||||
].map(({ theme, label }) => (
|
||||
<Styled.AppThemeItem
|
||||
key={theme}
|
||||
value={theme}
|
||||
backgroundcolor={Themes[theme][currentColorMode].layer2}
|
||||
gridcolor={Themes[theme][currentColorMode].borderDefault}
|
||||
onClick={() => {
|
||||
dispatch(setAppTheme(theme));
|
||||
}}
|
||||
>
|
||||
<Styled.AppThemeHeader textcolor={Themes[theme][currentColorMode].textPrimary}>
|
||||
{stringGetter({ key: label })}
|
||||
</Styled.AppThemeHeader>
|
||||
<Styled.Image src="/chart-bars.svg" />
|
||||
<Styled.CheckIndicator>
|
||||
<Styled.CheckIcon iconName={IconName.Check} />
|
||||
</Styled.CheckIndicator>
|
||||
</Styled.AppThemeItem>
|
||||
))}
|
||||
</Styled.AppThemeRoot>
|
||||
);
|
||||
};
|
||||
|
||||
const colorModeOptions = () => {
|
||||
return (
|
||||
<Styled.ColorPreferenceRoot value={currentColorMode}>
|
||||
{[
|
||||
{
|
||||
colorMode: AppColorMode.GreenUp,
|
||||
label: STRING_KEYS.GREEN_IS_UP,
|
||||
},
|
||||
{
|
||||
colorMode: AppColorMode.RedUp,
|
||||
label: STRING_KEYS.RED_IS_UP,
|
||||
},
|
||||
].map(({ colorMode, label }) => (
|
||||
<Styled.ColorPreferenceItem
|
||||
key={colorMode}
|
||||
value={colorMode}
|
||||
onClick={() => {
|
||||
dispatch(setAppColorMode(colorMode));
|
||||
}}
|
||||
>
|
||||
<Styled.ColorPreferenceLabel>
|
||||
<Styled.ArrowIconContainer>
|
||||
<Styled.ArrowIcon
|
||||
iconName={IconName.Arrow}
|
||||
direction="up"
|
||||
color={colorMode === AppColorMode.GreenUp ? 'green' : 'red'}
|
||||
/>
|
||||
<Styled.ArrowIcon
|
||||
iconName={IconName.Arrow}
|
||||
direction="down"
|
||||
color={colorMode === AppColorMode.GreenUp ? 'red' : 'green'}
|
||||
/>
|
||||
</Styled.ArrowIconContainer>
|
||||
{stringGetter({ key: label })}
|
||||
</Styled.ColorPreferenceLabel>
|
||||
<Styled.DotIndicator $selected={currentColorMode === colorMode} />
|
||||
</Styled.ColorPreferenceItem>
|
||||
))}
|
||||
</Styled.ColorPreferenceRoot>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
isOpen
|
||||
setIsOpen={setIsOpen}
|
||||
title={stringGetter({ key: STRING_KEYS.DISPLAY_SETTINGS })}
|
||||
>
|
||||
<Styled.Section>
|
||||
{sectionHeader(stringGetter({ key: STRING_KEYS.THEME }))}
|
||||
{themePanels()}
|
||||
</Styled.Section>
|
||||
<Styled.Section>
|
||||
{sectionHeader(stringGetter({ key: STRING_KEYS.DIRECTION_COLOR_PREFERENCE }))}
|
||||
{colorModeOptions()}
|
||||
</Styled.Section>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
const gridStyle = css`
|
||||
display: grid;
|
||||
gap: 1.5rem;
|
||||
`;
|
||||
|
||||
Styled.Section = styled.div`
|
||||
${gridStyle}
|
||||
padding: 1rem 0;
|
||||
`;
|
||||
|
||||
Styled.Header = styled.header`
|
||||
${layoutMixins.inlineRow}
|
||||
`;
|
||||
|
||||
Styled.AppThemeRoot = styled(Root)`
|
||||
${gridStyle}
|
||||
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;
|
||||
|
||||
&[data-state='checked'] {
|
||||
--border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
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};
|
||||
--themePanel-gridColor: ${gridcolor};
|
||||
`}
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
background-color: var(--themePanel-backgroundColor);
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
|
||||
border-radius: 0.875rem;
|
||||
|
||||
background: radial-gradient(
|
||||
55% 35% at 50% 65%,
|
||||
transparent,
|
||||
var(--themePanel-backgroundColor) 100%
|
||||
);
|
||||
background-color: var(--themePanel-gridColor);
|
||||
mask-image: url('/chart-bars-background.svg');
|
||||
mask-size: cover;
|
||||
}
|
||||
`;
|
||||
|
||||
Styled.AppThemeHeader = styled.h3<{ textcolor: string }>`
|
||||
${({ textcolor }) => css`
|
||||
color: ${textcolor};
|
||||
`}
|
||||
z-index: 1;
|
||||
`;
|
||||
|
||||
Styled.Image = styled.img`
|
||||
width: 100%;
|
||||
height: auto;
|
||||
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;
|
||||
|
||||
height: var(--indicator-size);
|
||||
width: var(--indicator-size);
|
||||
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
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);
|
||||
|
||||
background-color: var(--color-accent);
|
||||
color: var(--color-text-2);
|
||||
`;
|
||||
|
||||
Styled.CheckIcon = styled(Icon)`
|
||||
width: var(--icon-size);
|
||||
height: var(--icon-size);
|
||||
`;
|
||||
@ -323,7 +323,7 @@ Styled.ReceiptArea = styled.div`
|
||||
`;
|
||||
|
||||
Styled.Green = styled.span`
|
||||
color: var(--color-positive);
|
||||
color: var(--color-success);
|
||||
`;
|
||||
|
||||
Styled.GreenCheckCircle = styled(GreenCheckCircle)`
|
||||
|
||||
@ -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;
|
||||
`;
|
||||
|
||||
@ -441,7 +441,7 @@ Styled.DestinationInputLabel = styled.span`
|
||||
${layoutMixins.inlineRow}
|
||||
|
||||
svg {
|
||||
color: var(--color-positive);
|
||||
color: var(--color-success);
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@ -32,9 +32,11 @@ import { Icon, IconName } from '@/components/Icon';
|
||||
import { IconButton } from '@/components/IconButton';
|
||||
import { WithTooltip } from '@/components/WithTooltip';
|
||||
|
||||
import { AppTheme } from '@/state/configs';
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
import { getOnboardingState, getSubaccount } from '@/state/accountSelectors';
|
||||
import { getAppTheme } from '@/state/configsSelectors';
|
||||
|
||||
import { isTruthy } from '@/lib/isTruthy';
|
||||
import { truncateAddress } from '@/lib/wallet';
|
||||
@ -50,6 +52,7 @@ export const AccountMenu = () => {
|
||||
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
|
||||
const { nativeTokenBalance } = useAccountBalance();
|
||||
const { usdcLabel, chainTokenLabel } = useTokenConfigs();
|
||||
const theme = useSelector(getAppTheme);
|
||||
|
||||
const { evmAddress, walletType, dydxAddress, hdKey } = useAccounts();
|
||||
|
||||
@ -177,6 +180,17 @@ export const AccountMenu = () => {
|
||||
label: stringGetter({ key: STRING_KEYS.PREFERENCES }),
|
||||
onSelect: () => dispatch(openDialog({ type: DialogTypes.Preferences })),
|
||||
},
|
||||
{
|
||||
value: 'DisplaySettings',
|
||||
icon:
|
||||
theme === AppTheme.Light ? (
|
||||
<Icon iconName={IconName.Sun} />
|
||||
) : (
|
||||
<Icon iconName={IconName.Moon} />
|
||||
),
|
||||
label: stringGetter({ key: STRING_KEYS.DISPLAY_SETTINGS }),
|
||||
onSelect: () => dispatch(openDialog({ type: DialogTypes.DisplaySettings })),
|
||||
},
|
||||
...(onboardingState === OnboardingState.AccountConnected && hdKey
|
||||
? [
|
||||
(!isMainnet || testFlags.showMobileSignInOption) && {
|
||||
@ -189,7 +203,7 @@ export const AccountMenu = () => {
|
||||
value: 'MnemonicExport',
|
||||
icon: <Icon iconName={IconName.ExportKeys} />,
|
||||
label: <span>{stringGetter({ key: STRING_KEYS.EXPORT_SECRET_PHRASE })}</span>,
|
||||
highlightColor: 'negative',
|
||||
highlightColor: 'destroy',
|
||||
onSelect: () => dispatch(openDialog({ type: DialogTypes.MnemonicExport })),
|
||||
},
|
||||
].filter(isTruthy)
|
||||
@ -198,7 +212,7 @@ export const AccountMenu = () => {
|
||||
value: 'Disconnect',
|
||||
icon: <Icon iconName={IconName.BoxClose} />,
|
||||
label: stringGetter({ key: STRING_KEYS.DISCONNECT }),
|
||||
highlightColor: 'negative',
|
||||
highlightColor: 'destroy',
|
||||
onSelect: () => dispatch(openDialog({ type: DialogTypes.DisconnectWallet })),
|
||||
},
|
||||
].filter(isTruthy)}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
`;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user