Compare commits
3 Commits
main
...
mulan-moda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
292e16603d | ||
|
|
69d00e39ef | ||
|
|
eee19b3b93 |
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 |
@ -1,10 +1,10 @@
|
|||||||
import type { Story } from '@ladle/react';
|
import type { Story } from '@ladle/react';
|
||||||
|
|
||||||
import { Panel } from '@/components/Panel';
|
import { Panel, PanelProps } from '@/components/Panel';
|
||||||
|
|
||||||
import { StoryWrapper } from '.ladle/components';
|
import { StoryWrapper } from '.ladle/components';
|
||||||
|
|
||||||
export const PanelStory: Story<{ slotHeader: React.ReactNode, children?: React.ReactNode }> = (args) => {
|
export const PanelStory: Story<PanelProps> = (args) => {
|
||||||
return (
|
return (
|
||||||
<StoryWrapper>
|
<StoryWrapper>
|
||||||
<Panel {...args} />
|
<Panel {...args} />
|
||||||
@ -13,6 +13,8 @@ export const PanelStory: Story<{ slotHeader: React.ReactNode, children?: React.R
|
|||||||
};
|
};
|
||||||
|
|
||||||
PanelStory.args = {
|
PanelStory.args = {
|
||||||
slotHeader: 'Header',
|
slotHeaderContent: 'Header',
|
||||||
children: 'Content',
|
children: 'Content',
|
||||||
|
slotRight: '1️⃣',
|
||||||
|
hasSeparator: true,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { Icon, IconName } from '@/components/Icon';
|
|||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { breakpoints } from '@/styles';
|
import { breakpoints } from '@/styles';
|
||||||
|
|
||||||
type PanelProps = {
|
type ElementProps = {
|
||||||
slotHeaderContent?: React.ReactNode;
|
slotHeaderContent?: React.ReactNode;
|
||||||
slotHeader?: React.ReactNode;
|
slotHeader?: React.ReactNode;
|
||||||
slotRight?: React.ReactNode;
|
slotRight?: React.ReactNode;
|
||||||
@ -16,11 +16,13 @@ type PanelProps = {
|
|||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type PanelStyleProps = {
|
type StyleProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
hasSeparator?: boolean;
|
hasSeparator?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PanelProps = ElementProps & StyleProps;
|
||||||
|
|
||||||
export const Panel = ({
|
export const Panel = ({
|
||||||
slotHeaderContent,
|
slotHeaderContent,
|
||||||
slotHeader,
|
slotHeader,
|
||||||
@ -31,7 +33,7 @@ export const Panel = ({
|
|||||||
onClick,
|
onClick,
|
||||||
hasSeparator,
|
hasSeparator,
|
||||||
className,
|
className,
|
||||||
}: PanelProps & PanelStyleProps) => (
|
}: PanelProps) => (
|
||||||
<Styled.Panel onClick={onClick} className={className}>
|
<Styled.Panel onClick={onClick} className={className}>
|
||||||
<Styled.Left>
|
<Styled.Left>
|
||||||
{href ? (
|
{href ? (
|
||||||
|
|||||||
@ -2,6 +2,7 @@ export enum DialogTypes {
|
|||||||
ClosePosition = 'ClosePosition',
|
ClosePosition = 'ClosePosition',
|
||||||
Deposit = 'Deposit',
|
Deposit = 'Deposit',
|
||||||
DisconnectWallet = 'DisconnectWallet',
|
DisconnectWallet = 'DisconnectWallet',
|
||||||
|
DisplaySettings = 'DisplaySettings',
|
||||||
ExchangeOffline = 'ExchangeOffline',
|
ExchangeOffline = 'ExchangeOffline',
|
||||||
ExternalLink = 'ExternalLink',
|
ExternalLink = 'ExternalLink',
|
||||||
FillDetails = 'FillDetails',
|
FillDetails = 'FillDetails',
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { getActiveDialog } from '@/state/dialogsSelectors';
|
|||||||
import { ClosePositionDialog } from '@/views/dialogs/ClosePositionDialog';
|
import { ClosePositionDialog } from '@/views/dialogs/ClosePositionDialog';
|
||||||
import { DepositDialog } from '@/views/dialogs/DepositDialog';
|
import { DepositDialog } from '@/views/dialogs/DepositDialog';
|
||||||
import { DisconnectDialog } from '@/views/dialogs/DisconnectDialog';
|
import { DisconnectDialog } from '@/views/dialogs/DisconnectDialog';
|
||||||
|
import { DisplaySettingsDialog } from '@/views/dialogs/DisplaySettingsDialog';
|
||||||
import { ExchangeOfflineDialog } from '@/views/dialogs/ExchangeOfflineDialog';
|
import { ExchangeOfflineDialog } from '@/views/dialogs/ExchangeOfflineDialog';
|
||||||
import { HelpDialog } from '@/views/dialogs/HelpDialog';
|
import { HelpDialog } from '@/views/dialogs/HelpDialog';
|
||||||
import { ExternalLinkDialog } from '@/views/dialogs/ExternalLinkDialog';
|
import { ExternalLinkDialog } from '@/views/dialogs/ExternalLinkDialog';
|
||||||
@ -51,6 +52,7 @@ export const DialogManager = () => {
|
|||||||
return {
|
return {
|
||||||
[DialogTypes.ClosePosition]: <ClosePositionDialog {...modalProps} />,
|
[DialogTypes.ClosePosition]: <ClosePositionDialog {...modalProps} />,
|
||||||
[DialogTypes.Deposit]: <DepositDialog {...modalProps} />,
|
[DialogTypes.Deposit]: <DepositDialog {...modalProps} />,
|
||||||
|
[DialogTypes.DisplaySettings]: <DisplaySettingsDialog {...modalProps} />,
|
||||||
[DialogTypes.DisconnectWallet]: <DisconnectDialog {...modalProps} />,
|
[DialogTypes.DisconnectWallet]: <DisconnectDialog {...modalProps} />,
|
||||||
[DialogTypes.ExchangeOffline]: <ExchangeOfflineDialog {...modalProps} />,
|
[DialogTypes.ExchangeOffline]: <ExchangeOfflineDialog {...modalProps} />,
|
||||||
[DialogTypes.FillDetails]: <FillDetailsDialog {...modalProps} />,
|
[DialogTypes.FillDetails]: <FillDetailsDialog {...modalProps} />,
|
||||||
|
|||||||
199
src/views/dialogs/DisplaySettingsDialog.tsx
Normal file
199
src/views/dialogs/DisplaySettingsDialog.tsx
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
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, setAppTheme } from '@/state/configs';
|
||||||
|
import { getAppTheme } 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 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].layer2}
|
||||||
|
gridcolor={Themes[theme].borderDefault}
|
||||||
|
onClick={() => {
|
||||||
|
dispatch(setAppTheme(theme));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Styled.AppThemeHeader textcolor={Themes[theme].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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
isOpen
|
||||||
|
setIsOpen={setIsOpen}
|
||||||
|
title={stringGetter({ key: STRING_KEYS.DISPLAY_SETTINGS })}
|
||||||
|
>
|
||||||
|
<Styled.Section>
|
||||||
|
{sectionHeader(stringGetter({ key: STRING_KEYS.THEME }))}
|
||||||
|
{themePanels()}
|
||||||
|
</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.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.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;
|
||||||
|
`;
|
||||||
|
|
||||||
|
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.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);
|
||||||
|
`;
|
||||||
@ -32,9 +32,11 @@ import { Icon, IconName } from '@/components/Icon';
|
|||||||
import { IconButton } from '@/components/IconButton';
|
import { IconButton } from '@/components/IconButton';
|
||||||
import { WithTooltip } from '@/components/WithTooltip';
|
import { WithTooltip } from '@/components/WithTooltip';
|
||||||
|
|
||||||
|
import { AppTheme } from '@/state/configs';
|
||||||
import { openDialog } from '@/state/dialogs';
|
import { openDialog } from '@/state/dialogs';
|
||||||
|
|
||||||
import { getOnboardingState, getSubaccount } from '@/state/accountSelectors';
|
import { getOnboardingState, getSubaccount } from '@/state/accountSelectors';
|
||||||
|
import { getAppTheme } from '@/state/configsSelectors';
|
||||||
|
|
||||||
import { isTruthy } from '@/lib/isTruthy';
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
import { truncateAddress } from '@/lib/wallet';
|
import { truncateAddress } from '@/lib/wallet';
|
||||||
@ -50,6 +52,7 @@ export const AccountMenu = () => {
|
|||||||
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
|
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
|
||||||
const { nativeTokenBalance } = useAccountBalance();
|
const { nativeTokenBalance } = useAccountBalance();
|
||||||
const { usdcLabel, chainTokenLabel } = useTokenConfigs();
|
const { usdcLabel, chainTokenLabel } = useTokenConfigs();
|
||||||
|
const theme = useSelector(getAppTheme);
|
||||||
|
|
||||||
const { evmAddress, walletType, dydxAddress, hdKey } = useAccounts();
|
const { evmAddress, walletType, dydxAddress, hdKey } = useAccounts();
|
||||||
|
|
||||||
@ -177,6 +180,17 @@ export const AccountMenu = () => {
|
|||||||
label: stringGetter({ key: STRING_KEYS.PREFERENCES }),
|
label: stringGetter({ key: STRING_KEYS.PREFERENCES }),
|
||||||
onSelect: () => dispatch(openDialog({ type: DialogTypes.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
|
...(onboardingState === OnboardingState.AccountConnected && hdKey
|
||||||
? [
|
? [
|
||||||
(!isMainnet || testFlags.showMobileSignInOption) && {
|
(!isMainnet || testFlags.showMobileSignInOption) && {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user