Compare commits

..
Author SHA1 Message Date
Bill He a21558ad88 do not use TESTNET_CHAIN_ID 2023-11-06 16:07:55 -08:00
332 changed files with 5699 additions and 64331 deletions
-7
View File
@@ -8,14 +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=
STATUS_PAGE_SCRIPT_URI= STATUS_PAGE_SCRIPT_URI=
SMARTBANNER_APP_NAME=
SMARTBANNER_ORG_NAME=
SMARTBANNER_ICON_URL=
SMARTBANNER_APPSTORE_URL=
SMARTBANNER_GOOGLEPLAY_URL=
-1
View File
@@ -39,7 +39,6 @@ jobs:
pnpm run build:inject-amplitude pnpm run build:inject-amplitude
pnpm run build:inject-bugsnag pnpm run build:inject-bugsnag
pnpm run build:inject-statuspage pnpm run build:inject-statuspage
pnpm run build:inject-smartbanner
sh scripts/inject-app-deeplinks.sh sh scripts/inject-app-deeplinks.sh
- name: Upload to IPFS via web3.storage - name: Upload to IPFS via web3.storage
+33 -91
View File
@@ -2,132 +2,74 @@ import '@/polyfills';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import { WagmiConfig } from 'wagmi';
import { GrazProvider } from 'graz';
import { QueryClient, QueryClientProvider } from 'react-query';
import { SupportedLocales } from '@/constants/localization'; import { store } from '@/state/_store';
import { AccountsProvider } from '@/hooks/useAccounts';
import { AppThemeAndColorModeProvider } from '@/hooks/useAppThemeAndColorMode';
import { DydxProvider } from '@/hooks/useDydxClient';
import { DialogAreaProvider } from '@/hooks/useDialogArea';
import { LocaleProvider } from '@/hooks/useLocaleSeparators';
import { PotentialMarketsProvider } from '@/hooks/usePotentialMarkets';
import { RestrictionProvider } from '@/hooks/useRestrictions';
import { SubaccountProvider } from '@/hooks/useSubaccount';
import { GlobalStyle } from '@/styles/globalStyle';
import { SelectMenu, SelectItem } from '@/components/SelectMenu'; import { SelectMenu, SelectItem } from '@/components/SelectMenu';
import { import { setLocaleLoaded } from '@/state/localization';
AppTheme,
AppThemeSystemSetting,
AppColorMode,
setAppThemeSetting,
setAppColorMode,
} from '@/state/configs';
import { setLocaleLoaded, setSelectedLocale } from '@/state/localization';
import { store } from '@/state/_store';
import { config } from '@/lib/wagmi';
import '@/index.css'; import '@/index.css';
import './ladle.css'; import './ladle.css';
const queryClient = new QueryClient();
const wrapProvider = (Component: React.ComponentType<any>, props?: any) => {
// eslint-disable-next-line react/display-name
return ({ children }: { children: React.ReactNode }) => (
<Component {...props}>{children}</Component>
);
};
const providers = [
wrapProvider(QueryClientProvider, { client: queryClient }),
wrapProvider(GrazProvider),
wrapProvider(WagmiConfig, { config }),
wrapProvider(LocaleProvider),
wrapProvider(RestrictionProvider),
wrapProvider(DydxProvider),
wrapProvider(AccountsProvider),
wrapProvider(SubaccountProvider),
wrapProvider(DialogAreaProvider),
wrapProvider(PotentialMarketsProvider),
wrapProvider(AppThemeAndColorModeProvider),
];
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('Default theme');
const [colorMode, setColorMode] = useState(AppColorMode.GreenUp);
useEffect(() => { useEffect(() => {
store.dispatch(setAppThemeSetting(theme)); switch (theme) {
store.dispatch(setAppColorMode(colorMode)); case 'Dark theme': {
}, [theme, colorMode]); document?.documentElement?.classList.remove('theme-light');
document?.documentElement?.classList.add('theme-dark');
break;
}
case 'Light theme': {
document?.documentElement?.classList.remove('theme-dark');
document?.documentElement?.classList.add('theme-light');
break;
}
default: {
document?.documentElement?.classList.remove('theme-dark', 'theme-light');
break;
}
}
}, [theme]);
useEffect(() => { useEffect(() => {
store.dispatch(setSelectedLocale({ locale: SupportedLocales.EN }));
store.dispatch(setLocaleLoaded(true)); store.dispatch(setLocaleLoaded(true));
}, []); }, []);
const content = [...providers].reverse().reduce(
(children, Provider) => {
return <Provider>{children}</Provider>;
},
<StoryContent>
<GlobalStyle />
{children}
</StoryContent>
);
return ( return (
<Provider store={store}> <Provider store={store}>
<StoryHeader> <StoryHeader>
<h4>Active Theme:</h4> <h4>Active Theme:</h4>
<SelectMenu value={theme} onValueChange={setTheme}> <SelectMenu
value={theme}
onValueChange={setTheme}
>
{[ {[
{ {
value: AppTheme.Classic, value: 'Default theme',
label: 'Default theme', label: 'Default theme',
}, },
{ {
value: AppThemeSystemSetting.System, value: 'Dark theme',
label: 'System theme',
},
{
value: AppTheme.Dark,
label: 'Dark theme', label: 'Dark theme',
}, },
{ {
value: AppTheme.Light, value: 'Light theme',
label: 'Light theme', label: 'Light theme',
}, },
].map(({ value, label }) => ( ].map(({ value, label }) => (
<SelectItem key={value} value={value} label={label} /> <SelectItem
))} key={value}
</SelectMenu> value={value}
<h4>Active Color Mode:</h4> label={label}
<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 />
{content} <StoryContent>{children}</StoryContent>
</Provider> </Provider>
); );
}; };
+1 -10
View File
@@ -78,12 +78,11 @@ 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`.
- `STATUS_PAGE_SCRIPT_URI` (optional): Used for enabling the status page; used with `pnpm run build:inject-statuspage`. - `STATUS_PAGE_SCRIPT_URI` (optional): Used for enabling the status page; used with `pnpm run build:inject-statuspage`.
- `SMARTBANNER_APP_NAME`, `SMARTBANNER_ORG_NAME`, `SMARTBANNER_ICON_URL`, `SMARTBANNER_APPSTORE_URL` (optional): Used for enabling the smart app banner; used with `pnpm run build:inject-smartbanner`.
# Deployments # Deployments
@@ -99,17 +98,9 @@ For the "Build & Development Settings", we recommend the following:
- Framework Preset: `Vite` - Framework Preset: `Vite`
- Build Command (override): `pnpm run build` - Build Command (override): `pnpm run build`
By default, the dev server runs in development mode and the build command runs in production mode. To override the default mode, you can pass in the `--mode` option flag. For example, if you want to build your app for testnet:
```
pnpm run build --mode testnet
```
If you wish to incorporate analytics via Amplitude and Bugsnag, you can use our scripts: If you wish to incorporate analytics via Amplitude and Bugsnag, you can use our scripts:
`pnpm run build:inject-amplitude` and `pnpm run build:inject-bugsnag`. You will need to provide your own API keys for these services. In the Environment Variables section, name the variables as `AMPLITUDE_API_KEY` and `BUGSNAG_API_KEY` and provide the respective keys as their values. `pnpm run build:inject-amplitude` and `pnpm run build:inject-bugsnag`. You will need to provide your own API keys for these services. In the Environment Variables section, name the variables as `AMPLITUDE_API_KEY` and `BUGSNAG_API_KEY` and provide the respective keys as their values.
If you wish to incorporate smart banner for iOS and/or Android apps, you can use our scripts:
`pnpm run build:inject-smartbanner`. You will need to provide your own app configurations for these services. In the Environment Variables section, name the variables as `SMARTBANNER_APP_NAME`, `SMARTBANNER_ORG_NAME`, `SMARTBANNER_ICON_URL` and `SMARTBANNER_APPSTORE_URL` or `SMARTBANNER_GOOGLEPLAY_URL` and provide the respective values.
For more details, check out Vercel's [official documentation](https://vercel.com/docs). For more details, check out Vercel's [official documentation](https://vercel.com/docs).
## Deploying to IPFS ## Deploying to IPFS
+12 -23
View File
@@ -15,7 +15,6 @@
"build:inject-bugsnag": "node scripts/inject-bugsnag.js", "build:inject-bugsnag": "node scripts/inject-bugsnag.js",
"build:inject-intercom": "node scripts/inject-intercom.js", "build:inject-intercom": "node scripts/inject-intercom.js",
"build:inject-statuspage": "node scripts/inject-statuspage.js", "build:inject-statuspage": "node scripts/inject-statuspage.js",
"build:inject-smartbanner": "node scripts/inject-smartbanner.js",
"deploy:ipfs": "node scripts/upload-ipfs.js --verbose", "deploy:ipfs": "node scripts/upload-ipfs.js --verbose",
"deploy:update-ipns": "node scripts/update-ipns.js", "deploy:update-ipns": "node scripts/update-ipns.js",
"deploy:update-dnslink": "node scripts/update-dnslink.js", "deploy:update-dnslink": "node scripts/update-dnslink.js",
@@ -34,23 +33,20 @@
"packageManager": "pnpm@8.6.6", "packageManager": "pnpm@8.6.6",
"dependencies": { "dependencies": {
"@0xsquid/sdk": "^1.10.0", "@0xsquid/sdk": "^1.10.0",
"@cosmjs/amino": "^0.32.1", "@cosmjs/amino": "^0.31.0",
"@cosmjs/crypto": "^0.32.1", "@cosmjs/crypto": "^0.31.0",
"@cosmjs/encoding": "^0.32.1", "@cosmjs/encoding": "^0.31.0",
"@cosmjs/proto-signing": "^0.32.1", "@cosmjs/proto-signing": "^0.31.0",
"@cosmjs/stargate": "^0.32.1", "@cosmjs/stargate": "^0.31.0",
"@cosmjs/tendermint-rpc": "^0.32.1", "@cosmjs/tendermint-rpc": "^0.31.0",
"@dydxprotocol/v4-abacus": "^1.4.2", "@dydxprotocol/v4-abacus": "^1.0.10",
"@dydxprotocol/v4-client-js": "^1.0.20", "@dydxprotocol/v4-client-js": "^1.0.0",
"@dydxprotocol/v4-localization": "^1.1.26", "@dydxprotocol/v4-localization": "^1.0.0",
"@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-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-dialog": "^1.0.4", "@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5", "@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-navigation-menu": "^1.1.3", "@radix-ui/react-navigation-menu": "^1.1.3",
"@radix-ui/react-popover": "^1.0.6", "@radix-ui/react-popover": "^1.0.6",
"@radix-ui/react-radio-group": "^1.1.3", "@radix-ui/react-radio-group": "^1.1.3",
@@ -93,7 +89,6 @@
"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",
@@ -101,7 +96,6 @@
"long": "^5.2.3", "long": "^5.2.3",
"luxon": "^3.3.0", "luxon": "^3.3.0",
"qr-code-styling": "1.6.0-rc.1", "qr-code-styling": "1.6.0-rc.1",
"query-string": "^8.1.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-aria": "^3.25.0", "react-aria": "^3.25.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@@ -113,12 +107,12 @@
"reselect": "^4.1.8", "reselect": "^4.1.8",
"styled-components": "^5.3.11", "styled-components": "^5.3.11",
"use-latest": "^1.2.1", "use-latest": "^1.2.1",
"viem": "^1.20.0", "viem": "^1.12.2",
"wagmi": "^1.4.12" "wagmi": "^1.3.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.22.5", "@babel/core": "^7.22.5",
"@ladle/react": "^4.0.2", "@ladle/react": "^2.15.0",
"@types/color": "^3.0.3", "@types/color": "^3.0.3",
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.1.1",
"@types/luxon": "^3.3.0", "@types/luxon": "^3.3.0",
@@ -157,10 +151,5 @@
"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"
}
} }
} }
+1136 -3093
View File
File diff suppressed because it is too large Load Diff
-22
View File
@@ -1,22 +0,0 @@
[
{
"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"
]
}
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

-19
View File
@@ -1,19 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

-20
View File
@@ -1,20 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 2.2 MiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 2.1 MiB

-12
View File
@@ -1,12 +0,0 @@
[
{
"chainId": "1",
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "Ethereum"
},
{
"chainId": "5",
"tokenAddress": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F",
"name": "Ethereum Goerli"
}
]
-16
View File
@@ -1,16 +0,0 @@
{
"tradingRewardsFAQs": [
{
"questionLocalizationKey": "APP.TRADING_REWARDS.FAQ_WHO_IS_ELIGIBLE_QUESTION",
"answerLocalizationKey": "APP.TRADING_REWARDS.FAQ_WHO_IS_ELIGIBLE_ANSWER"
},
{
"questionLocalizationKey": "APP.TRADING_REWARDS.FAQ_HOW_DO_TRADING_REWARDS_WORK_QUESTION",
"answerLocalizationKey": "APP.TRADING_REWARDS.FAQ_HOW_DO_TRADING_REWARDS_WORK_ANSWER"
},
{
"questionLocalizationKey": "APP.TRADING_REWARDS.FAQ_HOW_DO_I_CLAIM_MY_REWARDS_QUESTION",
"answerLocalizationKey": "APP.TRADING_REWARDS.FAQ_HOW_DO_I_CLAIM_MY_REWARDS_ANSWER"
}
]
}
+75 -336
View File
@@ -1,7 +1,7 @@
{ {
"apps": { "apps": {
"ios": { "iOS": {
"scheme": "dydx-t-v4" "scheme": "dydxv4"
} }
}, },
"deployments": { "deployments": {
@@ -11,13 +11,6 @@
], ],
"default": "dydxprotocol-mainnet" "default": "dydxprotocol-mainnet"
}, },
"TESTFLIGHT": {
"environments": [
"dydxprotocol-mainnet",
"dydxprotocol-testnet"
],
"default": "dydxprotocol-mainnet"
},
"TESTNET": { "TESTNET": {
"environments": [ "environments": [
"dydxprotocol-testnet" "dydxprotocol-testnet"
@@ -46,10 +39,10 @@
"environments": { "environments": {
"dydxprotocol-dev": { "dydxprotocol-dev": {
"name": "v4 Dev", "name": "v4 Dev",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -78,7 +71,6 @@
"https://validator.v4dev.dydx.exchange" "https://validator.v4dev.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4dev.dydx.exchange" "faucet": "https://faucet.v4dev.dydx.exchange"
}, },
"links": { "links": {
@@ -88,16 +80,15 @@
"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/",
"community": "https://discord.com/invite/dydx", "community": "https://discord.com/invite/dydx",
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -117,24 +108,14 @@
"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": {
"name": "v4 Dev 2", "name": "v4 Dev 2",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -162,8 +143,7 @@
"validators": [ "validators": [
"http://54.92.118.111" "http://54.92.118.111"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -172,16 +152,15 @@
"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/",
"community": "https://discord.com/invite/dydx", "community": "https://discord.com/invite/dydx",
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -201,24 +180,14 @@
"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": {
"name": "v4 Dev 4", "name": "v4 Dev 4",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -244,11 +213,9 @@
} }
], ],
"validators": [ "validators": [
"https://validator.v4dev4.dydx.exchange" "http://validator.v4dev4.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4dev4.dydx.exchange"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -257,16 +224,15 @@
"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/",
"community": "https://discord.com/invite/dydx", "community": "https://discord.com/invite/dydx",
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -286,24 +252,14 @@
"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": {
"name": "v4 Dev 5", "name": "v4 Dev 5",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -331,8 +287,7 @@
"validators": [ "validators": [
"http://18.223.78.50" "http://18.223.78.50"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -341,16 +296,15 @@
"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/",
"community": "https://discord.com/invite/dydx", "community": "https://discord.com/invite/dydx",
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -370,24 +324,14 @@
"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": {
"name": "v4 Staging", "name": "v4 Staging",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -416,8 +360,7 @@
"validators": [ "validators": [
"https://validator.v4staging.dydx.exchange" "https://validator.v4staging.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -429,14 +372,13 @@
"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",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -456,108 +398,14 @@
"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": {
"name": "v4 Staging Forced Update",
"ethereumChainId": "11155111",
"dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"tokens": {
"chain": {
"name": "Dv4TNT",
"denom": "adv4tnt",
"decimals": 18,
"image": "/currencies/dydx.png"
},
"usdc": {
"name": "USDC",
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
"gasDenom": "uusdc",
"decimals": 6,
"image": "/currencies/usdc.png"
}
},
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4staging.dydx.exchange",
"socket": "wss://indexer.v4staging.dydx.exchange"
}
],
"faucet": "https://faucet.v4staging.dydx.exchange",
"validators": [
"https://validator.v4staging.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"links": {
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
"documentation": "https://v4-teacher.vercel.app/",
"community": "https://discord.com/invite/dydx",
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
"blogs": "https://www.dydx.foundation/blog",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals"
},
"wallets": {
"walletconnect": {
"client": {
"name": "dYdX v4",
"description": "dYdX v4 App",
"iconUrl": "/logos/dydx-x.png"
},
"v2": {
"projectId": "47559b2ec96c09aed9ff2cb54a31ab0e"
}
},
"walletSegue": {
"callbackUrl": "/walletsegue"
},
"images": "/wallets/",
"signTypedDataAction": "dYdX Chain Onboarding",
"signTypedDataDomainName": "dYdX Chain"
},
"apps": {
"ios": {
"minimalVersion": "1.0",
"build": 40000,
"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": {
"name": "v4 Staging West", "name": "v4 Staging West",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -586,8 +434,7 @@
"validators": [ "validators": [
"https://validator-uswest1.v4staging.dydx.exchange" "https://validator-uswest1.v4staging.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -599,14 +446,13 @@
"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",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -626,24 +472,14 @@
"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": {
"name": "v4 Public Testnet", "name": "v4 Public Testnet",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydx-testnet-4", "dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -664,8 +500,8 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
@@ -676,7 +512,6 @@
"https://dydx-rpc.liquify.com/api=8878132/dydx" "https://dydx-rpc.liquify.com/api=8878132/dydx"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -689,14 +524,13 @@
"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",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -716,24 +550,14 @@
"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": {
"name": "v4 Public Testnet/dYdX", "name": "v4 Public Testnet/dYdX",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydx-testnet-4", "dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -762,7 +586,6 @@
"https://validator.v4testnet.dydx.exchange" "https://validator.v4testnet.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -776,14 +599,13 @@
"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",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -803,24 +625,14 @@
"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": {
"name": "v4 Public Testnet/nodefleet", "name": "v4 Public Testnet/nodefleet",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydx-testnet-4", "dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -841,15 +653,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://dydx-testnet.nodefleet.org" "https://dydx-testnet.nodefleet.org"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -863,14 +674,13 @@
"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",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -890,24 +700,14 @@
"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": {
"name": "v4 Public Testnet/KingNodes", "name": "v4 Public Testnet/KingNodes",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydx-testnet-4", "dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -928,15 +728,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://test-dydx.kingnodes.com" "https://test-dydx.kingnodes.com"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -950,14 +749,13 @@
"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",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -977,24 +775,14 @@
"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": {
"name": "v4 Public Testnet/Liquify", "name": "v4 Public Testnet/Liquify",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydx-testnet-4", "dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -1015,15 +803,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://dydx-rpc.liquify.com/api=8878132/dydx" "https://dydx-rpc.liquify.com/api=8878132/dydx"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -1037,14 +824,13 @@
"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",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone", "accountExportLearnMore": "https://help.dydx.exchange",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -1064,24 +850,14 @@
"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": {
"name": "v4 Public Testnet/Polkahcu", "name": "v4 Public Testnet/Polkahcu",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydx-testnet-4", "dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -1102,15 +878,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://dydx-testnet-rpc.polkachu.com/" "https://dydx-testnet-rpc.polkachu.com/"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -1118,12 +893,10 @@
"privacy": "https://dydx.exchange/privacy", "privacy": "https://dydx.exchange/privacy",
"statusPage": "https://status.v4testnet.dydx.exchange/", "statusPage": "https://status.v4testnet.dydx.exchange/",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}", "mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
"documentation": "https://docs.dydx.exchange/", "documentation": "https://docs.dydx.exchange/",
"community": "https://discord.com/invite/dydx", "community": "https://discord.com/invite/dydx",
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform", "feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
"blogs": "https://www.dydx.foundation/blog", "blogs": "https://www.dydx.foundation/blog"
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals"
}, },
"wallets": { "wallets": {
"walletconnect": { "walletconnect": {
@@ -1142,24 +915,14 @@
"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": {
"name": "v4 Public Testnet/BWare", "name": "v4 Public Testnet/BWare",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydx-testnet-4", "dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -1180,15 +943,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://dydx-testnet-full-rpc.public.blastapi.io/" "https://dydx-testnet-full-rpc.public.blastapi.io/"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -1202,13 +964,12 @@
"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",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnmore": "https://help.dydx.exchange", "stakingLearnmore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnmore": "https://help.dydx.exchange", "accountExportLearnmore": "https://help.dydx.exchange",
"walletLearnmore": "https://www.dydx.academy/video/defi-wallet" "walletLearnmore": "https://www.dydx.academy/video/defi-wallet"
}, },
@@ -1229,16 +990,6 @@
"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": {
@@ -1246,7 +997,7 @@
"ethereumChainId": "1", "ethereumChainId": "1",
"dydxChainId": "[mainnet chain id]", "dydxChainId": "[mainnet chain id]",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "[mainnet squid integrator id]", "squidIntegratorId": "[mainnet squid integrator id]",
"isMainNet": true, "isMainNet": true,
"tokens": { "tokens": {
@@ -1276,26 +1027,24 @@
"[Validator endpoint 1", "[Validator endpoint 1",
"[Validator endpoint n]" "[Validator endpoint n]"
], ],
"0xsquid": "[0xSquid endpoint for mainnet]", "0xsquid": "[0xSquid endpoint for mainnet]"
"nobleValidator": "[noble validator endpoint for mainnet]"
}, },
"links": { "links": {
"tos": "[HTTP link to TOS]", "tos": "[HTTP link to TOS]",
"privacy": "[HTTP link to Privacy Policy]", "privacy": "[HTTP link to Privacy Policy]",
"mintscan": "[HTTP link to Mintscan, with {tx_hash} placeholder]", "mintscan": "[HTTP link to Mintscan, with {tx_hash} placeholder]",
"mintscanBase": "[HTTP link to TOS mintscan base url]", "mintscanBase": "[HTTP link to TOS mintsacn base url]",
"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]",
"reduceOnlyLearnMore": "[HTTP link to reduce-only learn more, can be null]", "initialMarginFractionLearnMore": "[HTTP link to initial margin fraction learn more, can be null]",
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
"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]",
"help": "[HTTP link to help page, can be null]", "help": "[HTTP link to help page, can be null]",
"governanceLearnMore": "[HTTP link to governance learn more, can be null]", "governanceLearnMore": "[HTTP link to governance learn more, can be null]",
"newMarketProposalLearnMore": "[HTTP link to new market proposal learn more, can be null]",
"stakingLearnMore": "[HTTP link to staking learn more, can be null]", "stakingLearnMore": "[HTTP link to staking learn more, can be null]",
"keplrDashboard": "[HTTP link to keplr dashboard, can be null]", "keplrDashboard": "[HTTP link to keplr dashboard, can be null]",
"strideZoneApp": "[HTTP link to stride zone app, can be null]",
"accountExportLearnMore": "[HTTP link to account export learn more, can be null]", "accountExportLearnMore": "[HTTP link to account export learn more, can be null]",
"walletLearnMore": "[HTTP link to wallet learn more, can be null]" "walletLearnMore": "[HTTP link to wallet learn more, can be null]"
}, },
@@ -1316,16 +1065,6 @@
"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
} }
} }
} }
-8
View File
@@ -1,8 +0,0 @@
[
{
"name": "coinbase",
"label": "Coinbase",
"icon": "/exchanges/coinbase.png",
"depositType": "noble"
}
]
+453 -373
View File
@@ -1,374 +1,454 @@
{ {
"1INCH-USD": { "1INCH-USD":{
"name": "1inch", "name":"1inch",
"tags": ["Defi"], "tags":[
"websiteLink": "https://1inch.io/", "Defi"
"whitepaperLink": "https://github.com/1inch", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/1inch/" "websiteLink":"https://1inch.io/",
}, "whitepaperLink":"https://github.com/1inch",
"AAVE-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/1inch/"
"name": "Aave", },
"tags": ["Defi"], "AAVE-USD":{
"websiteLink": "https://aave.com/", "name":"Aave",
"whitepaperLink": "https://github.com/aave/protocol-v2/blob/master/aave-v2-whitepaper.pdf", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/aave/" "Defi"
}, ],
"ADA-USD": { "websiteLink":"https://aave.com/",
"name": "Cardano", "whitepaperLink":"https://github.com/aave/protocol-v2/blob/master/aave-v2-whitepaper.pdf",
"tags": ["Layer 1"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/aave/"
"websiteLink": "https://cardano.org/", },
"whitepaperLink": "https://why.cardano.org/en/introduction/motivation/", "ADA-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/cardano/" "name":"Cardano",
}, "tags":[
"ALGO-USD": { "Layer 1"
"name": "Algorand", ],
"tags": ["Layer 1"], "websiteLink":"https://cardano.org/",
"websiteLink": "https://algorand.com/", "whitepaperLink":"https://why.cardano.org/en/introduction/motivation/",
"whitepaperLink": "https://algorand.com/technology/white-papers", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/cardano/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/algorand/" },
}, "ALGO-USD":{
"APE-USD": { "name":"Algorand",
"name": "ApeCoin", "tags":[
"tags": [], "Layer 1"
"websiteLink": "https://apecoin.com/", ],
"whitepaperLink": "https://apecoin.com/about", "websiteLink":"https://algorand.com/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/apecoin-ape/" "whitepaperLink":"https://algorand.com/technology/white-papers",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/algorand/"
"APT-USD": { },
"name": "Aptos", "APE-USD":{
"tags": ["Layer 1"], "name":"ApeCoin",
"websiteLink": "https://aptoslabs.com/", "tags":[
"whitepaperLink": "https://aptos.dev/aptos-white-paper/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/aptos/" ],
}, "websiteLink":"https://apecoin.com/",
"ARB-USD": { "whitepaperLink":"https://apecoin.com/about",
"name": "Arbitrum", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/apecoin-ape/"
"tags": [], },
"websiteLink": "https://arbitrum.io/", "APT-USD":{
"whitepaperLink": "https://github.com/OffchainLabs/nitro", "name":"Aptos",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/arbitrum/" "tags":[
}, "Layer 1"
"ATOM-USD": { ],
"name": "Cosmos", "websiteLink":"https://aptoslabs.com/",
"tags": ["Layer 1"], "whitepaperLink":"https://aptos.dev/aptos-white-paper/",
"websiteLink": "https://cosmos.network/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/aptos/"
"whitepaperLink": "https://v1.cosmos.network/resources/whitepaper", },
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/cosmos/" "ARB-USD":{
}, "name":"Arbitrum",
"AVAX-USD": { "tags":[
"name": "Avalanche",
"tags": ["Layer 1"], ],
"websiteLink": "https://www.avalabs.org/", "websiteLink":"https://arbitrum.io/",
"whitepaperLink": "https://assets.website-files.com/5d80307810123f5ffbb34d6e/6008d7bbf8b10d1eb01e7e16_Avalanche%20Platform%20Whitepaper.pdf", "whitepaperLink":"https://github.com/OffchainLabs/nitro",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/avalanche/" "coinMarketCapsLink":"https://coinmarketcap.com/currencies/arbitrum/"
}, },
"BCH-USD": { "ATOM-USD":{
"name": "Bitcoin Cash", "name":"Cosmos",
"tags": ["Layer 1"], "tags":[
"websiteLink": "https://bitcoincash.org/", "Layer 1"
"whitepaperLink": "https://bitcoincash.org/", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bitcoin-cash/" "websiteLink":"https://cosmos.network/",
}, "whitepaperLink":"https://v1.cosmos.network/resources/whitepaper",
"BONK-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/cosmos/"
"name": "BONK COIN", },
"tags": [], "AVAX-USD":{
"websiteLink": "https://bonkcoin.com/", "name":"Avalanche",
"whitepaperLink": "https://bonkcoin.com/", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bonk1/" "Layer 1"
}, ],
"BLUR-USD": { "websiteLink":"https://www.avalabs.org/",
"name": "Blur", "whitepaperLink":"https://assets.website-files.com/5d80307810123f5ffbb34d6e/6008d7bbf8b10d1eb01e7e16_Avalanche%20Platform%20Whitepaper.pdf",
"tags": [], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/avalanche/"
"websiteLink": "https://blur.io/", },
"whitepaperLink": "https://docs.blur.foundation/", "BCH-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/blur-token/" "name":"Bitcoin Cash",
}, "tags":[
"CELO-USD": { "Layer 1"
"name": "Celo", ],
"tags": [], "websiteLink":"https://bitcoincash.org/",
"websiteLink": "https://celo.org", "whitepaperLink":"https://bitcoincash.org/",
"whitepaperLink": "https://docs.celo.org", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/bitcoin-cash/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/celo/" },
}, "BLUR-USD":{
"BTC-USD": { "name":"Blur",
"name": "Bitcoin", "tags":[
"tags": ["Layer 1"],
"websiteLink": "https://bitcoin.org/", ],
"whitepaperLink": "https://bitcoin.org/bitcoin.pdf", "websiteLink":"https://blur.io/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bitcoin/" "whitepaperLink":"https://docs.blur.foundation/",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/blur-token/"
"COMP-USD": { },
"name": "Compound", "CELO-USD":{
"tags": ["Defi"], "name":"Celo",
"websiteLink": "https://compound.finance/", "tags":[
"whitepaperLink": "https://compound.finance/documents/Compound.Whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/compound/" ],
}, "websiteLink":"https://celo.org",
"CRV-USD": { "whitepaperLink":"https://docs.celo.org",
"name": "Curve", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/celo/"
"tags": ["Governance"], },
"websiteLink": "https://curve.fi/", "BTC-USD":{
"whitepaperLink": "https://curve.fi/whitepaper", "name":"Bitcoin",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/curve-dao-token/" "tags":[
}, "Layer 1"
"DOGE-USD": { ],
"name": "Dogecoin", "websiteLink":"https://bitcoin.org/",
"tags": ["Layer 1"], "whitepaperLink":"https://bitcoin.org/bitcoin.pdf",
"websiteLink": "https://dogecoin.com/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/bitcoin/"
"whitepaperLink": "https://github.com/dogecoin/dogecoin", },
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/dogecoin/" "COMP-USD":{
}, "name":"Compound",
"DOT-USD": { "tags":[
"name": "Polkadot", "Defi"
"tags": ["Layer 1"], ],
"websiteLink": "https://polkadot.network/", "websiteLink":"https://compound.finance/",
"whitepaperLink": "https://polkadot.network/PolkaDotPaper.pdf", "whitepaperLink":"https://compound.finance/documents/Compound.Whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/polkadot-new/" "coinMarketCapsLink":"https://coinmarketcap.com/currencies/compound/"
}, },
"ENJ-USD": { "CRV-USD":{
"name": "Enjin", "name":"Curve",
"tags": [], "tags":[
"websiteLink": "https://enjin.io/", "Governance"
"whitepaperLink": "https://cdn.enjin.io/downloads/whitepapers/enjin-coin/en.pdf/", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/enjin-coin/" "websiteLink":"https://curve.fi/",
}, "whitepaperLink":"https://curve.fi/whitepaper",
"EOS-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/curve-dao-token/"
"name": "EOS", },
"tags": ["Layer 1"], "DOGE-USD":{
"websiteLink": "https://eos.io/", "name":"Dogecoin",
"whitepaperLink": "https://github.com/EOSIO/Documentation/blob/master/TechnicalWhitePaper.md", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/eos/" "Layer 1"
}, ],
"ETC-USD": { "websiteLink":"https://dogecoin.com/",
"name": "Ethereum Classic", "whitepaperLink":"https://github.com/dogecoin/dogecoin",
"tags": ["Layer 1"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/dogecoin/"
"websiteLink": "https://ethereumclassic.org/", },
"whitepaperLink": "https://ethereumclassic.org/why-classic", "DOT-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/ethereum-classic/" "name":"Polkadot",
}, "tags":[
"ETH-USD": { "Layer 1"
"name": "Ethereum", ],
"tags": ["Layer 1"], "websiteLink":"https://polkadot.network/",
"websiteLink": "https://ethereum.org/", "whitepaperLink":"https://polkadot.network/PolkaDotPaper.pdf",
"whitepaperLink": "https://ethereum.org/whitepaper/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/polkadot-new/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/ethereum/", },
"displayStepSize": "0.001", "ENJ-USD":{
"displayTickSize": "0.1" "name":"Enjin",
}, "tags":[
"FIL-USD": {
"name": "Filecoin", ],
"tags": ["Layer 1"], "websiteLink":"https://enjin.io/",
"websiteLink": "https://filecoin.io/", "whitepaperLink":"https://cdn.enjin.io/downloads/whitepapers/enjin-coin/en.pdf/",
"whitepaperLink": "https://filecoin.io/filecoin.pdf", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/enjin-coin/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/filecoin/" },
}, "EOS-USD":{
"HNT-USD": { "name":"EOS",
"name": "Helium", "tags":[
"tags": ["Layer 1"], "Layer 1"
"websiteLink": "https://www.helium.com", ],
"whitepaperLink": "http://whitepaper.helium.com", "websiteLink":"https://eos.io/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/helium/" "whitepaperLink":"https://github.com/EOSIO/Documentation/blob/master/TechnicalWhitePaper.md",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/eos/"
"ICP-USD": { },
"name": "Internet Computer", "ETC-USD":{
"tags": ["Layer 1"], "name":"Ethereum Classic",
"websiteLink": "https://dfinity.org", "tags":[
"whitepaperLink": "https://dfinity.org/whitepaper.pdf", "Layer 1"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/internet-computer/" ],
}, "websiteLink":"https://ethereumclassic.org/",
"JUP-USD": { "whitepaperLink":"https://ethereumclassic.org/why-classic",
"name": "Jupiter", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/ethereum-classic/"
"tags": ["Defi"], },
"websiteLink": "https://station.jup.ag/", "ETH-USD":{
"whitepaperLink": "https://station.jup.ag/blog/green-paper", "name":"Ethereum",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/jupiter-ag/" "tags":[
}, "Layer 1"
"LDO-USD": { ],
"name": "Lido DAO", "websiteLink":"https://ethereum.org/",
"tags": ["Defi"], "whitepaperLink":"https://ethereum.org/whitepaper/",
"websiteLink": "https://lido.fi/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/ethereum/",
"whitepaperLink": "https://lido.fi/static/Lido:Ethereum-Liquid-Staking.pdf", "displayStepSize":"0.001",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/lido-dao/" "displayTickSize":"0.1"
}, },
"LINK-USD": { "FIL-USD":{
"name": "Chainlink", "name":"Filecoin",
"tags": ["Defi"], "tags":[
"websiteLink": "https://chain.link/", "Layer 1"
"whitepaperLink": "https://link.smartcontract.com/whitepaper", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/chainlink/" "websiteLink":"https://filecoin.io/",
}, "whitepaperLink":"https://filecoin.io/filecoin.pdf",
"LTC-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/filecoin/"
"name": "Litecoin", },
"tags": ["Layer 1"], "HNT-USD":{
"websiteLink": "https://litecoin.org/", "name":"Helium",
"whitepaperLink": "https://litecoin.info/index.php/Main_Page", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/litecoin/" "Layer 1"
}, ],
"MATIC-USD": { "websiteLink":"https://www.helium.com",
"name": "Polygon", "whitepaperLink":"http://whitepaper.helium.com",
"tags": ["Layer 2"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/helium/"
"websiteLink": "https://polygon.technology/", },
"whitepaperLink": "https://polygon.technology/lightpaper-polygon.pdf", "ICP-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/polygon/" "name":"Internet Computer",
}, "tags":[
"MKR-USD": { "Layer 1"
"name": "Maker", ],
"tags": ["Governance"], "websiteLink":"https://dfinity.org",
"websiteLink": "https://makerdao.com", "whitepaperLink":"https://dfinity.org/whitepaper.pdf",
"whitepaperLink": "https://makerdao.com/whitepaper", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/internet-computer/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/maker/" },
}, "LDO-USD":{
"NEAR-USD": { "name":"Lido DAO",
"name": "NEAR Protocol", "tags":[
"tags": ["Layer 1"], "Defi"
"websiteLink": "https://near.org", ],
"whitepaperLink": "https://near.org/papers/the-official-near-white-paper/", "websiteLink":"https://lido.fi/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/near-protocol/" "whitepaperLink":"https://lido.fi/static/Lido:Ethereum-Liquid-Staking.pdf",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/lido-dao/"
"OP-USD": { },
"name": "Optimism", "LINK-USD":{
"tags": [], "name":"Chainlink",
"websiteLink": "https://www.optimism.io/", "tags":[
"whitepaperLink": "https://github.com/ethereum-optimism", "Defi"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/optimism-ethereum/" ],
}, "websiteLink":"https://chain.link/",
"PEPE-USD": { "whitepaperLink":"https://link.smartcontract.com/whitepaper",
"name": "Pepe", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/chainlink/"
"tags": [], },
"websiteLink": "https://www.pepe.vip/", "LTC-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/pepe/" "name":"Litecoin",
}, "tags":[
"RUNE-USD": { "Layer 1"
"name": "THORChain", ],
"tags": ["Layer 1"], "websiteLink":"https://litecoin.org/",
"websiteLink": "https://thorchain.org", "whitepaperLink":"https://litecoin.info/index.php/Main_Page",
"whitepaperLink": "https://whitepaper.io/document/709/thorchain-whitepaper", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/litecoin/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/thorchain/" },
}, "MATIC-USD":{
"SEI-USD": { "name":"Polygon",
"name": "Sei", "tags":[
"tags": ["Layer 1", "Defi"], "Layer 2"
"websiteLink": "https://www.sei.io/", ],
"whitepaperLink": "https://github.com/sei-protocol/sei-chain/blob/3c9576fee3494ce039df684624f918dd8066ba3f/whitepaper/Sei_Whitepaper.pdf", "websiteLink":"https://polygon.technology/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/sei/" "whitepaperLink":"https://polygon.technology/lightpaper-polygon.pdf",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/polygon/"
"SHIB-USD": { },
"name": "Shiba Inu", "MKR-USD":{
"tags": [], "name":"Maker",
"websiteLink": "https://shibatoken.com/", "tags":[
"whitepaperLink": "https://docs.shibatoken.com/", "Governance"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/shiba-inu/" ],
}, "websiteLink":"https://makerdao.com",
"SNX-USD": { "whitepaperLink":"https://makerdao.com/whitepaper",
"name": "Synthetix", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/maker/"
"tags": ["Defi"], },
"websiteLink": "https://synthetix.io/", "NEAR-USD":{
"whitepaperLink": "https://docs.synthetix.io/litepaper", "name":"NEAR Protocol",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/synthetix-network-token/" "tags":[
}, "Layer 1"
"SOL-USD": { ],
"name": "Solana", "websiteLink":"https://near.org",
"tags": ["Layer 1"], "whitepaperLink":"https://near.org/papers/the-official-near-white-paper/",
"websiteLink": "https://solana.com/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/near-protocol/"
"whitepaperLink": "https://solana.com/solana-whitepaper.pdf", },
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/solana/" "OP-USD":{
}, "name":"Optimism",
"SUI-USD": { "tags":[
"name": "Sui",
"tags": ["Layer 1"], ],
"websiteLink": "https://sui.io/", "websiteLink":"https://www.optimism.io/",
"whitepaperLink": "https://github.com/MystenLabs", "whitepaperLink":"https://github.com/ethereum-optimism",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/sui/" "coinMarketCapsLink":"https://coinmarketcap.com/currencies/optimism-ethereum/"
}, },
"SUSHI-USD": { "PEPE-USD":{
"name": "Sushi", "name":"Pepe",
"tags": ["Defi"], "tags":[
"websiteLink": "https://sushi.com/",
"whitepaperLink": "https://docs.sushi.com/", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/sushiswap/" "websiteLink":"https://www.pepe.vip/",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/pepe/"
"TIA-USD": { },
"name": "Celestia", "RUNE-USD":{
"tags": ["Layer 1"], "name":"THORChain",
"websiteLink": "https://celestia.org/", "tags":[
"whitepaperLink": "https://arxiv.org/pdf/1905.09274.pdf", "Layer 1"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/celestia/" ],
}, "websiteLink":"https://thorchain.org",
"TRX-USD": { "whitepaperLink":"https://whitepaper.io/document/709/thorchain-whitepaper",
"name": "TRON", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/thorchain/"
"tags": ["Defi"], },
"websiteLink": "https://tron.network/", "SEI-USD":{
"whitepaperLink": "https://tron.network/static/doc/white_paper_v_2_0.pdf", "name":"Sei",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/tron/" "tags":[
}, "Layer 1",
"UMA-USD": { "Defi"
"name": "UMA", ],
"tags": ["Defi"], "websiteLink":"https://www.sei.io/",
"websiteLink": "https://umaproject.org/", "whitepaperLink":"https://github.com/sei-protocol/sei-chain/blob/3c9576fee3494ce039df684624f918dd8066ba3f/whitepaper/Sei_Whitepaper.pdf",
"whitepaperLink": "https://github.com/UMAprotocol/whitepaper", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/sei/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/uma/" },
}, "SHIB-USD":{
"UNI-USD": { "name":"Shiba Inu",
"name": "Uniswap", "tags":[
"tags": ["Defi"],
"websiteLink": "https://uniswap.org/", ],
"whitepaperLink": "https://uniswap.org/whitepaper-v3.pdf", "websiteLink":"https://shibatoken.com/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/uniswap/" "whitepaperLink":"https://docs.shibatoken.com/",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/shiba-inu/"
"WLD-USD": { },
"name": "Worldcoin", "SNX-USD":{
"tags": [], "name":"Synthetix",
"websiteLink": "https://worldcoin.org/", "tags":[
"whitepaperLink": "https://whitepaper.worldcoin.org/", "Defi"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/worldcoin-org/" ],
}, "websiteLink":"https://synthetix.io/",
"XLM-USD": { "whitepaperLink":"https://docs.synthetix.io/litepaper",
"name": "Stellar", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/synthetix-network-token/"
"tags": ["Layer 1"], },
"websiteLink": "https://www.stellar.org/", "SOL-USD":{
"whitepaperLink": "https://www.stellar.org/papers/stellar-consensus-protocol", "name":"Solana",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/stellar/" "tags":[
}, "Layer 1"
"XMR-USD": { ],
"name": "Monero", "websiteLink":"https://solana.com/",
"tags": ["Layer 1"], "whitepaperLink":"https://solana.com/solana-whitepaper.pdf",
"websiteLink": "https://www.getmonero.org/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/solana/"
"whitepaperLink": "https://www.getmonero.org/resources/research-lab/", },
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/monero/" "SUI-USD":{
}, "name":"Sui",
"XRP-USD": { "tags":[
"name": "Ripple", "Layer 1"
"tags": ["Layer 1"], ],
"websiteLink": "https://ripple.com/currency/", "websiteLink":"https://sui.io/",
"whitepaperLink": "https://github.com/ripple", "whitepaperLink":"https://github.com/MystenLabs",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/xrp/" "coinMarketCapsLink":"https://coinmarketcap.com/currencies/sui/"
}, },
"XTZ-USD": { "SUSHI-USD":{
"name": "Tezos", "name":"Sushi",
"tags": ["Layer 1"], "tags":[
"websiteLink": "https://tezos.com", "Defi"
"whitepaperLink": "https://tezos.com/whitepaper.pdf", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/tezos/" "websiteLink":"https://sushi.com/",
}, "whitepaperLink":"https://docs.sushi.com/",
"YFI-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/sushiswap/"
"name": "Yearn", },
"tags": ["Defi"], "TRX-USD":{
"websiteLink": "https://yearn.finance/", "name":"TRON",
"whitepaperLink": "https://docs.yearn.finance/", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/yearn-finance/" "Defi"
}, ],
"ZEC-USD": { "websiteLink":"https://tron.network/",
"name": "Zcash", "whitepaperLink":"https://tron.network/static/doc/white_paper_v_2_0.pdf",
"tags": ["Layer 1"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/tron/"
"websiteLink": "https://z.cash/", },
"whitepaperLink": "https://z.cash/technology/", "UMA-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/zcash/" "name":"UMA",
}, "tags":[
"ZRX-USD": { "Defi"
"name": "0x", ],
"tags": ["Defi"], "websiteLink":"https://umaproject.org/",
"websiteLink": "https://0x.org/", "whitepaperLink":"https://github.com/UMAprotocol/whitepaper",
"whitepaperLink": "https://0x.org/pdfs/0x_white_paper.pdf", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/uma/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/0x/" },
} "UNI-USD":{
} "name":"Uniswap",
"tags":[
"Defi"
],
"websiteLink":"https://uniswap.org/",
"whitepaperLink":"https://uniswap.org/whitepaper-v3.pdf",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/uniswap/"
},
"WLD-USD":{
"name":"Worldcoin",
"tags":[
],
"websiteLink":"https://worldcoin.org/",
"whitepaperLink":"https://whitepaper.worldcoin.org/",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/worldcoin-org/"
},
"XLM-USD":{
"name":"Stellar",
"tags":[
"Layer 1"
],
"websiteLink":"https://www.stellar.org/",
"whitepaperLink":"https://www.stellar.org/papers/stellar-consensus-protocol",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/stellar/"
},
"XMR-USD":{
"name":"Monero",
"tags":[
"Layer 1"
],
"websiteLink":"https://www.getmonero.org/",
"whitepaperLink":"https://www.getmonero.org/resources/research-lab/",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/monero/"
},
"XRP-USD":{
"name":"Ripple",
"tags":[
"Layer 1"
],
"websiteLink":"https://ripple.com/currency/",
"whitepaperLink":"https://github.com/ripple",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/xrp/"
},
"XTZ-USD":{
"name":"Tezos",
"tags":[
"Layer 1"
],
"websiteLink":"https://tezos.com",
"whitepaperLink":"https://tezos.com/whitepaper.pdf",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/tezos/"
},
"YFI-USD":{
"name":"Yearn",
"tags":[
"Defi"
],
"websiteLink":"https://yearn.finance/",
"whitepaperLink":"https://docs.yearn.finance/",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/yearn-finance/"
},
"ZEC-USD":{
"name":"Zcash",
"tags":[
"Layer 1"
],
"websiteLink":"https://z.cash/",
"whitepaperLink":"https://z.cash/technology/",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/zcash/"
},
"ZRX-USD":{
"name":"0x",
"tags":[
"Defi"
],
"websiteLink":"https://0x.org/",
"whitepaperLink":"https://0x.org/pdfs/0x_white_paper.pdf",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/0x/"
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -199,7 +199,7 @@
}, },
"mobile": { "mobile": {
"native": "trust:", "native": "trust:",
"universal": "" "universal": "https://link.trustwallet.com"
}, },
"desktop": { "desktop": {
"native": "", "native": "",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

-230
View File
@@ -1,230 +0,0 @@
<svg width="254" height="77" viewBox="0 0 254 77" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 1258">
<g id="Ellipse 9" opacity="0.4" filter="url(#filter0_f_20300_14972)">
<ellipse cx="86.5425" cy="-3.91219" rx="116.542" ry="20.0878" fill="#7774FF"/>
</g>
<g id="Ellipse 10" opacity="0.3" filter="url(#filter1_f_20300_14972)">
<circle cx="74.5734" cy="4.63007" r="1.00507" fill="#9A9AFF"/>
</g>
<g id="Ellipse 12" opacity="0.3" filter="url(#filter2_f_20300_14972)">
<circle cx="82.1105" cy="7.64179" r="1.00507" fill="#9A9AFF"/>
</g>
<g id="Ellipse 22" opacity="0.3" filter="url(#filter3_f_20300_14972)">
<circle cx="116.785" cy="4.63007" r="1.00507" fill="#9A9AFF"/>
</g>
<g id="Ellipse 11" opacity="0.3" filter="url(#filter4_f_20300_14972)">
<circle cx="64.774" cy="8.90488" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 18" opacity="0.3" filter="url(#filter5_f_20300_14972)">
<circle cx="96.4322" cy="3.87363" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 20" opacity="0.3" filter="url(#filter6_f_20300_14972)">
<circle cx="76.0807" cy="14.9361" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 21" opacity="0.3" filter="url(#filter7_f_20300_14972)">
<circle cx="104.725" cy="4.87754" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 23" opacity="0.3" filter="url(#filter8_f_20300_14972)">
<circle cx="114.021" cy="7.13925" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 24" opacity="0.3" filter="url(#filter9_f_20300_14972)">
<circle cx="109.75" cy="15.4361" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 25" opacity="0.3" filter="url(#filter10_f_20300_14972)">
<circle cx="119.801" cy="12.6705" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 27" opacity="0.3" filter="url(#filter11_f_20300_14972)">
<circle cx="94.0885" cy="11.0182" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 30" opacity="0.3" filter="url(#filter12_f_20300_14972)">
<circle cx="154.475" cy="11.6666" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 29" opacity="0.3" filter="url(#filter13_f_20300_14972)">
<circle cx="146.435" cy="8.90488" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 15" opacity="0.3" filter="url(#filter14_f_20300_14972)">
<circle cx="24.0103" cy="4.44785" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 33" opacity="0.3" filter="url(#filter15_f_20300_14972)">
<circle cx="-1.05899" cy="13.6783" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 16" opacity="0.3" filter="url(#filter16_f_20300_14972)">
<circle cx="17.441" cy="16.4908" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 35" opacity="0.3" filter="url(#filter17_f_20300_14972)">
<circle cx="36.0553" cy="6.63535" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 32" opacity="0.3" filter="url(#filter18_f_20300_14972)">
<circle cx="10.8707" cy="14.2994" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 13" opacity="0.3" filter="url(#filter19_f_20300_14972)">
<circle cx="55.7274" cy="9.65615" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 19" opacity="0.3" filter="url(#filter20_f_20300_14972)">
<circle cx="87.3886" cy="20.7108" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 26" opacity="0.3" filter="url(#filter21_f_20300_14972)">
<circle cx="123.82" cy="15.1874" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 36" opacity="0.3" filter="url(#filter22_f_20300_14972)">
<circle cx="134.876" cy="14.4335" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 28" opacity="0.3" filter="url(#filter23_f_20300_14972)">
<circle cx="129.6" cy="6.38662" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 14" opacity="0.3" filter="url(#filter24_f_20300_14972)">
<circle cx="41.6571" cy="14.9335" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 31" opacity="0.3" filter="url(#filter25_f_20300_14972)">
<circle cx="4.21767" cy="17.9491" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 34" opacity="0.3" filter="url(#filter26_f_20300_14972)">
<circle cx="12.2177" cy="6.88662" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 17" opacity="0.3" filter="url(#filter27_f_20300_14972)">
<circle cx="50.2001" cy="3.6249" r="0.753803" fill="#9A9AFF"/>
</g>
</g>
<defs>
<filter id="filter0_f_20300_14972" x="-94" y="-88" width="361.085" height="168.176" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="32" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter1_f_20300_14972" x="72.5633" y="2.61993" width="4.01991" height="4.02186" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter2_f_20300_14972" x="80.6029" y="6.13418" width="3.01484" height="3.01679" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter3_f_20300_14972" x="115.278" y="3.12246" width="3.01484" height="3.01679" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter4_f_20300_14972" x="63.2664" y="7.39727" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter5_f_20300_14972" x="94.9246" y="2.36602" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter6_f_20300_14972" x="74.5731" y="13.4285" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter7_f_20300_14972" x="103.218" y="3.36993" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter8_f_20300_14972" x="112.513" y="5.63165" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter9_f_20300_14972" x="108.242" y="13.9285" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter10_f_20300_14972" x="118.294" y="11.1629" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter11_f_20300_14972" x="92.5809" y="9.51055" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter12_f_20300_14972" x="153.47" y="10.6615" width="2.00995" height="2.00898" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter13_f_20300_14972" x="144.928" y="7.39727" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter14_f_20300_14972" x="22.5027" y="2.94024" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter15_f_20300_14972" x="-2.56659" y="12.1707" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter16_f_20300_14972" x="15.9334" y="14.9832" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter17_f_20300_14972" x="35.0502" y="5.63028" width="2.00995" height="2.00898" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter18_f_20300_14972" x="9.86563" y="13.2943" width="2.00995" height="2.00898" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter19_f_20300_14972" x="53.9686" y="7.89727" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter20_f_20300_14972" x="85.6297" y="18.952" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter21_f_20300_14972" x="122.061" y="13.4285" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter22_f_20300_14972" x="133.117" y="12.6746" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter23_f_20300_14972" x="127.842" y="4.62774" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter24_f_20300_14972" x="39.8982" y="13.1746" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter25_f_20300_14972" x="2.4588" y="16.1902" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter26_f_20300_14972" x="10.4588" y="5.12774" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter27_f_20300_14972" x="48.4412" y="1.86602" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 481 KiB

-15
View File
@@ -1,15 +0,0 @@
<!-- Smartbanner: Configure the mobile app -->
<meta name="smartbanner:title" content="SMARTBANNER_APP_NAME">
<meta name="smartbanner:author" content="SMARTBANNER_ORG_NAME">
<meta name="smartbanner:icon-apple" content="SMARTBANNER_ICON_URL">
<meta name="smartbanner:icon-google" content="SMARTBANNER_ICON_URL">
<!-- Smartbanner: The rest of the configurations can be kept as is -->
<meta name="smartbanner:price" content="FREE">
<meta name="smartbanner:price-suffix-apple" content=" - On the App Store">
<meta name="smartbanner:price-suffix-google" content=" - In Google Play">
<meta name="smartbanner:button" content="VIEW">
<meta name="smartbanner:close-label" content="Close">
<meta name="smartbanner:exclude-user-agent-regex" content="^.*(Windows NT|Intel Mac OS X).*$">
<script src="https://cdn.jsdelivr.net/npm/smartbanner.js@1.22.0/dist/smartbanner.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/smartbanner.js@1.22.0/dist/smartbanner.min.css" rel="stylesheet">
<!-- Smartbanner: End configuration -->
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 817 B

-14
View File
@@ -36,17 +36,3 @@ Customize Intercom Messenger by adding logo and brand colors
3. Add API key in Github > Secrets and Variables > Actions as `INTERCOM_APP_ID` 3. Add API key in Github > Secrets and Variables > Actions as `INTERCOM_APP_ID`
4. In your deploy scripts add `pnpm run build:inject-intercom` after your pnpm build / vite build command. 4. In your deploy scripts add `pnpm run build:inject-intercom` after your pnpm build / vite build command.
5. If you are using with the Amplitude deployment scripts, your build command may look like the following: `pnpm build && pnpm run build:inject-amplitude && pnpm run build:inject-intercom` 5. If you are using with the Amplitude deployment scripts, your build command may look like the following: `pnpm build && pnpm run build:inject-amplitude && pnpm run build:inject-intercom`
### Smartbanner
Smartbanner to show download links to iOS and/or Android native apps on mobile devices.
<b>To use with dydxprotocol/v4-web:</b>
1. iOS app App Store link or Android app Google Play link.
2. Add configurations in Github > Secrets and Variables > Actions as
`SMARTBANNER_APP_NAME` for app name
`SMARTBANNER_ORG_NAME` for organization name
`SMARTBANNER_ICON_URL` for icon image
`SMARTBANNER_APPSTORE_URL` for iOS App Store link
`SMARTBANNER_GOOGLEPLAY_URL` for Android Google Play link
3. In your deploy scripts add `pnpm run build:inject-smartbanner` after your pnpm build / vite build command.
4. If you are using with the Amplitude deployment scripts, your build command may look like the following: `pnpm build && pnpm run build:inject-smartbanner`
+3 -30
View File
@@ -3,13 +3,12 @@ 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');
@@ -19,34 +18,8 @@ if (AMPLITUDE_API_KEY) {
`; `;
const amplitudeListenerScript = `<script type="module"> const amplitudeListenerScript = `<script type="module">
!(function () { !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."))}();
var e = "${AMPLITUDE_API_KEY}"; </script>`;
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>',
-60
View File
@@ -1,60 +0,0 @@
/* eslint-disable no-console */
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
const SMARTBANNER_APP_NAME = process.env.SMARTBANNER_APP_NAME;
const SMARTBANNER_ORG_NAME = process.env.SMARTBANNER_ORG_NAME;
const SMARTBANNER_ICON_URL = process.env.SMARTBANNER_ICON_URL;
const SMARTBANNER_APPSTORE_URL = process.env.SMARTBANNER_APPSTORE_URL;
const SMARTBANNER_GOOGLEPLAY_URL = process.env.SMARTBANNER_GOOGLEPLAY_URL;
const currentPath = fileURLToPath(import.meta.url);
const projectRoot = path.dirname(currentPath);
const htmlFilePath = path.resolve(projectRoot, '../dist/index.html');
const smartbannerFilePath = path.resolve(projectRoot, '../dist/smartbanner.html');
if (
SMARTBANNER_APP_NAME &&
SMARTBANNER_ORG_NAME &&
SMARTBANNER_ICON_URL &&
(SMARTBANNER_APPSTORE_URL || SMARTBANNER_GOOGLEPLAY_URL)
) {
try {
const html = await fs.readFile(htmlFilePath, 'utf-8');
let smartbanner = await fs.readFile(smartbannerFilePath, 'utf-8');
smartbanner = smartbanner
.replace('SMARTBANNER_APP_NAME', SMARTBANNER_APP_NAME)
.replace('SMARTBANNER_ORG_NAME', SMARTBANNER_ORG_NAME)
.replace('SMARTBANNER_ICON_URL', SMARTBANNER_ICON_URL)
.replace('SMARTBANNER_ICON_URL', SMARTBANNER_ICON_URL);
/* hardcoded injection depending on whether the app is available on App Store and/or Google Play */
if (SMARTBANNER_APPSTORE_URL) {
smartbanner = `\t<meta name="smartbanner:button-url-apple" content="${SMARTBANNER_APPSTORE_URL}">\n` + smartbanner;
}
if (SMARTBANNER_GOOGLEPLAY_URL) {
smartbanner = `\t<meta name="smartbanner:button-url-google" content="${SMARTBANNER_GOOGLEPLAY_URL}">\n` + smartbanner;
}
if (SMARTBANNER_APPSTORE_URL) {
if (SMARTBANNER_GOOGLEPLAY_URL) {
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="android,ios">\n` + smartbanner;
} else {
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="ios">\n` + smartbanner;
}
} else {
if (SMARTBANNER_GOOGLEPLAY_URL) {
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="android">\n` + smartbanner;
}
}
const injectedHtml = html.replace('</head>', `${smartbanner}\n</head>`);
await fs.writeFile(htmlFilePath, injectedHtml, 'utf-8');
console.log('Smartbanner scripts successfully injected.');
} catch (err) {
console.error('Error injecting Smartbanner scripts:', err);
}
}
+48 -60
View File
@@ -1,11 +1,11 @@
import { lazy, Suspense } from 'react'; import { Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import styled, { AnyStyledComponent, css } from 'styled-components'; import styled, { AnyStyledComponent, css } from 'styled-components';
import { WagmiConfig } from 'wagmi'; 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, MarketsRoute } from '@/constants/routes'; import { AppRoute, DEFAULT_TRADE_ROUTE } from '@/constants/routes';
import { import {
useBreakpoints, useBreakpoints,
@@ -16,17 +16,26 @@ 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 { 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';
import { SquidProvider } from '@/hooks/useSquid';
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute'; import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
import MarketsPage from '@/pages/markets/Markets';
import PortfolioPage from '@/pages/portfolio/Portfolio';
import { AlertsPage } from '@/pages/AlertsPage';
import ProfilePage from '@/pages/Profile';
import { SettingsPage } from '@/pages/settings/Settings';
import TradePage from '@/pages/trade/Trade';
import { RewardsPage } from '@/pages/rewards/RewardsPage';
import { TermsOfUsePage } from '@/pages/TermsOfUsePage';
import { PrivacyPolicyPage } from '@/pages/PrivacyPolicyPage';
import { HeaderDesktop } from '@/layout/Header/HeaderDesktop'; import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
import { FooterDesktop } from '@/layout/Footer/FooterDesktop'; import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
import { FooterMobile } from '@/layout/Footer/FooterMobile'; import { FooterMobile } from '@/layout/Footer/FooterMobile';
@@ -37,25 +46,12 @@ import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';
import { config } from '@/lib/wagmi'; import { config } from '@/lib/wagmi';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
import { GlobalStyle } from '@/styles/globalStyle';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { LoadingSpace } from './components/Loading/LoadingSpinner';
import '@/styles/constants.css'; 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 PortfolioPage = lazy(() => import('@/pages/portfolio/Portfolio'));
const AlertsPage = lazy(() => import('@/pages/AlertsPage'));
const ProfilePage = lazy(() => import('@/pages/Profile'));
const SettingsPage = lazy(() => import('@/pages/settings/Settings'));
const TradePage = lazy(() => import('@/pages/trade/Trade'));
const TermsOfUsePage = lazy(() => import('@/pages/TermsOfUsePage'));
const PrivacyPolicyPage = lazy(() => import('@/pages/PrivacyPolicyPage'));
const TokenPage = lazy(() => import('@/pages/token/Token'));
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const Content = () => { const Content = () => {
@@ -70,55 +66,49 @@ const Content = () => {
const { chainTokenLabel } = useTokenConfigs(); const { chainTokenLabel } = useTokenConfigs();
return ( return (
<> <Styled.Content isShowingHeader={isShowingHeader} isShowingFooter={isShowingFooter}>
<GlobalStyle /> {isNotTablet && <HeaderDesktop />}
<Styled.Content isShowingHeader={isShowingHeader} isShowingFooter={isShowingFooter}>
{isNotTablet && <HeaderDesktop />}
<Styled.Main> <Styled.Main>
<Suspense fallback={<LoadingSpace id="main" />}> <Suspense fallback={null}>
<Routes> <Routes>
<Route path={AppRoute.Trade}> <Route path={AppRoute.Trade}>
<Route path=":market" element={<TradePage />} /> <Route path=":market" element={<TradePage />} />
<Route path={AppRoute.Trade} element={<TradePage />} /> <Route path={AppRoute.Trade} element={<TradePage />} />
</Route> </Route>
<Route path={AppRoute.Markets}> <Route path={AppRoute.Markets} element={<MarketsPage />} />
<Route path={MarketsRoute.New} element={<NewMarket />} /> <Route path={`/${chainTokenLabel}`} element={<RewardsPage />} />
<Route path={AppRoute.Markets} element={<MarketsPage />} /> {isTablet && (
</Route> <>
<Route path={`/${chainTokenLabel}/*`} element={<TokenPage />} /> <Route path={AppRoute.Alerts} element={<AlertsPage />} />
{isTablet && ( <Route path={AppRoute.Profile} element={<ProfilePage />} />
<> <Route path={`${AppRoute.Settings}/*`} element={<SettingsPage />} />
<Route path={AppRoute.Alerts} element={<AlertsPage />} /> </>
<Route path={AppRoute.Profile} element={<ProfilePage />} /> )}
<Route path={`${AppRoute.Settings}/*`} element={<SettingsPage />} />
</>
)}
<Route element={<GuardedMobileRoute />}> <Route element={<GuardedMobileRoute />}>
<Route path={`${AppRoute.Portfolio}/*`} element={<PortfolioPage />} /> <Route path={`${AppRoute.Portfolio}/*`} element={<PortfolioPage />} />
</Route> </Route>
<Route path={AppRoute.Terms} element={<TermsOfUsePage />} /> <Route path={AppRoute.Terms} element={<TermsOfUsePage />} />
<Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} /> <Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} />
<Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} /> <Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} />
</Routes> </Routes>
</Suspense> </Suspense>
</Styled.Main> </Styled.Main>
{isTablet ? <FooterMobile /> : <FooterDesktop />} {isTablet ? <FooterMobile /> : <FooterDesktop />}
<Styled.NotificationsToastArea /> <Styled.NotificationsToastArea />
<Styled.DialogArea ref={setDialogArea}> <Styled.DialogArea ref={setDialogArea}>
<DialogManager /> <DialogManager />
</Styled.DialogArea> </Styled.DialogArea>
<GlobalCommandDialog /> <GlobalCommandDialog />
</Styled.Content> </Styled.Content>
</>
); );
}; };
@@ -138,11 +128,10 @@ const providers = [
wrapProvider(DydxProvider), wrapProvider(DydxProvider),
wrapProvider(AccountsProvider), wrapProvider(AccountsProvider),
wrapProvider(SubaccountProvider), wrapProvider(SubaccountProvider),
wrapProvider(SquidProvider),
wrapProvider(LocalNotificationsProvider), wrapProvider(LocalNotificationsProvider),
wrapProvider(NotificationsProvider), wrapProvider(NotificationsProvider),
wrapProvider(DialogAreaProvider), wrapProvider(DialogAreaProvider),
wrapProvider(PotentialMarketsProvider),
wrapProvider(AppThemeAndColorModeProvider),
]; ];
const App = () => { const App = () => {
@@ -207,7 +196,6 @@ Styled.Content = styled.div<{ isShowingHeader: boolean; isShowingFooter: boolean
Styled.Main = styled.main` Styled.Main = styled.main`
${layoutMixins.contentSectionAttached} ${layoutMixins.contentSectionAttached}
box-shadow: none;
grid-area: Main; grid-area: Main;
-390
View File
@@ -1,390 +0,0 @@
[
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [{ "name": "", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_upgradedAddress", "type": "address" }],
"name": "deprecate",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "_spender", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "approve",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "deprecated",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_evilUser", "type": "address" }],
"name": "addBlackList",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "_from", "type": "address" },
{ "name": "_to", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "transferFrom",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "upgradedAddress",
"outputs": [{ "name": "", "type": "address" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "", "type": "address" }],
"name": "balances",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "maximumFee",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "_totalSupply",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "unpause",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "_maker", "type": "address" }],
"name": "getBlackListStatus",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "name": "", "type": "address" },
{ "name": "", "type": "address" }
],
"name": "allowed",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "paused",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "who", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "pause",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getOwner",
"outputs": [{ "name": "", "type": "address" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [{ "name": "", "type": "address" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [{ "name": "", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "_to", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "transfer",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "newBasisPoints", "type": "uint256" },
{ "name": "newMaxFee", "type": "uint256" }
],
"name": "setParams",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "amount", "type": "uint256" }],
"name": "issue",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "amount", "type": "uint256" }],
"name": "redeem",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "name": "_owner", "type": "address" },
{ "name": "_spender", "type": "address" }
],
"name": "allowance",
"outputs": [{ "name": "remaining", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "basisPointsRate",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "", "type": "address" }],
"name": "isBlackListed",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_clearedUser", "type": "address" }],
"name": "removeBlackList",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "MAX_UINT",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "newOwner", "type": "address" }],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_blackListedUser", "type": "address" }],
"name": "destroyBlackFunds",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "name": "_initialSupply", "type": "uint256" },
{ "name": "_name", "type": "string" },
{ "name": "_symbol", "type": "string" },
{ "name": "_decimals", "type": "uint256" }
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "amount", "type": "uint256" }],
"name": "Issue",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "amount", "type": "uint256" }],
"name": "Redeem",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "newAddress", "type": "address" }],
"name": "Deprecate",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "name": "feeBasisPoints", "type": "uint256" },
{ "indexed": false, "name": "maxFee", "type": "uint256" }
],
"name": "Params",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "name": "_blackListedUser", "type": "address" },
{ "indexed": false, "name": "_balance", "type": "uint256" }
],
"name": "DestroyedBlackFunds",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "_user", "type": "address" }],
"name": "AddedBlackList",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "_user", "type": "address" }],
"name": "RemovedBlackList",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "owner", "type": "address" },
{ "indexed": true, "name": "spender", "type": "address" },
{ "indexed": false, "name": "value", "type": "uint256" }
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "from", "type": "address" },
{ "indexed": true, "name": "to", "type": "address" },
{ "indexed": false, "name": "value", "type": "uint256" }
],
"name": "Transfer",
"type": "event"
},
{ "anonymous": false, "inputs": [], "name": "Pause", "type": "event" },
{ "anonymous": false, "inputs": [], "name": "Unpause", "type": "event" }
]
-26
View File
@@ -1,26 +0,0 @@
import type { Story } from '@ladle/react';
import { Accordion as AccordionComponent, AccordionProps } from '@/components/Accordion';
import { StoryWrapper } from '.ladle/components';
export const Accordion: Story<AccordionProps> = (args) => {
return (
<StoryWrapper>
<AccordionComponent {...args} />
</StoryWrapper>
);
};
Accordion.args = {
items: [
{
header: 'Question 1?',
content: 'Answer 1.',
},
{
header: 'Question 2?',
content: 'Answer 2.',
},
],
};
-129
View File
@@ -1,129 +0,0 @@
import styled, { keyframes, type AnyStyledComponent } from 'styled-components';
import { Root, Item, Header, Trigger, Content } from '@radix-ui/react-accordion';
import { layoutMixins } from '@/styles/layoutMixins';
import { breakpoints } from '@/styles';
import { PlusIcon } from '@/icons';
export type AccordionItem = {
header: React.ReactNode;
content: React.ReactNode;
};
export type AccordionProps = {
items: AccordionItem[];
className?: string;
};
export const Accordion = ({ items, className }: AccordionProps) => (
<Styled.Root className={className} type="single" collapsible>
{items.map(({ header, content }, idx) => (
<Styled.Item key={idx} value={idx.toString()}>
<Header>
<Styled.Trigger>
{header}
<Styled.Icon>
<PlusIcon />
</Styled.Icon>
</Styled.Trigger>
</Header>
<Styled.Content>{content}</Styled.Content>
</Styled.Item>
))}
</Styled.Root>
);
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Root = styled(Root)`
--accordion-paddingY: 1rem;
--accordion-paddingX: 1rem;
@media ${breakpoints.notTablet} {
--accordion-paddingX: 1.5rem;
}
> *:not(:last-child) {
border-bottom: var(--border-width) solid var(--border-color);
}
`;
Styled.Item = styled(Item)``;
Styled.Icon = styled.div`
display: inline-flex;
justify-content: center;
align-items: center;
width: 2.25rem;
height: 2.25rem;
--color-border: var(--color-layer-6);
color: var(--color-text-1);
background-color: var(--color-layer-5);
border: solid var(--border-width) var(--color-border);
border-radius: 50%;
font: var(--font-small-book);
svg {
height: 1.125em;
width: 1.125em;
}
`;
Styled.Trigger = styled(Trigger)`
${layoutMixins.spacedRow}
width: 100%;
padding: var(--accordion-paddingY) var(--accordion-paddingX);
gap: 0.5rem;
color: var(--color-text-1);
text-align: start;
&:hover {
${Styled.Icon} {
color: var(--color-text-2);
filter: brightness(var(--hover-filter-base));
}
}
svg {
color: var(--color-text-0);
transition: transform 0.3s var(--ease-out-expo);
}
&[data-state='open'] svg {
transform: rotate(45deg);
}
`;
Styled.Content = styled(Content)`
overflow: hidden;
margin: 0 var(--accordion-paddingX) var(--accordion-paddingY);
color: var(--color-text-0);
&[data-state='open'] {
animation: ${keyframes`
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
`} 0.3s var(--ease-out-expo);
}
&[data-state='closed'] {
animation: ${keyframes`
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
`} 0.1s var(--ease-in-expo);
}
`;
+3
View File
@@ -40,6 +40,9 @@ const AlertContainer = styled.div<StyleProps>`
case AlertType.Info: { case AlertType.Info: {
return css` return css`
--alert-accent-color: var(--color-text-1); --alert-accent-color: var(--color-text-1);
--alert-default-background-opacity: 0.133; // Relative
// --alert-background: var(--color-layer-6); // Absolute
`; `;
} }
case AlertType.Success: { case AlertType.Success: {
+2 -10
View File
@@ -16,7 +16,6 @@ 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',
@@ -31,7 +30,6 @@ const assetIcons = {
ETH: '/currencies/eth.png', ETH: '/currencies/eth.png',
FIL: '/currencies/fil.png', FIL: '/currencies/fil.png',
ICP: '/currencies/icp.png', ICP: '/currencies/icp.png',
JUP: '/currencies/jup.png',
LDO: '/currencies/ldo.png', LDO: '/currencies/ldo.png',
LINK: '/currencies/link.png', LINK: '/currencies/link.png',
LTC: '/currencies/ltc.png', LTC: '/currencies/ltc.png',
@@ -47,7 +45,6 @@ const assetIcons = {
SOL: '/currencies/sol.png', SOL: '/currencies/sol.png',
SUI: '/currencies/sui.png', SUI: '/currencies/sui.png',
SUSHI: '/currencies/sushi.png', SUSHI: '/currencies/sushi.png',
TIA: '/currencies/tia.png',
TRX: '/currencies/trx.png', TRX: '/currencies/trx.png',
UMA: '/currencies/uma.png', UMA: '/currencies/uma.png',
UNI: '/currencies/uni.png', UNI: '/currencies/uni.png',
@@ -74,13 +71,8 @@ export const AssetIcon = ({
}: { }: {
symbol?: Nullable<string>; symbol?: Nullable<string>;
className?: string; className?: string;
}) => ( }) =>
<Styled.Img isAssetSymbol(symbol) ? <Styled.Img src={assetIcons[symbol]} className={className} /> : null;
src={isAssetSymbol(symbol) ? assetIcons[symbol] : '/currencies/unavailable.png'}
className={className}
alt={symbol}
/>
);
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
+2 -2
View File
@@ -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(var(--active-filter)); --button-active-filter: brightness(0.9);
--button-hover-filter: brightness(var(--hover-filter-base)); --button-hover-filter: brightness(1.1);
--button-hover-textColor: var(--button-textColor); --button-hover-textColor: var(--button-textColor);
--button-radius: 0.5em; --button-radius: 0.5em;
+7 -11
View File
@@ -61,7 +61,7 @@ export const Button = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonPr
return ( return (
<StyledBaseButton <StyledBaseButton
disabled={state[ButtonState.Disabled] || state[ButtonState.Loading]} disabled={state[ButtonState.Disabled]}
{...{ ref, action, size, shape, state, ...otherProps }} {...{ ref, action, size, shape, state, ...otherProps }}
> >
{ {
@@ -89,10 +89,9 @@ 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-button); --button-textColor: var(--color-text-2);
--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`
@@ -102,17 +101,15 @@ const buttonActionVariants = {
`, `,
[ButtonAction.Create]: css` [ButtonAction.Create]: css`
--button-textColor: var(--color-text-button); --button-textColor: var(--color-text-2);
--button-backgroundColor: var(--color-green); --button-backgroundColor: var(--color-positive);
--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-button); --button-textColor: var(--color-text-2);
--button-backgroundColor: var(--color-red); --button-backgroundColor: var(--color-negative);
--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`
@@ -122,10 +119,9 @@ const buttonActionVariants = {
`, `,
[ButtonAction.Reset]: css` [ButtonAction.Reset]: css`
--button-textColor: var(--color-red); --button-textColor: var(--color-negative);
--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));
`, `,
}; };
-13
View File
@@ -1,13 +0,0 @@
import { forwardRef } from 'react';
type CanvasProps = {
className?: string;
width: number | string;
height: number | string;
};
export const Canvas = forwardRef<HTMLCanvasElement, CanvasProps>(
({ className, width, height }, canvasRef) => (
<canvas ref={canvasRef} className={className} width={width} height={height} />
)
);
+3 -13
View File
@@ -5,7 +5,7 @@ import { Checkbox, CheckboxProps } from '@/components/Checkbox';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
export const CheckboxStory: Story<CheckboxProps> = (args) => { export const Checkboxes: Story<CheckboxProps> = (args) => {
const [isChecked, setIsChecked] = useState(false); const [isChecked, setIsChecked] = useState(false);
return ( return (
@@ -13,20 +13,10 @@ export const CheckboxStory: Story<CheckboxProps> = (args) => {
<Checkbox <Checkbox
{...args} {...args}
checked={isChecked} checked={isChecked}
onCheckedChange={setIsChecked} onClick={(e: React.ChangeEvent) => setIsChecked((e.target as HTMLInputElement).checked)}
id="story-checkbox"
label="example label"
/> />
</StoryWrapper> </StoryWrapper>
); );
}; };
CheckboxStory.args = {}; Checkboxes.args = {};
CheckboxStory.argTypes = {
disabled: {
options: [true, false],
control: { type: 'select' },
defaultValue: false,
}
}
+70 -69
View File
@@ -1,15 +1,10 @@
import styled, { css, type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { Root, Indicator } from '@radix-ui/react-checkbox';
import { CheckIcon } from '@radix-ui/react-icons';
import { layoutMixins } from '@/styles/layoutMixins'; import { breakpoints } from '@/styles';
type ElementProps = { type ElementProps = {
checked: boolean; checked: boolean;
onCheckedChange: (checked: boolean) => void; onClick: (e: React.ChangeEvent) => void;
id?: string;
label?: React.ReactNode;
disabled?: boolean;
}; };
type StyleProps = { type StyleProps = {
@@ -18,79 +13,85 @@ type StyleProps = {
export type CheckboxProps = ElementProps & StyleProps; export type CheckboxProps = ElementProps & StyleProps;
export const Checkbox: React.FC<CheckboxProps> = ({ export const Checkbox: React.FC<CheckboxProps> = ({ checked, className, onClick }) => {
checked, return (
className, <Styled.CheckboxWrapper className={className}>
onCheckedChange, <Styled.Checkbox
id, type="checkbox"
label, checked={checked}
disabled, onChange={onClick}
}) => ( />
<Styled.Container> <Styled.CustomCheckbox />
<Styled.Root </Styled.CheckboxWrapper>
className={className} );
checked={checked} };
disabled={disabled}
onCheckedChange={onCheckedChange}
id={id}
>
<Styled.Indicator>
<CheckIcon />
</Styled.Indicator>
</Styled.Root>
{label && (
<Styled.Label disabled={disabled} htmlFor={id}>
{label}
</Styled.Label>
)}
</Styled.Container>
);
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
Styled.Container = styled.div` Styled.CustomCheckbox = styled.span`
${layoutMixins.row} width: 1.25em;
gap: 1ch; height: 1.25em;
font: var(--font-small-book);
`;
Styled.Root = styled(Root)` position: absolute;
--checkbox-backgroundColor: var(--color-layer-0); left: 0;
--checkbox-borderColor: var(--color-border); right: 0;
top: 0;
min-width: 1.25rem; bottom: 0;
height: 1.25rem;
border-radius: 0.375rem;
border: var(--border-width) solid var(--checkbox-borderColor);
background-color: var(--checkbox-backgroundColor); background-color: var(--checkbox-backgroundColor);
&[data-state='checked'] { &::after {
--checkbox-backgroundColor: var(--color-accent); position: absolute;
content: '';
top: 0.25em;
left: 0.4375em;
width: 0.3125em;
height: 0.5em;
border: solid var(--checkbox-checkColor);
border-width: 0 0.125em 0.125em 0;
border-radius: 0.0625em;
opacity: 0;
transform: rotate(0deg) scale(0);
transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out;
} }
&[data-disabled] { @media ${breakpoints.tablet} {
cursor: not-allowed; width: 1.5em;
--checkbox-backgroundColor: var(--color-layer-1); height: 1.5em;
&::after {
top: 0.25em;
left: 0.4375em;
width: 0.4375em;
height: 0.625em;
}
} }
`; `;
Styled.Indicator = styled(Indicator)` Styled.CheckboxWrapper = styled.div`
--checkbox-backgroundColor: var(--color-layer-1);
--checkbox-checkColor: var(--color-text-1);
display: flex; display: flex;
align-items: center; border-radius: 0.25em;
justify-content: center; overflow: hidden;
position: relative;
color: var(--color-text-button);
`;
Styled.Label = styled.label<{ disabled?: boolean }>`
cursor: pointer; cursor: pointer;
color: var(--color-text-2);
${({ disabled }) => > input:checked ~ ${Styled.CustomCheckbox}::after {
disabled && opacity: 1;
css` transform: rotate(40deg) scale(1);
cursor: not-allowed; }
color: var(--color-text-0); `;
`}
Styled.Checkbox = styled.input`
width: 1.25em;
height: 1.25em;
z-index: 1;
cursor: pointer;
opacity: 0;
@media ${breakpoints.tablet} {
width: 1.5em;
height: 1.5em;
}
`; `;
+6 -5
View File
@@ -1,13 +1,16 @@
import type { Story } from '@ladle/react'; import type { Story } from '@ladle/react';
import { Collapsible, type CollapsibleProps } from '@/components/Collapsible'; import { Collapsible } from '@/components/Collapsible';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
import { IconName } from './Icon'; import { IconName } from './Icon';
export const CollapsibleStory: Story<CollapsibleProps> = (args) => ( export const CollapsibleStory: Story<Parameters<typeof Collapsible>> = (args) => (
<StoryWrapper> <StoryWrapper>
<Collapsible {...args}> <Collapsible
label="Collapsible List of Items"
{...args}
>
<ul> <ul>
<li>Collapsible Item 1</li> <li>Collapsible Item 1</li>
<li>Collapsible Item 2</li> <li>Collapsible Item 2</li>
@@ -20,8 +23,6 @@ export const CollapsibleStory: Story<CollapsibleProps> = (args) => (
CollapsibleStory.args = { CollapsibleStory.args = {
disabled: false, disabled: false,
withTrigger: true,
label: 'Collapsible List of Items',
}; };
CollapsibleStory.argTypes = { CollapsibleStory.argTypes = {
+18 -24
View File
@@ -14,7 +14,6 @@ type ElementProps = {
label: React.ReactNode; label: React.ReactNode;
triggerIcon?: IconName; triggerIcon?: IconName;
children: React.ReactNode; children: React.ReactNode;
withTrigger?: boolean;
}; };
type StyleProps = { type StyleProps = {
@@ -24,8 +23,6 @@ type StyleProps = {
fullWidth?: boolean; fullWidth?: boolean;
}; };
export type CollapsibleProps = ElementProps & StyleProps;
export const Collapsible = ({ export const Collapsible = ({
defaultOpen = false, defaultOpen = false,
disabled, disabled,
@@ -38,29 +35,26 @@ export const Collapsible = ({
triggerIconSide = 'left', triggerIconSide = 'left',
fullWidth, fullWidth,
className, className,
withTrigger = true, }: ElementProps & StyleProps) => (
}: CollapsibleProps) => (
<Styled.Root defaultOpen={defaultOpen} open={open} onOpenChange={onOpenChange}> <Styled.Root defaultOpen={defaultOpen} open={open} onOpenChange={onOpenChange}>
{withTrigger && ( <Styled.Trigger className={className} disabled={disabled}>
<Styled.Trigger className={className} disabled={disabled}> {triggerIconSide === 'right' && (
{triggerIconSide === 'right' && ( <>
<> {label}
{label} {fullWidth && <HorizontalSeparatorFiller />}
{fullWidth && <HorizontalSeparatorFiller />} </>
</> )}
)}
<Styled.TriggerIcon> <Styled.TriggerIcon>
<Icon iconName={triggerIcon} /> <Icon iconName={triggerIcon} />
</Styled.TriggerIcon> </Styled.TriggerIcon>
{triggerIconSide === 'left' && ( {triggerIconSide === 'left' && (
<> <>
{fullWidth && <HorizontalSeparatorFiller />} {fullWidth && <HorizontalSeparatorFiller />}
{label} {label}
</> </>
)} )}
</Styled.Trigger> </Styled.Trigger>
)}
<Styled.Content $transitionDuration={transitionDuration}>{children}</Styled.Content> <Styled.Content $transitionDuration={transitionDuration}>{children}</Styled.Content>
</Styled.Root> </Styled.Root>
); );
+5 -7
View File
@@ -31,12 +31,10 @@ type ElementProps<TabItemsValue> = {
}; };
type StyleProps = { type StyleProps = {
className?: string;
fullWidthTabs?: boolean; fullWidthTabs?: boolean;
className?: string;
}; };
export type CollapsibleTabsProps<TabItemsValue> = ElementProps<TabItemsValue> & StyleProps;
export const CollapsibleTabs = <TabItemsValue extends string>({ export const CollapsibleTabs = <TabItemsValue extends string>({
defaultValue, defaultValue,
items, items,
@@ -45,9 +43,8 @@ export const CollapsibleTabs = <TabItemsValue extends string>({
onOpenChange, onOpenChange,
fullWidthTabs, fullWidthTabs,
className, className,
}: CollapsibleTabsProps<TabItemsValue>) => { }: ElementProps<TabItemsValue> & StyleProps) => {
const [value, setValue] = useState(defaultValue); const [value, setValue] = useState(defaultValue);
const currentItem = items.find((item) => item.value === value); const currentItem = items.find((item) => item.value === value);
@@ -89,8 +86,8 @@ export const CollapsibleTabs = <TabItemsValue extends string>({
</Styled.Header> </Styled.Header>
<Styled.CollapsibleContent> <Styled.CollapsibleContent>
{items.map(({ asChild, value, content }) => ( {items.map(({ value, content }) => (
<Styled.TabsContent key={value} asChild={asChild} value={value}> <Styled.TabsContent key={value} value={value}>
{content} {content}
</Styled.TabsContent> </Styled.TabsContent>
))} ))}
@@ -222,6 +219,7 @@ Styled.Header = styled.header`
Styled.CollapsibleContent = styled(CollapsibleContent)` Styled.CollapsibleContent = styled(CollapsibleContent)`
${layoutMixins.stack} ${layoutMixins.stack}
${layoutMixins.perspectiveArea}
box-shadow: none; box-shadow: none;
`; `;
+2 -13
View File
@@ -22,12 +22,7 @@ type PickComboxMenuProps<
MenuGroupValue extends string | number MenuGroupValue extends string | number
> = Pick< > = Pick<
ComboboxMenuProps<MenuItemValue, MenuGroupValue>, ComboboxMenuProps<MenuItemValue, MenuGroupValue>,
| 'inputPlaceholder' 'inputPlaceholder' | 'onItemSelected' | 'slotEmpty' | 'withSearch' | 'withStickyLayout'
| 'onItemSelected'
| 'slotEmpty'
| 'withItemBorders'
| 'withSearch'
| 'withStickyLayout'
>; >;
type PickDialogProps = Pick< type PickDialogProps = Pick<
@@ -58,7 +53,6 @@ export const ComboboxDialogMenu = <
onItemSelected, onItemSelected,
inputPlaceholder, inputPlaceholder,
slotEmpty, slotEmpty,
withItemBorders,
withSearch, withSearch,
withStickyLayout = true, withStickyLayout = true,
children, children,
@@ -89,7 +83,6 @@ export const ComboboxDialogMenu = <
title={title} title={title}
inputPlaceholder={inputPlaceholder} inputPlaceholder={inputPlaceholder}
slotEmpty={slotEmpty} slotEmpty={slotEmpty}
withItemBorders={withItemBorders}
withSearch={withSearch} withSearch={withSearch}
withStickyLayout={withStickyLayout} withStickyLayout={withStickyLayout}
/> />
@@ -102,8 +95,6 @@ const Styled: Record<string, AnyStyledComponent> = {};
Styled.Dialog = styled(Dialog)` Styled.Dialog = styled(Dialog)`
/* Params */ /* Params */
--comboboxDialogMenu-backgroundColor: var(--color-layer-2); --comboboxDialogMenu-backgroundColor: var(--color-layer-2);
--comboboxDialogMenu-item-gap: 0.5rem;
--comboboxDialogMenu-item-padding: 0.5rem 1rem;
/* Overrides */ /* Overrides */
& { & {
@@ -122,12 +113,10 @@ Styled.Dialog = styled(Dialog)`
/* Net 0 sticky top inset (let stickyArea1 header stick to top) */ /* Net 0 sticky top inset (let stickyArea1 header stick to top) */
--stickyArea0-topGap: calc(-1 * var(--stickyArea0-topHeight)); --stickyArea0-topGap: calc(-1 * var(--stickyArea0-topHeight));
overflow-x: clip;
} }
`; `;
Styled.ComboboxMenu = styled(ComboboxMenu)` Styled.ComboboxMenu = styled(ComboboxMenu)`
--comboboxMenu-backgroundColor: var(--comboboxDialogMenu-backgroundColor); --comboboxMenu-backgroundColor: var(--comboboxDialogMenu-backgroundColor);
--comboboxMenu-item-gap: var(--comboboxDialogMenu-item-gap); --comboboxMenu-item-gap: var(--comboxDialogMenu-item-gap, 0.5rem);
--comboboxMenu-item-padding: var(--comboboxDialogMenu-item-padding);
`; `;
+30 -61
View File
@@ -2,7 +2,7 @@ import { Fragment, type ReactNode, useState } from 'react';
import styled, { type AnyStyledComponent, css } from 'styled-components'; import styled, { type AnyStyledComponent, css } from 'styled-components';
import { Command } from 'cmdk'; import { Command } from 'cmdk';
import { MenuItem, type MenuConfig } from '@/constants/menus'; import { type MenuConfig } from '@/constants/menus';
import { popoverMixins } from '@/styles/popoverMixins'; import { popoverMixins } from '@/styles/popoverMixins';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
@@ -20,7 +20,6 @@ type ElementProps<MenuItemValue extends string | number, MenuGroupValue extends
type StyleProps = { type StyleProps = {
className?: string; className?: string;
withItemBorders?: boolean;
withStickyLayout?: boolean; withStickyLayout?: boolean;
}; };
@@ -39,36 +38,38 @@ export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extend
withSearch = true, withSearch = true,
className, className,
withItemBorders,
withStickyLayout, withStickyLayout,
}: ComboboxMenuProps<MenuItemValue, MenuGroupValue>) => { }: ComboboxMenuProps<MenuItemValue, MenuGroupValue>) => {
const [highlightedCommand, setHighlightedCommand] = useState<MenuItemValue>(); const [highlightedCommand, setHighlightedCommand] = useState<MenuItemValue>();
const [searchValue, setSearchValue] = useState(''); const [searchValue, setSearchValue] = useState('');
// const inputRef = useRef<HTMLInputElement | null>(null);
// console.log({ commandValue: highlightedCommand });
// useEffect(() => {
// inputRef?.current?.focus();
// }, []);
return ( return (
<Styled.Command <Styled.Command
label={title} label={title}
// value={highlightedCommand} // value={highlightedCommand}
// onValueChange={setHighlightedCommand} // onValueChange={setHighlightedCommand}
filter={(value: string, search: string) => filter={(value: string, search: string) => {
value.replace(/ /g, '').toLowerCase().includes(search.replace(/ /g, '').toLowerCase()) if (value.replace(/ /g, '').includes(search.replace(/ /g, ''))) return 1;
? 1 return 0;
: 0 }}
}
className={className} className={className}
$withStickyLayout={withStickyLayout} $withStickyLayout={withStickyLayout}
> >
{withSearch && ( {withSearch && (
<Styled.Header $withStickyLayout={withStickyLayout}> <Styled.Header $withStickyLayout={withStickyLayout}>
<Styled.Input <Styled.Input
/** // ref={inputRef}
* Mobile Issue: Search Input will always trigger mobile keyboard drawer. There is no fix.
* https://github.com/pacocoursey/cmdk/issues/127
*/
autoFocus
type="search" type="search"
value={searchValue} value={searchValue}
onValueChange={setSearchValue} onValueChange={setSearchValue}
autoFocus
placeholder={inputPlaceholder} placeholder={inputPlaceholder}
/> />
</Styled.Header> </Styled.Header>
@@ -79,7 +80,6 @@ export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extend
<Styled.Group <Styled.Group
key={group.group} key={group.group}
heading={group.groupLabel} heading={group.groupLabel}
$withItemBorders={withItemBorders}
$withStickyLayout={withStickyLayout} $withStickyLayout={withStickyLayout}
> >
{group.items.map((item) => ( {group.items.map((item) => (
@@ -99,31 +99,22 @@ export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extend
} }
}} }}
disabled={item.disabled} disabled={item.disabled}
$withItemBorders={withItemBorders}
> >
{ {item.slotBefore}
<> <Styled.ItemLabel>
{item.slotBefore} <span>
{item.slotCustomContent ?? ( {`${item.label}${item.subitems?.length ? '…' : ''}`}
<Styled.ItemLabel> {item.tag && (
<span> <>
{typeof item.label === 'string' {' '}
? `${item.label}${item.subitems?.length ? '…' : ''}` <Tag>{item.tag}</Tag>
: item.label} </>
{item.tag && (
<>
{' '}
<Tag>{item.tag}</Tag>
</>
)}
</span>
{item.description && <span>{item.description}</span>}
</Styled.ItemLabel>
)} )}
{item.slotAfter} </span>
{item.subitems && '→'} {item.description && <span>{item.description}</span>}
</> </Styled.ItemLabel>
} {item.slotAfter}
{item.subitems && '→'}
</Styled.Item> </Styled.Item>
{searchValue && {searchValue &&
@@ -146,7 +137,6 @@ export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extend
onItemSelected?.(); onItemSelected?.();
}} }}
disabled={subitem.disabled} disabled={subitem.disabled}
$withItemBorders={withItemBorders}
> >
{subitem.slotBefore} {subitem.slotBefore}
<Styled.ItemLabel> <Styled.ItemLabel>
@@ -179,17 +169,14 @@ const Styled: Record<string, AnyStyledComponent> = {};
Styled.Command = styled(Command)<{ $withStickyLayout?: boolean }>` Styled.Command = styled(Command)<{ $withStickyLayout?: boolean }>`
--comboboxMenu-backgroundColor: var(--color-layer-2); --comboboxMenu-backgroundColor: var(--color-layer-2);
--comboboxMenu-input-backgroundColor: var(--color-layer-3); --comboboxMenu-input-backgroundColor: var(--color-layer-3);
--comboboxMenu-input-height: 2.5rem; --comboboxMenu-input-height: 2.5rem;
--comboboxMenu-item-checked-backgroundColor: ; --comboboxMenu-item-checked-backgroundColor: ;
--comboboxMenu-item-checked-textColor: ; --comboboxMenu-item-checked-textColor: ;
--comboboxMenu-item-highlighted-backgroundColor: var(--color-layer-3); --comboboxMenu-item-highlighted-backgroundColor: var(--color-layer-3);
--comboboxMenu-item-highlighted-textColor: var(--color-text-1); --comboboxMenu-item-highlighted-textColor: var(--color-text-1);
--comboboxMenu-item-backgroundColor: ; --comboboxMenu-item-backgroundColor: ;
--comboboxMenu-item-gap: 0.5rem; --comboboxMenu-item-gap: 0.5rem;
--comboboxMenu-item-padding: 0.5em 1em;
display: grid; display: grid;
align-content: start; align-content: start;
@@ -238,7 +225,7 @@ Styled.Input = styled(Command.Input)`
gap: 0.5rem; gap: 0.5rem;
`; `;
Styled.Group = styled(Command.Group)<{ $withItemBorders?: boolean; $withStickyLayout?: boolean }>` Styled.Group = styled(Command.Group)<{ $withStickyLayout?: boolean }>`
color: var(--color-text-0); color: var(--color-text-0);
> [cmdk-group-heading] { > [cmdk-group-heading] {
@@ -255,21 +242,12 @@ Styled.Group = styled(Command.Group)<{ $withItemBorders?: boolean; $withStickyLa
> [cmdk-group-heading] { > [cmdk-group-heading] {
${layoutMixins.stickyHeader} ${layoutMixins.stickyHeader}
z-index: 2;
} }
> [cmdk-group-items] { > [cmdk-group-items] {
${layoutMixins.stickyArea3} ${layoutMixins.stickyArea3}
} }
`} `}
${({ $withItemBorders }) =>
$withItemBorders &&
css`
> [cmdk-group-items] {
padding: var(--border-width) 0;
}
`}
`; `;
Styled.List = styled(Command.List)<{ $withStickyLayout?: boolean }>` Styled.List = styled(Command.List)<{ $withStickyLayout?: boolean }>`
@@ -296,14 +274,13 @@ Styled.List = styled(Command.List)<{ $withStickyLayout?: boolean }>`
`} `}
`; `;
Styled.Item = styled(Command.Item)<{ $withItemBorders?: boolean }>` Styled.Item = styled(Command.Item)`
${layoutMixins.scrollSnapItem} ${layoutMixins.scrollSnapItem}
${popoverMixins.item} ${popoverMixins.item}
--item-checked-backgroundColor: var(--comboboxMenu-item-checked-backgroundColor); --item-checked-backgroundColor: var(--comboboxMenu-item-checked-backgroundColor);
--item-checked-textColor: var(--comboboxMenu-item-checked-textColor); --item-checked-textColor: var(--comboboxMenu-item-checked-textColor);
--item-highlighted-textColor: var(--comboboxMenu-item-highlighted-textColor); --item-highlighted-textColor: var(--comboboxMenu-item-highlighted-textColor);
--item-gap: var(--comboboxMenu-item-gap); --item-gap: var(--comboboxMenu-item-gap);
--item-padding: var(--comboboxMenu-item-padding);
background-color: var(--comboboxMenu-backgroundColor, inherit); background-color: var(--comboboxMenu-backgroundColor, inherit);
@@ -314,12 +291,6 @@ Styled.Item = styled(Command.Item)<{ $withItemBorders?: boolean }>`
opacity: 0.75; opacity: 0.75;
cursor: not-allowed; cursor: not-allowed;
} }
${({ $withItemBorders }) =>
$withItemBorders &&
css`
${layoutMixins.withOuterBorder}
`}
`; `;
Styled.ItemLabel = styled.div` Styled.ItemLabel = styled.div`
@@ -338,8 +309,6 @@ Styled.ItemLabel = styled.div`
opacity: 0.8; opacity: 0.8;
} }
} }
min-width: 0;
`; `;
Styled.Empty = styled(Command.Empty)` Styled.Empty = styled(Command.Empty)`
+1
View File
@@ -11,5 +11,6 @@ export const DetachedScrollableSection = styled.section`
export const AttachedExpandingSection = styled.section` export const AttachedExpandingSection = styled.section`
${layoutMixins.contentSectionAttached} ${layoutMixins.contentSectionAttached}
${layoutMixins.expandingColumnWithHeader}
gap: var(--border-width); gap: var(--border-width);
`; `;
+9 -13
View File
@@ -6,7 +6,6 @@ import { layoutMixins } from '@/styles/layoutMixins';
type ElementProps = { type ElementProps = {
title: string; title: string;
subtitle?: React.ReactNode; subtitle?: React.ReactNode;
slotLeft?: React.ReactNode;
slotRight?: React.ReactNode; slotRight?: React.ReactNode;
}; };
@@ -17,16 +16,14 @@ type StyleProps = {
export const ContentSectionHeader = ({ export const ContentSectionHeader = ({
title, title,
subtitle, subtitle,
slotLeft,
slotRight, slotRight,
className, className,
}: ElementProps & StyleProps) => ( }: ElementProps & StyleProps) => (
<Styled.ContentSectionHeader className={className}> <Styled.ContentSectionHeader className={className}>
{slotLeft} <div>
<Styled.Header>
{title && <h3>{title}</h3>} {title && <h3>{title}</h3>}
{subtitle && <p>{subtitle}</p>} {subtitle && <p>{subtitle}</p>}
</Styled.Header> </div>
{slotRight} {slotRight}
</Styled.ContentSectionHeader> </Styled.ContentSectionHeader>
); );
@@ -43,15 +40,9 @@ Styled.ContentSectionHeader = styled.header<StyleProps>`
padding: 1rem var(--header-horizontal-padding); padding: 1rem var(--header-horizontal-padding);
@media ${breakpoints.tablet} { > div {
flex-wrap: wrap; ${layoutMixins.column}
--header-horizontal-padding: 1.25rem;
} }
`;
Styled.Header = styled.div`
${layoutMixins.column}
flex: 1;
h3 { h3 {
color: var(--color-text-2); color: var(--color-text-2);
@@ -63,4 +54,9 @@ Styled.Header = styled.div`
font: var(--font-small-book); font: var(--font-small-book);
margin-top: 0.25rem; margin-top: 0.25rem;
} }
@media ${breakpoints.tablet} {
flex-wrap: wrap;
--header-horizontal-padding: 1.25rem;
}
`; `;
+3 -3
View File
@@ -15,10 +15,10 @@ CopyButtonStory.args = {
}; };
CopyButtonStory.argTypes = { CopyButtonStory.argTypes = {
buttonType: { shownAsText: {
options: ["text", "icon", "default"], options: [true, false],
control: { type: 'select' }, control: { type: 'select' },
defaultValue: "default", defaultValue: false,
}, },
children: { children: {
options: ['some text to copy'], options: ['some text to copy'],
+5 -42
View File
@@ -9,21 +9,14 @@ import { layoutMixins } from '@/styles/layoutMixins';
import { Button, ButtonProps } from './Button'; import { Button, ButtonProps } from './Button';
import { Icon, IconName } from './Icon'; import { Icon, IconName } from './Icon';
import { IconButton } from './IconButton';
import { WithTooltip } from './WithTooltip';
export type CopyButtonProps = { export type CopyButtonProps = {
value?: string; value?: string;
buttonType?: 'text' | 'icon' | 'default'; shownAsText?: boolean;
children?: React.ReactNode; children?: React.ReactNode;
} & ButtonProps; } & ButtonProps;
export const CopyButton = ({ export const CopyButton = ({ value, shownAsText, children, ...buttonProps }: CopyButtonProps) => {
value,
buttonType = 'default',
children,
...buttonProps
}: CopyButtonProps) => {
const stringGetter = useStringGetter(); const stringGetter = useStringGetter();
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
@@ -35,23 +28,11 @@ export const CopyButton = ({
setTimeout(() => setCopied(false), 500); setTimeout(() => setCopied(false), 500);
}; };
return buttonType === 'text' ? ( return shownAsText ? (
<Styled.InlineRow onClick={onCopy} copied={copied}> <Styled.InlineRow onClick={onCopy} copied={copied}>
{children} {children}
<Styled.Icon copied={copied} iconName={copied ? IconName.Check : IconName.Copy} /> <Icon iconName={IconName.Copy} />
</Styled.InlineRow> </Styled.InlineRow>
) : buttonType === 'icon' ? (
<WithTooltip
tooltipString={stringGetter({ key: copied ? STRING_KEYS.COPIED : STRING_KEYS.COPY })}
>
<Styled.IconButton
{...buttonProps}
copied={copied}
action={ButtonAction.Base}
iconName={copied ? IconName.Check : IconName.Copy}
onClick={onCopy}
/>
</WithTooltip>
) : ( ) : (
<Button <Button
{...buttonProps} {...buttonProps}
@@ -77,26 +58,8 @@ Styled.InlineRow = styled.div<{ copied: boolean }>`
` `
: css` : css`
&:hover { &:hover {
filter: brightness(var(--hover-filter-base)); filter: brightness(1.1);
text-decoration: underline; text-decoration: underline;
} }
`} `}
`; `;
Styled.Icon = styled(Icon)<{ copied: boolean }>`
${({ copied }) =>
copied &&
css`
color: var(--color-success);
`}
`;
Styled.IconButton = styled(IconButton)<{ copied: boolean }>`
${({ copied }) =>
copied &&
css`
svg {
color: var(--color-success);
}
`}
`;
+23 -38
View File
@@ -7,50 +7,35 @@ import { StoryWrapper } from '.ladle/components';
import styled, { type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
export const DetailsStory: Story<Parameters<typeof Details>[0]> = (args) => ( export const DetailsStory: Story<Parameters<typeof Details>> = () => (
<StoryWrapper> <StoryWrapper>
<Styled.Resizable> <Styled.Resizable>
<Details {...args} /> <Details
items={[
{
key: 'item-1',
label: 'Item 1',
tooltip: 'leverage',
value: 'Value 1',
},
{
key: 'item-2',
label: 'Really really really long item name 2',
tooltip: 'liquidation-price',
value: 'Value 2',
},
{
key: 'item-3',
label: 'Item 3',
tooltip: 'realized-pnl',
value: 'Value 3',
},
]}
/>
</Styled.Resizable> </Styled.Resizable>
</StoryWrapper> </StoryWrapper>
); );
DetailsStory.args = {
items: [
{
key: 'item-1',
label: 'Item 1',
tooltip: 'leverage',
value: 'Value 1',
},
{
key: 'item-2',
label: 'Really really really long item name 2',
tooltip: 'liquidation-price',
value: 'Value 2',
},
{
key: 'item-3',
label: 'Item 3',
tooltip: 'realized-pnl',
value: 'Value 3',
},
],
showSubitems: false,
isLoading: false,
withOverflow: false,
withSeparators: false,
};
DetailsStory.argTypes = {
justifyItems: { options: ['start', 'end'], control: { type: 'select' }, defaultValue: 'start' },
layout: {
options: ['column', 'row', 'rowColumns', 'grid', 'stackColumn'],
control: { type: 'select' },
defaultValue: 'column',
},
};
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
Styled.Resizable = styled.section` Styled.Resizable = styled.section`
+28 -38
View File
@@ -38,7 +38,6 @@ type ElementProps = {
slotTrigger?: React.ReactNode; slotTrigger?: React.ReactNode;
slotHeaderInner?: React.ReactNode; slotHeaderInner?: React.ReactNode;
slotFooter?: React.ReactNode; slotFooter?: React.ReactNode;
withClose?: boolean;
}; };
type StyleProps = { type StyleProps = {
@@ -47,7 +46,6 @@ type StyleProps = {
hasHeaderBorder?: boolean; hasHeaderBorder?: boolean;
children?: React.ReactNode; children?: React.ReactNode;
className?: string; className?: string;
withAnimation?: boolean;
}; };
export type DialogProps = ElementProps & StyleProps; export type DialogProps = ElementProps & StyleProps;
@@ -81,11 +79,9 @@ export const Dialog = ({
slotTrigger, slotTrigger,
slotHeaderInner, slotHeaderInner,
slotFooter, slotFooter,
withClose = true,
placement = DialogPlacement.Default, placement = DialogPlacement.Default,
portalContainer, portalContainer,
hasHeaderBorder = false, hasHeaderBorder = false,
withAnimation = false,
children, children,
className, className,
}: DialogProps) => { }: DialogProps) => {
@@ -109,7 +105,6 @@ export const Dialog = ({
e.preventDefault(); e.preventDefault();
} }
}} }}
$withAnimation={withAnimation}
> >
<Styled.Header $withBorder={hasHeaderBorder}> <Styled.Header $withBorder={hasHeaderBorder}>
<Styled.HeaderTopRow> <Styled.HeaderTopRow>
@@ -119,7 +114,7 @@ export const Dialog = ({
{title && <Styled.Title>{title}</Styled.Title>} {title && <Styled.Title>{title}</Styled.Title>}
{!preventClose && withClose && ( {!preventClose && (
<Styled.Close ref={closeButtonRef}> <Styled.Close ref={closeButtonRef}>
<Icon iconName={IconName.Close} /> <Icon iconName={IconName.Close} />
</Styled.Close> </Styled.Close>
@@ -173,7 +168,7 @@ Styled.Overlay = styled(Overlay)`
} }
`; `;
Styled.Container = styled(Content)<{ placement: DialogPlacement; $withAnimation?: boolean }>` Styled.Container = styled(Content)<{ placement: DialogPlacement }>`
/* Params */ /* Params */
--dialog-inset: 1rem; --dialog-inset: 1rem;
--dialog-width: 30rem; --dialog-width: 30rem;
@@ -229,7 +224,7 @@ Styled.Container = styled(Content)<{ placement: DialogPlacement; $withAnimation?
outline: none; outline: none;
${({ placement, $withAnimation }) => ${({ placement }) =>
({ ({
[DialogPlacement.Default]: css` [DialogPlacement.Default]: css`
inset: var(--dialog-inset); inset: var(--dialog-inset);
@@ -265,11 +260,9 @@ Styled.Container = styled(Content)<{ placement: DialogPlacement; $withAnimation?
padding-bottom: var(--dialog-radius); */ padding-bottom: var(--dialog-radius); */
} }
${$withAnimation && @media (prefers-reduced-motion: no-preference) {
css` &[data-state='open'] {
@media (prefers-reduced-motion: no-preference) { animation: ${keyframes`
&[data-state='open'] {
animation: ${keyframes`
from { from {
opacity: 0; opacity: 0;
} }
@@ -277,19 +270,18 @@ Styled.Container = styled(Content)<{ placement: DialogPlacement; $withAnimation?
max-height: 0; max-height: 0;
} }
`} 0.15s var(--ease-out-expo); `} 0.15s var(--ease-out-expo);
} }
&[data-state='closed'] { &[data-state='closed'] {
animation: ${keyframes` animation: ${keyframes`
to { to {
opacity: 0; opacity: 0;
scale: 0.9; scale: 0.9;
max-height: 0; max-height: 0;
} }
`} 0.15s; `} 0.15s;
}
} }
`} }
`, `,
[DialogPlacement.Sidebar]: css` [DialogPlacement.Sidebar]: css`
--dialog-width: var(--sidebar-width); --dialog-width: var(--sidebar-width);
@@ -299,52 +291,50 @@ Styled.Container = styled(Content)<{ placement: DialogPlacement; $withAnimation?
margin-left: auto; margin-left: auto;
} }
${$withAnimation && @media (prefers-reduced-motion: no-preference) {
css` &[data-state='open'] {
@media (prefers-reduced-motion: no-preference) { animation: ${keyframes`
&[data-state='open'] {
animation: ${keyframes`
from { from {
translate: 100% 0; translate: 100% 0;
opacity: 0; opacity: 0;
} }
`} 0.15s var(--ease-out-expo); `} 0.15s var(--ease-out-expo);
} }
&[data-state='closed'] { &[data-state='closed'] {
animation: ${keyframes` animation: ${keyframes`
to { to {
translate: 100% 0; translate: 100% 0;
opacity: 0; opacity: 0;
} }
`} 0.15s var(--ease-out-expo); `} 0.15s var(--ease-out-expo);
}
} }
`} }
`, `,
[DialogPlacement.Inline]: css` [DialogPlacement.Inline]: css`
${$withAnimation && @media (prefers-reduced-motion: no-preference) {
css` &[data-state='open'] {
@media (prefers-reduced-motion: no-preference) { animation: ${keyframes`
&[data-state='open'] {
animation: ${keyframes`
from { from {
scale: 0.99; scale: 0.99;
opacity: 0; opacity: 0;
/* filter: blur(2px); */
/* backdrop-filter: none; */
} }
`} 0.15s var(--ease-out-expo); `} 0.15s var(--ease-out-expo);
} }
&[data-state='closed'] { &[data-state='closed'] {
animation: ${keyframes` animation: ${keyframes`
to { to {
scale: 0.99; scale: 0.99;
opacity: 0; opacity: 0;
/* filter: blur(2px); */
/* backdrop-filter: none; */
} }
`} 0.15s var(--ease-out-expo); `} 0.15s var(--ease-out-expo);
}
} }
`} }
`, `,
[DialogPlacement.FullScreen]: css` [DialogPlacement.FullScreen]: css`
--dialog-width: 100vw; --dialog-width: 100vw;
+1 -1
View File
@@ -14,7 +14,7 @@ export const DiffArrowStory: Story<DiffArrowProps> = (args) => (
DiffArrowStory.argTypes = { DiffArrowStory.argTypes = {
direction: { direction: {
options: ['left', 'right', 'up', 'down'], options: ['left', 'right'],
control: { type: 'select' }, control: { type: 'select' },
defaultValue: 'right', defaultValue: 'right',
}, },
+1 -7
View File
@@ -10,7 +10,7 @@ type ElementProps = {
type StyleProps = { type StyleProps = {
className?: string; className?: string;
direction?: 'right' | 'left' | 'up' | 'down'; direction?: 'right' | 'left';
}; };
export type DiffArrowProps = ElementProps & StyleProps; export type DiffArrowProps = ElementProps & StyleProps;
@@ -57,11 +57,5 @@ Styled.DiffArrowContainer = styled.span<DiffArrowProps>`
left: css` left: css`
transform: scaleX(-1); transform: scaleX(-1);
`, `,
up: css`
transform: rotate(-90deg);
`,
down: css`
transform: rotate(90deg);
`,
}[direction || 'right'])} }[direction || 'right'])}
`; `;
+1 -1
View File
@@ -75,7 +75,7 @@ Styled.DiffValue = styled.div<{ hasInvalidNewValue?: boolean }>`
${({ hasInvalidNewValue }) => ${({ hasInvalidNewValue }) =>
hasInvalidNewValue && hasInvalidNewValue &&
css` css`
color: var(--color-error); color: var(--color-negative);
`} `}
`; `;
+3 -3
View File
@@ -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(var(--hover-filter-base)); filter: brightness(1.1);
} }
`; `;
+24 -29
View File
@@ -4,43 +4,38 @@ import { DropdownMenu } from '@/components/DropdownMenu';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
export const DropdownMenuStory: Story<Parameters<typeof DropdownMenu>[0]> = (args) => { export const DropdownMenuStory: Story<Parameters<typeof DropdownMenu>> = (args) => {
const exampleItems = [
{
value: '1',
label: 'Item 1',
onSelect: () => alert('Item 1 action'),
},
{
value: '2',
label: 'Item 2',
onSelect: () => alert('Item 2 action'),
},
{
value: '3',
label: 'Item 3',
onSelect: () => alert('Item 3 action'),
},
];
return ( return (
<StoryWrapper> <StoryWrapper>
<DropdownMenu {...args}> <DropdownMenu
{...args}
items={exampleItems}
>
<span>Menu</span> <span>Menu</span>
</DropdownMenu> </DropdownMenu>
</StoryWrapper> </StoryWrapper>
); );
}; };
DropdownMenuStory.args = { DropdownMenuStory.args = {};
items: [
{
value: '0',
label: 'Item 0',
onSelect: () => alert('Item 0 action'),
},
{
value: '1',
label: 'Item 1 (accent)',
onSelect: () => alert('Item 1 action'),
highlightColor: 'accent',
},
{
value: '2',
label: 'Item 2 (create)',
onSelect: () => alert('Item 2 action'),
highlightColor: 'create',
},
{
value: '3',
label: 'Item 3 (destroy)',
onSelect: () => alert('Item 3 action'),
highlightColor: 'destroy',
},
],
};
DropdownMenuStory.argTypes = { DropdownMenuStory.argTypes = {
align: { align: {
+6 -6
View File
@@ -13,7 +13,7 @@ export type DropdownMenuItem<T> = {
label: React.ReactNode; label: React.ReactNode;
onSelect?: () => void; onSelect?: () => void;
separator?: boolean; separator?: boolean;
highlightColor?: 'accent' | 'create' | 'destroy'; highlightColor?: 'accent' | 'positive' | 'negative';
}; };
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' | 'create' | 'destroy' }>` Styled.Item = styled(Item)<{ $highlightColor: 'accent' | 'positive' | 'negative' }>`
${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' | 'create' | 'destroy' }>
['accent']: ` ['accent']: `
--item-highlighted-textColor: var(--color-accent); --item-highlighted-textColor: var(--color-accent);
`, `,
['create']: ` ['positive']: `
--item-highlighted-textColor: var(--color-green); --item-highlighted-textColor: var(--color-positive);
`, `,
['destroy']: ` ['negative']: `
--item-highlighted-textColor: var(--color-red); --item-highlighted-textColor: var(--color-negative);
`, `,
}[$highlightColor])} }[$highlightColor])}
@@ -28,22 +28,21 @@ const exampleItems = [
}, },
]; ];
export const DropdownSelectMenuStory: Story< export const DropdownSelectMenuStory: Story<Parameters<typeof DropdownSelectMenu>> = (args) => {
Pick<Parameters<typeof DropdownSelectMenu>[0], 'items' | 'align' | 'sideOffset' | 'disabled'>
> = (args) => {
const [item, setItem] = useState(exampleItems[0].value); const [item, setItem] = useState(exampleItems[0].value);
return ( return (
<StoryWrapper> <StoryWrapper>
<DropdownSelectMenu value={item} onValueChange={(value) => setItem(value)} {...args} /> <DropdownSelectMenu
items={exampleItems}
value={item}
onValueChange={(value) => setItem(value)}
{...args}
/>
</StoryWrapper> </StoryWrapper>
); );
}; };
DropdownSelectMenuStory.args = { DropdownSelectMenuStory.args = {};
items: exampleItems,
sideOffset: 1,
disabled: false,
};
DropdownSelectMenuStory.argTypes = { DropdownSelectMenuStory.argTypes = {
align: { align: {
+1 -4
View File
@@ -9,7 +9,6 @@ import {
RadioItem, RadioItem,
Portal, Portal,
} from '@radix-ui/react-dropdown-menu'; } from '@radix-ui/react-dropdown-menu';
import { CheckIcon } from '@radix-ui/react-icons';
import { type MenuItem } from '@/constants/menus'; import { type MenuItem } from '@/constants/menus';
@@ -91,9 +90,7 @@ export const DropdownSelectMenu = <MenuItemValue extends string>({
{slotAfter} {slotAfter}
<Styled.ItemIndicator> <Styled.ItemIndicator>{/* <CheckIcon /> */}</Styled.ItemIndicator>
<CheckIcon />
</Styled.ItemIndicator>
</Styled.RadioItem> </Styled.RadioItem>
))} ))}
</RadioGroup> </RadioGroup>
+3 -3
View File
@@ -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} disabled={otherProps?.disabled}> <Styled.WithLabel label={label} inputID={id}>
<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)<{ disabled?: boolean }>` Styled.WithLabel = styled(WithLabel)`
${formMixins.inputLabel} ${formMixins.inputLabel}
label { label {
${({ disabled }) => !disabled && 'cursor: text;'} cursor: text;
padding: var(--form-input-paddingY) var(--form-input-paddingX) 0; padding: var(--form-input-paddingY) var(--form-input-paddingX) 0;
} }
`; `;
+29 -2
View File
@@ -1,16 +1,43 @@
import styled, { AnyStyledComponent } from 'styled-components'; import styled, { AnyStyledComponent } from 'styled-components';
import { layoutMixins } from '@/styles/layoutMixins';
import { Icon, IconName } from '@/components/Icon'; import { Icon, IconName } from '@/components/Icon';
export const GreenCheckCircle = ({ className }: { className?: string }) => ( export const GreenCheckCircle = ({ className }: { className?: string }) => (
<Styled.Icon className={className} iconName={IconName.CheckCircle} /> <Styled.GreenCheckCircle className={className}>
<Icon iconName={IconName.Check} />
</Styled.GreenCheckCircle>
); );
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
Styled.Icon = styled(Icon)` Styled.GreenCheckCircle = styled.div`
${layoutMixins.stack}
--icon-size: 1.25rem; --icon-size: 1.25rem;
--icon-border-width: 3px;
width: var(--icon-size); width: var(--icon-size);
height: var(--icon-size); height: var(--icon-size);
border-radius: 50%;
align-items: center;
&:before {
content: '';
width: calc(var(--icon-size) - var(--icon-border-width) * 2);
height: calc(var(--icon-size) - var(--icon-border-width) * 2);
border: solid var(--icon-border-width) var(--color-positive);
border-radius: 50%;
opacity: 0.6;
}
svg {
width: calc(var(--icon-size) / 3);
height: calc(var(--icon-size) / 3);
color: var(--color-positive);
justify-self: center;
}
`; `;
+1 -1
View File
@@ -4,7 +4,7 @@ import { Icon, IconName } from '@/components/Icon';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
export const IconStory: Story<Parameters<typeof Icon>[0]> = (args) => { export const IconStory: Story<Parameters<typeof Icon>> = (args) => {
return ( return (
<StoryWrapper> <StoryWrapper>
<Icon {...args} /> <Icon {...args} />
+3 -33
View File
@@ -13,10 +13,8 @@ import {
CaretIcon, CaretIcon,
CautionCircleStrokeIcon, CautionCircleStrokeIcon,
CautionCircleIcon, CautionCircleIcon,
ChaosLabsIcon,
ChatIcon, ChatIcon,
CheckIcon, CheckIcon,
CheckCircleIcon,
ChevronLeftIcon, ChevronLeftIcon,
ChevronRightIcon, ChevronRightIcon,
ClockIcon, ClockIcon,
@@ -25,7 +23,7 @@ import {
CoinsIcon, CoinsIcon,
CommentIcon, CommentIcon,
CopyIcon, CopyIcon,
CurrencySignIcon, CubeIcon,
DepositIcon, DepositIcon,
DepthChartIcon, DepthChartIcon,
DiscordIcon, DiscordIcon,
@@ -36,18 +34,15 @@ import {
FundingChartIcon, FundingChartIcon,
GearIcon, GearIcon,
GiftboxIcon, GiftboxIcon,
GovernanceIcon,
HelpCircleIcon, HelpCircleIcon,
HideIcon, HideIcon,
HistoryIcon, HistoryIcon,
LeaderboardIcon,
LinkOutIcon, LinkOutIcon,
LockIcon, LockIcon,
LogoShortIcon, LogoShortIcon,
MenuIcon, MenuIcon,
MigrateIcon, MigrateIcon,
MintscanIcon, MintscanIcon,
MoonIcon,
OrderbookIcon, OrderbookIcon,
OrderCanceledIcon, OrderCanceledIcon,
OrderFilledIcon, OrderFilledIcon,
@@ -57,22 +52,17 @@ import {
OrderUntriggeredIcon, OrderUntriggeredIcon,
OverviewIcon, OverviewIcon,
PencilIcon, PencilIcon,
PlayIcon,
PlusIcon,
PositionsIcon, PositionsIcon,
PriceChartIcon, PriceChartIcon,
PrivacyIcon, PrivacyIcon,
QrIcon, QrIcon,
RewardStarIcon,
SearchIcon, SearchIcon,
SendIcon, SendIcon,
ShareIcon, ShareIcon,
ShowIcon, ShowIcon,
TogglesMenuIcon, TogglesMenuIcon,
StarIcon, StarIcon,
SunIcon,
TerminalIcon, TerminalIcon,
TokenIcon,
TradeIcon, TradeIcon,
TransferIcon, TransferIcon,
TriangleIcon, TriangleIcon,
@@ -94,10 +84,8 @@ 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',
ChevronLeft = 'ChevronLeft', ChevronLeft = 'ChevronLeft',
ChevronRight = 'ChevronRight', ChevronRight = 'ChevronRight',
Clock = 'Clock', Clock = 'Clock',
@@ -106,7 +94,7 @@ export enum IconName {
Coins = 'Coins', Coins = 'Coins',
Comment = 'Comment', Comment = 'Comment',
Copy = 'Copy', Copy = 'Copy',
CurrencySign = 'CurrencySign', Cube = 'Cube',
Deposit = 'Deposit', Deposit = 'Deposit',
DepthChart = 'DepthChart', DepthChart = 'DepthChart',
Discord = 'Discord', Discord = 'Discord',
@@ -117,18 +105,15 @@ export enum IconName {
FundingChart = 'FundingChart', FundingChart = 'FundingChart',
Gear = 'Gear', Gear = 'Gear',
Giftbox = 'Giftbox', Giftbox = 'Giftbox',
Governance = 'Governance',
HelpCircle = 'HelpCircle', HelpCircle = 'HelpCircle',
Hide = 'Hide', Hide = 'Hide',
History = 'History', History = 'History',
Leaderboard = 'Leaderboard',
LinkOut = 'LinkOut', LinkOut = 'LinkOut',
Lock = 'Lock', Lock = 'Lock',
LogoShort = 'LogoShort', LogoShort = 'LogoShort',
Menu = 'Menu', Menu = 'Menu',
Migrate = 'Migrate', Migrate = 'Migrate',
Mintscan = 'Mintscan', Mintscan = 'Mintscan',
Moon = 'Moon',
Onboarding = 'Onboarding', Onboarding = 'Onboarding',
Orderbook = 'OrderbookIcon', Orderbook = 'OrderbookIcon',
OrderCanceled = 'OrderCanceled', OrderCanceled = 'OrderCanceled',
@@ -139,22 +124,17 @@ export enum IconName {
OrderUntriggered = 'OrderUntriggered', OrderUntriggered = 'OrderUntriggered',
Overview = 'Overview', Overview = 'Overview',
Pencil = 'Pencil', Pencil = 'Pencil',
Play = 'Play',
Plus = 'Plus',
Positions = 'Positions', Positions = 'Positions',
PriceChart = 'PriceChart', PriceChart = 'PriceChart',
Privacy = 'Privacy', Privacy = 'Privacy',
Qr = 'Qr', Qr = 'Qr',
RewardStar = 'RewardStar',
Search = 'Search', Search = 'Search',
Send = 'Send', Send = 'Send',
Share = 'Share', Share = 'Share',
Show = 'Show', Show = 'Show',
Star = 'Star', Star = 'Star',
Sun = 'Sun',
Terminal = 'Terminal', Terminal = 'Terminal',
TogglesMenu = 'TogglesMenu', TogglesMenu = 'TogglesMenu',
Token = 'Token',
Trade = 'Trade', Trade = 'Trade',
Transfer = 'Transfer', Transfer = 'Transfer',
Triangle = 'Triangle', Triangle = 'Triangle',
@@ -176,10 +156,8 @@ 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.ChevronLeft]: ChevronLeftIcon, [IconName.ChevronLeft]: ChevronLeftIcon,
[IconName.ChevronRight]: ChevronRightIcon, [IconName.ChevronRight]: ChevronRightIcon,
[IconName.Clock]: ClockIcon, [IconName.Clock]: ClockIcon,
@@ -188,7 +166,7 @@ const icons = {
[IconName.Coins]: CoinsIcon, [IconName.Coins]: CoinsIcon,
[IconName.Comment]: CommentIcon, [IconName.Comment]: CommentIcon,
[IconName.Copy]: CopyIcon, [IconName.Copy]: CopyIcon,
[IconName.CurrencySign]: CurrencySignIcon, [IconName.Cube]: CubeIcon,
[IconName.Deposit]: DepositIcon, [IconName.Deposit]: DepositIcon,
[IconName.DepthChart]: DepthChartIcon, [IconName.DepthChart]: DepthChartIcon,
[IconName.Discord]: DiscordIcon, [IconName.Discord]: DiscordIcon,
@@ -199,18 +177,15 @@ const icons = {
[IconName.FundingChart]: FundingChartIcon, [IconName.FundingChart]: FundingChartIcon,
[IconName.Gear]: GearIcon, [IconName.Gear]: GearIcon,
[IconName.Giftbox]: GiftboxIcon, [IconName.Giftbox]: GiftboxIcon,
[IconName.Governance]: GovernanceIcon,
[IconName.HelpCircle]: HelpCircleIcon, [IconName.HelpCircle]: HelpCircleIcon,
[IconName.Hide]: HideIcon, [IconName.Hide]: HideIcon,
[IconName.History]: HistoryIcon, [IconName.History]: HistoryIcon,
[IconName.Leaderboard]: LeaderboardIcon,
[IconName.LinkOut]: LinkOutIcon, [IconName.LinkOut]: LinkOutIcon,
[IconName.Lock]: LockIcon, [IconName.Lock]: LockIcon,
[IconName.LogoShort]: LogoShortIcon, [IconName.LogoShort]: LogoShortIcon,
[IconName.Menu]: MenuIcon, [IconName.Menu]: MenuIcon,
[IconName.Migrate]: MigrateIcon, [IconName.Migrate]: MigrateIcon,
[IconName.Mintscan]: MintscanIcon, [IconName.Mintscan]: MintscanIcon,
[IconName.Moon]: MoonIcon,
[IconName.Orderbook]: OrderbookIcon, [IconName.Orderbook]: OrderbookIcon,
[IconName.OrderCanceled]: OrderCanceledIcon, [IconName.OrderCanceled]: OrderCanceledIcon,
[IconName.OrderFilled]: OrderFilledIcon, [IconName.OrderFilled]: OrderFilledIcon,
@@ -220,22 +195,17 @@ const icons = {
[IconName.OrderUntriggered]: OrderUntriggeredIcon, [IconName.OrderUntriggered]: OrderUntriggeredIcon,
[IconName.Overview]: OverviewIcon, [IconName.Overview]: OverviewIcon,
[IconName.Pencil]: PencilIcon, [IconName.Pencil]: PencilIcon,
[IconName.Play]: PlayIcon,
[IconName.Plus]: PlusIcon,
[IconName.Positions]: PositionsIcon, [IconName.Positions]: PositionsIcon,
[IconName.PriceChart]: PriceChartIcon, [IconName.PriceChart]: PriceChartIcon,
[IconName.Privacy]: PrivacyIcon, [IconName.Privacy]: PrivacyIcon,
[IconName.Qr]: QrIcon, [IconName.Qr]: QrIcon,
[IconName.RewardStar]: RewardStarIcon,
[IconName.Search]: SearchIcon, [IconName.Search]: SearchIcon,
[IconName.Send]: SendIcon, [IconName.Send]: SendIcon,
[IconName.Share]: ShareIcon, [IconName.Share]: ShareIcon,
[IconName.Show]: ShowIcon, [IconName.Show]: ShowIcon,
[IconName.Star]: StarIcon, [IconName.Star]: StarIcon,
[IconName.Sun]: SunIcon,
[IconName.Terminal]: TerminalIcon, [IconName.Terminal]: TerminalIcon,
[IconName.TogglesMenu]: TogglesMenuIcon, [IconName.TogglesMenu]: TogglesMenuIcon,
[IconName.Token]: TokenIcon,
[IconName.Trade]: TradeIcon, [IconName.Trade]: TradeIcon,
[IconName.Transfer]: TransferIcon, [IconName.Transfer]: TransferIcon,
[IconName.Triangle]: TriangleIcon, [IconName.Triangle]: TriangleIcon,
+21 -30
View File
@@ -10,7 +10,7 @@ import {
USD_DECIMALS, USD_DECIMALS,
} from '@/constants/numbers'; } from '@/constants/numbers';
import { BIG_NUMBERS } from '@/lib/numbers'; import { BIG_NUMBERS, MustBigNumber } from '@/lib/numbers';
import { useLocaleSeparators } from '@/hooks'; import { useLocaleSeparators } from '@/hooks';
export enum InputType { export enum InputType {
@@ -29,38 +29,31 @@ type StyleProps = {
type ElementProps = { type ElementProps = {
type?: InputType; type?: InputType;
value?: string | number | null; value?: string | number | null;
allowNegative?: boolean;
decimals?: number;
disabled?: boolean; disabled?: boolean;
id?: string; id?: string;
max?: number;
onBlur?: () => void; onBlur?: () => void;
onChange?:
| Dispatch<SetStateAction<string>>
| React.ReactEventHandler<HTMLInputElement>
| ((values: NumberFormatValues, e: SourceInfo) => void);
onFocus?: () => void; onFocus?: () => void;
onInput?: ({
value,
floatValue,
formattedValue,
}: {
value: string;
floatValue?: number;
formattedValue: string;
}) => void;
placeholder?: string; placeholder?: string;
}; };
type ConditionalProps = export type InputProps = ElementProps & StyleProps;
| {
allowNegative?: boolean;
decimals?: number;
max?: number;
onChange?: (values: NumberFormatValues, e: SourceInfo) => void;
onInput?: ({
value,
floatValue,
formattedValue,
}: {
value: string;
floatValue?: number;
formattedValue: string;
}) => void;
}
| {
allowNegative?: never;
decimals?: never;
max?: never;
onChange?: Dispatch<SetStateAction<string>> | React.ReactEventHandler<HTMLInputElement>;
onInput?: (e: SyntheticInputEvent) => void;
};
export type InputProps = ElementProps & StyleProps & ConditionalProps;
export const Input = forwardRef<HTMLInputElement, InputProps>( export const Input = forwardRef<HTMLInputElement, InputProps>(
( (
@@ -136,7 +129,6 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
placeholder={placeholder} placeholder={placeholder}
value={value} value={value}
// Other // Other
data-1p-ignore // prevent 1Password fill
{...otherProps} {...otherProps}
/> />
) : ( ) : (
@@ -145,7 +137,6 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
ref={ref as React.Ref<typeof NumericFormat<unknown>>} ref={ref as React.Ref<typeof NumericFormat<unknown>>}
id={id} id={id}
// NumericFormat // NumericFormat
valueIsNumericString
allowNegative={allowNegative} allowNegative={allowNegative}
decimalScale={decimals} decimalScale={decimals}
decimalSeparator={LOCALE_DECIMAL_SEPARATOR} decimalSeparator={LOCALE_DECIMAL_SEPARATOR}
@@ -169,7 +160,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
? undefined ? undefined
: Number(formattedValue.replace(',', '.')); : Number(formattedValue.replace(',', '.'));
onInput?.({ value, floatValue, formattedValue, ...e }); onInput?.({ value, floatValue, formattedValue });
}} }}
// Native // Native
disabled={disabled} disabled={disabled}
@@ -177,7 +168,6 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
value={formattedValue} value={formattedValue}
autoComplete="off" autoComplete="off"
autoCorrect="off" autoCorrect="off"
data-1p-ignore // prevent 1Password fill
{...otherProps} {...otherProps}
/> />
)} )}
@@ -198,6 +188,7 @@ Styled.InputContainer = styled.div`
border-radius: inherit; border-radius: inherit;
input { input {
user-select: all;
flex: 1; flex: 1;
width: 100%; width: 100%;
} }
+1 -1
View File
@@ -6,7 +6,7 @@ import { Link } from '@/components/Link';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
export const LinkStory: Story<Parameters<typeof Link>[0]> = (args) => { export const LinkStory: Story<Parameters<typeof Link>> = (args) => {
return ( return (
<StoryWrapper> <StoryWrapper>
<Styled.Container> <Styled.Container>
@@ -11,7 +11,6 @@ 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"
+1 -1
View File
@@ -1,11 +1,11 @@
import styled, { type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { RiskLevels } from '@/constants/abacus'; import { RiskLevels } from '@/constants/abacus';
import { UsageColorFromRiskLevel } from '@/styles/colors';
import { Ring } from '@/components/Ring'; import { Ring } from '@/components/Ring';
import { abacusHelper } from '@/lib/abacus'; import { abacusHelper } from '@/lib/abacus';
import { UsageColorFromRiskLevel } from '@/lib/styles';
type ElementProps = { type ElementProps = {
value: number; value: number;
+17 -19
View File
@@ -5,24 +5,8 @@ import { HashRouter } from 'react-router-dom';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
export const NavigationMenuStory: Story< export const NavigationMenuStory: Story<Parameters<typeof NavigationMenu>> = (args) => {
Pick<Parameters<typeof NavigationMenu>[0], 'items' | 'orientation' | 'submenuPlacement'> const exampleItems = [
> = (args) => {
return (
<StoryWrapper>
<HashRouter
children={
<NavigationMenu {...args}>
<span>Menu</span>
</NavigationMenu>
}
/>
</StoryWrapper>
);
};
NavigationMenuStory.args = {
items: [
{ {
group: 'navigation', group: 'navigation',
groupLabel: 'Views', groupLabel: 'Views',
@@ -109,9 +93,23 @@ NavigationMenuStory.args = {
}, },
], ],
}, },
], ];
return (
<StoryWrapper>
<HashRouter
children={
<NavigationMenu {...args} items={exampleItems}>
<span>Menu</span>
</NavigationMenu>
}
/>
</StoryWrapper>
);
}; };
NavigationMenuStory.args = {};
NavigationMenuStory.argTypes = { NavigationMenuStory.argTypes = {
orientation: { orientation: {
options: ['vertical', 'horizontal'], options: ['vertical', 'horizontal'],
+64 -11
View File
@@ -1,4 +1,4 @@
import { forwardRef, Ref } from 'react'; import { forwardRef, Ref, useEffect, useRef, useState } from 'react';
import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components'; import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components';
import { NavLink, matchPath, useLocation } from 'react-router-dom'; import { NavLink, matchPath, useLocation } from 'react-router-dom';
@@ -21,6 +21,8 @@ import {
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { isTruthy } from '@/lib/isTruthy';
import { Tag } from './Tag'; import { Tag } from './Tag';
import { Icon, IconName } from './Icon'; import { Icon, IconName } from './Icon';
@@ -59,6 +61,7 @@ const NavItem = forwardRef(
<> <>
{slotBefore} {slotBefore}
<span> <span>
{/* {`${label}${subitems?.length ? ' ' : ''}`} */}
{label} {label}
{tag && ( {tag && (
<> <>
@@ -97,6 +100,8 @@ const NavItem = forwardRef(
} }
); );
type TriggerRef = HTMLAnchorElement | HTMLDivElement | HTMLButtonElement | null;
export const NavigationMenu = <MenuItemValue extends string, MenuGroupValue extends string>({ export const NavigationMenu = <MenuItemValue extends string, MenuGroupValue extends string>({
onSelectItem, onSelectItem,
onSelectGroup, onSelectGroup,
@@ -107,6 +112,33 @@ export const NavigationMenu = <MenuItemValue extends string, MenuGroupValue exte
dir = 'ltr', dir = 'ltr',
className, className,
}: ElementProps<MenuItemValue, MenuGroupValue> & StyleProps) => { }: ElementProps<MenuItemValue, MenuGroupValue> & StyleProps) => {
// Disable click (close) in the first 500ms after hover (open)
// https://github.com/radix-ui/primitives/issues/1630#issuecomment-1545995075
const [clickIsDisabled, setClickIsDisabled] = useState(false);
const triggerRefs = useRef({} as { [value: string]: TriggerRef });
useEffect(() => {
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (
mutation.type === 'attributes' &&
mutation.attributeName === 'data-state' &&
(mutation.target as unknown as HTMLOrSVGElement).dataset.state === 'open' &&
mutation.target !== document.activeElement
) {
setClickIsDisabled(true);
setTimeout(() => setClickIsDisabled(false), 500);
}
}
});
for (const element of Object.values(triggerRefs.current).filter(isTruthy)) {
observer.observe(element, { attributes: true });
}
return () => observer.disconnect();
}, []);
const renderSubitems = ({ const renderSubitems = ({
item, item,
depth = 0, depth = 0,
@@ -116,18 +148,18 @@ export const NavigationMenu = <MenuItemValue extends string, MenuGroupValue exte
}) => ( }) => (
<> <>
<Styled.SubMenuTrigger <Styled.SubMenuTrigger
asChild asChild={depth > 0}
onPointerMove={(e: MouseEvent) => e.preventDefault()} ref={(ref: TriggerRef) => (triggerRefs.current[item.value] = ref)}
onPointerLeave={(e: MouseEvent) => e.preventDefault()} onClick={(e: MouseEvent) => {
if (clickIsDisabled) {
e.preventDefault();
}
}}
> >
<Styled.NavItem onSelect={onSelectGroup} orientation={itemOrientation} {...item} /> <Styled.NavItem onSelect={onSelectGroup} orientation={itemOrientation} {...item} />
</Styled.SubMenuTrigger> </Styled.SubMenuTrigger>
<Styled.Content <Styled.Content data-placement={submenuPlacement}>
onPointerEnter={(e: MouseEvent) => e.preventDefault()}
onPointerLeave={(e: MouseEvent) => e.preventDefault()}
data-placement={submenuPlacement}
>
<Styled.Sub data-placement={submenuPlacement}> <Styled.Sub data-placement={submenuPlacement}>
<Styled.List <Styled.List
data-orientation={depth > 0 ? 'menu' : orientation === 'vertical' ? 'vertical' : 'menu'} data-orientation={depth > 0 ? 'menu' : orientation === 'vertical' ? 'vertical' : 'menu'}
@@ -378,12 +410,25 @@ Styled.List = styled(List)`
`; `;
Styled.ListItem = styled(Item)` Styled.ListItem = styled(Item)`
/* display: contents; */
display: grid; display: grid;
position: relative; position: relative;
${Styled.List}[data-orientation="horizontal"] > & { ${Styled.List}[data-orientation="horizontal"] > & {
gap: var(--submenu-side-offset); gap: var(--submenu-side-offset);
} }
/* ${Styled.List}[data-orientation="menu"] > & {
grid-template-columns: 1fr 0;
align-items: start;
gap: 2rem;
} */
/* &:has([data-state="open"]) {
position: sticky;
left: 0;
right: 0;
} */
`; `;
Styled.SubMenuTrigger = styled(Trigger)` Styled.SubMenuTrigger = styled(Trigger)`
@@ -391,6 +436,11 @@ Styled.SubMenuTrigger = styled(Trigger)`
outline-offset: -2px; outline-offset: -2px;
&[data-state='open'] { &[data-state='open'] {
div {
background-color: var(--navigationMenu-item-checked-backgroundColor);
color: var(--navigationMenu-item-checked-textColor);
}
svg { svg {
rotate: 0.5turn; rotate: 0.5turn;
} }
@@ -402,10 +452,11 @@ Styled.NavItem = styled(NavItem)<{ orientation: 'horizontal' | 'vertical' }>`
subitems?.length subitems?.length
? css` ? css`
${popoverMixins.trigger} ${popoverMixins.trigger}
--trigger-open-backgroundColor: var(--navigationMenu-item-checked-backgroundColor); --trigger-backgroundColor: transparent;
--trigger-open-backgroundColor: var(--color-layer-3);
` `
: css` : css`
&:hover:not(:active) { &:hover:not(.active) {
background-color: var(--navigationMenu-item-highlighted-backgroundColor); background-color: var(--navigationMenu-item-highlighted-backgroundColor);
color: var(--navigationMenu-item-highlighted-textColor); color: var(--navigationMenu-item-highlighted-textColor);
} }
@@ -419,6 +470,8 @@ Styled.NavItem = styled(NavItem)<{ orientation: 'horizontal' | 'vertical' }>`
--item-radius: var(--navigationMenu-item-radius); --item-radius: var(--navigationMenu-item-radius);
--item-padding: var(--navigationMenu-item-padding); --item-padding: var(--navigationMenu-item-padding);
/* ${popoverMixins.backdropOverlay} */
${layoutMixins.scrollSnapItem} ${layoutMixins.scrollSnapItem}
min-height: var(--navigationMenu-item-height); min-height: var(--navigationMenu-item-height);
-201
View File
@@ -1,201 +0,0 @@
import React, { type MouseEvent } from 'react';
import styled, { css } from 'styled-components';
import { ButtonShape, ButtonSize } from '@/constants/buttons';
import {
NotificationStatus,
type Notification as NotificationDataType,
} from '@/constants/notifications';
import { useNotifications } from '@/hooks/useNotifications';
import { popoverMixins } from '@/styles/popoverMixins';
import { layoutMixins } from '@/styles/layoutMixins';
import { IconButton } from '@/components/IconButton';
import { IconName } from '@/components/Icon';
import { Output, OutputType } from '@/components/Output';
type ElementProps = {
notification: NotificationDataType;
onClick?: () => void;
slotIcon?: React.ReactNode;
slotTitle?: React.ReactNode;
slotTitleLeft?: React.ReactNode;
slotTitleRight?: React.ReactNode;
slotDescription?: React.ReactNode;
slotCustomContent?: React.ReactNode;
slotAction?: React.ReactNode;
withClose?: boolean;
};
type StyleProps = {
className?: string;
isToast?: boolean;
};
export type NotificationProps = ElementProps & StyleProps;
export const Notification = ({
className,
isToast,
notification,
onClick,
slotIcon,
slotTitle,
slotTitleLeft,
slotTitleRight,
slotDescription,
slotCustomContent,
slotAction,
withClose = !isToast,
}: NotificationProps) => {
const { markCleared, markSeen } = useNotifications();
return (
<$Container className={className} isToast={isToast} onClick={onClick}>
<$Header>
{slotTitleLeft ?? (slotIcon && <$Icon>{slotIcon}</$Icon>)}
<$Title>{slotTitle}</$Title>
{slotTitleRight}
{withClose && !isToast && (
<$ActionItems>
<$Output
type={OutputType.RelativeTime}
value={notification.timestamps[NotificationStatus.Triggered]}
/>
{notification.status < NotificationStatus.Seen ? <$UnreadIndicator /> : null}
{notification.status < NotificationStatus.Cleared ? (
<$IconButton
iconName={IconName.Close}
shape={ButtonShape.Square}
size={ButtonSize.XSmall}
onClick={(e: MouseEvent) => {
e.stopPropagation();
if (notification.status < NotificationStatus.Seen) {
markSeen(notification);
} else if (notification.status < NotificationStatus.Cleared) {
markCleared(notification);
}
}}
/>
) : null}
</$ActionItems>
)}
</$Header>
<$Description>{slotCustomContent ?? slotDescription}</$Description>
{slotAction && <$Action>{slotAction}</$Action>}
</$Container>
);
};
const $Container = styled.div<{ isToast?: boolean }>`
// Params
--toast-icon-size: 1.75em;
// Rules
${popoverMixins.popover}
overflow: visible;
padding: 1rem 1.25rem;
${({ isToast }) =>
isToast
? css`
padding: 1rem;
box-shadow: 0 0 0 var(--border-width) var(--color-border),
// border
0 0 0.5rem 0.1rem var(--color-layer-2); // shadow
`
: css`
flex: 1;
background-color: transparent;
border-radius: 0;
backdrop-filter: none;
`}
`;
const $Header = styled.header`
${layoutMixins.row}
position: relative;
`;
const $Icon = styled.div`
${layoutMixins.row}
float: left;
margin-right: 0.5rem;
line-height: 1;
> svg,
img {
width: 1.5rem;
height: 1.5rem;
}
`;
const $Title = styled.div`
flex: 1;
font: var(--font-base-medium);
color: var(--color-text-2);
overflow: hidden;
text-overflow: ellipsis;
`;
const $Description = styled.div`
margin-top: 0.5rem;
color: var(--color-text-0);
font: var(--font-small-book);
`;
const $Action = styled.div`
margin-top: 0.5rem;
font: var(--font-small-book);
`;
const $ActionItems = styled.div`
min-width: fit-content;
padding-left: 0.5rem;
height: 100%;
${layoutMixins.row};
justify-content: end;
gap: 0.5rem;
position: absolute;
right: 0;
top: 0;
background-color: var(--color-layer-2);
font: var(--font-mini-book);
display: none;
z-index: 1;
${$Container}:hover & {
display: flex;
}
`;
const $UnreadIndicator = styled.div`
width: 0.5rem;
height: 0.5rem;
border-radius: 50%;
background-color: var(--color-accent);
border: 1px solid var(--color-layer-2);
`;
const $Output = styled(Output)`
color: var(--color-text-0);
`;
const $IconButton = styled(IconButton)`
--button-border: none;
--button-textColor: var(--color-text-0);
--button-hover-textColor: var(--color-text-1);
`;
+1 -11
View File
@@ -65,9 +65,6 @@ 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;
@@ -92,7 +89,6 @@ export const Output = ({
relativeTimeFormatOptions = { relativeTimeFormatOptions = {
format: 'singleCharacter', format: 'singleCharacter',
}, },
timeOptions,
tag, tag,
withParentheses, withParentheses,
locale = navigator.language || 'en-US', locale = navigator.language || 'en-US',
@@ -120,7 +116,6 @@ export const Output = ({
{value?.toString() ?? null} {value?.toString() ?? null}
{tag && <Tag>{tag}</Tag>} {tag && <Tag>{tag}</Tag>}
{slotRight}
</Styled.Text> </Styled.Text>
); );
} }
@@ -170,21 +165,16 @@ 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, { [OutputType.Date]: date.toLocaleString(selectedLocale, { dateStyle: 'medium' }),
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];
+3 -5
View File
@@ -1,10 +1,10 @@
import type { Story } from '@ladle/react'; import type { Story } from '@ladle/react';
import { Panel, PanelProps } from '@/components/Panel'; import { Panel } from '@/components/Panel';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
export const PanelStory: Story<PanelProps> = (args) => { export const PanelStory: Story<{ slotHeader: React.ReactNode, children?: React.ReactNode }> = (args) => {
return ( return (
<StoryWrapper> <StoryWrapper>
<Panel {...args} /> <Panel {...args} />
@@ -13,8 +13,6 @@ export const PanelStory: Story<PanelProps> = (args) => {
}; };
PanelStory.args = { PanelStory.args = {
slotHeaderContent: 'Header', slotHeader: 'Header',
children: 'Content', children: 'Content',
slotRight: '1️⃣',
hasSeparator: true,
}; };
+4 -13
View File
@@ -4,10 +4,9 @@ import { Link } from 'react-router-dom';
import { Icon, IconName } from '@/components/Icon'; import { Icon, IconName } from '@/components/Icon';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { breakpoints } from '@/styles';
type ElementProps = { type PanelProps = {
slotHeaderContent?: React.ReactNode; slotHeaderContent?: string;
slotHeader?: React.ReactNode; slotHeader?: React.ReactNode;
slotRight?: React.ReactNode; slotRight?: React.ReactNode;
children?: React.ReactNode; children?: React.ReactNode;
@@ -16,13 +15,11 @@ type ElementProps = {
onClick?: () => void; onClick?: () => void;
}; };
type StyleProps = { type PanelStyleProps = {
className?: string; className?: string;
hasSeparator?: boolean; hasSeparator?: boolean;
}; };
export type PanelProps = ElementProps & StyleProps;
export const Panel = ({ export const Panel = ({
slotHeaderContent, slotHeaderContent,
slotHeader, slotHeader,
@@ -33,7 +30,7 @@ export const Panel = ({
onClick, onClick,
hasSeparator, hasSeparator,
className, className,
}: PanelProps) => ( }: PanelProps & PanelStyleProps) => (
<Styled.Panel onClick={onClick} className={className}> <Styled.Panel onClick={onClick} className={className}>
<Styled.Left> <Styled.Left>
{href ? ( {href ? (
@@ -70,12 +67,6 @@ Styled.Panel = styled.section<{ onClick?: () => void }>`
--panel-content-paddingY: var(--panel-paddingY); --panel-content-paddingY: var(--panel-paddingY);
--panel-content-paddingX: var(--panel-paddingX); --panel-content-paddingX: var(--panel-paddingX);
@media ${breakpoints.notTablet} {
--panel-paddingX: 1.5rem;
--panel-paddingY: 1.25rem;
--panel-content-paddingY: 1rem;
}
${layoutMixins.row} ${layoutMixins.row}
background-color: var(--color-layer-3); background-color: var(--color-layer-3);
+2 -3
View File
@@ -11,7 +11,6 @@ type ElementProps = {
}; };
type StyleProps = { type StyleProps = {
className?: string;
hasLogo?: boolean; hasLogo?: boolean;
size?: number; size?: number;
}; };
@@ -19,7 +18,7 @@ type StyleProps = {
const DARK_LOGO_MARK_URL = '/logos/logo-mark-dark.svg'; const DARK_LOGO_MARK_URL = '/logos/logo-mark-dark.svg';
const LIGHT_LOGO_MARK_URL = '/logos/logo-mark-light.svg'; const LIGHT_LOGO_MARK_URL = '/logos/logo-mark-light.svg';
export const QrCode = ({ className, value, hasLogo, size = 300 }: ElementProps & StyleProps) => { export const QrCode = ({ value, hasLogo, size = 300 }: ElementProps & StyleProps) => {
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const appTheme: AppTheme = useSelector(getAppTheme); const appTheme: AppTheme = useSelector(getAppTheme);
@@ -75,7 +74,7 @@ export const QrCode = ({ className, value, hasLogo, size = 300 }: ElementProps &
} }
}, [appTheme, hasLogo]); }, [appTheme, hasLogo]);
return <Styled.QrCode className={className} ref={ref} />; return <Styled.QrCode ref={ref} />;
}; };
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
+1 -1
View File
@@ -7,7 +7,7 @@ import { StoryWrapper } from '.ladle/components';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { InputType } from './Input'; import { InputType } from './Input';
export const SearchInputStory: Story<Parameters<typeof SearchInput>[0]> = (args) => ( export const SearchInputStory: Story<Parameters<typeof SearchInput>> = (args) => (
<StoryWrapper> <StoryWrapper>
<Styled.Container> <Styled.Container>
<SearchInput placeholder="Search something..." type={InputType.Search} /> <SearchInput placeholder="Search something..." type={InputType.Search} />
+1 -7
View File
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'; import { useState } from 'react';
import styled, { type AnyStyledComponent, css } from 'styled-components'; import styled, { type AnyStyledComponent, css } from 'styled-components';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
@@ -22,11 +22,6 @@ export const SearchInput = ({
}: SearchInputProps) => { }: SearchInputProps) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [value, setValue] = useState(''); const [value, setValue] = useState('');
const inputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
if (isOpen) inputRef?.current?.focus();
}, [inputRef, isOpen]);
return ( return (
<Styled.Search> <Styled.Search>
@@ -46,7 +41,6 @@ export const SearchInput = ({
/> />
<Styled.Input <Styled.Input
autoFocus autoFocus
ref={inputRef}
value={value} value={value}
isOpen={isOpen} isOpen={isOpen}
type={type} type={type}
+5 -2
View File
@@ -6,7 +6,7 @@ import { SearchSelectMenu } from '@/components/SearchSelectMenu';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
export const SearchSelectMenuStory: Story<Parameters<typeof SearchSelectMenu>[0]> = (args) => { export const SearchSelectMenuStory: Story<Parameters<typeof SearchSelectMenu>> = (args) => {
const [selectedItem, setSelectedItem] = useState<string>(); const [selectedItem, setSelectedItem] = useState<string>();
const exampleItems = [ const exampleItems = [
@@ -24,7 +24,10 @@ export const SearchSelectMenuStory: Story<Parameters<typeof SearchSelectMenu>[0]
return ( return (
<StoryWrapper> <StoryWrapper>
<Container> <Container>
<SearchSelectMenu {...args} items={exampleItems}> <SearchSelectMenu
{...args}
items={exampleItems}
>
{!selectedItem ? <span>Search and Select</span> : <span>{selectedItem}</span>} {!selectedItem ? <span>Search and Select</span> : <span>{selectedItem}</span>}
</SearchSelectMenu> </SearchSelectMenu>
</Container> </Container>
+7 -12
View File
@@ -12,8 +12,6 @@ import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
import { WithLabel } from '@/components/WithLabel'; import { WithLabel } from '@/components/WithLabel';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { formMixins } from '@/styles/formMixins';
import breakpoints from '@/styles/breakpoints';
type ElementProps = { type ElementProps = {
asChild?: boolean; asChild?: boolean;
@@ -86,30 +84,27 @@ export const SearchSelectMenu = ({
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
Styled.SearchSelectMenu = styled.div`
${layoutMixins.column}
`;
Styled.MenuTrigger = styled.div` Styled.MenuTrigger = styled.div`
height: var(--form-input-height); height: var(--form-input-height);
${layoutMixins.spacedRow} ${layoutMixins.spacedRow}
align-items: center; align-items: center;
padding: var(--form-input-paddingY) var(--form-input-paddingX); padding: 0 1rem;
@media ${breakpoints.tablet} {
height: var(--form-input-height-mobile);
}
`; `;
Styled.WithLabel = styled(WithLabel)` Styled.WithLabel = styled(WithLabel)`
${formMixins.inputLabel} --label-textColor: var(--color-text-0);
gap: 0.25rem;
label { label {
font: var(--font-mini-book); font: var(--font-mini-book);
} }
`; `;
Styled.SearchSelectMenu = styled.div`
${layoutMixins.column}
`;
Styled.WithDetailsReceipt = styled(WithDetailsReceipt)` Styled.WithDetailsReceipt = styled(WithDetailsReceipt)`
--withReceipt-backgroundColor: var(--color-layer-2); --withReceipt-backgroundColor: var(--color-layer-2);
+1 -1
View File
@@ -26,7 +26,7 @@ const exampleItems: { value: string; label: string }[] = [
}, },
]; ];
export const SelectMenuStory: Story<Parameters<typeof SelectMenu>[0]> = (args) => { export const SelectMenuStory: Story<Parameters<typeof SelectMenu>> = (args) => {
const [value, setValue] = useState(exampleItems[0].value); const [value, setValue] = useState(exampleItems[0].value);
const [value2, setValue2] = useState(exampleItems[2].value); const [value2, setValue2] = useState(exampleItems[2].value);
+9 -15
View File
@@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import styled, { css, type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { import {
Root, Root,
@@ -13,13 +13,11 @@ import {
Portal, Portal,
Icon as SelectIcon, Icon as SelectIcon,
} from '@radix-ui/react-select'; } from '@radix-ui/react-select';
import { CheckIcon } from '@radix-ui/react-icons';
import { popoverMixins } from '@/styles/popoverMixins'; import { popoverMixins } from '@/styles/popoverMixins';
import { formMixins } from '@/styles/formMixins'; import { formMixins } from '@/styles/formMixins';
import { WithLabel } from '@/components/WithLabel'; import { WithLabel } from '@/components/WithLabel';
import { Icon, IconName } from './Icon';
export const SelectMenu = <T extends string>({ export const SelectMenu = <T extends string>({
children, children,
@@ -46,9 +44,7 @@ export const SelectMenu = <T extends string>({
) : ( ) : (
<Value /> <Value />
)} )}
{React.Children.toArray(children).length > 1 && ( {React.Children.toArray(children).length > 1 && <Styled.DropdownIcon />}
<Styled.TriggerIcon iconName={IconName.Triangle} />
)}
</Styled.Trigger> </Styled.Trigger>
<Portal> <Portal>
<Styled.Content className={className}> <Styled.Content className={className}>
@@ -72,9 +68,7 @@ export const SelectItem = <T extends string>({
}) => ( }) => (
<Styled.Item className={className} value={value}> <Styled.Item className={className} value={value}>
<ItemText>{label}</ItemText> <ItemText>{label}</ItemText>
<Styled.ItemIndicator> <Styled.ItemIndicator>{/* <CheckIcon /> */}</Styled.ItemIndicator>
<CheckIcon />
</Styled.ItemIndicator>
</Styled.Item> </Styled.Item>
); );
@@ -94,6 +88,12 @@ Styled.Trigger = styled(Trigger)<{ $withBlur?: boolean }>`
} }
`; `;
Styled.DropdownIcon = styled(SelectIcon)`
font-size: 0.675em;
color: var(--color-text-1);
margin-left: auto;
`;
Styled.Content = styled(Content)` Styled.Content = styled(Content)`
--select-menu-content-maxWidth: ; --select-menu-content-maxWidth: ;
max-width: var(--select-menu-content-maxWidth); max-width: var(--select-menu-content-maxWidth);
@@ -116,9 +116,3 @@ Styled.WithLabel = styled(WithLabel)`
${formMixins.inputLabel} ${formMixins.inputLabel}
border-radius: 0; border-radius: 0;
`; `;
Styled.TriggerIcon = styled(Icon)`
width: 0.625rem;
height: 0.375rem;
color: var(--color-text-0);
`;
+20 -101
View File
@@ -33,20 +33,16 @@ import {
import { useAsyncList } from 'react-stately'; import { useAsyncList } from 'react-stately';
import { useBreakpoints, useStringGetter } from '@/hooks'; import { useBreakpoints } from '@/hooks';
import { MediaQueryKeys } from '@/hooks/useBreakpoints'; import { MediaQueryKeys } from '@/hooks/useBreakpoints';
import { Checkbox } from '@/components/Checkbox';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { CaretIcon } from '@/icons';
import { STRING_KEYS } from '@/constants/localization';
import { MustBigNumber } from '@/lib/numbers';
import { Icon, IconName } from './Icon'; import { Icon, IconName } from './Icon';
import { Tag } from './Tag'; import { Tag } from './Tag';
import { Button } from './Button';
export { TableCell } from './Table/TableCell'; export { TableCell } from './Table/TableCell';
export { TableColumnHeader } from './Table/TableColumnHeader'; export { TableColumnHeader } from './Table/TableColumnHeader';
@@ -83,7 +79,7 @@ export type ColumnDef<TableRowData extends object> = {
width?: ColumnSize; width?: ColumnSize;
}; };
export type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = { type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
label?: string; label?: string;
columns: ColumnDef<TableRowData>[]; columns: ColumnDef<TableRowData>[];
data: TableRowData[]; data: TableRowData[];
@@ -95,10 +91,6 @@ 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;
viewMoreConfig?: {
initialNumRowsToShow: number;
numRowsPerPage?: number;
};
// collection: TableCollection<string>; // collection: TableCollection<string>;
// children: React.ReactNode; // children: React.ReactNode;
}; };
@@ -128,7 +120,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
selectionMode = 'single', selectionMode = 'single',
selectionBehavior = 'toggle', selectionBehavior = 'toggle',
slotEmpty, slotEmpty,
viewMoreConfig,
// shouldRowRender, // shouldRowRender,
// collection, // collection,
@@ -144,18 +135,6 @@ 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(viewMoreConfig?.initialNumRowsToShow);
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(
@@ -182,7 +161,10 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
? // String ? // String
collator.compare(first as string, second as string) collator.compare(first as string, second as string)
: // Number : // Number
MustBigNumber(first).comparedTo(MustBigNumber(second))) * Math.sign(
(parseInt(first as string) || (first as number)) -
(parseInt(second as string) || (second as number))
)) *
// Flip the direction if descending order is specified. // Flip the direction if descending order is specified.
(sortDirection === 'descending' ? -1 : 1) (sortDirection === 'descending' ? -1 : 1)
); );
@@ -229,10 +211,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
onRowAction && onRowAction &&
((key: TableRowKey) => onRowAction(key, data.find((row) => getRowKey(row) === key)!)) ((key: TableRowKey) => onRowAction(key, data.find((row) => getRowKey(row) === key)!))
} }
numColumns={shownColumns.length}
onViewMoreClick={
enableViewMore && numRowsToShow! < data.length ? onViewMoreClick : undefined
}
// shouldRowRender={shouldRowRender} // shouldRowRender={shouldRowRender}
hideHeader={hideHeader} hideHeader={hideHeader}
withGradientCardRows={withGradientCardRows} withGradientCardRows={withGradientCardRows}
@@ -257,7 +235,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
)} )}
</TableHeader> </TableHeader>
<TableBody items={enableViewMore ? list.items.slice(0, numRowsToShow) : list.items}> <TableBody items={list.items}>
{(item) => ( {(item) => (
<Row key={getRowKey(item)}> <Row key={getRowKey(item)}>
{(columnKey) => ( {(columnKey) => (
@@ -291,8 +269,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
onRowAction?: (key: TableRowKey) => void; onRowAction?: (key: TableRowKey) => void;
// shouldRowRender?: (prevRowData: object, currentRowData: object) => boolean; // shouldRowRender?: (prevRowData: object, currentRowData: object) => boolean;
children: CollectionChildren<TableRowData>; children: CollectionChildren<TableRowData>;
numColumns: number;
onViewMoreClick?: () => void;
hideHeader?: boolean; hideHeader?: boolean;
withGradientCardRows?: boolean; withGradientCardRows?: boolean;
@@ -302,7 +278,7 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
withScrollSnapColumns?: boolean; withScrollSnapColumns?: boolean;
withScrollSnapRows?: boolean; withScrollSnapRows?: boolean;
}) => { }) => {
const { selectionMode, selectionBehavior, numColumns, onViewMoreClick } = props; const { selectionMode, selectionBehavior } = props;
const state = useTableState<TableRowData>({ const state = useTableState<TableRowData>({
...props, ...props,
@@ -363,7 +339,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
<TableBodyRowGroup <TableBodyRowGroup
withGradientCardRows={props.withGradientCardRows} withGradientCardRows={props.withGradientCardRows}
withInnerBorders={props.withInnerBorders} withInnerBorders={props.withInnerBorders}
withOuterBorder={props.withOuterBorder}
> >
{/* {Array.from(collection.getChildren!(collection.body.key), (row) => */} {/* {Array.from(collection.getChildren!(collection.body.key), (row) => */}
{[...collection.body.childNodes].map((row) => {[...collection.body.childNodes].map((row) =>
@@ -409,9 +384,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
</TableRow> </TableRow>
) )
)} )}
{onViewMoreClick ? (
<ViewMoreRow colSpan={numColumns} onClick={onViewMoreClick} />
) : undefined}
</TableBodyRowGroup> </TableBodyRowGroup>
</Styled.Table> </Styled.Table>
); );
@@ -445,7 +417,6 @@ const TableBodyRowGroup = ({
children, children,
withGradientCardRows, withGradientCardRows,
withInnerBorders, withInnerBorders,
withOuterBorder,
}: { children: React.ReactNode } & StyleProps) => { }: { children: React.ReactNode } & StyleProps) => {
const { rowGroupProps } = useTableRowGroup(); const { rowGroupProps } = useTableRowGroup();
@@ -454,7 +425,6 @@ const TableBodyRowGroup = ({
{...rowGroupProps} {...rowGroupProps}
withGradientCardRows={withGradientCardRows} withGradientCardRows={withGradientCardRows}
withInnerBorders={withInnerBorders} withInnerBorders={withInnerBorders}
withOuterBorder={withOuterBorder}
> >
{children} {children}
</Styled.Tbody> </Styled.Tbody>
@@ -521,23 +491,6 @@ const TableColumnHeader = <TableRowData extends object>({
); );
}; };
export const ViewMoreRow = ({ colSpan, onClick }: { colSpan: number; onClick: () => void }) => {
const stringGetter = useStringGetter();
return (
<Styled.ViewMoreTr key="viewmore">
<Styled.Td
colSpan={colSpan}
onMouseDown={(e: MouseEvent) => e.preventDefault()}
onPointerDown={(e: MouseEvent) => e.preventDefault()}
>
<Styled.ViewMoreButton slotRight={<CaretIcon />} onClick={onClick}>
{stringGetter({ key: STRING_KEYS.VIEW_MORE })}
</Styled.ViewMoreButton>
</Styled.Td>
</Styled.ViewMoreTr>
);
};
export const TableRow = <TableRowData extends object>({ export const TableRow = <TableRowData extends object>({
item, item,
children, children,
@@ -684,8 +637,6 @@ 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;
@@ -711,7 +662,7 @@ Styled.Empty = styled.div<{ withOuterBorder: boolean }>`
justify-items: center; justify-items: center;
align-content: center; align-content: center;
padding: 4rem; padding: 2rem;
gap: 0.75em; gap: 0.75em;
color: var(--color-text-0); color: var(--color-text-0);
@@ -795,7 +746,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(var(--hover-filter-base)); filter: brightness(1.1);
} }
`}; `};
@@ -880,7 +831,6 @@ Styled.SortArrow = styled.span<{ sortDirection: 'ascending' | 'descending' }>`
Styled.Thead = styled.thead<StyleProps>` Styled.Thead = styled.thead<StyleProps>`
${layoutMixins.stickyHeader} ${layoutMixins.stickyHeader}
scroll-snap-align: none; scroll-snap-align: none;
font: var(--font-mini-book);
> * { > * {
height: var(--stickyArea-topHeight); height: var(--stickyArea-topHeight);
@@ -889,17 +839,18 @@ Styled.Thead = styled.thead<StyleProps>`
color: var(--tableHeader-textColor); color: var(--tableHeader-textColor);
background-color: var(--tableHeader-backgroundColor); background-color: var(--tableHeader-backgroundColor);
${({ withInnerBorders, withGradientCardRows }) => @media ${breakpoints.notTablet} {
withInnerBorders && ${({ withInnerBorders, withGradientCardRows }) =>
!withGradientCardRows && withInnerBorders &&
css` !withGradientCardRows &&
${layoutMixins.withInnerHorizontalBorders} css`
`} ${layoutMixins.withInnerHorizontalBorders}
`}
}
`; `;
Styled.Tbody = styled.tbody<StyleProps>` Styled.Tbody = styled.tbody<StyleProps>`
${layoutMixins.stickyArea2} ${layoutMixins.stickyArea2}
font: var(--font-small-book);
// If <table> height is fixed with not enough rows to overflow, vertically center the rows // If <table> height is fixed with not enough rows to overflow, vertically center the rows
&:before, &:before,
@@ -918,22 +869,6 @@ Styled.Tbody = styled.tbody<StyleProps>`
--stickyArea2-paddingBottom: var(--border-width); --stickyArea2-paddingBottom: var(--border-width);
--stickyArea2-paddingLeft: var(--border-width); --stickyArea2-paddingLeft: var(--border-width);
--stickyArea2-paddingRight: var(--border-width); --stickyArea2-paddingRight: var(--border-width);
tr:first-of-type {
box-shadow: 0 calc(var(--border-width)) 0 0 var(--border-color);
}
`}
${({ withOuterBorder }) =>
withOuterBorder &&
css`
tr:last-of-type:not(:only-of-type) {
box-shadow: 0 calc(-1 * var(--border-width)) 0 0 var(--border-color);
}
tr:first-of-type {
box-shadow: none;
}
`} `}
${({ withGradientCardRows }) => ${({ withGradientCardRows }) =>
@@ -985,19 +920,3 @@ Styled.Row = styled.div`
${layoutMixins.inlineRow} ${layoutMixins.inlineRow}
padding: var(--tableCell-padding); padding: var(--tableCell-padding);
`; `;
Styled.ViewMoreButton = styled(Button)`
--button-backgroundColor: var(--color-layer-2);
--button-textColor: var(--color-text-1);
width: 100%;
svg {
width: 0.675rem;
margin-left: 0.5ch;
}
`;
Styled.ViewMoreTr = styled(Styled.Tr)`
--border-color: var(--tableViewMore-borderColor);
`;
+20 -19
View File
@@ -13,11 +13,29 @@ enum TabItem {
Item3 = 'Item3', Item3 = 'Item3',
} }
export const TabsStory: Story<Parameters<typeof Tabs>[0]> = (args) => { const TabItems = [
{
value: TabItem.Item1,
label: 'Item 1',
content: <div>Item 1 Content</div>,
},
{
value: TabItem.Item2,
label: 'Item 2',
content: <div>Item 2 Content</div>,
},
{
value: TabItem.Item3,
label: 'Item 3',
content: <div>Item 3 Content</div>,
},
];
export const TabsStory: Story<Parameters<typeof Tabs>> = (args) => {
return ( return (
<StoryWrapper> <StoryWrapper>
<Styled.Container> <Styled.Container>
<Tabs {...args} /> <Tabs items={TabItems} {...args} />
</Styled.Container> </Styled.Container>
</StoryWrapper> </StoryWrapper>
); );
@@ -25,23 +43,6 @@ export const TabsStory: Story<Parameters<typeof Tabs>[0]> = (args) => {
TabsStory.args = { TabsStory.args = {
fullWidthTabs: false, fullWidthTabs: false,
items: [
{
value: TabItem.Item1,
label: 'Item 1',
content: <div>Item 1 Content</div>,
},
{
value: TabItem.Item2,
label: 'Item 2',
content: <div>Item 2 Content</div>,
},
{
value: TabItem.Item3,
label: 'Item 3',
content: <div>Item 3 Content</div>,
},
],
}; };
TabsStory.argTypes = { TabsStory.argTypes = {
+2 -5
View File
@@ -21,7 +21,6 @@ export type TabItem<TabItemsValue> = {
content?: React.ReactNode; content?: React.ReactNode;
subitems?: TabItem<TabItemsValue>[]; subitems?: TabItem<TabItemsValue>[];
customTrigger?: ReactNode; customTrigger?: ReactNode;
asChild?: boolean;
}; };
type ElementProps<TabItemsValue> = { type ElementProps<TabItemsValue> = {
@@ -42,8 +41,6 @@ type StyleProps = {
className?: string; className?: string;
}; };
export type TabsProps<TabItemsValue> = ElementProps<TabItemsValue> & StyleProps;
export const Tabs = <TabItemsValue extends string>({ export const Tabs = <TabItemsValue extends string>({
defaultValue, defaultValue,
value, value,
@@ -110,10 +107,9 @@ export const Tabs = <TabItemsValue extends string>({
sharedContent sharedContent
) : ( ) : (
<Styled.Stack> <Styled.Stack>
{items.map(({ asChild, value, content, forceMount }) => ( {items.map(({ value, content, forceMount }) => (
<Styled.Content <Styled.Content
key={value} key={value}
asChild={asChild}
value={value} value={value}
forceMount={forceMount} forceMount={forceMount}
$hide={forceMount && currentItem?.value !== value} $hide={forceMount && currentItem?.value !== value}
@@ -246,6 +242,7 @@ Styled.Trigger = styled(Trigger)<{ $withBorders?: boolean }>`
Styled.Stack = styled.div` Styled.Stack = styled.div`
${layoutMixins.stack} ${layoutMixins.stack}
${layoutMixins.perspectiveArea}
box-shadow: none; box-shadow: none;
`; `;
+2 -21
View File
@@ -1,10 +1,10 @@
import type { Story } from '@ladle/react'; import type { Story } from '@ladle/react';
import { Tag, TagSign, TagSize, TagType } from '@/components/Tag'; import { Tag } from '@/components/Tag';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
export const TagStory: Story<Parameters<typeof Tag>[0]> = (args) => { export const TagStory: Story<Parameters<typeof Tag>> = (args) => {
return ( return (
<StoryWrapper> <StoryWrapper>
<Tag {...args} /> <Tag {...args} />
@@ -14,23 +14,4 @@ export const TagStory: Story<Parameters<typeof Tag>[0]> = (args) => {
TagStory.args = { TagStory.args = {
children: 'USDC', children: 'USDC',
isHighlighted: false,
};
TagStory.argTypes = {
size: {
options: Object.values(TagSize),
control: { type: 'select' },
defaultValue: TagSize.Small,
},
type: {
options: [...Object.values(TagType), undefined],
control: { type: 'select' },
defaultValue: undefined,
},
sign: {
options: [...Object.values(TagSign), undefined],
control: { type: 'select' },
defaultValue: undefined,
},
}; };
+8 -8
View File
@@ -1,20 +1,20 @@
import styled, { css } from 'styled-components'; import styled, { css } from 'styled-components';
export enum TagSize { export enum TagSize {
Small = 'Small', Small,
Medium = 'Medium', Medium,
} }
export enum TagType { export enum TagType {
Asset = 'Asset', Asset,
Side = 'Side', Side,
Number = 'Number', Number,
} }
export enum TagSign { export enum TagSign {
Positive = 'Positive', Positive,
Negative = 'Negative', Negative,
Neutral = 'Neutral', Neutral,
} }
type StyleProps = { type StyleProps = {
-4
View File
@@ -8,7 +8,6 @@ import { Button, type ButtonStateConfig, type ButtonProps } from '@/components/B
type ElementProps = { type ElementProps = {
timeoutInSeconds: number; timeoutInSeconds: number;
slotFinal?: ReactNode;
} & ButtonProps; } & ButtonProps;
export type TimeoutButtonProps = ElementProps; export type TimeoutButtonProps = ElementProps;
@@ -16,7 +15,6 @@ export type TimeoutButtonProps = ElementProps;
export const TimeoutButton = ({ export const TimeoutButton = ({
children, children,
timeoutInSeconds, timeoutInSeconds,
slotFinal,
...otherProps ...otherProps
}: TimeoutButtonProps) => { }: TimeoutButtonProps) => {
const [timeoutDeadline] = useState(Date.now() + timeoutInSeconds * 1000); const [timeoutDeadline] = useState(Date.now() + timeoutInSeconds * 1000);
@@ -25,8 +23,6 @@ export const TimeoutButton = ({
const secondsLeft = Math.max(0, (timeoutDeadline - now) / 1000); const secondsLeft = Math.max(0, (timeoutDeadline - now) / 1000);
if (slotFinal && secondsLeft <= 0) return slotFinal;
return ( return (
<Button <Button
{...otherProps} {...otherProps}
+77 -76
View File
@@ -1,19 +1,24 @@
import { type MouseEvent, useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import styled, { keyframes } from 'styled-components';
import { Root, Action, Close } from '@radix-ui/react-toast'; import { Root, Title, Description, Action, Close } from '@radix-ui/react-toast';
import { ButtonShape, ButtonSize } from '@/constants/buttons'; import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { popoverMixins } from '@/styles/popoverMixins';
import { breakpoints } from '@/styles';
import { Notification, type NotificationProps } from '@/components/Notification';
import { IconButton } from './IconButton'; import { IconButton } from './IconButton';
import { IconName } from './Icon'; import { CloseIcon } from '@/icons';
import styled, { keyframes } from 'styled-components';
import { popoverMixins } from '@/styles/popoverMixins';
import { layoutMixins } from '@/styles/layoutMixins';
type ElementProps = { type ElementProps = {
isOpen?: boolean; isOpen?: boolean;
setIsOpen?: (isOpen: boolean, isClosedFromTimeout?: boolean) => void; setIsOpen?: (isOpen: boolean, isClosedFromTimeout?: boolean) => void;
slotIcon?: React.ReactNode;
slotTitle?: React.ReactNode;
slotDescription?: React.ReactNode;
slotCustomContent?: React.ReactNode;
slotAction?: React.ReactNode;
actionDescription?: string; actionDescription?: string;
actionAltText?: string; actionAltText?: string;
sensitivity?: 'foreground' | 'background'; sensitivity?: 'foreground' | 'background';
@@ -21,22 +26,13 @@ type ElementProps = {
lastUpdated?: number; lastUpdated?: number;
}; };
type StyleProps = { type StyleProps = {};
className?: string;
};
type ToastProps = NotificationProps & ElementProps & StyleProps;
export const Toast = ({ export const Toast = ({
className,
isOpen = true, isOpen = true,
notification,
onClick,
setIsOpen, setIsOpen,
slotIcon, slotIcon,
slotTitle, slotTitle,
slotTitleLeft,
slotTitleRight,
slotDescription, slotDescription,
slotCustomContent, slotCustomContent,
slotAction, slotAction,
@@ -45,7 +41,7 @@ export const Toast = ({
sensitivity = 'background', sensitivity = 'background',
duration = Infinity, duration = Infinity,
lastUpdated, lastUpdated,
}: ToastProps) => { }: ElementProps & StyleProps) => {
// Timeout // Timeout
const timeout = useRef<number>(); const timeout = useRef<number>();
const [isPaused, setIsPaused] = useState(false); const [isPaused, setIsPaused] = useState(false);
@@ -62,45 +58,37 @@ export const Toast = ({
return ( return (
<$Root <$Root
className={className}
type={sensitivity} type={sensitivity}
duration={Infinity} duration={Infinity}
open={isOpen} open={isOpen}
onOpenChange={setIsOpen} onOpenChange={setIsOpen}
onPause={() => setIsPaused(true)} onPause={() => setIsPaused(true)}
onResume={() => setIsPaused(false)} onResume={() => setIsPaused(false)}
onClick={() => {
setIsOpen?.(false, false);
onClick?.();
}}
> >
<Close asChild> <div>
<$CloseButton <$Container>
iconName={IconName.Close} <$Header>
shape={ButtonShape.Circle} {slotIcon && <$Icon>{slotIcon}</$Icon>}
size={ButtonSize.XSmall}
onClick={(e: MouseEvent) => e.stopPropagation()}
/>
</Close>
{slotCustomContent ?? ( <Close asChild>
<$Notification <$CloseButton
isToast iconComponent={CloseIcon}
notification={notification} shape={ButtonShape.Square}
slotIcon={slotIcon} size={ButtonSize.XSmall}
slotTitle={slotTitle} />
slotTitleLeft={slotTitleLeft} </Close>
slotTitleRight={slotTitleRight}
slotDescription={slotDescription} <$Title>{slotTitle}</$Title>
slotAction={ </$Header>
actionDescription && ( {!slotCustomContent && <$Description>{slotDescription}</$Description>}
<$Action asChild altText={actionAltText}> {slotCustomContent}
{slotAction} {actionDescription && (
</$Action> <$Action asChild altText={actionAltText}>
) {slotAction}
} </$Action>
/> )}
)} </$Container>
</div>
</$Root> </$Root>
); );
}; };
@@ -126,7 +114,7 @@ const $Root = styled(Root)`
translate: var(--x) var(--y); translate: var(--x) var(--y);
will-change: translate, margin-top; will-change: translate, margin-top;
/* margin-bottom: var(--toasts-gap); */ margin-bottom: var(--toasts-gap);
&[data-swipe-direction='right'] { &[data-swipe-direction='right'] {
&[data-state='open'] { &[data-state='open'] {
@@ -175,10 +163,6 @@ const $Root = styled(Root)`
cursor: n-resize; cursor: n-resize;
} }
&:focus:not([data-swipe='end']) & {
outline: var(--color-accent) 1px solid;
}
&[data-swipe='move'] { &[data-swipe='move'] {
transition-property: opacity; transition-property: opacity;
opacity: 0.98; opacity: 0.98;
@@ -187,10 +171,6 @@ const $Root = styled(Root)`
* { * {
cursor: inherit; cursor: inherit;
} }
& > * {
opacity: 0.5;
}
} }
&[data-state='closed'], &[data-state='closed'],
@@ -218,48 +198,69 @@ const $Root = styled(Root)`
} }
`; `;
const $Notification = styled(Notification)` const $Container = styled.div`
// Params // Params
--toast-icon-size: 1.75em; --toast-icon-size: 1.75em;
// Rules // Rules
${popoverMixins.popover} ${popoverMixins.popover}
overflow: visible;
padding: 1rem; padding: 1rem;
box-shadow: 0 0 0 var(--border-width) var(--color-border), box-shadow: 0 0 0 var(--border-width) var(--color-border),
// border // border
0 0 0.5rem 0.1rem var(--color-layer-2); // shadow 0 0 0.5rem 0.1rem var(--color-layer-2); // shadow
${$Root}:focus:not([data-swipe='end']) & {
outline: var(--color-accent) 1px solid;
}
> * { > * {
transition: opacity 0.2s; transition: opacity 0.2s;
} }
${$Root}[data-swipe='move'] & > * {
opacity: 0.5;
}
`;
const $Header = styled.header`
display: block;
`;
const $Icon = styled.div`
${layoutMixins.row}
float: left;
width: 1em;
height: 1em;
margin-right: 0.4em;
line-height: 1;
`; `;
const $CloseButton = styled(IconButton)` const $CloseButton = styled(IconButton)`
--button-textColor: var(--color-text-0); --button-textColor: var(--color-text-0);
--button-border: none; --button-border: none;
--button-icon-size: 0.85em; --button-icon-size: 0.85em;
display: none;
/* float: right; */ float: right;
margin: -0.42rem -0.42rem -0.42rem 0.42rem; margin: -0.42rem -0.42rem -0.42rem 0.42rem;
`;
// Absolute const $Title = styled(Title)`
position: absolute; flex: 1;
top: 0;
right: 0;
border: solid var(--border-width) var(--color-border); font: var(--font-base-medium);
color: var(--color-text-2);
${$Root}:hover & { overflow: hidden;
display: block; text-overflow: ellipsis;
z-index: 2; `;
}
@media ${breakpoints.mobile} { const $Description = styled(Description)`
display: block; margin-top: 0.5rem;
z-index: 2; color: var(--color-text-0);
} font: var(--font-small-book);
`; `;
const $Action = styled(Action)` const $Action = styled(Action)`
+4 -8
View File
@@ -1,7 +1,6 @@
import styled from 'styled-components';
import { Provider, Viewport } from '@radix-ui/react-toast'; import { Provider, Viewport } from '@radix-ui/react-toast';
import styled from 'styled-components';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
type ElementProps = { type ElementProps = {
@@ -13,9 +12,7 @@ type StyleProps = {
className?: string; className?: string;
}; };
type ToastAreaProps = ElementProps & StyleProps; export const ToastArea = ({ swipeDirection, children, className }: ElementProps & StyleProps) => (
export const ToastArea = ({ swipeDirection, children, className }: ToastAreaProps) => (
<$ToastArea className={className}> <$ToastArea className={className}>
<Provider swipeDirection={swipeDirection}> <Provider swipeDirection={swipeDirection}>
{children} {children}
@@ -27,8 +24,9 @@ export const ToastArea = ({ swipeDirection, children, className }: ToastAreaProp
const $ToastArea = styled.aside` const $ToastArea = styled.aside`
// Params // Params
--toasts-gap: 0.5rem; --toasts-gap: 0.5rem;
// Rules // Rules
${layoutMixins.scrollArea}
z-index: 1; z-index: 1;
pointer-events: none; pointer-events: none;
@@ -36,7 +34,6 @@ const $ToastArea = styled.aside`
> * { > * {
display: contents; display: contents;
pointer-events: none; pointer-events: none;
position: relative;
> ol { > ol {
/* display: block; */ /* display: block; */
@@ -46,7 +43,6 @@ const $ToastArea = styled.aside`
// Desired display order: latest to earliest (¯\_(ツ)_/¯) // Desired display order: latest to earliest (¯\_(ツ)_/¯)
display: flex; display: flex;
flex-direction: column-reverse; flex-direction: column-reverse;
position: relative;
pointer-events: none; pointer-events: none;
+1 -1
View File
@@ -5,7 +5,7 @@ import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { StoryWrapper } from '.ladle/components'; import { StoryWrapper } from '.ladle/components';
import { ToggleButton } from './ToggleButton'; import { ToggleButton } from './ToggleButton';
export const ToggleButtonStory: Story<Parameters<typeof ToggleButton>[0]> = (args) => ( export const ToggleButtonStory: Story<Parameters<typeof ToggleButton>> = (args) => (
<StoryWrapper> <StoryWrapper>
<ToggleButton {...args}>Toggle me</ToggleButton> <ToggleButton {...args}>Toggle me</ToggleButton>
</StoryWrapper> </StoryWrapper>
-4
View File
@@ -52,19 +52,15 @@ const Styled: Record<string, AnyStyledComponent> = {};
Styled.BaseButton = styled(BaseButton)` Styled.BaseButton = styled(BaseButton)`
--button-toggle-off-backgroundColor: var(--color-layer-3); --button-toggle-off-backgroundColor: var(--color-layer-3);
--button-toggle-off-textColor: var(--color-text-0); --button-toggle-off-textColor: var(--color-text-0);
--button-toggle-off-border: solid var(--border-width) var(--border-color);
--button-toggle-on-backgroundColor: var(--color-layer-1); --button-toggle-on-backgroundColor: var(--color-layer-1);
--button-toggle-on-textColor: var(--color-text-2); --button-toggle-on-textColor: var(--color-text-2);
--button-toggle-on-border: solid var(--border-width) var(--border-color);
--button-backgroundColor: var(--button-toggle-off-backgroundColor); --button-backgroundColor: var(--button-toggle-off-backgroundColor);
--button-textColor: var(--button-toggle-off-textColor); --button-textColor: var(--button-toggle-off-textColor);
--button-border: var(--button-toggle-off-border);
&[data-state='on'], &[data-state='on'],
&[data-state='active'] { &[data-state='active'] {
--button-backgroundColor: var(--button-toggle-on-backgroundColor); --button-backgroundColor: var(--button-toggle-on-backgroundColor);
--button-textColor: var(--button-toggle-on-textColor); --button-textColor: var(--button-toggle-on-textColor);
--button-border: var(--button-toggle-on-border);
} }
`; `;
+2 -8
View File
@@ -21,22 +21,16 @@ const ToggleGroupItems = [
}, },
]; ];
export const ToggleGroupStory: Story< export const ToggleGroupStory: Story<Parameters<typeof ToggleGroup>> = (args) => {
Pick<Parameters<typeof ToggleGroup>[0], 'items' | 'size' | 'shape'>
> = (args) => {
const [value, setValue] = useState('0'); const [value, setValue] = useState('0');
return ( return (
<StoryWrapper> <StoryWrapper>
<ToggleGroup value={value} onValueChange={setValue} {...args} /> <ToggleGroup items={ToggleGroupItems} value={value} onValueChange={setValue} {...args} />
</StoryWrapper> </StoryWrapper>
); );
}; };
ToggleGroupStory.args = {
items: ToggleGroupItems,
};
ToggleGroupStory.argTypes = { ToggleGroupStory.argTypes = {
size: { size: {
options: Object.values(ButtonSize), options: Object.values(ButtonSize),
+2 -2
View File
@@ -2,9 +2,9 @@ import styled, { type AnyStyledComponent } from 'styled-components';
import { type RiskLevels } from '@/constants/abacus'; import { type RiskLevels } from '@/constants/abacus';
import { abacusHelper } from '@/lib/abacus'; import { UsageColorFromRiskLevel } from '@/styles/colors';
import { UsageColorFromRiskLevel } from '@/lib/styles';
import { abacusHelper } from '@/lib/abacus';
type ElementProps = { type ElementProps = {
value: number; value: number;
}; };
+2 -2
View File
@@ -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-green); color: var(--color-positive);
} }
`; `;
@@ -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-red); color: var(--color-negative);
width: 0.8em; width: 0.8em;
height: 0.8em; height: 0.8em;
+1 -1
View File
@@ -40,5 +40,5 @@ Styled.Details = styled(Details)`
padding: 0.375rem 0.75rem 0.25rem; padding: 0.375rem 0.75rem 0.25rem;
font-size: var(--details-item-fontSize, 0.8125em); font-size: 0.8125em;
`; `;

Some files were not shown because too many files have changed in this diff Show More