Feature/simple trading drawer (#435)

* feat(simple-trading-app): add drawer component to ui-toolkit

* feat(simple-trading-app): use drawer component and add navigation routes

* feat(simple-trading-app): move drawer out of ui-toolkit and into simple trading

* feat(simple-trading-app): remove suspense for now as nothing gets lazy loaded

* feat(simple-trading-app): add simple market list into routes
This commit is contained in:
Elmar 2022-05-23 10:43:08 +01:00 committed by GitHub
parent 497d3738ce
commit d9fccb137e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 300 additions and 24 deletions

View File

@ -1,4 +1,4 @@
import { useState, useMemo } from 'react';
import React, { useState, useMemo, useEffect } from 'react';
import { ApolloProvider } from '@apollo/client';
import { ThemeContext } from '@vegaprotocol/react-helpers';
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
@ -9,14 +9,14 @@ import {
VegaManageDialog,
VegaWalletProvider,
} from '@vegaprotocol/wallet';
// import { DealTicketContainer } from './components/deal-ticket';
import { VegaWalletConnectButton } from './components/vega-wallet-connect-button';
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
import { Connectors } from './lib/vega-connectors';
import '../styles.scss';
import { AppLoader } from './components/app-loader';
import SimpleMarketList from './components/simple-market-list';
import { Main } from './components/main';
import { DrawerToggle, DRAWER_TOGGLE_VARIANTS } from './components/drawer';
import { useLocation } from 'react-router-dom';
function App() {
const [theme, toggleTheme] = useThemeSwitcher();
@ -27,13 +27,28 @@ function App() {
const client = useMemo(() => createClient(DATA_SOURCES.dataNodeUrl), []);
const [menuOpen, setMenuOpen] = useState(false);
const onToggle = () => setMenuOpen(!menuOpen);
const location = useLocation();
useEffect(() => {
setMenuOpen(false);
}, [location]);
return (
<ThemeContext.Provider value={theme}>
<ApolloProvider client={client}>
<VegaWalletProvider>
<AppLoader>
<div className="h-full max-h-full dark:bg-black dark:text-white-60 bg-white text-black-60 grid md:grid-rows-[min-content_1fr_min-content] lg:grid-cols-[375px_1fr] md:grid-cols-[200px_1fr] sm:grid-rows-[min-content_min-content_1fr_min-content]">
<div className="flex items-stretch border-b-[7px] border-vega-yellow md:col-span-3">
<div className="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-center gap-4 ml-auto mr-8">
<VegaWalletConnectButton
setConnectDialog={(open) =>
@ -47,24 +62,8 @@ function App() {
</div>
</div>
<aside className="md:col-start-1 md:col-end-1 md:row-start-2 md:row-end-2">
<ul>
<li>{t('Markets')}</li>
<li>{t('Trade')}</li>
<li>{t('Liquid')}</li>
<li>{t('Markets')}</li>
</ul>
</aside>
<div className="md:col-start-2 md:col-end-2 md:row-start-2 md:row-end-2 overflow-auto">
<SimpleMarketList />
{/*<DealTicketContainer
marketId={
'0e4c4e0ce6626ea5c6bf5b5b510afadb3c91627aa9ff61e4c7e37ef8394f2c6f'
}
/>*/}
</div>
<Main isMenuOpen={menuOpen} onToggle={onToggle} />
<footer className="md:col-span-3">®</footer>
<VegaConnectDialog
connectors={Connectors}
dialogOpen={vegaWallet.connect}

View File

@ -0,0 +1,14 @@
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">{children}</div>
);

View File

@ -0,0 +1,38 @@
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>
);
};

View File

@ -0,0 +1,42 @@
import * as React from 'react';
import classNames from 'classnames';
import { Button, Icon } from '@vegaprotocol/ui-toolkit';
import { IconNames } from '@blueprintjs/icons';
import type { IconName } from '@vegaprotocol/ui-toolkit';
import { useEffect, useState } from 'react';
export const enum DRAWER_TOGGLE_VARIANTS {
OPEN = 'open',
CLOSE = 'close',
}
interface Props {
onToggle: React.MouseEventHandler<HTMLButtonElement>;
variant: DRAWER_TOGGLE_VARIANTS.OPEN | DRAWER_TOGGLE_VARIANTS.CLOSE;
className?: string;
}
export const DrawerToggle = ({
onToggle,
variant = DRAWER_TOGGLE_VARIANTS.CLOSE,
className,
}: Props) => {
const [iconName, setIconName] = useState(IconNames.MENU);
const classes = classNames('md:hidden', {
[className as string]: className,
});
useEffect(() => {
if (variant === DRAWER_TOGGLE_VARIANTS.OPEN) {
setIconName(IconNames.MENU);
} else {
setIconName(IconNames.CROSS);
}
}, [variant]);
return (
<Button variant="inline" className={classes} onClick={onToggle}>
<Icon name={iconName as IconName} />
</Button>
);
};

View File

@ -0,0 +1,66 @@
import * as React from 'react';
import { theme } from '@vegaprotocol/tailwindcss-config';
import type { ReactElement } from 'react';
import { useEffect } from 'react';
import Drawer from '@mui/material/Drawer';
interface Props {
children?: ReactElement | ReactElement[];
isMenuOpen?: boolean;
onToggle(): void;
}
export const NavigationDrawer = ({
isMenuOpen = false,
onToggle,
children,
}: Props) => {
const [windowSize, setWindowSize] = React.useState({
width: window.innerWidth,
height: window.innerHeight,
});
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);
}
// 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',
};
return (
<Drawer
classes={drawerRootClasses}
variant={isMobile ? 'temporary' : 'permanent'}
open={isMobile ? isMenuOpen : true}
onClose={onToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
{children}
</Drawer>
);
};

View File

@ -0,0 +1,4 @@
export * from './drawer';
export * from './drawer-menu';
export * from './drawer-toggle';
export * from './drawer-container';

View File

@ -0,0 +1,62 @@
import React from 'react';
import { useRoutes, NavLink } from 'react-router-dom';
import {
NavigationDrawer,
DrawerWrapper,
DrawerContainer,
DrawerToggle,
DRAWER_TOGGLE_VARIANTS,
} from '../drawer';
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>
);
interface Props {
onToggle(): void;
isMenuOpen: boolean;
}
export const Main = ({ onToggle, isMenuOpen }: Props) => {
return (
<DrawerWrapper>
<NavigationDrawer onToggle={onToggle} isMenuOpen={isMenuOpen}>
<DrawerToggle
onToggle={onToggle}
variant={DRAWER_TOGGLE_VARIANTS.CLOSE}
className="self-end p-16"
/>
<Menu />
</NavigationDrawer>
<DrawerContainer>
<AppRouter />
</DrawerContainer>
</DrawerWrapper>
);
};

View File

@ -1 +1 @@
export { default } from './simple-market-list';
export { default as SimpleMarketList } from './simple-market-list';

View File

@ -0,0 +1 @@
export * from './router-config';

View File

@ -0,0 +1,50 @@
import { t } from '@vegaprotocol/react-helpers';
import { DealTicketContainer } from '../components/deal-ticket';
import { SimpleMarketList } from '../components/simple-market-list';
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,
name: 'Markets',
text: t('Markets'),
element: <SimpleMarketList />,
},
{
path: ROUTES.TRADING,
name: 'Trading',
text: t('Trading'),
element: (
<DealTicketContainer
marketId={
'41013c28d53a72225c07cf2660cdd415d9dd0e9317ec4574e77592332db35596'
}
/>
),
},
{
path: ROUTES.LIQUIDITY,
name: 'Liquidity',
text: t('Liquidity'),
element: <div>Liquidity</div>,
},
{
path: ROUTES.PORTFOLIO,
name: 'Portfolio',
text: t('Portfolio'),
element: <div>Portfolio</div>,
},
];