Merge branch 'master' into task/token-flow-tests
This commit is contained in:
commit
8d2d1f8a6a
@ -5,7 +5,10 @@ describe('market list', () => {
|
||||
});
|
||||
|
||||
it('selects menus', () => {
|
||||
cy.get('.MuiDrawer-root [aria-current]').should('have.text', 'Markets');
|
||||
cy.get('[aria-label="Sidebar Navigation Menu"] [aria-current]').should(
|
||||
'have.text',
|
||||
'Markets'
|
||||
);
|
||||
cy.getByTestId('state-trigger').should('have.text', 'Active');
|
||||
cy.get('[aria-label="Future"]').click();
|
||||
cy.get('[data-testid="market-assets-menu"] a.active').should(
|
||||
|
@ -40,13 +40,7 @@ function App() {
|
||||
<VegaWalletProvider>
|
||||
<AppLoader>
|
||||
<div className="max-h-full min-h-full dark:bg-black dark:text-white-60 bg-white text-black-60 grid grid-rows-[min-content,1fr]">
|
||||
<div className="flex items-stretch border-b-[7px] border-vega-yellow">
|
||||
<DrawerToggle
|
||||
onToggle={onToggle}
|
||||
variant={DRAWER_TOGGLE_VARIANTS.OPEN}
|
||||
className="xs:py-32 xs:px-16"
|
||||
/>
|
||||
|
||||
<div className="flex items-stretch p-16 bg-black text-white-60">
|
||||
<div className="flex items-center gap-4 ml-auto mr-8">
|
||||
<VegaWalletConnectButton
|
||||
setConnectDialog={(open) =>
|
||||
@ -56,8 +50,17 @@ function App() {
|
||||
setVegaWallet((x) => ({ ...x, manage: open }))
|
||||
}
|
||||
/>
|
||||
<ThemeSwitcher onToggle={toggleTheme} className="-my-4" />
|
||||
<ThemeSwitcher
|
||||
onToggle={toggleTheme}
|
||||
className="-my-4"
|
||||
sunClassName="text-white"
|
||||
/>
|
||||
</div>
|
||||
<DrawerToggle
|
||||
onToggle={onToggle}
|
||||
variant={DRAWER_TOGGLE_VARIANTS.OPEN}
|
||||
className="xs:py-32 xs:px-16 xs:text-white xs:hover:text-blue"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Main isMenuOpen={menuOpen} onToggle={onToggle} />
|
||||
|
@ -1,14 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
interface Props {
|
||||
children: ReactElement | ReactElement[];
|
||||
}
|
||||
|
||||
export const DrawerContainer = ({ children }: Props) => (
|
||||
<div className="w-full md:w-3/4 grow-1">{children}</div>
|
||||
);
|
||||
|
||||
export const DrawerWrapper = ({ children }: Props) => (
|
||||
<div className="flex dark:bg-black">{children}</div>
|
||||
);
|
@ -0,0 +1,21 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
interface Props {
|
||||
children: ReactElement | ReactElement[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const DrawerContent = ({ children, className = '' }: Props) => {
|
||||
const classes = classNames(
|
||||
'w-full sm:w-full grow-1 p-20 overflow-hidden',
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<main aria-label="Page Content" className={classes}>
|
||||
{children}
|
||||
</main>
|
||||
);
|
||||
};
|
@ -1,38 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ButtonProps } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
type MenuItem = {
|
||||
label: string;
|
||||
component: ReactElement | ReactElement[];
|
||||
onClick(): void;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* Menu items passed as an array
|
||||
*/
|
||||
menuItems: MenuItem[];
|
||||
}
|
||||
|
||||
export const NavigationDrawerMenu = ({ menuItems }: Props) => {
|
||||
return (
|
||||
<ul>
|
||||
{menuItems.map((item, index) => {
|
||||
const btnProps = {
|
||||
variant: item.active ? 'accent' : 'primary',
|
||||
className: 'w-full mb-8',
|
||||
onClick: item.onClick,
|
||||
} as ButtonProps;
|
||||
|
||||
return (
|
||||
<li key={index}>
|
||||
<Button {...btnProps}>{item.label}</Button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
};
|
@ -19,12 +19,10 @@ interface Props {
|
||||
export const DrawerToggle = ({
|
||||
onToggle,
|
||||
variant = DRAWER_TOGGLE_VARIANTS.CLOSE,
|
||||
className,
|
||||
className = '',
|
||||
}: Props) => {
|
||||
const [iconName, setIconName] = useState(IconNames.MENU);
|
||||
const classes = classNames('md:hidden', {
|
||||
[className as string]: className,
|
||||
});
|
||||
const classes = classNames('md:hidden', className);
|
||||
|
||||
useEffect(() => {
|
||||
if (variant === DRAWER_TOGGLE_VARIANTS.OPEN) {
|
||||
@ -34,8 +32,17 @@ export const DrawerToggle = ({
|
||||
}
|
||||
}, [variant]);
|
||||
|
||||
const ariaLabel = `${
|
||||
variant === DRAWER_TOGGLE_VARIANTS.OPEN ? 'Open' : 'Close'
|
||||
} Sidebar Navigation Menu`;
|
||||
|
||||
return (
|
||||
<Button variant="inline-link" className={classes} onClick={onToggle}>
|
||||
<Button
|
||||
aria-label={ariaLabel}
|
||||
variant="inline-link"
|
||||
className={classes}
|
||||
onClick={onToggle}
|
||||
>
|
||||
<Icon name={iconName as IconName} />
|
||||
</Button>
|
||||
);
|
||||
|
@ -0,0 +1,13 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
interface Props {
|
||||
children: ReactElement | ReactElement[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const DrawerWrapper = ({ children, className = '' }: Props) => {
|
||||
const classes = classNames('flex dark:bg-black md:flex-row', className);
|
||||
return <div className={classes}>{children}</div>;
|
||||
};
|
@ -1,66 +1,60 @@
|
||||
import * as React from 'react';
|
||||
import { themelite as theme } from '@vegaprotocol/tailwindcss-config';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import Drawer from '@mui/material/Drawer';
|
||||
|
||||
interface Props {
|
||||
children?: ReactElement | ReactElement[];
|
||||
isMenuOpen?: boolean;
|
||||
onToggle(): void;
|
||||
rtl?: boolean;
|
||||
outerClasses?: string;
|
||||
innerClasses?: string;
|
||||
}
|
||||
|
||||
export const NavigationDrawer = ({
|
||||
isMenuOpen = false,
|
||||
onToggle,
|
||||
children,
|
||||
rtl,
|
||||
outerClasses = '',
|
||||
innerClasses = '',
|
||||
}: Props) => {
|
||||
const [windowSize, setWindowSize] = React.useState({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
const width = 'w-full md:w-auto md:min-w-[15%] shrink-0';
|
||||
const position = 'absolute inset-0 h-full z-10 md:static';
|
||||
const background = 'bg-black/50 dark:bg-white/50';
|
||||
const flex = 'flex justify-end overflow-hidden';
|
||||
const joinedClasses = [flex, width, position, background].join(' ');
|
||||
|
||||
const outerStyles = classNames(joinedClasses, {
|
||||
visible: isMenuOpen,
|
||||
'invisible md:visible': !isMenuOpen,
|
||||
'flex-row-reverse': !rtl,
|
||||
[outerClasses]: outerClasses,
|
||||
});
|
||||
const mobileScreenWidth = parseInt(theme.screens.md);
|
||||
const isMobile = windowSize.width <= mobileScreenWidth;
|
||||
const timeout = React.useRef(0);
|
||||
|
||||
const handleResize = () => {
|
||||
if (timeout.current) {
|
||||
window.cancelAnimationFrame(timeout.current);
|
||||
}
|
||||
const translateClose = rtl ? 'translate-x-full' : '-translate-x-full';
|
||||
|
||||
// Setup the new requestAnimationFrame()
|
||||
timeout.current = window.requestAnimationFrame(function () {
|
||||
setWindowSize({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
window.cancelAnimationFrame(timeout.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const drawerRootClasses = {
|
||||
root: 'w-3/4 md:w-1/4 shrink-0',
|
||||
paper: 'p-16 w-3/4 md:w-1/4 box-border',
|
||||
};
|
||||
const innerStyles = classNames('w-3/4 md:w-full bg-white dark:bg-black', {
|
||||
'translate-x-0 transition-transform md:transform-none': isMenuOpen,
|
||||
[`${translateClose} md:transform-none`]: !isMenuOpen,
|
||||
[innerClasses]: innerClasses,
|
||||
});
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
classes={drawerRootClasses}
|
||||
variant={isMobile ? 'temporary' : 'permanent'}
|
||||
open={isMobile ? isMenuOpen : true}
|
||||
onClose={onToggle}
|
||||
ModalProps={{
|
||||
keepMounted: true, // Better open performance on mobile.
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Drawer>
|
||||
<aside aria-label="Sidebar Navigation Menu" className={outerStyles}>
|
||||
<div
|
||||
role="presentation"
|
||||
aria-label="Content Overlay - Click To Close Sidebar Navigation"
|
||||
className="md:hidden grow h-full"
|
||||
onClick={onToggle}
|
||||
/>
|
||||
<div
|
||||
role="group"
|
||||
aria-label="Sidebar Navigation Grouped Content"
|
||||
className={innerStyles}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from './drawer';
|
||||
export * from './drawer-menu';
|
||||
export * from './drawer-toggle';
|
||||
export * from './drawer-container';
|
||||
export * from './drawer-content';
|
||||
export * from './drawer-wrapper';
|
||||
|
51
apps/simple-trading-app/src/app/components/icons/icon.tsx
Normal file
51
apps/simple-trading-app/src/app/components/icons/icon.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import type { ReactElement } from 'react';
|
||||
import { LiquidityIconPath } from './liquidity-icon';
|
||||
import { MarketIconPath } from './market-icon';
|
||||
import { TradeIconPath } from './trade-icon';
|
||||
import { PortfolioIconPath } from './portfolio-icon';
|
||||
|
||||
interface IconProps {
|
||||
name: string;
|
||||
className: string;
|
||||
}
|
||||
|
||||
interface IconSVGWrapperProps {
|
||||
className: string;
|
||||
children: ReactElement | ReactElement[] | null;
|
||||
}
|
||||
|
||||
const getIconPath = (name: string): ReactElement | null => {
|
||||
switch (name) {
|
||||
case 'liquidity':
|
||||
return <LiquidityIconPath />;
|
||||
case 'market':
|
||||
return <MarketIconPath />;
|
||||
case 'trade':
|
||||
return <TradeIconPath />;
|
||||
case 'portfolio':
|
||||
return <PortfolioIconPath />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const IconSVGWrapper = ({ className, children }: IconSVGWrapperProps) => {
|
||||
return (
|
||||
<svg
|
||||
role="presentation"
|
||||
className={className}
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
{children}
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const Icon = ({ name, className }: IconProps) => {
|
||||
return (
|
||||
<IconSVGWrapper className={className}>{getIconPath(name)}</IconSVGWrapper>
|
||||
);
|
||||
};
|
@ -0,0 +1 @@
|
||||
export * from './icon';
|
@ -0,0 +1,15 @@
|
||||
export const LiquidityIconPath = () => (
|
||||
<>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12.5268 1.46612L12 1.99999L11.4732 1.46612L12 0.946381L12.5268 1.46612ZM12 3.07542C11.8274 3.25709 11.6185 3.48044 11.3826 3.73943C10.6899 4.49987 9.76793 5.56335 8.84782 6.77789C7.92587 7.99485 7.01715 9.34862 6.34179 10.6903C5.66046 12.0439 5.25 13.3205 5.25 14.4C5.25 19.0485 8.47431 22.15 12 22.15C15.5257 22.15 18.75 19.0485 18.75 14.4C18.75 13.3205 18.3395 12.0439 17.6582 10.6903C16.9829 9.34862 16.0741 7.99485 15.1522 6.77789C14.2321 5.56335 13.3101 4.49987 12.6174 3.73943C12.3815 3.48044 12.1726 3.25709 12 3.07542ZM11.4732 1.46612C11.4734 1.46597 11.4732 1.46612 12 1.99999C12.5268 1.46612 12.5266 1.46597 12.5268 1.46612L12.5336 1.47291L12.5512 1.49036C12.5663 1.5055 12.5884 1.52759 12.6169 1.55634C12.6739 1.61384 12.7566 1.698 12.8615 1.80641C13.071 2.02319 13.3692 2.33722 13.7263 2.72931C14.4399 3.51261 15.3929 4.61164 16.3478 5.8721C17.3009 7.13013 18.2671 8.56386 18.998 10.0159C19.723 11.4561 20.25 12.9795 20.25 14.4C20.25 19.7514 16.4743 23.65 12 23.65C7.52569 23.65 3.75 19.7514 3.75 14.4C3.75 12.9795 4.27704 11.4561 5.00196 10.0159C5.73285 8.56386 6.69913 7.13013 7.65218 5.8721C8.60707 4.61164 9.56014 3.51261 10.2737 2.72931C10.6308 2.33722 10.929 2.02319 11.1385 1.80641C11.2434 1.698 11.3261 1.61384 11.3831 1.55634C11.4116 1.52759 11.4337 1.5055 11.4488 1.49036L11.4664 1.47291L11.4712 1.46817L11.4732 1.46612Z"
|
||||
/>
|
||||
<rect x="11.5" y="17.4" width="1" height="1" />
|
||||
<rect x="12.5" y="16.4" width="1" height="1" />
|
||||
<rect x="10.5" y="16.4" width="1" height="1" />
|
||||
<rect x="14.5" y="15.4" width="1" height="1" />
|
||||
<rect x="13.5" y="11.4" width="1" height="4" />
|
||||
<rect x="9.5" y="11.4" width="1" height="5" />
|
||||
</>
|
||||
);
|
@ -0,0 +1,17 @@
|
||||
export const MarketIconPath = () => (
|
||||
<>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M3.5 2H2V20.5V22H3.5H22V20.5H3.5V2Z"
|
||||
/>
|
||||
<rect x="5" y="15" width="2" height="2" />
|
||||
<rect x="7" y="13" width="2" height="2" />
|
||||
<rect x="9" y="11" width="2" height="2" />
|
||||
<rect x="11" y="9" width="2" height="2" />
|
||||
<rect x="13" y="11" width="2" height="2" />
|
||||
<rect x="15" y="9" width="2" height="2" />
|
||||
<rect x="17" y="7" width="2" height="2" />
|
||||
<rect x="19" y="5" width="2" height="2" />
|
||||
</>
|
||||
);
|
@ -0,0 +1,17 @@
|
||||
export const PortfolioIconPath = () => (
|
||||
<>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.5 3.5H15.5V6H8.5V3.5ZM7 6V3.5C7 2.67157 7.67157 2 8.5 2H15.5C16.3284 2 17 2.67157 17 3.5V6H20.5C21.3284 6 22 6.67157 22 7.5V20.5C22 21.3284 21.3284 22 20.5 22H3.5C2.67157 22 2 21.3284 2 20.5V7.5C2 6.67157 2.67157 6 3.5 6H7ZM15.5 7.5H8.5H3.5L3.5 20.5H20.5V7.5H15.5Z"
|
||||
/>
|
||||
<rect x="4" y="8" width="2" height="2" />
|
||||
<rect x="6" y="10" width="2" height="2" />
|
||||
<rect x="18" y="8" width="2" height="2" />
|
||||
<rect x="16" y="10" width="2" height="2" />
|
||||
<rect x="14" y="12" width="2" height="2" />
|
||||
<rect x="8" y="12" width="2" height="2" />
|
||||
<rect x="10" y="14" width="2" height="2" />
|
||||
<rect x="12" y="14" width="2" height="2" />
|
||||
</>
|
||||
);
|
@ -0,0 +1,14 @@
|
||||
export const TradeIconPath = () => (
|
||||
<>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M19.3254 7.28784L14.8547 2.93099L15.7621 1.99999L21.4056 7.49983L21.8833 7.96534L21.4056 8.43085L15.7621 13.9307L14.8547 12.9997L19.3819 8.58784L1.99999 8.58784L1.99999 7.28784L19.3254 7.28784Z"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M4.55785 16.6429L9.02855 20.9997L8.12124 21.9307L2.47767 16.4309L2 15.9654L2.47767 15.4999L8.12124 10L9.02855 10.931L4.50141 15.3429L21.8833 15.3429V16.6429L4.55785 16.6429Z"
|
||||
/>
|
||||
</>
|
||||
);
|
@ -1,62 +1,41 @@
|
||||
import React from 'react';
|
||||
import { useRoutes, NavLink } from 'react-router-dom';
|
||||
import { useRoutes } from 'react-router-dom';
|
||||
import {
|
||||
NavigationDrawer,
|
||||
DrawerWrapper,
|
||||
DrawerContainer,
|
||||
DrawerContent,
|
||||
DrawerToggle,
|
||||
DRAWER_TOGGLE_VARIANTS,
|
||||
} from '../drawer';
|
||||
import { Nav, TabBar } from '../nav';
|
||||
import { routerConfig } from '../../routes/router-config';
|
||||
|
||||
export interface RouteChildProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const AppRouter = () => {
|
||||
const routes = useRoutes(routerConfig);
|
||||
|
||||
return <main className="p-20 overflow-hidden">{routes}</main>;
|
||||
};
|
||||
|
||||
export const Menu = () => (
|
||||
<nav>
|
||||
{routerConfig.map((r) => (
|
||||
<NavLink
|
||||
key={r.name}
|
||||
to={r.path}
|
||||
className={({ isActive }) =>
|
||||
`text-h5 block mb-8 px-8 hover:bg-vega-yellow hover:text-black ${
|
||||
isActive && 'bg-vega-yellow text-black'
|
||||
}`
|
||||
}
|
||||
>
|
||||
{r.text}
|
||||
</NavLink>
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
export const AppRouter = () => useRoutes(routerConfig);
|
||||
|
||||
interface Props {
|
||||
onToggle(): void;
|
||||
|
||||
isMenuOpen: boolean;
|
||||
}
|
||||
|
||||
export const Main = ({ onToggle, isMenuOpen }: Props) => {
|
||||
return (
|
||||
<DrawerWrapper>
|
||||
<NavigationDrawer onToggle={onToggle} isMenuOpen={isMenuOpen}>
|
||||
<NavigationDrawer rtl onToggle={onToggle} isMenuOpen={isMenuOpen}>
|
||||
<DrawerToggle
|
||||
onToggle={onToggle}
|
||||
variant={DRAWER_TOGGLE_VARIANTS.CLOSE}
|
||||
className="self-end p-16"
|
||||
className="p-16"
|
||||
/>
|
||||
<Menu />
|
||||
<Nav className="hidden md:block my-20 h-full" />
|
||||
</NavigationDrawer>
|
||||
<DrawerContainer>
|
||||
<DrawerContent>
|
||||
<AppRouter />
|
||||
</DrawerContainer>
|
||||
<TabBar className="md:hidden" />
|
||||
</DrawerContent>
|
||||
</DrawerWrapper>
|
||||
);
|
||||
};
|
||||
|
2
apps/simple-trading-app/src/app/components/nav/index.tsx
Normal file
2
apps/simple-trading-app/src/app/components/nav/index.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './nav';
|
||||
export * from './tab-bar';
|
16
apps/simple-trading-app/src/app/components/nav/nav-item.tsx
Normal file
16
apps/simple-trading-app/src/app/components/nav/nav-item.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Icon } from '../icons';
|
||||
|
||||
interface NavItemProps {
|
||||
iconName: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export const NavItem = ({ iconName, label }: NavItemProps) => {
|
||||
return (
|
||||
<div className="flex flex-col md:flex-row items-center justify-start cursor-pointer relative">
|
||||
<Icon name={iconName} className="mr-8" />
|
||||
<span>{label}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
30
apps/simple-trading-app/src/app/components/nav/nav.tsx
Normal file
30
apps/simple-trading-app/src/app/components/nav/nav.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { routerConfig } from '../../routes';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { NavItem } from './nav-item';
|
||||
import React from 'react';
|
||||
|
||||
interface NavProps {
|
||||
className?: string;
|
||||
tabs?: boolean;
|
||||
}
|
||||
|
||||
export const Nav = ({ className, tabs = false }: NavProps) => {
|
||||
return (
|
||||
<nav role={tabs ? 'tablist' : 'menu'} className={className}>
|
||||
{routerConfig.map((r) => (
|
||||
<NavLink
|
||||
role={tabs ? 'tab' : 'menuitem'}
|
||||
key={r.name}
|
||||
to={r.path}
|
||||
className={({ isActive }) =>
|
||||
`text-h5 block md:mb-40 px-40 md:text-black md:dark:text-white ${
|
||||
isActive && 'text-white md:text-blue md:dark:text-blue'
|
||||
}`
|
||||
}
|
||||
>
|
||||
<NavItem iconName={r.icon} label={r.text} />
|
||||
</NavLink>
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
};
|
15
apps/simple-trading-app/src/app/components/nav/tab-bar.tsx
Normal file
15
apps/simple-trading-app/src/app/components/nav/tab-bar.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { Nav } from './nav';
|
||||
import React from 'react';
|
||||
|
||||
interface TabBarProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const TabBar = ({ className }: TabBarProps) => (
|
||||
<div role="group" aria-label="Tab Bar Navigation Menu" className={className}>
|
||||
<div role="presentation" className="py-[42px]" />
|
||||
<div className="md:hidden fixed bottom-0 left-0 right-0 bg-black py-16">
|
||||
<Nav tabs className="flex justify-evenly items-center" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
@ -1,3 +1,4 @@
|
||||
import produce from 'immer';
|
||||
import { gql } from '@apollo/client';
|
||||
import { makeDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
@ -87,15 +88,16 @@ export const FILTERS_QUERY = gql`
|
||||
`;
|
||||
|
||||
const update = (
|
||||
draft: SimpleMarkets_markets[],
|
||||
data: SimpleMarkets_markets[],
|
||||
delta: SimpleMarketDataSub_marketData
|
||||
) => {
|
||||
const index = draft.findIndex((m) => m.id === delta.market.id);
|
||||
if (index !== -1) {
|
||||
draft[index].data = delta;
|
||||
}
|
||||
// @TODO - else push new market to draft
|
||||
};
|
||||
) =>
|
||||
produce(data, (draft) => {
|
||||
const index = draft.findIndex((m) => m.id === delta.market.id);
|
||||
if (index !== -1) {
|
||||
draft[index].data = delta;
|
||||
}
|
||||
// @TODO - else push new market to draft
|
||||
});
|
||||
|
||||
const getData = (responseData: SimpleMarkets) => responseData.markets;
|
||||
const getDelta = (
|
||||
|
@ -4,20 +4,12 @@ import { SimpleMarketList } from '../components/simple-market-list';
|
||||
import { Portfolio } from '../components/portfolio';
|
||||
|
||||
export const ROUTES = {
|
||||
HOME: '/',
|
||||
MARKETS: 'markets',
|
||||
TRADING: 'trading',
|
||||
LIQUIDITY: 'liquidity',
|
||||
PORTFOLIO: 'portfolio',
|
||||
};
|
||||
|
||||
export const routerConfig = [
|
||||
{
|
||||
path: ROUTES.HOME,
|
||||
name: 'Home',
|
||||
text: t('Home'),
|
||||
element: <div>Home</div>,
|
||||
},
|
||||
{
|
||||
path: ROUTES.MARKETS,
|
||||
children: [
|
||||
@ -36,6 +28,7 @@ export const routerConfig = [
|
||||
name: 'Markets',
|
||||
text: t('Markets'),
|
||||
element: <SimpleMarketList />,
|
||||
icon: 'market',
|
||||
},
|
||||
{
|
||||
path: ROUTES.TRADING,
|
||||
@ -48,17 +41,13 @@ export const routerConfig = [
|
||||
element: <DealTicketContainer />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: ROUTES.LIQUIDITY,
|
||||
name: 'Liquidity',
|
||||
text: t('Liquidity'),
|
||||
element: <div>Liquidity</div>,
|
||||
icon: 'trade',
|
||||
},
|
||||
{
|
||||
path: ROUTES.PORTFOLIO,
|
||||
name: 'Portfolio',
|
||||
text: t('Portfolio'),
|
||||
element: <Portfolio />,
|
||||
icon: 'portfolio',
|
||||
},
|
||||
];
|
||||
|
@ -38,7 +38,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "125135.491715841699705585",
|
||||
"locked_amount": "124661.013711767544930765",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@ -488,7 +488,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "97499.58",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "65968.462097822203561422",
|
||||
"locked_amount": "65503.04337545080622283",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "97499.58",
|
||||
@ -521,7 +521,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "135173.4239508",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "90167.49870786346458279454272",
|
||||
"locked_amount": "89531.35166557213976323285608",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "135173.4239508",
|
||||
@ -554,7 +554,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "32499.86",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "27751.792790148093061242",
|
||||
"locked_amount": "27555.99917099787937361",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "32499.86",
|
||||
@ -587,7 +587,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "10833.29",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "9032.939256170343795749",
|
||||
"locked_amount": "8969.210333073256934278",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10833.29",
|
||||
@ -675,7 +675,7 @@
|
||||
"tranche_end": "2022-11-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "15712.88213315217375",
|
||||
"locked_amount": "15468.3027626811615",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "15000",
|
||||
@ -761,7 +761,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1815010.058055673609877812",
|
||||
"locked_amount": "1804379.69836047439128314",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@ -1776,8 +1776,8 @@
|
||||
"tranche_start": "2021-09-05T00:00:00.000Z",
|
||||
"tranche_end": "2022-09-30T00:00:00.000Z",
|
||||
"total_added": "60916.66666633337",
|
||||
"total_removed": "18323.723696937179372649",
|
||||
"locked_amount": "15072.4168891625501902368233482636",
|
||||
"total_removed": "18705.279504739679372649",
|
||||
"locked_amount": "14760.0056484630890178248654459722",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2833.333333",
|
||||
@ -1876,6 +1876,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "381.5558078025",
|
||||
"user": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05",
|
||||
"tx": "0xdf5387ab07596bf2a4a608ea38d3f98f8020941f4fa7ad88f1ccd223669ac2c7"
|
||||
},
|
||||
{
|
||||
"amount": "327.532400005",
|
||||
"user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2",
|
||||
@ -2591,6 +2596,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "381.5558078025",
|
||||
"user": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05",
|
||||
"tranche_id": 13,
|
||||
"tx": "0xdf5387ab07596bf2a4a608ea38d3f98f8020941f4fa7ad88f1ccd223669ac2c7"
|
||||
},
|
||||
{
|
||||
"amount": "490.9767850775",
|
||||
"user": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05",
|
||||
@ -2635,8 +2646,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "4250",
|
||||
"withdrawn_tokens": "2838.102475055",
|
||||
"remaining_tokens": "1411.897524945"
|
||||
"withdrawn_tokens": "3219.6582828575",
|
||||
"remaining_tokens": "1030.3417171425"
|
||||
},
|
||||
{
|
||||
"address": "0xDFaF6D0a0102ea5e4688F95Eb22Dc353751a7563",
|
||||
@ -5216,8 +5227,8 @@
|
||||
"tranche_start": "2021-09-03T00:00:00.000Z",
|
||||
"tranche_end": "2022-09-03T00:00:00.000Z",
|
||||
"total_added": "19455.000000000000000003",
|
||||
"total_removed": "5052.45813105178",
|
||||
"locked_amount": "3704.25642979452060480057120376712328768",
|
||||
"total_removed": "5056.88782409978",
|
||||
"locked_amount": "3597.64752092846370375055476445966514475",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "75",
|
||||
@ -8271,6 +8282,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "4.429693048",
|
||||
"user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b",
|
||||
"tx": "0xfbca378f6263977884e6eebc653c8d68f39b6c8eb6ce2f6668767ed63bfcc55b"
|
||||
},
|
||||
{
|
||||
"amount": "8.25227042",
|
||||
"user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b",
|
||||
@ -14019,6 +14035,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "4.429693048",
|
||||
"user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xfbca378f6263977884e6eebc653c8d68f39b6c8eb6ce2f6668767ed63bfcc55b"
|
||||
},
|
||||
{
|
||||
"amount": "8.25227042",
|
||||
"user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b",
|
||||
@ -14075,8 +14097,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "157.871905124",
|
||||
"remaining_tokens": "42.128094876"
|
||||
"withdrawn_tokens": "162.301598172",
|
||||
"remaining_tokens": "37.698401828"
|
||||
},
|
||||
{
|
||||
"address": "0x1775cc97E5c05Fde8b571ef75CA52d0A9ff19025",
|
||||
@ -14101,7 +14123,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "74162.9780761646031",
|
||||
"locked_amount": "2813539.86457541017334277964",
|
||||
"locked_amount": "2797204.7028220379638062054",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@ -14813,8 +14835,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15788853.065470999700000001",
|
||||
"total_removed": "6989.59530997724295",
|
||||
"locked_amount": "15198109.6225936964233990941947241879805353",
|
||||
"total_removed": "7926.7627792759659",
|
||||
"locked_amount": "15140482.7365636033722263648641426217383077",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@ -15323,6 +15345,21 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xf2208f6e0a6d6b7f5e52e128632ac52b8473b408421318b9a28460aa19feca9c"
|
||||
},
|
||||
{
|
||||
"amount": "358.037173900154925",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x2a92ef6c2eb5779e6219058a74210fcd461484d42d623dd06dcb9886683d7b50"
|
||||
},
|
||||
{
|
||||
"amount": "226.8137106757935",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xcb5d0a1e6fdae5bed77fe2f8a29df14985d9f21d0e681416c618104b530fab36"
|
||||
},
|
||||
{
|
||||
"amount": "352.316584722774525",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xa79f7f3e6436a1f473f3beab9e0a5c8bc4f52b38ac7aedb8610a1a9a9c4a786c"
|
||||
},
|
||||
{
|
||||
"amount": "2446.31552516990115",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@ -15427,6 +15464,24 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0xf2208f6e0a6d6b7f5e52e128632ac52b8473b408421318b9a28460aa19feca9c"
|
||||
},
|
||||
{
|
||||
"amount": "358.037173900154925",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x2a92ef6c2eb5779e6219058a74210fcd461484d42d623dd06dcb9886683d7b50"
|
||||
},
|
||||
{
|
||||
"amount": "226.8137106757935",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xcb5d0a1e6fdae5bed77fe2f8a29df14985d9f21d0e681416c618104b530fab36"
|
||||
},
|
||||
{
|
||||
"amount": "352.316584722774525",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xa79f7f3e6436a1f473f3beab9e0a5c8bc4f52b38ac7aedb8610a1a9a9c4a786c"
|
||||
},
|
||||
{
|
||||
"amount": "2446.31552516990115",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@ -15471,8 +15526,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "194999.1675",
|
||||
"withdrawn_tokens": "6989.59530997724295",
|
||||
"remaining_tokens": "188009.57219002275705"
|
||||
"withdrawn_tokens": "7926.7627792759659",
|
||||
"remaining_tokens": "187072.4047207240341"
|
||||
},
|
||||
{
|
||||
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
|
||||
@ -16876,8 +16931,8 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "2111906.584458928859990382",
|
||||
"locked_amount": "8381555.21023446802429182215306625",
|
||||
"total_removed": "2113641.840890679071831632",
|
||||
"locked_amount": "8328080.66510881884167481291924447",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@ -17111,6 +17166,21 @@
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
"tx": "0xd950c34bf5f503998bddc8f9fdeb7cdc4ae1e76c5e9b1564795c306c2e8cad63"
|
||||
},
|
||||
{
|
||||
"amount": "657.674387973356598",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xd0f13de38f21ba54433885d7e3e3db7438b9bcc92dbd52a75e0b7f772018ab1c"
|
||||
},
|
||||
{
|
||||
"amount": "424.7645385693677305",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x77d249279d8ea7554d19c557311687d57884b5e08537ac9574897ca58a13d880"
|
||||
},
|
||||
{
|
||||
"amount": "652.81750520748751275",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xc62ffa6bf5029422f44d9406972fc074b498e02f667a86ae9faba138b6cfd758"
|
||||
},
|
||||
{
|
||||
"amount": "652.48254356494551875",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@ -18711,6 +18781,24 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0xcb8ecc71a9024bab7454a33f6adf7bfcd0f25b3dc1919f92ca362a25b71f2a4d"
|
||||
},
|
||||
{
|
||||
"amount": "657.674387973356598",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xd0f13de38f21ba54433885d7e3e3db7438b9bcc92dbd52a75e0b7f772018ab1c"
|
||||
},
|
||||
{
|
||||
"amount": "424.7645385693677305",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x77d249279d8ea7554d19c557311687d57884b5e08537ac9574897ca58a13d880"
|
||||
},
|
||||
{
|
||||
"amount": "652.81750520748751275",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xc62ffa6bf5029422f44d9406972fc074b498e02f667a86ae9faba138b6cfd758"
|
||||
},
|
||||
{
|
||||
"amount": "652.48254356494551875",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@ -19949,8 +20037,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "152357.71935946585119525",
|
||||
"remaining_tokens": "206765.75021553414880475"
|
||||
"withdrawn_tokens": "154092.9757912160630365",
|
||||
"remaining_tokens": "205030.4937837839369635"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@ -20947,7 +21035,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "5778205.3912159303",
|
||||
"total_removed": "1390546.591547348229906227",
|
||||
"locked_amount": "2994699.75124732873280622934348863",
|
||||
"locked_amount": "2973571.63505682836710488797665665",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "552496.6455",
|
||||
@ -22069,8 +22157,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "11.163032724",
|
||||
"locked_amount": "445821.47442149508818133870319632",
|
||||
"total_removed": "34.173053016",
|
||||
"locked_amount": "443233.07466590775804275636428212",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@ -28693,6 +28781,11 @@
|
||||
"amount": "11.163032724",
|
||||
"user": "0xF5037DDA4A660d67560200f45380FF8364e35540",
|
||||
"tx": "0x0db96c68606a35c59786e3b1ff4f8e939a56af133709dd154718eb03138fe227"
|
||||
},
|
||||
{
|
||||
"amount": "23.010020292",
|
||||
"user": "0xD27929d68ac0E5fd5C919A5eb5968C1D06D3Fb83",
|
||||
"tx": "0x8daf320262d0384cf5f9c290cc33721587beabd5e93026b3e9b76dc3fcd6659c"
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
@ -47207,10 +47300,17 @@
|
||||
"tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "23.010020292",
|
||||
"user": "0xD27929d68ac0E5fd5C919A5eb5968C1D06D3Fb83",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x8daf320262d0384cf5f9c290cc33721587beabd5e93026b3e9b76dc3fcd6659c"
|
||||
}
|
||||
],
|
||||
"total_tokens": "400",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "400"
|
||||
"withdrawn_tokens": "23.010020292",
|
||||
"remaining_tokens": "376.989979708"
|
||||
},
|
||||
{
|
||||
"address": "0xF5037DDA4A660d67560200f45380FF8364e35540",
|
||||
@ -47736,7 +47836,7 @@
|
||||
"tranche_start": "2021-12-05T00:00:00.000Z",
|
||||
"tranche_end": "2022-06-05T00:00:00.000Z",
|
||||
"total_added": "171288.42",
|
||||
"total_removed": "31035.4825162206377",
|
||||
"total_removed": "32094.1716569431377",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@ -52011,6 +52111,31 @@
|
||||
"user": "0x4796314cC5bDa80Ee2E8b119004b1fc72Cfb1783",
|
||||
"tx": "0xbfdbd5e3712968f2726e8dba1f226944cfa637f8738f25c3a5b12a1c6a8e7197"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0xC26B3b40DC383d97B69Eedcd4E78a9e4eEb73499",
|
||||
"tx": "0x2c9f57d5e697c29b67034cea8738939ec13b20b5a7d7fcb995fe83f16b4abf75"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x9f6b5A46593b991dC78a0e1907a07517A1F80CC2",
|
||||
"tx": "0x55b21517cf5fd148e596d9e4b63964ab1df82534fd76b6d9dc9d7cfd00971da0"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x696971413b8Ae5342277AfeC16591271648B4FfF",
|
||||
"tx": "0xa55b22bf465927c195b424ad7ea893c1c497da34290d5261be205c760fc11cf5"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x8FC36B7695965Bc39BCB8a3679529f1825e472aE",
|
||||
"tx": "0x7072667bf81811acda07177c1ace2edcfe19ce68711fa349ad94c1f8aa3d0b25"
|
||||
},
|
||||
{
|
||||
"amount": "58.6891407225",
|
||||
"user": "0xDD5730a33719083470e641cF0e4154Dd04D5738d",
|
||||
"tx": "0x49bd6332008e65069aad8012f76f15f3dae19f664237b02f9152946297db812d"
|
||||
},
|
||||
{
|
||||
"amount": "183.6335597275",
|
||||
"user": "0x690Fc36d52eD3f198F0eBDea1557333a1766f786",
|
||||
@ -58532,6 +58657,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "58.6891407225",
|
||||
"user": "0xDD5730a33719083470e641cF0e4154Dd04D5738d",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x49bd6332008e65069aad8012f76f15f3dae19f664237b02f9152946297db812d"
|
||||
},
|
||||
{
|
||||
"amount": "65.928596865",
|
||||
"user": "0xDD5730a33719083470e641cF0e4154Dd04D5738d",
|
||||
@ -58546,8 +58677,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "191.3108592775",
|
||||
"remaining_tokens": "58.6891407225"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x243e23c83135cA0fed2F9f5dF9068dE644929433",
|
||||
@ -61925,10 +62056,17 @@
|
||||
"tx": "0x716a7be06da5a7a3d8038907974887a31805ea8eeab5d130cba528e4d2094d9f"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x9f6b5A46593b991dC78a0e1907a07517A1F80CC2",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x55b21517cf5fd148e596d9e4b63964ab1df82534fd76b6d9dc9d7cfd00971da0"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x758E9AA35F2feA08aEc1613A0F0d9Ebe4d374152",
|
||||
@ -61980,10 +62118,17 @@
|
||||
"tx": "0x716a7be06da5a7a3d8038907974887a31805ea8eeab5d130cba528e4d2094d9f"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x8FC36B7695965Bc39BCB8a3679529f1825e472aE",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x7072667bf81811acda07177c1ace2edcfe19ce68711fa349ad94c1f8aa3d0b25"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x8186CDe8f7A2f95b50f847e2a3301c28bB61Fa8A",
|
||||
@ -63994,10 +64139,17 @@
|
||||
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x696971413b8Ae5342277AfeC16591271648B4FfF",
|
||||
"tranche_id": 6,
|
||||
"tx": "0xa55b22bf465927c195b424ad7ea893c1c497da34290d5261be205c760fc11cf5"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xcbEca0abcc675A0F977c4Eb9a45bB4153C0246C3",
|
||||
@ -64031,10 +64183,17 @@
|
||||
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0xC26B3b40DC383d97B69Eedcd4E78a9e4eEb73499",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x2c9f57d5e697c29b67034cea8738939ec13b20b5a7d7fcb995fe83f16b4abf75"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xd866082E19c9E36bcA4fA649d530166303B656f2",
|
||||
|
@ -38,7 +38,7 @@
|
||||
"tranche_end": "2022-11-26T13:48:10.000Z",
|
||||
"total_added": "100",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "42.21141552511416",
|
||||
"locked_amount": "41.663429096905125",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "100",
|
||||
@ -242,7 +242,7 @@
|
||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||
"total_added": "1100",
|
||||
"total_removed": "673.04388635",
|
||||
"locked_amount": "327.08752536783356",
|
||||
"locked_amount": "321.05967465753423",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1000",
|
||||
|
@ -69,7 +69,7 @@
|
||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||
"total_added": "1010.000000000000000001",
|
||||
"total_removed": "668.4622323651",
|
||||
"locked_amount": "300.32585077371895640029735232749873164",
|
||||
"locked_amount": "294.7911558219177930002918724315068493",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1000",
|
||||
|
@ -24,6 +24,7 @@ export const ProposalsContainer = () => {
|
||||
const { t } = useTranslation();
|
||||
const { data, loading, error } = useQuery<Proposals, never>(PROPOSALS_QUERY, {
|
||||
pollInterval: 5000,
|
||||
errorPolicy: 'ignore', // this is to get around some backend issues and should be removed in future
|
||||
});
|
||||
|
||||
const proposals = React.useMemo(() => {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import produce from 'immer';
|
||||
import { gql } from '@apollo/client';
|
||||
import type {
|
||||
Accounts,
|
||||
@ -52,17 +53,18 @@ export const getId = (
|
||||
) => `${data.type}-${data.asset.symbol}-${data.market?.id ?? 'null'}`;
|
||||
|
||||
const update = (
|
||||
draft: Accounts_party_accounts[],
|
||||
data: Accounts_party_accounts[],
|
||||
delta: AccountSubscribe_accounts
|
||||
) => {
|
||||
const id = getId(delta);
|
||||
const index = draft.findIndex((a) => getId(a) === id);
|
||||
if (index !== -1) {
|
||||
draft[index] = delta;
|
||||
} else {
|
||||
draft.push(delta);
|
||||
}
|
||||
};
|
||||
) =>
|
||||
produce(data, (draft) => {
|
||||
const id = getId(delta);
|
||||
const index = draft.findIndex((a) => getId(a) === id);
|
||||
if (index !== -1) {
|
||||
draft[index] = delta;
|
||||
} else {
|
||||
draft.push(delta);
|
||||
}
|
||||
});
|
||||
const getData = (responseData: Accounts): Accounts_party_accounts[] | null =>
|
||||
responseData.party ? responseData.party.accounts : null;
|
||||
const getDelta = (
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { DepthChart } from 'pennant';
|
||||
import { produce } from 'immer';
|
||||
import throttle from 'lodash/throttle';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
@ -92,28 +91,31 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
|
||||
if (!dataRef.current) {
|
||||
return false;
|
||||
}
|
||||
dataRef.current = produce(dataRef.current, (draft) => {
|
||||
if (delta.buy) {
|
||||
draft.data.buy = updateLevels(
|
||||
draft.data.buy,
|
||||
delta.buy,
|
||||
decimalPlacesRef.current
|
||||
);
|
||||
}
|
||||
if (delta.sell) {
|
||||
draft.data.sell = updateLevels(
|
||||
draft.data.sell,
|
||||
delta.sell,
|
||||
decimalPlacesRef.current
|
||||
);
|
||||
}
|
||||
draft.midPrice = delta.market.data?.staticMidPrice
|
||||
dataRef.current = {
|
||||
...dataRef.current,
|
||||
midPrice: delta.market.data?.staticMidPrice
|
||||
? formatMidPrice(
|
||||
delta.market.data?.staticMidPrice,
|
||||
decimalPlacesRef.current
|
||||
)
|
||||
: undefined;
|
||||
});
|
||||
: undefined,
|
||||
data: {
|
||||
buy: delta.buy
|
||||
? updateLevels(
|
||||
dataRef.current.data.buy,
|
||||
delta.buy,
|
||||
decimalPlacesRef.current
|
||||
)
|
||||
: dataRef.current.data.buy,
|
||||
sell: delta.sell
|
||||
? updateLevels(
|
||||
dataRef.current.data.sell,
|
||||
delta.sell,
|
||||
decimalPlacesRef.current
|
||||
)
|
||||
: dataRef.current.data.sell,
|
||||
},
|
||||
};
|
||||
setDepthDataThrottledRef.current(dataRef.current);
|
||||
return true;
|
||||
},
|
||||
|
@ -86,27 +86,31 @@ const sequenceNumbers: Record<string, number> = {};
|
||||
const update: Update<
|
||||
MarketDepth_market,
|
||||
MarketDepthSubscription_marketDepthUpdate
|
||||
> = (draft, delta, reload) => {
|
||||
if (delta.market.id !== draft.id) {
|
||||
return;
|
||||
> = (data, delta, reload) => {
|
||||
if (delta.market.id !== data.id) {
|
||||
return data;
|
||||
}
|
||||
const sequenceNumber = Number(delta.sequenceNumber);
|
||||
if (sequenceNumber <= sequenceNumbers[delta.market.id]) {
|
||||
return;
|
||||
return data;
|
||||
}
|
||||
/*
|
||||
if (sequenceNumber - 1 !== sequenceNumbers[delta.market.id]) {
|
||||
sequenceNumbers[delta.market.id] = 0;
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
sequenceNumbers[delta.market.id] = sequenceNumber;
|
||||
Object.assign(draft.data, delta.market.data);
|
||||
const updatedData = { ...data };
|
||||
data.data = delta.market.data;
|
||||
if (delta.buy) {
|
||||
draft.depth.buy = updateLevels(draft.depth.buy ?? [], delta.buy);
|
||||
updatedData.depth.buy = updateLevels(data.depth.buy ?? [], delta.buy);
|
||||
}
|
||||
if (delta.sell) {
|
||||
draft.depth.sell = updateLevels(draft.depth.sell ?? [], delta.sell);
|
||||
updatedData.depth.sell = updateLevels(data.depth.sell ?? [], delta.sell);
|
||||
}
|
||||
return updatedData;
|
||||
};
|
||||
|
||||
const getData = (responseData: MarketDepth) => {
|
||||
|
@ -55,10 +55,8 @@ describe('compactRows', () => {
|
||||
'1097': 3,
|
||||
'1098': 2,
|
||||
'1099': 1,
|
||||
'1100': 0,
|
||||
});
|
||||
expect(orderbookRows[orderbookRows.length - 1].bidByLevel).toEqual({
|
||||
'901': 0,
|
||||
'902': 1,
|
||||
'903': 2,
|
||||
'904': 3,
|
||||
@ -81,7 +79,7 @@ describe('compactRows', () => {
|
||||
});
|
||||
|
||||
describe('updateLevels', () => {
|
||||
const levels: MarketDepth_market_depth_sell[] = new Array(10)
|
||||
let levels: MarketDepth_market_depth_sell[] = new Array(10)
|
||||
.fill(null)
|
||||
.map((n, i) => ({
|
||||
__typename: 'PriceLevel',
|
||||
@ -96,9 +94,9 @@ describe('updateLevels', () => {
|
||||
volume: '0',
|
||||
numberOfOrders: '0',
|
||||
};
|
||||
updateLevels(levels, [removeFirstRow]);
|
||||
levels = updateLevels(levels, [removeFirstRow]);
|
||||
expect(levels[0].price).toEqual('20');
|
||||
updateLevels(levels, [removeFirstRow]);
|
||||
levels = updateLevels(levels, [removeFirstRow]);
|
||||
expect(levels[0].price).toEqual('20');
|
||||
expect(updateLevels([], [removeFirstRow])).toEqual([]);
|
||||
const addFirstRow: MarketDepthSubscription_marketDepthUpdate_sell = {
|
||||
@ -107,7 +105,7 @@ describe('updateLevels', () => {
|
||||
volume: '10',
|
||||
numberOfOrders: '10',
|
||||
};
|
||||
updateLevels(levels, [addFirstRow]);
|
||||
levels = updateLevels(levels, [addFirstRow]);
|
||||
expect(levels[0].price).toEqual('10');
|
||||
const addBeforeLastRow: MarketDepthSubscription_marketDepthUpdate_sell = {
|
||||
__typename: 'PriceLevel',
|
||||
@ -115,7 +113,7 @@ describe('updateLevels', () => {
|
||||
volume: '95',
|
||||
numberOfOrders: '95',
|
||||
};
|
||||
updateLevels(levels, [addBeforeLastRow]);
|
||||
levels = updateLevels(levels, [addBeforeLastRow]);
|
||||
expect(levels[levels.length - 2].price).toEqual('95');
|
||||
const addAtTheEnd: MarketDepthSubscription_marketDepthUpdate_sell = {
|
||||
__typename: 'PriceLevel',
|
||||
@ -123,7 +121,7 @@ describe('updateLevels', () => {
|
||||
volume: '115',
|
||||
numberOfOrders: '115',
|
||||
};
|
||||
updateLevels(levels, [addAtTheEnd]);
|
||||
levels = updateLevels(levels, [addAtTheEnd]);
|
||||
expect(levels[levels.length - 1].price).toEqual('115');
|
||||
const updateLastRow: MarketDepthSubscription_marketDepthUpdate_sell = {
|
||||
__typename: 'PriceLevel',
|
||||
@ -131,7 +129,7 @@ describe('updateLevels', () => {
|
||||
volume: '116',
|
||||
numberOfOrders: '115',
|
||||
};
|
||||
updateLevels(levels, [updateLastRow]);
|
||||
levels = updateLevels(levels, [updateLastRow]);
|
||||
expect(levels[levels.length - 1]).toEqual(updateLastRow);
|
||||
expect(updateLevels([], [updateLastRow])).toEqual([updateLastRow]);
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
import produce from 'immer';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import { VolumeType } from '@vegaprotocol/react-helpers';
|
||||
import { MarketTradingMode } from '@vegaprotocol/types';
|
||||
@ -31,6 +30,8 @@ export interface OrderbookRowData {
|
||||
cumulativeVol: CumulativeVol;
|
||||
}
|
||||
|
||||
type PartialOrderbookRowData = Pick<OrderbookRowData, 'price' | 'ask' | 'bid'>;
|
||||
|
||||
export type OrderbookData = Partial<
|
||||
Omit<MarketDepth_market_data, '__typename' | 'market'>
|
||||
> & { rows: OrderbookRowData[] | null };
|
||||
@ -75,21 +76,31 @@ const updateRelativeData = (data: OrderbookRowData[]) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const createPartialRow = (
|
||||
price: string,
|
||||
volume = 0,
|
||||
dataType?: VolumeType
|
||||
): PartialOrderbookRowData => ({
|
||||
price,
|
||||
ask: dataType === VolumeType.ask ? volume : 0,
|
||||
bid: dataType === VolumeType.bid ? volume : 0,
|
||||
});
|
||||
|
||||
export const extendRow = (row: PartialOrderbookRowData): OrderbookRowData =>
|
||||
Object.assign(row, {
|
||||
cumulativeVol: {
|
||||
ask: 0,
|
||||
bid: 0,
|
||||
},
|
||||
askByLevel: row.ask ? { [row.price]: row.ask } : {},
|
||||
bidByLevel: row.bid ? { [row.price]: row.bid } : {},
|
||||
});
|
||||
|
||||
export const createRow = (
|
||||
price: string,
|
||||
volume = 0,
|
||||
dataType?: VolumeType
|
||||
): OrderbookRowData => ({
|
||||
price,
|
||||
ask: dataType === VolumeType.ask ? volume : 0,
|
||||
bid: dataType === VolumeType.bid ? volume : 0,
|
||||
cumulativeVol: {
|
||||
ask: dataType === VolumeType.ask ? volume : 0,
|
||||
bid: dataType === VolumeType.bid ? volume : 0,
|
||||
},
|
||||
askByLevel: dataType === VolumeType.ask ? { [price]: volume } : {},
|
||||
bidByLevel: dataType === VolumeType.bid ? { [price]: volume } : {},
|
||||
});
|
||||
): OrderbookRowData => extendRow(createPartialRow(price, volume, dataType));
|
||||
|
||||
const mapRawData =
|
||||
(dataType: VolumeType.ask | VolumeType.bid) =>
|
||||
@ -99,8 +110,8 @@ const mapRawData =
|
||||
| MarketDepthSubscription_marketDepthUpdate_sell
|
||||
| MarketDepth_market_depth_buy
|
||||
| MarketDepthSubscription_marketDepthUpdate_buy
|
||||
): OrderbookRowData =>
|
||||
createRow(data.price, Number(data.volume), dataType);
|
||||
): PartialOrderbookRowData =>
|
||||
createPartialRow(data.price, Number(data.volume), dataType);
|
||||
|
||||
/**
|
||||
* @summary merges sell amd buy data, orders by price desc, group by price level, counts cumulative and relative values
|
||||
@ -121,37 +132,38 @@ export const compactRows = (
|
||||
resolution: number
|
||||
) => {
|
||||
// map raw sell data to OrderbookData
|
||||
const askOrderbookData = [...(sell ?? [])].map<OrderbookRowData>(
|
||||
const askOrderbookData = [...(sell ?? [])].map<PartialOrderbookRowData>(
|
||||
mapRawData(VolumeType.ask)
|
||||
);
|
||||
// map raw buy data to OrderbookData
|
||||
const bidOrderbookData = [...(buy ?? [])].map<OrderbookRowData>(
|
||||
const bidOrderbookData = [...(buy ?? [])].map<PartialOrderbookRowData>(
|
||||
mapRawData(VolumeType.bid)
|
||||
);
|
||||
|
||||
// group by price level
|
||||
const groupedByLevel = groupBy<OrderbookRowData>(
|
||||
const groupedByLevel = groupBy<PartialOrderbookRowData>(
|
||||
[...askOrderbookData, ...bidOrderbookData],
|
||||
(row) => getPriceLevel(row.price, resolution)
|
||||
);
|
||||
|
||||
// create single OrderbookData from grouped OrderbookData[], sum volumes and atore volume by level
|
||||
const orderbookData = Object.keys(groupedByLevel).reduce<OrderbookRowData[]>(
|
||||
(rows, price) =>
|
||||
rows.concat(
|
||||
groupedByLevel[price].reduce<OrderbookRowData>(
|
||||
(a, c) => ({
|
||||
...a,
|
||||
ask: a.ask + c.ask,
|
||||
askByLevel: Object.assign(a.askByLevel, c.askByLevel),
|
||||
bid: (a.bid ?? 0) + (c.bid ?? 0),
|
||||
bidByLevel: Object.assign(a.bidByLevel, c.bidByLevel),
|
||||
}),
|
||||
createRow(price)
|
||||
)
|
||||
),
|
||||
[]
|
||||
);
|
||||
const orderbookData: OrderbookRowData[] = [];
|
||||
Object.keys(groupedByLevel).forEach((price) => {
|
||||
const row = extendRow(
|
||||
groupedByLevel[price].pop() as PartialOrderbookRowData
|
||||
);
|
||||
row.price = price;
|
||||
let subRow: PartialOrderbookRowData | undefined;
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while ((subRow = groupedByLevel[price].pop())) {
|
||||
row.ask += subRow.ask;
|
||||
row.bid += subRow.bid;
|
||||
if (subRow.ask) {
|
||||
row.askByLevel[subRow.price] = subRow.ask;
|
||||
}
|
||||
if (subRow.bid) {
|
||||
row.bidByLevel[subRow.price] = subRow.bid;
|
||||
}
|
||||
}
|
||||
orderbookData.push(row);
|
||||
});
|
||||
// order by price, it's safe to cast to number price diff should not exceed Number.MAX_SAFE_INTEGER
|
||||
orderbookData.sort((a, b) => Number(BigInt(b.price) - BigInt(a.price)));
|
||||
// count cumulative volumes
|
||||
@ -163,11 +175,9 @@ export const compactRows = (
|
||||
(i !== 0 ? orderbookData[i - 1].cumulativeVol.bid : 0);
|
||||
}
|
||||
for (let i = maxIndex; i >= 0; i--) {
|
||||
if (!orderbookData[i].cumulativeVol.ask) {
|
||||
orderbookData[i].cumulativeVol.ask =
|
||||
orderbookData[i].ask +
|
||||
(i !== maxIndex ? orderbookData[i + 1].cumulativeVol.ask : 0);
|
||||
}
|
||||
orderbookData[i].cumulativeVol.ask =
|
||||
orderbookData[i].ask +
|
||||
(i !== maxIndex ? orderbookData[i + 1].cumulativeVol.ask : 0);
|
||||
}
|
||||
}
|
||||
// count relative volumes
|
||||
@ -186,13 +196,13 @@ export const compactRows = (
|
||||
*/
|
||||
const partiallyUpdateCompactedRows = (
|
||||
dataType: VolumeType,
|
||||
draft: OrderbookRowData[],
|
||||
data: OrderbookRowData[],
|
||||
delta:
|
||||
| MarketDepthSubscription_marketDepthUpdate_sell
|
||||
| MarketDepthSubscription_marketDepthUpdate_buy,
|
||||
resolution: number,
|
||||
modifiedIndex: number
|
||||
) => {
|
||||
): [number, OrderbookRowData[]] => {
|
||||
const { price } = delta;
|
||||
const volume = Number(delta.volume);
|
||||
const priceLevel = getPriceLevel(price, resolution);
|
||||
@ -201,28 +211,36 @@ const partiallyUpdateCompactedRows = (
|
||||
const oppositeVolKey = isAskDataType ? 'bid' : 'ask';
|
||||
const volByLevelKey = isAskDataType ? 'askByLevel' : 'bidByLevel';
|
||||
const resolveModifiedIndex = isAskDataType ? Math.max : Math.min;
|
||||
let index = draft.findIndex((data) => data.price === priceLevel);
|
||||
let index = data.findIndex((row) => row.price === priceLevel);
|
||||
if (index !== -1) {
|
||||
modifiedIndex = resolveModifiedIndex(modifiedIndex, index);
|
||||
draft[index][volKey] =
|
||||
draft[index][volKey] - (draft[index][volByLevelKey][price] || 0) + volume;
|
||||
draft[index][volByLevelKey][price] = volume;
|
||||
data[index] = {
|
||||
...data[index],
|
||||
[volKey]:
|
||||
data[index][volKey] - (data[index][volByLevelKey][price] || 0) + volume,
|
||||
[volByLevelKey]: {
|
||||
...data[index][volByLevelKey],
|
||||
[price]: volume,
|
||||
},
|
||||
};
|
||||
return [modifiedIndex, [...data]];
|
||||
} else {
|
||||
const newData: OrderbookRowData = createRow(priceLevel, volume, dataType);
|
||||
index = draft.findIndex((data) => BigInt(data.price) < BigInt(priceLevel));
|
||||
index = data.findIndex((row) => BigInt(row.price) < BigInt(priceLevel));
|
||||
if (index !== -1) {
|
||||
draft.splice(index, 0, newData);
|
||||
newData.cumulativeVol[oppositeVolKey] =
|
||||
draft[index + (isAskDataType ? -1 : 1)]?.cumulativeVol[
|
||||
oppositeVolKey
|
||||
] ?? 0;
|
||||
data[index + (isAskDataType ? 0 : 1)]?.cumulativeVol[oppositeVolKey] ??
|
||||
0;
|
||||
modifiedIndex = resolveModifiedIndex(modifiedIndex, index);
|
||||
return [
|
||||
modifiedIndex,
|
||||
[...data.slice(0, index), newData, ...data.slice(index)],
|
||||
];
|
||||
} else {
|
||||
draft.push(newData);
|
||||
modifiedIndex = draft.length - 1;
|
||||
modifiedIndex = data.length - 1;
|
||||
return [modifiedIndex, [...data, newData]];
|
||||
}
|
||||
}
|
||||
return modifiedIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -239,59 +257,66 @@ export const updateCompactedRows = (
|
||||
sell: MarketDepthSubscription_marketDepthUpdate_sell[] | null,
|
||||
buy: MarketDepthSubscription_marketDepthUpdate_buy[] | null,
|
||||
resolution: number
|
||||
) =>
|
||||
produce(rows, (draft) => {
|
||||
let sellModifiedIndex = -1;
|
||||
sell?.forEach((delta) => {
|
||||
sellModifiedIndex = partiallyUpdateCompactedRows(
|
||||
VolumeType.ask,
|
||||
draft,
|
||||
delta,
|
||||
resolution,
|
||||
sellModifiedIndex
|
||||
);
|
||||
});
|
||||
let buyModifiedIndex = draft.length;
|
||||
buy?.forEach((delta) => {
|
||||
buyModifiedIndex = partiallyUpdateCompactedRows(
|
||||
VolumeType.bid,
|
||||
draft,
|
||||
delta,
|
||||
resolution,
|
||||
buyModifiedIndex
|
||||
);
|
||||
});
|
||||
|
||||
// update cummulative ask only below hihgest modified price level
|
||||
if (sellModifiedIndex !== -1) {
|
||||
for (let i = Math.min(sellModifiedIndex, draft.length - 2); i >= 0; i--) {
|
||||
draft[i].cumulativeVol.ask =
|
||||
draft[i + 1].cumulativeVol.ask + draft[i].ask;
|
||||
}
|
||||
}
|
||||
// update cummulative bid only above lowest modified price level
|
||||
if (buyModifiedIndex !== draft.length) {
|
||||
for (
|
||||
let i = Math.max(buyModifiedIndex, 1), l = draft.length;
|
||||
i < l;
|
||||
i++
|
||||
) {
|
||||
draft[i].cumulativeVol.bid =
|
||||
draft[i - 1].cumulativeVol.bid + draft[i].bid;
|
||||
}
|
||||
}
|
||||
let index = 0;
|
||||
// remove levels that do not have any volume
|
||||
while (index < draft.length) {
|
||||
if (!draft[index].ask && !draft[index].bid) {
|
||||
draft.splice(index, 1);
|
||||
} else {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
// count relative volumes
|
||||
updateRelativeData(draft);
|
||||
) => {
|
||||
let sellModifiedIndex = -1;
|
||||
let data = [...rows];
|
||||
sell?.forEach((delta) => {
|
||||
[sellModifiedIndex, data] = partiallyUpdateCompactedRows(
|
||||
VolumeType.ask,
|
||||
data,
|
||||
delta,
|
||||
resolution,
|
||||
sellModifiedIndex
|
||||
);
|
||||
});
|
||||
let buyModifiedIndex = data.length;
|
||||
buy?.forEach((delta) => {
|
||||
[buyModifiedIndex, data] = partiallyUpdateCompactedRows(
|
||||
VolumeType.bid,
|
||||
data,
|
||||
delta,
|
||||
resolution,
|
||||
buyModifiedIndex
|
||||
);
|
||||
});
|
||||
|
||||
// update cummulative ask only below hihgest modified price level
|
||||
if (sellModifiedIndex !== -1) {
|
||||
for (let i = Math.min(sellModifiedIndex, data.length - 2); i >= 0; i--) {
|
||||
data[i] = {
|
||||
...data[i],
|
||||
cumulativeVol: {
|
||||
...data[i].cumulativeVol,
|
||||
ask: data[i + 1].cumulativeVol.ask + data[i].ask,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
// update cummulative bid only above lowest modified price level
|
||||
if (buyModifiedIndex !== data.length) {
|
||||
for (let i = Math.max(buyModifiedIndex, 1), l = data.length; i < l; i++) {
|
||||
data[i] = {
|
||||
...data[i],
|
||||
cumulativeVol: {
|
||||
...data[i].cumulativeVol,
|
||||
bid: data[i - 1].cumulativeVol.bid + data[i].bid,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
let index = 0;
|
||||
// remove levels that do not have any volume
|
||||
while (index < data.length) {
|
||||
if (!data[index].ask && !data[index].bid) {
|
||||
data.splice(index, 1);
|
||||
} else {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
// count relative volumes
|
||||
updateRelativeData(data);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const mapMarketData = (
|
||||
data:
|
||||
@ -319,23 +344,24 @@ export const mapMarketData = (
|
||||
* @returns
|
||||
*/
|
||||
export const updateLevels = (
|
||||
levels: (MarketDepth_market_depth_buy | MarketDepth_market_depth_sell)[],
|
||||
draft: (MarketDepth_market_depth_buy | MarketDepth_market_depth_sell)[],
|
||||
updates: (
|
||||
| MarketDepthSubscription_marketDepthUpdate_buy
|
||||
| MarketDepthSubscription_marketDepthUpdate_sell
|
||||
)[]
|
||||
) => {
|
||||
const levels = [...draft];
|
||||
updates.forEach((update) => {
|
||||
let index = levels.findIndex((level) => level.price === update.price);
|
||||
if (index !== -1) {
|
||||
if (update.volume === '0') {
|
||||
levels.splice(index, 1);
|
||||
} else {
|
||||
Object.assign(levels[index], update);
|
||||
levels[index] = update;
|
||||
}
|
||||
} else if (update.volume !== '0') {
|
||||
index = levels.findIndex(
|
||||
(level) => Number(level.price) > Number(update.price)
|
||||
(level) => BigInt(level.price) > BigInt(update.price)
|
||||
);
|
||||
if (index !== -1) {
|
||||
levels.splice(index, 0, update);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import throttle from 'lodash/throttle';
|
||||
import produce from 'immer';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { Orderbook } from './orderbook';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
@ -25,27 +24,52 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
|
||||
rows: null,
|
||||
});
|
||||
const dataRef = useRef<OrderbookData>({ rows: null });
|
||||
const setOrderbookDataThrottled = useRef(throttle(setOrderbookData, 1000));
|
||||
const deltaRef = useRef<MarketDepthSubscription_marketDepthUpdate>();
|
||||
const updateOrderbookData = useRef(
|
||||
throttle(() => {
|
||||
if (!deltaRef.current) {
|
||||
return;
|
||||
}
|
||||
dataRef.current = {
|
||||
...deltaRef.current.market.data,
|
||||
...mapMarketData(deltaRef.current.market.data, resolutionRef.current),
|
||||
rows: updateCompactedRows(
|
||||
dataRef.current.rows ?? [],
|
||||
deltaRef.current.sell,
|
||||
deltaRef.current.buy,
|
||||
resolutionRef.current
|
||||
),
|
||||
};
|
||||
deltaRef.current = undefined;
|
||||
setOrderbookData(dataRef.current);
|
||||
}, 1000)
|
||||
);
|
||||
|
||||
const update = useCallback(
|
||||
(delta: MarketDepthSubscription_marketDepthUpdate) => {
|
||||
if (!dataRef.current.rows) {
|
||||
return false;
|
||||
}
|
||||
dataRef.current = produce(dataRef.current, (draft) => {
|
||||
Object.assign(draft, delta.market.data);
|
||||
draft.rows = updateCompactedRows(
|
||||
draft.rows ?? [],
|
||||
delta.sell,
|
||||
delta.buy,
|
||||
resolutionRef.current
|
||||
);
|
||||
Object.assign(
|
||||
draft,
|
||||
mapMarketData(delta.market.data, resolutionRef.current)
|
||||
);
|
||||
});
|
||||
setOrderbookDataThrottled.current(dataRef.current);
|
||||
if (deltaRef.current) {
|
||||
deltaRef.current.market = delta.market;
|
||||
if (delta.sell) {
|
||||
if (deltaRef.current.sell) {
|
||||
deltaRef.current.sell.push(...delta.sell);
|
||||
} else {
|
||||
deltaRef.current.sell = delta.sell;
|
||||
}
|
||||
}
|
||||
if (delta.buy) {
|
||||
if (deltaRef.current.buy) {
|
||||
deltaRef.current.buy.push(...delta.buy);
|
||||
} else {
|
||||
deltaRef.current.buy = delta.buy;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
deltaRef.current = delta;
|
||||
}
|
||||
updateOrderbookData.current();
|
||||
return true;
|
||||
},
|
||||
// using resolutionRef.current to avoid using resolution as a dependency - it will cause data provider restart on resolution change
|
||||
|
@ -176,7 +176,10 @@ export const Orderbook = ({
|
||||
// adjust to current rows position
|
||||
scrollTop +=
|
||||
(scrollTopRef.current % rowHeight) - (scrollTop % rowHeight);
|
||||
const priceCenterScrollOffset = Math.max(0, Math.min(scrollTop));
|
||||
const priceCenterScrollOffset = Math.max(
|
||||
0,
|
||||
Math.min(scrollTop, numberOfRows * rowHeight - viewportHeight)
|
||||
);
|
||||
if (scrollTopRef.current !== priceCenterScrollOffset) {
|
||||
updateScrollOffset(priceCenterScrollOffset);
|
||||
scrollTopRef.current = priceCenterScrollOffset;
|
||||
@ -184,7 +187,13 @@ export const Orderbook = ({
|
||||
}
|
||||
}
|
||||
},
|
||||
[maxPriceLevel, resolution, viewportHeight, updateScrollOffset]
|
||||
[
|
||||
maxPriceLevel,
|
||||
resolution,
|
||||
viewportHeight,
|
||||
numberOfRows,
|
||||
updateScrollOffset,
|
||||
]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -199,23 +208,36 @@ export const Orderbook = ({
|
||||
return;
|
||||
}
|
||||
priceInCenter.current = undefined;
|
||||
setLockOnMidPrice(true);
|
||||
scrollToPrice(
|
||||
getPriceLevel(
|
||||
BigInt(bestStaticOfferPrice) +
|
||||
(BigInt(bestStaticBidPrice) - BigInt(bestStaticOfferPrice)) /
|
||||
BigInt(2),
|
||||
resolution
|
||||
)
|
||||
let midPrice = getPriceLevel(
|
||||
BigInt(bestStaticOfferPrice) +
|
||||
(BigInt(bestStaticBidPrice) - BigInt(bestStaticOfferPrice)) / BigInt(2),
|
||||
resolution
|
||||
);
|
||||
}, [bestStaticOfferPrice, bestStaticBidPrice, scrollToPrice, resolution]);
|
||||
if (BigInt(midPrice) > BigInt(maxPriceLevel)) {
|
||||
midPrice = maxPriceLevel;
|
||||
} else {
|
||||
const minPriceLevel =
|
||||
BigInt(maxPriceLevel) - BigInt(Math.floor(numberOfRows * resolution));
|
||||
if (BigInt(midPrice) < minPriceLevel) {
|
||||
midPrice = minPriceLevel.toString();
|
||||
}
|
||||
}
|
||||
scrollToPrice(midPrice);
|
||||
setLockOnMidPrice(true);
|
||||
}, [
|
||||
bestStaticOfferPrice,
|
||||
bestStaticBidPrice,
|
||||
scrollToPrice,
|
||||
resolution,
|
||||
maxPriceLevel,
|
||||
numberOfRows,
|
||||
]);
|
||||
|
||||
// adjust scroll position to keep selected price in center
|
||||
useLayoutEffect(() => {
|
||||
if (resolutionRef.current !== resolution) {
|
||||
priceInCenter.current = undefined;
|
||||
resolutionRef.current = resolution;
|
||||
setLockOnMidPrice(true);
|
||||
}
|
||||
if (priceInCenter.current) {
|
||||
scrollToPrice(priceInCenter.current);
|
||||
@ -238,21 +260,19 @@ export const Orderbook = ({
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, []);
|
||||
|
||||
const renderedRows = useMemo(() => {
|
||||
let offset = Math.max(0, Math.round(scrollOffset / rowHeight));
|
||||
const prependingBufferSize = Math.min(bufferSize, offset);
|
||||
offset -= prependingBufferSize;
|
||||
const viewportSize = Math.round(viewportHeight / rowHeight);
|
||||
const limit = Math.min(
|
||||
prependingBufferSize + viewportSize + bufferSize,
|
||||
numberOfRows - offset
|
||||
);
|
||||
return {
|
||||
offset,
|
||||
limit,
|
||||
data: getRowsToRender(rows, resolution, offset, limit),
|
||||
};
|
||||
}, [rows, scrollOffset, resolution, viewportHeight, numberOfRows]);
|
||||
let offset = Math.max(0, Math.round(scrollOffset / rowHeight));
|
||||
const prependingBufferSize = Math.min(bufferSize, offset);
|
||||
offset -= prependingBufferSize;
|
||||
const viewportSize = Math.round(viewportHeight / rowHeight);
|
||||
const limit = Math.min(
|
||||
prependingBufferSize + viewportSize + bufferSize,
|
||||
numberOfRows - offset
|
||||
);
|
||||
const renderedRows = {
|
||||
offset,
|
||||
limit,
|
||||
data: getRowsToRender(rows, resolution, offset, limit),
|
||||
};
|
||||
|
||||
const paddingTop = renderedRows.offset * rowHeight;
|
||||
const paddingBottom =
|
||||
|
@ -1,3 +1,4 @@
|
||||
import produce from 'immer';
|
||||
import { gql } from '@apollo/client';
|
||||
import type {
|
||||
Markets,
|
||||
@ -90,13 +91,14 @@ const MARKET_DATA_SUB = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
const update = (draft: Markets_markets[], delta: MarketDataSub_marketData) => {
|
||||
const index = draft.findIndex((m) => m.id === delta.market.id);
|
||||
if (index !== -1) {
|
||||
draft[index].data = delta;
|
||||
}
|
||||
// @TODO - else push new market to draft
|
||||
};
|
||||
const update = (data: Markets_markets[], delta: MarketDataSub_marketData) =>
|
||||
produce(data, (draft) => {
|
||||
const index = draft.findIndex((m) => m.id === delta.market.id);
|
||||
if (index !== -1) {
|
||||
draft[index].data = delta;
|
||||
}
|
||||
// @TODO - else push new market to draft
|
||||
});
|
||||
const getData = (responseData: Markets): Markets_markets[] | null =>
|
||||
responseData.markets;
|
||||
const getDelta = (subscriptionData: MarketDataSub): MarketDataSub_marketData =>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import produce from 'immer';
|
||||
import { gql } from '@apollo/client';
|
||||
import { makeDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type { OrderFields } from './__generated__/OrderFields';
|
||||
@ -78,19 +79,20 @@ export const prepareIncomingOrders = (delta: OrderFields[]) => {
|
||||
return incoming;
|
||||
};
|
||||
|
||||
const update = (draft: OrderFields[], delta: OrderFields[]) => {
|
||||
const incoming = prepareIncomingOrders(delta);
|
||||
const update = (data: OrderFields[], delta: OrderFields[]) =>
|
||||
produce(data, (draft) => {
|
||||
const incoming = prepareIncomingOrders(delta);
|
||||
|
||||
// Add or update incoming orders
|
||||
incoming.forEach((order) => {
|
||||
const index = draft.findIndex((o) => o.id === order.id);
|
||||
if (index === -1) {
|
||||
draft.unshift(order);
|
||||
} else {
|
||||
draft[index] = order;
|
||||
}
|
||||
// Add or update incoming orders
|
||||
incoming.forEach((order) => {
|
||||
const index = draft.findIndex((o) => o.id === order.id);
|
||||
if (index === -1) {
|
||||
draft.unshift(order);
|
||||
} else {
|
||||
draft[index] = order;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getData = (responseData: Orders): Orders_party_orders[] | null =>
|
||||
responseData?.party?.orders || null;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import produce from 'immer';
|
||||
import { gql } from '@apollo/client';
|
||||
import type {
|
||||
Positions,
|
||||
@ -75,16 +76,17 @@ export const POSITIONS_SUB = gql`
|
||||
`;
|
||||
|
||||
const update = (
|
||||
draft: Positions_party_positions[],
|
||||
data: Positions_party_positions[],
|
||||
delta: PositionSubscribe_positions
|
||||
) => {
|
||||
const index = draft.findIndex((m) => m.market.id === delta.market.id);
|
||||
if (index !== -1) {
|
||||
draft[index] = delta;
|
||||
} else {
|
||||
draft.push(delta);
|
||||
}
|
||||
};
|
||||
) =>
|
||||
produce(data, (draft) => {
|
||||
const index = draft.findIndex((m) => m.market.id === delta.market.id);
|
||||
if (index !== -1) {
|
||||
draft[index] = delta;
|
||||
} else {
|
||||
draft.push(delta);
|
||||
}
|
||||
});
|
||||
const getData = (responseData: Positions): Positions_party_positions[] | null =>
|
||||
responseData.party ? responseData.party.positions : null;
|
||||
const getDelta = (
|
||||
|
@ -2,3 +2,4 @@ export * from './use-apply-grid-transaction';
|
||||
export * from './use-data-provider';
|
||||
export * from './use-theme-switcher';
|
||||
export * from './use-fetch';
|
||||
export * from './use-resize';
|
||||
|
34
libs/react-helpers/src/hooks/use-resize.ts
Normal file
34
libs/react-helpers/src/hooks/use-resize.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { useRef, useEffect, useState } from 'react';
|
||||
|
||||
export const useResize = () => {
|
||||
const [windowSize, setWindowSize] = useState({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
|
||||
const timeout = useRef(0);
|
||||
|
||||
const handleResize = () => {
|
||||
if (timeout.current) {
|
||||
window.cancelAnimationFrame(timeout.current);
|
||||
}
|
||||
|
||||
// Setup the new requestAnimationFrame()
|
||||
timeout.current = window.requestAnimationFrame(function () {
|
||||
setWindowSize({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
window.cancelAnimationFrame(timeout.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return windowSize;
|
||||
};
|
@ -1,5 +1,3 @@
|
||||
import { produce } from 'immer';
|
||||
import type { Draft } from 'immer';
|
||||
import type {
|
||||
ApolloClient,
|
||||
DocumentNode,
|
||||
@ -34,11 +32,7 @@ export interface Subscribe<Data, Delta> {
|
||||
type Query<Result> = DocumentNode | TypedDocumentNode<Result, any>;
|
||||
|
||||
export interface Update<Data, Delta> {
|
||||
(
|
||||
draft: Draft<Data>,
|
||||
delta: Delta,
|
||||
reload: (forceReset?: boolean) => void
|
||||
): void;
|
||||
(data: Data, delta: Delta, reload: (forceReset?: boolean) => void): Data;
|
||||
}
|
||||
|
||||
interface GetData<QueryData, Data> {
|
||||
@ -105,14 +99,12 @@ function makeDataProviderInternal<QueryData, Data, SubscriptionData, Delta>(
|
||||
data = getData(res.data);
|
||||
// if there was some updates received from subscription during initial query loading apply them on just received data
|
||||
if (data && updateQueue && updateQueue.length > 0) {
|
||||
data = produce(data, (draft) => {
|
||||
while (updateQueue.length) {
|
||||
const delta = updateQueue.shift();
|
||||
if (delta) {
|
||||
update(draft, delta, reload);
|
||||
}
|
||||
while (updateQueue.length) {
|
||||
const delta = updateQueue.shift();
|
||||
if (delta) {
|
||||
data = update(data, delta, reload);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// if error will occur data provider stops subscription
|
||||
@ -168,9 +160,7 @@ function makeDataProviderInternal<QueryData, Data, SubscriptionData, Delta>(
|
||||
if (loading || !data) {
|
||||
updateQueue.push(delta);
|
||||
} else {
|
||||
const newData = produce(data, (draft) => {
|
||||
update(draft, delta, reload);
|
||||
});
|
||||
const newData = update(data, delta, reload);
|
||||
if (newData === data) {
|
||||
return;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ module.exports = {
|
||||
yellow: '#DFFF0B',
|
||||
mint: '#00F780',
|
||||
pink: '#FF077F',
|
||||
blue: '#2E6DE5',
|
||||
},
|
||||
fontSize: {
|
||||
...theme.fontSize,
|
||||
|
@ -4,6 +4,7 @@ import type { TradeFields } from './__generated__/TradeFields';
|
||||
import type { Trades } from './__generated__/Trades';
|
||||
import type { TradesSub } from './__generated__/TradesSub';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import produce from 'immer';
|
||||
|
||||
export const MAX_TRADES = 50;
|
||||
|
||||
@ -52,17 +53,18 @@ export const sortTrades = (trades: TradeFields[]) => {
|
||||
);
|
||||
};
|
||||
|
||||
const update = (draft: TradeFields[], delta: TradeFields[]) => {
|
||||
const incoming = sortTrades(delta);
|
||||
const update = (data: TradeFields[], delta: TradeFields[]) =>
|
||||
produce(data, (draft) => {
|
||||
const incoming = sortTrades(delta);
|
||||
|
||||
// Add new trades to the top
|
||||
draft.unshift(...incoming);
|
||||
// Add new trades to the top
|
||||
draft.unshift(...incoming);
|
||||
|
||||
// Remove old trades from the bottom
|
||||
if (draft.length > MAX_TRADES) {
|
||||
draft.splice(MAX_TRADES, draft.length - MAX_TRADES);
|
||||
}
|
||||
};
|
||||
// Remove old trades from the bottom
|
||||
if (draft.length > MAX_TRADES) {
|
||||
draft.splice(MAX_TRADES, draft.length - MAX_TRADES);
|
||||
}
|
||||
});
|
||||
|
||||
const getData = (responseData: Trades): TradeFields[] | null =>
|
||||
responseData.market ? responseData.market.trades : null;
|
||||
|
25
libs/ui-toolkit/src/components/theme-switcher/icons.tsx
Normal file
25
libs/ui-toolkit/src/components/theme-switcher/icons.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
export const SunIcon = () => (
|
||||
<svg viewBox="0 0 45 45" className="w-32 h-32">
|
||||
<g>
|
||||
<path
|
||||
d="M22.5 27.79a5.29 5.29 0 1 0 0-10.58 5.29 5.29 0 0 0 0 10.58Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
<path
|
||||
d="M15.01 22.5H10M35 22.5h-5.01M22.5 29.99V35M22.5 10v5.01M17.21 27.79l-3.55 3.55M31.34 13.66l-3.55 3.55M27.79 27.79l3.55 3.55M13.66 13.66l3.55 3.55"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.3"
|
||||
strokeMiterlimit="10"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const MoonIcon = () => (
|
||||
<svg viewBox="0 0 45 45" className="w-32 h-32">
|
||||
<path
|
||||
d="M28.75 11.69A12.39 12.39 0 0 0 22.5 10a12.5 12.5 0 1 0 0 25c2.196 0 4.353-.583 6.25-1.69A12.46 12.46 0 0 0 35 22.5a12.46 12.46 0 0 0-6.25-10.81Zm-6.25 22a11.21 11.21 0 0 1-11.2-11.2 11.21 11.21 0 0 1 11.2-11.2c1.246 0 2.484.209 3.66.62a13.861 13.861 0 0 0-5 10.58 13.861 13.861 0 0 0 5 10.58 11.078 11.078 0 0 1-3.66.63v-.01Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
@ -1 +1,2 @@
|
||||
export * from './theme-switcher';
|
||||
export * from './icons';
|
||||
|
@ -1,34 +1,31 @@
|
||||
import classNames from 'classnames';
|
||||
import { SunIcon, MoonIcon } from './icons';
|
||||
|
||||
export const ThemeSwitcher = ({
|
||||
onToggle,
|
||||
className,
|
||||
sunClassName = '',
|
||||
moonClassName = '',
|
||||
}: {
|
||||
onToggle: () => void;
|
||||
className?: string;
|
||||
}) => (
|
||||
<button type="button" onClick={() => onToggle()} className={className}>
|
||||
<span className="dark:hidden text-black">
|
||||
<svg viewBox="0 0 45 45" className="w-32 h-32">
|
||||
<g>
|
||||
<path
|
||||
d="M22.5 27.79a5.29 5.29 0 1 0 0-10.58 5.29 5.29 0 0 0 0 10.58Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
<path
|
||||
d="M15.01 22.5H10M35 22.5h-5.01M22.5 29.99V35M22.5 10v5.01M17.21 27.79l-3.55 3.55M31.34 13.66l-3.55 3.55M27.79 27.79l3.55 3.55M13.66 13.66l3.55 3.55"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.3"
|
||||
strokeMiterlimit="10"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="hidden dark:inline text-white">
|
||||
<svg viewBox="0 0 45 45" className="w-32 h-32">
|
||||
<path
|
||||
d="M28.75 11.69A12.39 12.39 0 0 0 22.5 10a12.5 12.5 0 1 0 0 25c2.196 0 4.353-.583 6.25-1.69A12.46 12.46 0 0 0 35 22.5a12.46 12.46 0 0 0-6.25-10.81Zm-6.25 22a11.21 11.21 0 0 1-11.2-11.2 11.21 11.21 0 0 1 11.2-11.2c1.246 0 2.484.209 3.66.62a13.861 13.861 0 0 0-5 10.58 13.861 13.861 0 0 0 5 10.58 11.078 11.078 0 0 1-3.66.63v-.01Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
sunClassName?: string;
|
||||
moonClassName?: string;
|
||||
}) => {
|
||||
const sunClasses = classNames('dark:hidden text-black', sunClassName);
|
||||
const moonClasses = classNames(
|
||||
'hidden dark:inline text-white',
|
||||
moonClassName
|
||||
);
|
||||
|
||||
return (
|
||||
<button type="button" onClick={() => onToggle()} className={className}>
|
||||
<span className={sunClasses}>
|
||||
<SunIcon />
|
||||
</span>
|
||||
<span className={moonClasses}>
|
||||
<MoonIcon />
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user