diff options
author | Brandon Millman <brandon@0xproject.com> | 2018-04-06 03:15:16 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-06 03:15:16 +0800 |
commit | 21dc94b709b9a3dbe292287fb95aacddcf0175f1 (patch) | |
tree | c8997715956a3c12a1a43a920e424fc47c828913 | |
parent | d6176872f7041e2cd1d7ecfb12b0f2323c3459ad (diff) | |
parent | 250d97a7c4eacceb8d6be0b23a640e22cec5a43c (diff) | |
download | dexon-sol-tools-21dc94b709b9a3dbe292287fb95aacddcf0175f1.tar.gz dexon-sol-tools-21dc94b709b9a3dbe292287fb95aacddcf0175f1.tar.zst dexon-sol-tools-21dc94b709b9a3dbe292287fb95aacddcf0175f1.zip |
Merge pull request #503 from 0xProject/feature/website/relayer-grid
Implement initial relayer grid
7 files changed, 294 insertions, 11 deletions
diff --git a/packages/website/ts/components/portal.tsx b/packages/website/ts/components/portal.tsx index ceb0ecc72..b79f5e288 100644 --- a/packages/website/ts/components/portal.tsx +++ b/packages/website/ts/components/portal.tsx @@ -15,6 +15,7 @@ import { EthWrappers } from 'ts/components/eth_wrappers'; import { FillOrder } from 'ts/components/fill_order'; import { Footer } from 'ts/components/footer'; import { PortalMenu } from 'ts/components/portal_menu'; +import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; import { TokenBalances } from 'ts/components/token_balances'; import { TopBar } from 'ts/components/top_bar/top_bar'; import { TradeHistory } from 'ts/components/trade_history/trade_history'; @@ -155,6 +156,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( this.props.dispatcher, ); + const isDevelopment = configs.ENVIRONMENT === Environments.DEVELOPMENT; const portalStyle: React.CSSProperties = { minHeight: '100vh', display: 'flex', @@ -204,12 +206,18 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { <div className="py2" style={{ backgroundColor: colors.grey50 }}> {this.props.blockchainIsLoaded ? ( <Switch> - {configs.ENVIRONMENT === Environments.DEVELOPMENT && ( + {isDevelopment && ( <Route path={`${WebsitePaths.Portal}/wallet`} render={this._renderWallet.bind(this)} /> )} + {isDevelopment && ( + <Route + path={`${WebsitePaths.Portal}/relayers`} + render={this._renderRelayers.bind(this)} + /> + )} <Route path={`${WebsitePaths.Portal}/weth`} render={this._renderEthWrapper.bind(this)} @@ -313,6 +321,15 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { </div> ); } + private _renderRelayers() { + return ( + <div className="flex flex-center"> + <div className="mx-auto" style={{ width: 800 }}> + <RelayerIndex networkId={this.props.networkId} /> + </div> + </div> + ); + } private _renderEthWrapper() { return ( <EthWrappers diff --git a/packages/website/ts/components/portal_menu.tsx b/packages/website/ts/components/portal_menu.tsx index 9ab611556..2b4d7eea2 100644 --- a/packages/website/ts/components/portal_menu.tsx +++ b/packages/website/ts/components/portal_menu.tsx @@ -59,14 +59,24 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState {this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')} </MenuItem> {configs.ENVIRONMENT === Environments.DEVELOPMENT && ( - <MenuItem - style={this.props.menuItemStyle} - className="py2" - to={`${WebsitePaths.Portal}/wallet`} - onClick={this.props.onClick.bind(this)} - > - {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')} - </MenuItem> + <div> + <MenuItem + style={this.props.menuItemStyle} + className="py2" + to={`${WebsitePaths.Portal}/wallet`} + onClick={this.props.onClick.bind(this)} + > + {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')} + </MenuItem> + <MenuItem + style={this.props.menuItemStyle} + className="py2" + to={`${WebsitePaths.Portal}/relayers`} + onClick={this.props.onClick.bind(this)} + > + {this._renderMenuItemWithIcon('Relayers', 'zmdi-input-antenna')} + </MenuItem> + </div> )} </div> ); diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx new file mode 100644 index 000000000..530576828 --- /dev/null +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -0,0 +1,84 @@ +import { colors, Styles } from '@0xproject/react-shared'; +import * as _ from 'lodash'; +import { GridTile } from 'material-ui/GridList'; +import * as React from 'react'; + +import { TopTokens } from 'ts/components/relayer_index/relayer_top_tokens'; +import { TokenIcon } from 'ts/components/ui/token_icon'; +import { RelayerInfo, Token } from 'ts/types'; + +export interface RelayerGridTileProps { + relayerInfo: RelayerInfo; + networkId: number; +} + +const styles: Styles = { + root: { + backgroundColor: colors.white, + borderBottomRightRadius: 10, + borderBottomLeftRadius: 10, + borderTopRightRadius: 10, + borderTopLeftRadius: 10, + boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`, + overflow: 'hidden', + boxSizing: 'border-box', + }, + innerDiv: { + padding: 6, + height: '100%', + boxSizing: 'border-box', + }, + header: { + height: '50%', + width: '100%', + objectFit: 'cover', + borderBottomRightRadius: 4, + borderBottomLeftRadius: 4, + borderTopRightRadius: 4, + borderTopLeftRadius: 4, + }, + body: { + paddingLeft: 6, + paddingRight: 6, + height: '50%', + width: '100%', + boxSizing: 'border-box', + }, + marketShareBar: { + height: 14, + width: '100%', + backgroundColor: colors.mediumBlue, + }, + subLabel: { + fontSize: 12, + color: colors.lightGrey, + }, + relayerNameLabel: { + fontSize: 16, + fontWeight: 'bold', + color: colors.black, + }, +}; + +export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (props: RelayerGridTileProps) => { + return ( + <GridTile style={styles.root}> + <div style={styles.innerDiv}> + <img src={props.relayerInfo.headerUrl} style={styles.header} /> + <div style={styles.body}> + <div className="py1" style={styles.relayerNameLabel}> + {props.relayerInfo.name} + </div> + <div style={styles.marketShareBar} /> + <div className="py1" style={styles.subLabel}> + Market share + </div> + <TopTokens tokens={props.relayerInfo.topTokens} networkId={props.networkId} /> + <div className="py1" style={styles.subLabel}> + Top tokens + </div> + </div> + </div> + </GridTile> + ); +}; diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx new file mode 100644 index 000000000..db3cf07b5 --- /dev/null +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -0,0 +1,118 @@ +import { colors, Styles } from '@0xproject/react-shared'; +import { GridList } from 'material-ui/GridList'; +import * as React from 'react'; + +import { RelayerGridTile } from 'ts/components/relayer_index/relayer_grid_tile'; +import { RelayerInfo } from 'ts/types'; + +export interface RelayerIndexProps { + networkId: number; +} + +const styles: Styles = { + root: { + width: '100%', + }, + item: { + backgroundColor: colors.white, + borderBottomRightRadius: 10, + borderBottomLeftRadius: 10, + borderTopRightRadius: 10, + borderTopLeftRadius: 10, + boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`, + overflow: 'hidden', + padding: 4, + }, +}; + +// TODO: replace fake data with real, remote data +const topTokens = [ + { + address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba', + decimals: 18, + iconUrl: '/images/token_icons/makerdao.png', + isRegistered: true, + isTracked: true, + name: 'Maker DAO', + symbol: 'MKR', + }, + { + address: '0x323b5d4c32345ced77393b3530b1eed0f346429d', + decimals: 18, + iconUrl: '/images/token_icons/melon.png', + isRegistered: true, + isTracked: true, + name: 'Melon Token', + symbol: 'MLN', + }, + { + address: '0xb18845c260f680d5b9d84649638813e342e4f8c9', + decimals: 18, + iconUrl: '/images/token_icons/augur.png', + isRegistered: true, + isTracked: true, + name: 'Augur Reputation Token', + symbol: 'REP', + }, +]; + +const relayerInfos: RelayerInfo[] = [ + { + id: '1', + headerUrl: '/images/og_image.png', + name: 'Radar Relay', + marketShare: 0.5, + topTokens, + }, + { + id: '2', + headerUrl: '/images/og_image.png', + name: 'Paradex', + marketShare: 0.5, + topTokens, + }, + { + id: '3', + headerUrl: '/images/og_image.png', + name: 'yo', + marketShare: 0.5, + topTokens, + }, + { + id: '4', + headerUrl: '/images/og_image.png', + name: 'test', + marketShare: 0.5, + topTokens, + }, + { + id: '5', + headerUrl: '/images/og_image.png', + name: 'blahg', + marketShare: 0.5, + topTokens, + }, + { + id: '6', + headerUrl: '/images/og_image.png', + name: 'hello', + marketShare: 0.5, + topTokens, + }, +]; + +const CELL_HEIGHT = 260; +const NUMBER_OF_COLUMNS = 4; +const GRID_PADDING = 16; + +export const RelayerIndex: React.StatelessComponent<RelayerIndexProps> = (props: RelayerIndexProps) => { + return ( + <div style={styles.root}> + <GridList cellHeight={CELL_HEIGHT} cols={NUMBER_OF_COLUMNS} padding={GRID_PADDING} style={styles.gridList}> + {relayerInfos.map((relayerInfo: RelayerInfo) => ( + <RelayerGridTile key={relayerInfo.id} relayerInfo={relayerInfo} networkId={props.networkId} /> + ))} + </GridList> + </div> + ); +}; diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx new file mode 100644 index 000000000..233590b78 --- /dev/null +++ b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx @@ -0,0 +1,46 @@ +import { colors, EtherscanLinkSuffixes, Styles, utils as sharedUtils } from '@0xproject/react-shared'; +import * as _ from 'lodash'; +import * as React from 'react'; + +import { TokenIcon } from 'ts/components/ui/token_icon'; +import { Token } from 'ts/types'; + +export interface TopTokensProps { + tokens: Token[]; + networkId: number; +} + +const styles: Styles = { + tokenLabel: { + textDecoration: 'none', + color: colors.mediumBlue, + }, + followingTokenLabel: { + paddingLeft: 16, + }, +}; + +export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTokensProps) => { + return ( + <div className="flex"> + {_.map(props.tokens, (token: Token, index: number) => { + const firstItemStyle = { ...styles.tokenLabel, ...styles.followingTokenLabel }; + const style = index !== 0 ? firstItemStyle : styles.tokenLabel; + return ( + <a + key={token.address} + href={tokenLinkFromToken(token, props.networkId)} + target="_blank" + style={style} + > + {token.symbol} + </a> + ); + })} + </div> + ); +}; + +function tokenLinkFromToken(token: Token, networkId: number) { + return sharedUtils.getEtherScanLinkIfExists(token.address, networkId, EtherscanLinkSuffixes.Address); +} diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 64e8bb53f..d3dc8e3dd 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -71,7 +71,7 @@ interface AccessoryItemConfig { } const styles: Styles = { - wallet: { + root: { width: 346, backgroundColor: colors.white, borderBottomRightRadius: 10, @@ -178,7 +178,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> { } public render() { const isReadyToRender = this.props.blockchainIsLoaded && this.props.blockchainErr === BlockchainErrs.NoError; - return <div style={styles.wallet}>{isReadyToRender && this._renderRows()}</div>; + return <div style={styles.root}>{isReadyToRender && this._renderRows()}</div>; } private _renderRows() { const isAddressAvailable = !_.isEmpty(this.props.userAddress); diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 901483327..dba59f704 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -490,4 +490,12 @@ export interface TokenState { allowance: BigNumber; isLoaded: boolean; } + +export interface RelayerInfo { + headerUrl: string; + id: string; + name: string; + marketShare: number; + topTokens: Token[]; +} // tslint:disable:max-file-line-count |