Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a3e0ac618 | ||
|
|
707db7b111 | ||
|
|
8c759997d1 | ||
|
|
f762e9bfac | ||
|
|
ed3c336cc0 | ||
|
|
b4f9f03bdc | ||
|
|
44ed52d5e2 | ||
|
|
42595a3667 | ||
|
|
2fc55bbe9f | ||
|
|
97452d7785 | ||
|
|
2704baf378 | ||
|
|
453d7c545e | ||
|
|
f79c062808 | ||
|
|
7d30c80320 | ||
|
|
1c1d602bf3 | ||
|
|
23a96c1c20 | ||
|
|
d81e6b3a2c | ||
|
|
732114a8de | ||
|
|
2c220233e3 | ||
|
|
8187e3615b | ||
|
|
c5888c2d5c | ||
|
|
793b522487 | ||
|
|
13d6610492 | ||
|
|
9cbb9fc2c6 | ||
|
|
91f5b89eb6 | ||
|
|
41cc531700 |
@@ -8,6 +8,7 @@ VITE_V3_TOKEN_ADDRESS=
|
|||||||
VITE_TOKEN_MIGRATION_URI=
|
VITE_TOKEN_MIGRATION_URI=
|
||||||
|
|
||||||
AMPLITUDE_API_KEY=
|
AMPLITUDE_API_KEY=
|
||||||
|
AMPLITUDE_SERVER_URL=
|
||||||
BUGSNAG_API_KEY=
|
BUGSNAG_API_KEY=
|
||||||
IOS_APP_ID=
|
IOS_APP_ID=
|
||||||
INTERCOM_APP_ID=
|
INTERCOM_APP_ID=
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ Set environment variables via `.env`.
|
|||||||
- `VITE_V3_TOKEN_ADDRESS` (optional): Address of the V3 $DYDX token.
|
- `VITE_V3_TOKEN_ADDRESS` (optional): Address of the V3 $DYDX token.
|
||||||
- `VITE_TOKEN_MIGRATION_URI` (optional): The URL of the token migration website.
|
- `VITE_TOKEN_MIGRATION_URI` (optional): The URL of the token migration website.
|
||||||
- `AMPLITUDE_API_KEY` (optional): Amplitude API key for enabling Amplitude; used with `pnpm run build:inject-amplitude`.
|
- `AMPLITUDE_API_KEY` (optional): Amplitude API key for enabling Amplitude; used with `pnpm run build:inject-amplitude`.
|
||||||
|
- `AMPLITUDE_SERVER_URL` (optional): Custom Amplitude server URL
|
||||||
- `BUGSNAG_API_KEY` (optional): API key for enabling Bugsnag; used with `pnpm run build:inject-bugsnag`.
|
- `BUGSNAG_API_KEY` (optional): API key for enabling Bugsnag; used with `pnpm run build:inject-bugsnag`.
|
||||||
- `IOS_APP_ID` (optional): iOS app ID used for enabling deep linking to the iOS app; used with `pnpm run build:inject-app-deeplinks`.
|
- `IOS_APP_ID` (optional): iOS app ID used for enabling deep linking to the iOS app; used with `pnpm run build:inject-app-deeplinks`.
|
||||||
- `INTERCOM_APP_ID` (optional): Used for enabling Intercom; utilized with `pnpm run build:inject-intercom`.
|
- `INTERCOM_APP_ID` (optional): Used for enabling Intercom; utilized with `pnpm run build:inject-intercom`.
|
||||||
|
|||||||
@@ -39,9 +39,9 @@
|
|||||||
"@cosmjs/proto-signing": "^0.32.1",
|
"@cosmjs/proto-signing": "^0.32.1",
|
||||||
"@cosmjs/stargate": "^0.32.1",
|
"@cosmjs/stargate": "^0.32.1",
|
||||||
"@cosmjs/tendermint-rpc": "^0.32.1",
|
"@cosmjs/tendermint-rpc": "^0.32.1",
|
||||||
"@dydxprotocol/v4-abacus": "^1.3.2",
|
"@dydxprotocol/v4-abacus": "^1.4.2",
|
||||||
"@dydxprotocol/v4-client-js": "^1.0.17",
|
"@dydxprotocol/v4-client-js": "^1.0.20",
|
||||||
"@dydxprotocol/v4-localization": "^1.1.17",
|
"@dydxprotocol/v4-localization": "^1.1.22",
|
||||||
"@ethersproject/providers": "^5.7.2",
|
"@ethersproject/providers": "^5.7.2",
|
||||||
"@js-joda/core": "^5.5.3",
|
"@js-joda/core": "^5.5.3",
|
||||||
"@radix-ui/react-accordion": "^1.1.2",
|
"@radix-ui/react-accordion": "^1.1.2",
|
||||||
@@ -92,6 +92,7 @@
|
|||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"cmdk": "^0.2.0",
|
"cmdk": "^0.2.0",
|
||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
|
"cosmjs-types": "^0.9.0",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"ethers": "^6.6.1",
|
"ethers": "^6.6.1",
|
||||||
"graz": "^0.0.43",
|
"graz": "^0.0.43",
|
||||||
@@ -155,5 +156,10 @@
|
|||||||
"vitest": "^0.32.2",
|
"vitest": "^0.32.2",
|
||||||
"w3name": "^1.0.8",
|
"w3name": "^1.0.8",
|
||||||
"web3.storage": "^4.5.4"
|
"web3.storage": "^4.5.4"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"overrides": {
|
||||||
|
"follow-redirects": "1.15.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
lockfileVersion: '6.0'
|
lockfileVersion: '6.0'
|
||||||
|
|
||||||
settings:
|
overrides:
|
||||||
autoInstallPeers: true
|
follow-redirects: 1.15.3
|
||||||
excludeLinksFromLockfile: false
|
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@0xsquid/sdk':
|
'@0xsquid/sdk':
|
||||||
@@ -27,14 +26,14 @@ dependencies:
|
|||||||
specifier: ^0.32.1
|
specifier: ^0.32.1
|
||||||
version: 0.32.2
|
version: 0.32.2
|
||||||
'@dydxprotocol/v4-abacus':
|
'@dydxprotocol/v4-abacus':
|
||||||
specifier: ^1.3.2
|
specifier: ^1.4.2
|
||||||
version: 1.3.2
|
version: 1.4.2
|
||||||
'@dydxprotocol/v4-client-js':
|
'@dydxprotocol/v4-client-js':
|
||||||
specifier: ^1.0.17
|
specifier: ^1.0.20
|
||||||
version: 1.0.17
|
version: 1.0.20
|
||||||
'@dydxprotocol/v4-localization':
|
'@dydxprotocol/v4-localization':
|
||||||
specifier: ^1.1.17
|
specifier: ^1.1.22
|
||||||
version: 1.1.17
|
version: 1.1.22
|
||||||
'@ethersproject/providers':
|
'@ethersproject/providers':
|
||||||
specifier: ^5.7.2
|
specifier: ^5.7.2
|
||||||
version: 5.7.2
|
version: 5.7.2
|
||||||
@@ -185,6 +184,9 @@ dependencies:
|
|||||||
color:
|
color:
|
||||||
specifier: ^4.2.3
|
specifier: ^4.2.3
|
||||||
version: 4.2.3
|
version: 4.2.3
|
||||||
|
cosmjs-types:
|
||||||
|
specifier: ^0.9.0
|
||||||
|
version: 0.9.0
|
||||||
crypto-js:
|
crypto-js:
|
||||||
specifier: ^4.1.1
|
specifier: ^4.1.1
|
||||||
version: 4.1.1
|
version: 4.1.1
|
||||||
@@ -1086,12 +1088,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
|
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@dydxprotocol/v4-abacus@1.3.2:
|
/@dydxprotocol/v4-abacus@1.4.2:
|
||||||
resolution: {integrity: sha512-zo0IHjGMlJRKOYDgNqNFQ9GtBJKJP4+Y9YY7V0X3Wt61ppKAYzodaYQhc9V/RYchcZTtS/xkicLug444YrvehQ==}
|
resolution: {integrity: sha512-+hugk0RulMwMthR2xCMYXohcC3sEYqVW/lmiq0RUuHZ9yrjmgy48xl0aZUmXGUYXyoiHXPS4AULhRKHQ4OOLwg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-client-js@1.0.17:
|
/@dydxprotocol/v4-client-js@1.0.20:
|
||||||
resolution: {integrity: sha512-PbTKbzcS7VapuFRofkirUxkF9ThNS2tWYyr0asFOMUfebsQWMvTC1sYC/s1NZIiBeq3cFz9vKdZFbfsKi7Z1bw==}
|
resolution: {integrity: sha512-dXKW2NC1XlVVIRKvHWVDofLZSCPTJAaRY5eXzxH5CcXpnl2kdXorr7ykqWZxW0jHFPWWvRSJtUDqZN1qFrEe/w==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cosmjs/amino': 0.32.2
|
'@cosmjs/amino': 0.32.2
|
||||||
'@cosmjs/encoding': 0.32.2
|
'@cosmjs/encoding': 0.32.2
|
||||||
@@ -1100,7 +1102,7 @@ packages:
|
|||||||
'@cosmjs/stargate': 0.32.2
|
'@cosmjs/stargate': 0.32.2
|
||||||
'@cosmjs/tendermint-rpc': 0.32.2
|
'@cosmjs/tendermint-rpc': 0.32.2
|
||||||
'@cosmjs/utils': 0.32.2
|
'@cosmjs/utils': 0.32.2
|
||||||
'@dydxprotocol/v4-proto': 3.0.0-dev.0
|
'@dydxprotocol/v4-proto': 4.0.0-dev.0
|
||||||
'@osmonauts/lcd': 0.6.0
|
'@osmonauts/lcd': 0.6.0
|
||||||
'@scure/bip32': 1.3.2
|
'@scure/bip32': 1.3.2
|
||||||
'@scure/bip39': 1.2.1
|
'@scure/bip39': 1.2.1
|
||||||
@@ -1119,12 +1121,12 @@ packages:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-localization@1.1.17:
|
/@dydxprotocol/v4-localization@1.1.22:
|
||||||
resolution: {integrity: sha512-kal1LrcihLMEv5YxaA/hd6Zl10Mp3x6jicoXDcXvtyNdrczAl3YapyI2nmeifRAPvfueOaY3W/sKkm2BiSKSsA==}
|
resolution: {integrity: sha512-DURyvBx0qjXmtebSRMW4ZdTsX5xI8Mb6c7LQ8WUPU0O3Jr7n7iUT/phzZszTpwNOMFFMukMFtn7fHCgijw1TOg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-proto@3.0.0-dev.0:
|
/@dydxprotocol/v4-proto@4.0.0-dev.0:
|
||||||
resolution: {integrity: sha512-hT6F/AgaTqv8Bwo7twpIhmjXvJE/Fx+3mmHHTuIXMeL6OhVtlOpcEQyHvBEAdh1VrNq/S7qWvdQD0fvC/UgKyA==}
|
resolution: {integrity: sha512-PC/xq5YJIisAd3jjIULJGrnujbrYkr5h4ehepnLc6U34nJT720iumKVMiPaezwRC+kHKTI1culpKNnlMnbeYBA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
protobufjs: 6.11.4
|
protobufjs: 6.11.4
|
||||||
dev: false
|
dev: false
|
||||||
@@ -7476,7 +7478,7 @@ packages:
|
|||||||
/axios@0.21.4:
|
/axios@0.21.4:
|
||||||
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.5
|
follow-redirects: 1.15.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
dev: false
|
dev: false
|
||||||
@@ -7484,7 +7486,7 @@ packages:
|
|||||||
/axios@0.27.2:
|
/axios@0.27.2:
|
||||||
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
|
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.2
|
follow-redirects: 1.15.3
|
||||||
form-data: 4.0.0
|
form-data: 4.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
@@ -7493,7 +7495,7 @@ packages:
|
|||||||
/axios@1.1.3:
|
/axios@1.1.3:
|
||||||
resolution: {integrity: sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==}
|
resolution: {integrity: sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.5
|
follow-redirects: 1.15.3
|
||||||
form-data: 4.0.0
|
form-data: 4.0.0
|
||||||
proxy-from-env: 1.1.0
|
proxy-from-env: 1.1.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -7503,7 +7505,7 @@ packages:
|
|||||||
/axios@1.6.5:
|
/axios@1.6.5:
|
||||||
resolution: {integrity: sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==}
|
resolution: {integrity: sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.5
|
follow-redirects: 1.15.3
|
||||||
form-data: 4.0.0
|
form-data: 4.0.0
|
||||||
proxy-from-env: 1.1.0
|
proxy-from-env: 1.1.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -9526,18 +9528,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
|
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/follow-redirects@1.15.2:
|
/follow-redirects@1.15.3:
|
||||||
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
|
resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==}
|
||||||
engines: {node: '>=4.0'}
|
|
||||||
peerDependencies:
|
|
||||||
debug: '*'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
debug:
|
|
||||||
optional: true
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/follow-redirects@1.15.5:
|
|
||||||
resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==}
|
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
debug: '*'
|
debug: '*'
|
||||||
@@ -14920,3 +14912,7 @@ packages:
|
|||||||
/zwitch@2.0.4:
|
/zwitch@2.0.4:
|
||||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||||
|
"target": {
|
||||||
|
"namespace": "android_app",
|
||||||
|
"package_name": "exchange.dydx.trading.debug",
|
||||||
|
"sha256_cert_fingerprints": [
|
||||||
|
"8A:9C:CC:49:B0:35:9A:91:67:CB:98:B0:B5:87:92:5F:9E:B7:EF:CE:A0:47:57:85:A4:35:3E:0C:E1:56:9E:A2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||||
|
"target": {
|
||||||
|
"namespace": "android_app",
|
||||||
|
"package_name": "exchange.dydx.trading",
|
||||||
|
"sha256_cert_fingerprints": [
|
||||||
|
"B2:2D:CC:27:9D:52:05:98:63:C9:7B:34:36:70:A3:8E:00:31:28:08:2D:2E:70:76:C9:31:AE:F9:55:21:15:A5"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
Before Width: | Height: | Size: 122 KiB |
@@ -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 |
@@ -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 |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 2.1 MiB |
@@ -11,6 +11,13 @@
|
|||||||
],
|
],
|
||||||
"default": "dydxprotocol-mainnet"
|
"default": "dydxprotocol-mainnet"
|
||||||
},
|
},
|
||||||
|
"TESTFLIGHT": {
|
||||||
|
"environments": [
|
||||||
|
"dydxprotocol-mainnet",
|
||||||
|
"dydxprotocol-testnet"
|
||||||
|
],
|
||||||
|
"default": "dydxprotocol-mainnet"
|
||||||
|
},
|
||||||
"TESTNET": {
|
"TESTNET": {
|
||||||
"environments": [
|
"environments": [
|
||||||
"dydxprotocol-testnet"
|
"dydxprotocol-testnet"
|
||||||
@@ -81,7 +88,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"documentation": "https://docs.dydx.exchange/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
@@ -109,6 +115,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX Chain"
|
"signTypedDataDomainName": "dYdX Chain"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-dev-2": {
|
"dydxprotocol-dev-2": {
|
||||||
@@ -154,7 +170,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"documentation": "https://docs.dydx.exchange/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
@@ -182,6 +197,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX Chain"
|
"signTypedDataDomainName": "dYdX Chain"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-dev-4": {
|
"dydxprotocol-dev-4": {
|
||||||
@@ -228,7 +253,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"documentation": "https://docs.dydx.exchange/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
@@ -256,6 +280,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX Chain"
|
"signTypedDataDomainName": "dYdX Chain"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-dev-5": {
|
"dydxprotocol-dev-5": {
|
||||||
@@ -301,7 +335,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"documentation": "https://docs.dydx.exchange/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
@@ -329,6 +362,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX Chain"
|
"signTypedDataDomainName": "dYdX Chain"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-staging": {
|
"dydxprotocol-staging": {
|
||||||
@@ -378,7 +421,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"help": "https://help.dydx.exchange",
|
"help": "https://help.dydx.exchange",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"governanceLearnMore": "https://help.dydx.exchange",
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
@@ -404,6 +446,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX Chain"
|
"signTypedDataDomainName": "dYdX Chain"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-staging-forced-update": {
|
"dydxprotocol-staging-forced-update": {
|
||||||
@@ -477,6 +529,16 @@
|
|||||||
"build": 40000,
|
"build": 40000,
|
||||||
"url": "https://apps.apple.com/app/dydx/id1564787350"
|
"url": "https://apps.apple.com/app/dydx/id1564787350"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-staging-west": {
|
"dydxprotocol-staging-west": {
|
||||||
@@ -526,7 +588,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"help": "https://help.dydx.exchange",
|
"help": "https://help.dydx.exchange",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"governanceLearnMore": "https://help.dydx.exchange",
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
@@ -552,6 +613,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX Chain"
|
"signTypedDataDomainName": "dYdX Chain"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-testnet": {
|
"dydxprotocol-testnet": {
|
||||||
@@ -605,7 +676,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"governanceLearnMore": "https://help.dydx.exchange",
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
@@ -631,6 +701,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX V4"
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-testnet-dydx": {
|
"dydxprotocol-testnet-dydx": {
|
||||||
@@ -681,7 +761,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"governanceLearnMore": "https://help.dydx.exchange",
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
@@ -707,6 +786,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX V4"
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-testnet-nodefleet": {
|
"dydxprotocol-testnet-nodefleet": {
|
||||||
@@ -757,7 +846,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"governanceLearnMore": "https://help.dydx.exchange",
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
@@ -783,6 +871,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX V4"
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-testnet-kingnodes": {
|
"dydxprotocol-testnet-kingnodes": {
|
||||||
@@ -833,7 +931,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"governanceLearnMore": "https://help.dydx.exchange",
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
@@ -859,6 +956,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX V4"
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-testnet-liquify": {
|
"dydxprotocol-testnet-liquify": {
|
||||||
@@ -909,7 +1016,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"governanceLearnMore": "https://help.dydx.exchange",
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
@@ -935,6 +1041,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX V4"
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-testnet-polkachu": {
|
"dydxprotocol-testnet-polkachu": {
|
||||||
@@ -1002,6 +1118,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX V4"
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-testnet-bware": {
|
"dydxprotocol-testnet-bware": {
|
||||||
@@ -1052,7 +1178,6 @@
|
|||||||
"blogs": "https://www.dydx.foundation/blog",
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
"foundation": "https://www.dydx.foundation",
|
"foundation": "https://www.dydx.foundation",
|
||||||
"help": "https://help.dydx.exchange/",
|
"help": "https://help.dydx.exchange/",
|
||||||
"initialMarginFractionLearnmore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
|
||||||
"reduceOnlyLearnmore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
"reduceOnlyLearnmore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"governanceLearnmore": "https://help.dydx.exchange",
|
"governanceLearnmore": "https://help.dydx.exchange",
|
||||||
@@ -1078,6 +1203,16 @@
|
|||||||
"images": "/wallets/",
|
"images": "/wallets/",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX V4"
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 10000000,
|
||||||
|
"delayBlocks": 900,
|
||||||
|
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dydxprotocol-mainnet": {
|
"dydxprotocol-mainnet": {
|
||||||
@@ -1126,7 +1261,6 @@
|
|||||||
"feedback": "[HTTP link to feedback form, can be null]",
|
"feedback": "[HTTP link to feedback form, can be null]",
|
||||||
"blogs": "[HTTP link to blogs, can be null]",
|
"blogs": "[HTTP link to blogs, can be null]",
|
||||||
"foundation": "[HTTP link to foundation, can be null]",
|
"foundation": "[HTTP link to foundation, can be null]",
|
||||||
"initialMarginFractionLearnMore": "[HTTP link to initial margin fraction learn more, can be null]",
|
|
||||||
"reduceOnlyLearnMore": "[HTTP link to reduce-only learn more, can be null]",
|
"reduceOnlyLearnMore": "[HTTP link to reduce-only learn more, can be null]",
|
||||||
"documentation": "[HTTP link to documentation, can be null]",
|
"documentation": "[HTTP link to documentation, can be null]",
|
||||||
"community": "[HTTP link to community, can be null]",
|
"community": "[HTTP link to community, can be null]",
|
||||||
@@ -1154,6 +1288,16 @@
|
|||||||
"images": "[Relative URL for wallet images]",
|
"images": "[Relative URL for wallet images]",
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
"signTypedDataDomainName": "dYdX Chain"
|
"signTypedDataDomainName": "dYdX Chain"
|
||||||
|
},
|
||||||
|
"governance": {
|
||||||
|
"newMarketProposal": {
|
||||||
|
"initialDepositAmount": 0,
|
||||||
|
"delayBlocks": 0,
|
||||||
|
"newMarketsMethodology": "[URL to spreadsheet or document that explains methodology]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"reduceOnlySupported": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,13 @@
|
|||||||
"whitepaperLink": "https://bitcoincash.org/",
|
"whitepaperLink": "https://bitcoincash.org/",
|
||||||
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bitcoin-cash/"
|
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bitcoin-cash/"
|
||||||
},
|
},
|
||||||
|
"BONK-USD": {
|
||||||
|
"name": "BONK COIN",
|
||||||
|
"tags": [],
|
||||||
|
"websiteLink": "https://bonkcoin.com/",
|
||||||
|
"whitepaperLink": "https://bonkcoin.com/",
|
||||||
|
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bonk1/"
|
||||||
|
},
|
||||||
"BLUR-USD": {
|
"BLUR-USD": {
|
||||||
"name": "Blur",
|
"name": "Blur",
|
||||||
"tags": [],
|
"tags": [],
|
||||||
|
|||||||
|
After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
@@ -3,12 +3,13 @@ import path from 'path';
|
|||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
const AMPLITUDE_API_KEY = process.env.AMPLITUDE_API_KEY;
|
const AMPLITUDE_API_KEY = process.env.AMPLITUDE_API_KEY;
|
||||||
|
const AMPLITUDE_SERVER_URL = process.env.AMPLITUDE_SERVER_URL;
|
||||||
|
|
||||||
const currentPath = fileURLToPath(import.meta.url);
|
const currentPath = fileURLToPath(import.meta.url);
|
||||||
const projectRoot = path.dirname(currentPath);
|
const projectRoot = path.dirname(currentPath);
|
||||||
const htmlFilePath = path.resolve(projectRoot, '../dist/index.html');
|
const htmlFilePath = path.resolve(projectRoot, '../dist/index.html');
|
||||||
|
|
||||||
if(AMPLITUDE_API_KEY){
|
if (AMPLITUDE_API_KEY) {
|
||||||
try {
|
try {
|
||||||
const html = await fs.readFile(htmlFilePath, 'utf-8');
|
const html = await fs.readFile(htmlFilePath, 'utf-8');
|
||||||
|
|
||||||
@@ -18,8 +19,34 @@ if(AMPLITUDE_API_KEY){
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const amplitudeListenerScript = `<script type="module">
|
const amplitudeListenerScript = `<script type="module">
|
||||||
!function(){var e="${AMPLITUDE_API_KEY}";e&&(globalThis.amplitude.init(e),globalThis.amplitude.setOptOut(!1),globalThis.addEventListener("dydx:track",function(e){var t=e.detail.eventType,d=e.detail.eventData;globalThis.amplitude.track(t,d)}),globalThis.addEventListener("dydx:identify",function(e){var t=e.detail.property,d=e.detail.propertyValue;if("walletAddress"===t)globalThis.amplitude.setUserId(d);else{var i=new globalThis.amplitude.Identify;i.set(t,d),globalThis.amplitude.identify(i)}}),console.log("Amplitude enabled."))}();
|
!(function () {
|
||||||
</script>`;
|
var e = "${AMPLITUDE_API_KEY}";
|
||||||
|
e &&
|
||||||
|
(globalThis.amplitude.init(e${
|
||||||
|
AMPLITUDE_SERVER_URL
|
||||||
|
? `, undefined, {
|
||||||
|
serverUrl: "${AMPLITUDE_SERVER_URL}"
|
||||||
|
}`
|
||||||
|
: ''
|
||||||
|
}),
|
||||||
|
globalThis.amplitude.setOptOut(!1),
|
||||||
|
globalThis.addEventListener("dydx:track", function (e) {
|
||||||
|
var t = e.detail.eventType,
|
||||||
|
d = e.detail.eventData;
|
||||||
|
globalThis.amplitude.track(t, d);
|
||||||
|
}),
|
||||||
|
globalThis.addEventListener("dydx:identify", function (e) {
|
||||||
|
var t = e.detail.property,
|
||||||
|
d = e.detail.propertyValue;
|
||||||
|
if ("walletAddress" === t) globalThis.amplitude.setUserId(d);
|
||||||
|
else {
|
||||||
|
var i = new globalThis.amplitude.Identify();
|
||||||
|
i.set(t, d), globalThis.amplitude.identify(i);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
console.log("Amplitude enabled."));
|
||||||
|
})();
|
||||||
|
</script>`;
|
||||||
|
|
||||||
const injectedHtml = html.replace(
|
const injectedHtml = html.replace(
|
||||||
'<div id="root"></div>',
|
'<div id="root"></div>',
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { WagmiConfig } from 'wagmi';
|
|||||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
import { GrazProvider } from 'graz';
|
import { GrazProvider } from 'graz';
|
||||||
|
|
||||||
import { AppRoute, DEFAULT_TRADE_ROUTE } from '@/constants/routes';
|
import { AppRoute, DEFAULT_TRADE_ROUTE, MarketsRoute } from '@/constants/routes';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useBreakpoints,
|
useBreakpoints,
|
||||||
@@ -16,11 +16,12 @@ 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';
|
||||||
import { LocalNotificationsProvider } from '@/hooks/useLocalNotifications';
|
import { LocalNotificationsProvider } from '@/hooks/useLocalNotifications';
|
||||||
|
import { PotentialMarketsProvider } from '@/hooks/usePotentialMarkets';
|
||||||
import { RestrictionProvider } from '@/hooks/useRestrictions';
|
import { RestrictionProvider } from '@/hooks/useRestrictions';
|
||||||
import { SubaccountProvider } from '@/hooks/useSubaccount';
|
import { SubaccountProvider } from '@/hooks/useSubaccount';
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ import '@/styles/constants.css';
|
|||||||
import '@/styles/fonts.css';
|
import '@/styles/fonts.css';
|
||||||
import '@/styles/web3modal.css';
|
import '@/styles/web3modal.css';
|
||||||
|
|
||||||
|
const NewMarket = lazy(() => import('@/pages/markets/NewMarket'));
|
||||||
const MarketsPage = lazy(() => import('@/pages/markets/Markets'));
|
const MarketsPage = lazy(() => import('@/pages/markets/Markets'));
|
||||||
const PortfolioPage = lazy(() => import('@/pages/portfolio/Portfolio'));
|
const PortfolioPage = lazy(() => import('@/pages/portfolio/Portfolio'));
|
||||||
const AlertsPage = lazy(() => import('@/pages/AlertsPage'));
|
const AlertsPage = lazy(() => import('@/pages/AlertsPage'));
|
||||||
@@ -81,7 +83,10 @@ const Content = () => {
|
|||||||
<Route path={AppRoute.Trade} element={<TradePage />} />
|
<Route path={AppRoute.Trade} element={<TradePage />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path={AppRoute.Markets} element={<MarketsPage />} />
|
<Route path={AppRoute.Markets}>
|
||||||
|
<Route path={MarketsRoute.New} element={<NewMarket />} />
|
||||||
|
<Route path={AppRoute.Markets} element={<MarketsPage />} />
|
||||||
|
</Route>
|
||||||
<Route path={`/${chainTokenLabel}`} element={<RewardsPage />} />
|
<Route path={`/${chainTokenLabel}`} element={<RewardsPage />} />
|
||||||
{isTablet && (
|
{isTablet && (
|
||||||
<>
|
<>
|
||||||
@@ -136,7 +141,8 @@ const providers = [
|
|||||||
wrapProvider(LocalNotificationsProvider),
|
wrapProvider(LocalNotificationsProvider),
|
||||||
wrapProvider(NotificationsProvider),
|
wrapProvider(NotificationsProvider),
|
||||||
wrapProvider(DialogAreaProvider),
|
wrapProvider(DialogAreaProvider),
|
||||||
wrapProvider(AppThemeProvider),
|
wrapProvider(PotentialMarketsProvider),
|
||||||
|
wrapProvider(AppThemeAndColorModeProvider),
|
||||||
];
|
];
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const assetIcons = {
|
|||||||
AVAX: '/currencies/avax.png',
|
AVAX: '/currencies/avax.png',
|
||||||
BCH: '/currencies/bch.png',
|
BCH: '/currencies/bch.png',
|
||||||
BLUR: '/currencies/blur.png',
|
BLUR: '/currencies/blur.png',
|
||||||
|
BONK: '/currencies/bonk.png',
|
||||||
BTC: '/currencies/btc.png',
|
BTC: '/currencies/btc.png',
|
||||||
CELO: '/currencies/celo.png',
|
CELO: '/currencies/celo.png',
|
||||||
COMP: '/currencies/comp.png',
|
COMP: '/currencies/comp.png',
|
||||||
|
|||||||
@@ -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));
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,15 +24,25 @@ export const Checkbox: React.FC<CheckboxProps> = ({
|
|||||||
onCheckedChange,
|
onCheckedChange,
|
||||||
id,
|
id,
|
||||||
label,
|
label,
|
||||||
disabled
|
disabled,
|
||||||
}) => (
|
}) => (
|
||||||
<Styled.Container>
|
<Styled.Container>
|
||||||
<Styled.Root className={className} checked={checked} disabled={disabled} onCheckedChange={onCheckedChange} id={id}>
|
<Styled.Root
|
||||||
|
className={className}
|
||||||
|
checked={checked}
|
||||||
|
disabled={disabled}
|
||||||
|
onCheckedChange={onCheckedChange}
|
||||||
|
id={id}
|
||||||
|
>
|
||||||
<Styled.Indicator>
|
<Styled.Indicator>
|
||||||
<CheckIcon />
|
<CheckIcon />
|
||||||
</Styled.Indicator>
|
</Styled.Indicator>
|
||||||
</Styled.Root>
|
</Styled.Root>
|
||||||
{label && <Styled.label disabled={disabled} htmlFor={id}>{label}</Styled.label>}
|
{label && (
|
||||||
|
<Styled.Label disabled={disabled} htmlFor={id}>
|
||||||
|
{label}
|
||||||
|
</Styled.Label>
|
||||||
|
)}
|
||||||
</Styled.Container>
|
</Styled.Container>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -42,10 +52,6 @@ Styled.Container = styled.div`
|
|||||||
${layoutMixins.row}
|
${layoutMixins.row}
|
||||||
gap: 1ch;
|
gap: 1ch;
|
||||||
font: var(--font-small-book);
|
font: var(--font-small-book);
|
||||||
|
|
||||||
label {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Root = styled(Root)`
|
Styled.Root = styled(Root)`
|
||||||
@@ -74,13 +80,17 @@ 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.div<{ disabled: boolean; }>`
|
Styled.Label = styled.label<{ disabled?: boolean }>`
|
||||||
|
cursor: pointer;
|
||||||
color: var(--color-text-2);
|
color: var(--color-text-2);
|
||||||
|
|
||||||
${({disabled}) => disabled && css`
|
${({ disabled }) =>
|
||||||
color: var(--color-text-0);
|
disabled &&
|
||||||
`}
|
css`
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: var(--color-text-0);
|
||||||
|
`}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -50,10 +50,11 @@ export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extend
|
|||||||
label={title}
|
label={title}
|
||||||
// value={highlightedCommand}
|
// value={highlightedCommand}
|
||||||
// onValueChange={setHighlightedCommand}
|
// onValueChange={setHighlightedCommand}
|
||||||
filter={(value: string, search: string) => {
|
filter={(value: string, search: string) =>
|
||||||
if (value.replace(/ /g, '').includes(search.replace(/ /g, ''))) return 1;
|
value.replace(/ /g, '').toLowerCase().includes(search.replace(/ /g, '').toLowerCase())
|
||||||
return 0;
|
? 1
|
||||||
}}
|
: 0
|
||||||
|
}
|
||||||
className={className}
|
className={className}
|
||||||
$withStickyLayout={withStickyLayout}
|
$withStickyLayout={withStickyLayout}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -6,29 +6,34 @@ import { StoryWrapper } from '.ladle/components';
|
|||||||
|
|
||||||
export const DropdownMenuStory: Story<Parameters<typeof DropdownMenu>> = (args) => {
|
export const DropdownMenuStory: Story<Parameters<typeof DropdownMenu>> = (args) => {
|
||||||
const exampleItems = [
|
const exampleItems = [
|
||||||
|
{
|
||||||
|
value: '0',
|
||||||
|
label: 'Item 0',
|
||||||
|
onSelect: () => alert('Item 0 action'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: '1',
|
value: '1',
|
||||||
label: 'Item 1',
|
label: 'Item 1 (accent)',
|
||||||
onSelect: () => alert('Item 1 action'),
|
onSelect: () => alert('Item 1 action'),
|
||||||
|
highlightColor: 'accent',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: '2',
|
value: '2',
|
||||||
label: 'Item 2',
|
label: 'Item 2 (create)',
|
||||||
onSelect: () => alert('Item 2 action'),
|
onSelect: () => alert('Item 2 action'),
|
||||||
|
highlightColor: 'create',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: '3',
|
value: '3',
|
||||||
label: 'Item 3',
|
label: 'Item 3 (destroy)',
|
||||||
onSelect: () => alert('Item 3 action'),
|
onSelect: () => alert('Item 3 action'),
|
||||||
|
highlightColor: 'destroy',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StoryWrapper>
|
<StoryWrapper>
|
||||||
<DropdownMenu
|
<DropdownMenu {...args} items={exampleItems}>
|
||||||
{...args}
|
|
||||||
items={exampleItems}
|
|
||||||
>
|
|
||||||
<span>Menu</span>
|
<span>Menu</span>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</StoryWrapper>
|
</StoryWrapper>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export type DropdownMenuItem<T> = {
|
|||||||
label: React.ReactNode;
|
label: React.ReactNode;
|
||||||
onSelect?: () => void;
|
onSelect?: () => void;
|
||||||
separator?: boolean;
|
separator?: boolean;
|
||||||
highlightColor?: 'accent' | 'positive' | 'negative';
|
highlightColor?: 'accent' | 'create' | 'destroy';
|
||||||
};
|
};
|
||||||
|
|
||||||
type StyleProps = {
|
type StyleProps = {
|
||||||
@@ -82,7 +82,7 @@ Styled.Separator = styled(Separator)`
|
|||||||
margin: 0.25rem 1rem;
|
margin: 0.25rem 1rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Item = styled(Item)<{ $highlightColor: 'accent' | 'positive' | 'negative' }>`
|
Styled.Item = styled(Item)<{ $highlightColor: 'accent' | 'create' | 'destroy' }>`
|
||||||
${popoverMixins.item}
|
${popoverMixins.item}
|
||||||
--item-font-size: var(--dropdownMenu-item-font-size);
|
--item-font-size: var(--dropdownMenu-item-font-size);
|
||||||
${({ $highlightColor }) =>
|
${({ $highlightColor }) =>
|
||||||
@@ -90,11 +90,11 @@ Styled.Item = styled(Item)<{ $highlightColor: 'accent' | 'positive' | 'negative'
|
|||||||
['accent']: `
|
['accent']: `
|
||||||
--item-highlighted-textColor: var(--color-accent);
|
--item-highlighted-textColor: var(--color-accent);
|
||||||
`,
|
`,
|
||||||
['positive']: `
|
['create']: `
|
||||||
--item-highlighted-textColor: var(--color-positive);
|
--item-highlighted-textColor: var(--color-success);
|
||||||
`,
|
`,
|
||||||
['negative']: `
|
['destroy']: `
|
||||||
--item-highlighted-textColor: var(--color-negative);
|
--item-highlighted-textColor: var(--color-error);
|
||||||
`,
|
`,
|
||||||
}[$highlightColor])}
|
}[$highlightColor])}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const FormInput = forwardRef<HTMLInputElement, FormInputProps>(
|
|||||||
isValidationAttached={validationConfig?.attached}
|
isValidationAttached={validationConfig?.attached}
|
||||||
>
|
>
|
||||||
<Styled.InputContainer hasSlotRight={!!slotRight}>
|
<Styled.InputContainer hasSlotRight={!!slotRight}>
|
||||||
<Styled.WithLabel label={label} inputID={id}>
|
<Styled.WithLabel label={label} inputID={id} disabled={otherProps?.disabled}>
|
||||||
<Input ref={ref} id={id} {...otherProps} />
|
<Input ref={ref} id={id} {...otherProps} />
|
||||||
</Styled.WithLabel>
|
</Styled.WithLabel>
|
||||||
{slotRight}
|
{slotRight}
|
||||||
@@ -85,11 +85,11 @@ Styled.InputContainer = styled.div<{ hasSlotRight?: boolean }>`
|
|||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.WithLabel = styled(WithLabel)`
|
Styled.WithLabel = styled(WithLabel)<{ disabled?: boolean }>`
|
||||||
${formMixins.inputLabel}
|
${formMixins.inputLabel}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
cursor: text;
|
${({ disabled }) => !disabled && 'cursor: text;'}
|
||||||
padding: var(--form-input-paddingY) var(--form-input-paddingX) 0;
|
padding: var(--form-input-paddingY) var(--form-input-paddingX) 0;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export const LoadingSpinner: React.FC<{
|
|||||||
return (
|
return (
|
||||||
<Styled.Spinner className={className}>
|
<Styled.Spinner className={className}>
|
||||||
<Styled.LoadingSpinnerSvg
|
<Styled.LoadingSpinnerSvg
|
||||||
|
id={id}
|
||||||
width="38"
|
width="38"
|
||||||
height="38"
|
height="38"
|
||||||
viewBox="0 0 38 38"
|
viewBox="0 0 38 38"
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ type ElementProps = {
|
|||||||
resolution?: number;
|
resolution?: number;
|
||||||
stripRelativeWords?: boolean;
|
stripRelativeWords?: boolean;
|
||||||
};
|
};
|
||||||
|
timeOptions?: {
|
||||||
|
useUTC?: boolean;
|
||||||
|
};
|
||||||
tag?: React.ReactNode;
|
tag?: React.ReactNode;
|
||||||
withParentheses?: boolean;
|
withParentheses?: boolean;
|
||||||
locale?: string;
|
locale?: string;
|
||||||
@@ -89,6 +92,7 @@ export const Output = ({
|
|||||||
relativeTimeFormatOptions = {
|
relativeTimeFormatOptions = {
|
||||||
format: 'singleCharacter',
|
format: 'singleCharacter',
|
||||||
},
|
},
|
||||||
|
timeOptions,
|
||||||
tag,
|
tag,
|
||||||
withParentheses,
|
withParentheses,
|
||||||
locale = navigator.language || 'en-US',
|
locale = navigator.language || 'en-US',
|
||||||
@@ -116,6 +120,7 @@ export const Output = ({
|
|||||||
{value?.toString() ?? null}
|
{value?.toString() ?? null}
|
||||||
|
|
||||||
{tag && <Tag>{tag}</Tag>}
|
{tag && <Tag>{tag}</Tag>}
|
||||||
|
{slotRight}
|
||||||
</Styled.Text>
|
</Styled.Text>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -165,16 +170,21 @@ export const Output = ({
|
|||||||
if ((typeof value !== 'string' && typeof value !== 'number') || !value) return null;
|
if ((typeof value !== 'string' && typeof value !== 'number') || !value) return null;
|
||||||
const date = new Date(value);
|
const date = new Date(value);
|
||||||
const dateString = {
|
const dateString = {
|
||||||
[OutputType.Date]: date.toLocaleString(selectedLocale, { dateStyle: 'medium' }),
|
[OutputType.Date]: date.toLocaleString(selectedLocale, {
|
||||||
|
dateStyle: 'medium',
|
||||||
|
timeZone: timeOptions?.useUTC ? 'UTC' : undefined,
|
||||||
|
}),
|
||||||
[OutputType.DateTime]: date.toLocaleString(selectedLocale, {
|
[OutputType.DateTime]: date.toLocaleString(selectedLocale, {
|
||||||
dateStyle: 'short',
|
dateStyle: 'short',
|
||||||
timeStyle: 'short',
|
timeStyle: 'short',
|
||||||
|
timeZone: timeOptions?.useUTC ? 'UTC' : undefined,
|
||||||
}),
|
}),
|
||||||
[OutputType.Time]: date.toLocaleString(selectedLocale, {
|
[OutputType.Time]: date.toLocaleString(selectedLocale, {
|
||||||
hour12: false,
|
hour12: false,
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
second: '2-digit',
|
second: '2-digit',
|
||||||
|
timeZone: timeOptions?.useUTC ? 'UTC' : undefined,
|
||||||
}),
|
}),
|
||||||
}[type];
|
}[type];
|
||||||
|
|
||||||
|
|||||||
@@ -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 ? (
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export type TableItem<TableRowData> = {
|
|||||||
onSelect?: (key: TableRowData) => void;
|
onSelect?: (key: TableRowData) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ColumnDef<TableRowData extends object> = {
|
export type ColumnDef<TableRowData extends object> = {
|
||||||
columnKey: string;
|
columnKey: string;
|
||||||
label: React.ReactNode;
|
label: React.ReactNode;
|
||||||
tag?: React.ReactNode;
|
tag?: React.ReactNode;
|
||||||
@@ -95,7 +95,10 @@ export type ElementProps<TableRowData extends object | CustomRowConfig, TableRow
|
|||||||
selectionBehavior?: 'replace' | 'toggle';
|
selectionBehavior?: 'replace' | 'toggle';
|
||||||
onRowAction?: (key: TableRowKey, row: TableRowData) => void;
|
onRowAction?: (key: TableRowKey, row: TableRowData) => void;
|
||||||
slotEmpty?: React.ReactNode;
|
slotEmpty?: React.ReactNode;
|
||||||
initialNumRowsToShow?: number;
|
viewMoreConfig?: {
|
||||||
|
initialNumRowsToShow: number;
|
||||||
|
numRowsPerPage?: number;
|
||||||
|
};
|
||||||
// collection: TableCollection<string>;
|
// collection: TableCollection<string>;
|
||||||
// children: React.ReactNode;
|
// children: React.ReactNode;
|
||||||
};
|
};
|
||||||
@@ -125,7 +128,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
|||||||
selectionMode = 'single',
|
selectionMode = 'single',
|
||||||
selectionBehavior = 'toggle',
|
selectionBehavior = 'toggle',
|
||||||
slotEmpty,
|
slotEmpty,
|
||||||
initialNumRowsToShow,
|
viewMoreConfig,
|
||||||
// shouldRowRender,
|
// shouldRowRender,
|
||||||
|
|
||||||
// collection,
|
// collection,
|
||||||
@@ -141,8 +144,18 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
|||||||
style,
|
style,
|
||||||
}: ElementProps<TableRowData, TableRowKey> & StyleProps) => {
|
}: ElementProps<TableRowData, TableRowKey> & StyleProps) => {
|
||||||
const [selectedKeys, setSelectedKeys] = useState(new Set<TableRowKey>());
|
const [selectedKeys, setSelectedKeys] = useState(new Set<TableRowKey>());
|
||||||
const [numRowsToShow, setNumRowsToShow] = useState(initialNumRowsToShow);
|
const [numRowsToShow, setNumRowsToShow] = useState(viewMoreConfig?.initialNumRowsToShow);
|
||||||
const enableViewMore = numRowsToShow !== undefined;
|
const enableViewMore = viewMoreConfig !== undefined;
|
||||||
|
|
||||||
|
const onViewMoreClick = () => {
|
||||||
|
if (!viewMoreConfig) return;
|
||||||
|
const { numRowsPerPage } = viewMoreConfig;
|
||||||
|
if (numRowsPerPage) {
|
||||||
|
setNumRowsToShow((prev) => (prev ?? 0) + numRowsPerPage);
|
||||||
|
} else {
|
||||||
|
setNumRowsToShow(data.length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const currentBreakpoints = useBreakpoints();
|
const currentBreakpoints = useBreakpoints();
|
||||||
const shownColumns = columns.filter(
|
const shownColumns = columns.filter(
|
||||||
@@ -218,9 +231,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
|||||||
}
|
}
|
||||||
numColumns={shownColumns.length}
|
numColumns={shownColumns.length}
|
||||||
onViewMoreClick={
|
onViewMoreClick={
|
||||||
enableViewMore && numRowsToShow < data.length
|
enableViewMore && numRowsToShow! < data.length ? onViewMoreClick : undefined
|
||||||
? () => setNumRowsToShow(data.length)
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
// shouldRowRender={shouldRowRender}
|
// shouldRowRender={shouldRowRender}
|
||||||
hideHeader={hideHeader}
|
hideHeader={hideHeader}
|
||||||
@@ -513,7 +524,7 @@ const TableColumnHeader = <TableRowData extends object>({
|
|||||||
export const ViewMoreRow = ({ colSpan, onClick }: { colSpan: number; onClick: () => void }) => {
|
export const ViewMoreRow = ({ colSpan, onClick }: { colSpan: number; onClick: () => void }) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
return (
|
return (
|
||||||
<Styled.Tr key="viewmore">
|
<Styled.ViewMoreTr key="viewmore">
|
||||||
<Styled.Td
|
<Styled.Td
|
||||||
colSpan={colSpan}
|
colSpan={colSpan}
|
||||||
onMouseDown={(e: MouseEvent) => e.preventDefault()}
|
onMouseDown={(e: MouseEvent) => e.preventDefault()}
|
||||||
@@ -523,7 +534,7 @@ export const ViewMoreRow = ({ colSpan, onClick }: { colSpan: number; onClick: ()
|
|||||||
{stringGetter({ key: STRING_KEYS.VIEW_MORE })}
|
{stringGetter({ key: STRING_KEYS.VIEW_MORE })}
|
||||||
</Styled.ViewMoreButton>
|
</Styled.ViewMoreButton>
|
||||||
</Styled.Td>
|
</Styled.Td>
|
||||||
</Styled.Tr>
|
</Styled.ViewMoreTr>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -673,6 +684,8 @@ Styled.TableWrapper = styled.div<{
|
|||||||
--table-lastColumn-cell-align: end; // start | center | end | var(--table-cell-align)
|
--table-lastColumn-cell-align: end; // start | center | end | var(--table-cell-align)
|
||||||
--tableCell-padding: 0 1rem;
|
--tableCell-padding: 0 1rem;
|
||||||
|
|
||||||
|
--tableViewMore-borderColor: inherit;
|
||||||
|
|
||||||
// Rules
|
// Rules
|
||||||
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -782,7 +795,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));
|
||||||
}
|
}
|
||||||
`};
|
`};
|
||||||
|
|
||||||
@@ -984,3 +997,7 @@ Styled.ViewMoreButton = styled(Button)`
|
|||||||
margin-left: 0.5ch;
|
margin-left: 0.5ch;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
Styled.ViewMoreTr = styled(Styled.Tr)`
|
||||||
|
--border-color: var(--tableViewMore-borderColor);
|
||||||
|
`;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -40,5 +40,5 @@ Styled.Details = styled(Details)`
|
|||||||
|
|
||||||
padding: 0.375rem 0.75rem 0.25rem;
|
padding: 0.375rem 0.75rem 0.25rem;
|
||||||
|
|
||||||
font-size: 0.8125em;
|
font-size: var(--details-item-fontSize, 0.8125em);
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -119,6 +119,13 @@ export const InputSelectionOption = Abacus.exchange.dydx.abacus.output.input.Sel
|
|||||||
// ------ Wallet ------ //
|
// ------ Wallet ------ //
|
||||||
export type Wallet = Abacus.exchange.dydx.abacus.output.Wallet;
|
export type Wallet = Abacus.exchange.dydx.abacus.output.Wallet;
|
||||||
export type AccountBalance = Abacus.exchange.dydx.abacus.output.AccountBalance;
|
export type AccountBalance = Abacus.exchange.dydx.abacus.output.AccountBalance;
|
||||||
|
export type TradingRewards = Abacus.exchange.dydx.abacus.output.TradingRewards;
|
||||||
|
export type HistoricalTradingReward = Abacus.exchange.dydx.abacus.output.HistoricalTradingReward;
|
||||||
|
export const HistoricalTradingRewardsPeriod =
|
||||||
|
Abacus.exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod;
|
||||||
|
const historicalTradingRewardsPeriod = [...HistoricalTradingRewardsPeriod.values()] as const;
|
||||||
|
export type HistoricalTradingRewardsPeriods = (typeof historicalTradingRewardsPeriod)[number];
|
||||||
|
|
||||||
export type Subaccount = Abacus.exchange.dydx.abacus.output.Subaccount;
|
export type Subaccount = Abacus.exchange.dydx.abacus.output.Subaccount;
|
||||||
export type SubaccountPosition = Abacus.exchange.dydx.abacus.output.SubaccountPosition;
|
export type SubaccountPosition = Abacus.exchange.dydx.abacus.output.SubaccountPosition;
|
||||||
export type SubaccountOrder = Abacus.exchange.dydx.abacus.output.SubaccountOrder;
|
export type SubaccountOrder = Abacus.exchange.dydx.abacus.output.SubaccountOrder;
|
||||||
@@ -202,6 +209,9 @@ export const RestrictionType = Abacus.exchange.dydx.abacus.output.Restriction;
|
|||||||
const restrictionTypes = [...RestrictionType.values()] as const;
|
const restrictionTypes = [...RestrictionType.values()] as const;
|
||||||
export type RestrictionTypes = (typeof restrictionTypes)[number];
|
export type RestrictionTypes = (typeof restrictionTypes)[number];
|
||||||
|
|
||||||
|
// ------ Api data ------ //
|
||||||
|
export const ApiData = Abacus.exchange.dydx.abacus.state.manager.ApiData;
|
||||||
|
|
||||||
// ------ Enum Conversions ------ //
|
// ------ Enum Conversions ------ //
|
||||||
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
|
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
|
||||||
? A
|
? A
|
||||||
@@ -236,6 +246,15 @@ export const HISTORICAL_PNL_PERIODS: Record<
|
|||||||
[HistoricalPnlPeriod.Period90d.name]: HistoricalPnlPeriod.Period90d,
|
[HistoricalPnlPeriod.Period90d.name]: HistoricalPnlPeriod.Period90d,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const HISTORICAL_TRADING_REWARDS_PERIODS: Record<
|
||||||
|
KotlinIrEnumValues<typeof HistoricalTradingRewardsPeriod>,
|
||||||
|
HistoricalTradingRewardsPeriods
|
||||||
|
> = {
|
||||||
|
[HistoricalTradingRewardsPeriod.MONTHLY.name]: HistoricalTradingRewardsPeriod.MONTHLY,
|
||||||
|
[HistoricalTradingRewardsPeriod.WEEKLY.name]: HistoricalTradingRewardsPeriod.WEEKLY,
|
||||||
|
[HistoricalTradingRewardsPeriod.DAILY.name]: HistoricalTradingRewardsPeriod.DAILY,
|
||||||
|
};
|
||||||
|
|
||||||
export const ORDER_STATUS_STRINGS: Record<KotlinIrEnumValues<typeof AbacusOrderStatus>, string> = {
|
export const ORDER_STATUS_STRINGS: Record<KotlinIrEnumValues<typeof AbacusOrderStatus>, string> = {
|
||||||
[AbacusOrderStatus.open.name]: STRING_KEYS.OPEN_STATUS,
|
[AbacusOrderStatus.open.name]: STRING_KEYS.OPEN_STATUS,
|
||||||
[AbacusOrderStatus.open.rawValue]: STRING_KEYS.OPEN_STATUS,
|
[AbacusOrderStatus.open.rawValue]: STRING_KEYS.OPEN_STATUS,
|
||||||
|
|||||||
@@ -173,3 +173,5 @@ export type AnalyticsEventData<T extends AnalyticsEvent> =
|
|||||||
validatorUrl: string;
|
validatorUrl: string;
|
||||||
}
|
}
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
|
export const DEFAULT_TRANSACTION_MEMO = 'dYdX Frontend (web)';
|
||||||
|
|||||||
@@ -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',
|
||||||
@@ -19,6 +20,8 @@ export enum DialogTypes {
|
|||||||
Transfer = 'Transfer',
|
Transfer = 'Transfer',
|
||||||
Withdraw = 'Withdraw',
|
Withdraw = 'Withdraw',
|
||||||
ManageFunds = 'ManageFunds',
|
ManageFunds = 'ManageFunds',
|
||||||
|
NewMarketMessageDetails = 'NewMarketMessageDetails',
|
||||||
|
NewMarketAgreement = 'NewMarketAgreement',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TradeBoxDialogTypes {
|
export enum TradeBoxDialogTypes {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Temporary Indexer types
|
||||||
|
* remove when Indexer type lib is available through @dydxprotocol/v4-client-js
|
||||||
|
*/
|
||||||
|
export type PerpetualMarketResponse = {
|
||||||
|
clobPairId: string;
|
||||||
|
ticker: string;
|
||||||
|
status: string;
|
||||||
|
oraclePrice: string;
|
||||||
|
priceChange24H: string;
|
||||||
|
volume24H: string;
|
||||||
|
trades24H: number;
|
||||||
|
nextFundingRate: string;
|
||||||
|
initialMarginFraction: string;
|
||||||
|
maintenanceMarginFraction: string;
|
||||||
|
openInterest: string;
|
||||||
|
atomicResolution: number;
|
||||||
|
quantumConversionExponent: number;
|
||||||
|
tickSize: string;
|
||||||
|
stepSize: string;
|
||||||
|
stepBaseQuantums: number;
|
||||||
|
subticksPerTick: number;
|
||||||
|
};
|
||||||
@@ -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',
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export type TooltipStrings = {
|
|||||||
stringParams?: any;
|
stringParams?: any;
|
||||||
urlConfigs?: LinksConfigs;
|
urlConfigs?: LinksConfigs;
|
||||||
}) => {
|
}) => {
|
||||||
title: string;
|
title?: string;
|
||||||
body: string;
|
body: string;
|
||||||
learnMoreLink?: string;
|
learnMoreLink?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
export type ExchangeConfigParsedCsv = Array<{
|
||||||
|
base_asset: string;
|
||||||
|
exchange: string;
|
||||||
|
pair: string;
|
||||||
|
|
||||||
|
adjust_by_market: string;
|
||||||
|
min_2_depth: string;
|
||||||
|
avg_30d_vol: string;
|
||||||
|
reference_price: string;
|
||||||
|
risk_assessment: string;
|
||||||
|
num_oracles: string;
|
||||||
|
liquidity_tier: string;
|
||||||
|
asset_name: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type ExchangeConfigItem = {
|
||||||
|
exchangeName: string;
|
||||||
|
ticker: string;
|
||||||
|
adjustByMarket?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PotentialMarketParsedCsv = Array<{
|
||||||
|
base_asset: string;
|
||||||
|
reference_price: string;
|
||||||
|
num_oracles: string;
|
||||||
|
liquidity_tier: string;
|
||||||
|
asset_name: string;
|
||||||
|
p: string;
|
||||||
|
atomic_resolution: string;
|
||||||
|
min_exchanges: string;
|
||||||
|
min_price_change_ppm: string;
|
||||||
|
price_exponent: string;
|
||||||
|
step_base_quantum: string;
|
||||||
|
ticksize_exponent: string;
|
||||||
|
subticks_per_tick: string;
|
||||||
|
min_order_size: string;
|
||||||
|
quantum_conversion_exponent: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type PotentialMarketItem = {
|
||||||
|
baseAsset: string;
|
||||||
|
referencePrice: string;
|
||||||
|
numOracles: number;
|
||||||
|
liquidityTier: number;
|
||||||
|
assetName: string;
|
||||||
|
p: number;
|
||||||
|
atomicResolution: number;
|
||||||
|
minExchanges: number;
|
||||||
|
minPriceChangePpm: number;
|
||||||
|
priceExponent: number;
|
||||||
|
stepBaseQuantum: number;
|
||||||
|
ticksizeExponent: number;
|
||||||
|
subticksPerTick: number;
|
||||||
|
minOrderSize: number;
|
||||||
|
quantumConversionExponent: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NUM_ORACLES_TO_QUALIFY_AS_SAFE = 6;
|
||||||
|
|
||||||
|
export const LIQUIDITY_TIERS = {
|
||||||
|
0: {
|
||||||
|
label: 'Large-cap',
|
||||||
|
initialMarginFraction: 0.05,
|
||||||
|
maintenanceMarginFraction: 0.03,
|
||||||
|
impactNotional: 10_000,
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
label: 'Mid-cap',
|
||||||
|
initialMarginFraction: 0.1,
|
||||||
|
maintenanceMarginFraction: 0.05,
|
||||||
|
impactNotional: 5_000,
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
label: 'Long-tail',
|
||||||
|
initialMarginFraction: 0.2,
|
||||||
|
maintenanceMarginFraction: 0.1,
|
||||||
|
impactNotional: 2_500,
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
label: 'Safety',
|
||||||
|
initialMarginFraction: 1,
|
||||||
|
maintenanceMarginFraction: 0.2,
|
||||||
|
impactNotional: 2_500,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -11,6 +11,10 @@ export enum AppRoute {
|
|||||||
Privacy = '/privacy',
|
Privacy = '/privacy',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum MarketsRoute {
|
||||||
|
New = 'new',
|
||||||
|
}
|
||||||
|
|
||||||
export enum PortfolioRoute {
|
export enum PortfolioRoute {
|
||||||
Fees = 'fees',
|
Fees = 'fees',
|
||||||
History = 'history',
|
History = 'history',
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
|
|||||||
@@ -57,10 +57,9 @@ export const tradeTooltips: TooltipStrings = {
|
|||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_TITLE }),
|
||||||
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_BODY }),
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_BODY }),
|
||||||
}),
|
}),
|
||||||
'initial-margin-fraction': ({ stringGetter, urlConfigs }) => ({
|
'initial-margin-fraction': ({ stringGetter }) => ({
|
||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_TITLE }),
|
||||||
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_BODY }),
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_BODY }),
|
||||||
learnMoreLink: urlConfigs?.initialMarginFractionLearnMore,
|
|
||||||
}),
|
}),
|
||||||
'initial-stop': ({ stringGetter }) => ({
|
'initial-stop': ({ stringGetter }) => ({
|
||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_STOP_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_STOP_TITLE }),
|
||||||
@@ -163,6 +162,10 @@ export const tradeTooltips: TooltipStrings = {
|
|||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TIMEINFORCE_IOC_FOK_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TIMEINFORCE_IOC_FOK_TITLE }),
|
||||||
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TIMEINFORCE_IOC_FOK_BODY }),
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TIMEINFORCE_IOC_FOK_BODY }),
|
||||||
}),
|
}),
|
||||||
|
'reference-price': ({ stringGetter }) => ({
|
||||||
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.REFERENCE_PRICE_TITLE }),
|
||||||
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REFERENCE_PRICE_BODY }),
|
||||||
|
}),
|
||||||
spread: () => ({
|
spread: () => ({
|
||||||
title: 'Spread',
|
title: 'Spread',
|
||||||
body: 'The difference in price between the highest bid (the price a buyer is willing to buy for) and lowest ask (the price a seller is willing to sell for) an asset.',
|
body: 'The difference in price between the highest bid (the price a buyer is willing to buy for) and lowest ask (the price a seller is willing to sell for) an asset.',
|
||||||
@@ -195,4 +198,7 @@ export const tradeTooltips: TooltipStrings = {
|
|||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.UNREALIZED_PNL_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.UNREALIZED_PNL_TITLE }),
|
||||||
body: stringGetter({ key: TOOLTIP_STRING_KEYS.UNREALIZED_PNL_BODY }),
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.UNREALIZED_PNL_BODY }),
|
||||||
}),
|
}),
|
||||||
|
'reward-history': ({ stringGetter }) => ({
|
||||||
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REWARD_HISTORY_BODY }),
|
||||||
|
}),
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { useDebounce } from './useDebounce';
|
|||||||
import { useInterval } from './useInterval';
|
import { useInterval } from './useInterval';
|
||||||
import { useDocumentTitle } from './useDocumentTitle';
|
import { useDocumentTitle } from './useDocumentTitle';
|
||||||
import { useDydxClient } from './useDydxClient';
|
import { useDydxClient } from './useDydxClient';
|
||||||
|
import { useGovernanceVariables } from './useGovernanceVariables';
|
||||||
import { useAccountBalance } from './useAccountBalance';
|
import { useAccountBalance } from './useAccountBalance';
|
||||||
import { useAccounts } from './useAccounts';
|
import { useAccounts } from './useAccounts';
|
||||||
import { useAnalytics } from './useAnalytics';
|
import { useAnalytics } from './useAnalytics';
|
||||||
@@ -14,6 +15,7 @@ import { useInitializePage } from './useInitializePage';
|
|||||||
import { useIsFirstRender } from './useIsFirstRender';
|
import { useIsFirstRender } from './useIsFirstRender';
|
||||||
import { useLocaleSeparators } from './useLocaleSeparators';
|
import { useLocaleSeparators } from './useLocaleSeparators';
|
||||||
import { useLocalStorage } from './useLocalStorage';
|
import { useLocalStorage } from './useLocalStorage';
|
||||||
|
import { useNextClobPairId } from './useNextClobPairId';
|
||||||
import { useNow } from './useNow';
|
import { useNow } from './useNow';
|
||||||
import { useOnClickOutside } from './useOnClickOutside';
|
import { useOnClickOutside } from './useOnClickOutside';
|
||||||
import { usePageTitlePriceUpdates } from './usePageTitlePriceUpdates';
|
import { usePageTitlePriceUpdates } from './usePageTitlePriceUpdates';
|
||||||
@@ -34,6 +36,7 @@ export {
|
|||||||
useDebounce,
|
useDebounce,
|
||||||
useDocumentTitle,
|
useDocumentTitle,
|
||||||
useDydxClient,
|
useDydxClient,
|
||||||
|
useGovernanceVariables,
|
||||||
useAccountBalance,
|
useAccountBalance,
|
||||||
useAccounts,
|
useAccounts,
|
||||||
useAnalytics,
|
useAnalytics,
|
||||||
@@ -42,6 +45,7 @@ export {
|
|||||||
useIsFirstRender,
|
useIsFirstRender,
|
||||||
useLocaleSeparators,
|
useLocaleSeparators,
|
||||||
useLocalStorage,
|
useLocalStorage,
|
||||||
|
useNextClobPairId,
|
||||||
useNow,
|
useNow,
|
||||||
useOnClickOutside,
|
useOnClickOutside,
|
||||||
usePageTitlePriceUpdates,
|
usePageTitlePriceUpdates,
|
||||||
|
|||||||
@@ -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];
|
|
||||||
}
|
|
||||||
@@ -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];
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BECH32_PREFIX,
|
BECH32_PREFIX,
|
||||||
CompositeClient,
|
CompositeClient,
|
||||||
@@ -9,11 +10,13 @@ import {
|
|||||||
onboarding,
|
onboarding,
|
||||||
Network,
|
Network,
|
||||||
ValidatorConfig,
|
ValidatorConfig,
|
||||||
|
type ProposalStatus,
|
||||||
} from '@dydxprotocol/v4-client-js';
|
} from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import type { ResolutionString } from 'public/tradingview/charting_library';
|
import type { ResolutionString } from 'public/tradingview/charting_library';
|
||||||
|
|
||||||
import type { ConnectNetworkEvent, NetworkConfig } from '@/constants/abacus';
|
import type { ConnectNetworkEvent, NetworkConfig } from '@/constants/abacus';
|
||||||
|
import { DEFAULT_TRANSACTION_MEMO } from '@/constants/analytics';
|
||||||
import { type Candle, RESOLUTION_MAP } from '@/constants/candles';
|
import { type Candle, RESOLUTION_MAP } from '@/constants/candles';
|
||||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
import { DydxChainAsset } from '@/constants/wallets';
|
import { DydxChainAsset } from '@/constants/wallets';
|
||||||
@@ -68,17 +71,22 @@ const useDydxClientContext = () => {
|
|||||||
new Network(
|
new Network(
|
||||||
selectedNetwork,
|
selectedNetwork,
|
||||||
new IndexerConfig(networkConfig.indexerUrl, networkConfig.websocketUrl),
|
new IndexerConfig(networkConfig.indexerUrl, networkConfig.websocketUrl),
|
||||||
new ValidatorConfig(networkConfig.validatorUrl, networkConfig.chainId,
|
new ValidatorConfig(
|
||||||
|
networkConfig.validatorUrl,
|
||||||
|
networkConfig.chainId,
|
||||||
{
|
{
|
||||||
USDC_DENOM: tokensConfigs[DydxChainAsset.USDC].denom,
|
USDC_DENOM: tokensConfigs[DydxChainAsset.USDC].denom,
|
||||||
USDC_DECIMALS: tokensConfigs[DydxChainAsset.USDC].decimals,
|
USDC_DECIMALS: tokensConfigs[DydxChainAsset.USDC].decimals,
|
||||||
USDC_GAS_DENOM: tokensConfigs[DydxChainAsset.USDC].gasDenom,
|
USDC_GAS_DENOM: tokensConfigs[DydxChainAsset.USDC].gasDenom,
|
||||||
CHAINTOKEN_DENOM: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
|
CHAINTOKEN_DENOM: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
|
||||||
CHAINTOKEN_DECIMALS: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
|
CHAINTOKEN_DECIMALS: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
|
||||||
}, {
|
},
|
||||||
broadcastPollIntervalMs: 3_000,
|
{
|
||||||
broadcastTimeoutMs: 60_000,
|
broadcastPollIntervalMs: 3_000,
|
||||||
})
|
broadcastTimeoutMs: 60_000,
|
||||||
|
},
|
||||||
|
DEFAULT_TRANSACTION_MEMO
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
setCompositeClient(initializedClient);
|
setCompositeClient(initializedClient);
|
||||||
@@ -111,6 +119,36 @@ const useDydxClientContext = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ------ Public Methods ------ //
|
// ------ Public Methods ------ //
|
||||||
|
const requestAllPerpetualMarkets = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const { markets } =
|
||||||
|
(await compositeClient?.indexerClient.markets.getPerpetualMarkets()) || {};
|
||||||
|
return markets || [];
|
||||||
|
} catch (error) {
|
||||||
|
log('useDydxClient/getPerpetualMarkets', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}, [compositeClient]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param proposalStatus - Optional filter for proposal status. If not provided, all proposals in ProposalStatus.VotingPeriod will be returned.
|
||||||
|
*/
|
||||||
|
const requestAllGovernanceProposals = useCallback(
|
||||||
|
async (proposalStatus?: ProposalStatus) => {
|
||||||
|
try {
|
||||||
|
const allGovProposals = await compositeClient?.validatorClient.get.getAllGovProposals(
|
||||||
|
proposalStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
return allGovProposals;
|
||||||
|
} catch (error) {
|
||||||
|
log('useDydxClient/getProposals', error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[compositeClient]
|
||||||
|
);
|
||||||
|
|
||||||
const requestCandles = useCallback(
|
const requestCandles = useCallback(
|
||||||
async ({
|
async ({
|
||||||
marketId,
|
marketId,
|
||||||
@@ -225,6 +263,8 @@ const useDydxClientContext = () => {
|
|||||||
getWalletFromEvmSignature,
|
getWalletFromEvmSignature,
|
||||||
|
|
||||||
// Public Methods
|
// Public Methods
|
||||||
|
requestAllPerpetualMarkets,
|
||||||
|
requestAllGovernanceProposals,
|
||||||
getCandlesForDatafeed,
|
getCandlesForDatafeed,
|
||||||
screenAddresses,
|
screenAddresses,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
|
import { useSelectedNetwork } from '@/hooks';
|
||||||
|
|
||||||
|
export interface GovernanceVariables {
|
||||||
|
newMarketProposal: {
|
||||||
|
initialDepositAmount: number;
|
||||||
|
delayBlocks: number;
|
||||||
|
newMarketsMethodology: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGovernanceVariables = (): GovernanceVariables => {
|
||||||
|
const { selectedNetwork } = useSelectedNetwork();
|
||||||
|
const governanceVars = ENVIRONMENT_CONFIG_MAP[selectedNetwork].governance as GovernanceVariables;
|
||||||
|
return governanceVars;
|
||||||
|
};
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
|
import {
|
||||||
|
MsgCreateClobPair,
|
||||||
|
MsgCreateOracleMarket,
|
||||||
|
MsgCreatePerpetual,
|
||||||
|
MsgDelayMessage,
|
||||||
|
MsgUpdateClobPair,
|
||||||
|
TYPE_URL_MSG_CREATE_CLOB_PAIR,
|
||||||
|
TYPE_URL_MSG_CREATE_ORACLE_MARKET,
|
||||||
|
TYPE_URL_MSG_CREATE_PERPETUAL,
|
||||||
|
TYPE_URL_MSG_DELAY_MESSAGE,
|
||||||
|
TYPE_URL_MSG_UPDATE_CLOB_PAIR,
|
||||||
|
} from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
|
import type { PerpetualMarketResponse } from '@/constants/indexer';
|
||||||
|
import { useDydxClient } from '@/hooks/useDydxClient';
|
||||||
|
|
||||||
|
export const useNextClobPairId = () => {
|
||||||
|
const { isConnected, requestAllPerpetualMarkets, requestAllGovernanceProposals } =
|
||||||
|
useDydxClient();
|
||||||
|
|
||||||
|
const { data: perpetualMarkets, status: perpetualMarketsStatus } = useQuery({
|
||||||
|
enabled: isConnected,
|
||||||
|
queryKey: 'requestAllPerpetualMarkets',
|
||||||
|
queryFn: requestAllPerpetualMarkets,
|
||||||
|
refetchInterval: 60_000,
|
||||||
|
staleTime: 60_000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: allGovProposals, status: allGovProposalsStatus } = useQuery({
|
||||||
|
enabled: isConnected,
|
||||||
|
queryKey: 'requestAllActiveGovernanceProposals',
|
||||||
|
queryFn: () => requestAllGovernanceProposals(),
|
||||||
|
refetchInterval: 10_000,
|
||||||
|
staleTime: 10_000,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param message from proposal. Each message is wrapped in a type any (on purpose).
|
||||||
|
* @param callback method used to compile all clobPairIds, perpetualIds, marketIds, etc.
|
||||||
|
*/
|
||||||
|
const decodeMsgForClobPairId = (message: any, callback: (id?: number) => void): any => {
|
||||||
|
const { typeUrl, value } = message;
|
||||||
|
|
||||||
|
switch (typeUrl) {
|
||||||
|
case TYPE_URL_MSG_CREATE_ORACLE_MARKET: {
|
||||||
|
const decodedValue = MsgCreateOracleMarket.decode(value);
|
||||||
|
callback(decodedValue.params?.id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_URL_MSG_CREATE_PERPETUAL: {
|
||||||
|
const decodedValue = MsgCreatePerpetual.decode(value);
|
||||||
|
callback(decodedValue.params?.id);
|
||||||
|
callback(decodedValue.params?.marketId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_URL_MSG_CREATE_CLOB_PAIR: {
|
||||||
|
const decodedValue = MsgCreateClobPair.decode(value);
|
||||||
|
callback(decodedValue.clobPair?.id);
|
||||||
|
callback(decodedValue.clobPair?.perpetualClobMetadata?.perpetualId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_URL_MSG_UPDATE_CLOB_PAIR: {
|
||||||
|
const decodedValue = MsgUpdateClobPair.decode(value);
|
||||||
|
callback(decodedValue.clobPair?.id);
|
||||||
|
callback(decodedValue.clobPair?.perpetualClobMetadata?.perpetualId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_URL_MSG_DELAY_MESSAGE: {
|
||||||
|
const decodedValue = MsgDelayMessage.decode(value);
|
||||||
|
decodeMsgForClobPairId(decodedValue.msg, callback);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextAvailableClobPairId = useMemo(() => {
|
||||||
|
const idsFromProposals: number[] = [];
|
||||||
|
|
||||||
|
if (allGovProposals && Object.values(allGovProposals.proposals).length > 0) {
|
||||||
|
const proposals = allGovProposals.proposals;
|
||||||
|
proposals.forEach((proposal) => {
|
||||||
|
if (proposal.messages) {
|
||||||
|
proposal.messages.map((message) => {
|
||||||
|
decodeMsgForClobPairId(message, (id?: number) => {
|
||||||
|
if (id) {
|
||||||
|
idsFromProposals.push(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (perpetualMarkets && Object.values(perpetualMarkets).length > 0) {
|
||||||
|
const clobPairIds = Object.values(perpetualMarkets)?.map((perpetualMarket) =>
|
||||||
|
Number((perpetualMarket as PerpetualMarketResponse).clobPairId)
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextAvailableClobPairId = Math.max(...[...clobPairIds, ...idsFromProposals]) + 1;
|
||||||
|
return nextAvailableClobPairId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}, [perpetualMarkets, allGovProposals]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
allGovProposalsStatus,
|
||||||
|
perpetualMarketsStatus,
|
||||||
|
nextAvailableClobPairId,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { createContext, useContext, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ExchangeConfigItem,
|
||||||
|
ExchangeConfigParsedCsv,
|
||||||
|
PotentialMarketItem,
|
||||||
|
PotentialMarketParsedCsv,
|
||||||
|
} from '@/constants/potentialMarkets';
|
||||||
|
|
||||||
|
import { log } from '@/lib/telemetry';
|
||||||
|
|
||||||
|
const PotentialMarketsContext = createContext<ReturnType<typeof usePotentialMarketsContext>>({
|
||||||
|
potentialMarkets: undefined,
|
||||||
|
exchangeConfigs: undefined,
|
||||||
|
hasPotentialMarketsData: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
PotentialMarketsContext.displayName = 'PotentialMarkets';
|
||||||
|
|
||||||
|
export const PotentialMarketsProvider = ({ ...props }) => (
|
||||||
|
<PotentialMarketsContext.Provider value={usePotentialMarketsContext()} {...props} />
|
||||||
|
);
|
||||||
|
|
||||||
|
export const usePotentialMarkets = () => useContext(PotentialMarketsContext);
|
||||||
|
|
||||||
|
const EXCHANGE_CONFIG_FILE_PATH = '/configs/potentialMarketExchangeConfig.json';
|
||||||
|
const POTENTIAL_MARKETS_FILE_PATH = '/configs/potentialMarketParameters.json';
|
||||||
|
|
||||||
|
export const usePotentialMarketsContext = () => {
|
||||||
|
const [potentialMarkets, setPotentialMarkets] = useState<PotentialMarketItem[]>();
|
||||||
|
const [exchangeConfigs, setExchangeConfigs] = useState<Record<string, ExchangeConfigItem[]>>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
fetch(POTENTIAL_MARKETS_FILE_PATH)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
setPotentialMarkets(data as PotentialMarketItem[]);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
log('usePotentialMarkets/potentialMarkets', error);
|
||||||
|
setPotentialMarkets(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fetch(EXCHANGE_CONFIG_FILE_PATH)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
setExchangeConfigs(data as Record<string, ExchangeConfigItem[]>);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
log('usePotentialMarkets/exchangeConfigs', error);
|
||||||
|
setExchangeConfigs(undefined);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
potentialMarkets,
|
||||||
|
exchangeConfigs,
|
||||||
|
hasPotentialMarketsData: Boolean(potentialMarkets && exchangeConfigs),
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -2,11 +2,16 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState }
|
|||||||
import { shallowEqual, useSelector, useDispatch } from 'react-redux';
|
import { shallowEqual, useSelector, useDispatch } from 'react-redux';
|
||||||
import type { Nullable } from '@dydxprotocol/v4-abacus';
|
import type { Nullable } from '@dydxprotocol/v4-abacus';
|
||||||
import Long from 'long';
|
import Long from 'long';
|
||||||
import type { IndexedTx } from '@cosmjs/stargate';
|
import { type IndexedTx } from '@cosmjs/stargate';
|
||||||
import type { EncodeObject } from '@cosmjs/proto-signing';
|
import type { EncodeObject } from '@cosmjs/proto-signing';
|
||||||
import { Method } from '@cosmjs/tendermint-rpc';
|
import { Method } from '@cosmjs/tendermint-rpc';
|
||||||
|
|
||||||
import { type LocalWallet, SubaccountClient } from '@dydxprotocol/v4-client-js';
|
import {
|
||||||
|
type LocalWallet,
|
||||||
|
SubaccountClient,
|
||||||
|
type GovAddNewMarketParams,
|
||||||
|
utils,
|
||||||
|
} from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AccountBalance,
|
AccountBalance,
|
||||||
@@ -16,7 +21,6 @@ import type {
|
|||||||
} from '@/constants/abacus';
|
} from '@/constants/abacus';
|
||||||
|
|
||||||
import { AMOUNT_RESERVED_FOR_GAS_USDC } from '@/constants/account';
|
import { AMOUNT_RESERVED_FOR_GAS_USDC } from '@/constants/account';
|
||||||
import { AnalyticsEvent } from '@/constants/analytics';
|
|
||||||
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
||||||
import { DydxAddress } from '@/constants/wallets';
|
import { DydxAddress } from '@/constants/wallets';
|
||||||
|
|
||||||
@@ -24,14 +28,13 @@ import { setSubaccount, setHistoricalPnl, removeUncommittedOrderClientId } from
|
|||||||
import { getBalances } from '@/state/accountSelectors';
|
import { getBalances } from '@/state/accountSelectors';
|
||||||
|
|
||||||
import abacusStateManager from '@/lib/abacus';
|
import abacusStateManager from '@/lib/abacus';
|
||||||
import { track } from '@/lib/analytics';
|
import { hashFromTx } from '@/lib/hashfromTx';
|
||||||
import { MustBigNumber } from '@/lib/numbers';
|
|
||||||
import { log } from '@/lib/telemetry';
|
import { log } from '@/lib/telemetry';
|
||||||
|
|
||||||
import { useAccounts } from './useAccounts';
|
import { useAccounts } from './useAccounts';
|
||||||
import { useTokenConfigs } from './useTokenConfigs';
|
import { useTokenConfigs } from './useTokenConfigs';
|
||||||
import { useDydxClient } from './useDydxClient';
|
import { useDydxClient } from './useDydxClient';
|
||||||
import { hashFromTx } from '@/lib/hashfromTx';
|
import { useGovernanceVariables } from './useGovernanceVariables';
|
||||||
|
|
||||||
type SubaccountContextType = ReturnType<typeof useSubaccountContext>;
|
type SubaccountContextType = ReturnType<typeof useSubaccountContext>;
|
||||||
const SubaccountContext = createContext<SubaccountContextType>({} as SubaccountContextType);
|
const SubaccountContext = createContext<SubaccountContextType>({} as SubaccountContextType);
|
||||||
@@ -201,8 +204,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
value: {
|
value: {
|
||||||
...transaction.msg,
|
...transaction.msg,
|
||||||
timeoutTimestamp: transaction.msg.timeoutTimestamp
|
timeoutTimestamp: transaction.msg.timeoutTimestamp
|
||||||
// Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
? // Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
||||||
? BigInt(Long.fromValue(transaction.msg.timeoutTimestamp).toString())
|
BigInt(Long.fromValue(transaction.msg.timeoutTimestamp).toString())
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -301,7 +304,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
|
|
||||||
const sendSquidWithdraw = useCallback(
|
const sendSquidWithdraw = useCallback(
|
||||||
async (amount: number, payload: string, isCctp?: boolean) => {
|
async (amount: number, payload: string, isCctp?: boolean) => {
|
||||||
|
|
||||||
const cctpWithdraw = () => {
|
const cctpWithdraw = () => {
|
||||||
return new Promise<string>((resolve, reject) =>
|
return new Promise<string>((resolve, reject) =>
|
||||||
abacusStateManager.cctpWithdraw((success, error, data) => {
|
abacusStateManager.cctpWithdraw((success, error, data) => {
|
||||||
@@ -312,8 +314,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
if (isCctp) {
|
if (isCctp) {
|
||||||
return await cctpWithdraw();
|
return await cctpWithdraw();
|
||||||
}
|
}
|
||||||
@@ -413,6 +415,32 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
[subaccountClient]
|
[subaccountClient]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { newMarketProposal } = useGovernanceVariables();
|
||||||
|
|
||||||
|
// ------ Governance Methods ------ //
|
||||||
|
const submitNewMarketProposal = useCallback(
|
||||||
|
async (params: GovAddNewMarketParams) => {
|
||||||
|
if (!compositeClient) {
|
||||||
|
throw new Error('client not initialized');
|
||||||
|
} else if (!localDydxWallet) {
|
||||||
|
throw new Error('wallet not initialized');
|
||||||
|
} else if (!newMarketProposal) {
|
||||||
|
throw new Error('governance variables not initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await compositeClient.submitGovAddNewMarketProposal(
|
||||||
|
localDydxWallet,
|
||||||
|
params,
|
||||||
|
utils.getGovAddNewMarketTitle(params.ticker),
|
||||||
|
utils.getGovAddNewMarketSummary(params.ticker, newMarketProposal.delayBlocks),
|
||||||
|
BigInt(newMarketProposal.initialDepositAmount).toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
[compositeClient, localDydxWallet]
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Deposit/Withdraw/Faucet Methods
|
// Deposit/Withdraw/Faucet Methods
|
||||||
deposit,
|
deposit,
|
||||||
@@ -427,5 +455,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
placeOrder,
|
placeOrder,
|
||||||
closePosition,
|
closePosition,
|
||||||
cancelOrder,
|
cancelOrder,
|
||||||
|
|
||||||
|
// Governance Methods
|
||||||
|
submitNewMarketProposal,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -115,7 +115,15 @@ export const useWalletConnection = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const connectWallet = useCallback(
|
const connectWallet = useCallback(
|
||||||
async ({ walletType, forceConnect }: { walletType?: WalletType; forceConnect?: boolean }) => {
|
async ({
|
||||||
|
walletType,
|
||||||
|
forceConnect,
|
||||||
|
isAccountConnected,
|
||||||
|
}: {
|
||||||
|
walletType?: WalletType;
|
||||||
|
forceConnect?: boolean;
|
||||||
|
isAccountConnected?: boolean;
|
||||||
|
}) => {
|
||||||
if (!walletType) return { walletType, walletConnectionType };
|
if (!walletType) return { walletType, walletConnectionType };
|
||||||
|
|
||||||
const walletConnection = getWalletConnection({ walletType });
|
const walletConnection = getWalletConnection({ walletType });
|
||||||
@@ -143,9 +151,6 @@ export const useWalletConnection = () => {
|
|||||||
} else if (walletConnection.type === WalletConnectionType.TestWallet) {
|
} else if (walletConnection.type === WalletConnectionType.TestWallet) {
|
||||||
saveEvmAddress(STRING_KEYS.TEST_WALLET as EvmAddress);
|
saveEvmAddress(STRING_KEYS.TEST_WALLET as EvmAddress);
|
||||||
} else {
|
} else {
|
||||||
const isAccountConnected = Boolean(
|
|
||||||
evmAddress && evmDerivedAddresses[evmAddress]?.encryptedSignature
|
|
||||||
);
|
|
||||||
// if account connected (via remember me), do not show wagmi popup until forceConnect
|
// if account connected (via remember me), do not show wagmi popup until forceConnect
|
||||||
if (!isConnectedWagmi && (forceConnect || !isAccountConnected)) {
|
if (!isConnectedWagmi && (forceConnect || !isAccountConnected)) {
|
||||||
await connectWagmi({
|
await connectWagmi({
|
||||||
@@ -195,6 +200,9 @@ export const useWalletConnection = () => {
|
|||||||
try {
|
try {
|
||||||
const { walletType, walletConnectionType } = await connectWallet({
|
const { walletType, walletConnectionType } = await connectWallet({
|
||||||
walletType: selectedWalletType,
|
walletType: selectedWalletType,
|
||||||
|
isAccountConnected: Boolean(
|
||||||
|
evmAddress && evmDerivedAddresses[evmAddress]?.encryptedSignature
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
setWalletType(walletType);
|
setWalletType(walletType);
|
||||||
@@ -217,7 +225,7 @@ export const useWalletConnection = () => {
|
|||||||
await disconnectWallet();
|
await disconnectWallet();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, [selectedWalletType, signerWagmi, signerGraz]);
|
}, [selectedWalletType, signerWagmi, signerGraz, evmDerivedAddresses, evmAddress]);
|
||||||
|
|
||||||
const selectWalletType = async (walletType: WalletType | undefined) => {
|
const selectWalletType = async (walletType: WalletType | undefined) => {
|
||||||
if (selectedWalletType) {
|
if (selectedWalletType) {
|
||||||
|
|||||||
@@ -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';
|
||||||
@@ -27,6 +28,8 @@ import { ManageFundsDialog } from '@/views/dialogs/ManageFundsDialog';
|
|||||||
|
|
||||||
import { OrderDetailsDialog } from '@/views/dialogs/DetailsDialog/OrderDetailsDialog';
|
import { OrderDetailsDialog } from '@/views/dialogs/DetailsDialog/OrderDetailsDialog';
|
||||||
import { FillDetailsDialog } from '@/views/dialogs/DetailsDialog/FillDetailsDialog';
|
import { FillDetailsDialog } from '@/views/dialogs/DetailsDialog/FillDetailsDialog';
|
||||||
|
import { NewMarketMessageDetailsDialog } from '@/views/dialogs/NewMarketMessageDetailsDialog';
|
||||||
|
import { NewMarketAgreementDialog } from '@/views/dialogs/NewMarketAgreementDialog';
|
||||||
|
|
||||||
export const DialogManager = () => {
|
export const DialogManager = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -49,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} />,
|
||||||
@@ -67,5 +71,7 @@ export const DialogManager = () => {
|
|||||||
[DialogTypes.Transfer]: <TransferDialog {...modalProps} />,
|
[DialogTypes.Transfer]: <TransferDialog {...modalProps} />,
|
||||||
[DialogTypes.Withdraw]: <WithdrawDialog {...modalProps} />,
|
[DialogTypes.Withdraw]: <WithdrawDialog {...modalProps} />,
|
||||||
[DialogTypes.ManageFunds]: <ManageFundsDialog {...modalProps} />,
|
[DialogTypes.ManageFunds]: <ManageFundsDialog {...modalProps} />,
|
||||||
|
[DialogTypes.NewMarketMessageDetails]: <NewMarketMessageDetailsDialog {...modalProps} />,
|
||||||
|
[DialogTypes.NewMarketAgreement]: <NewMarketAgreementDialog {...modalProps} />,
|
||||||
}[type];
|
}[type];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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])};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import {
|
|||||||
type HumanReadableTransferPayload,
|
type HumanReadableTransferPayload,
|
||||||
} from '@/constants/abacus';
|
} from '@/constants/abacus';
|
||||||
|
|
||||||
|
import { DEFAULT_TRANSACTION_MEMO } from '@/constants/analytics';
|
||||||
import { DialogTypes } from '@/constants/dialogs';
|
import { DialogTypes } from '@/constants/dialogs';
|
||||||
import { UNCOMMITTED_ORDER_TIMEOUT_MS } from '@/constants/trade';
|
import { UNCOMMITTED_ORDER_TIMEOUT_MS } from '@/constants/trade';
|
||||||
import { ENVIRONMENT_CONFIG_MAP, DydxNetwork, isTestnet } from '@/constants/networks';
|
import { ENVIRONMENT_CONFIG_MAP, DydxNetwork, isTestnet } from '@/constants/networks';
|
||||||
@@ -115,7 +116,8 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
|||||||
{
|
{
|
||||||
broadcastPollIntervalMs: 3_000,
|
broadcastPollIntervalMs: 3_000,
|
||||||
broadcastTimeoutMs: 60_000,
|
broadcastTimeoutMs: 60_000,
|
||||||
}
|
},
|
||||||
|
DEFAULT_TRANSACTION_MEMO
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -370,8 +372,8 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
|||||||
value: {
|
value: {
|
||||||
...params.msg,
|
...params.msg,
|
||||||
timeoutTimestamp: params.msg.timeoutTimestamp
|
timeoutTimestamp: params.msg.timeoutTimestamp
|
||||||
// Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
? // Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
||||||
? BigInt(Long.fromValue(params.msg.timeoutTimestamp).toString())
|
BigInt(Long.fromValue(params.msg.timeoutTimestamp).toString())
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -387,7 +389,11 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ibcMsg.value.token.amount = amount.toString();
|
ibcMsg.value.token.amount = amount.toString();
|
||||||
const tx = await this.nobleClient.send([ibcMsg]);
|
const tx = await this.nobleClient.send(
|
||||||
|
[ibcMsg],
|
||||||
|
undefined,
|
||||||
|
`${DEFAULT_TRANSACTION_MEMO} | ${this.nobleWallet?.address}`
|
||||||
|
);
|
||||||
|
|
||||||
const parsedTx = this.parseToPrimitives(tx);
|
const parsedTx = this.parseToPrimitives(tx);
|
||||||
|
|
||||||
@@ -426,8 +432,8 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
|||||||
value: {
|
value: {
|
||||||
...parsedIbcPayload.msg,
|
...parsedIbcPayload.msg,
|
||||||
timeoutTimestamp: parsedIbcPayload.msg.timeoutTimestamp
|
timeoutTimestamp: parsedIbcPayload.msg.timeoutTimestamp
|
||||||
// Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
? // Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
||||||
? BigInt(Long.fromValue(parsedIbcPayload.msg.timeoutTimestamp).toString())
|
BigInt(Long.fromValue(parsedIbcPayload.msg.timeoutTimestamp).toString())
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import type { LocalWallet } from '@dydxprotocol/v4-client-js';
|
|||||||
import type {
|
import type {
|
||||||
ClosePositionInputFields,
|
ClosePositionInputFields,
|
||||||
Nullable,
|
Nullable,
|
||||||
|
HistoricalTradingRewardsPeriod,
|
||||||
|
HistoricalTradingRewardsPeriods,
|
||||||
HumanReadablePlaceOrderPayload,
|
HumanReadablePlaceOrderPayload,
|
||||||
HumanReadableCancelOrderPayload,
|
HumanReadableCancelOrderPayload,
|
||||||
TradeInputFields,
|
TradeInputFields,
|
||||||
@@ -23,6 +25,7 @@ import {
|
|||||||
CoroutineTimer,
|
CoroutineTimer,
|
||||||
TransferType,
|
TransferType,
|
||||||
AbacusAppConfig,
|
AbacusAppConfig,
|
||||||
|
ApiData,
|
||||||
} from '@/constants/abacus';
|
} from '@/constants/abacus';
|
||||||
|
|
||||||
import { DEFAULT_MARKETID } from '@/constants/markets';
|
import { DEFAULT_MARKETID } from '@/constants/markets';
|
||||||
@@ -33,8 +36,6 @@ import type { RootStore } from '@/state/_store';
|
|||||||
import { setTradeFormInputs } from '@/state/inputs';
|
import { setTradeFormInputs } from '@/state/inputs';
|
||||||
import { getInputTradeOptions, getTransferInputs } from '@/state/inputsSelectors';
|
import { getInputTradeOptions, getTransferInputs } from '@/state/inputsSelectors';
|
||||||
|
|
||||||
import { testFlags } from '@/lib/testFlags';
|
|
||||||
|
|
||||||
import AbacusRest from './rest';
|
import AbacusRest from './rest';
|
||||||
import AbacusAnalytics from './analytics';
|
import AbacusAnalytics from './analytics';
|
||||||
import AbacusWebsocket from './websocket';
|
import AbacusWebsocket from './websocket';
|
||||||
@@ -227,6 +228,15 @@ class AbacusStateManager {
|
|||||||
this.stateManager.historicalPnlPeriod = period;
|
this.stateManager.historicalPnlPeriod = period;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setHistoricalTradingRewardPeriod = (
|
||||||
|
period: (typeof HistoricalTradingRewardsPeriod)[keyof typeof HistoricalTradingRewardsPeriod]
|
||||||
|
) => {
|
||||||
|
this.stateManager.historicalTradingRewardPeriod = period;
|
||||||
|
};
|
||||||
|
|
||||||
|
refreshHistoricalTradingRewards = () =>
|
||||||
|
this.stateManager.refresh(ApiData.HISTORICAL_TRADING_REWARDS);
|
||||||
|
|
||||||
switchNetwork = (network: DydxNetwork) => {
|
switchNetwork = (network: DydxNetwork) => {
|
||||||
this.stateManager.environmentId = network;
|
this.stateManager.environmentId = network;
|
||||||
|
|
||||||
@@ -278,6 +288,9 @@ class AbacusStateManager {
|
|||||||
getHistoricalPnlPeriod = (): Nullable<HistoricalPnlPeriods> =>
|
getHistoricalPnlPeriod = (): Nullable<HistoricalPnlPeriods> =>
|
||||||
this.stateManager.historicalPnlPeriod;
|
this.stateManager.historicalPnlPeriod;
|
||||||
|
|
||||||
|
getHistoricalTradingRewardPeriod = (): HistoricalTradingRewardsPeriods =>
|
||||||
|
this.stateManager.historicalTradingRewardPeriod;
|
||||||
|
|
||||||
handleCandlesSubscription = ({
|
handleCandlesSubscription = ({
|
||||||
channelId,
|
channelId,
|
||||||
subscribe,
|
subscribe,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
setSubaccount,
|
setSubaccount,
|
||||||
setTransfers,
|
setTransfers,
|
||||||
setWallet,
|
setWallet,
|
||||||
|
setTradingRewards,
|
||||||
} from '@/state/account';
|
} from '@/state/account';
|
||||||
|
|
||||||
import { setApiState } from '@/state/app';
|
import { setApiState } from '@/state/app';
|
||||||
@@ -96,6 +97,12 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changes.has(Changes.tradingRewards)) {
|
||||||
|
if (updatedState.account?.tradingRewards) {
|
||||||
|
dispatch(setTradingRewards(updatedState.account?.tradingRewards));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (changes.has(Changes.configs)) {
|
if (changes.has(Changes.configs)) {
|
||||||
dispatch(setConfigs(updatedState.configs));
|
dispatch(setConfigs(updatedState.configs));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -19,16 +19,12 @@ class TestFlags {
|
|||||||
return !!this.queryParams.displayinitializingmarkets;
|
return !!this.queryParams.displayinitializingmarkets;
|
||||||
}
|
}
|
||||||
|
|
||||||
get showMobileSignInOption() {
|
|
||||||
return !!this.queryParams.mobilesignin;
|
|
||||||
}
|
|
||||||
|
|
||||||
get addressOverride():string {
|
get addressOverride():string {
|
||||||
return this.queryParams.address;
|
return this.queryParams.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
get showCEXDepositOption() {
|
get showTradingRewards() {
|
||||||
return !!this.queryParams.cexdeposit;
|
return !!this.queryParams.tradingrewards;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ import { AppRoute, PortfolioRoute, HistoryRoute } from '@/constants/routes';
|
|||||||
import { wallets } from '@/constants/wallets';
|
import { wallets } from '@/constants/wallets';
|
||||||
import { useAccounts, useStringGetter, useTokenConfigs } from '@/hooks';
|
import { useAccounts, useStringGetter, useTokenConfigs } from '@/hooks';
|
||||||
|
|
||||||
import { getOnboardingState } from '@/state/accountSelectors';
|
import {
|
||||||
|
getHistoricalTradingRewardsForCurrentWeek,
|
||||||
|
getOnboardingState,
|
||||||
|
} from '@/state/accountSelectors';
|
||||||
import { openDialog } from '@/state/dialogs';
|
import { openDialog } from '@/state/dialogs';
|
||||||
|
|
||||||
import { isTruthy } from '@/lib/isTruthy';
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
@@ -52,6 +55,8 @@ const Profile = () => {
|
|||||||
chainId: ENS_CHAIN_ID,
|
chainId: ENS_CHAIN_ID,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const currentWeekTradingReward = useSelector(getHistoricalTradingRewardsForCurrentWeek);
|
||||||
|
|
||||||
const actions = [
|
const actions = [
|
||||||
{
|
{
|
||||||
key: 'deposit',
|
key: 'deposit',
|
||||||
@@ -159,64 +164,62 @@ const Profile = () => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Styled.Actions>
|
</Styled.Actions>
|
||||||
<Styled.EqualGrid>
|
|
||||||
<Styled.PanelButton
|
<Styled.SettingsButton
|
||||||
slotHeader={
|
slotHeader={
|
||||||
<Styled.InlineRow>
|
<Styled.InlineRow>
|
||||||
<Icon iconName={IconName.Gear} />
|
<Icon iconName={IconName.Gear} />
|
||||||
{stringGetter({ key: STRING_KEYS.SETTINGS })}
|
{stringGetter({ key: STRING_KEYS.SETTINGS })}
|
||||||
</Styled.InlineRow>
|
</Styled.InlineRow>
|
||||||
}
|
}
|
||||||
onClick={() => navigate(AppRoute.Settings)}
|
onClick={() => navigate(AppRoute.Settings)}
|
||||||
|
/>
|
||||||
|
<Styled.HelpButton
|
||||||
|
slotHeader={
|
||||||
|
<Styled.InlineRow>
|
||||||
|
<Icon iconName={IconName.HelpCircle} />
|
||||||
|
{stringGetter({ key: STRING_KEYS.HELP })}
|
||||||
|
</Styled.InlineRow>
|
||||||
|
}
|
||||||
|
onClick={() => dispatch(openDialog({ type: DialogTypes.Help }))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Styled.MigratePanel />
|
||||||
|
|
||||||
|
<Styled.DYDXBalancePanel />
|
||||||
|
|
||||||
|
<Styled.RewardsPanel
|
||||||
|
slotHeaderContent={stringGetter({ key: STRING_KEYS.TRADING_REWARDS })}
|
||||||
|
href={`/${chainTokenLabel}`}
|
||||||
|
hasSeparator
|
||||||
|
>
|
||||||
|
<Styled.Details
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: 'week-rewards',
|
||||||
|
label: stringGetter({ key: STRING_KEYS.THIS_WEEK }),
|
||||||
|
value: currentWeekTradingReward?.amount ?? '-',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
layout="grid"
|
||||||
/>
|
/>
|
||||||
<Styled.PanelButton
|
</Styled.RewardsPanel>
|
||||||
slotHeader={
|
<Styled.FeesPanel
|
||||||
<Styled.InlineRow>
|
slotHeaderContent={stringGetter({ key: STRING_KEYS.FEES })}
|
||||||
<Icon iconName={IconName.HelpCircle} />
|
href={`${AppRoute.Portfolio}/${PortfolioRoute.Fees}`}
|
||||||
{stringGetter({ key: STRING_KEYS.HELP })}
|
hasSeparator
|
||||||
</Styled.InlineRow>
|
>
|
||||||
}
|
<Styled.Details
|
||||||
onClick={() => dispatch(openDialog({ type: DialogTypes.Help }))}
|
items={[
|
||||||
|
{ key: 'maker', label: stringGetter({ key: STRING_KEYS.MAKER }), value: '-' },
|
||||||
|
{ key: 'taker', label: stringGetter({ key: STRING_KEYS.TAKER }), value: '-' },
|
||||||
|
{ key: 'volume', label: stringGetter({ key: STRING_KEYS.VOLUME_30D }), value: '-' },
|
||||||
|
]}
|
||||||
|
layout="grid"
|
||||||
/>
|
/>
|
||||||
</Styled.EqualGrid>
|
</Styled.FeesPanel>
|
||||||
|
|
||||||
<MigratePanel />
|
<Styled.HistoryPanel
|
||||||
<DYDXBalancePanel />
|
|
||||||
|
|
||||||
<Styled.EqualGrid>
|
|
||||||
<Styled.RewardsPanel
|
|
||||||
slotHeaderContent="Trading Rewards"
|
|
||||||
href={`/${chainTokenLabel}`}
|
|
||||||
hasSeparator
|
|
||||||
>
|
|
||||||
<Styled.Details
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
key: 'week-rewards',
|
|
||||||
label: stringGetter({ key: STRING_KEYS.THIS_WEEK }),
|
|
||||||
value: '-',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
layout="grid"
|
|
||||||
/>
|
|
||||||
</Styled.RewardsPanel>
|
|
||||||
<Panel
|
|
||||||
slotHeaderContent={stringGetter({ key: STRING_KEYS.FEES })}
|
|
||||||
href={`${AppRoute.Portfolio}/${PortfolioRoute.Fees}`}
|
|
||||||
hasSeparator
|
|
||||||
>
|
|
||||||
<Styled.Details
|
|
||||||
items={[
|
|
||||||
{ key: 'maker', label: stringGetter({ key: STRING_KEYS.MAKER }), value: '-' },
|
|
||||||
{ key: 'taker', label: stringGetter({ key: STRING_KEYS.TAKER }), value: '-' },
|
|
||||||
{ key: 'volume', label: stringGetter({ key: STRING_KEYS.VOLUME_30D }), value: '-' },
|
|
||||||
]}
|
|
||||||
layout="grid"
|
|
||||||
/>
|
|
||||||
</Panel>
|
|
||||||
</Styled.EqualGrid>
|
|
||||||
|
|
||||||
<Styled.TablePanel
|
|
||||||
slotHeaderContent={stringGetter({ key: STRING_KEYS.HISTORY })}
|
slotHeaderContent={stringGetter({ key: STRING_KEYS.HISTORY })}
|
||||||
href={`${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Trades}`}
|
href={`${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Trades}`}
|
||||||
hasSeparator
|
hasSeparator
|
||||||
@@ -230,10 +233,10 @@ const Profile = () => {
|
|||||||
]}
|
]}
|
||||||
withInnerBorders={false}
|
withInnerBorders={false}
|
||||||
/>
|
/>
|
||||||
</Styled.TablePanel>
|
</Styled.HistoryPanel>
|
||||||
|
|
||||||
<GovernancePanel />
|
<Styled.GovernancePanel />
|
||||||
<StakingPanel />
|
<Styled.StakingPanel />
|
||||||
</Styled.MobileProfileLayout>
|
</Styled.MobileProfileLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -245,14 +248,27 @@ const Styled: Record<string, AnyStyledComponent> = {};
|
|||||||
Styled.MobileProfileLayout = styled.div`
|
Styled.MobileProfileLayout = styled.div`
|
||||||
${layoutMixins.contentContainerPage}
|
${layoutMixins.contentContainerPage}
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1.25rem 0.9rem;
|
padding: 1.25rem 0.9rem;
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
|
|
||||||
|
grid-template-areas:
|
||||||
|
'header header'
|
||||||
|
'actions actions'
|
||||||
|
'settings help'
|
||||||
|
'migrate migrate'
|
||||||
|
'balance balance'
|
||||||
|
'rewards fees'
|
||||||
|
'history history'
|
||||||
|
'governance governance'
|
||||||
|
'staking staking';
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Header = styled.header`
|
Styled.Header = styled.header`
|
||||||
|
grid-area: header;
|
||||||
${layoutMixins.row}
|
${layoutMixins.row}
|
||||||
|
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -286,10 +302,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`
|
||||||
@@ -299,6 +315,7 @@ Styled.Address = styled.h1`
|
|||||||
Styled.Actions = styled(Toolbar)`
|
Styled.Actions = styled(Toolbar)`
|
||||||
${layoutMixins.spacedRow}
|
${layoutMixins.spacedRow}
|
||||||
--stickyArea-topHeight: 5rem;
|
--stickyArea-topHeight: 5rem;
|
||||||
|
grid-area: actions;
|
||||||
|
|
||||||
> a,
|
> a,
|
||||||
> label {
|
> label {
|
||||||
@@ -318,7 +335,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 &&
|
||||||
@@ -329,22 +346,16 @@ Styled.ActionButton = styled(IconButton)<{ iconName?: IconName }>`
|
|||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.EqualGrid = styled.div`
|
|
||||||
${layoutMixins.gridEqualColumns}
|
|
||||||
|
|
||||||
gap: 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Details = styled(Details)`
|
Styled.Details = styled(Details)`
|
||||||
font: var(--font-small-book);
|
font: var(--font-small-book);
|
||||||
--details-value-font: var(--font-medium-book);
|
--details-value-font: var(--font-medium-book);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.RewardsPanel = styled(Panel)`
|
Styled.RewardsPanel = styled(Panel)`
|
||||||
|
grid-area: rewards;
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
|
height: 100%;
|
||||||
&,
|
> div {
|
||||||
> * {
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +364,12 @@ Styled.RewardsPanel = styled(Panel)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.TablePanel = styled(Panel)`
|
Styled.FeesPanel = styled(Panel)`
|
||||||
|
grid-area: fees;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.HistoryPanel = styled(Panel)`
|
||||||
|
grid-area: history;
|
||||||
--panel-content-paddingY: 0;
|
--panel-content-paddingY: 0;
|
||||||
--panel-content-paddingX: 0;
|
--panel-content-paddingX: 0;
|
||||||
|
|
||||||
@@ -393,3 +409,27 @@ Styled.PanelButton = styled(Panel)`
|
|||||||
--panel-paddingY: 0
|
--panel-paddingY: 0
|
||||||
--panel-paddingX:0;
|
--panel-paddingX:0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
Styled.SettingsButton = styled(Styled.PanelButton)`
|
||||||
|
grid-area: settings;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.HelpButton = styled(Styled.PanelButton)`
|
||||||
|
grid-area: help;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.MigratePanel = styled(MigratePanel)`
|
||||||
|
grid-area: migrate;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.DYDXBalancePanel = styled(DYDXBalancePanel)`
|
||||||
|
grid-area: balance;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.GovernancePanel = styled(GovernancePanel)`
|
||||||
|
grid-area: governance;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.StakingPanel = styled(StakingPanel)`
|
||||||
|
grid-area: staking;
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { breakpoints } from '@/styles';
|
import { breakpoints } from '@/styles';
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import { AppRoute, MarketsRoute } from '@/constants/routes';
|
||||||
import { useBreakpoints, useDocumentTitle, useStringGetter } from '@/hooks';
|
import { useBreakpoints, useDocumentTitle, useStringGetter } from '@/hooks';
|
||||||
|
import { usePotentialMarkets } from '@/hooks/usePotentialMarkets';
|
||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
|
import { Button } from '@/components/Button';
|
||||||
import { ContentSectionHeader } from '@/components/ContentSectionHeader';
|
import { ContentSectionHeader } from '@/components/ContentSectionHeader';
|
||||||
|
|
||||||
import { ExchangeBillboards } from '@/views/ExchangeBillboards';
|
import { ExchangeBillboards } from '@/views/ExchangeBillboards';
|
||||||
import { MarketsTable } from '@/views/tables/MarketsTable';
|
import { MarketsTable } from '@/views/tables/MarketsTable';
|
||||||
|
|
||||||
const Markets = () => {
|
const Markets = () => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { isNotTablet } = useBreakpoints();
|
const { isNotTablet } = useBreakpoints();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { hasPotentialMarketsData } = usePotentialMarkets();
|
||||||
|
|
||||||
useDocumentTitle(stringGetter({ key: STRING_KEYS.MARKETS }));
|
useDocumentTitle(stringGetter({ key: STRING_KEYS.MARKETS }));
|
||||||
|
|
||||||
@@ -25,6 +29,13 @@ const Markets = () => {
|
|||||||
<Styled.ContentSectionHeader
|
<Styled.ContentSectionHeader
|
||||||
title={stringGetter({ key: STRING_KEYS.MARKETS })}
|
title={stringGetter({ key: STRING_KEYS.MARKETS })}
|
||||||
subtitle={isNotTablet && stringGetter({ key: STRING_KEYS.DISCOVER_NEW_ASSETS })}
|
subtitle={isNotTablet && stringGetter({ key: STRING_KEYS.DISCOVER_NEW_ASSETS })}
|
||||||
|
slotRight={
|
||||||
|
hasPotentialMarketsData && (
|
||||||
|
<Button onClick={() => navigate(`${AppRoute.Markets}/${MarketsRoute.New}`)}>
|
||||||
|
{stringGetter({ key: STRING_KEYS.ADD_A_MARKET })}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Styled.ExchangeBillboards isSearching={false} searchQuery="" />
|
<Styled.ExchangeBillboards isSearching={false} searchQuery="" />
|
||||||
</Styled.HeaderSection>
|
</Styled.HeaderSection>
|
||||||
|
|||||||
@@ -0,0 +1,259 @@
|
|||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import { isMainnet } from '@/constants/networks';
|
||||||
|
import { AppRoute } from '@/constants/routes';
|
||||||
|
|
||||||
|
import {
|
||||||
|
useBreakpoints,
|
||||||
|
useDocumentTitle,
|
||||||
|
useGovernanceVariables,
|
||||||
|
useStringGetter,
|
||||||
|
useTokenConfigs,
|
||||||
|
} from '@/hooks';
|
||||||
|
|
||||||
|
import { breakpoints } from '@/styles';
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
|
import { Button } from '@/components/Button';
|
||||||
|
import { ContentSectionHeader } from '@/components/ContentSectionHeader';
|
||||||
|
import { IconButton } from '@/components/IconButton';
|
||||||
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
|
import { Link } from '@/components/Link';
|
||||||
|
import { NewMarketForm } from '@/views/forms/NewMarketForm';
|
||||||
|
|
||||||
|
import { MustBigNumber } from '@/lib/numbers';
|
||||||
|
|
||||||
|
const StepItem = ({ step, subtitle, title }: { step: number; subtitle: string; title: string }) => (
|
||||||
|
<Styled.StepItem>
|
||||||
|
<Styled.StepNumber>{step}</Styled.StepNumber>
|
||||||
|
<Styled.Column>
|
||||||
|
<Styled.Title>{title}</Styled.Title>
|
||||||
|
<Styled.Subtitle>{subtitle}</Styled.Subtitle>
|
||||||
|
</Styled.Column>
|
||||||
|
</Styled.StepItem>
|
||||||
|
);
|
||||||
|
|
||||||
|
const NewMarket = () => {
|
||||||
|
const { isNotTablet } = useBreakpoints();
|
||||||
|
const { newMarketProposal } = useGovernanceVariables();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [displaySteps, setDisplaySteps] = useState(true);
|
||||||
|
const stringGetter = useStringGetter();
|
||||||
|
const { chainTokenLabel, chainTokenDecimals } = useTokenConfigs();
|
||||||
|
|
||||||
|
useDocumentTitle(stringGetter({ key: STRING_KEYS.ADD_A_MARKET }));
|
||||||
|
|
||||||
|
const steps = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
step: 1,
|
||||||
|
title: stringGetter({ key: STRING_KEYS.ADD_MARKET_STEP_1_TITLE }),
|
||||||
|
subtitle: stringGetter({
|
||||||
|
key: STRING_KEYS.ADD_MARKET_STEP_1_DESCRIPTION,
|
||||||
|
params: {
|
||||||
|
HERE: (
|
||||||
|
<Styled.Link href={newMarketProposal.newMarketsMethodology}>
|
||||||
|
{stringGetter({ key: STRING_KEYS.HERE })}
|
||||||
|
</Styled.Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step: 2,
|
||||||
|
title: stringGetter({ key: STRING_KEYS.ADD_MARKET_STEP_2_TITLE }),
|
||||||
|
subtitle: stringGetter({ key: STRING_KEYS.ADD_MARKET_STEP_2_DESCRIPTION }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step: 3,
|
||||||
|
title: stringGetter({ key: STRING_KEYS.ADD_MARKET_STEP_3_TITLE }),
|
||||||
|
subtitle: stringGetter({
|
||||||
|
key: STRING_KEYS.ADD_MARKET_STEP_3_DESCRIPTION,
|
||||||
|
params: {
|
||||||
|
REQUIRED_NUM_TOKENS: MustBigNumber(newMarketProposal?.initialDepositAmount)
|
||||||
|
.div(Number(`1e${chainTokenDecimals}`))
|
||||||
|
.toFixed(isMainnet ? 0 : chainTokenDecimals),
|
||||||
|
NATIVE_TOKEN_DENOM: chainTokenLabel,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, [stringGetter, newMarketProposal, chainTokenLabel]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Styled.Page>
|
||||||
|
<Styled.HeaderSection>
|
||||||
|
<Styled.ContentSectionHeader
|
||||||
|
title={stringGetter({ key: STRING_KEYS.SUGGEST_NEW_MARKET })}
|
||||||
|
slotRight={
|
||||||
|
<IconButton iconName={IconName.Close} onClick={() => navigate(AppRoute.Markets)} />
|
||||||
|
}
|
||||||
|
subtitle={isNotTablet && stringGetter({ key: STRING_KEYS.ADD_DETAILS_TO_LAUNCH_MARKET })}
|
||||||
|
/>
|
||||||
|
</Styled.HeaderSection>
|
||||||
|
<Styled.Content>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
slotLeft={<Styled.Icon iconName={displaySteps ? IconName.Hide : IconName.HelpCircle} />}
|
||||||
|
onClick={() => setDisplaySteps(!displaySteps)}
|
||||||
|
>
|
||||||
|
{displaySteps
|
||||||
|
? stringGetter({ key: STRING_KEYS.HIDE_STEPS })
|
||||||
|
: stringGetter({ key: STRING_KEYS.SHOW_STEPS })}
|
||||||
|
</Button>
|
||||||
|
{displaySteps && (
|
||||||
|
<>
|
||||||
|
<Styled.StepsTitle>
|
||||||
|
{stringGetter({ key: STRING_KEYS.STEPS_TO_CREATE })}
|
||||||
|
</Styled.StepsTitle>
|
||||||
|
{steps.map((item) => (
|
||||||
|
<StepItem
|
||||||
|
key={item.step}
|
||||||
|
step={item.step}
|
||||||
|
title={item.title}
|
||||||
|
subtitle={item.subtitle}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Styled.FormContainer>
|
||||||
|
<NewMarketForm />
|
||||||
|
</Styled.FormContainer>
|
||||||
|
</Styled.Content>
|
||||||
|
</Styled.Page>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.Page = styled.div`
|
||||||
|
${layoutMixins.contentContainerPage}
|
||||||
|
gap: 1.5rem;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
--content-max-width: 80rem;
|
||||||
|
max-width: min(calc(100vw - 4rem), var(--content-max-width));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media ${breakpoints.tablet} {
|
||||||
|
--stickyArea-topHeight: var(--page-header-height-mobile);
|
||||||
|
padding: 0 1rem 1rem;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
max-width: calc(100vw - 2rem);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.ContentSectionHeader = styled(ContentSectionHeader)`
|
||||||
|
@media ${breakpoints.notTablet} {
|
||||||
|
padding: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media ${breakpoints.tablet} {
|
||||||
|
padding: 1.25rem 0;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font: var(--font-extra-medium);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.HeaderSection = styled.section`
|
||||||
|
${layoutMixins.contentSectionDetached}
|
||||||
|
|
||||||
|
@media ${breakpoints.tablet} {
|
||||||
|
${layoutMixins.flexColumn}
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Content = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 2rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
@media ${breakpoints.tablet} {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.StepsTitle = styled.h2`
|
||||||
|
font: var(--font-large-medium);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
margin: 1rem;
|
||||||
|
|
||||||
|
@media ${breakpoints.tablet} {
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Icon = styled(Icon)`
|
||||||
|
margin-right: 0.5ch;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.StepItem = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.StepNumber = styled.div`
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
min-width: 2.5rem;
|
||||||
|
min-height: 2.5rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--color-layer-5);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--color-text-2);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Column = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Title = styled.span`
|
||||||
|
color: var(--color-text-2);
|
||||||
|
font: var(--font-medium-book);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Subtitle = styled.span`
|
||||||
|
color: var(--color-text-0);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Link = styled(Link)`
|
||||||
|
--link-color: var(--color-accent);
|
||||||
|
display: inline-block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.FormContainer = styled.div`
|
||||||
|
min-width: 31.25rem;
|
||||||
|
height: fit-content;
|
||||||
|
border-radius: 1rem;
|
||||||
|
background-color: var(--color-layer-3);
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
@media ${breakpoints.tablet} {
|
||||||
|
width: 100%;
|
||||||
|
min-width: unset;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default NewMarket;
|
||||||
@@ -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 }) =>
|
||||||
({
|
({
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton
|
|||||||
import { openDialog } from '@/state/dialogs';
|
import { openDialog } from '@/state/dialogs';
|
||||||
import { calculateCanAccountTrade } from '@/state/accountCalculators';
|
import { calculateCanAccountTrade } from '@/state/accountCalculators';
|
||||||
|
|
||||||
export const DYDXBalancePanel = () => {
|
export const DYDXBalancePanel = ({ className }: { className?: string }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ export const DYDXBalancePanel = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Panel
|
<Panel
|
||||||
|
className={className}
|
||||||
slotHeader={
|
slotHeader={
|
||||||
<Styled.Header>
|
<Styled.Header>
|
||||||
<Styled.Title>
|
<Styled.Title>
|
||||||
|
|||||||
@@ -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_ALL_CAPS })} <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,11 @@ Styled.Image = styled.img`
|
|||||||
height: auto;
|
height: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.ChaosLabsLogo = styled.img`
|
Styled.ChaosLabsLogo = styled.span`
|
||||||
height: 1.25rem;
|
display: flex;
|
||||||
align-self: start;
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
font: var(--font-tiny-medium);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.NewTag = styled(Tag)`
|
Styled.NewTag = styled(Tag)`
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
||||||
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import { isMainnet } from '@/constants/networks';
|
||||||
|
import { AppRoute, MarketsRoute } from '@/constants/routes';
|
||||||
|
|
||||||
|
import { useStringGetter, useTokenConfigs } from '@/hooks';
|
||||||
|
import { usePotentialMarkets } from '@/hooks/usePotentialMarkets';
|
||||||
|
import { useGovernanceVariables } from '@/hooks/useGovernanceVariables';
|
||||||
|
|
||||||
|
import { Panel } from '@/components/Panel';
|
||||||
|
import { IconName } from '@/components/Icon';
|
||||||
|
import { IconButton } from '@/components/IconButton';
|
||||||
|
import { Output, OutputType } from '@/components/Output';
|
||||||
|
import { Tag } from '@/components/Tag';
|
||||||
|
|
||||||
|
import { MustBigNumber } from '@/lib/numbers';
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
|
export const NewMarketsPanel = () => {
|
||||||
|
const stringGetter = useStringGetter();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { hasPotentialMarketsData } = usePotentialMarkets();
|
||||||
|
const { chainTokenDecimals, chainTokenLabel } = useTokenConfigs();
|
||||||
|
const { newMarketProposal } = useGovernanceVariables();
|
||||||
|
const initialDepositAmountBN = MustBigNumber(newMarketProposal.initialDepositAmount).div(
|
||||||
|
Number(`1e${chainTokenDecimals}`)
|
||||||
|
);
|
||||||
|
const initialDepositAmountDecimals = isMainnet ? 0 : chainTokenDecimals;
|
||||||
|
|
||||||
|
if (!hasPotentialMarketsData) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel
|
||||||
|
slotHeaderContent={
|
||||||
|
<Styled.Title>
|
||||||
|
{stringGetter({ key: STRING_KEYS.ADD_A_MARKET })}
|
||||||
|
<Styled.NewTag>{stringGetter({ key: STRING_KEYS.NEW })}</Styled.NewTag>
|
||||||
|
</Styled.Title>
|
||||||
|
}
|
||||||
|
slotRight={
|
||||||
|
<Styled.Arrow>
|
||||||
|
<Styled.IconButton
|
||||||
|
action={ButtonAction.Base}
|
||||||
|
iconName={IconName.Arrow}
|
||||||
|
size={ButtonSize.Small}
|
||||||
|
/>
|
||||||
|
</Styled.Arrow>
|
||||||
|
}
|
||||||
|
onClick={() => navigate(`${AppRoute.Markets}/${MarketsRoute.New}`)}
|
||||||
|
>
|
||||||
|
<Styled.Description>
|
||||||
|
{stringGetter({
|
||||||
|
key: STRING_KEYS.NEW_MARKET_REWARDS_ENTRY_DESCRIPTION,
|
||||||
|
params: {
|
||||||
|
REQUIRED_NUM_TOKENS: (
|
||||||
|
<Styled.Output
|
||||||
|
useGrouping
|
||||||
|
type={OutputType.Number}
|
||||||
|
value={initialDepositAmountBN}
|
||||||
|
fractionDigits={initialDepositAmountDecimals}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
NATIVE_TOKEN_DENOM: chainTokenLabel,
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
</Styled.Description>
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.Description = styled.div`
|
||||||
|
color: var(--color-text-0);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.IconButton = styled(IconButton)`
|
||||||
|
color: var(--color-text-0);
|
||||||
|
--color-border: var(--color-layer-6);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Arrow = styled.div`
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Title = styled.h3`
|
||||||
|
font: var(--font-medium-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
margin-bottom: -1rem;
|
||||||
|
${layoutMixins.inlineRow}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Output = styled(Output)`
|
||||||
|
display: inline-block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.NewTag = styled(Tag)`
|
||||||
|
color: var(--color-accent);
|
||||||
|
background-color: var(--color-accent-faded);
|
||||||
|
`;
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
|
||||||
|
import { useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
|
import {
|
||||||
|
HISTORICAL_TRADING_REWARDS_PERIODS,
|
||||||
|
HistoricalTradingRewardsPeriod,
|
||||||
|
HistoricalTradingRewardsPeriods,
|
||||||
|
} from '@/constants/abacus';
|
||||||
|
|
||||||
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import breakpoints from '@/styles/breakpoints';
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
|
import { Panel } from '@/components/Panel';
|
||||||
|
import { ToggleGroup } from '@/components/ToggleGroup';
|
||||||
|
import { WithTooltip } from '@/components/WithTooltip';
|
||||||
|
import { TradingRewardHistoryTable } from '@/views/tables/TradingRewardHistoryTable';
|
||||||
|
|
||||||
|
import abacusStateManager from '@/lib/abacus';
|
||||||
|
|
||||||
|
export const RewardHistoryPanel = () => {
|
||||||
|
const stringGetter = useStringGetter();
|
||||||
|
|
||||||
|
const [selectedPeriod, setSelectedPeriod] = useState<HistoricalTradingRewardsPeriods>(
|
||||||
|
abacusStateManager.getHistoricalTradingRewardPeriod() || HistoricalTradingRewardsPeriod.WEEKLY
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectPeriod = useCallback(
|
||||||
|
(periodName: string) => {
|
||||||
|
const selectedPeriod =
|
||||||
|
HISTORICAL_TRADING_REWARDS_PERIODS[
|
||||||
|
periodName as keyof typeof HISTORICAL_TRADING_REWARDS_PERIODS
|
||||||
|
];
|
||||||
|
setSelectedPeriod(selectedPeriod);
|
||||||
|
abacusStateManager.setHistoricalTradingRewardPeriod(selectedPeriod);
|
||||||
|
},
|
||||||
|
[setSelectedPeriod, selectedPeriod]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel
|
||||||
|
slotHeader={
|
||||||
|
<Styled.Header>
|
||||||
|
<Styled.Title>
|
||||||
|
<WithTooltip tooltip="reward-history">
|
||||||
|
<h3>{stringGetter({ key: STRING_KEYS.REWARD_HISTORY })}</h3>
|
||||||
|
</WithTooltip>
|
||||||
|
<span>{stringGetter({ key: STRING_KEYS.REWARD_HISTORY_DESCRIPTION })}</span>
|
||||||
|
</Styled.Title>
|
||||||
|
<ToggleGroup
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
value: HistoricalTradingRewardsPeriod.MONTHLY.name,
|
||||||
|
label: stringGetter({ key: STRING_KEYS.MONTHLY }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: HistoricalTradingRewardsPeriod.WEEKLY.name,
|
||||||
|
label: stringGetter({ key: STRING_KEYS.WEEKLY }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: HistoricalTradingRewardsPeriod.DAILY.name,
|
||||||
|
label: stringGetter({ key: STRING_KEYS.DAILY }),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
value={selectedPeriod.name}
|
||||||
|
onValueChange={onSelectPeriod}
|
||||||
|
/>
|
||||||
|
</Styled.Header>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<TradingRewardHistoryTable period={selectedPeriod} />
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.Header = styled.div`
|
||||||
|
${layoutMixins.spacedRow}
|
||||||
|
|
||||||
|
padding: 1rem 1rem 0;
|
||||||
|
margin-bottom: -0.5rem;
|
||||||
|
|
||||||
|
@media ${breakpoints.notTablet} {
|
||||||
|
padding: 1.25rem 1.5rem 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Title = styled.div`
|
||||||
|
${layoutMixins.column}
|
||||||
|
color: var(--color-text-0);
|
||||||
|
font: var(--font-small-book);
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font: var(--font-medium-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Content = styled.div`
|
||||||
|
${layoutMixins.flexColumn}
|
||||||
|
gap: 0.75rem;
|
||||||
|
`;
|
||||||
@@ -29,20 +29,18 @@ export const RewardsHelpPanel = () => {
|
|||||||
>
|
>
|
||||||
<Accordion
|
<Accordion
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
header: 'Who is eligible for trading rewards?',
|
header: stringGetter({ key: STRING_KEYS.FAQ_WHO_IS_ELIGIBLE_QUESTION }),
|
||||||
content: 'All traders are eligible for trading rewards.',
|
content: stringGetter({ key: STRING_KEYS.FAQ_WHO_IS_ELIGIBLE_ANSWER }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'How do trading rewards work?',
|
header: stringGetter({ key: STRING_KEYS.FAQ_HOW_DO_TRADING_REWARDS_WORK_QUESTION }),
|
||||||
content:
|
content: stringGetter({ key: STRING_KEYS.FAQ_HOW_DO_TRADING_REWARDS_WORK_ANSWER }),
|
||||||
'Immediately after each fill, trading rewards are sent directly to the trader’s dYdX Chain address, based on the amount of fees paid by the trader.',
|
},
|
||||||
},
|
{
|
||||||
{
|
header: stringGetter({ key: STRING_KEYS.FAQ_HOW_DO_I_CLAIM_MY_REWARDS_QUESTION }),
|
||||||
header: 'How do I claim my rewards?',
|
content: stringGetter({ key: STRING_KEYS.FAQ_HOW_DO_I_CLAIM_MY_REWARDS_ANSWER }),
|
||||||
content:
|
},
|
||||||
'Each block, trading rewards are automatically sent directly to the trader’s dYdX Chain address.',
|
|
||||||
},
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Styled.HelpCard>
|
</Styled.HelpCard>
|
||||||
@@ -72,7 +70,7 @@ Styled.Header = styled.div`
|
|||||||
font: var(--font-small-book);
|
font: var(--font-small-book);
|
||||||
|
|
||||||
@media ${breakpoints.notTablet} {
|
@media ${breakpoints.notTablet} {
|
||||||
padding: 1.5rem 1.25rem;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent, css } from 'styled-components';
|
||||||
import { useDispatch } from 'react-redux';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
@@ -11,17 +10,20 @@ import { breakpoints } from '@/styles';
|
|||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
import { BackButton } from '@/components/BackButton';
|
import { BackButton } from '@/components/BackButton';
|
||||||
import { Panel } from '@/components/Panel';
|
|
||||||
|
import { testFlags } from '@/lib/testFlags';
|
||||||
|
|
||||||
import { DYDXBalancePanel } from './DYDXBalancePanel';
|
import { DYDXBalancePanel } from './DYDXBalancePanel';
|
||||||
import { MigratePanel } from './MigratePanel';
|
|
||||||
import { LaunchIncentivesPanel } from './LaunchIncentivesPanel';
|
import { LaunchIncentivesPanel } from './LaunchIncentivesPanel';
|
||||||
|
import { MigratePanel } from './MigratePanel';
|
||||||
import { RewardsHelpPanel } from './RewardsHelpPanel';
|
import { RewardsHelpPanel } from './RewardsHelpPanel';
|
||||||
|
import { TradingRewardsSummaryPanel } from './TradingRewardsSummaryPanel';
|
||||||
|
import { RewardHistoryPanel } from './RewardHistoryPanel';
|
||||||
import { GovernancePanel } from './GovernancePanel';
|
import { GovernancePanel } from './GovernancePanel';
|
||||||
import { StakingPanel } from './StakingPanel';
|
import { StakingPanel } from './StakingPanel';
|
||||||
|
import { NewMarketsPanel } from './NewMarketsPanel';
|
||||||
|
|
||||||
const RewardsPage = () => {
|
const RewardsPage = () => {
|
||||||
const dispatch = useDispatch();
|
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { isTablet, isNotTablet } = useBreakpoints();
|
const { isTablet, isNotTablet } = useBreakpoints();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -34,25 +36,38 @@ const RewardsPage = () => {
|
|||||||
{stringGetter({ key: STRING_KEYS.TRADING_REWARDS })}
|
{stringGetter({ key: STRING_KEYS.TRADING_REWARDS })}
|
||||||
</Styled.MobileHeader>
|
</Styled.MobileHeader>
|
||||||
)}
|
)}
|
||||||
{import.meta.env.VITE_V3_TOKEN_ADDRESS && isNotTablet && <MigratePanel />}
|
<Styled.GridLayout
|
||||||
|
showTradingRewards={testFlags.showTradingRewards}
|
||||||
|
showMigratePanel={import.meta.env.VITE_V3_TOKEN_ADDRESS && isNotTablet}
|
||||||
|
>
|
||||||
|
{import.meta.env.VITE_V3_TOKEN_ADDRESS && isNotTablet && <Styled.MigratePanel />}
|
||||||
|
|
||||||
{isTablet ? (
|
{isTablet ? (
|
||||||
<LaunchIncentivesPanel />
|
<Styled.LaunchIncentivesPanel />
|
||||||
) : (
|
) : (
|
||||||
<Styled.PanelRowIncentivesAndBalance>
|
<>
|
||||||
<LaunchIncentivesPanel />
|
<Styled.LaunchIncentivesPanel />
|
||||||
<DYDXBalancePanel />
|
<Styled.DYDXBalancePanel />
|
||||||
</Styled.PanelRowIncentivesAndBalance>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isNotTablet && (
|
{testFlags.showTradingRewards && (
|
||||||
<Styled.PanelRow>
|
<Styled.TradingRewardsColumn>
|
||||||
<GovernancePanel />
|
<TradingRewardsSummaryPanel />
|
||||||
<StakingPanel />
|
{isTablet && <RewardsHelpPanel />}
|
||||||
</Styled.PanelRow>
|
<RewardHistoryPanel />
|
||||||
)}
|
</Styled.TradingRewardsColumn>
|
||||||
|
)}
|
||||||
|
|
||||||
<RewardsHelpPanel />
|
{isNotTablet && (
|
||||||
|
<Styled.OtherColumn showTradingRewards={testFlags.showTradingRewards}>
|
||||||
|
<NewMarketsPanel />
|
||||||
|
<GovernancePanel />
|
||||||
|
<StakingPanel />
|
||||||
|
<RewardsHelpPanel />
|
||||||
|
</Styled.OtherColumn>
|
||||||
|
)}
|
||||||
|
</Styled.GridLayout>
|
||||||
</Styled.Page>
|
</Styled.Page>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -63,7 +78,6 @@ const Styled: Record<string, AnyStyledComponent> = {};
|
|||||||
|
|
||||||
Styled.Page = styled.div`
|
Styled.Page = styled.div`
|
||||||
${layoutMixins.contentContainerPage}
|
${layoutMixins.contentContainerPage}
|
||||||
gap: 1.5rem;
|
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
@@ -88,27 +102,98 @@ Styled.MobileHeader = styled.header`
|
|||||||
${layoutMixins.stickyHeader}
|
${layoutMixins.stickyHeader}
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
padding: 1.25rem 0;
|
padding: 1.25rem 0;
|
||||||
margin-bottom: -1.5rem;
|
|
||||||
|
|
||||||
font: var(--font-large-medium);
|
font: var(--font-large-medium);
|
||||||
color: var(--color-text-2);
|
color: var(--color-text-2);
|
||||||
background-color: var(--color-layer-2);
|
background-color: var(--color-layer-2);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Panel = styled(Panel)`
|
Styled.GridLayout = styled.div<{ showTradingRewards?: boolean; showMigratePanel?: boolean }>`
|
||||||
height: fit-content;
|
--gap: 1.5rem;
|
||||||
`;
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 1fr;
|
||||||
|
gap: var(--gap);
|
||||||
|
|
||||||
Styled.PanelRow = styled.div`
|
> * {
|
||||||
${layoutMixins.gridEqualColumns}
|
gap: var(--gap);
|
||||||
gap: 1.5rem;
|
}
|
||||||
|
|
||||||
|
${({ showTradingRewards, showMigratePanel }) =>
|
||||||
|
showTradingRewards && showMigratePanel
|
||||||
|
? css`
|
||||||
|
grid-template-areas:
|
||||||
|
'migrate migrate'
|
||||||
|
'incentives balance'
|
||||||
|
'rewards other';
|
||||||
|
`
|
||||||
|
: showTradingRewards
|
||||||
|
? css`
|
||||||
|
grid-template-areas: 'incentives balance' 'rewards other';
|
||||||
|
`
|
||||||
|
: showMigratePanel
|
||||||
|
? css`
|
||||||
|
grid-template-areas: 'migrate migrate' 'incentives balance' 'other other';
|
||||||
|
`
|
||||||
|
: css`
|
||||||
|
grid-template-areas: 'incentives balance' 'other other';
|
||||||
|
`};
|
||||||
|
|
||||||
@media ${breakpoints.tablet} {
|
@media ${breakpoints.tablet} {
|
||||||
grid-auto-flow: row;
|
--gap: 1rem;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
${({ showTradingRewards }) =>
|
||||||
|
showTradingRewards
|
||||||
|
? css`
|
||||||
|
grid-template-areas:
|
||||||
|
'incentives'
|
||||||
|
'rewards';
|
||||||
|
`
|
||||||
|
: css`
|
||||||
|
grid-template-areas: 'incentives';
|
||||||
|
`}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.PanelRowIncentivesAndBalance = styled(Styled.PanelRow)`
|
Styled.MigratePanel = styled(MigratePanel)`
|
||||||
grid-template-columns: 2fr 1fr;
|
grid-area: migrate;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.LaunchIncentivesPanel = styled(LaunchIncentivesPanel)`
|
||||||
|
grid-area: incentives;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.DYDXBalancePanel = styled(DYDXBalancePanel)`
|
||||||
|
grid-area: balance;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.TradingRewardsColumn = styled.div`
|
||||||
|
grid-area: rewards;
|
||||||
|
${layoutMixins.flexColumn}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.OtherColumn = styled.div<{ showTradingRewards?: boolean }>`
|
||||||
|
grid-area: other;
|
||||||
|
${layoutMixins.flexColumn}
|
||||||
|
|
||||||
|
${({ showTradingRewards }) =>
|
||||||
|
!showTradingRewards &&
|
||||||
|
css`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
|
||||||
|
> section:last-of-type {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.RewardHistoryHeader = styled.div`
|
||||||
|
h3 {
|
||||||
|
font: var(--font-medium-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
padding: 1rem 1.5rem 0;
|
||||||
|
margin-bottom: -0.5rem;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
import { useStringGetter, useTokenConfigs } from '@/hooks';
|
||||||
|
|
||||||
|
import { AssetIcon } from '@/components/AssetIcon';
|
||||||
|
import { Details } from '@/components/Details';
|
||||||
|
import { Output, OutputType } from '@/components/Output';
|
||||||
|
import { Panel } from '@/components/Panel';
|
||||||
|
|
||||||
|
import { getHistoricalTradingRewardsForCurrentWeek } from '@/state/accountSelectors';
|
||||||
|
|
||||||
|
import abacusStateManager from '@/lib/abacus';
|
||||||
|
|
||||||
|
export const TradingRewardsSummaryPanel = () => {
|
||||||
|
const stringGetter = useStringGetter();
|
||||||
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
const currentWeekTradingReward = useSelector(getHistoricalTradingRewardsForCurrentWeek, shallowEqual);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
abacusStateManager.refreshHistoricalTradingRewards();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return !currentWeekTradingReward ? null : (
|
||||||
|
<Panel
|
||||||
|
slotHeader={
|
||||||
|
<Styled.Header>{stringGetter({ key: STRING_KEYS.TRADING_REWARDS_SUMMARY })}</Styled.Header>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Styled.Content>
|
||||||
|
<Styled.TradingRewardsDetails
|
||||||
|
layout="grid"
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: 'week',
|
||||||
|
label: (
|
||||||
|
<Styled.Label>
|
||||||
|
<h4>{stringGetter({ key: STRING_KEYS.THIS_WEEK })}</h4>
|
||||||
|
</Styled.Label>
|
||||||
|
),
|
||||||
|
value: (
|
||||||
|
<Styled.Column>
|
||||||
|
<Output
|
||||||
|
slotRight={<Styled.AssetIcon symbol={chainTokenLabel} />}
|
||||||
|
type={OutputType.Asset}
|
||||||
|
value={currentWeekTradingReward.amount}
|
||||||
|
/>
|
||||||
|
<Styled.TimePeriod>
|
||||||
|
<Output
|
||||||
|
type={OutputType.Date}
|
||||||
|
value={currentWeekTradingReward.startedAtInMilliseconds}
|
||||||
|
timeOptions={{ useUTC: true }}
|
||||||
|
/>
|
||||||
|
→
|
||||||
|
<Output
|
||||||
|
type={OutputType.Date}
|
||||||
|
value={currentWeekTradingReward.endedAtInMilliseconds}
|
||||||
|
timeOptions={{ useUTC: true }}
|
||||||
|
/>
|
||||||
|
</Styled.TimePeriod>
|
||||||
|
</Styled.Column>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
// TODO(@aforaleka): add all-time when supported
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Styled.Content>
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.Header = styled.div`
|
||||||
|
padding: var(--panel-paddingY) var(--panel-paddingX) 0;
|
||||||
|
font: var(--font-medium-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Content = styled.div`
|
||||||
|
${layoutMixins.flexColumn}
|
||||||
|
gap: 0.75rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.TradingRewardsDetails = styled(Details)`
|
||||||
|
--details-item-backgroundColor: var(--color-layer-6);
|
||||||
|
|
||||||
|
grid-template-columns: 1fr; // TODO(@aforaleka): change to 1fr 1fr when all-time is supported
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0.75em;
|
||||||
|
background-color: var(--color-layer-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
output {
|
||||||
|
color: var(--color-text-2);
|
||||||
|
font: var(--font-large-book);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Label = styled.div`
|
||||||
|
${layoutMixins.spacedRow}
|
||||||
|
|
||||||
|
font: var(--font-base-book);
|
||||||
|
color: var(--color-text-1);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.TimePeriod = styled.div`
|
||||||
|
${layoutMixins.inlineRow}
|
||||||
|
|
||||||
|
&, output {
|
||||||
|
color: var(--color-text-0);
|
||||||
|
font: var(--font-small-book);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Column = styled.div`
|
||||||
|
${layoutMixins.flexColumn}
|
||||||
|
gap: 0.33rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.AssetIcon = styled(AssetIcon)`
|
||||||
|
margin-left: 0.5ch;
|
||||||
|
`;
|
||||||
@@ -13,6 +13,7 @@ import type {
|
|||||||
HistoricalPnlPeriods,
|
HistoricalPnlPeriods,
|
||||||
SubAccountHistoricalPNLs,
|
SubAccountHistoricalPNLs,
|
||||||
UsageRestriction,
|
UsageRestriction,
|
||||||
|
TradingRewards,
|
||||||
} from '@/constants/abacus';
|
} from '@/constants/abacus';
|
||||||
|
|
||||||
import { OnboardingGuard, OnboardingState } from '@/constants/account';
|
import { OnboardingGuard, OnboardingState } from '@/constants/account';
|
||||||
@@ -24,6 +25,7 @@ import { getLocalStorage } from '@/lib/localStorage';
|
|||||||
export type AccountState = {
|
export type AccountState = {
|
||||||
balances?: Record<string, AccountBalance>;
|
balances?: Record<string, AccountBalance>;
|
||||||
stakingBalances?: Record<string, AccountBalance>;
|
stakingBalances?: Record<string, AccountBalance>;
|
||||||
|
tradingRewards?: TradingRewards;
|
||||||
wallet?: Nullable<Wallet>;
|
wallet?: Nullable<Wallet>;
|
||||||
walletType?: WalletType;
|
walletType?: WalletType;
|
||||||
|
|
||||||
@@ -179,6 +181,9 @@ export const accountSlice = createSlice({
|
|||||||
setStakingBalances: (state, action: PayloadAction<Record<string, AccountBalance>>) => {
|
setStakingBalances: (state, action: PayloadAction<Record<string, AccountBalance>>) => {
|
||||||
state.stakingBalances = action.payload;
|
state.stakingBalances = action.payload;
|
||||||
},
|
},
|
||||||
|
setTradingRewards: (state, action: PayloadAction<TradingRewards>) => {
|
||||||
|
state.tradingRewards = action.payload;
|
||||||
|
},
|
||||||
addUncommittedOrderClientId: (state, action: PayloadAction<number>) => {
|
addUncommittedOrderClientId: (state, action: PayloadAction<number>) => {
|
||||||
state.uncommittedOrderClientIds.push(action.payload);
|
state.uncommittedOrderClientIds.push(action.payload);
|
||||||
},
|
},
|
||||||
@@ -206,6 +211,7 @@ export const {
|
|||||||
viewedOrders,
|
viewedOrders,
|
||||||
setBalances,
|
setBalances,
|
||||||
setStakingBalances,
|
setStakingBalances,
|
||||||
|
setTradingRewards,
|
||||||
addUncommittedOrderClientId,
|
addUncommittedOrderClientId,
|
||||||
removeUncommittedOrderClientId,
|
removeUncommittedOrderClientId,
|
||||||
} = accountSlice.actions;
|
} = accountSlice.actions;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Nullable, kollections } from '@dydxprotocol/v4-abacus';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
@@ -9,6 +10,8 @@ import {
|
|||||||
AbacusOrderStatus,
|
AbacusOrderStatus,
|
||||||
AbacusPositionSide,
|
AbacusPositionSide,
|
||||||
ORDER_SIDES,
|
ORDER_SIDES,
|
||||||
|
HistoricalTradingReward,
|
||||||
|
HistoricalTradingRewardsPeriod,
|
||||||
} from '@/constants/abacus';
|
} from '@/constants/abacus';
|
||||||
|
|
||||||
import { OnboardingState } from '@/constants/account';
|
import { OnboardingState } from '@/constants/account';
|
||||||
@@ -349,6 +352,38 @@ export const getBalances = (state: RootState) => state.account?.balances;
|
|||||||
* */
|
* */
|
||||||
export const getStakingBalances = (state: RootState) => state.account?.stakingBalances;
|
export const getStakingBalances = (state: RootState) => state.account?.stakingBalances;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns account all time trading rewards
|
||||||
|
*/
|
||||||
|
export const getTotalTradingRewards = (state: RootState) => state.account?.tradingRewards?.total;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns account trading rewards aggregated by period
|
||||||
|
*/
|
||||||
|
export const getHistoricalTradingRewards = (state: RootState) =>
|
||||||
|
state.account?.tradingRewards?.historical;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns account historical trading rewards for the specified perid
|
||||||
|
*/
|
||||||
|
export const getHistoricalTradingRewardsForPeriod = (period: string) =>
|
||||||
|
createSelector(
|
||||||
|
[getHistoricalTradingRewards],
|
||||||
|
(
|
||||||
|
historicalTradingRewards: Nullable<
|
||||||
|
kollections.Map<string, kollections.List<HistoricalTradingReward>>
|
||||||
|
>
|
||||||
|
) => historicalTradingRewards?.get(period)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns account historical trading rewards for the current week
|
||||||
|
*/
|
||||||
|
export const getHistoricalTradingRewardsForCurrentWeek = createSelector(
|
||||||
|
[getHistoricalTradingRewardsForPeriod(HistoricalTradingRewardsPeriod.WEEKLY.name)],
|
||||||
|
(historicalTradingRewards) => historicalTradingRewards?.firstOrNull()
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns UsageRestriction of the current session
|
* @returns UsageRestriction of the current session
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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`
|
||||||
|
|||||||
@@ -3,23 +3,26 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components';
|
import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { ButtonSize } from '@/constants/buttons';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { MarketFilters, type MarketData } from '@/constants/markets';
|
import { MarketFilters, type MarketData } from '@/constants/markets';
|
||||||
import { AppRoute } from '@/constants/routes';
|
import { AppRoute, MarketsRoute } from '@/constants/routes';
|
||||||
|
|
||||||
import { useStringGetter } from '@/hooks';
|
import { useStringGetter } from '@/hooks';
|
||||||
|
import { useMarketsData } from '@/hooks/useMarketsData';
|
||||||
|
import { usePotentialMarkets } from '@/hooks/usePotentialMarkets';
|
||||||
|
|
||||||
import { popoverMixins } from '@/styles/popoverMixins';
|
import { popoverMixins } from '@/styles/popoverMixins';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
import { AssetIcon } from '@/components/AssetIcon';
|
import { AssetIcon } from '@/components/AssetIcon';
|
||||||
|
import { Button } from '@/components/Button';
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
import { Output, OutputType } from '@/components/Output';
|
import { Output, OutputType } from '@/components/Output';
|
||||||
import { Popover, TriggerType } from '@/components/Popover';
|
import { Popover, TriggerType } from '@/components/Popover';
|
||||||
|
import { ColumnDef, Table } from '@/components/Table';
|
||||||
import { Tag } from '@/components/Tag';
|
import { Tag } from '@/components/Tag';
|
||||||
import { Toolbar } from '@/components/Toolbar';
|
import { Toolbar } from '@/components/Toolbar';
|
||||||
import { ColumnDef, Table } from '@/components/Table';
|
|
||||||
|
|
||||||
import { useMarketsData } from '@/hooks/useMarketsData';
|
|
||||||
import { getSelectedLocale } from '@/state/localizationSelectors';
|
import { getSelectedLocale } from '@/state/localizationSelectors';
|
||||||
|
|
||||||
import { MustBigNumber } from '@/lib/numbers';
|
import { MustBigNumber } from '@/lib/numbers';
|
||||||
@@ -32,6 +35,8 @@ const MarketsDropdownContent = ({ onRowAction }: { onRowAction?: (market: string
|
|||||||
const selectedLocale = useSelector(getSelectedLocale);
|
const selectedLocale = useSelector(getSelectedLocale);
|
||||||
const [searchFilter, setSearchFilter] = useState<string>();
|
const [searchFilter, setSearchFilter] = useState<string>();
|
||||||
const { filteredMarkets, marketFilters } = useMarketsData(filter, searchFilter);
|
const { filteredMarkets, marketFilters } = useMarketsData(filter, searchFilter);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { hasPotentialMarketsData } = usePotentialMarkets();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -134,16 +139,16 @@ const MarketsDropdownContent = ({ onRowAction }: { onRowAction?: (market: string
|
|||||||
})}
|
})}
|
||||||
</h2>
|
</h2>
|
||||||
<p>{stringGetter({ key: STRING_KEYS.MARKET_SEARCH_DOES_NOT_EXIST_YET })}</p>
|
<p>{stringGetter({ key: STRING_KEYS.MARKET_SEARCH_DOES_NOT_EXIST_YET })}</p>
|
||||||
{/* TODO TRCL-1693 - uncomment when feedback modal is finalized
|
{hasPotentialMarketsData && (
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
// TODO: uncomment when feedback modal is finalized
|
onClick={() => navigate(`${AppRoute.Markets}/${MarketsRoute.New}`)}
|
||||||
// onClick={() => dispatch(openModal({ modalType: MODALS.FEEDBACK }))}
|
size={ButtonSize.Small}
|
||||||
size={ButtonSize.Small}
|
>
|
||||||
>
|
{stringGetter({ key: STRING_KEYS.PROPOSE_NEW_MARKET })}
|
||||||
{stringGetter({ key: STRING_KEYS.GIVE_FEEDBACK })}
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div> */}
|
)}
|
||||||
</Styled.MarketNotFound>
|
</Styled.MarketNotFound>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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`
|
||||||
|
|||||||
@@ -0,0 +1,349 @@
|
|||||||
|
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 { Dialog } from '@/components/Dialog';
|
||||||
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
|
import { HorizontalSeparatorFiller } from '@/components/Separator';
|
||||||
|
|
||||||
|
type ElementProps = {
|
||||||
|
setIsOpen: (open: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DisplaySettingsDialog = ({ setIsOpen }: ElementProps) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const stringGetter = useStringGetter();
|
||||||
|
|
||||||
|
const currentThemeSetting: AppThemeSetting = useSelector(getAppThemeSetting);
|
||||||
|
const currentTheme: AppTheme = useSelector(getAppTheme);
|
||||||
|
const currentColorMode: AppColorMode = useSelector(getAppColorMode);
|
||||||
|
|
||||||
|
const sectionHeader = (heading: string) => {
|
||||||
|
return (
|
||||||
|
<Styled.Header>
|
||||||
|
{heading}
|
||||||
|
{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
|
||||||
|
? globalThis.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
? AppTheme.Dark
|
||||||
|
: AppTheme.Light
|
||||||
|
: 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.ArrowIconContainer>
|
||||||
|
<Styled.ArrowIcon
|
||||||
|
iconName={IconName.Arrow}
|
||||||
|
direction="up"
|
||||||
|
color={colorMode === AppColorMode.GreenUp ? 'green' : 'red'}
|
||||||
|
/>
|
||||||
|
<Styled.ArrowIcon
|
||||||
|
iconName={IconName.Arrow}
|
||||||
|
direction="down"
|
||||||
|
color={colorMode === AppColorMode.GreenUp ? 'red' : 'green'}
|
||||||
|
/>
|
||||||
|
</Styled.ArrowIconContainer>
|
||||||
|
{stringGetter({ key: label })}
|
||||||
|
</Styled.ColorPreferenceLabel>
|
||||||
|
<Styled.DotIndicator $selected={currentColorMode === colorMode} />
|
||||||
|
</Styled.ColorPreferenceItem>
|
||||||
|
))}
|
||||||
|
</Styled.ColorPreferenceRoot>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
isOpen
|
||||||
|
setIsOpen={setIsOpen}
|
||||||
|
title={stringGetter({ key: STRING_KEYS.DISPLAY_SETTINGS })}
|
||||||
|
>
|
||||||
|
<Styled.Section>
|
||||||
|
{sectionHeader(stringGetter({ key: STRING_KEYS.THEME }))}
|
||||||
|
{themePanels()}
|
||||||
|
</Styled.Section>
|
||||||
|
<Styled.Section>
|
||||||
|
{sectionHeader(stringGetter({ key: STRING_KEYS.DIRECTION_COLOR_PREFERENCE }))}
|
||||||
|
{colorModeOptions()}
|
||||||
|
</Styled.Section>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
const gridStyle = css`
|
||||||
|
display: grid;
|
||||||
|
gap: 1.5rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Section = styled.div`
|
||||||
|
${gridStyle}
|
||||||
|
padding: 1rem 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Header = styled.header`
|
||||||
|
${layoutMixins.inlineRow}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.AppThemeRoot = styled(Root)`
|
||||||
|
${gridStyle}
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.ColorPreferenceRoot = styled(Root)`
|
||||||
|
${gridStyle}
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Item = styled(Item)`
|
||||||
|
--border-color: var(--color-border);
|
||||||
|
--item-padding: 0.75rem;
|
||||||
|
|
||||||
|
&[data-state='checked'] {
|
||||||
|
--border-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
border: solid var(--border-width) var(--border-color);
|
||||||
|
border-radius: 0.875rem;
|
||||||
|
|
||||||
|
padding: var(--item-padding);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.ColorPreferenceItem = styled(Styled.Item)`
|
||||||
|
&[data-state='checked'] {
|
||||||
|
background-color: var(--color-layer-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
${layoutMixins.row}
|
||||||
|
justify-content: space-between;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.AppThemeItem = styled(Styled.Item)<{ backgroundcolor: string; gridcolor: string }>`
|
||||||
|
${({ backgroundcolor, gridcolor }) => css`
|
||||||
|
--themePanel-backgroundColor: ${backgroundcolor};
|
||||||
|
--themePanel-gridColor: ${gridcolor};
|
||||||
|
`}
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
background-color: var(--themePanel-backgroundColor);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
border-radius: 0.875rem;
|
||||||
|
|
||||||
|
background: radial-gradient(
|
||||||
|
55% 35% at 50% 65%,
|
||||||
|
transparent,
|
||||||
|
var(--themePanel-backgroundColor) 100%
|
||||||
|
);
|
||||||
|
background-color: var(--themePanel-gridColor);
|
||||||
|
mask-image: url('/chart-bars-background.svg');
|
||||||
|
mask-size: cover;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.AppThemeHeader = styled.h3<{ textcolor: string }>`
|
||||||
|
${({ textcolor }) => css`
|
||||||
|
color: ${textcolor};
|
||||||
|
`}
|
||||||
|
z-index: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Image = styled.img`
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
z-index: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.ColorPreferenceLabel = styled.div`
|
||||||
|
${layoutMixins.inlineRow};
|
||||||
|
gap: 1ch;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.ArrowIconContainer = styled.div`
|
||||||
|
${layoutMixins.column}
|
||||||
|
gap: 0.5ch;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
height: 0.75em;
|
||||||
|
width: 0.75em;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.ArrowIcon = styled(Icon)<{ direction: 'up' | 'down'; color: 'green' | 'red' }>`
|
||||||
|
${({ direction }) =>
|
||||||
|
({
|
||||||
|
['up']: css`
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
`,
|
||||||
|
['down']: css`
|
||||||
|
transform: rotate(90deg);
|
||||||
|
`,
|
||||||
|
}[direction])}
|
||||||
|
|
||||||
|
${({ color }) =>
|
||||||
|
({
|
||||||
|
['green']: css`
|
||||||
|
color: var(--color-success);
|
||||||
|
`,
|
||||||
|
['red']: css`
|
||||||
|
color: var(--color-error);
|
||||||
|
`,
|
||||||
|
}[color])}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const indicatorStyle = css`
|
||||||
|
--indicator-size: 1.25rem;
|
||||||
|
--icon-size: 0.5rem;
|
||||||
|
|
||||||
|
height: var(--indicator-size);
|
||||||
|
width: var(--indicator-size);
|
||||||
|
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.DotIndicator = styled.div<{ $selected: boolean }>`
|
||||||
|
${indicatorStyle}
|
||||||
|
--background-color: var(--color-layer-2);
|
||||||
|
--border-color: var(--color-border);
|
||||||
|
|
||||||
|
${({ $selected }) =>
|
||||||
|
$selected &&
|
||||||
|
css`
|
||||||
|
--background-color: var(--color-accent);
|
||||||
|
--border-color: var(--color-accent);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: var(--icon-size);
|
||||||
|
height: var(--icon-size);
|
||||||
|
background-color: var(--color-layer-2);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
|
||||||
|
background-color: var(--background-color);
|
||||||
|
border: solid var(--border-width) var(--border-color);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.CheckIndicator = styled(Indicator)`
|
||||||
|
${indicatorStyle}
|
||||||
|
position: absolute;
|
||||||
|
bottom: var(--item-padding);
|
||||||
|
right: var(--item-padding);
|
||||||
|
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
color: var(--color-text-button);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.CheckIcon = styled(Icon)`
|
||||||
|
width: var(--icon-size);
|
||||||
|
height: var(--icon-size);
|
||||||
|
`;
|
||||||