Compare commits

..
Author SHA1 Message Date
Adam Fraser 8a2cb2a296 Add trailing blocks to NetworkStatus analytics event 2024-01-12 16:01:37 -05:00
36 changed files with 244 additions and 844 deletions
+1 -1
View File
@@ -39,7 +39,7 @@
"@cosmjs/proto-signing": "^0.31.0",
"@cosmjs/stargate": "^0.31.0",
"@cosmjs/tendermint-rpc": "^0.31.0",
"@dydxprotocol/v4-abacus": "^1.2.5",
"@dydxprotocol/v4-abacus": "^1.2.3",
"@dydxprotocol/v4-client-js": "^1.0.11",
"@dydxprotocol/v4-localization": "^1.1.11",
"@ethersproject/providers": "^5.7.2",
+8 -8
View File
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
'@0xsquid/sdk':
specifier: ^1.10.0
@@ -23,8 +27,8 @@ dependencies:
specifier: ^0.31.0
version: 0.31.0
'@dydxprotocol/v4-abacus':
specifier: ^1.2.5
version: 1.2.5
specifier: ^1.2.3
version: 1.2.3
'@dydxprotocol/v4-client-js':
specifier: ^1.0.11
version: 1.0.11
@@ -987,8 +991,8 @@ packages:
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
dev: true
/@dydxprotocol/v4-abacus@1.2.5:
resolution: {integrity: sha512-pB3Fv1bzJRUDp29kAN61daZ34gTSGrSTNh+/AP3TUB63/Q/gaXQVBf91xVcso4Hw23xM3FwIcrRK0cvOSWgXKg==}
/@dydxprotocol/v4-abacus@1.2.3:
resolution: {integrity: sha512-OHGhN4uQo/ikRjeGzf+wGblFvb0uRA916QvQXG4LixsJy7H7HAt7AeZr9LqTM/GqYJicMmZCUS3WIMqgZ20hKA==}
dev: false
/@dydxprotocol/v4-client-js@1.0.11:
@@ -14809,7 +14813,3 @@ packages:
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: true
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
-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

+1
View File
@@ -11,5 +11,6 @@ export const DetachedScrollableSection = styled.section`
export const AttachedExpandingSection = styled.section`
${layoutMixins.contentSectionAttached}
${layoutMixins.expandingColumnWithHeader}
gap: var(--border-width);
`;
-3
View File
@@ -59,7 +59,6 @@ import {
PriceChartIcon,
PrivacyIcon,
QrIcon,
RewardStarIcon,
SearchIcon,
SendIcon,
ShareIcon,
@@ -135,7 +134,6 @@ export enum IconName {
PriceChart = 'PriceChart',
Privacy = 'Privacy',
Qr = 'Qr',
RewardStar = 'RewardStar',
Search = 'Search',
Send = 'Send',
Share = 'Share',
@@ -210,7 +208,6 @@ const icons = {
[IconName.PriceChart]: PriceChartIcon,
[IconName.Privacy]: PrivacyIcon,
[IconName.Qr]: QrIcon,
[IconName.RewardStar]: RewardStarIcon,
[IconName.Search]: SearchIcon,
[IconName.Send]: SendIcon,
[IconName.Share]: ShareIcon,
+1 -1
View File
@@ -7,7 +7,7 @@ import { layoutMixins } from '@/styles/layoutMixins';
import { breakpoints } from '@/styles';
type PanelProps = {
slotHeaderContent?: React.ReactNode;
slotHeaderContent?: string;
slotHeader?: React.ReactNode;
slotRight?: React.ReactNode;
children?: React.ReactNode;
+9 -70
View File
@@ -33,20 +33,17 @@ import {
import { useAsyncList } from 'react-stately';
import { useBreakpoints, useStringGetter } from '@/hooks';
import { useBreakpoints } from '@/hooks';
import { MediaQueryKeys } from '@/hooks/useBreakpoints';
import { Checkbox } from '@/components/Checkbox';
import { breakpoints } from '@/styles';
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 { Tag } from './Tag';
import { Button } from './Button';
import { MustBigNumber } from '@/lib/numbers';
export { TableCell } from './Table/TableCell';
export { TableColumnHeader } from './Table/TableColumnHeader';
@@ -68,7 +65,7 @@ export type TableItem<TableRowData> = {
onSelect?: (key: TableRowData) => void;
};
type ColumnDef<TableRowData extends object> = {
export type ColumnDef<TableRowData extends object> = {
columnKey: string;
label: React.ReactNode;
tag?: React.ReactNode;
@@ -83,7 +80,7 @@ type ColumnDef<TableRowData extends object> = {
width?: ColumnSize;
};
export type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
label?: string;
columns: ColumnDef<TableRowData>[];
data: TableRowData[];
@@ -95,7 +92,6 @@ export type ElementProps<TableRowData extends object | CustomRowConfig, TableRow
selectionBehavior?: 'replace' | 'toggle';
onRowAction?: (key: TableRowKey, row: TableRowData) => void;
slotEmpty?: React.ReactNode;
initialNumRowsToShow?: number;
// collection: TableCollection<string>;
// children: React.ReactNode;
};
@@ -125,7 +121,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
selectionMode = 'single',
selectionBehavior = 'toggle',
slotEmpty,
initialNumRowsToShow = data.length,
// shouldRowRender,
// collection,
@@ -141,7 +136,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
style,
}: ElementProps<TableRowData, TableRowKey> & StyleProps) => {
const [selectedKeys, setSelectedKeys] = useState(new Set<TableRowKey>());
const [numRowsToShow, setNumRowsToShow] = useState(initialNumRowsToShow);
const currentBreakpoints = useBreakpoints();
const shownColumns = columns.filter(
@@ -215,12 +209,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
onRowAction &&
((key: TableRowKey) => onRowAction(key, data.find((row) => getRowKey(row) === key)!))
}
numColumns={shownColumns.length}
onViewMoreClick={
numRowsToShow !== undefined && numRowsToShow < data.length
? () => setNumRowsToShow(data.length)
: undefined
}
// shouldRowRender={shouldRowRender}
hideHeader={hideHeader}
withGradientCardRows={withGradientCardRows}
@@ -245,7 +233,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
)}
</TableHeader>
<TableBody items={list.items.slice(0, numRowsToShow)}>
<TableBody items={list.items}>
{(item) => (
<Row key={getRowKey(item)}>
{(columnKey) => (
@@ -279,8 +267,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
onRowAction?: (key: TableRowKey) => void;
// shouldRowRender?: (prevRowData: object, currentRowData: object) => boolean;
children: CollectionChildren<TableRowData>;
numColumns: number;
onViewMoreClick?: () => void;
hideHeader?: boolean;
withGradientCardRows?: boolean;
@@ -290,7 +276,7 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
withScrollSnapColumns?: boolean;
withScrollSnapRows?: boolean;
}) => {
const { selectionMode, selectionBehavior, numColumns, onViewMoreClick } = props;
const { selectionMode, selectionBehavior } = props;
const state = useTableState<TableRowData>({
...props,
@@ -351,7 +337,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
<TableBodyRowGroup
withGradientCardRows={props.withGradientCardRows}
withInnerBorders={props.withInnerBorders}
withOuterBorder={props.withOuterBorder}
>
{/* {Array.from(collection.getChildren!(collection.body.key), (row) => */}
{[...collection.body.childNodes].map((row) =>
@@ -397,9 +382,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
</TableRow>
)
)}
{onViewMoreClick ? (
<ViewMoreRow colSpan={numColumns} onClick={onViewMoreClick} />
) : undefined}
</TableBodyRowGroup>
</Styled.Table>
);
@@ -433,7 +415,6 @@ const TableBodyRowGroup = ({
children,
withGradientCardRows,
withInnerBorders,
withOuterBorder,
}: { children: React.ReactNode } & StyleProps) => {
const { rowGroupProps } = useTableRowGroup();
@@ -442,7 +423,6 @@ const TableBodyRowGroup = ({
{...rowGroupProps}
withGradientCardRows={withGradientCardRows}
withInnerBorders={withInnerBorders}
withOuterBorder={withOuterBorder}
>
{children}
</Styled.Tbody>
@@ -509,23 +489,6 @@ const TableColumnHeader = <TableRowData extends object>({
);
};
export const ViewMoreRow = ({ colSpan, onClick }: { colSpan: number; onClick: () => void }) => {
const stringGetter = useStringGetter();
return (
<Styled.Tr 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.Tr>
);
};
export const TableRow = <TableRowData extends object>({
item,
children,
@@ -697,7 +660,7 @@ Styled.Empty = styled.div<{ withOuterBorder: boolean }>`
justify-items: center;
align-content: center;
padding: 4rem;
padding: 2rem;
gap: 0.75em;
color: var(--color-text-0);
@@ -905,18 +868,6 @@ Styled.Tbody = styled.tbody<StyleProps>`
--stickyArea2-paddingLeft: 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;
}
@@ -971,15 +922,3 @@ Styled.Row = styled.div`
${layoutMixins.inlineRow}
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;
}
`;
+2 -1
View File
@@ -27,8 +27,9 @@ export const ToastArea = ({ swipeDirection, children, className }: ToastAreaProp
const $ToastArea = styled.aside`
// Params
--toasts-gap: 0.5rem;
// Rules
${layoutMixins.scrollArea}
z-index: 1;
pointer-events: none;
-2
View File
@@ -87,8 +87,6 @@ export type NotificationDisplayData = {
slotTitleLeft?: React.ReactNode;
slotTitleRight?: React.ReactNode;
groupKey: string; // Grouping key toast notification stacking
// Overrides title/body for Notification in NotificationMenu
renderCustomBody?: ({
isToast,
-28
View File
@@ -28,7 +28,6 @@ import { useLocalNotifications } from '@/hooks/useLocalNotifications';
import { AssetIcon } from '@/components/AssetIcon';
import { Icon, IconName } from '@/components/Icon';
import { BlockRewardNotification } from '@/views/notifications/BlockRewardNotification';
import { TradeNotification } from '@/views/notifications/TradeNotification';
import { TransferStatusNotification } from '@/views/notifications/TransferStatusNotification';
@@ -81,7 +80,6 @@ export const notificationTypes: NotificationTypeConfig[] = [
body: abacusNotif.text ? stringGetter({ key: abacusNotif.text, params }) : '',
toastDuration: DEFAULT_TOAST_AUTO_CLOSE_MS,
toastSensitivity: 'foreground',
groupKey: abacusNotificationType,
renderCustomBody: ({ isToast, notification }) => (
<TradeNotification
isToast={isToast}
@@ -95,29 +93,6 @@ export const notificationTypes: NotificationTypeConfig[] = [
);
break;
}
case 'blockReward': {
trigger(
abacusNotif.id,
{
icon: abacusNotif.image && <$Icon src={abacusNotif.image} alt="" />,
title: stringGetter({ key: abacusNotif.title }),
body: abacusNotif.text ? stringGetter({ key: abacusNotif.text, params }) : '',
toastDuration: DEFAULT_TOAST_AUTO_CLOSE_MS,
toastSensitivity: 'foreground',
groupKey: abacusNotificationType,
renderCustomBody: ({ isToast, notification }) => (
<BlockRewardNotification
isToast={isToast}
data={parsedData}
notification={notification}
/>
),
},
[abacusNotif.updateTimeInMilliseconds, abacusNotif.data],
true
);
break;
}
default:
trigger(
abacusNotif.id,
@@ -127,7 +102,6 @@ export const notificationTypes: NotificationTypeConfig[] = [
body: abacusNotif.text ? stringGetter({ key: abacusNotif.text, params }) : '',
toastDuration: DEFAULT_TOAST_AUTO_CLOSE_MS,
toastSensitivity: 'foreground',
groupKey: abacusNotificationType,
},
[abacusNotif.updateTimeInMilliseconds, abacusNotif.data]
);
@@ -223,7 +197,6 @@ export const notificationTypes: NotificationTypeConfig[] = [
/>
),
toastSensitivity: 'foreground',
groupKey: NotificationType.SquidTransfer,
},
[isFinished]
);
@@ -269,7 +242,6 @@ export const notificationTypes: NotificationTypeConfig[] = [
},
}),
toastSensitivity: 'foreground',
groupKey: NotificationType.ReleaseUpdates,
},
[]
);
+3 -20
View File
@@ -1,7 +1,6 @@
import { useCallback, useEffect, useState, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { EvmDerivedAddresses } from '@/constants/account';
import { LocalStorageKey } from '@/constants/localStorage';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
@@ -105,17 +104,11 @@ export const useWalletConnection = () => {
[walletConnectConfig, walletType, walletConnectionType]
);
const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector });
const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector })
const { suggestAndConnect: connectGraz } = useConnectGraz();
const [evmDerivedAddresses] = useLocalStorage({
key: LocalStorageKey.EvmDerivedAddresses,
defaultValue: {} as EvmDerivedAddresses,
});
const connectWallet = useCallback(
async ({ walletType, forceConnect }: { walletType?: WalletType; forceConnect?: boolean }) => {
if (!walletType) return { walletType, walletConnectionType };
async ({ walletType }: { walletType: WalletType }) => {
const walletConnection = getWalletConnection({ walletType });
try {
@@ -139,11 +132,7 @@ export const useWalletConnection = () => {
});
}
} else {
const isAccountConnected = Boolean(
evmAddress && evmDerivedAddresses[evmAddress]?.encryptedSignature
);
// if account connected (via remember me), do not show wagmi popup until forceConnect
if (!isConnectedWagmi && (forceConnect || !isAccountConnected)) {
if (!isConnectedWagmi) {
await connectWagmi({
connector: resolveWagmiConnector({
walletType,
@@ -239,12 +228,6 @@ export const useWalletConnection = () => {
evmAddressWagmi,
signerWagmi,
publicClientWagmi,
isConnectedWagmi,
connectWallet: () =>
connectWallet({
walletType: selectedWalletType,
forceConnect: true,
}),
// Wallet connection (Cosmos)
dydxAddress,
-1
View File
@@ -50,7 +50,6 @@ export { default as PriceChartIcon } from './price-chart.svg';
export { default as PrivacyIcon } from './privacy.svg';
export { default as ProfileIcon } from './profile.svg';
export { default as QrIcon } from './qr.svg';
export { default as RewardStarIcon } from './reward-star.svg';
export { default as SearchIcon } from './search.svg';
export { default as SendIcon } from './send.svg';
export { default as ShareIcon } from './share.svg';
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 481 KiB

@@ -1,11 +1,7 @@
import { useState } from 'react';
import { useMemo, useState } from 'react';
import styled, { css } from 'styled-components';
import {
type Notification,
type NotificationDisplayData,
NotificationStatus,
} from '@/constants/notifications';
import { NotificationStatus } from '@/constants/notifications';
import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { useNotifications } from '@/hooks/useNotifications';
import { useBreakpoints } from '@/hooks/useBreakpoints';
@@ -17,31 +13,54 @@ import { Toast } from '@/components/Toast';
import { ToastArea } from '@/components/ToastArea';
import { ToggleButton } from '@/components/ToggleButton';
type ElementProps = {
notifications: {
notification: Notification<any, any>;
key: string;
displayData: NotificationDisplayData;
}[];
};
type StyleProps = {
className?: string;
};
export const NotificationStack = ({ notifications, className }: ElementProps & StyleProps) => {
const MAX_TOASTS = 10;
export const NotificationsToastArea = ({ className }: StyleProps) => {
const [shouldStackNotifications, setshouldStackNotifications] = useState(true);
const { markUnseen, markSeen, onNotificationAction } = useNotifications();
const {
notifications,
getKey,
getDisplayData,
markUnseen,
markSeen,
isMenuOpen,
onNotificationAction,
} = useNotifications();
const { isMobile } = useBreakpoints();
const hasMultipleToasts = notifications.length > 1;
const notificationMap = useMemo(() => {
return (
Object.values(notifications)
// Sort by time of first trigger
.sort(
(n1, n2) =>
n1.timestamps[NotificationStatus.Triggered]! -
n2.timestamps[NotificationStatus.Triggered]!
)
.map((notification) => ({
notification,
key: getKey(notification),
displayData: getDisplayData(notification),
}))
.filter(
({ displayData, notification }) =>
displayData && notification.status < NotificationStatus.Unseen
)
.slice(-MAX_TOASTS)
);
}, [notifications, getKey, getDisplayData]);
if (isMenuOpen) return null;
const hasMultipleToasts = notificationMap.length > 1;
return (
<StyledToastArea
swipeDirection={isMobile ? 'up' : 'right'}
className={className}
size={notifications.length}
>
<StyledToastArea swipeDirection={isMobile ? 'up' : 'right'} className={className}>
{hasMultipleToasts && (
<StyledToggleButton
shape={ButtonShape.Pill}
@@ -53,12 +72,12 @@ export const NotificationStack = ({ notifications, className }: ElementProps & S
</StyledToggleButton>
)}
{notifications.map(({ notification, key, displayData }, idx) => (
{notificationMap.map(({ notification, key, displayData }, idx) => (
<StyledToast
key={key}
isStacked={idx > 0 && shouldStackNotifications}
isStacked={shouldStackNotifications}
isOpen={notification.status < NotificationStatus.Unseen}
layer={idx}
layer={notificationMap.length - 1 - idx}
notification={notification}
slotIcon={displayData.icon}
slotTitle={displayData.title}
@@ -91,13 +110,19 @@ export const NotificationStack = ({ notifications, className }: ElementProps & S
);
};
const StyledToastArea = styled(ToastArea)<{ size: number }>`
position: relative;
${({ size }) =>
size &&
css`
padding-bottom: calc(${size - 1} * 2px);
`}
const StyledToastArea = styled(ToastArea)`
position: absolute;
width: min(17.5rem, 100%);
inset: 0 0 0 auto;
padding: 0.75rem 0.75rem 0.75rem 0;
mask-image: linear-gradient(to left, transparent, white 0.5rem);
@media ${breakpoints.mobile} {
width: 100%;
position: fixed;
}
`;
const StyledToast = styled(Toast)<{ isStacked?: boolean; layer: number }>`
@@ -108,7 +133,7 @@ const StyledToast = styled(Toast)<{ isStacked?: boolean; layer: number }>`
position: absolute;
left: 0;
top: calc(${layer} * 2px);
right: 0;
right: calc(${layer} * -2px);
`
: css`
margin-bottom: 0.75rem;
@@ -120,7 +145,7 @@ const StyledToggleButton = styled(ToggleButton)<{ isPressed: boolean }>`
pointer-events: auto;
display: none;
position: absolute;
top: -0.5rem;
top: 4px;
left: calc(50% - 0.75rem);
--button-width: 2rem;
--button-height: 1rem;
@@ -1,71 +0,0 @@
import { useMemo } from 'react';
import { groupBy } from 'lodash';
import styled from 'styled-components';
import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins';
import { NotificationStatus } from '@/constants/notifications';
import { useNotifications } from '@/hooks/useNotifications';
import { NotificationStack } from './NotifcationStack';
type StyleProps = {
className?: string;
};
const MAX_TOASTS = 10;
export const NotificationsToastArea = ({ className }: StyleProps) => {
const { notifications, getKey, getDisplayData, isMenuOpen } = useNotifications();
const notificationMapByType = useMemo(() => {
const notificationMap = Object.values(notifications)
// Sort by time of first trigger
.sort(
(n1, n2) =>
n1.timestamps[NotificationStatus.Triggered]! -
n2.timestamps[NotificationStatus.Triggered]!
)
.map((notification) => ({
notification,
key: getKey(notification),
displayData: getDisplayData(notification),
}))
.filter(
({ displayData, notification }) =>
displayData && notification.status < NotificationStatus.Unseen
)
.slice(-MAX_TOASTS);
return groupBy(notificationMap, (notification) => notification.displayData?.groupKey);
}, [notifications, getKey, getDisplayData]);
if (isMenuOpen) return null;
return (
<StyledToastArea className={className}>
{Object.keys(notificationMapByType).map((groupKey) => (
<NotificationStack notifications={notificationMapByType[groupKey]} key={groupKey} />
))}
</StyledToastArea>
);
};
const StyledToastArea = styled.div`
${layoutMixins.scrollArea}
position: absolute;
width: min(17.5rem, 100%);
inset: 0 0 0 auto;
padding: 0.75rem 0.75rem 0.75rem 0;
mask-image: linear-gradient(to left, transparent, white 0.5rem);
pointer-events: none;
@media ${breakpoints.mobile} {
width: 100%;
position: fixed;
}
`;
-4
View File
@@ -56,10 +56,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
this.store = undefined;
}
get isNobleClientConnected(): boolean {
return this.nobleClient?.isConnected ?? false;
}
setStore(store: RootStore): void {
this.store = store;
}
+5 -10
View File
@@ -171,15 +171,6 @@ class AbacusStateManager {
this.setTransferValue({ value: null, field: TransferInputField.usdcSize });
};
resetInputState = () => {
this.clearTransferInputValues();
this.setTransferValue({
field: TransferInputField.type,
value: null,
});
this.clearTradeInputValues();
};
// ------ Set Data ------ //
setStore = (store: RootStore) => {
this.store = store;
@@ -271,7 +262,11 @@ class AbacusStateManager {
) => this.stateManager.cancelOrder(orderId, callback);
cctpWithdraw = (
callback: (success: boolean, parsingError: Nullable<ParsingError>, data: string) => void
callback: (
success: boolean,
parsingError: Nullable<ParsingError>,
data: string,
) => void
): void => this.stateManager.commitCCTPWithdraw(callback);
// ------ Utils ------ //
+4 -4
View File
@@ -11,16 +11,16 @@ class TestFlags {
const params = new URLSearchParams(queryParamsString);
for (const [key, value] of params) {
this.queryParams[key.toLowerCase()] = value;
this.queryParams[key] = value;
}
}
get displayInitializingMarkets() {
return !!this.queryParams.displayinitializingmarkets;
return !!this.queryParams.displayInitializingMarkets;
}
get showMobileSignInOption() {
return !!this.queryParams.mobilesignin;
get withCCTP() {
return !!this.queryParams.withCCTP;
}
}
+4 -9
View File
@@ -5,7 +5,7 @@ import { useEnsName } from 'wagmi';
import { useNavigate } from 'react-router-dom';
import { ButtonSize } from '@/constants/buttons';
import { TransferType } from '@/constants/abacus';
import { TransferInputField, TransferType } from '@/constants/abacus';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -26,13 +26,12 @@ import { useAccounts, useStringGetter, useTokenConfigs } from '@/hooks';
import { getOnboardingState } from '@/state/accountSelectors';
import { openDialog } from '@/state/dialogs';
import abacusStateManager from '@/lib/abacus';
import { isTruthy } from '@/lib/isTruthy';
import { truncateAddress } from '@/lib/wallet';
import { DYDXBalancePanel } from './rewards/DYDXBalancePanel';
import { MigratePanel } from './rewards/MigratePanel';
import { GovernancePanel } from './rewards/GovernancePanel';
import { StakingPanel } from './rewards/StakingPanel';
const ENS_CHAIN_ID = 1; // Ethereum
@@ -179,7 +178,7 @@ const Profile = () => {
onClick={() => dispatch(openDialog({ type: DialogTypes.Help }))}
/>
</Styled.EqualGrid>
<MigratePanel />
<DYDXBalancePanel />
@@ -231,9 +230,6 @@ const Profile = () => {
withInnerBorders={false}
/>
</Styled.TablePanel>
<GovernancePanel />
<StakingPanel />
</Styled.MobileProfileLayout>
);
};
@@ -247,7 +243,6 @@ Styled.MobileProfileLayout = styled.div`
gap: 1rem;
padding: 1.25rem 0.9rem;
max-width: 100vw;
`;
Styled.Header = styled.header`
@@ -342,7 +337,7 @@ Styled.Details = styled(Details)`
Styled.RewardsPanel = styled(Panel)`
align-self: flex-start;
&,
> * {
height: 100%;
+3 -24
View File
@@ -17,14 +17,11 @@ import { TransferHistoryTable } from '@/views/tables/TransferHistoryTable';
import { Button } from '@/components/Button';
import { Icon, IconName } from '@/components/Icon';
import { NavigationMenu } from '@/components/NavigationMenu';
import { Tag, TagType } from '@/components/Tag';
import { WithSidebar } from '@/components/WithSidebar';
import { getOnboardingState, getSubaccount, getTradeInfoNumbers } from '@/state/accountSelectors';
import { getOnboardingState, getSubaccount } from '@/state/accountSelectors';
import { openDialog } from '@/state/dialogs';
import { shortenNumberForDisplay } from '@/lib/numbers';
import { PortfolioNavMobile } from './PortfolioNavMobile';
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
@@ -45,10 +42,6 @@ export default () => {
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
const { nativeTokenBalance } = useAccountBalance();
const { numTotalPositions, numTotalOpenOrders } = useSelector(getTradeInfoNumbers, shallowEqual) || {};
const numPositions = shortenNumberForDisplay(numTotalPositions);
const numOrders = shortenNumberForDisplay(numTotalOpenOrders);
const usdcBalance = freeCollateral?.current || 0;
useDocumentTitle(stringGetter({ key: STRING_KEYS.PORTFOLIO }));
@@ -126,27 +119,13 @@ export default () => {
{
value: PortfolioRoute.Positions,
slotBefore: <Styled.Icon iconName={IconName.Positions} />,
label: (
<>
{stringGetter({ key: STRING_KEYS.POSITIONS })}
{numPositions > 0 && (
<Tag type={TagType.Number}> {numPositions} </Tag>
)}
</>
),
label: stringGetter({ key: STRING_KEYS.POSITIONS }),
href: PortfolioRoute.Positions,
},
{
value: PortfolioRoute.Orders,
slotBefore: <Styled.Icon iconName={IconName.OrderPending} />,
label: (
<>
{stringGetter({ key: STRING_KEYS.ORDERS })}
{numOrders > 0 && (
<Tag type={TagType.Number}> {numOrders} </Tag>
)}
</>
),
label: stringGetter({ key: STRING_KEYS.ORDERS }),
href: PortfolioRoute.Orders,
},
{
-75
View File
@@ -1,75 +0,0 @@
import styled, { AnyStyledComponent } from 'styled-components';
import { useDispatch } from 'react-redux';
import { ButtonAction, ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { DialogTypes } from '@/constants/dialogs';
import { useStringGetter, useURLConfigs } from '@/hooks';
import { Panel } from '@/components/Panel';
import { IconName } from '@/components/Icon';
import { IconButton } from '@/components/IconButton';
import { Link } from '@/components/Link';
import { openDialog } from '@/state/dialogs';
export const GovernancePanel = () => {
const stringGetter = useStringGetter();
const dispatch = useDispatch();
const { governanceLearnMore } = useURLConfigs();
return (
<Panel
slotHeaderContent={
<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>
}
slotRight={
<Styled.Arrow>
<Styled.IconButton
action={ButtonAction.Base}
iconName={IconName.Arrow}
size={ButtonSize.Small}
/>
</Styled.Arrow>
}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
<Link href={governanceLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
</Panel>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Description = styled.div`
color: var(--color-text-0);
--link-color: var(--color-text-1);
a {
display: inline;
::before {
content: ' ';
}
}
`;
Styled.IconButton = styled(IconButton)`
color: var(--color-text-0);
--color-border: var(--color-layer-6);
`;
Styled.Arrow = styled.div`
padding-right: 1.5rem;
`;
Styled.Title = styled.h3`
font: var(--font-medium-book);
color: var(--color-text-2);
margin-bottom: -1rem;
`;
+2 -3
View File
@@ -146,15 +146,14 @@ Styled.Title = styled.h3`
color: var(--color-text-2);
padding: var(--panel-paddingY) var(--panel-paddingX) 0;
margin-bottom: -0.5rem;
`;
Styled.MigrateAction = styled.div`
${layoutMixins.flexEqualColumns}
align-items: center;
margin: 1rem;
gap: 1rem;
padding: 1rem;
margin: 1rem;
width: 100%;
background-color: var(--color-layer-2);
@@ -234,4 +233,4 @@ Styled.InlineRow = styled.div`
${layoutMixins.inlineRow}
color: var(--color-text-0);
--link-color: var(--color-text-1);
`;
`;
+77 -9
View File
@@ -3,29 +3,45 @@ import { useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { STRING_KEYS } from '@/constants/localization';
import { ButtonAction, ButtonSize } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs';
import { AppRoute } from '@/constants/routes';
import { useBreakpoints, useStringGetter } from '@/hooks';
import { useBreakpoints, useStringGetter, useURLConfigs } from '@/hooks';
import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins';
import { BackButton } from '@/components/BackButton';
import { Panel } from '@/components/Panel';
import { IconName } from '@/components/Icon';
import { IconButton } from '@/components/IconButton';
import { Link } from '@/components/Link';
import { openDialog } from '@/state/dialogs';
import { DYDXBalancePanel } from './DYDXBalancePanel';
import { MigratePanel } from './MigratePanel';
import { LaunchIncentivesPanel } from './LaunchIncentivesPanel';
import { RewardsHelpPanel } from './RewardsHelpPanel';
import { GovernancePanel } from './GovernancePanel';
import { StakingPanel } from './StakingPanel';
const RewardsPage = () => {
const dispatch = useDispatch();
const stringGetter = useStringGetter();
const { governanceLearnMore, stakingLearnMore } = useURLConfigs();
const { isTablet, isNotTablet } = useBreakpoints();
const navigate = useNavigate();
const panelArrow = (
<Styled.Arrow>
<Styled.IconButton
action={ButtonAction.Base}
iconName={IconName.Arrow}
size={ButtonSize.Small}
/>
</Styled.Arrow>
);
return (
<Styled.Page>
{isTablet && (
@@ -45,12 +61,37 @@ const RewardsPage = () => {
</Styled.PanelRowIncentivesAndBalance>
)}
{isNotTablet && (
<Styled.PanelRow>
<GovernancePanel />
<StakingPanel />
</Styled.PanelRow>
)}
<Styled.PanelRow>
<Styled.Panel
slotHeaderContent={
<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>
}
slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
<Link href={governanceLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
</Styled.Panel>
<Styled.Panel
slotHeaderContent={
<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>
}
slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
<Link href={stakingLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
</Styled.Panel>
</Styled.PanelRow>
<RewardsHelpPanel />
</Styled.Page>
@@ -99,6 +140,24 @@ Styled.Panel = styled(Panel)`
height: fit-content;
`;
Styled.Title = styled.h3`
font: var(--font-medium-book);
color: var(--color-text-2);
margin-bottom: -1rem;
`;
Styled.Description = styled.div`
color: var(--color-text-0);
--link-color: var(--color-text-1);
a {
display: inline;
::before {
content: ' ';
}
}
`;
Styled.PanelRow = styled.div`
${layoutMixins.gridEqualColumns}
gap: 1.5rem;
@@ -112,3 +171,12 @@ Styled.PanelRow = styled.div`
Styled.PanelRowIncentivesAndBalance = styled(Styled.PanelRow)`
grid-template-columns: 2fr 1fr;
`;
Styled.IconButton = styled(IconButton)`
color: var(--color-text-0);
--color-border: var(--color-layer-6);
`;
Styled.Arrow = styled.div`
padding: 1rem;
`;
-73
View File
@@ -1,73 +0,0 @@
import styled, { AnyStyledComponent } from 'styled-components';
import { useDispatch } from 'react-redux';
import { ButtonAction, ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { DialogTypes } from '@/constants/dialogs';
import { useStringGetter, useURLConfigs } from '@/hooks';
import { Panel } from '@/components/Panel';
import { IconName } from '@/components/Icon';
import { IconButton } from '@/components/IconButton';
import { Link } from '@/components/Link';
import { openDialog } from '@/state/dialogs';
export const StakingPanel = () => {
const stringGetter = useStringGetter();
const dispatch = useDispatch();
const { stakingLearnMore } = useURLConfigs();
return (
<Panel
slotHeaderContent={<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>}
slotRight={
<Styled.Arrow>
<Styled.IconButton
action={ButtonAction.Base}
iconName={IconName.Arrow}
size={ButtonSize.Small}
/>
</Styled.Arrow>
}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
<Link href={stakingLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
</Panel>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Description = styled.div`
color: var(--color-text-0);
--link-color: var(--color-text-1);
a {
display: inline;
::before {
content: ' ';
}
}
`;
Styled.IconButton = styled(IconButton)`
color: var(--color-text-0);
--color-border: var(--color-layer-6);
`;
Styled.Arrow = styled.div`
padding-right: 1.5rem;
`;
Styled.Title = styled.h3`
font: var(--font-medium-book);
color: var(--color-text-2);
margin-bottom: -1rem;
`;
+8 -1
View File
@@ -1,8 +1,10 @@
import { createSelector } from 'reselect';
import { SubaccountPosition } from '@/constants/abacus';
import { OnboardingState, OnboardingSteps } from '@/constants/account';
import {
getExistingOpenPositions,
getOnboardingGuards,
getOnboardingState,
getSubaccountId,
@@ -58,8 +60,13 @@ export const calculateIsAccountViewOnly = createSelector(
);
/**
* @description calculate whether the subaccount has uncommitted positions
* @description calculate whether the subaccount has open positions
*/
export const calculateHasOpenPositions = createSelector(
[getExistingOpenPositions],
(openPositions?: SubaccountPosition[]) => (openPositions?.length || 0) > 0
);
export const calculateHasUncommittedOrders = createSelector(
[getUncommittedOrderClientIds],
(uncommittedOrderClientIds: number[]) => uncommittedOrderClientIds.length > 0
+5 -11
View File
@@ -2,7 +2,6 @@ import { OrderSide } from '@dydxprotocol/v4-client-js';
import { createSelector } from 'reselect';
import {
type AbacusOrderStatuses,
type SubaccountOrder,
type SubaccountFill,
type SubaccountFundingPayment,
@@ -44,6 +43,7 @@ export const getSubaccountBuyingPower = (state: RootState) => state.account.suba
export const getSubaccountEquity = (state: RootState) => state.account.subaccount?.equity;
export const getSubaccountHistoricalPnl = (state: RootState) => state.account?.historicalPnl;
/**
* @param state
* @returns list of a subaccount's open positions. Each item in the list is an open position in a different market.
@@ -258,14 +258,6 @@ export const getCurrentMarketFundingPayments = createSelector(
!currentMarketId ? [] : marketFundingPayments[currentMarketId]
);
/**
* @param state
* @returns boolean on whether an order status is considered open
*/
const isOpenOrderStatus = (status: AbacusOrderStatuses) => {
return status !== AbacusOrderStatus.filled && status !== AbacusOrderStatus.cancelled;
};
/**
* @param state
* @returns Total numbers of the subaccount's open positions, open orders and fills
@@ -274,7 +266,8 @@ export const getTradeInfoNumbers = createSelector(
[getExistingOpenPositions, getSubaccountOrders, getSubaccountFills, getSubaccountFundingPayments],
(positions, orders, fills, fundingPayments) => ({
numTotalPositions: positions?.length,
numTotalOpenOrders: orders?.filter((order) => isOpenOrderStatus(order.status)).length,
numTotalOpenOrders: orders?.filter((order) => order.status !== AbacusOrderStatus.cancelled)
.length,
numTotalFills: fills?.length,
numTotalFundingPayments: fundingPayments?.length,
})
@@ -288,7 +281,8 @@ export const getCurrentMarketTradeInfoNumbers = createSelector(
[getCurrentMarketOrders, getCurrentMarketFills, getCurrentMarketFundingPayments],
(marketOrders, marketFills, marketFundingPayments) => {
return {
numOpenOrders: marketOrders?.filter((order) => isOpenOrderStatus(order.status)).length,
numOpenOrders: marketOrders?.filter((order) => order.status !== AbacusOrderStatus.cancelled)
.length,
numFills: marketFills?.length,
numFundingPayments: marketFundingPayments?.length,
};
+1
View File
@@ -29,6 +29,7 @@ export const MarketDetails: React.FC = () => {
if (!configs) return null;
const {
basePositionNotional,
tickSize,
stepSize,
initialMarginFraction,
@@ -72,7 +72,6 @@ export const GenerateKeys = ({
if (message) {
log('GenerateKeys/switchNetwork', error, { walletErrorType });
setError(message);
throw error;
}
}
};
@@ -17,7 +17,6 @@ import type { EvmAddress } from '@/constants/wallets';
import { useAccounts, useDebounce, useStringGetter, useSelectedNetwork } from '@/hooks';
import { useAccountBalance, CHAIN_DEFAULT_TOKEN_ADDRESS } from '@/hooks/useAccountBalance';
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
import { useWalletConnection } from '@/hooks/useWalletConnection';
import { layoutMixins } from '@/styles/layoutMixins';
import { formMixins } from '@/styles/formMixins';
@@ -121,7 +120,11 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
});
return () => {
abacusStateManager.resetInputState();
abacusStateManager.clearTransferInputValues();
abacusStateManager.setTransferValue({
field: TransferInputField.type,
value: null,
});
};
}, []);
@@ -232,10 +235,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
throw new Error('Missing request payload');
}
if (isCctp && !abacusStateManager.chainTransactions.isNobleClientConnected) {
throw new Error('Noble RPC endpoint unaccessible');
}
setIsLoading(true);
await validateTokenApproval();
@@ -365,8 +364,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
return <LoadingSpace id="DepositForm" />;
}
const [requireUserActionInWallet, setRequireUserActionInWallet] = useState(false);
return (
<Styled.Form onSubmit={onSubmit}>
<ChainSelectMenu selectedChain={chainIdStr || undefined} onSelectChain={onSelectChain} />
@@ -385,11 +382,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
/>
</Styled.WithDetailsReceipt>
{errorMessage && <AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>}
{requireUserActionInWallet && (
<AlertMessage type={AlertType.Warning}>
{stringGetter({ key: STRING_KEYS.CHECK_WALLET_FOR_REQUEST })}
</AlertMessage>
)}
<Styled.Footer>
<DepositButtonAndReceipt
isDisabled={isDisabled}
@@ -398,8 +391,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
setSlippage={onSetSlippage}
slippage={slippage}
sourceToken={sourceToken || undefined}
setRequireUserActionInWallet={setRequireUserActionInWallet}
setError={setError}
/>
</Styled.Footer>
</Styled.Form>
@@ -1,7 +1,8 @@
import { type Dispatch, type SetStateAction, useState, type ReactNode, useEffect } from 'react';
import { type Dispatch, type ReactNode, type SetStateAction, useState, useMemo } from 'react';
import styled, { type AnyStyledComponent } from 'styled-components';
import { shallowEqual, useSelector } from 'react-redux';
import type { RouteData } from '@0xsquid/sdk';
import { formatUnits } from 'viem';
import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons';
@@ -11,7 +12,6 @@ import { NumberSign, TOKEN_DECIMALS } from '@/constants/numbers';
import { useStringGetter, useTokenConfigs } from '@/hooks';
import { useMatchingEvmNetwork } from '@/hooks/useMatchingEvmNetwork';
import { useWalletConnection } from '@/hooks/useWalletConnection';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -39,8 +39,7 @@ type ElementProps = {
isLoading?: boolean;
chainId?: string | number;
setError?: Dispatch<SetStateAction<Error | null>>;
setRequireUserActionInWallet: (val: boolean) => void;
setError?: Dispatch<SetStateAction<Error | undefined>>;
slippage: number;
slotError?: ReactNode;
setSlippage: (slippage: number) => void;
@@ -58,7 +57,6 @@ export const DepositButtonAndReceipt = ({
isDisabled,
isLoading,
slotError,
setRequireUserActionInWallet,
}: ElementProps) => {
const [showFeeBreakdown, setShowFeeBreakdown] = useState(false);
const [isEditingSlippage, setIsEditingSlipapge] = useState(false);
@@ -66,24 +64,6 @@ export const DepositButtonAndReceipt = ({
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
const { connectWallet, isConnectedWagmi } = useWalletConnection();
const connectWagmi = async () => {
try {
setRequireUserActionInWallet(false);
await connectWallet();
setRequireUserActionInWallet(false);
} catch (e) {
setRequireUserActionInWallet(true);
}
};
useEffect(() => {
if (!isConnectedWagmi && canAccountTrade) {
connectWagmi();
}
}, [isConnectedWagmi, canAccountTrade]);
const {
matchNetwork: switchNetwork,
isSwitchingNetwork,
@@ -100,7 +80,7 @@ export const DepositButtonAndReceipt = ({
useSelector(getSubaccountBuyingPower, shallowEqual) || {};
const { isCctp, summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {};
const { usdcLabel } = useTokenConfigs();
const { usdcDecimals, usdcLabel } = useTokenConfigs();
const feeSubitems: DetailsItem[] = [];
@@ -136,9 +116,7 @@ export const DepositButtonAndReceipt = ({
{stringGetter({ key: STRING_KEYS.EXPECTED_DEPOSIT_AMOUNT })} <Tag>{usdcLabel}</Tag>
</span>
),
value: (
<Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmount} />
),
value: <Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmount} />,
subitems: [
{
key: 'minimum-deposit-amount',
@@ -148,11 +126,7 @@ export const DepositButtonAndReceipt = ({
</span>
),
value: (
<Output
type={OutputType.Fiat}
fractionDigits={TOKEN_DECIMALS}
value={summary?.toAmountMin}
/>
<Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmountMin} />
),
tooltip: 'minimum-deposit-amount',
},
@@ -279,8 +253,6 @@ export const DepositButtonAndReceipt = ({
>
{!canAccountTrade ? (
<OnboardingTriggerButton size={ButtonSize.Base} />
) : !isConnectedWagmi ? (
<Button action={ButtonAction.Primary} onClick={connectWallet} state={{ isLoading: true }} />
) : !isMatchingNetwork ? (
<Button
action={ButtonAction.Primary}
@@ -101,7 +101,11 @@ export const WithdrawForm = () => {
});
return () => {
abacusStateManager.resetInputState();
abacusStateManager.clearTransferInputValues();
abacusStateManager.setTransferValue({
field: TransferInputField.type,
value: null,
});
};
}, []);
@@ -144,10 +148,6 @@ export const WithdrawForm = () => {
throw new Error('Invalid request payload');
}
if (isCctp && !abacusStateManager.chainTransactions.isNobleClientConnected) {
throw new Error('Noble RPC endpoint unaccessible');
}
setIsLoading(true);
setError(undefined);
@@ -55,7 +55,7 @@ export const WithdrawButtonAndReceipt = ({
const stringGetter = useStringGetter();
const { leverage } = useSelector(getSubaccount, shallowEqual) || {};
const { summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {};
const { isCctp, summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {};
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
const { usdcLabel } = useTokenConfigs();
@@ -85,6 +85,26 @@ export const WithdrawButtonAndReceipt = ({
const totalFees = (summary?.bridgeFee || 0) + (summary?.gasFee || 0);
const { toAmount, toAmountMin } = useMemo(() => {
if (isCctp) {
return {
toAmount: summary?.toAmount,
toAmountMin: summary?.toAmountMin,
};
} else {
return {
toAmount:
summary?.toAmount &&
withdrawToken?.decimals &&
formatUnits(BigInt(summary.toAmount), withdrawToken.decimals),
toAmountMin:
summary?.toAmountMin &&
withdrawToken?.decimals &&
formatUnits(BigInt(summary.toAmountMin), withdrawToken.decimals),
};
}
}, [isCctp, summary, withdrawToken]);
const submitButtonReceipt = [
{
key: 'total-fees',
@@ -133,7 +153,7 @@ export const WithdrawButtonAndReceipt = ({
{withdrawToken && <Tag>{withdrawToken?.symbol}</Tag>}
</span>
),
value: <Output type={OutputType.Asset} value={summary?.toAmount} fractionDigits={TOKEN_DECIMALS} />,
value: <Output type={OutputType.Asset} value={toAmount} fractionDigits={TOKEN_DECIMALS} />,
subitems: [
{
key: 'minimum-amount-received',
@@ -144,7 +164,7 @@ export const WithdrawButtonAndReceipt = ({
</span>
),
value: (
<Output type={OutputType.Asset} value={summary?.toAmountMin} fractionDigits={TOKEN_DECIMALS} />
<Output type={OutputType.Asset} value={toAmountMin} fractionDigits={TOKEN_DECIMALS} />
),
tooltip: 'minimum-amount-received',
},
+5 -1
View File
@@ -118,7 +118,11 @@ export const TransferForm = ({
onChangeAsset(selectedAsset);
return () => {
abacusStateManager.resetInputState();
abacusStateManager.clearTransferInputValues();
abacusStateManager.setTransferValue({
field: TransferInputField.type,
value: null,
});
};
}, []);
+4 -5
View File
@@ -10,9 +10,6 @@ import { STRING_KEYS, StringGetterFunction, TOOLTIP_STRING_KEYS } from '@/consta
import { isMainnet } from '@/constants/networks';
import { DydxChainAsset, wallets } from '@/constants/wallets';
import { layoutMixins } from '@/styles/layoutMixins';
import { headerMixins } from '@/styles/headerMixins';
import {
useAccounts,
useBreakpoints,
@@ -38,8 +35,10 @@ import { getOnboardingState, getSubaccount } from '@/state/accountSelectors';
import { isTruthy } from '@/lib/isTruthy';
import { truncateAddress } from '@/lib/wallet';
import { layoutMixins } from '@/styles/layoutMixins';
import { headerMixins } from '@/styles/headerMixins';
import { MustBigNumber } from '@/lib/numbers';
import { testFlags } from '@/lib/testFlags';
export const AccountMenu = () => {
const stringGetter = useStringGetter();
@@ -179,7 +178,7 @@ export const AccountMenu = () => {
},
...(onboardingState === OnboardingState.AccountConnected && hdKey
? [
(!isMainnet || testFlags.showMobileSignInOption) && {
!isMainnet && {
value: 'MobileQrSignIn',
icon: <Icon iconName={IconName.Qr} />,
label: stringGetter({ key: STRING_KEYS.TITLE_SIGN_INTO_MOBILE }),
@@ -1,78 +0,0 @@
import styled, { type AnyStyledComponent } from 'styled-components';
import { STRING_KEYS } from '@/constants/localization';
import { useStringGetter } from '@/hooks';
import { Details } from '@/components/Details';
import { Notification, NotificationProps } from '@/components/Notification';
import { Output, OutputType } from '@/components/Output';
import { Icon, IconName } from '@/components/Icon';
type ElementProps = {
data: {
BLOCK_REWARD_AMOUNT: string;
BLOCK_REWARD_HEIGHT: string;
BLOCK_REWARD_TIME_MILLISECONDS: string;
TOKEN_NAME: string;
};
};
export type BlockRewardNotificationProps = NotificationProps & ElementProps;
export const BlockRewardNotification = ({
isToast,
data,
notification,
}: BlockRewardNotificationProps) => {
const stringGetter = useStringGetter();
const { BLOCK_REWARD_AMOUNT, TOKEN_NAME } = data;
return (
<Styled.Notification
isToast={isToast}
notification={notification}
slotIcon={<Icon iconName={IconName.RewardStar} />}
slotTitle={stringGetter({ key: STRING_KEYS.TRADING_REWARD_RECEIVED })}
slotCustomContent={
<Styled.Details
items={[
{
key: 'block_reward',
label: stringGetter({ key: STRING_KEYS.BLOCK_REWARD }),
value: (
<Styled.Output
type={OutputType.Asset}
value={BLOCK_REWARD_AMOUNT}
tag={TOKEN_NAME}
/>
),
},
]}
/>
}
/>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Details = styled(Details)`
--details-item-height: 1.5rem;
dd {
color: var(--color-text-2);
}
`;
Styled.Notification = styled(Notification)`
background-image: url('/dots-background-2.svg');
background-size: cover;
`;
Styled.Output = styled(Output)`
&:before {
content: '+';
color: var(--color-positive);
margin-right: 0.5ch;
}
`;
+2
View File
@@ -36,6 +36,8 @@ import { openDialog } from '@/state/dialogs';
import { MustBigNumber } from '@/lib/numbers';
import { getHydratedTradingData } from '@/lib/orders';
import { tableMixins } from '@/styles/tableMixins';
import { breakpoints } from '@/styles';
const MOBILE_FILLS_PER_PAGE = 50;