diff --git a/.ladle/components.tsx b/.ladle/components.tsx
index 40cade6..04ee536 100644
--- a/.ladle/components.tsx
+++ b/.ladle/components.tsx
@@ -5,29 +5,35 @@ import styled from 'styled-components';
import { store } from '@/state/_store';
+import { GlobalStyle } from '@/styles/globalStyle';
+
import { SelectMenu, SelectItem } from '@/components/SelectMenu';
+import { AppThemeProvider } from '@/hooks/useAppTheme';
+
+import { AppTheme, setAppTheme } from '@/state/configs';
import { setLocaleLoaded } from '@/state/localization';
import '@/index.css';
import './ladle.css';
export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
- const [theme, setTheme] = useState('Default theme');
+ const [theme, setTheme] = useState(AppTheme.Classic);
useEffect(() => {
+ store.dispatch(setAppTheme(theme));
switch (theme) {
- case 'Dark theme': {
+ case AppTheme.Dark: {
document?.documentElement?.classList.remove('theme-light');
document?.documentElement?.classList.add('theme-dark');
break;
}
- case 'Light theme': {
+ case AppTheme.Light: {
document?.documentElement?.classList.remove('theme-dark');
document?.documentElement?.classList.add('theme-light');
break;
}
- default: {
+ case AppTheme.Classic: {
document?.documentElement?.classList.remove('theme-dark', 'theme-light');
break;
}
@@ -48,15 +54,15 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
>
{[
{
- value: 'Default theme',
+ value: AppTheme.Classic,
label: 'Default theme',
},
{
- value: 'Dark theme',
+ value: AppTheme.Dark,
label: 'Dark theme',
},
{
- value: 'Light theme',
+ value: AppTheme.Light,
label: 'Light theme',
},
].map(({ value, label }) => (
@@ -69,8 +75,11 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
- {children}
-
+
+
+ {children}
+
+
);
};
diff --git a/src/App.tsx b/src/App.tsx
index ae59c05..416b110 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -16,6 +16,7 @@ import {
} from '@/hooks';
import { DydxProvider } from '@/hooks/useDydxClient';
import { AccountsProvider } from '@/hooks/useAccounts';
+import { AppThemeProvider } from '@/hooks/useAppTheme';
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
import { LocaleProvider } from '@/hooks/useLocaleSeparators';
import { NotificationsProvider } from '@/hooks/useNotifications';
@@ -35,6 +36,7 @@ import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';
import { config } from '@/lib/wagmi';
import { breakpoints } from '@/styles';
+import { GlobalStyle } from '@/styles/globalStyle';
import { layoutMixins } from '@/styles/layoutMixins';
import { LoadingSpace } from './components/Loading/LoadingSpinner';
@@ -66,49 +68,52 @@ const Content = () => {
const { chainTokenLabel } = useTokenConfigs();
return (
-
- {isNotTablet && }
+ <>
+
+
+ {isNotTablet && }
-
- }>
-
-
- } />
- } />
-
+
+ }>
+
+
+ } />
+ } />
+
- } />
- } />
- {isTablet && (
- <>
- } />
- } />
- } />
- >
- )}
+ } />
+ } />
+ {isTablet && (
+ <>
+ } />
+ } />
+ } />
+ >
+ )}
- }>
- } />
-
+ }>
+ } />
+
- } />
- } />
+ } />
+ } />
- } />
-
-
-
+ } />
+
+
+
- {isTablet ? : }
+ {isTablet ? : }
-
+
-
-
-
+
+
+
-
-
+
+
+ >
);
};
@@ -131,6 +136,7 @@ const providers = [
wrapProvider(LocalNotificationsProvider),
wrapProvider(NotificationsProvider),
wrapProvider(DialogAreaProvider),
+ wrapProvider(AppThemeProvider),
];
const App = () => {
diff --git a/src/components/MarginUsageRing.tsx b/src/components/MarginUsageRing.tsx
index 51483f1..60c1e6b 100644
--- a/src/components/MarginUsageRing.tsx
+++ b/src/components/MarginUsageRing.tsx
@@ -1,11 +1,11 @@
import styled, { type AnyStyledComponent } from 'styled-components';
import { RiskLevels } from '@/constants/abacus';
-import { UsageColorFromRiskLevel } from '@/styles/colors';
import { Ring } from '@/components/Ring';
import { abacusHelper } from '@/lib/abacus';
+import { UsageColorFromRiskLevel } from '@/lib/styles';
type ElementProps = {
value: number;
diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx
index 103f933..cc8b149 100644
--- a/src/components/Switch.tsx
+++ b/src/components/Switch.tsx
@@ -47,7 +47,7 @@ Styled.Root = styled(Root)`
--switch-thumb-backgroundColor: var(--color-layer-6);
--switch-active-backgroundColor: var(--color-accent);
- --switch-active-thumb-backgroundColor: var(--color-white);
+ --switch-active-thumb-backgroundColor: ${({ theme }) => theme.switchThumbActiveBackground};
position: relative;
width: var(--switch-width);
diff --git a/src/components/UsageBars.tsx b/src/components/UsageBars.tsx
index 07322fb..3b77a17 100644
--- a/src/components/UsageBars.tsx
+++ b/src/components/UsageBars.tsx
@@ -2,9 +2,9 @@ import styled, { type AnyStyledComponent } from 'styled-components';
import { type RiskLevels } from '@/constants/abacus';
-import { UsageColorFromRiskLevel } from '@/styles/colors';
-
import { abacusHelper } from '@/lib/abacus';
+import { UsageColorFromRiskLevel } from '@/lib/styles';
+
type ElementProps = {
value: number;
};
diff --git a/src/components/WithTooltip.tsx b/src/components/WithTooltip.tsx
index 34b0f14..a817f3a 100644
--- a/src/components/WithTooltip.tsx
+++ b/src/components/WithTooltip.tsx
@@ -110,12 +110,7 @@ Styled.Abbr = styled.abbr`
Styled.Content = styled(Content)`
--tooltip-backgroundColor: var(--color-layer-4);
- --tooltip-backgroundColor: hsl(
- var(--layer-base-hue),
- var(--layer-base-saturation),
- calc(var(--layer-base-lightness) + 4%),
- 0.66
- );
+ --tooltip-backgroundColor: ${({ theme }) => theme.tooltipBackground};
${popoverMixins.popover}
--popover-backgroundColor: var(--tooltip-backgroundColor);
diff --git a/src/components/visx/TooltipContent.tsx b/src/components/visx/TooltipContent.tsx
index db3d108..7b594f1 100644
--- a/src/components/visx/TooltipContent.tsx
+++ b/src/components/visx/TooltipContent.tsx
@@ -27,12 +27,7 @@ Styled.TooltipContent = styled.aside<{ accentColor?: string }>`
${popoverMixins.popover}
--popover-radius: 0.5rem;
- --popover-background-color: hsl(
- var(--layer-base-hue),
- var(--layer-base-saturation),
- calc(var(--layer-base-lightness)),
- 0.9
- );
+ --popover-background-color: ${({ theme }) => theme.popoverBackground};
--popover-backdrop-filter: saturate(120%) blur(12px);
display: grid;
diff --git a/src/constants/styles/base.ts b/src/constants/styles/base.ts
new file mode 100644
index 0000000..8251ffa
--- /dev/null
+++ b/src/constants/styles/base.ts
@@ -0,0 +1,70 @@
+export enum ColorToken {
+ Black = '#000000',
+ White = '#FFFFFF',
+
+ LightGray0 = '#FAFAFA',
+ LightGray1 = '#F7F8FA',
+ LightGray2 = '#FAFAFD',
+ LightGray3 = '#F5F5F5',
+ LightGray4 = '#EDF0F2',
+ LightGray5 = '#EDEDED',
+ LightGray6 = '#E9ECEE',
+ LightGray7 = '#E6E6E6',
+ LightGray8 = '#DBDBDB',
+ LightGray9 = '#D5DADF',
+ LightGray10 = '#D1D9E0',
+
+ MediumGray0 = '#CACACE',
+ MediumGray1 = '#C2CBD3',
+
+ DarkGray0 = '#888891',
+ DarkGray1 = '#737373',
+ DarkGray2 = '#56565C',
+ DarkGray3 = '#4B4B4B',
+ DarkGray4 = '#494950',
+ DarkGray5 = '#3B3B3F',
+ DarkGray6 = '#303033',
+ DarkGray7 = '#313135',
+ DarkGray8 = '#292929',
+ DarkGray9 = '#23232F',
+ DarkGray10 = '#212124',
+ DarkGray11 = '#18181B',
+ DarkGray12 = '#181818',
+ DarkGray13 = '#0C0C0D',
+
+ GrayBlue0 = '#464659',
+ GrayBlue1 = '#38384D',
+ GrayBlue2 = '#303045',
+ GrayBlue3 = '#29293D',
+ GrayBlue4 = '#212131',
+ GrayBlue5 = '#181825',
+ GrayBlue6 = '#101018',
+ GrayBlue7 = '#08080C',
+
+ GrayPurple0 = '#DFDADF',
+ GrayPurple1 = '#C8C7D8',
+ GrayPurple2 = '#807E98',
+
+ Purple0 = '#7774FF',
+ Purple1 = '#6966FF',
+
+ Green0 = '#1AFFB9',
+ Green1 = '#3ED9A4',
+ Green2 = '#2CCC98',
+ Green3 = '#3EB68A',
+
+ Yellow0 = '#FFCC48',
+ Yellow1 = '#FFB647',
+
+ Red0 = '#FF5C5C',
+ Red1 = '#E76565',
+ Red2 = '#E45555',
+}
+
+/** Maps opacity to corresponding hex value */
+export enum OpacityToken {
+ Opacity16 = '29',
+ Opacity20 = '33',
+ Opacity66 = 'A8',
+ Opacity90 = 'E6',
+}
diff --git a/src/constants/styles/colors.ts b/src/constants/styles/colors.ts
new file mode 100644
index 0000000..a7c9eb1
--- /dev/null
+++ b/src/constants/styles/colors.ts
@@ -0,0 +1,77 @@
+export type ThemeColors = LayerColors &
+ BorderColors &
+ TextColors &
+ GradientColors &
+ AccentColors &
+ StatusColors &
+ DirectionalColors &
+ RiskColors &
+ IconColors &
+ ComponentColors;
+
+type LayerColors = {
+ layer0: string;
+ layer1: string;
+ layer2: string;
+ layer3: string;
+ layer4: string;
+ layer5: string;
+ layer6: string;
+ layer7: string;
+};
+
+type BorderColors = {
+ borderDefault: string;
+ borderDestructive: string;
+ borderButton: string;
+};
+
+type TextColors = {
+ textPrimary: string;
+ textSecondary: string;
+ textTertiary: string;
+};
+
+type GradientColors = {
+ gradientBase0: string;
+ gradientBase1: string;
+};
+
+type AccentColors = {
+ accent: string;
+ accentFaded: string;
+ favorite: string;
+};
+
+type StatusColors = {
+ success: string;
+ warning: string;
+ error: string;
+};
+
+type DirectionalColors = {
+ positive: string;
+ negative: string;
+ positiveFaded: string;
+ negativeFaded: string;
+};
+
+type RiskColors = {
+ riskLow: string;
+ riskMedium: string;
+ riskHigh: string;
+};
+
+type IconColors = {
+ logoFill: string;
+ profileYellow: string;
+ profileRed: string;
+};
+
+type ComponentColors = {
+ inputBackground: string;
+ popoverBackground: string;
+ switchThumbActiveBackground: string;
+ toggleBackground: string;
+ tooltipBackground: string;
+};
diff --git a/src/hooks/tradingView/useTradingViewTheme.ts b/src/hooks/tradingView/useTradingViewTheme.ts
index 302c54f..6436063 100644
--- a/src/hooks/tradingView/useTradingViewTheme.ts
+++ b/src/hooks/tradingView/useTradingViewTheme.ts
@@ -4,7 +4,6 @@ import { useSelector } from 'react-redux';
import type { IChartingLibraryWidget, ThemeName } from 'public/tradingview/charting_library';
import { AppTheme } from '@/state/configs';
-
import { getAppTheme } from '@/state/configsSelectors';
import { getWidgetOverrides } from '@/lib/tradingView/utils';
@@ -29,7 +28,7 @@ export const useTradingViewTheme = ({
tvWidget: (IChartingLibraryWidget & { _id?: string; _ready?: boolean }) | null;
isWidgetReady?: boolean;
}) => {
- const appTheme = useSelector(getAppTheme);
+ const appTheme: AppTheme = useSelector(getAppTheme);
useEffect(() => {
if (tvWidget && isWidgetReady) {
diff --git a/src/hooks/useAppTheme.tsx b/src/hooks/useAppTheme.tsx
new file mode 100644
index 0000000..790cc89
--- /dev/null
+++ b/src/hooks/useAppTheme.tsx
@@ -0,0 +1,16 @@
+import { useSelector } from 'react-redux';
+import { ThemeProvider } from 'styled-components';
+
+import { AppTheme } from '@/state/configs';
+import { getAppTheme } from '@/state/configsSelectors';
+
+import { Themes } from '@/styles/themes';
+
+export const AppThemeProvider = ({ ...props }) => {
+ return
+};
+
+export const useAppThemeContext = () => {
+ const theme: AppTheme = useSelector(getAppTheme);
+ return Themes[theme];
+}
diff --git a/src/icons/logo-short.tsx b/src/icons/logo-short.tsx
index c618ec4..81ffe2f 100644
--- a/src/icons/logo-short.tsx
+++ b/src/icons/logo-short.tsx
@@ -1,45 +1,52 @@
-const LogoShortIcon: React.FC<{ id?: string }> = ({ id }: { id?: string }) => (
-
-);
+import { useAppThemeContext } from '@/hooks/useAppTheme';
+
+const LogoShortIcon: React.FC<{ id?: string }> = ({ id }: { id?: string }) => {
+ const theme = useAppThemeContext();
+ const fill = theme.logoFill;
+
+ return (
+
+ );
+};
export default LogoShortIcon;
diff --git a/src/index.css b/src/index.css
index 869904f..fc5919b 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,6 +1,5 @@
@import 'styles/fonts.css';
@import 'styles/text.css';
-@import 'styles/colors.css';
@import 'styles/animations.css';
:root {
diff --git a/src/lib/styles.ts b/src/lib/styles.ts
new file mode 100644
index 0000000..ede2dd4
--- /dev/null
+++ b/src/lib/styles.ts
@@ -0,0 +1,20 @@
+import { css } from 'styled-components';
+
+import { type RiskLevels } from '@/constants/abacus';
+
+export const UsageColorFromRiskLevel = (riskLevel: RiskLevels) =>
+ ({
+ low: css`
+ color: var(--color-risk-low);
+ `,
+ medium: css`
+ color: var(--color-risk-medium);
+ `,
+ high: css`
+ color: var(--color-risk-high);
+ `,
+ }[riskLevel.name]);
+
+export const generateFadedColorVariant = (colorHex: string, opacityHex: string) => {
+ return `${colorHex}${opacityHex}`;
+};
diff --git a/src/lib/tradingView/utils.ts b/src/lib/tradingView/utils.ts
index b4e77ab..5a50209 100644
--- a/src/lib/tradingView/utils.ts
+++ b/src/lib/tradingView/utils.ts
@@ -1,11 +1,9 @@
-import Color from 'color';
-import isEmpty from 'lodash/isEmpty';
-
import { Candle, TradingViewBar, TradingViewSymbol } from '@/constants/candles';
-import { Colors } from '@/styles/colors';
import { AppTheme } from '@/state/configs';
+import { Themes } from '@/styles/themes';
+
export const mapCandle = ({
startedAt,
open,
@@ -49,42 +47,42 @@ export const getHistorySlice = ({
return bars.filter(({ time }) => time >= fromMs);
};
-export const getWidgetOverrides = (theme: AppTheme) => {
- const colors = Colors[theme];
+export const getWidgetOverrides = (appTheme: AppTheme) => {
+ const theme = Themes[appTheme];
return {
overrides: {
- 'paneProperties.background': Color(colors.layer2).hex(),
- 'paneProperties.horzGridProperties.color': Color(colors.layer3).hex(),
- 'paneProperties.vertGridProperties.color': Color(colors.layer3).hex(),
+ 'paneProperties.background': theme.layer2,
+ 'paneProperties.horzGridProperties.color': theme.layer3,
+ 'paneProperties.vertGridProperties.color': theme.layer3,
'paneProperties.crossHairProperties.style': 1,
'paneProperties.legendProperties.showBarChange': false,
'paneProperties.backgroundType': 'solid',
'mainSeriesProperties.style': 1,
- 'mainSeriesProperties.candleStyle.upColor': Color(colors.positive).hex(),
- 'mainSeriesProperties.candleStyle.borderUpColor': Color(colors.positive).hex(),
- 'mainSeriesProperties.candleStyle.wickUpColor': Color(colors.positive).hex(),
- 'mainSeriesProperties.candleStyle.downColor': Color(colors.negative).hex(),
- 'mainSeriesProperties.candleStyle.borderDownColor': Color(colors.negative).hex(),
- 'mainSeriesProperties.candleStyle.wickDownColor': Color(colors.negative).hex(),
+ 'mainSeriesProperties.candleStyle.upColor': theme.positive,
+ 'mainSeriesProperties.candleStyle.borderUpColor': theme.positive,
+ 'mainSeriesProperties.candleStyle.wickUpColor': theme.positive,
+ 'mainSeriesProperties.candleStyle.downColor': theme.negative,
+ 'mainSeriesProperties.candleStyle.borderDownColor': theme.negative,
+ 'mainSeriesProperties.candleStyle.wickDownColor': theme.negative,
'mainSeriesProperties.statusViewStyle.symbolTextSource': 'ticker',
- 'scalesProperties.textColor': Color(colors.text1).hex(),
- 'scalesProperties.backgroundColor': Color(colors.layer2).hex(),
- 'scalesProperties.lineColor': Color(colors.layer3).hex(),
+ 'scalesProperties.textColor': theme.textPrimary,
+ 'scalesProperties.backgroundColor': theme.layer2,
+ 'scalesProperties.lineColor': theme.layer3,
},
studies_overrides: {
- 'volume.volume.color.0': Color(colors.negative).hex(),
- 'volume.volume.color.1': Color(colors.positive).hex(),
+ 'volume.volume.color.0': theme.negative,
+ 'volume.volume.color.1': theme.positive,
'volume.volume ma.visible': false,
- 'relative strength index.plot.color': Color(colors.accent).hex(),
+ 'relative strength index.plot.color': theme.accent,
'relative strength index.plot.linewidth': 1.5,
'relative strength index.hlines background.color': '#134A9F',
},
loading_screen: {
- backgroundColor: Color(colors.layer2).hex(),
- foregroundColor: Color(colors.layer2).hex(),
+ backgroundColor: theme.layer2,
+ foregroundColor: theme.layer2,
},
};
};
diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx
index fc5703a..ff362bd 100644
--- a/src/pages/Profile.tsx
+++ b/src/pages/Profile.tsx
@@ -264,8 +264,8 @@ Styled.ProfileIcon = styled.div`
border-radius: 50%;
background: linear-gradient(
135deg,
- var(--theme-classic-color-yellow) 0%,
- var(--theme-classic-color-red) 100%
+ ${({ theme }) => theme.profileYellow} 0%,
+ ${({ theme }) => theme.profileRed} 100%
);
`;
diff --git a/src/styles/colors.css b/src/styles/colors.css
deleted file mode 100644
index d3a6812..0000000
--- a/src/styles/colors.css
+++ /dev/null
@@ -1,180 +0,0 @@
-:root {
- /* Parameters */
-
- /*
- --layer-base-hue
- --layer-base-saturation
- --layer-base-lightness
-
- --color-text-0
- --color-text-1
- --color-text-2
-
- --color-accent
- --color-positive
- --color-negative
- --color-success
- --color-warning
- --color-error
- --color-favorite
- */
-
- /* Computed: Layers */
-
- --color-layer-0: hsl(
- var(--layer-base-hue),
- var(--layer-base-saturation),
- calc(var(--layer-base-lightness) - 12%)
- );
-
- --color-layer-1: hsl(
- var(--layer-base-hue),
- var(--layer-base-saturation),
- calc(var(--layer-base-lightness) - 8%)
- );
-
- --color-layer-2: hsl(
- var(--layer-base-hue),
- var(--layer-base-saturation),
- calc(var(--layer-base-lightness) - 4%)
- );
-
- --color-layer-3: hsl(
- var(--layer-base-hue),
- var(--layer-base-saturation),
- var(--layer-base-lightness)
- );
-
- --color-layer-4: hsl(
- var(--layer-base-hue),
- var(--layer-base-saturation),
- calc(var(--layer-base-lightness) + 4%)
- );
-
- --color-layer-5: hsl(
- var(--layer-base-hue),
- calc(var(--layer-base-saturation) - 2%),
- calc(var(--layer-base-lightness) + 7%)
- );
-
- --color-layer-6: hsl(
- var(--layer-base-hue),
- calc(var(--layer-base-saturation) - 4%),
- calc(var(--layer-base-lightness) + 10%)
- );
-
- --color-layer-7: hsla(var(--layer-base-hue), 0%, 100%, 0.07);
-
- --color-gradient-base-0: hsl(
- var(--layer-base-hue),
- calc(var(--layer-base-saturation) - 5%),
- var(--layer-base-lightness)
- );
-
- --color-gradient-base-1: hsl(
- var(--layer-base-hue),
- calc(var(--layer-base-saturation) - 1%),
- calc(var(--layer-base-lightness) + 7%)
- );
-
- /* Computed: Borders */
-
- --color-border: var(--color-layer-5);
- --color-border-white: hsla(0, 0%, 100%, 0.2);
- --color-border-red: hsla(360, 73%, 61%, 0.2);
-}
-
-/* Theme: Classic (default) */
-:root {
- /* Constants */
-
- --theme-classic-hue-purple: 240;
- --theme-classic-color-green: hsl(159, 67%, 39%);
- --theme-classic-color-yellow: hsl(36, 100%, 64%);
- --theme-classic-color-red: hsl(360, 73%, 61%);
-
- /* Parameters */
-
- --layer-base-hue: var(--theme-classic-hue-purple);
- --layer-base-saturation: 20%;
- --layer-base-lightness: 16%;
-
- --color-text-0: hsl(245, 11%, 55%);
- --color-text-1: hsl(244, 18%, 81%);
- --color-text-2: hsl(240, 43%, 99%);
-
- --color-accent: hsl(var(--theme-classic-hue-purple), 100%, 70%);
- --color-positive: var(--theme-classic-color-green);
- --color-negative: var(--theme-classic-color-red);
- --color-success: var(--theme-classic-color-green);
- --color-warning: var(--theme-classic-color-yellow);
- --color-error: var(--theme-classic-color-red);
- --color-favorite: var(--theme-classic-color-yellow);
-
- --color-white: #fff;
- --color-black: #000;
-
- --color-gradient-positive: hsla(158, 49%, 48%, 0.16);
- --color-gradient-negative: hsla(0, 100%, 66%, 0.16);
- --color-accent-faded: hsla(var(--theme-classic-hue-purple), 100%, 70%, 0.16);
-
- --color-risk-low: var(--theme-classic-color-green);
- --color-risk-medium: var(--theme-classic-color-yellow);
- --color-risk-high: var(--theme-classic-color-red);
-}
-
-/* Theme: Light */
-:root.theme-light {
- /* Constants */
-
- --theme-light-hue-purple: 234;
- --theme-light-color-green: hsl(159, 67%, 39%);
- --theme-light-color-yellow: hsl(36, 100%, 64%);
- --theme-light-color-red: hsl(360, 73%, 61%);
-
- /* Parameters */
-
- --layer-base-hue: var(--theme-light-hue-purple);
- --layer-base-saturation: 0%;
- --layer-base-lightness: 86%;
-
- --color-text-0: hsl(0, 0%, 55%);
- --color-text-1: hsl(0, 0%, 40%);
- --color-text-2: hsl(0, 0%, 5%);
-
- --color-accent: hsl(var(--theme-light-hue-purple), 100%, 70%);
- --color-positive: var(--theme-light-color-green);
- --color-negative: var(--theme-light-color-red);
- --color-success: var(--theme-light-color-green);
- --color-warning: var(--theme-light-color-yellow);
- --color-error: var(--theme-light-color-red);
- --color-favorite: var(--theme-light-color-yellow);
-}
-
-/* Theme: Dark */
-:root.theme-dark {
- /* Constants */
-
- --theme-dark-hue-purple: 240;
- --theme-dark-color-green: hsl(159, 67%, 39%);
- --theme-dark-color-yellow: hsl(36, 100%, 64%);
- --theme-dark-color-red: hsl(360, 73%, 61%);
-
- /* Parameters */
-
- --layer-base-hue: 0;
- --layer-base-saturation: 0%;
- --layer-base-lightness: 16%;
-
- --color-text-0: hsl(0, 0%, 47%);
- --color-text-1: hsl(0, 0%, 67%);
- --color-text-2: hsl(0, 0%, 100%);
-
- --color-accent: hsl(var(--theme-dark-hue-purple), 100%, 70%);
- --color-positive: var(--theme-dark-color-green);
- --color-negative: var(--theme-dark-color-red);
- --color-success: var(--theme-dark-color-green);
- --color-warning: var(--theme-dark-color-yellow);
- --color-error: var(--theme-dark-color-red);
- --color-favorite: var(--theme-dark-color-yellow);
-}
diff --git a/src/styles/colors.ts b/src/styles/colors.ts
deleted file mode 100644
index 8d26d67..0000000
--- a/src/styles/colors.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-import { css } from 'styled-components';
-
-import { type RiskLevels } from '@/constants/abacus';
-
-import { AppTheme } from '@/state/configs';
-
-const BaseElements = {
- [AppTheme.Classic]: {
- hue: 240,
- saturation: 20,
- lightness: 16,
- },
- [AppTheme.Dark]: {
- hue: 0,
- saturation: 0,
- lightness: 16,
- },
- [AppTheme.Light]: {
- hue: 234,
- saturation: 0,
- lightness: 86,
- },
-};
-
-const LayerColors = ({ theme }: { theme: AppTheme }) => {
- const { hue, saturation, lightness } = BaseElements[theme];
-
- return {
- layer0: `hsl(${hue}, ${saturation}%, ${lightness - 12}%)`,
- layer1: `hsl(${hue}, ${saturation}%, ${lightness - 8}%)`,
- layer2: `hsl(${hue}, ${saturation}%, ${lightness - 4}%)`,
- layer3: `hsl(${hue}, ${saturation}%, ${lightness}%)`,
- layer4: `hsl(${hue}, ${saturation}%, ${lightness + 4}%)`,
- layer5: `hsl(${hue}, ${saturation - 2}%, ${lightness + 7}%)`,
- layer6: `hsl(${hue}, ${saturation - 4}%, ${lightness + 10}%)`,
- };
-};
-
-const AccentColor = ({ theme }: { theme: AppTheme }) => {
- const purpleHue = {
- Classic: 240,
- Dark: 240,
- Light: 234,
- }[theme];
-
- return {
- accent: `hsl(${purpleHue}, 100%, 70%)`,
- };
-};
-
-export const Colors = {
- [AppTheme.Classic]: {
- ...LayerColors({ theme: AppTheme.Classic }),
- text0: 'hsl(245, 11%, 55%)',
- text1: 'hsl(244, 18%, 81%)',
- text2: 'hsl(240, 43%, 99%)',
-
- ...AccentColor({ theme: AppTheme.Classic }),
- green: 'hsl(159, 67%, 39%)',
- yellow: 'hsl(36, 100%, 64%)',
- red: 'hsl(360, 73%, 61%)',
-
- positive: 'hsl(159, 67%, 39%)',
- negative: 'hsl(360, 73%, 61%)',
-
- success: 'hsl(159, 67%, 39%)',
- warning: 'hsl(36, 100%, 64%)',
- error: 'hsl(360, 73%, 61%)',
-
- favorite: 'hsl(36, 100%, 64%)',
- },
- [AppTheme.Dark]: {
- ...LayerColors({ theme: AppTheme.Dark }),
- text0: 'hsl(0, 0%, 47%)',
- text1: 'hsl(0, 0%, 67%)',
- text2: 'hsl(0, 0%, 100%)',
-
- ...AccentColor({ theme: AppTheme.Dark }),
- green: 'hsl(159, 67%, 39%)',
- yellow: 'hsl(36, 100%, 64%)',
- red: 'hsl(360, 73%, 61%)',
-
- positive: 'hsl(159, 67%, 39%)',
- negative: 'hsl(360, 73%, 61%)',
-
- success: 'hsl(159, 67%, 39%)',
- warning: 'hsl(36, 100%, 64%)',
- error: 'hsl(360, 73%, 61%)',
-
- favorite: 'hsl(36, 100%, 64%)',
- },
- [AppTheme.Light]: {
- ...LayerColors({ theme: AppTheme.Light }),
- text0: 'hsl(0, 0%, 55%)',
- text1: 'hsl(0, 0%, 40%)',
- text2: 'hsl(0, 0%, 5%)',
-
- ...AccentColor({ theme: AppTheme.Light }),
- green: 'hsl(159, 67%, 39%)',
- yellow: 'hsl(36, 100%, 64%)',
- red: 'hsl(360, 73%, 61%)',
-
- positive: 'hsl(159, 67%, 39%)',
- negative: 'hsl(360, 73%, 61%)',
-
- success: 'hsl(159, 67%, 39%)',
- warning: 'hsl(36, 100%, 64%)',
- error: 'hsl(360, 73%, 61%)',
-
- favorite: 'hsl(36, 100%, 64%)',
- },
-};
-
-export const UsageColorFromRiskLevel = (riskLevel: RiskLevels) =>
- ({
- low: css`
- color: var(--color-risk-low);
- `,
- medium: css`
- color: var(--color-risk-medium);
- `,
- high: css`
- color: var(--color-risk-high);
- `,
- }[riskLevel.name]);
diff --git a/src/styles/formMixins.ts b/src/styles/formMixins.ts
index 3345b14..d709bef 100644
--- a/src/styles/formMixins.ts
+++ b/src/styles/formMixins.ts
@@ -21,7 +21,7 @@ export const formMixins: Record<
--input-radius: 0.5em;
--input-height: var(--form-input-height);
--input-width: 100%;
- --input-backgroundColor: var(--color-layer-4);
+ --input-backgroundColor: ${({ theme }) => theme.inputBackground};
--input-borderColor: var(--color-layer-6);
${layoutMixins.row}
diff --git a/src/styles/globalStyle.ts b/src/styles/globalStyle.ts
new file mode 100644
index 0000000..bf534cd
--- /dev/null
+++ b/src/styles/globalStyle.ts
@@ -0,0 +1,42 @@
+import { createGlobalStyle } from 'styled-components';
+
+export const GlobalStyle = createGlobalStyle`
+ :root {
+ --color-layer-0: ${({ theme }) => theme.layer0};
+ --color-layer-1: ${({ theme }) => theme.layer1};
+ --color-layer-2: ${({ theme }) => theme.layer2};
+ --color-layer-3: ${({ theme }) => theme.layer3};
+ --color-layer-4: ${({ theme }) => theme.layer4};
+ --color-layer-5: ${({ theme }) => theme.layer5};
+ --color-layer-6: ${({ theme }) => theme.layer6};
+ --color-layer-7: ${({ theme }) => theme.layer7};
+
+ --color-border: ${({ theme }) => theme.borderDefault};
+ --color-border-white: ${({ theme }) => theme.borderButton};
+ --color-border-red: ${({ theme }) => theme.borderDestructive};
+
+ --color-text-0: ${({ theme }) => theme.textTertiary};
+ --color-text-1: ${({ theme }) => theme.textSecondary};
+ --color-text-2: ${({ theme }) => theme.textPrimary};
+
+ --color-gradient-base-0: ${({ theme }) => theme.gradientBase0};
+ --color-gradient-base-1: ${({ theme }) => theme.gradientBase1};
+
+ --color-accent: ${({ theme }) => theme.accent};
+ --color-accent-faded: ${({ theme }) => theme.accentFaded};
+ --color-favorite: ${({ theme }) => theme.favorite};
+
+ --color-success: ${({ theme }) => theme.success};
+ --color-warning: ${({ theme }) => theme.warning};
+ --color-error: ${({ theme }) => theme.error};
+
+ --color-positive: ${({ theme }) => theme.positive};
+ --color-negative: ${({ theme }) => theme.negative};
+ --color-gradient-positive: ${({ theme }) => theme.positiveFaded};
+ --color-gradient-negative: ${({ theme }) => theme.negativeFaded};
+
+ --color-risk-low: ${({ theme }) => theme.riskLow};
+ --color-risk-medium: ${({ theme }) => theme.riskMedium};
+ --color-risk-high: ${({ theme }) => theme.riskHigh};
+ }
+`;
diff --git a/src/styles/themes.ts b/src/styles/themes.ts
new file mode 100644
index 0000000..ec96986
--- /dev/null
+++ b/src/styles/themes.ts
@@ -0,0 +1,157 @@
+import { AppTheme } from '@/state/configs';
+import { ThemeColors } from '@/constants/styles/colors';
+import { ColorToken, OpacityToken } from '@/constants/styles/base';
+import { generateFadedColorVariant } from '@/lib/styles';
+
+const ClassicTheme: ThemeColors = {
+ layer0: ColorToken.GrayBlue7,
+ layer1: ColorToken.GrayBlue6,
+ layer2: ColorToken.GrayBlue5,
+ layer3: ColorToken.GrayBlue4,
+ layer4: ColorToken.GrayBlue3,
+ layer5: ColorToken.GrayBlue2,
+ layer6: ColorToken.GrayBlue1,
+ layer7: ColorToken.GrayBlue0,
+
+ borderDefault: ColorToken.GrayBlue2,
+ borderDestructive: generateFadedColorVariant(ColorToken.Red2, OpacityToken.Opacity20),
+ borderButton: generateFadedColorVariant(ColorToken.White, OpacityToken.Opacity20),
+
+ textPrimary: ColorToken.LightGray2,
+ textSecondary: ColorToken.GrayPurple1,
+ textTertiary: ColorToken.GrayPurple2,
+
+ gradientBase0: ColorToken.DarkGray9,
+ gradientBase1: ColorToken.GrayBlue2,
+
+ accent: ColorToken.Purple1,
+ accentFaded: generateFadedColorVariant(ColorToken.Purple1, OpacityToken.Opacity16),
+ favorite: ColorToken.Yellow0,
+
+ success: ColorToken.Green1,
+ warning: ColorToken.Yellow0,
+ error: ColorToken.Red2,
+
+ positive: ColorToken.Green1,
+ negative: ColorToken.Red2,
+ positiveFaded: generateFadedColorVariant(ColorToken.Green1, OpacityToken.Opacity16),
+ negativeFaded: generateFadedColorVariant(ColorToken.Red2, OpacityToken.Opacity16),
+
+ riskLow: ColorToken.Green1,
+ riskMedium: ColorToken.Yellow0,
+ riskHigh: ColorToken.Red2,
+
+ logoFill: ColorToken.White,
+ profileYellow: ColorToken.Yellow1,
+ profileRed: ColorToken.Red2,
+
+ inputBackground: ColorToken.GrayBlue3,
+ popoverBackground: generateFadedColorVariant(ColorToken.GrayBlue4, OpacityToken.Opacity90),
+ switchThumbActiveBackground: ColorToken.White,
+ toggleBackground: ColorToken.GrayBlue3,
+ tooltipBackground: generateFadedColorVariant(ColorToken.GrayBlue3, OpacityToken.Opacity66),
+};
+
+const DarkTheme: ThemeColors = {
+ layer0: ColorToken.Black,
+ layer1: ColorToken.DarkGray11,
+ layer2: ColorToken.DarkGray13,
+ layer3: ColorToken.DarkGray10,
+ layer4: ColorToken.DarkGray6,
+ layer5: ColorToken.DarkGray5,
+ layer6: ColorToken.DarkGray4,
+ layer7: ColorToken.DarkGray2,
+
+ borderDefault: ColorToken.DarkGray4,
+ borderDestructive: generateFadedColorVariant(ColorToken.Red0, OpacityToken.Opacity20),
+ borderButton: generateFadedColorVariant(ColorToken.White, OpacityToken.Opacity20),
+
+ textPrimary: ColorToken.LightGray0,
+ textSecondary: ColorToken.MediumGray0,
+ textTertiary: ColorToken.DarkGray0,
+
+ gradientBase0: ColorToken.DarkGray8,
+ gradientBase1: ColorToken.DarkGray5,
+
+ accent: ColorToken.Purple0,
+ accentFaded: generateFadedColorVariant(ColorToken.Purple0, OpacityToken.Opacity16),
+ favorite: ColorToken.Yellow0,
+
+ success: ColorToken.Green0,
+ warning: ColorToken.Yellow0,
+ error: ColorToken.Red0,
+
+ positive: ColorToken.Green0,
+ negative: ColorToken.Red0,
+ positiveFaded: generateFadedColorVariant(ColorToken.Green0, OpacityToken.Opacity16),
+ negativeFaded: generateFadedColorVariant(ColorToken.Red0, OpacityToken.Opacity16),
+
+ riskLow: ColorToken.Green0,
+ riskMedium: ColorToken.Yellow0,
+ riskHigh: ColorToken.Red0,
+
+ logoFill: ColorToken.White,
+ profileYellow: ColorToken.Yellow1,
+ profileRed: ColorToken.Red2,
+
+ inputBackground: ColorToken.DarkGray6,
+ popoverBackground: generateFadedColorVariant(ColorToken.DarkGray8, OpacityToken.Opacity90),
+ switchThumbActiveBackground: ColorToken.White,
+ toggleBackground: ColorToken.DarkGray6,
+ tooltipBackground: generateFadedColorVariant(ColorToken.DarkGray6, OpacityToken.Opacity66),
+};
+
+const LightTheme: ThemeColors = {
+ layer0: ColorToken.White,
+ layer1: ColorToken.LightGray6,
+ layer2: ColorToken.White,
+ layer3: ColorToken.LightGray1,
+ layer4: ColorToken.White,
+ layer5: ColorToken.LightGray4,
+ layer6: ColorToken.LightGray9,
+ layer7: ColorToken.MediumGray1,
+
+ borderDefault: ColorToken.LightGray10,
+ borderDestructive: generateFadedColorVariant(ColorToken.Red1, OpacityToken.Opacity20),
+ borderButton: generateFadedColorVariant(ColorToken.Black, OpacityToken.Opacity20),
+
+ textPrimary: ColorToken.DarkGray12,
+ textSecondary: ColorToken.DarkGray3,
+ textTertiary: ColorToken.DarkGray1,
+
+ gradientBase0: ColorToken.LightGray8,
+ gradientBase1: ColorToken.LightGray5,
+
+ accent: ColorToken.Purple0,
+ accentFaded: generateFadedColorVariant(ColorToken.Purple0, OpacityToken.Opacity16),
+ favorite: ColorToken.Yellow0,
+
+ success: ColorToken.Green2,
+ warning: ColorToken.Yellow0,
+ error: ColorToken.Red1,
+
+ positive: ColorToken.Green2,
+ negative: ColorToken.Red1,
+ positiveFaded: generateFadedColorVariant(ColorToken.Green2, OpacityToken.Opacity16),
+ negativeFaded: generateFadedColorVariant(ColorToken.Red1, OpacityToken.Opacity16),
+
+ riskLow: ColorToken.Green2,
+ riskMedium: ColorToken.Yellow0,
+ riskHigh: ColorToken.Red1,
+
+ logoFill: ColorToken.Black,
+ profileYellow: ColorToken.Yellow1,
+ profileRed: ColorToken.Red2,
+
+ inputBackground: ColorToken.White,
+ popoverBackground: generateFadedColorVariant(ColorToken.LightGray8, OpacityToken.Opacity90),
+ switchThumbActiveBackground: ColorToken.White,
+ toggleBackground: ColorToken.LightGray4,
+ tooltipBackground: generateFadedColorVariant(ColorToken.LightGray7, OpacityToken.Opacity66),
+};
+
+export const Themes = {
+ [AppTheme.Classic]: ClassicTheme,
+ [AppTheme.Dark]: DarkTheme,
+ [AppTheme.Light]: LightTheme,
+};
diff --git a/src/views/forms/TradeForm/TradeSideToggle.tsx b/src/views/forms/TradeForm/TradeSideToggle.tsx
index ab269e3..8af0c6a 100644
--- a/src/views/forms/TradeForm/TradeSideToggle.tsx
+++ b/src/views/forms/TradeForm/TradeSideToggle.tsx
@@ -44,6 +44,7 @@ export const TradeSideToggle = memo(() => {
const ToggleContainer = styled(ToggleGroup)<{ value: OrderSide }>`
--toggle-radius: 0.5em;
--toggle-color: var(--color-negative);
+ --toggle-background: ${({ theme }) => theme.toggleBackground};
${({ value }) =>
value === OrderSide.BUY &&
@@ -52,7 +53,7 @@ const ToggleContainer = styled(ToggleGroup)<{ value: OrderSide }>`
`}
border-radius: var(--toggle-radius);
- background-color: var(--color-layer-4);
+ background-color: var(--toggle-background);
position: relative;
> button {