Compare commits
21 Commits
main
...
mulan-them
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51803780ba | ||
|
|
1495ecde98 | ||
|
|
569090db6b | ||
|
|
790a1f13db | ||
|
|
9b7fe27606 | ||
|
|
3ec9c2442e | ||
|
|
f111f54295 | ||
|
|
ed84a8a66b | ||
|
|
58fde4ce96 | ||
|
|
59ef66ffe1 | ||
|
|
ae102b8990 | ||
|
|
d72846670f | ||
|
|
93f8ef7cce | ||
|
|
4563fdab03 | ||
|
|
7309f88515 | ||
|
|
67ad0defce | ||
|
|
ea10585b89 | ||
|
|
6fc037ddeb | ||
|
|
292e16603d | ||
|
|
69d00e39ef | ||
|
|
eee19b3b93 |
@ -9,9 +9,15 @@ import { GlobalStyle } from '@/styles/globalStyle';
|
|||||||
|
|
||||||
import { SelectMenu, SelectItem } from '@/components/SelectMenu';
|
import { SelectMenu, SelectItem } from '@/components/SelectMenu';
|
||||||
|
|
||||||
import { AppThemeProvider } from '@/hooks/useAppTheme';
|
import { AppThemeAndColorModeProvider } from '@/hooks/useAppThemeAndColorMode';
|
||||||
|
|
||||||
import { AppTheme, setAppTheme } from '@/state/configs';
|
import {
|
||||||
|
AppTheme,
|
||||||
|
AppThemeSystemSetting,
|
||||||
|
AppColorMode,
|
||||||
|
setAppThemeSetting,
|
||||||
|
setAppColorMode,
|
||||||
|
} from '@/state/configs';
|
||||||
import { setLocaleLoaded } from '@/state/localization';
|
import { setLocaleLoaded } from '@/state/localization';
|
||||||
|
|
||||||
import '@/index.css';
|
import '@/index.css';
|
||||||
@ -19,26 +25,12 @@ import './ladle.css';
|
|||||||
|
|
||||||
export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
const [theme, setTheme] = useState(AppTheme.Classic);
|
const [theme, setTheme] = useState(AppTheme.Classic);
|
||||||
|
const [colorMode, setColorMode] = useState(AppColorMode.GreenUp);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
store.dispatch(setAppTheme(theme));
|
store.dispatch(setAppThemeSetting(theme));
|
||||||
switch (theme) {
|
store.dispatch(setAppColorMode(colorMode));
|
||||||
case AppTheme.Dark: {
|
}, [theme, colorMode]);
|
||||||
document?.documentElement?.classList.remove('theme-light');
|
|
||||||
document?.documentElement?.classList.add('theme-dark');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AppTheme.Light: {
|
|
||||||
document?.documentElement?.classList.remove('theme-dark');
|
|
||||||
document?.documentElement?.classList.add('theme-light');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AppTheme.Classic: {
|
|
||||||
document?.documentElement?.classList.remove('theme-dark', 'theme-light');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [theme]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
store.dispatch(setLocaleLoaded(true));
|
store.dispatch(setLocaleLoaded(true));
|
||||||
@ -48,15 +40,16 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<StoryHeader>
|
<StoryHeader>
|
||||||
<h4>Active Theme:</h4>
|
<h4>Active Theme:</h4>
|
||||||
<SelectMenu
|
<SelectMenu value={theme} onValueChange={setTheme}>
|
||||||
value={theme}
|
|
||||||
onValueChange={setTheme}
|
|
||||||
>
|
|
||||||
{[
|
{[
|
||||||
{
|
{
|
||||||
value: AppTheme.Classic,
|
value: AppTheme.Classic,
|
||||||
label: 'Default theme',
|
label: 'Default theme',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: AppThemeSystemSetting.System,
|
||||||
|
label: 'System theme',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: AppTheme.Dark,
|
value: AppTheme.Dark,
|
||||||
label: 'Dark theme',
|
label: 'Dark theme',
|
||||||
@ -66,20 +59,31 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
label: 'Light theme',
|
label: 'Light theme',
|
||||||
},
|
},
|
||||||
].map(({ value, label }) => (
|
].map(({ value, label }) => (
|
||||||
<SelectItem
|
<SelectItem key={value} value={value} label={label} />
|
||||||
key={value}
|
))}
|
||||||
value={value}
|
</SelectMenu>
|
||||||
label={label}
|
<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>
|
</SelectMenu>
|
||||||
</StoryHeader>
|
</StoryHeader>
|
||||||
<hr />
|
<hr />
|
||||||
<AppThemeProvider>
|
<AppThemeAndColorModeProvider>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
<StoryContent>{children}</StoryContent>
|
<StoryContent>{children}</StoryContent>
|
||||||
</AppThemeProvider>
|
</AppThemeAndColorModeProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 122 KiB |
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
@ -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 |
20484
public/chart-dots-background-dark.svg
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
20484
public/chart-dots-background-light.svg
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 9.6 KiB |
@ -16,7 +16,7 @@ import {
|
|||||||
} from '@/hooks';
|
} from '@/hooks';
|
||||||
import { DydxProvider } from '@/hooks/useDydxClient';
|
import { DydxProvider } from '@/hooks/useDydxClient';
|
||||||
import { AccountsProvider } from '@/hooks/useAccounts';
|
import { AccountsProvider } from '@/hooks/useAccounts';
|
||||||
import { AppThemeProvider } from '@/hooks/useAppTheme';
|
import { AppThemeAndColorModeProvider } from '@/hooks/useAppThemeAndColorMode';
|
||||||
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
|
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
|
||||||
import { LocaleProvider } from '@/hooks/useLocaleSeparators';
|
import { LocaleProvider } from '@/hooks/useLocaleSeparators';
|
||||||
import { NotificationsProvider } from '@/hooks/useNotifications';
|
import { NotificationsProvider } from '@/hooks/useNotifications';
|
||||||
@ -141,8 +141,7 @@ const providers = [
|
|||||||
wrapProvider(LocalNotificationsProvider),
|
wrapProvider(LocalNotificationsProvider),
|
||||||
wrapProvider(NotificationsProvider),
|
wrapProvider(NotificationsProvider),
|
||||||
wrapProvider(DialogAreaProvider),
|
wrapProvider(DialogAreaProvider),
|
||||||
wrapProvider(PotentialMarketsProvider),
|
wrapProvider(AppThemeAndColorModeProvider),
|
||||||
wrapProvider(AppThemeProvider),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
|||||||
@ -85,7 +85,7 @@ Styled.Trigger = styled(Trigger)`
|
|||||||
&:hover {
|
&:hover {
|
||||||
${Styled.Icon} {
|
${Styled.Icon} {
|
||||||
color: var(--color-text-2);
|
color: var(--color-text-2);
|
||||||
filter: brightness(1.1);
|
filter: brightness(var(--hover-filter-base));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -134,8 +134,8 @@ const ButtonStyle = css<StyleProps>`
|
|||||||
|
|
||||||
--button-textColor: var(--color-text-0);
|
--button-textColor: var(--color-text-0);
|
||||||
--button-backgroundColor: transparent;
|
--button-backgroundColor: transparent;
|
||||||
--button-active-filter: brightness(0.9);
|
--button-active-filter: brightness(var(--active-filter));
|
||||||
--button-hover-filter: brightness(1.1);
|
--button-hover-filter: brightness(var(--hover-filter-base));
|
||||||
--button-hover-textColor: var(--button-textColor);
|
--button-hover-textColor: var(--button-textColor);
|
||||||
|
|
||||||
--button-radius: 0.5em;
|
--button-radius: 0.5em;
|
||||||
|
|||||||
@ -89,9 +89,10 @@ const buttonActionVariants = {
|
|||||||
--button-border: solid var(--border-width) var(--color-border);
|
--button-border: solid var(--border-width) var(--color-border);
|
||||||
`,
|
`,
|
||||||
[ButtonAction.Primary]: css`
|
[ButtonAction.Primary]: css`
|
||||||
--button-textColor: var(--color-text-2);
|
--button-textColor: var(--color-text-button);
|
||||||
--button-backgroundColor: var(--color-accent);
|
--button-backgroundColor: var(--color-accent);
|
||||||
--button-border: solid var(--border-width) var(--color-border-white);
|
--button-border: solid var(--border-width) var(--color-border-white);
|
||||||
|
--button-hover-filter: brightness(var(--hover-filter-variant));
|
||||||
`,
|
`,
|
||||||
|
|
||||||
[ButtonAction.Secondary]: css`
|
[ButtonAction.Secondary]: css`
|
||||||
@ -101,15 +102,17 @@ const buttonActionVariants = {
|
|||||||
`,
|
`,
|
||||||
|
|
||||||
[ButtonAction.Create]: css`
|
[ButtonAction.Create]: css`
|
||||||
--button-textColor: var(--color-text-2);
|
--button-textColor: var(--color-text-button);
|
||||||
--button-backgroundColor: var(--color-positive);
|
--button-backgroundColor: var(--color-success);
|
||||||
--button-border: solid var(--border-width) var(--color-border-white);
|
--button-border: solid var(--border-width) var(--color-border-white);
|
||||||
|
--button-hover-filter: brightness(var(--hover-filter-variant));
|
||||||
`,
|
`,
|
||||||
|
|
||||||
[ButtonAction.Destroy]: css`
|
[ButtonAction.Destroy]: css`
|
||||||
--button-textColor: var(--color-text-2);
|
--button-textColor: var(--color-text-button);
|
||||||
--button-backgroundColor: var(--color-negative);
|
--button-backgroundColor: var(--color-error);
|
||||||
--button-border: solid var(--border-width) var(--color-border-white);
|
--button-border: solid var(--border-width) var(--color-border-white);
|
||||||
|
--button-hover-filter: brightness(var(--hover-filter-variant));
|
||||||
`,
|
`,
|
||||||
|
|
||||||
[ButtonAction.Navigation]: css`
|
[ButtonAction.Navigation]: css`
|
||||||
@ -119,9 +122,10 @@ const buttonActionVariants = {
|
|||||||
`,
|
`,
|
||||||
|
|
||||||
[ButtonAction.Reset]: css`
|
[ButtonAction.Reset]: css`
|
||||||
--button-textColor: var(--color-negative);
|
--button-textColor: var(--color-error);
|
||||||
--button-backgroundColor: var(--color-layer-3);
|
--button-backgroundColor: var(--color-layer-3);
|
||||||
--button-border: solid var(--border-width) var(--color-border-red);
|
--button-border: solid var(--border-width) var(--color-border-red);
|
||||||
|
--button-hover-filter: brightness(var(--hover-filter-variant));
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -80,7 +80,7 @@ Styled.Indicator = styled(Indicator)`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
color: var(--color-text-2);
|
color: var(--color-text-button);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Label = styled.label<{ disabled?: boolean }>`
|
Styled.Label = styled.label<{ disabled?: boolean }>`
|
||||||
|
|||||||
@ -77,7 +77,7 @@ Styled.InlineRow = styled.div<{ copied: boolean }>`
|
|||||||
`
|
`
|
||||||
: css`
|
: css`
|
||||||
&:hover {
|
&:hover {
|
||||||
filter: brightness(1.1);
|
filter: brightness(var(--hover-filter-base));
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
@ -87,7 +87,7 @@ Styled.Icon = styled(Icon)<{ copied: boolean }>`
|
|||||||
${({ copied }) =>
|
${({ copied }) =>
|
||||||
copied &&
|
copied &&
|
||||||
css`
|
css`
|
||||||
color: var(--color-positive);
|
color: var(--color-success);
|
||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ Styled.IconButton = styled(IconButton)<{ copied: boolean }>`
|
|||||||
copied &&
|
copied &&
|
||||||
css`
|
css`
|
||||||
svg {
|
svg {
|
||||||
color: var(--color-positive);
|
color: var(--color-success);
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -62,6 +62,6 @@ Styled.DiffArrowContainer = styled.span<DiffArrowProps>`
|
|||||||
`,
|
`,
|
||||||
down: css`
|
down: css`
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
`
|
`,
|
||||||
}[direction || 'right'])}
|
}[direction || 'right'])}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -75,7 +75,7 @@ Styled.DiffValue = styled.div<{ hasInvalidNewValue?: boolean }>`
|
|||||||
${({ hasInvalidNewValue }) =>
|
${({ hasInvalidNewValue }) =>
|
||||||
hasInvalidNewValue &&
|
hasInvalidNewValue &&
|
||||||
css`
|
css`
|
||||||
color: var(--color-negative);
|
color: var(--color-error);
|
||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -35,8 +35,8 @@ export const DropdownHeaderMenu = <MenuItemValue extends string>({
|
|||||||
<Root>
|
<Root>
|
||||||
<Styled.Trigger className={className} asChild>
|
<Styled.Trigger className={className} asChild>
|
||||||
<div>
|
<div>
|
||||||
{children}
|
{children}
|
||||||
<Styled.DropdownIconButton iconName={IconName.Caret} isToggle />
|
<Styled.DropdownIconButton iconName={IconName.Caret} isToggle />
|
||||||
</div>
|
</div>
|
||||||
</Styled.Trigger>
|
</Styled.Trigger>
|
||||||
<Portal>
|
<Portal>
|
||||||
@ -87,7 +87,7 @@ Styled.Trigger = styled(Trigger)`
|
|||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
filter: brightness(1.1);
|
filter: brightness(var(--hover-filter-base));
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -91,10 +91,10 @@ Styled.Item = styled(Item)<{ $highlightColor: 'accent' | 'positive' | 'negative'
|
|||||||
--item-highlighted-textColor: var(--color-accent);
|
--item-highlighted-textColor: var(--color-accent);
|
||||||
`,
|
`,
|
||||||
['positive']: `
|
['positive']: `
|
||||||
--item-highlighted-textColor: var(--color-positive);
|
--item-highlighted-textColor: var(--color-success);
|
||||||
`,
|
`,
|
||||||
['negative']: `
|
['negative']: `
|
||||||
--item-highlighted-textColor: var(--color-negative);
|
--item-highlighted-textColor: var(--color-error);
|
||||||
`,
|
`,
|
||||||
}[$highlightColor])}
|
}[$highlightColor])}
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
CaretIcon,
|
CaretIcon,
|
||||||
CautionCircleStrokeIcon,
|
CautionCircleStrokeIcon,
|
||||||
CautionCircleIcon,
|
CautionCircleIcon,
|
||||||
|
ChaosLabsIcon,
|
||||||
ChatIcon,
|
ChatIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
CheckCircleIcon,
|
CheckCircleIcon,
|
||||||
@ -90,6 +91,7 @@ export enum IconName {
|
|||||||
Caret = 'Caret',
|
Caret = 'Caret',
|
||||||
CautionCircle = 'CautionCircle',
|
CautionCircle = 'CautionCircle',
|
||||||
CautionCircleStroked = 'CautionCircleStroked',
|
CautionCircleStroked = 'CautionCircleStroked',
|
||||||
|
ChaosLabs = 'ChaosLabs',
|
||||||
Chat = 'Chat',
|
Chat = 'Chat',
|
||||||
Check = 'Check',
|
Check = 'Check',
|
||||||
CheckCircle = 'CheckCircle',
|
CheckCircle = 'CheckCircle',
|
||||||
@ -168,6 +170,7 @@ const icons = {
|
|||||||
[IconName.Caret]: CaretIcon,
|
[IconName.Caret]: CaretIcon,
|
||||||
[IconName.CautionCircle]: CautionCircleIcon,
|
[IconName.CautionCircle]: CautionCircleIcon,
|
||||||
[IconName.CautionCircleStroked]: CautionCircleStrokeIcon,
|
[IconName.CautionCircleStroked]: CautionCircleStrokeIcon,
|
||||||
|
[IconName.ChaosLabs]: ChaosLabsIcon,
|
||||||
[IconName.Chat]: ChatIcon,
|
[IconName.Chat]: ChatIcon,
|
||||||
[IconName.Check]: CheckIcon,
|
[IconName.Check]: CheckIcon,
|
||||||
[IconName.CheckCircle]: CheckCircleIcon,
|
[IconName.CheckCircle]: CheckCircleIcon,
|
||||||
|
|||||||
@ -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 ? (
|
||||||
|
|||||||
@ -782,7 +782,7 @@ Styled.Tr = styled.tr<{
|
|||||||
&:focus-visible,
|
&:focus-visible,
|
||||||
&:focus-within {
|
&:focus-within {
|
||||||
--tableRow-currentBackgroundColor: var(--tableRow-hover-backgroundColor);
|
--tableRow-currentBackgroundColor: var(--tableRow-hover-backgroundColor);
|
||||||
filter: brightness(1.1);
|
filter: brightness(var(--hover-filter-base));
|
||||||
}
|
}
|
||||||
`};
|
`};
|
||||||
|
|
||||||
|
|||||||
@ -117,7 +117,7 @@ Styled.ConfirmButton = styled(Styled.IconButton)`
|
|||||||
--button-backgroundColor: hsla(203, 25%, 19%, 1);
|
--button-backgroundColor: hsla(203, 25%, 19%, 1);
|
||||||
|
|
||||||
svg {
|
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);
|
--button-backgroundColor: hsla(296, 16%, 18%, 1);
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
color: var(--color-negative);
|
color: var(--color-error);
|
||||||
width: 0.8em;
|
width: 0.8em;
|
||||||
height: 0.8em;
|
height: 0.8em;
|
||||||
|
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export enum LocalStorageKey {
|
|||||||
SelectedLocale = 'dydx.SelectedLocale',
|
SelectedLocale = 'dydx.SelectedLocale',
|
||||||
SelectedNetwork = 'dydx.SelectedNetwork',
|
SelectedNetwork = 'dydx.SelectedNetwork',
|
||||||
SelectedTheme = 'dydx.SelectedTheme',
|
SelectedTheme = 'dydx.SelectedTheme',
|
||||||
|
SelectedColorMode = 'dydx.SelectedColorMode',
|
||||||
SelectedTradeLayout = 'dydx.SelectedTradeLayout',
|
SelectedTradeLayout = 'dydx.SelectedTradeLayout',
|
||||||
TradingViewChartConfig = 'dydx.TradingViewChartConfig',
|
TradingViewChartConfig = 'dydx.TradingViewChartConfig',
|
||||||
HasSeenLaunchIncentives = 'dydx.HasSeenLaunchIncentives',
|
HasSeenLaunchIncentives = 'dydx.HasSeenLaunchIncentives',
|
||||||
|
|||||||
@ -68,3 +68,9 @@ export enum OpacityToken {
|
|||||||
Opacity66 = 'A8',
|
Opacity66 = 'A8',
|
||||||
Opacity90 = 'E6',
|
Opacity90 = 'E6',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum BrightnessFilterToken {
|
||||||
|
Darken10 = '0.9',
|
||||||
|
Darken5 = '0.95',
|
||||||
|
Lighten10 = '1.1',
|
||||||
|
}
|
||||||
|
|||||||
@ -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 &
|
BorderColors &
|
||||||
TextColors &
|
TextColors &
|
||||||
GradientColors &
|
GradientColors &
|
||||||
@ -7,7 +14,8 @@ export type ThemeColors = LayerColors &
|
|||||||
DirectionalColors &
|
DirectionalColors &
|
||||||
RiskColors &
|
RiskColors &
|
||||||
IconColors &
|
IconColors &
|
||||||
ComponentColors;
|
ComponentColors &
|
||||||
|
Filters;
|
||||||
|
|
||||||
type LayerColors = {
|
type LayerColors = {
|
||||||
layer0: string;
|
layer0: string;
|
||||||
@ -30,6 +38,8 @@ type TextColors = {
|
|||||||
textPrimary: string;
|
textPrimary: string;
|
||||||
textSecondary: string;
|
textSecondary: string;
|
||||||
textTertiary: string;
|
textTertiary: string;
|
||||||
|
|
||||||
|
textButton: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type GradientColors = {
|
type GradientColors = {
|
||||||
@ -47,8 +57,13 @@ type StatusColors = {
|
|||||||
success: string;
|
success: string;
|
||||||
warning: string;
|
warning: string;
|
||||||
error: 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 = {
|
type DirectionalColors = {
|
||||||
positive: string;
|
positive: string;
|
||||||
negative: string;
|
negative: string;
|
||||||
@ -75,3 +90,9 @@ type ComponentColors = {
|
|||||||
toggleBackground: string;
|
toggleBackground: string;
|
||||||
tooltipBackground: string;
|
tooltipBackground: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Filters = {
|
||||||
|
hoverFilterBase: string;
|
||||||
|
hoverFilterVariant: string;
|
||||||
|
activeFilter: string;
|
||||||
|
};
|
||||||
|
|||||||
@ -12,8 +12,9 @@ import {
|
|||||||
ORDERBOOK_WIDTH,
|
ORDERBOOK_WIDTH,
|
||||||
} from '@/constants/orderbook';
|
} from '@/constants/orderbook';
|
||||||
|
|
||||||
|
import { useAppThemeAndColorModeContext } from '@/hooks/useAppThemeAndColorMode';
|
||||||
|
|
||||||
import { getCurrentMarketConfig, getCurrentMarketOrderbookMap } from '@/state/perpetualsSelectors';
|
import { getCurrentMarketConfig, getCurrentMarketOrderbookMap } from '@/state/perpetualsSelectors';
|
||||||
import { getAppTheme } from '@/state/configsSelectors';
|
|
||||||
|
|
||||||
import { MustBigNumber } from '@/lib/numbers';
|
import { MustBigNumber } from '@/lib/numbers';
|
||||||
|
|
||||||
@ -23,7 +24,6 @@ import {
|
|||||||
getXByColumn,
|
getXByColumn,
|
||||||
getYForElements,
|
getYForElements,
|
||||||
} from '@/lib/orderbookHelpers';
|
} from '@/lib/orderbookHelpers';
|
||||||
import { useAppThemeContext } from '../useAppTheme';
|
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
data: Array<PerpetualMarketOrderbookLevel | undefined>;
|
data: Array<PerpetualMarketOrderbookLevel | undefined>;
|
||||||
@ -53,7 +53,7 @@ export const useDrawOrderbook = ({
|
|||||||
const { stepSizeDecimals = TOKEN_DECIMALS, tickSizeDecimals = SMALL_USD_DECIMALS } =
|
const { stepSizeDecimals = TOKEN_DECIMALS, tickSizeDecimals = SMALL_USD_DECIMALS } =
|
||||||
useSelector(getCurrentMarketConfig, shallowEqual) || {};
|
useSelector(getCurrentMarketConfig, shallowEqual) || {};
|
||||||
const prevData = useRef<typeof data>(data);
|
const prevData = useRef<typeof data>(data);
|
||||||
const theme = useAppThemeContext();
|
const theme = useAppThemeAndColorModeContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scale canvas using device pixel ratio to unblur drawn text
|
* 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 { store } from '@/state/_store';
|
||||||
|
|
||||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
import { getAppTheme } from '@/state/configsSelectors';
|
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||||
import { getSelectedLocale } from '@/state/localizationSelectors';
|
import { getSelectedLocale } from '@/state/localizationSelectors';
|
||||||
import { getCurrentMarketId, getMarketIds } from '@/state/perpetualsSelectors';
|
import { getCurrentMarketId, getMarketIds } from '@/state/perpetualsSelectors';
|
||||||
|
|
||||||
@ -30,6 +30,7 @@ export const useTradingView = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const marketId = useSelector(getCurrentMarketId);
|
const marketId = useSelector(getCurrentMarketId);
|
||||||
const appTheme = useSelector(getAppTheme);
|
const appTheme = useSelector(getAppTheme);
|
||||||
|
const appColorMode = useSelector(getAppColorMode);
|
||||||
const marketIds = useSelector(getMarketIds, shallowEqual);
|
const marketIds = useSelector(getMarketIds, shallowEqual);
|
||||||
const selectedLocale = useSelector(getSelectedLocale);
|
const selectedLocale = useSelector(getSelectedLocale);
|
||||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
@ -46,7 +47,7 @@ export const useTradingView = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasMarkets && isClientConnected && marketId) {
|
if (hasMarkets && isClientConnected && marketId) {
|
||||||
const widgetOptions = getWidgetOptions();
|
const widgetOptions = getWidgetOptions();
|
||||||
const widgetOverrides = getWidgetOverrides(appTheme);
|
const widgetOverrides = getWidgetOverrides({ appTheme, appColorMode });
|
||||||
const options = {
|
const options = {
|
||||||
// debug: true,
|
// debug: true,
|
||||||
...widgetOptions,
|
...widgetOptions,
|
||||||
@ -75,7 +76,14 @@ export const useTradingView = ({
|
|||||||
tvWidgetRef.current = null;
|
tvWidgetRef.current = null;
|
||||||
setIsChartReady(false);
|
setIsChartReady(false);
|
||||||
};
|
};
|
||||||
}, [getCandlesForDatafeed, isClientConnected, hasMarkets, selectedLocale, selectedNetwork, !!marketId]);
|
}, [
|
||||||
|
getCandlesForDatafeed,
|
||||||
|
isClientConnected,
|
||||||
|
hasMarkets,
|
||||||
|
selectedLocale,
|
||||||
|
selectedNetwork,
|
||||||
|
!!marketId,
|
||||||
|
]);
|
||||||
|
|
||||||
return { savedResolution };
|
return { savedResolution };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { useSelector } from 'react-redux';
|
|||||||
|
|
||||||
import type { IChartingLibraryWidget, ThemeName } from 'public/tradingview/charting_library';
|
import type { IChartingLibraryWidget, ThemeName } from 'public/tradingview/charting_library';
|
||||||
|
|
||||||
import { AppTheme } from '@/state/configs';
|
import { AppColorMode, AppTheme } from '@/state/configs';
|
||||||
import { getAppTheme } from '@/state/configsSelectors';
|
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||||
|
|
||||||
import { getWidgetOverrides } from '@/lib/tradingView/utils';
|
import { getWidgetOverrides } from '@/lib/tradingView/utils';
|
||||||
|
|
||||||
@ -29,6 +29,7 @@ export const useTradingViewTheme = ({
|
|||||||
isWidgetReady?: boolean;
|
isWidgetReady?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const appTheme: AppTheme = useSelector(getAppTheme);
|
const appTheme: AppTheme = useSelector(getAppTheme);
|
||||||
|
const appColorMode: AppColorMode = useSelector(getAppColorMode);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (tvWidget && isWidgetReady) {
|
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?.applyOverrides(overrides);
|
||||||
tvWidget?.applyStudiesOverrides(studies_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];
|
|
||||||
}
|
|
||||||
48
src/hooks/useAppThemeAndColorMode.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { ThemeProvider } from 'styled-components';
|
||||||
|
|
||||||
|
import { AppTheme, AppThemeSetting, AppColorMode, AppThemeSystemSetting } from '@/state/configs';
|
||||||
|
import { getAppThemeSetting, getAppColorMode } from '@/state/configsSelectors';
|
||||||
|
|
||||||
|
import { Themes } from '@/styles/themes';
|
||||||
|
|
||||||
|
export const AppThemeAndColorModeProvider = ({ ...props }) => {
|
||||||
|
return <ThemeProvider theme={useAppThemeAndColorModeContext()} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAppThemeAndColorModeContext = () => {
|
||||||
|
const themeSetting: AppThemeSetting = useSelector(getAppThemeSetting);
|
||||||
|
const colorMode: AppColorMode = useSelector(getAppColorMode);
|
||||||
|
|
||||||
|
const darkModePref = globalThis.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
|
||||||
|
const [systemPreference, setSystemPreference] = useState(
|
||||||
|
darkModePref.matches ? AppTheme.Dark : AppTheme.Light
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = (e) => {
|
||||||
|
if (e.matches) {
|
||||||
|
setSystemPreference(AppTheme.Dark);
|
||||||
|
} else {
|
||||||
|
setSystemPreference(AppTheme.Light);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
darkModePref.addEventListener('change', handler);
|
||||||
|
return () => darkModePref.removeEventListener('change', handler);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getThemeFromSetting = (): AppTheme => {
|
||||||
|
switch (themeSetting) {
|
||||||
|
case AppThemeSystemSetting.System:
|
||||||
|
return systemPreference;
|
||||||
|
case AppTheme.Classic:
|
||||||
|
case AppTheme.Dark:
|
||||||
|
case AppTheme.Light:
|
||||||
|
return themeSetting;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Themes[getThemeFromSetting()][colorMode];
|
||||||
|
};
|
||||||
62
src/icons/chaos-labs.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { AppTheme } from '@/state/configs';
|
||||||
|
import { getAppTheme } from '@/state/configsSelectors';
|
||||||
|
|
||||||
|
const ChaosLabsIcon: React.FC = () => {
|
||||||
|
const appTheme = useSelector(getAppTheme);
|
||||||
|
|
||||||
|
const fills = appTheme === AppTheme.Light ? ['#1482E5', '#000000'] : ['#1482E5', '#E5E9EB'];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg width="91" height="17" viewBox="0 0 91 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M13.4384 13.2558C13.3846 13.2931 13.3295 13.3283 13.2724 13.3615L11.4238 14.4385L4.17188 10.2149V6.61884L11.4198 2.39746L13.2724 3.47652C13.3376 3.51449 13.4007 3.55521 13.4619 3.59848L8.28233 6.60962V6.60225L6.20661 7.81644V9.05132L8.28233 10.2629V9.0364L14.4967 5.41709C14.5028 5.48788 14.5055 5.55928 14.5055 5.63112V7.80972L10.3675 10.2318V11.4757L13.4384 13.2558Z"
|
||||||
|
fill={fills[0]}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9.34397 1.18863L8.48587 0.688787C7.72318 0.244363 6.78308 0.244363 6.01972 0.688787L1.23307 3.47666C0.470044 3.92109 0 4.74241 0 5.63125V11.207C0 12.0958 0.470044 12.9172 1.23307 13.3616L6.01972 16.1495C6.78308 16.5939 7.72318 16.5939 8.48587 16.1495L9.348 15.6475L2.09628 11.4241V5.41158L2.09911 5.41323L2.09628 5.41L9.34397 1.18863Z"
|
||||||
|
fill={fills[0]}
|
||||||
|
/>
|
||||||
|
<path d="M62.777 12.3629V4.57764H64.1102V11.1154H67.7133V12.3629H62.777Z" fill={fills[1]} />
|
||||||
|
<path
|
||||||
|
d="M70.2932 10.5919L69.5029 12.3629H68.0797L71.5585 4.57764H72.9817L76.4605 12.3629H75.0373L74.2464 10.5919H70.2932ZM73.7041 9.37795L72.2701 6.17032L70.8355 9.37795H73.7041Z"
|
||||||
|
fill={fills[1]}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M81.0141 12.3629H77.5581V4.57764H80.6304C81.1646 4.57764 81.6242 4.64075 82.0079 4.76698C82.3997 4.8932 82.6893 5.06398 82.8781 5.27931C83.2396 5.68026 83.4197 6.1332 83.4197 6.6381C83.4197 7.24693 83.2242 7.69991 82.8324 7.99692C82.6893 8.10087 82.5918 8.16767 82.5388 8.19737C82.4863 8.21968 82.3923 8.26047 82.2565 8.31987C82.7464 8.42382 83.1341 8.64289 83.4197 8.97699C83.7134 9.3037 83.8605 9.71213 83.8605 10.2021C83.8605 10.7442 83.6724 11.2231 83.2961 11.6389C82.8512 12.1215 82.0912 12.3629 81.0141 12.3629ZM78.8906 7.80756H80.5847C81.5489 7.80756 82.0307 7.48454 82.0307 6.83858C82.0307 6.46732 81.9138 6.20002 81.6806 6.03667C81.4468 5.87331 81.086 5.79164 80.5961 5.79164H78.8906V7.80756ZM78.8906 11.1489H80.9805C81.4697 11.1489 81.8426 11.0746 82.0986 10.9261C82.362 10.7701 82.4937 10.4806 82.4937 10.0574C82.4937 9.3668 81.9326 9.02154 80.8111 9.02154H78.8906V11.1489Z"
|
||||||
|
fill={fills[1]}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M87.9162 5.60121C87.5325 5.60121 87.216 5.67917 86.9674 5.8351C86.7194 5.99103 86.5951 6.22863 86.5951 6.54791C86.5951 6.85977 86.7194 7.1011 86.9674 7.27185C87.216 7.4352 87.7435 7.61341 88.5492 7.80647C89.3623 7.99953 89.9724 8.27053 90.379 8.61949C90.7929 8.96851 90.9999 9.48452 90.9999 10.1676C90.9999 10.8433 90.7405 11.3928 90.2204 11.816C89.701 12.2393 89.0196 12.4509 88.1763 12.4509C86.9412 12.4509 85.8459 12.0314 84.8896 11.1923L85.7249 10.201C86.5232 10.8842 87.3518 11.2257 88.2099 11.2257C88.6393 11.2257 88.9779 11.1366 89.2266 10.9584C89.4826 10.7728 89.6109 10.5314 89.6109 10.2345C89.6109 9.93003 89.49 9.69619 89.2494 9.53283C89.0156 9.36202 88.609 9.20981 88.0291 9.07616C87.4499 8.93511 87.0091 8.80885 86.708 8.6975C86.407 8.5787 86.1395 8.42643 85.9057 8.24083C85.4393 7.89188 85.2055 7.35726 85.2055 6.63702C85.2055 5.91678 85.4689 5.36361 85.9964 4.9775C86.5306 4.58397 87.1898 4.38721 87.9727 4.38721C88.4773 4.38721 88.9779 4.46889 89.4752 4.63224C89.9724 4.79558 90.4012 5.02577 90.7627 5.32277L90.0511 6.31402C89.8179 6.10612 89.5014 5.93534 89.1022 5.80169C88.7031 5.66804 88.308 5.60121 87.9162 5.60121Z"
|
||||||
|
fill={fills[1]}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M24.047 4.38721C22.8629 4.38721 21.861 4.77008 21.0648 5.54419L21.0634 5.54519C20.2745 6.31948 19.8807 7.2916 19.8807 8.43967C19.8807 9.58585 20.2665 10.5517 21.0433 11.3136L21.0439 11.3146C21.8268 12.0745 22.8072 12.4509 23.9643 12.4509C25.1463 12.4509 26.1536 11.9892 26.9707 11.0839L27.1609 10.8729L25.9722 9.65318L25.7558 9.85645C25.442 10.1501 25.1524 10.3555 24.8869 10.4827C24.6336 10.5973 24.3191 10.6603 23.9334 10.6603C23.3434 10.6603 22.8361 10.4504 22.3966 10.0177C21.9686 9.58323 21.7542 9.05029 21.7542 8.39841C21.7542 7.73954 21.9719 7.22084 22.4006 6.81607L22.402 6.81454C22.8367 6.39839 23.371 6.18802 24.0261 6.18802C24.4071 6.18802 24.7216 6.24839 24.9776 6.35892L24.9797 6.35987C25.2437 6.47129 25.5394 6.67559 25.866 6.98947L26.0904 7.20438L27.2583 5.92696L27.0729 5.72256C26.2665 4.83489 25.2511 4.38721 24.047 4.38721Z"
|
||||||
|
fill={fills[1]}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M47.6624 4.38721C46.5167 4.38721 45.5396 4.77222 44.7521 5.54468C43.9625 6.31199 43.5687 7.27749 43.5687 8.41904C43.5687 9.55454 43.9632 10.5194 44.7514 11.2929L44.7527 11.2939C45.5403 12.0594 46.5173 12.4406 47.6624 12.4406C48.8074 12.4406 49.7845 12.0594 50.572 11.2939L50.5734 11.2929C51.3616 10.5194 51.756 9.55454 51.756 8.41904C51.756 7.27749 51.3623 6.312 50.5727 5.54469C49.7851 4.77223 48.8081 4.38721 47.6624 4.38721ZM45.4207 8.41904C45.4207 7.76676 45.6364 7.22501 46.0671 6.77549C46.5039 6.32689 47.0294 6.10561 47.6624 6.10561C48.2954 6.10561 48.8168 6.32697 49.2462 6.77466L49.2476 6.77617C49.6857 7.22615 49.9034 7.7677 49.9034 8.41904C49.9034 9.06265 49.6864 9.60104 49.2476 10.0516L49.2462 10.0531C48.8168 10.5008 48.2954 10.7222 47.6624 10.7222C47.0294 10.7222 46.5039 10.5009 46.0671 10.0523C45.6357 9.60218 45.4207 9.06359 45.4207 8.41904Z"
|
||||||
|
fill={fills[1]}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M55.2113 4.38721C54.4439 4.38721 53.7767 4.58367 53.2277 4.99291C52.6605 5.41417 52.3843 6.02137 52.3843 6.77092C52.3843 7.50415 52.6222 8.09878 53.1396 8.49282C53.3768 8.68366 53.6463 8.83835 53.9446 8.95789L53.9514 8.96024C54.2423 9.06951 54.6576 9.18959 55.1898 9.32096L55.1938 9.32176C55.7153 9.4438 56.0345 9.57362 56.1944 9.69243L56.1991 9.69565L56.2038 9.69874C56.3355 9.78966 56.402 9.90967 56.402 10.098C56.402 10.2701 56.3362 10.4048 56.1756 10.523C56.0177 10.6376 55.7791 10.7119 55.4277 10.7119C54.7335 10.7119 54.0461 10.4338 53.36 9.83838L53.1262 9.63551L51.9791 11.0155L52.1975 11.2103C53.1228 12.0336 54.1933 12.4509 55.3968 12.4509C56.2179 12.4509 56.9134 12.2409 57.4537 11.7944C57.9987 11.3443 58.2748 10.7498 58.2748 10.0363C58.2748 9.34239 58.0652 8.77028 57.6029 8.37509C57.1809 8.00799 56.5721 7.74216 55.808 7.55804C55.4458 7.47001 55.1515 7.38669 54.923 7.3084C54.6926 7.22931 54.5461 7.16104 54.4648 7.10769C54.3257 7.00954 54.2571 6.88184 54.2571 6.68852C54.2571 6.48456 54.3277 6.36719 54.4574 6.28486C54.6227 6.17969 54.8498 6.11592 55.1596 6.11592C55.4814 6.11592 55.8087 6.17147 56.144 6.28523C56.4813 6.39984 56.73 6.54009 56.9033 6.69703L57.1567 6.92574L58.1646 5.50194L57.9496 5.32269C57.5874 5.02123 57.1621 4.79104 56.6769 4.62937C56.1937 4.46839 55.7052 4.38721 55.2113 4.38721Z"
|
||||||
|
fill={fills[1]}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M29.7507 4.56055H27.9297V12.3667H29.7507V9.42066H32.7195V12.3667H34.5406V4.56055H32.7195V7.68166H29.7507V4.56055Z"
|
||||||
|
fill={fills[1]}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M40.3586 4.56055H38.6659L35.2261 12.3667H37.1862L37.9072 10.7289H41.1173L41.8383 12.3667H43.7984L40.3586 4.56055ZM38.6686 9.00014L39.5126 7.08737L40.3559 9.00014H38.6686Z"
|
||||||
|
fill={fills[1]}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChaosLabsIcon;
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import ChaosLabsIcon from './chaos-labs';
|
||||||
export { default as AddressConnectorIcon } from './address-connector.svg';
|
export { default as AddressConnectorIcon } from './address-connector.svg';
|
||||||
export { default as ArrowIcon } from './arrow.svg';
|
export { default as ArrowIcon } from './arrow.svg';
|
||||||
export { default as Bar3Icon } from './bar3.svg';
|
export { default as Bar3Icon } from './bar3.svg';
|
||||||
@ -34,7 +35,6 @@ export { default as HistoryIcon } from './history.svg';
|
|||||||
export { default as LeaderboardIcon } from './leaderboard.svg';
|
export { default as LeaderboardIcon } from './leaderboard.svg';
|
||||||
export { default as LinkOutIcon } from './link-out.svg';
|
export { default as LinkOutIcon } from './link-out.svg';
|
||||||
export { default as LockIcon } from './lock.svg';
|
export { default as LockIcon } from './lock.svg';
|
||||||
export { default as LogoShortIcon } from './logo-short';
|
|
||||||
export { default as MarketsIcon } from './markets.svg';
|
export { default as MarketsIcon } from './markets.svg';
|
||||||
export { default as MenuIcon } from './menu.svg';
|
export { default as MenuIcon } from './menu.svg';
|
||||||
export { default as MigrateIcon } from './migrate.svg';
|
export { default as MigrateIcon } from './migrate.svg';
|
||||||
@ -90,7 +90,9 @@ export { default as WebsiteIcon } from './website.svg';
|
|||||||
export { default as WhitepaperIcon } from './whitepaper.svg';
|
export { default as WhitepaperIcon } from './whitepaper.svg';
|
||||||
|
|
||||||
// Logos
|
// Logos
|
||||||
|
export { default as ChaosLabsIcon } from './chaos-labs';
|
||||||
export { default as EtherscanIcon } from './logos/etherscan.svg';
|
export { default as EtherscanIcon } from './logos/etherscan.svg';
|
||||||
|
export { default as LogoShortIcon } from './logo-short';
|
||||||
|
|
||||||
// Trade
|
// Trade
|
||||||
export { default as OrderCanceledIcon } from './trade/order-canceled.svg';
|
export { default as OrderCanceledIcon } from './trade/order-canceled.svg';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useAppThemeContext } from '@/hooks/useAppTheme';
|
import { useAppThemeAndColorModeContext } from '@/hooks/useAppThemeAndColorMode';
|
||||||
|
|
||||||
const LogoShortIcon: React.FC<{ id?: string }> = ({ id }: { id?: string }) => {
|
const LogoShortIcon: React.FC<{ id?: string }> = ({ id }: { id?: string }) => {
|
||||||
const theme = useAppThemeContext();
|
const theme = useAppThemeAndColorModeContext();
|
||||||
const fill = theme.logoFill;
|
const fill = theme.logoFill;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 380 B After Width: | Height: | Size: 364 B |
@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg" stroke-width="1.5" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11 1V3.5M18.0711 3.92889L16.3033 5.69667M21 11H18.5M18.0711 18.0711L16.3033 16.3033M11 18.5V21M5.69667 16.3033L3.92889 18.0711M3.5 11H1M5.69667 5.69667L3.92889 3.92889M15.1667 11C15.1667 12.1051 14.7277 13.1649 13.9463 13.9463C13.1649 14.7277 12.1051 15.1667 11 15.1667C9.89493 15.1667 8.83512 14.7277 8.05372 13.9463C7.27232 13.1649 6.83333 12.1051 6.83333 11C6.83333 9.89493 7.27232 8.83512 8.05372 8.05372C8.83512 7.27232 9.89493 6.83333 11 6.83333C12.1051 6.83333 13.1649 7.27232 13.9463 8.05372C14.7277 8.83512 15.1667 9.89493 15.1667 11Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 750 B |
@ -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} />,
|
||||||
|
|||||||
@ -127,7 +127,7 @@ Styled.StatusDot = styled.div<{ exchangeStatus: ExchangeStatus }>`
|
|||||||
background-color: ${({ exchangeStatus }) =>
|
background-color: ${({ exchangeStatus }) =>
|
||||||
({
|
({
|
||||||
[ExchangeStatus.Degraded]: css`var(--color-warning)`,
|
[ExchangeStatus.Degraded]: css`var(--color-warning)`,
|
||||||
[ExchangeStatus.Operational]: css`var(--color-positive)`,
|
[ExchangeStatus.Operational]: css`var(--color-success)`,
|
||||||
}[exchangeStatus])};
|
}[exchangeStatus])};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -43,19 +43,19 @@ export const getStatusIconInfo = ({
|
|||||||
case AbacusOrderStatus.filled: {
|
case AbacusOrderStatus.filled: {
|
||||||
return {
|
return {
|
||||||
statusIcon: IconName.OrderFilled,
|
statusIcon: IconName.OrderFilled,
|
||||||
statusIconColor: `var(--color-positive)`,
|
statusIconColor: `var(--color-success)`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case AbacusOrderStatus.cancelled: {
|
case AbacusOrderStatus.cancelled: {
|
||||||
return {
|
return {
|
||||||
statusIcon: IconName.OrderCanceled,
|
statusIcon: IconName.OrderCanceled,
|
||||||
statusIconColor: `var(--color-negative)`,
|
statusIconColor: `var(--color-error)`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case AbacusOrderStatus.canceling: {
|
case AbacusOrderStatus.canceling: {
|
||||||
return {
|
return {
|
||||||
statusIcon: IconName.OrderPending,
|
statusIcon: IconName.OrderPending,
|
||||||
statusIconColor: `var(--color-negative)`,
|
statusIconColor: `var(--color-error)`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case AbacusOrderStatus.untriggered: {
|
case AbacusOrderStatus.untriggered: {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Candle, TradingViewBar, TradingViewSymbol } from '@/constants/candles';
|
import { Candle, TradingViewBar, TradingViewSymbol } from '@/constants/candles';
|
||||||
|
|
||||||
import { AppTheme } from '@/state/configs';
|
import type { AppTheme, AppColorMode } from '@/state/configs';
|
||||||
|
|
||||||
import { Themes } from '@/styles/themes';
|
import { Themes } from '@/styles/themes';
|
||||||
|
|
||||||
@ -47,8 +47,14 @@ export const getHistorySlice = ({
|
|||||||
return bars.filter(({ time }) => time >= fromMs);
|
return bars.filter(({ time }) => time >= fromMs);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWidgetOverrides = (appTheme: AppTheme) => {
|
export const getWidgetOverrides = ({
|
||||||
const theme = Themes[appTheme];
|
appTheme,
|
||||||
|
appColorMode,
|
||||||
|
}: {
|
||||||
|
appTheme: AppTheme;
|
||||||
|
appColorMode: AppColorMode;
|
||||||
|
}) => {
|
||||||
|
const theme = Themes[appTheme][appColorMode];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
overrides: {
|
overrides: {
|
||||||
|
|||||||
@ -286,10 +286,10 @@ Styled.ConnectedIcon = styled.div`
|
|||||||
height: 0.5rem;
|
height: 0.5rem;
|
||||||
width: 0.5rem;
|
width: 0.5rem;
|
||||||
margin-right: 0.25rem;
|
margin-right: 0.25rem;
|
||||||
background: var(--color-positive);
|
background: var(--color-success);
|
||||||
|
|
||||||
border-radius: 50%;
|
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`
|
Styled.Address = styled.h1`
|
||||||
@ -318,7 +318,7 @@ Styled.ActionButton = styled(IconButton)<{ iconName?: IconName }>`
|
|||||||
${({ iconName }) =>
|
${({ iconName }) =>
|
||||||
iconName === IconName.Close
|
iconName === IconName.Close
|
||||||
? css`
|
? css`
|
||||||
--button-textColor: var(--color-negative);
|
--button-textColor: var(--color-error);
|
||||||
--button-icon-size: 0.75em;
|
--button-icon-size: 0.75em;
|
||||||
`
|
`
|
||||||
: iconName === IconName.Transfer &&
|
: iconName === IconName.Transfer &&
|
||||||
|
|||||||
@ -272,7 +272,7 @@ Styled.AccountDetail = styled.div<{ gridArea: string }>`
|
|||||||
|
|
||||||
Styled.PnlChart = styled(PnlChart)<{ pnlDiffSign: NumberSign }>`
|
Styled.PnlChart = styled(PnlChart)<{ pnlDiffSign: NumberSign }>`
|
||||||
grid-area: Chart;
|
grid-area: Chart;
|
||||||
background-color: var(--color-layer-1);
|
background-color: var(--color-layer-2);
|
||||||
|
|
||||||
--pnl-line-color: ${({ pnlDiffSign }) =>
|
--pnl-line-color: ${({ pnlDiffSign }) =>
|
||||||
({
|
({
|
||||||
|
|||||||
@ -7,6 +7,8 @@ import { STRING_KEYS } from '@/constants/localization';
|
|||||||
import { ButtonAction } from '@/constants/buttons';
|
import { ButtonAction } from '@/constants/buttons';
|
||||||
import { DialogTypes } from '@/constants/dialogs';
|
import { DialogTypes } from '@/constants/dialogs';
|
||||||
|
|
||||||
|
import { ChaosLabsIcon } from '@/icons';
|
||||||
|
|
||||||
import breakpoints from '@/styles/breakpoints';
|
import breakpoints from '@/styles/breakpoints';
|
||||||
import { useAccounts, useBreakpoints, useStringGetter } from '@/hooks';
|
import { useAccounts, useBreakpoints, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
@ -114,7 +116,9 @@ const LaunchIncentivesContent = () => {
|
|||||||
<Styled.Description>
|
<Styled.Description>
|
||||||
{stringGetter({ key: STRING_KEYS.LAUNCH_INCENTIVES_DESCRIPTION })}{' '}
|
{stringGetter({ key: STRING_KEYS.LAUNCH_INCENTIVES_DESCRIPTION })}{' '}
|
||||||
</Styled.Description>
|
</Styled.Description>
|
||||||
<Styled.ChaosLabsLogo src="/logos/chaos-labs.svg" />
|
<Styled.ChaosLabsLogo>
|
||||||
|
{stringGetter({ key: STRING_KEYS.POWERED_BY })} <ChaosLabsIcon />
|
||||||
|
</Styled.ChaosLabsLogo>
|
||||||
<Styled.ButtonRow>
|
<Styled.ButtonRow>
|
||||||
<Styled.AboutButton
|
<Styled.AboutButton
|
||||||
action={ButtonAction.Base}
|
action={ButtonAction.Base}
|
||||||
@ -126,7 +130,7 @@ const LaunchIncentivesContent = () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
slotRight={<Styled.LinkOutIcon iconName={IconName.LinkOut} />}
|
slotRight={<Icon iconName={IconName.LinkOut} />}
|
||||||
>
|
>
|
||||||
{stringGetter({ key: STRING_KEYS.ABOUT })}
|
{stringGetter({ key: STRING_KEYS.ABOUT })}
|
||||||
</Styled.AboutButton>
|
</Styled.AboutButton>
|
||||||
@ -140,7 +144,7 @@ const LaunchIncentivesContent = () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
slotRight={<Styled.LinkOutIcon iconName={IconName.LinkOut} />}
|
slotRight={<Icon iconName={IconName.LinkOut} />}
|
||||||
slotLeft={<Icon iconName={IconName.Leaderboard} />}
|
slotLeft={<Icon iconName={IconName.Leaderboard} />}
|
||||||
>
|
>
|
||||||
{stringGetter({ key: STRING_KEYS.LEADERBOARD })}
|
{stringGetter({ key: STRING_KEYS.LEADERBOARD })}
|
||||||
@ -153,7 +157,7 @@ const LaunchIncentivesContent = () => {
|
|||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
Styled.Panel = styled(Panel)`
|
Styled.Panel = styled(Panel)`
|
||||||
background-color: var(--color-layer-4);
|
background-color: var(--color-layer-3);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -200,10 +204,6 @@ Styled.Button = styled(Button)`
|
|||||||
--button-padding: 0 1rem;
|
--button-padding: 0 1rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.LinkOutIcon = styled(Icon)`
|
|
||||||
color: var(--color-text-1);
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.AboutButton = styled(Styled.Button)`
|
Styled.AboutButton = styled(Styled.Button)`
|
||||||
--button-textColor: var(--color-text-2);
|
--button-textColor: var(--color-text-2);
|
||||||
--button-backgroundColor: var(--color-layer-6);
|
--button-backgroundColor: var(--color-layer-6);
|
||||||
@ -280,9 +280,10 @@ Styled.Image = styled.img`
|
|||||||
height: auto;
|
height: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.ChaosLabsLogo = styled.img`
|
Styled.ChaosLabsLogo = styled.span`
|
||||||
height: 1.25rem;
|
display: flex;
|
||||||
align-self: start;
|
gap: 0.5em;
|
||||||
|
font: var(--font-mini-medium);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.NewTag = styled(Tag)`
|
Styled.NewTag = styled(Tag)`
|
||||||
|
|||||||
@ -12,35 +12,35 @@ export enum AppTheme {
|
|||||||
Light = 'Light',
|
Light = 'Light',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AppThemeSystemSetting {
|
||||||
|
System = 'System',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AppThemeSetting = AppTheme | AppThemeSystemSetting;
|
||||||
|
|
||||||
|
export enum AppColorMode {
|
||||||
|
GreenUp = 'GreenUp',
|
||||||
|
RedUp = 'RedUp',
|
||||||
|
}
|
||||||
|
|
||||||
export interface ConfigsState {
|
export interface ConfigsState {
|
||||||
appTheme: AppTheme;
|
appThemeSetting: AppThemeSetting;
|
||||||
|
appColorMode: AppColorMode;
|
||||||
feeTiers?: kollections.List<FeeTier>;
|
feeTiers?: kollections.List<FeeTier>;
|
||||||
feeDiscounts?: FeeDiscount[];
|
feeDiscounts?: FeeDiscount[];
|
||||||
network?: NetworkConfigs;
|
network?: NetworkConfigs;
|
||||||
hasSeenLaunchIncentives: boolean;
|
hasSeenLaunchIncentives: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DOCUMENT_THEME_MAP = {
|
|
||||||
[AppTheme.Classic]: () => {
|
|
||||||
document?.documentElement?.classList.remove('theme-dark', 'theme-light');
|
|
||||||
},
|
|
||||||
[AppTheme.Dark]: () => {
|
|
||||||
document?.documentElement?.classList.remove('theme-light');
|
|
||||||
document?.documentElement?.classList.add('theme-dark');
|
|
||||||
},
|
|
||||||
[AppTheme.Light]: () => {
|
|
||||||
document?.documentElement?.classList.remove('theme-dark');
|
|
||||||
document?.documentElement?.classList.add('theme-light');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const changeTheme = (theme: AppTheme) => DOCUMENT_THEME_MAP[theme]();
|
|
||||||
|
|
||||||
const initialState: ConfigsState = {
|
const initialState: ConfigsState = {
|
||||||
appTheme: getLocalStorage({
|
appThemeSetting: getLocalStorage({
|
||||||
key: LocalStorageKey.SelectedTheme,
|
key: LocalStorageKey.SelectedTheme,
|
||||||
defaultValue: AppTheme.Classic,
|
defaultValue: AppTheme.Classic,
|
||||||
}),
|
}),
|
||||||
|
appColorMode: getLocalStorage({
|
||||||
|
key: LocalStorageKey.SelectedColorMode,
|
||||||
|
defaultValue: AppColorMode.GreenUp,
|
||||||
|
}),
|
||||||
feeDiscounts: undefined,
|
feeDiscounts: undefined,
|
||||||
feeTiers: undefined,
|
feeTiers: undefined,
|
||||||
network: undefined,
|
network: undefined,
|
||||||
@ -50,16 +50,17 @@ const initialState: ConfigsState = {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
changeTheme(initialState.appTheme);
|
|
||||||
|
|
||||||
export const configsSlice = createSlice({
|
export const configsSlice = createSlice({
|
||||||
name: 'Inputs',
|
name: 'Inputs',
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
setAppTheme: (state: ConfigsState, { payload }: PayloadAction<AppTheme>) => {
|
setAppThemeSetting: (state: ConfigsState, { payload }: PayloadAction<AppThemeSetting>) => {
|
||||||
setLocalStorage({ key: LocalStorageKey.SelectedTheme, value: payload });
|
setLocalStorage({ key: LocalStorageKey.SelectedTheme, value: payload });
|
||||||
changeTheme(payload);
|
state.appThemeSetting = 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>>) => ({
|
setConfigs: (state: ConfigsState, action: PayloadAction<Nullable<Configs>>) => ({
|
||||||
...state,
|
...state,
|
||||||
@ -72,4 +73,5 @@ export const configsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { setAppTheme, setConfigs, markLaunchIncentivesSeen } = configsSlice.actions;
|
export const { setAppThemeSetting, setAppColorMode, setConfigs, markLaunchIncentivesSeen } =
|
||||||
|
configsSlice.actions;
|
||||||
|
|||||||
@ -1,6 +1,21 @@
|
|||||||
import type { RootState } from './_store';
|
import type { RootState } from './_store';
|
||||||
|
import { AppTheme, AppThemeSystemSetting, AppThemeSetting } from './configs';
|
||||||
|
|
||||||
export const getAppTheme = (state: RootState) => state.configs.appTheme;
|
export const getAppThemeSetting = (state: RootState): AppThemeSetting =>
|
||||||
|
state.configs.appThemeSetting;
|
||||||
|
|
||||||
|
export const getAppTheme = (state: RootState): AppTheme => {
|
||||||
|
switch (state.configs.appThemeSetting) {
|
||||||
|
case AppThemeSystemSetting.System:
|
||||||
|
return globalThis.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
? AppTheme.Dark
|
||||||
|
: AppTheme.Light;
|
||||||
|
default:
|
||||||
|
return state.configs.appThemeSetting;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAppColorMode = (state: RootState) => state.configs.appColorMode;
|
||||||
|
|
||||||
export const getFeeTiers = (state: RootState) => state.configs.feeTiers?.toArray();
|
export const getFeeTiers = (state: RootState) => state.configs.feeTiers?.toArray();
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export const formMixins: Record<
|
|||||||
border-radius: var(--input-radius);
|
border-radius: var(--input-radius);
|
||||||
|
|
||||||
&:focus-within {
|
&:focus-within {
|
||||||
filter: brightness(1.1);
|
filter: brightness(var(--hover-filter-base));
|
||||||
}
|
}
|
||||||
|
|
||||||
@media ${breakpoints.tablet} {
|
@media ${breakpoints.tablet} {
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export const GlobalStyle = createGlobalStyle`
|
|||||||
--color-text-0: ${({ theme }) => theme.textTertiary};
|
--color-text-0: ${({ theme }) => theme.textTertiary};
|
||||||
--color-text-1: ${({ theme }) => theme.textSecondary};
|
--color-text-1: ${({ theme }) => theme.textSecondary};
|
||||||
--color-text-2: ${({ theme }) => theme.textPrimary};
|
--color-text-2: ${({ theme }) => theme.textPrimary};
|
||||||
|
--color-text-button: ${({ theme }) => theme.textButton};
|
||||||
|
|
||||||
--color-gradient-base-0: ${({ theme }) => theme.gradientBase0};
|
--color-gradient-base-0: ${({ theme }) => theme.gradientBase0};
|
||||||
--color-gradient-base-1: ${({ theme }) => theme.gradientBase1};
|
--color-gradient-base-1: ${({ theme }) => theme.gradientBase1};
|
||||||
@ -29,6 +30,9 @@ export const GlobalStyle = createGlobalStyle`
|
|||||||
--color-success: ${({ theme }) => theme.success};
|
--color-success: ${({ theme }) => theme.success};
|
||||||
--color-warning: ${({ theme }) => theme.warning};
|
--color-warning: ${({ theme }) => theme.warning};
|
||||||
--color-error: ${({ theme }) => theme.error};
|
--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-positive: ${({ theme }) => theme.positive};
|
||||||
--color-negative: ${({ theme }) => theme.negative};
|
--color-negative: ${({ theme }) => theme.negative};
|
||||||
@ -38,5 +42,9 @@ export const GlobalStyle = createGlobalStyle`
|
|||||||
--color-risk-low: ${({ theme }) => theme.riskLow};
|
--color-risk-low: ${({ theme }) => theme.riskLow};
|
||||||
--color-risk-medium: ${({ theme }) => theme.riskMedium};
|
--color-risk-medium: ${({ theme }) => theme.riskMedium};
|
||||||
--color-risk-high: ${({ theme }) => theme.riskHigh};
|
--color-risk-high: ${({ theme }) => theme.riskHigh};
|
||||||
|
|
||||||
|
--hover-filter-base: ${({ theme }) => theme.hoverFilterBase};
|
||||||
|
--hover-filter-variant: ${({ theme }) => theme.hoverFilterVariant};
|
||||||
|
--active-filter: ${({ theme }) => theme.activeFilter};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -21,8 +21,8 @@ export const popoverMixins = {
|
|||||||
--trigger-open-backgroundColor: var(--color-layer-1);
|
--trigger-open-backgroundColor: var(--color-layer-1);
|
||||||
--trigger-open-textColor: var(--color-text-2);
|
--trigger-open-textColor: var(--color-text-2);
|
||||||
|
|
||||||
--trigger-active-filter: brightness(0.9);
|
--trigger-active-filter: brightness(var(--active-filter));
|
||||||
--trigger-hover-filter: brightness(1.1);
|
--trigger-hover-filter: brightness(var(--hover-filter-base));
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -219,7 +219,7 @@ export const popoverMixins = {
|
|||||||
&[aria-selected="true"], // cmdk
|
&[aria-selected="true"], // cmdk
|
||||||
&[data-highlighted] // @radix-ui
|
&[data-highlighted] // @radix-ui
|
||||||
{
|
{
|
||||||
filter: brightness(1.1);
|
filter: brightness(var(--hover-filter-base));
|
||||||
background-color: var(--item-highlighted-backgroundColor);
|
background-color: var(--item-highlighted-backgroundColor);
|
||||||
color: var(--item-highlighted-textColor, var(--trigger-textColor, inherit)) !important;
|
color: var(--item-highlighted-textColor, var(--trigger-textColor, inherit)) !important;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { AppTheme } from '@/state/configs';
|
import { AppTheme, AppColorMode } from '@/state/configs';
|
||||||
import type { ThemeColors } from '@/constants/styles/colors';
|
import type { Theme, ThemeColorBase } from '@/constants/styles/colors';
|
||||||
import { ColorToken, OpacityToken } from '@/constants/styles/base';
|
import { BrightnessFilterToken, ColorToken, OpacityToken } from '@/constants/styles/base';
|
||||||
import { generateFadedColorVariant } from '@/lib/styles';
|
import { generateFadedColorVariant } from '@/lib/styles';
|
||||||
|
|
||||||
const ClassicTheme: ThemeColors = {
|
const ClassicThemeBase: ThemeColorBase = {
|
||||||
layer0: ColorToken.GrayBlue7,
|
layer0: ColorToken.GrayBlue7,
|
||||||
layer1: ColorToken.GrayBlue6,
|
layer1: ColorToken.GrayBlue6,
|
||||||
layer2: ColorToken.GrayBlue5,
|
layer2: ColorToken.GrayBlue5,
|
||||||
@ -20,6 +20,7 @@ const ClassicTheme: ThemeColors = {
|
|||||||
textPrimary: ColorToken.LightGray2,
|
textPrimary: ColorToken.LightGray2,
|
||||||
textSecondary: ColorToken.GrayPurple1,
|
textSecondary: ColorToken.GrayPurple1,
|
||||||
textTertiary: ColorToken.GrayPurple2,
|
textTertiary: ColorToken.GrayPurple2,
|
||||||
|
textButton: ColorToken.LightGray2,
|
||||||
|
|
||||||
gradientBase0: ColorToken.DarkGray9,
|
gradientBase0: ColorToken.DarkGray9,
|
||||||
gradientBase1: ColorToken.GrayBlue2,
|
gradientBase1: ColorToken.GrayBlue2,
|
||||||
@ -31,6 +32,9 @@ const ClassicTheme: ThemeColors = {
|
|||||||
success: ColorToken.Green1,
|
success: ColorToken.Green1,
|
||||||
warning: ColorToken.Yellow0,
|
warning: ColorToken.Yellow0,
|
||||||
error: ColorToken.Red2,
|
error: ColorToken.Red2,
|
||||||
|
successFaded: generateFadedColorVariant(ColorToken.Green1, OpacityToken.Opacity16),
|
||||||
|
warningFaded: generateFadedColorVariant(ColorToken.Yellow0, OpacityToken.Opacity16),
|
||||||
|
errorFaded: generateFadedColorVariant(ColorToken.Red2, OpacityToken.Opacity16),
|
||||||
|
|
||||||
positive: ColorToken.Green1,
|
positive: ColorToken.Green1,
|
||||||
negative: ColorToken.Red2,
|
negative: ColorToken.Red2,
|
||||||
@ -50,9 +54,13 @@ const ClassicTheme: ThemeColors = {
|
|||||||
switchThumbActiveBackground: ColorToken.White,
|
switchThumbActiveBackground: ColorToken.White,
|
||||||
toggleBackground: ColorToken.GrayBlue3,
|
toggleBackground: ColorToken.GrayBlue3,
|
||||||
tooltipBackground: generateFadedColorVariant(ColorToken.GrayBlue3, OpacityToken.Opacity66),
|
tooltipBackground: generateFadedColorVariant(ColorToken.GrayBlue3, OpacityToken.Opacity66),
|
||||||
|
|
||||||
|
hoverFilterBase: BrightnessFilterToken.Lighten10,
|
||||||
|
hoverFilterVariant: BrightnessFilterToken.Lighten10,
|
||||||
|
activeFilter: BrightnessFilterToken.Darken10,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DarkTheme: ThemeColors = {
|
const DarkThemeBase: ThemeColorBase = {
|
||||||
layer0: ColorToken.Black,
|
layer0: ColorToken.Black,
|
||||||
layer1: ColorToken.DarkGray11,
|
layer1: ColorToken.DarkGray11,
|
||||||
layer2: ColorToken.DarkGray13,
|
layer2: ColorToken.DarkGray13,
|
||||||
@ -69,6 +77,7 @@ const DarkTheme: ThemeColors = {
|
|||||||
textPrimary: ColorToken.LightGray0,
|
textPrimary: ColorToken.LightGray0,
|
||||||
textSecondary: ColorToken.MediumGray0,
|
textSecondary: ColorToken.MediumGray0,
|
||||||
textTertiary: ColorToken.DarkGray0,
|
textTertiary: ColorToken.DarkGray0,
|
||||||
|
textButton: ColorToken.LightGray0,
|
||||||
|
|
||||||
gradientBase0: ColorToken.DarkGray8,
|
gradientBase0: ColorToken.DarkGray8,
|
||||||
gradientBase1: ColorToken.DarkGray5,
|
gradientBase1: ColorToken.DarkGray5,
|
||||||
@ -80,6 +89,9 @@ const DarkTheme: ThemeColors = {
|
|||||||
success: ColorToken.Green0,
|
success: ColorToken.Green0,
|
||||||
warning: ColorToken.Yellow0,
|
warning: ColorToken.Yellow0,
|
||||||
error: ColorToken.Red0,
|
error: ColorToken.Red0,
|
||||||
|
successFaded: generateFadedColorVariant(ColorToken.Green0, OpacityToken.Opacity16),
|
||||||
|
warningFaded: generateFadedColorVariant(ColorToken.Yellow0, OpacityToken.Opacity16),
|
||||||
|
errorFaded: generateFadedColorVariant(ColorToken.Red0, OpacityToken.Opacity16),
|
||||||
|
|
||||||
positive: ColorToken.Green0,
|
positive: ColorToken.Green0,
|
||||||
negative: ColorToken.Red0,
|
negative: ColorToken.Red0,
|
||||||
@ -99,9 +111,13 @@ const DarkTheme: ThemeColors = {
|
|||||||
switchThumbActiveBackground: ColorToken.White,
|
switchThumbActiveBackground: ColorToken.White,
|
||||||
toggleBackground: ColorToken.DarkGray6,
|
toggleBackground: ColorToken.DarkGray6,
|
||||||
tooltipBackground: generateFadedColorVariant(ColorToken.DarkGray6, OpacityToken.Opacity66),
|
tooltipBackground: generateFadedColorVariant(ColorToken.DarkGray6, OpacityToken.Opacity66),
|
||||||
|
|
||||||
|
hoverFilterBase: BrightnessFilterToken.Lighten10,
|
||||||
|
hoverFilterVariant: BrightnessFilterToken.Lighten10,
|
||||||
|
activeFilter: BrightnessFilterToken.Darken10,
|
||||||
};
|
};
|
||||||
|
|
||||||
const LightTheme: ThemeColors = {
|
const LightThemeBase: ThemeColorBase = {
|
||||||
layer0: ColorToken.White,
|
layer0: ColorToken.White,
|
||||||
layer1: ColorToken.LightGray6,
|
layer1: ColorToken.LightGray6,
|
||||||
layer2: ColorToken.White,
|
layer2: ColorToken.White,
|
||||||
@ -118,6 +134,7 @@ const LightTheme: ThemeColors = {
|
|||||||
textPrimary: ColorToken.DarkGray12,
|
textPrimary: ColorToken.DarkGray12,
|
||||||
textSecondary: ColorToken.DarkGray3,
|
textSecondary: ColorToken.DarkGray3,
|
||||||
textTertiary: ColorToken.DarkGray1,
|
textTertiary: ColorToken.DarkGray1,
|
||||||
|
textButton: ColorToken.White,
|
||||||
|
|
||||||
gradientBase0: ColorToken.LightGray8,
|
gradientBase0: ColorToken.LightGray8,
|
||||||
gradientBase1: ColorToken.LightGray5,
|
gradientBase1: ColorToken.LightGray5,
|
||||||
@ -129,6 +146,9 @@ const LightTheme: ThemeColors = {
|
|||||||
success: ColorToken.Green2,
|
success: ColorToken.Green2,
|
||||||
warning: ColorToken.Yellow0,
|
warning: ColorToken.Yellow0,
|
||||||
error: ColorToken.Red1,
|
error: ColorToken.Red1,
|
||||||
|
successFaded: generateFadedColorVariant(ColorToken.Green2, OpacityToken.Opacity16),
|
||||||
|
warningFaded: generateFadedColorVariant(ColorToken.Yellow0, OpacityToken.Opacity16),
|
||||||
|
errorFaded: generateFadedColorVariant(ColorToken.Red1, OpacityToken.Opacity16),
|
||||||
|
|
||||||
positive: ColorToken.Green2,
|
positive: ColorToken.Green2,
|
||||||
negative: ColorToken.Red1,
|
negative: ColorToken.Red1,
|
||||||
@ -148,10 +168,28 @@ const LightTheme: ThemeColors = {
|
|||||||
switchThumbActiveBackground: ColorToken.White,
|
switchThumbActiveBackground: ColorToken.White,
|
||||||
toggleBackground: ColorToken.LightGray4,
|
toggleBackground: ColorToken.LightGray4,
|
||||||
tooltipBackground: generateFadedColorVariant(ColorToken.LightGray7, OpacityToken.Opacity66),
|
tooltipBackground: generateFadedColorVariant(ColorToken.LightGray7, OpacityToken.Opacity66),
|
||||||
|
|
||||||
|
hoverFilterBase: BrightnessFilterToken.Darken5,
|
||||||
|
hoverFilterVariant: BrightnessFilterToken.Lighten10,
|
||||||
|
activeFilter: BrightnessFilterToken.Darken10,
|
||||||
|
};
|
||||||
|
|
||||||
|
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 = {
|
export const Themes = {
|
||||||
[AppTheme.Classic]: ClassicTheme,
|
[AppTheme.Classic]: generateTheme(ClassicThemeBase),
|
||||||
[AppTheme.Dark]: DarkTheme,
|
[AppTheme.Dark]: generateTheme(DarkThemeBase),
|
||||||
[AppTheme.Light]: LightTheme,
|
[AppTheme.Light]: generateTheme(LightThemeBase),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -231,7 +231,7 @@ Styled.CircleContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Icon = styled(Icon)`
|
Styled.Icon = styled(Icon)`
|
||||||
color: var(--color-negative);
|
color: var(--color-error);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.WithUsage = styled.div`
|
Styled.WithUsage = styled.div`
|
||||||
|
|||||||
@ -557,11 +557,11 @@ Styled.PositionTile = styled(PositionTile)``;
|
|||||||
|
|
||||||
Styled.ClosePositionButton = styled(Button)`
|
Styled.ClosePositionButton = styled(Button)`
|
||||||
--button-border: solid var(--border-width) var(--color-border-red);
|
--button-border: solid var(--border-width) var(--color-border-red);
|
||||||
--button-textColor: var(--color-negative);
|
--button-textColor: var(--color-error);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.ClosePositionToggleButton = styled(ToggleButton)`
|
Styled.ClosePositionToggleButton = styled(ToggleButton)`
|
||||||
--button-border: solid var(--border-width) var(--color-border-red);
|
--button-border: solid var(--border-width) var(--color-border-red);
|
||||||
--button-toggle-off-textColor: var(--color-negative);
|
--button-toggle-off-textColor: var(--color-error);
|
||||||
--button-toggle-on-textColor: var(--color-negative);
|
--button-toggle-on-textColor: var(--color-error);
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -9,34 +9,30 @@ import {
|
|||||||
HistoricalPnlPeriods,
|
HistoricalPnlPeriods,
|
||||||
HISTORICAL_PNL_PERIODS,
|
HISTORICAL_PNL_PERIODS,
|
||||||
} from '@/constants/abacus';
|
} from '@/constants/abacus';
|
||||||
// import { STRING_KEYS } from '@/constants/localization';
|
|
||||||
import { timeUnits } from '@/constants/time';
|
import { timeUnits } from '@/constants/time';
|
||||||
import { breakpoints } from '@/styles';
|
import { breakpoints } from '@/styles';
|
||||||
|
|
||||||
import { useBreakpoints, useNow /*, useStringGetter*/ } from '@/hooks';
|
import { useBreakpoints, useNow } from '@/hooks';
|
||||||
|
|
||||||
// import { Details } from '@/components/Details';
|
import { Output } from '@/components/Output';
|
||||||
import { Output /*, OutputType, ShowSign*/ } from '@/components/Output';
|
|
||||||
// import { HorizontalSeparator } from '@/components/Separator';
|
|
||||||
import { ToggleGroup } from '@/components/ToggleGroup';
|
import { ToggleGroup } from '@/components/ToggleGroup';
|
||||||
|
|
||||||
import type { TooltipContextType } from '@visx/xychart';
|
import type { TooltipContextType } from '@visx/xychart';
|
||||||
import { TimeSeriesChart } from '@/components/visx/TimeSeriesChart';
|
import { TimeSeriesChart } from '@/components/visx/TimeSeriesChart';
|
||||||
import { AxisLabelOutput } from '@/components/visx/AxisLabelOutput';
|
import { AxisLabelOutput } from '@/components/visx/AxisLabelOutput';
|
||||||
// import { TooltipContent } from '@/components/visx/TooltipContent';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getSubaccount,
|
getSubaccount,
|
||||||
getSubaccountHistoricalPnl,
|
getSubaccountHistoricalPnl,
|
||||||
getSubaccountId,
|
getSubaccountId,
|
||||||
} from '@/state/accountSelectors';
|
} from '@/state/accountSelectors';
|
||||||
|
import { AppTheme } from '@/state/configs';
|
||||||
|
import { getAppTheme } from '@/state/configsSelectors';
|
||||||
|
|
||||||
import abacusStateManager from '@/lib/abacus';
|
import abacusStateManager from '@/lib/abacus';
|
||||||
import { formatRelativeTime } from '@/lib/dateTime';
|
import { formatRelativeTime } from '@/lib/dateTime';
|
||||||
import { isTruthy } from '@/lib/isTruthy';
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
|
|
||||||
import chartBackground from '/chart-background.png';
|
|
||||||
|
|
||||||
enum PnlSide {
|
enum PnlSide {
|
||||||
Profit = 'Profit',
|
Profit = 'Profit',
|
||||||
Loss = 'Loss',
|
Loss = 'Loss',
|
||||||
@ -62,6 +58,9 @@ const MS_FOR_PERIOD = {
|
|||||||
[HistoricalPnlPeriod.Period90d.name]: 90 * timeUnits.day,
|
[HistoricalPnlPeriod.Period90d.name]: 90 * timeUnits.day,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DARK_CHART_BACKGROUND_URL = '/chart-dots-background-dark.svg';
|
||||||
|
const LIGHT_CHART_BACKGROUND_URL = '/chart-dots-background-light.svg';
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
onTooltipContext?: (tooltipContext: TooltipContextType<PnlDatum>) => void;
|
onTooltipContext?: (tooltipContext: TooltipContextType<PnlDatum>) => void;
|
||||||
onVisibleDataChange?: (data: Array<PnlDatum>) => void;
|
onVisibleDataChange?: (data: Array<PnlDatum>) => void;
|
||||||
@ -82,8 +81,8 @@ export const PnlChart = ({
|
|||||||
selectedLocale,
|
selectedLocale,
|
||||||
slotEmpty,
|
slotEmpty,
|
||||||
}: PnlChartProps) => {
|
}: PnlChartProps) => {
|
||||||
// const stringGetter = useStringGetter();
|
|
||||||
const { isTablet } = useBreakpoints();
|
const { isTablet } = useBreakpoints();
|
||||||
|
const appTheme = useSelector(getAppTheme);
|
||||||
const { equity } = useSelector(getSubaccount, shallowEqual) || {};
|
const { equity } = useSelector(getSubaccount, shallowEqual) || {};
|
||||||
const now = useNow({ intervalMs: timeUnits.minute });
|
const now = useNow({ intervalMs: timeUnits.minute });
|
||||||
|
|
||||||
@ -171,10 +170,11 @@ export const PnlChart = ({
|
|||||||
[pnlData, equity, selectedPeriod, now]
|
[pnlData, equity, selectedPeriod, now]
|
||||||
);
|
);
|
||||||
|
|
||||||
// const latestDatum = data?.[data.length - 1];
|
const chartBackground =
|
||||||
|
appTheme === AppTheme.Light ? LIGHT_CHART_BACKGROUND_URL : DARK_CHART_BACKGROUND_URL;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Styled.Container className={className}>
|
<Styled.Container className={className} chartBackground={chartBackground}>
|
||||||
<TimeSeriesChart
|
<TimeSeriesChart
|
||||||
id="pnl-chart"
|
id="pnl-chart"
|
||||||
selectedLocale={selectedLocale}
|
selectedLocale={selectedLocale}
|
||||||
@ -198,25 +198,6 @@ export const PnlChart = ({
|
|||||||
yAccessor: (datum) => datum?.equity,
|
yAccessor: (datum) => datum?.equity,
|
||||||
colorAccessor: () => 'var(--pnl-line-color)',
|
colorAccessor: () => 'var(--pnl-line-color)',
|
||||||
getCurve: () => curveLinear,
|
getCurve: () => curveLinear,
|
||||||
// getCurve: ({ zoomDomain }) =>
|
|
||||||
// PNL_TIME_RESOLUTION * 30 < zoomDomain && zoomDomain < PNL_TIME_RESOLUTION * 400
|
|
||||||
// ? curveMonotoneX
|
|
||||||
// : curveLinear,
|
|
||||||
// threshold: {
|
|
||||||
// yAccessor: (datum) => datum?.netTransfers,
|
|
||||||
// aboveAreaProps: {
|
|
||||||
// fill: 'var(--color-positive)',
|
|
||||||
// fillOpacity: 0.33,
|
|
||||||
// strokeWidth: 1,
|
|
||||||
// stroke: 'var(--color-positive)',
|
|
||||||
// },
|
|
||||||
// belowAreaProps: {
|
|
||||||
// fill: 'var(--color-negative)',
|
|
||||||
// fillOpacity: 0.33,
|
|
||||||
// strokeWidth: 1,
|
|
||||||
// stroke: 'var(--color-negative)',
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
tickFormatY={(value) =>
|
tickFormatY={(value) =>
|
||||||
@ -229,98 +210,6 @@ export const PnlChart = ({
|
|||||||
.format(Math.abs(value))
|
.format(Math.abs(value))
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
}
|
}
|
||||||
// renderXAxisLabel={({ tooltipData }) => {
|
|
||||||
// const tooltipDatum = tooltipData!.nearestDatum!.datum ?? latestDatum;
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <Styled.XAxisLabelOutput type={OutputType.DateTime} value={tooltipDatum.createdAt} />
|
|
||||||
// );
|
|
||||||
// }}
|
|
||||||
// renderYAxisLabel={({ tooltipData }) => {
|
|
||||||
// const tooltipDatum = tooltipData!.nearestDatum!.datum ?? latestDatum;
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <Styled.YAxisLabelOutput
|
|
||||||
// type={OutputType.CompactFiat}
|
|
||||||
// value={tooltipDatum.totalPnl}
|
|
||||||
// accentColor={
|
|
||||||
// {
|
|
||||||
// [PnlSide.Loss]: 'var(--color-negative)',
|
|
||||||
// [PnlSide.Profit]: 'var(--color-positive)',
|
|
||||||
// [PnlSide.Flat]: 'var(--color-layer-6)',
|
|
||||||
// }[tooltipDatum.side]
|
|
||||||
// }
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
// }}
|
|
||||||
// renderTooltip={({ tooltipData }) => {
|
|
||||||
// const { nearestDatum } = tooltipData || {};
|
|
||||||
|
|
||||||
// const tooltipDatum = nearestDatum?.datum ?? latestDatum;
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <TooltipContent
|
|
||||||
// accentColor={
|
|
||||||
// {
|
|
||||||
// [PnlSide.Loss]: 'var(--color-negative)',
|
|
||||||
// [PnlSide.Profit]: 'var(--color-positive)',
|
|
||||||
// [PnlSide.Flat]: 'var(--color-layer-6)',
|
|
||||||
// }[tooltipDatum.side]
|
|
||||||
// }
|
|
||||||
// >
|
|
||||||
// <Details
|
|
||||||
// layout="column"
|
|
||||||
// items={[
|
|
||||||
// {
|
|
||||||
// key: 'createdAt',
|
|
||||||
// label: stringGetter({ key: STRING_KEYS.TIME }),
|
|
||||||
// value: <Output type={OutputType.DateTime} value={tooltipDatum.createdAt} />,
|
|
||||||
// },
|
|
||||||
// ].filter(Boolean)}
|
|
||||||
// />
|
|
||||||
|
|
||||||
// <HorizontalSeparator />
|
|
||||||
|
|
||||||
// <Details
|
|
||||||
// layout="column"
|
|
||||||
// items={[
|
|
||||||
// {
|
|
||||||
// key: 'netTransfers',
|
|
||||||
// label: stringGetter({ key: STRING_KEYS.NET_TRANSFERS }),
|
|
||||||
// value: <Output type={OutputType.Fiat} value={tooltipDatum.netTransfers} />,
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// key: 'equity',
|
|
||||||
// label: {
|
|
||||||
// [PnlSide.Profit]: stringGetter({
|
|
||||||
// key: STRING_KEYS.NET_PROFIT,
|
|
||||||
// }),
|
|
||||||
// [PnlSide.Loss]: stringGetter({
|
|
||||||
// key: STRING_KEYS.NET_LOSS,
|
|
||||||
// }),
|
|
||||||
// [PnlSide.Flat]: stringGetter({
|
|
||||||
// key: STRING_KEYS.NET_ZERO,
|
|
||||||
// }),
|
|
||||||
// }[tooltipDatum.side],
|
|
||||||
// value: (
|
|
||||||
// <Styled.SignedOutput
|
|
||||||
// type={OutputType.Fiat}
|
|
||||||
// value={tooltipDatum.equity}
|
|
||||||
// showSign={ShowSign.Both}
|
|
||||||
// side={tooltipDatum.side}
|
|
||||||
// />
|
|
||||||
// ),
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// key: 'totalPnl',
|
|
||||||
// label: stringGetter({ key: STRING_KEYS.TOTAL_VALUE }), // stringGetter({ key: STRING_KEYS.EQUITY }),
|
|
||||||
// value: <Output type={OutputType.Fiat} value={tooltipDatum.totalPnl} />,
|
|
||||||
// },
|
|
||||||
// ].filter(Boolean)}
|
|
||||||
// />
|
|
||||||
// </TooltipContent>
|
|
||||||
// );
|
|
||||||
// }}
|
|
||||||
renderTooltip={() => <div />}
|
renderTooltip={() => <div />}
|
||||||
onTooltipContext={onTooltipContext}
|
onTooltipContext={onTooltipContext}
|
||||||
onVisibleDataChange={onVisibleDataChange}
|
onVisibleDataChange={onVisibleDataChange}
|
||||||
@ -358,9 +247,9 @@ export const PnlChart = ({
|
|||||||
|
|
||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
Styled.Container = styled.div`
|
Styled.Container = styled.div<{ chartBackground: string }>`
|
||||||
position: relative;
|
position: relative;
|
||||||
background: url(${chartBackground}) no-repeat center center;
|
background: url(${({ chartBackground }) => chartBackground}) no-repeat center center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.PeriodToggle = styled.div`
|
Styled.PeriodToggle = styled.div`
|
||||||
|
|||||||
330
src/views/dialogs/DisplaySettingsDialog.tsx
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
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,
|
||||||
|
type AppThemeSetting,
|
||||||
|
AppThemeSystemSetting,
|
||||||
|
AppColorMode,
|
||||||
|
setAppThemeSetting,
|
||||||
|
setAppColorMode,
|
||||||
|
} from '@/state/configs';
|
||||||
|
import { getAppTheme, getAppThemeSetting, getAppColorMode } from '@/state/configsSelectors';
|
||||||
|
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
import { Themes } from '@/styles/themes';
|
||||||
|
|
||||||
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import { NumberSign } from '@/constants/numbers';
|
||||||
|
|
||||||
|
import { Dialog } from '@/components/Dialog';
|
||||||
|
import { DiffArrow } from '@/components/DiffArrow';
|
||||||
|
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 currentThemeSetting: AppThemeSetting = useSelector(getAppThemeSetting);
|
||||||
|
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={currentThemeSetting}>
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
themeSetting: AppTheme.Classic,
|
||||||
|
label: STRING_KEYS.CLASSIC_DARK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
themeSetting: AppThemeSystemSetting.System,
|
||||||
|
label: STRING_KEYS.SYSTEM,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
themeSetting: AppTheme.Dark,
|
||||||
|
label: STRING_KEYS.DARK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
themeSetting: AppTheme.Light,
|
||||||
|
label: STRING_KEYS.LIGHT,
|
||||||
|
},
|
||||||
|
].map(({ themeSetting, label }) => {
|
||||||
|
const theme = themeSetting === AppThemeSystemSetting.System ? currentTheme : themeSetting;
|
||||||
|
|
||||||
|
const backgroundColor = Themes[theme][currentColorMode].layer2;
|
||||||
|
const gridColor = Themes[theme][currentColorMode].borderDefault;
|
||||||
|
const textColor = Themes[theme][currentColorMode].textPrimary;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Styled.AppThemeItem
|
||||||
|
key={themeSetting}
|
||||||
|
value={themeSetting}
|
||||||
|
backgroundcolor={backgroundColor}
|
||||||
|
gridcolor={gridColor}
|
||||||
|
onClick={() => {
|
||||||
|
dispatch(setAppThemeSetting(themeSetting));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Styled.AppThemeHeader textcolor={textColor}>
|
||||||
|
{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.DiffArrowContainer>
|
||||||
|
<Styled.DiffArrow
|
||||||
|
direction="up"
|
||||||
|
sign={
|
||||||
|
colorMode === AppColorMode.GreenUp ? NumberSign.Positive : NumberSign.Negative
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Styled.DiffArrow
|
||||||
|
direction="down"
|
||||||
|
sign={
|
||||||
|
colorMode === AppColorMode.GreenUp ? NumberSign.Negative : NumberSign.Positive
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Styled.DiffArrowContainer>
|
||||||
|
{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.DiffArrowContainer = styled.div`
|
||||||
|
${layoutMixins.column}
|
||||||
|
gap: 0.5ch;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.DiffArrow = styled(DiffArrow)`
|
||||||
|
--diffArrow-color-positive: var(--color-success);
|
||||||
|
--diffArrow-color-negative: var(--color-error);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 0.75em;
|
||||||
|
height: 0.75em;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
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-button);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.CheckIcon = styled(Icon)`
|
||||||
|
width: var(--icon-size);
|
||||||
|
height: var(--icon-size);
|
||||||
|
`;
|
||||||
@ -189,7 +189,7 @@ Styled.WordList = styled.div<{ isShowing?: boolean }>`
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
filter: brightness(1.1);
|
filter: brightness(var(--hover-filter-base));
|
||||||
}
|
}
|
||||||
|
|
||||||
> :first-child {
|
> :first-child {
|
||||||
|
|||||||
@ -183,7 +183,7 @@ Styled.QrCodeContainer = styled.figure<{ isShowing: boolean }>`
|
|||||||
transition: 0.2s;
|
transition: 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
filter: brightness(1.1);
|
filter: brightness(var(--hover-filter-base));
|
||||||
}
|
}
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
|
|||||||
@ -323,7 +323,7 @@ Styled.ReceiptArea = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Green = styled.span`
|
Styled.Green = styled.span`
|
||||||
color: var(--color-positive);
|
color: var(--color-success);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.GreenCheckCircle = styled(GreenCheckCircle)`
|
Styled.GreenCheckCircle = styled(GreenCheckCircle)`
|
||||||
|
|||||||
@ -453,6 +453,6 @@ Styled.FormInputButton = styled(Button)`
|
|||||||
Styled.CheckIcon = styled(Icon)`
|
Styled.CheckIcon = styled(Icon)`
|
||||||
margin: 0 1ch;
|
margin: 0 1ch;
|
||||||
|
|
||||||
color: var(--color-positive);
|
color: var(--color-success);
|
||||||
font-size: 0.625rem;
|
font-size: 0.625rem;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -441,7 +441,7 @@ Styled.DestinationInputLabel = styled.span`
|
|||||||
${layoutMixins.inlineRow}
|
${layoutMixins.inlineRow}
|
||||||
|
|
||||||
svg {
|
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 { 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) && {
|
||||||
|
|||||||
@ -6,19 +6,19 @@ import { TradeLayouts } from '@/constants/layout';
|
|||||||
|
|
||||||
import { AssetIcon } from '@/components/AssetIcon';
|
import { AssetIcon } from '@/components/AssetIcon';
|
||||||
|
|
||||||
import { AppTheme, setAppTheme } from '@/state/configs';
|
import {
|
||||||
|
AppTheme,
|
||||||
|
AppThemeSystemSetting,
|
||||||
|
AppColorMode,
|
||||||
|
setAppThemeSetting,
|
||||||
|
setAppColorMode,
|
||||||
|
} from '@/state/configs';
|
||||||
import { setSelectedTradeLayout } from '@/state/layout';
|
import { setSelectedTradeLayout } from '@/state/layout';
|
||||||
|
|
||||||
import { getAssets } from '@/state/assetsSelectors';
|
import { getAssets } from '@/state/assetsSelectors';
|
||||||
import { getPerpetualMarkets } from '@/state/perpetualsSelectors';
|
import { getPerpetualMarkets } from '@/state/perpetualsSelectors';
|
||||||
import { Asset, PerpetualMarket } from '@/constants/abacus';
|
import { Asset, PerpetualMarket } from '@/constants/abacus';
|
||||||
|
|
||||||
enum ThemeItems {
|
|
||||||
SetClassicTheme = 'SetDefaultTheme',
|
|
||||||
SetLightTheme = 'SetLightTheme',
|
|
||||||
SetDarkTheme = 'SetDarkTheme',
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LayoutItems {
|
enum LayoutItems {
|
||||||
setDefaultLayout = 'SetDefaultLayout',
|
setDefaultLayout = 'SetDefaultLayout',
|
||||||
setReverseLayout = 'SetReverseLayout',
|
setReverseLayout = 'SetReverseLayout',
|
||||||
@ -53,24 +53,51 @@ export const useGlobalCommands = (): MenuConfig<string, string> => {
|
|||||||
groupLabel: 'Themes',
|
groupLabel: 'Themes',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
value: ThemeItems.SetClassicTheme,
|
value: AppTheme.Classic,
|
||||||
label: 'Set Classic Theme',
|
label: 'Set Classic Theme',
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
dispatch(setAppTheme(AppTheme.Classic));
|
dispatch(setAppThemeSetting(AppTheme.Classic));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: ThemeItems.SetLightTheme,
|
value: AppThemeSystemSetting.System,
|
||||||
|
label: 'Set System Theme',
|
||||||
|
onSelect: () => {
|
||||||
|
dispatch(setAppThemeSetting(AppThemeSystemSetting.System));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: AppTheme.Light,
|
||||||
label: 'Set Light Theme',
|
label: 'Set Light Theme',
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
dispatch(setAppTheme(AppTheme.Light));
|
dispatch(setAppThemeSetting(AppTheme.Light));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: ThemeItems.SetDarkTheme,
|
value: AppTheme.Dark,
|
||||||
label: 'Set Dark Theme',
|
label: 'Set Dark Theme',
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
dispatch(setAppTheme(AppTheme.Dark));
|
dispatch(setAppThemeSetting(AppTheme.Dark));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'colorPreferences',
|
||||||
|
groupLabel: 'Color Preferences',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
value: AppColorMode.GreenUp,
|
||||||
|
label: 'Set Green is Up',
|
||||||
|
onSelect: () => {
|
||||||
|
dispatch(setAppColorMode(AppColorMode.GreenUp));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: AppColorMode.RedUp,
|
||||||
|
label: 'Set Red is Up',
|
||||||
|
onSelect: () => {
|
||||||
|
dispatch(setAppColorMode(AppColorMode.RedUp));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@ -72,7 +72,7 @@ Styled.Notification = styled(Notification)`
|
|||||||
Styled.Output = styled(Output)`
|
Styled.Output = styled(Output)`
|
||||||
&:before {
|
&:before {
|
||||||
content: '+';
|
content: '+';
|
||||||
color: var(--color-positive);
|
color: var(--color-success);
|
||||||
margin-right: 0.5ch;
|
margin-right: 0.5ch;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -179,7 +179,7 @@ Styled.Icon = styled.div<{ state: 'complete' | 'default' }>`
|
|||||||
${({ state }) =>
|
${({ state }) =>
|
||||||
({
|
({
|
||||||
['complete']: css`
|
['complete']: css`
|
||||||
color: var(--color-positive);
|
color: var(--color-success);
|
||||||
`,
|
`,
|
||||||
['default']: css`
|
['default']: css`
|
||||||
color: var(--color-text-0);
|
color: var(--color-text-0);
|
||||||
|
|||||||
@ -82,6 +82,6 @@ Styled.ActionButton = styled(IconButton)`
|
|||||||
|
|
||||||
Styled.CancelButton = styled(Styled.ActionButton)`
|
Styled.CancelButton = styled(Styled.ActionButton)`
|
||||||
&:not(:disabled) {
|
&:not(:disabled) {
|
||||||
--button-textColor: var(--color-negative);
|
--button-textColor: var(--color-error);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||