diff options
Diffstat (limited to 'packages/website/ts')
17 files changed, 222 insertions, 178 deletions
diff --git a/packages/website/ts/components/generate_order/asset_picker.tsx b/packages/website/ts/components/generate_order/asset_picker.tsx index 87618f1e0..0f569e1ad 100644 --- a/packages/website/ts/components/generate_order/asset_picker.tsx +++ b/packages/website/ts/components/generate_order/asset_picker.tsx @@ -9,6 +9,7 @@ import { TokenIcon } from 'ts/components/ui/token_icon'; import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; import { Dispatcher } from 'ts/redux/dispatcher'; import { DialogConfigs, Token, TokenByAddress, TokenVisibility } from 'ts/types'; +import { constants } from 'ts/utils/constants'; const TOKEN_ICON_DIMENSION = 100; const TILE_DIMENSION = 146; @@ -116,7 +117,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt private _renderAssetPicker(): React.ReactNode { return ( <div - className="clearfix flex flex-wrap" + className="flex flex-wrap" style={{ overflowY: 'auto', maxWidth: 720, @@ -134,7 +135,9 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt const gridTiles = _.map(this.props.tokenByAddress, (token: Token, address: string) => { if ( (this.props.tokenVisibility === TokenVisibility.TRACKED && !token.isTracked) || - (this.props.tokenVisibility === TokenVisibility.UNTRACKED && token.isTracked) + (this.props.tokenVisibility === TokenVisibility.UNTRACKED && token.isTracked) || + token.symbol === constants.ZRX_TOKEN_SYMBOL || + token.symbol === constants.ETHER_TOKEN_SYMBOL ) { return null; // Skip } @@ -151,7 +154,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt height: TILE_DIMENSION, ...tileStyles, }} - className="p2 flex flex-column items-center" + className="p2 flex sm-col-6 md-col-3 lg-col-3 flex-column items-center mx-auto" onClick={this._onChooseToken.bind(this, address)} onMouseEnter={this._onToggleHover.bind(this, address, true)} onMouseLeave={this._onToggleHover.bind(this, address, false)} @@ -159,7 +162,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt <div className="p1"> <TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} /> </div> - <div className="center">{token.name}</div> + <div className="center">{token.symbol}</div> </div> ); }); @@ -178,7 +181,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt height: TILE_DIMENSION, ...tileStyles, }} - className="p2 mx-auto" + className="p2 flex sm-col-6 md-col-3 lg-col-3 flex-column items-center mx-auto" onClick={this._onCustomAssetChosen.bind(this)} onMouseEnter={this._onToggleHover.bind(this, otherTokenKey, true)} onMouseLeave={this._onToggleHover.bind(this, otherTokenKey, false)} diff --git a/packages/website/ts/components/onboarding/onboarding_flow.tsx b/packages/website/ts/components/onboarding/onboarding_flow.tsx index 331899469..ec8d96191 100644 --- a/packages/website/ts/components/onboarding/onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/onboarding_flow.tsx @@ -42,7 +42,11 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> { onboardingElement = <Animation type="easeUpFromBottom">{this._renderOnboardignCard()}</Animation>; } else { onboardingElement = ( - <Popper referenceElement={this._getElementForStep()} placement={this._getCurrentStep().placement}> + <Popper + referenceElement={this._getElementForStep()} + placement={this._getCurrentStep().placement} + positionFixed={true} + > {this._renderPopperChildren.bind(this)} </Popper> ); diff --git a/packages/website/ts/components/portal/drawer_menu.tsx b/packages/website/ts/components/portal/drawer_menu.tsx index 4bd07769f..205a60afc 100644 --- a/packages/website/ts/components/portal/drawer_menu.tsx +++ b/packages/website/ts/components/portal/drawer_menu.tsx @@ -65,7 +65,7 @@ interface HeaderProps { const Header = (props: HeaderProps) => { return ( <div className="flex flex-center py4"> - <div className="flex flex-column mx-auto"> + <div className="flex flex-column mx-auto items-center"> <Identicon address={props.userAddress} diameter={IDENTICON_DIAMETER} style={styles.identicon} /> <Text className="pt2" fontColor={colors.white}> {props.displayMessage} diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 11b3b43f4..4166fde53 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -1,4 +1,4 @@ -import { colors, constants as sharedConstants, Styles } from '@0xproject/react-shared'; +import { colors, constants as sharedConstants } from '@0xproject/react-shared'; import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; @@ -107,26 +107,7 @@ const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded); const LEFT_COLUMN_WIDTH = 346; const MENU_PADDING_LEFT = 185; const LARGE_LAYOUT_MAX_WIDTH = 1200; - -const styles: Styles = { - root: { - width: '100%', - height: '100%', - backgroundColor: colors.lightestGrey, - }, - body: { - height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, - }, - leftColumn: { - width: LEFT_COLUMN_WIDTH, - height: '100%', - }, - scrollContainer: { - height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, - WebkitOverflowScrolling: 'touch', - overflow: 'auto', - }, -}; +const LARGE_LAYOUT_MARGIN = 30; export class Portal extends React.Component<PortalProps, PortalState> { private _blockchain: Blockchain; @@ -245,7 +226,7 @@ export class Portal extends React.Component<PortalProps, PortalState> { ? TokenVisibility.UNTRACKED : TokenVisibility.TRACKED; return ( - <div style={styles.root}> + <Container> <DocumentTitle title="0x Portal DApp" /> <TopBar userAddress={this.props.userAddress} @@ -259,10 +240,14 @@ export class Portal extends React.Component<PortalProps, PortalState> { blockchain={this._blockchain} translate={this.props.translate} displayType={TopBarDisplayType.Expanded} - style={{ backgroundColor: colors.lightestGrey }} + style={{ + backgroundColor: colors.lightestGrey, + position: 'fixed', + zIndex: zIndex.topBar, + }} maxWidth={LARGE_LAYOUT_MAX_WIDTH} /> - <div id="portal" style={styles.body}> + <Container marginTop={TOP_BAR_HEIGHT} minHeight="100vh" backgroundColor={colors.lightestGrey}> <Switch> <Route path={`${WebsitePaths.Portal}/:route`} render={this._renderOtherRoutes.bind(this)} /> <Route @@ -301,13 +286,8 @@ export class Portal extends React.Component<PortalProps, PortalState> { tokenByAddress={this.props.tokenByAddress} tokenVisibility={tokenVisibility} /> - </div> - <PortalOnboardingFlow - blockchain={this._blockchain} - trackedTokenStateByAddress={this.state.trackedTokenStateByAddress} - refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)} - /> - </div> + </Container> + </Container> ); } private _renderMainRoute(): React.ReactNode { @@ -341,41 +321,48 @@ export class Portal extends React.Component<PortalProps, PortalState> { } private _renderWallet(): React.ReactNode { const startOnboarding = this._renderStartOnboarding(); - const isMobile = this.props.screenWidth === ScreenWidths.Sm; + const isMobile = utils.isMobile(this.props.screenWidth); // We need room to scroll down for mobile onboarding const marginBottom = isMobile ? '200px' : '15px'; return ( <div> - {isMobile && <Container marginBottom="15px">{startOnboarding}</Container>} - <Container marginBottom={marginBottom}> - <Wallet - style={ - !isMobile && this.props.isPortalOnboardingShowing - ? { zIndex: zIndex.aboveOverlay, position: 'relative' } - : undefined - } - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this._blockchain} - blockchainIsLoaded={this.props.blockchainIsLoaded} - blockchainErr={this.props.blockchainErr} - dispatcher={this.props.dispatcher} - tokenByAddress={this.props.tokenByAddress} - trackedTokens={this._getCurrentTrackedTokens()} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - injectedProviderName={this.props.injectedProviderName} - providerType={this.props.providerType} - screenWidth={this.props.screenWidth} - location={this.props.location} - trackedTokenStateByAddress={this.state.trackedTokenStateByAddress} - onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} - onAddToken={this._onAddToken.bind(this)} - onRemoveToken={this._onRemoveToken.bind(this)} - refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)} - /> + <Container> + {isMobile && <Container marginBottom="15px">{startOnboarding}</Container>} + <Container marginBottom={marginBottom}> + <Wallet + style={ + !isMobile && this.props.isPortalOnboardingShowing + ? { zIndex: zIndex.aboveOverlay, position: 'relative' } + : undefined + } + userAddress={this.props.userAddress} + networkId={this.props.networkId} + blockchain={this._blockchain} + blockchainIsLoaded={this.props.blockchainIsLoaded} + blockchainErr={this.props.blockchainErr} + dispatcher={this.props.dispatcher} + tokenByAddress={this.props.tokenByAddress} + trackedTokens={this._getCurrentTrackedTokens()} + userEtherBalanceInWei={this.props.userEtherBalanceInWei} + lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} + injectedProviderName={this.props.injectedProviderName} + providerType={this.props.providerType} + screenWidth={this.props.screenWidth} + location={this.props.location} + trackedTokenStateByAddress={this.state.trackedTokenStateByAddress} + onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} + onAddToken={this._onAddToken.bind(this)} + onRemoveToken={this._onRemoveToken.bind(this)} + refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)} + /> + </Container> + {!isMobile && <Container marginTop="15px">{startOnboarding}</Container>} </Container> - {!isMobile && <Container marginTop="15px">{startOnboarding}</Container>} + <PortalOnboardingFlow + blockchain={this._blockchain} + trackedTokenStateByAddress={this.state.trackedTokenStateByAddress} + refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)} + /> </div> ); } @@ -551,7 +538,7 @@ export class Portal extends React.Component<PortalProps, PortalState> { private _renderRelayerIndexSection(): React.ReactNode { return ( <Section - header={<TextHeader labelText="Explore 0x Relayers" />} + header={<TextHeader labelText="0x Relayers" />} body={<RelayerIndex networkId={this.props.networkId} screenWidth={this.props.screenWidth} />} /> ); @@ -708,14 +695,23 @@ interface LargeLayoutProps { } const LargeLayout = (props: LargeLayoutProps) => { return ( - <div className="mx-auto flex flex-center" style={{ maxWidth: LARGE_LAYOUT_MAX_WIDTH }}> - <div className="flex-last px2"> - <div style={styles.leftColumn}>{props.left}</div> - </div> - <div className="flex-auto px2" style={styles.scrollContainer}> - {props.right} + <Container className="mx-auto flex flex-center" maxWidth={LARGE_LAYOUT_MAX_WIDTH}> + <div className="flex-last"> + <Container + width={LEFT_COLUMN_WIDTH} + position="fixed" + zIndex={zIndex.aboveTopBar} + marginLeft={LARGE_LAYOUT_MARGIN} + > + {props.left} + </Container> </div> - </div> + <Container className="flex-auto" marginLeft={LEFT_COLUMN_WIDTH + LARGE_LAYOUT_MARGIN}> + <Container className="flex-auto" marginLeft={LARGE_LAYOUT_MARGIN} marginRight={LARGE_LAYOUT_MARGIN}> + {props.right} + </Container> + </Container> + </Container> ); }; @@ -725,9 +721,7 @@ interface SmallLayoutProps { const SmallLayout = (props: SmallLayoutProps) => { return ( <div className="flex flex-center"> - <div className="flex-auto px3" style={styles.scrollContainer}> - {props.content} - </div> + <div className="flex-auto px3">{props.content}</div> </div> ); }; // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/portal/text_header.tsx b/packages/website/ts/components/portal/text_header.tsx index 4aabd47d0..853da3a29 100644 --- a/packages/website/ts/components/portal/text_header.tsx +++ b/packages/website/ts/components/portal/text_header.tsx @@ -1,21 +1,16 @@ -import { Styles } from '@0xproject/react-shared'; +import { colors } from '@0xproject/react-shared'; import * as React from 'react'; +import { Text } from 'ts/components/ui/text'; + export interface TextHeaderProps { labelText: string; } -const styles: Styles = { - title: { - fontWeight: 'bold', - fontSize: 20, - }, -}; - export const TextHeader = (props: TextHeaderProps) => { return ( - <div className="py3" style={styles.title}> + <Text className="pt3 pb2" fontWeight="bold" fontSize="16px" fontColor={colors.darkestGrey}> {props.labelText} - </div> + </Text> ); }; diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 23860856b..b26bf512b 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -1,6 +1,6 @@ import { constants as sharedConstants, Styles } from '@0xproject/react-shared'; import * as _ from 'lodash'; -import { GridTile } from 'material-ui/GridList'; +import { GridTile as PlainGridTile } from 'material-ui/GridList'; import * as React from 'react'; import { analytics } from 'ts/utils/analytics'; @@ -9,7 +9,9 @@ import { Container } from 'ts/components/ui/container'; import { Image } from 'ts/components/ui/image'; import { Island } from 'ts/components/ui/island'; import { colors } from 'ts/style/colors'; +import { styled } from 'ts/style/theme'; import { WebsiteBackendRelayerInfo } from 'ts/types'; +import { utils } from 'ts/utils/utils'; export interface RelayerGridTileProps { relayerInfo: WebsiteBackendRelayerInfo; @@ -19,29 +21,23 @@ export interface RelayerGridTileProps { const styles: Styles = { root: { boxSizing: 'border-box', + // All material UI components have position: relative + // which creates a new stacking context and makes z-index stuff impossible. So reset. + position: 'static', }, innerDiv: { - padding: 6, height: '100%', boxSizing: 'border-box', }, header: { height: '50%', width: '100%', - borderBottomRightRadius: 4, - borderBottomLeftRadius: 4, - borderTopRightRadius: 4, - borderTopLeftRadius: 4, - borderWidth: 1, - borderStyle: 'solid', - borderColor: colors.walletBorder, }, body: { - paddingLeft: 6, - paddingRight: 6, height: '50%', width: '100%', boxSizing: 'border-box', + padding: 12, }, weeklyTradeVolumeLabel: { fontSize: 14, @@ -58,7 +54,7 @@ const styles: Styles = { }, }; -const FALLBACK_IMG_SRC = '/images/landing/hero_chip_image.png'; +const FALLBACK_IMG_SRC = '/images/relayer_fallback.png'; const FALLBACK_PRIMARY_COLOR = colors.grey200; const NO_CONTENT_MESSAGE = '--'; const RELAYER_ICON_HEIGHT = '110px'; @@ -69,7 +65,10 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = ( const weeklyTxnVolume = props.relayerInfo.weeklyTxnVolume; const networkName = sharedConstants.NETWORK_NAME_BY_ID[props.networkId]; const eventLabel = `${props.relayerInfo.name}-${networkName}`; - const trackRelayerClick = () => analytics.logEvent('Portal', 'Relayer Click', eventLabel); + const onClick = () => { + analytics.logEvent('Portal', 'Relayer Click', eventLabel); + utils.openUrl(link); + }; const headerImageUrl = props.relayerInfo.logoImgUrl; const headerBackgroundColor = !_.isUndefined(headerImageUrl) && !_.isUndefined(props.relayerInfo.primaryColor) @@ -77,22 +76,17 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = ( : FALLBACK_PRIMARY_COLOR; return ( <Island style={styles.root} Component={GridTile}> - <div style={styles.innerDiv}> - <a href={link} target="_blank" style={{ textDecoration: 'none' }} onClick={trackRelayerClick}> - <div - className="flex items-center" - style={{ ...styles.header, backgroundColor: headerBackgroundColor }} - > - <Image - className="mx-auto" - src={props.relayerInfo.logoImgUrl} - fallbackSrc={FALLBACK_IMG_SRC} - height={RELAYER_ICON_HEIGHT} - /> - </div> - </a> + <div style={styles.innerDiv} onClick={onClick}> + <div className="flex items-center" style={{ ...styles.header, backgroundColor: headerBackgroundColor }}> + <Image + className="mx-auto" + src={props.relayerInfo.logoImgUrl} + fallbackSrc={FALLBACK_IMG_SRC} + height={RELAYER_ICON_HEIGHT} + /> + </div> <div style={styles.body}> - <div className="py1" style={styles.relayerNameLabel}> + <div className="pb1" style={styles.relayerNameLabel}> {props.relayerInfo.name} </div> <Section titleText="Weekly Trade Volume"> @@ -111,6 +105,14 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = ( ); }; +const GridTile = styled(PlainGridTile)` + cursor: pointer; + transition: transform 0.2s ease; + &:hover { + transform: translate(0px, -3px); + } +`; + interface SectionProps { titleText: string; children?: React.ReactNode; diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index d565eb608..4aea1bbbb 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -1,4 +1,3 @@ -import { Styles } from '@0xproject/react-shared'; import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; import { GridList } from 'material-ui/GridList'; @@ -6,7 +5,6 @@ import * as React from 'react'; import { RelayerGridTile } from 'ts/components/relayer_index/relayer_grid_tile'; import { Retry } from 'ts/components/ui/retry'; -import { colors } from 'ts/style/colors'; import { ScreenWidths, WebsiteBackendRelayerInfo } from 'ts/types'; import { backendClient } from 'ts/utils/backend_client'; @@ -20,22 +18,6 @@ interface RelayerIndexState { error?: Error; } -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, - }, -}; - const CELL_HEIGHT = 290; const NUMBER_OF_COLUMNS_LARGE = 3; const NUMBER_OF_COLUMNS_MEDIUM = 2; @@ -76,18 +58,16 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde } else { const numberOfColumns = this._numberOfColumnsForScreenWidth(this.props.screenWidth); return ( - <div style={styles.root}> - <GridList - cellHeight={CELL_HEIGHT} - cols={numberOfColumns} - padding={GRID_PADDING} - style={styles.gridList} - > - {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => ( - <RelayerGridTile key={index} relayerInfo={relayerInfo} networkId={this.props.networkId} /> - ))} - </GridList> - </div> + <GridList + cellHeight={CELL_HEIGHT} + cols={numberOfColumns} + padding={GRID_PADDING} + style={{ marginTop: -10, marginBottom: 0 }} + > + {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => ( + <RelayerGridTile key={index} relayerInfo={relayerInfo} networkId={this.props.networkId} /> + ))} + </GridList> ); } } diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx index b599e7123..f544fc924 100644 --- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx +++ b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx @@ -70,7 +70,10 @@ class TokenLink extends React.Component<TokenLinkProps, TokenLinkState> { }; const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId]; const eventLabel = `${this.props.tokenInfo.symbol}-${networkName}`; - const trackTokenClick = () => analytics.logEvent('Portal', 'Token Click', eventLabel); + const onClick = (event: React.MouseEvent<HTMLElement>) => { + event.stopPropagation(); + analytics.logEvent('Portal', 'Token Click', eventLabel); + }; return ( <a href={tokenLinkFromToken(this.props.tokenInfo, this.props.networkId)} @@ -78,7 +81,7 @@ class TokenLink extends React.Component<TokenLinkProps, TokenLinkState> { style={style} onMouseEnter={this._onToggleHover.bind(this, true)} onMouseLeave={this._onToggleHover.bind(this, false)} - onClick={trackTokenClick} + onClick={onClick} > {this.props.tokenInfo.symbol} </a> diff --git a/packages/website/ts/components/ui/animation.tsx b/packages/website/ts/components/ui/animation.tsx index cbda2993d..136f3d005 100644 --- a/packages/website/ts/components/ui/animation.tsx +++ b/packages/website/ts/components/ui/animation.tsx @@ -11,13 +11,15 @@ const PlainAnimation: React.StatelessComponent<AnimationProps> = props => <div { const appearFromBottomFrames = keyframes` from { - position: absolute; + position: fixed; bottom: -500px; + left: 0px; } to { - position: absolute; + position: fixed; bottom: 0px; + left: 0px; } `; diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx index 90aec0e7c..a747ef01f 100644 --- a/packages/website/ts/components/ui/container.tsx +++ b/packages/website/ts/components/ui/container.tsx @@ -15,6 +15,7 @@ export interface ContainerProps { borderRadius?: StringOrNum; maxWidth?: StringOrNum; width?: StringOrNum; + minHeight?: StringOrNum; isHidden?: boolean; className?: string; position?: 'absolute' | 'fixed' | 'relative' | 'unset'; diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index f88fd6c24..dc48d6619 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -29,6 +29,7 @@ import { WrapEtherItem } from 'ts/components/wallet/wrap_ether_item'; import { AllowanceToggle } from 'ts/containers/inputs/allowance_toggle'; import { Dispatcher } from 'ts/redux/dispatcher'; import { colors } from 'ts/style/colors'; +import { styled } from 'ts/style/theme'; import { BlockchainErrs, ProviderType, @@ -138,6 +139,12 @@ const USD_DECIMAL_PLACES = 2; const NO_ALLOWANCE_TOGGLE_SPACE_WIDTH = 56; const ACCOUNT_PATH = `${WebsitePaths.Portal}/account`; +const ActionButton = styled(FloatingActionButton)` + button { + position: static !important; + } +`; + export class Wallet extends React.Component<WalletProps, WalletState> { public static defaultProps = { style: {}, @@ -244,17 +251,12 @@ export class Wallet extends React.Component<WalletProps, WalletState> { <ListItem primaryText={ <div className="flex"> - <FloatingActionButton mini={true} zDepth={0} onClick={this.props.onAddToken}> + <ActionButton mini={true} zDepth={0} onClick={this.props.onAddToken}> <ContentAdd /> - </FloatingActionButton> - <FloatingActionButton - mini={true} - zDepth={0} - className="px1" - onClick={this.props.onRemoveToken} - > + </ActionButton> + <ActionButton mini={true} zDepth={0} className="px1" onClick={this.props.onRemoveToken}> <ContentRemove /> - </FloatingActionButton> + </ActionButton> <div style={{ paddingLeft: 10, @@ -309,7 +311,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> { wrappedEtherDirection: Side.Deposit, }; const key = ETHER_ITEM_KEY; - return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig, 'eth-row'); + return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig, false, 'eth-row'); } private _renderTokenRows(): React.ReactNode { const trackedTokens = this.props.trackedTokens; @@ -320,7 +322,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> { ); return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this)); } - private _renderTokenRow(token: Token, _index: number): React.ReactNode { + private _renderTokenRow(token: Token, index: number): React.ReactNode { const tokenState = this.props.trackedTokenStateByAddress[token.address]; if (_.isUndefined(tokenState)) { return null; @@ -348,12 +350,14 @@ export class Wallet extends React.Component<WalletProps, WalletState> { }, }; const key = token.address; + const isLastRow = index === this.props.trackedTokens.length - 1; return this._renderBalanceRow( key, icon, primaryText, secondaryText, accessoryItemConfig, + isLastRow, isWeth ? 'weth-row' : undefined, ); } @@ -363,13 +367,19 @@ export class Wallet extends React.Component<WalletProps, WalletState> { primaryText: React.ReactNode, secondaryText: React.ReactNode, accessoryItemConfig: AccessoryItemConfig, + isLastRow: boolean, className?: string, ): React.ReactNode { const shouldShowWrapEtherItem = !_.isUndefined(this.state.wrappedEtherDirection) && this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection && !_.isUndefined(this.props.userEtherBalanceInWei); - const additionalStyle = shouldShowWrapEtherItem ? walletItemStyles.focusedItem : styles.borderedItem; + let additionalStyle; + if (shouldShowWrapEtherItem) { + additionalStyle = walletItemStyles.focusedItem; + } else if (!isLastRow) { + additionalStyle = styles.borderedItem; + } const style = { ...styles.tokenItem, ...additionalStyle }; const etherToken = this._getEthToken(); return ( diff --git a/packages/website/ts/components/wallet/wallet_disconnected_item.tsx b/packages/website/ts/components/wallet/wallet_disconnected_item.tsx index 1015dce29..024b28544 100644 --- a/packages/website/ts/components/wallet/wallet_disconnected_item.tsx +++ b/packages/website/ts/components/wallet/wallet_disconnected_item.tsx @@ -3,7 +3,7 @@ import FlatButton from 'material-ui/FlatButton'; import * as React from 'react'; import { colors } from 'ts/style/colors'; -import { ProviderType } from 'ts/types'; +import { BrowserType, ProviderType } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { utils } from 'ts/utils/utils'; @@ -66,16 +66,35 @@ interface ProviderButtonProps { isExternallyInjectedProvider: boolean; } -const ProviderButton: React.StatelessComponent<ProviderButtonProps> = (props: ProviderButtonProps) => ( - <FlatButton - label={props.isExternallyInjectedProvider ? 'Please unlock account' : 'Get Metamask Wallet Extension'} - labelStyle={{ color: colors.black }} - labelPosition="after" - primary={true} - icon={<img src="/images/metamask_icon.png" width={METAMASK_ICON_WIDTH.toString()} />} - style={props.isExternallyInjectedProvider ? styles.button : { ...styles.button, ...styles.hrefAdjustment }} - href={props.isExternallyInjectedProvider ? undefined : constants.URL_METAMASK_CHROME_STORE} - target={props.isExternallyInjectedProvider ? undefined : '_blank'} - disabled={props.isExternallyInjectedProvider} - /> -); +const ProviderButton: React.StatelessComponent<ProviderButtonProps> = (props: ProviderButtonProps) => { + const browserType = utils.getBrowserType(); + let extensionLink; + if (!props.isExternallyInjectedProvider) { + switch (browserType) { + case BrowserType.Chrome: + extensionLink = constants.URL_METAMASK_CHROME_STORE; + break; + case BrowserType.Firefox: + extensionLink = constants.URL_METAMASK_FIREFOX_STORE; + break; + case BrowserType.Opera: + extensionLink = constants.URL_METAMASK_OPERA_STORE; + break; + default: + extensionLink = constants.URL_METAMASK_HOMEPAGE; + } + } + return ( + <FlatButton + label={props.isExternallyInjectedProvider ? 'Please unlock account' : 'Get Metamask Wallet Extension'} + labelStyle={{ color: colors.black }} + labelPosition="after" + primary={true} + icon={<img src="/images/metamask_icon.png" width={METAMASK_ICON_WIDTH.toString()} />} + style={props.isExternallyInjectedProvider ? styles.button : { ...styles.button, ...styles.hrefAdjustment }} + href={extensionLink} + target={props.isExternallyInjectedProvider ? undefined : '_blank'} + disabled={props.isExternallyInjectedProvider} + /> + ); +}; diff --git a/packages/website/ts/pages/jobs/open_positions.tsx b/packages/website/ts/pages/jobs/open_positions.tsx index f3d980315..e789795c1 100644 --- a/packages/website/ts/pages/jobs/open_positions.tsx +++ b/packages/website/ts/pages/jobs/open_positions.tsx @@ -11,6 +11,7 @@ import { colors } from 'ts/style/colors'; import { styled } from 'ts/style/theme'; import { ScreenWidths, WebsiteBackendJobInfo } from 'ts/types'; import { backendClient } from 'ts/utils/backend_client'; +import { utils } from 'ts/utils/utils'; const labelStyle = { fontFamily: 'Roboto Mono', fontSize: 18 }; const HEADER_TEXT = 'Open Positions'; @@ -161,7 +162,7 @@ export class OpenPositions extends React.Component<OpenPositionsProps, OpenPosit private _openJobInfoUrl(jobInfo: WebsiteBackendJobInfo): void { const url = jobInfo.url; - window.open(url, '_blank'); + utils.openUrl(url); } } diff --git a/packages/website/ts/style/z_index.ts b/packages/website/ts/style/z_index.ts index 0411cdd91..a3998f59b 100644 --- a/packages/website/ts/style/z_index.ts +++ b/packages/website/ts/style/z_index.ts @@ -1,5 +1,6 @@ export const zIndex = { topBar: 1100, + aboveTopBar: 1101, overlay: 1105, aboveOverlay: 1106, }; diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index d00154652..8a88c31b2 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -546,4 +546,11 @@ export interface WebsiteBackendJobInfo { office: string; url: string; } + +export enum BrowserType { + Chrome = 'Chrome', + Firefox = 'Firefox', + Opera = 'Opera', + Other = 'Other', +} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts index 25670ef27..a3f8eacb0 100644 --- a/packages/website/ts/utils/constants.ts +++ b/packages/website/ts/utils/constants.ts @@ -70,6 +70,9 @@ export const constants = { URL_GITHUB_ORG: 'https://github.com/0xProject', URL_GITHUB_WIKI: 'https://github.com/0xProject/wiki', URL_METAMASK_CHROME_STORE: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn', + URL_METAMASK_FIREFOX_STORE: 'https://addons.mozilla.org/en-US/firefox/addon/ether-metamask/', + URL_METAMASK_HOMEPAGE: 'https://metamask.io/', + URL_METAMASK_OPERA_STORE: 'https://addons.opera.com/en/extensions/details/metamask/', URL_MIST_DOWNLOAD: 'https://github.com/ethereum/mist/releases', URL_PARITY_CHROME_STORE: 'https://chrome.google.com/webstore/detail/parity-ethereum-integrati/himekenlppkgeaoeddcliojfddemadig', diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts index 0bd3dbcfa..ff06d923d 100644 --- a/packages/website/ts/utils/utils.ts +++ b/packages/website/ts/utils/utils.ts @@ -4,11 +4,13 @@ import { constants as sharedConstants, Networks } from '@0xproject/react-shared' import { ECSignature, Provider } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as bowser from 'bowser'; import deepEqual = require('deep-equal'); import * as _ from 'lodash'; import * as moment from 'moment'; import { BlockchainCallErrs, + BrowserType, Environments, Order, Providers, @@ -362,4 +364,21 @@ export const utils = { const formattedAmount = unitAmount.toFixed(precision); return `${formattedAmount} ${symbol}`; }, + openUrl(url: string): void { + window.open(url, '_blank'); + }, + isMobile(screenWidth: ScreenWidths): boolean { + return screenWidth === ScreenWidths.Sm; + }, + getBrowserType(): BrowserType { + if (bowser.chrome) { + return BrowserType.Chrome; + } else if (bowser.firefox) { + return BrowserType.Firefox; + } else if (bowser.opera) { + return BrowserType.Opera; + } else { + return BrowserType.Other; + } + }, }; |