aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/components/top_bar
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/components/top_bar')
-rw-r--r--packages/website/ts/components/top_bar/provider_display.tsx148
-rw-r--r--packages/website/ts/components/top_bar/provider_picker.tsx81
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx376
-rw-r--r--packages/website/ts/components/top_bar/top_bar_menu_item.tsx52
4 files changed, 657 insertions, 0 deletions
diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx
new file mode 100644
index 000000000..39e7f2a8c
--- /dev/null
+++ b/packages/website/ts/components/top_bar/provider_display.tsx
@@ -0,0 +1,148 @@
+import * as _ from 'lodash';
+import RaisedButton from 'material-ui/RaisedButton';
+import * as React from 'react';
+import { Blockchain } from 'ts/blockchain';
+import { ProviderPicker } from 'ts/components/top_bar/provider_picker';
+import { DropDown } from 'ts/components/ui/drop_down';
+import { Identicon } from 'ts/components/ui/identicon';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { ProviderType } from 'ts/types';
+import { colors } from 'ts/utils/colors';
+import { constants } from 'ts/utils/constants';
+import { utils } from 'ts/utils/utils';
+
+const IDENTICON_DIAMETER = 32;
+
+interface ProviderDisplayProps {
+ dispatcher: Dispatcher;
+ userAddress: string;
+ networkId: number;
+ injectedProviderName: string;
+ providerType: ProviderType;
+ onToggleLedgerDialog: () => void;
+ blockchain: Blockchain;
+}
+
+interface ProviderDisplayState {}
+
+export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
+ public render() {
+ const isAddressAvailable = !_.isEmpty(this.props.userAddress);
+ const isExternallyInjectedProvider = ProviderType.Injected && this.props.injectedProviderName !== '0x Public';
+ const displayAddress = isAddressAvailable
+ ? utils.getAddressBeginAndEnd(this.props.userAddress)
+ : isExternallyInjectedProvider ? 'Account locked' : '0x0000...0000';
+ // If the "injected" provider is our fallback public node, then we want to
+ // show the "connect a wallet" message instead of the providerName
+ const injectedProviderName = isExternallyInjectedProvider
+ ? this.props.injectedProviderName
+ : 'Connect a wallet';
+ const providerTitle =
+ this.props.providerType === ProviderType.Injected ? injectedProviderName : 'Ledger Nano S';
+ const hoverActiveNode = (
+ <div className="flex right lg-pr0 md-pr2 sm-pr2" style={{ paddingTop: 16 }}>
+ <div>
+ <Identicon address={this.props.userAddress} diameter={IDENTICON_DIAMETER} />
+ </div>
+ <div style={{ marginLeft: 12, paddingTop: 1 }}>
+ <div style={{ fontSize: 12, color: colors.amber800 }}>{providerTitle}</div>
+ <div style={{ fontSize: 14 }}>{displayAddress}</div>
+ </div>
+ <div
+ style={{ borderLeft: `1px solid ${colors.grey300}`, marginLeft: 17, paddingTop: 1 }}
+ className="px2"
+ >
+ <i style={{ fontSize: 30, color: colors.grey300 }} className="zmdi zmdi zmdi-chevron-down" />
+ </div>
+ </div>
+ );
+ const hasInjectedProvider =
+ this.props.injectedProviderName !== '0x Public' && this.props.providerType === ProviderType.Injected;
+ const hasLedgerProvider = this.props.providerType === ProviderType.Ledger;
+ const horizontalPosition = hasInjectedProvider || hasLedgerProvider ? 'left' : 'middle';
+ return (
+ <div style={{ width: 'fit-content', height: 48, float: 'right' }}>
+ <DropDown
+ hoverActiveNode={hoverActiveNode}
+ popoverContent={this.renderPopoverContent(hasInjectedProvider, hasLedgerProvider)}
+ anchorOrigin={{ horizontal: horizontalPosition, vertical: 'bottom' }}
+ targetOrigin={{ horizontal: horizontalPosition, vertical: 'top' }}
+ zDepth={1}
+ />
+ </div>
+ );
+ }
+ public renderPopoverContent(hasInjectedProvider: boolean, hasLedgerProvider: boolean) {
+ if (hasInjectedProvider || hasLedgerProvider) {
+ return (
+ <ProviderPicker
+ dispatcher={this.props.dispatcher}
+ networkId={this.props.networkId}
+ injectedProviderName={this.props.injectedProviderName}
+ providerType={this.props.providerType}
+ onToggleLedgerDialog={this.props.onToggleLedgerDialog}
+ blockchain={this.props.blockchain}
+ />
+ );
+ } else {
+ // Nothing to connect to, show install/info popover
+ return (
+ <div className="px2" style={{ maxWidth: 420 }}>
+ <div className="center h4 py2" style={{ color: colors.grey700 }}>
+ Choose a wallet:
+ </div>
+ <div className="flex pb3">
+ <div className="center px2">
+ <div style={{ color: colors.darkGrey }}>Install a browser wallet</div>
+ <div className="py2">
+ <img src="/images/metamask_or_parity.png" width="135" />
+ </div>
+ <div>
+ Use{' '}
+ <a
+ href={constants.URL_METAMASK_CHROME_STORE}
+ target="_blank"
+ style={{ color: colors.lightBlueA700 }}
+ >
+ Metamask
+ </a>{' '}
+ or{' '}
+ <a
+ href={constants.URL_PARITY_CHROME_STORE}
+ target="_blank"
+ style={{ color: colors.lightBlueA700 }}
+ >
+ Parity Signer
+ </a>
+ </div>
+ </div>
+ <div>
+ <div
+ className="pl1 ml1"
+ style={{ borderLeft: `1px solid ${colors.grey300}`, height: 65 }}
+ />
+ <div className="py1">or</div>
+ <div
+ className="pl1 ml1"
+ style={{ borderLeft: `1px solid ${colors.grey300}`, height: 68 }}
+ />
+ </div>
+ <div className="px2 center">
+ <div style={{ color: colors.darkGrey }}>Connect to a ledger hardware wallet</div>
+ <div style={{ paddingTop: 21, paddingBottom: 29 }}>
+ <img src="/images/ledger_icon.png" style={{ width: 80 }} />
+ </div>
+ <div>
+ <RaisedButton
+ style={{ width: '100%' }}
+ label="Use Ledger"
+ onClick={this.props.onToggleLedgerDialog}
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+ }
+}
diff --git a/packages/website/ts/components/top_bar/provider_picker.tsx b/packages/website/ts/components/top_bar/provider_picker.tsx
new file mode 100644
index 000000000..be7e57d6f
--- /dev/null
+++ b/packages/website/ts/components/top_bar/provider_picker.tsx
@@ -0,0 +1,81 @@
+import * as _ from 'lodash';
+import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
+import * as React from 'react';
+import { Blockchain } from 'ts/blockchain';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { ProviderType } from 'ts/types';
+import { colors } from 'ts/utils/colors';
+import { constants } from 'ts/utils/constants';
+
+interface ProviderPickerProps {
+ networkId: number;
+ injectedProviderName: string;
+ providerType: ProviderType;
+ onToggleLedgerDialog: () => void;
+ dispatcher: Dispatcher;
+ blockchain: Blockchain;
+}
+
+interface ProviderPickerState {}
+
+export class ProviderPicker extends React.Component<ProviderPickerProps, ProviderPickerState> {
+ public render() {
+ const isLedgerSelected = this.props.providerType === ProviderType.Ledger;
+ const menuStyle = {
+ padding: 10,
+ paddingTop: 15,
+ paddingBottom: 15,
+ };
+ // Show dropdown with two options
+ return (
+ <div style={{ width: 225, overflow: 'hidden' }}>
+ <RadioButtonGroup name="provider" defaultSelected={this.props.providerType}>
+ <RadioButton
+ onClick={this._onProviderRadioChanged.bind(this, ProviderType.Injected)}
+ style={{ ...menuStyle, backgroundColor: !isLedgerSelected && colors.grey50 }}
+ value={ProviderType.Injected}
+ label={this._renderLabel(this.props.injectedProviderName, !isLedgerSelected)}
+ />
+ <RadioButton
+ onClick={this._onProviderRadioChanged.bind(this, ProviderType.Ledger)}
+ style={{ ...menuStyle, backgroundColor: isLedgerSelected && colors.grey50 }}
+ value={ProviderType.Ledger}
+ label={this._renderLabel('Ledger Nano S', isLedgerSelected)}
+ />
+ </RadioButtonGroup>
+ </div>
+ );
+ }
+ private _renderLabel(title: string, shouldShowNetwork: boolean) {
+ const label = (
+ <div className="flex">
+ <div style={{ fontSize: 14 }}>{title}</div>
+ {shouldShowNetwork && this._renderNetwork()}
+ </div>
+ );
+ return label;
+ }
+ private _renderNetwork() {
+ const networkName = constants.NETWORK_NAME_BY_ID[this.props.networkId];
+ return (
+ <div className="flex" style={{ marginTop: 1 }}>
+ <div className="relative" style={{ width: 14, paddingLeft: 14 }}>
+ <img
+ src={`/images/network_icons/${networkName.toLowerCase()}.png`}
+ className="absolute"
+ style={{ top: 6, width: 10 }}
+ />
+ </div>
+ <div style={{ color: colors.lightGrey, fontSize: 11 }}>{networkName}</div>
+ </div>
+ );
+ }
+ private _onProviderRadioChanged(value: string) {
+ if (value === ProviderType.Ledger) {
+ this.props.onToggleLedgerDialog();
+ } else {
+ // tslint:disable-next-line:no-floating-promises
+ this.props.blockchain.updateProviderToInjectedAsync();
+ }
+ }
+}
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
new file mode 100644
index 000000000..1a0691e83
--- /dev/null
+++ b/packages/website/ts/components/top_bar/top_bar.tsx
@@ -0,0 +1,376 @@
+import * as _ from 'lodash';
+import Drawer from 'material-ui/Drawer';
+import Menu from 'material-ui/Menu';
+import MenuItem from 'material-ui/MenuItem';
+import * as React from 'react';
+import { Link } from 'react-router-dom';
+import ReactTooltip = require('react-tooltip');
+import { Blockchain } from 'ts/blockchain';
+import { PortalMenu } from 'ts/components/portal_menu';
+import { ProviderDisplay } from 'ts/components/top_bar/provider_display';
+import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item';
+import { DropDown } from 'ts/components/ui/drop_down';
+import { Identicon } from 'ts/components/ui/identicon';
+import { DocsInfo } from 'ts/pages/documentation/docs_info';
+import { NestedSidebarMenu } from 'ts/pages/shared/nested_sidebar_menu';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { DocsMenu, MenuSubsectionsBySection, ProviderType, Styles, WebsitePaths } from 'ts/types';
+import { colors } from 'ts/utils/colors';
+import { constants } from 'ts/utils/constants';
+
+interface TopBarProps {
+ userAddress?: string;
+ networkId?: number;
+ injectedProviderName?: string;
+ providerType?: ProviderType;
+ onToggleLedgerDialog?: () => void;
+ blockchain?: Blockchain;
+ dispatcher?: Dispatcher;
+ blockchainIsLoaded: boolean;
+ location: Location;
+ docsVersion?: string;
+ availableDocVersions?: string[];
+ menu?: DocsMenu;
+ menuSubsectionsBySection?: MenuSubsectionsBySection;
+ shouldFullWidth?: boolean;
+ docsInfo?: DocsInfo;
+ style?: React.CSSProperties;
+ isNightVersion?: boolean;
+}
+
+interface TopBarState {
+ isDrawerOpen: boolean;
+}
+
+const styles: Styles = {
+ address: {
+ marginRight: 12,
+ overflow: 'hidden',
+ paddingTop: 4,
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ width: 70,
+ },
+ topBar: {
+ backgroundcolor: colors.white,
+ height: 59,
+ width: '100%',
+ position: 'relative',
+ top: 0,
+ zIndex: 1100,
+ paddingBottom: 1,
+ },
+ bottomBar: {
+ boxShadow: 'rgba(0, 0, 0, 0.187647) 0px 1px 3px',
+ },
+ menuItem: {
+ fontSize: 14,
+ color: colors.darkestGrey,
+ paddingTop: 6,
+ paddingBottom: 6,
+ marginTop: 17,
+ cursor: 'pointer',
+ fontWeight: 400,
+ },
+};
+
+export class TopBar extends React.Component<TopBarProps, TopBarState> {
+ public static defaultProps: Partial<TopBarProps> = {
+ shouldFullWidth: false,
+ style: {},
+ isNightVersion: false,
+ };
+ constructor(props: TopBarProps) {
+ super(props);
+ this.state = {
+ isDrawerOpen: false,
+ };
+ }
+ public render() {
+ const isNightVersion = this.props.isNightVersion;
+ const isFullWidthPage = this.props.shouldFullWidth;
+ const parentClassNames = `flex mx-auto ${isFullWidthPage ? 'pl2' : 'max-width-4'}`;
+ const developerSectionMenuItems = [
+ <Link key="subMenuItem-zeroEx" to={WebsitePaths.ZeroExJs} className="text-decoration-none">
+ <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="0x.js" />
+ </Link>,
+ <Link key="subMenuItem-smartContracts" to={WebsitePaths.SmartContracts} className="text-decoration-none">
+ <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Smart Contracts" />
+ </Link>,
+ <Link key="subMenuItem-0xconnect" to={WebsitePaths.Connect} className="text-decoration-none">
+ <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="0x Connect" />
+ </Link>,
+ <a
+ key="subMenuItem-standard-relayer-api"
+ target="_blank"
+ className="text-decoration-none"
+ href={constants.URL_STANDARD_RELAYER_API_GITHUB}
+ >
+ <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Standard Relayer API" />
+ </a>,
+ <a
+ key="subMenuItem-github"
+ target="_blank"
+ className="text-decoration-none"
+ href={constants.URL_GITHUB_ORG}
+ >
+ <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="GitHub" />
+ </a>,
+ <a
+ key="subMenuItem-whitePaper"
+ target="_blank"
+ className="text-decoration-none"
+ href={`${WebsitePaths.Whitepaper}`}
+ >
+ <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Whitepaper" />
+ </a>,
+ ];
+ const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {};
+ const fullWidthClasses = isFullWidthPage ? 'pr4' : '';
+ const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png';
+ const menuClasses = `col col-${isFullWidthPage ? '4' : '5'} ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`;
+ const menuIconStyle = {
+ fontSize: 25,
+ color: isNightVersion ? 'white' : 'black',
+ cursor: 'pointer',
+ paddingTop: 16,
+ };
+ const hoverActiveNode = (
+ <div className="flex relative" style={{ color: menuIconStyle.color }}>
+ <div style={{ paddingRight: 10 }}>Developers</div>
+ <div className="absolute" style={{ paddingLeft: 3, right: 3, top: -2 }}>
+ <i className="zmdi zmdi-caret-right" style={{ fontSize: 22 }} />
+ </div>
+ </div>
+ );
+ const popoverContent = <Menu style={{ color: colors.darkGrey }}>{developerSectionMenuItems}</Menu>;
+ return (
+ <div style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style }} className="pb1">
+ <div className={parentClassNames}>
+ <div className="col col-2 sm-pl2 md-pl2 lg-pl0" style={{ paddingTop: 15 }}>
+ <Link to={`${WebsitePaths.Home}`} className="text-decoration-none">
+ <img src={logoUrl} height="30" />
+ </Link>
+ </div>
+ <div className={`col col-${isFullWidthPage ? '8' : '9'} lg-hide md-hide`} />
+ <div className={`col col-${isFullWidthPage ? '6' : '5'} sm-hide xs-hide`} />
+ {!this._isViewingPortal() && (
+ <div className={menuClasses}>
+ <div className="flex justify-between">
+ <DropDown
+ hoverActiveNode={hoverActiveNode}
+ popoverContent={popoverContent}
+ anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }}
+ targetOrigin={{ horizontal: 'middle', vertical: 'top' }}
+ style={styles.menuItem}
+ />
+ <TopBarMenuItem
+ title="Wiki"
+ path={`${WebsitePaths.Wiki}`}
+ style={styles.menuItem}
+ isNightVersion={isNightVersion}
+ />
+ <TopBarMenuItem
+ title="About"
+ path={`${WebsitePaths.About}`}
+ style={styles.menuItem}
+ isNightVersion={isNightVersion}
+ />
+ <TopBarMenuItem
+ title="Portal DApp"
+ path={`${WebsitePaths.Portal}`}
+ isPrimary={true}
+ style={styles.menuItem}
+ className={`${isFullWidthPage && 'md-hide'}`}
+ isNightVersion={isNightVersion}
+ />
+ </div>
+ </div>
+ )}
+ {this.props.blockchainIsLoaded && (
+ <div className="sm-hide xs-hide col col-5">
+ <ProviderDisplay
+ dispatcher={this.props.dispatcher}
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ injectedProviderName={this.props.injectedProviderName}
+ providerType={this.props.providerType}
+ onToggleLedgerDialog={this.props.onToggleLedgerDialog}
+ blockchain={this.props.blockchain}
+ />
+ </div>
+ )}
+ <div className={`col ${isFullWidthPage ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}>
+ <div style={menuIconStyle}>
+ <i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} />
+ </div>
+ </div>
+ </div>
+ {this._renderDrawer()}
+ </div>
+ );
+ }
+ private _renderDrawer() {
+ return (
+ <Drawer
+ open={this.state.isDrawerOpen}
+ docked={false}
+ openSecondary={true}
+ onRequestChange={this._onMenuButtonClick.bind(this)}
+ >
+ {this._renderPortalMenu()}
+ {this._renderDocsMenu()}
+ {this._renderWiki()}
+ <div className="pl1 py1 mt3" style={{ backgroundColor: colors.lightGrey }}>
+ Website
+ </div>
+ <Link to={WebsitePaths.Home} className="text-decoration-none">
+ <MenuItem className="py2">Home</MenuItem>
+ </Link>
+ <Link to={`${WebsitePaths.Wiki}`} className="text-decoration-none">
+ <MenuItem className="py2">Wiki</MenuItem>
+ </Link>
+ {!this._isViewing0xjsDocs() && (
+ <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
+ <MenuItem className="py2">0x.js Docs</MenuItem>
+ </Link>
+ )}
+ {!this._isViewingConnectDocs() && (
+ <Link to={WebsitePaths.Connect} className="text-decoration-none">
+ <MenuItem className="py2">0x Connect Docs</MenuItem>
+ </Link>
+ )}
+ {!this._isViewingSmartContractsDocs() && (
+ <Link to={WebsitePaths.SmartContracts} className="text-decoration-none">
+ <MenuItem className="py2">Smart Contract Docs</MenuItem>
+ </Link>
+ )}
+ {!this._isViewingPortal() && (
+ <Link to={`${WebsitePaths.Portal}`} className="text-decoration-none">
+ <MenuItem className="py2">Portal DApp</MenuItem>
+ </Link>
+ )}
+ <a className="text-decoration-none" target="_blank" href={`${WebsitePaths.Whitepaper}`}>
+ <MenuItem className="py2">Whitepaper</MenuItem>
+ </a>
+ <Link to={`${WebsitePaths.About}`} className="text-decoration-none">
+ <MenuItem className="py2">About</MenuItem>
+ </Link>
+ <a className="text-decoration-none" target="_blank" href={constants.URL_BLOG}>
+ <MenuItem className="py2">Blog</MenuItem>
+ </a>
+ <Link to={`${WebsitePaths.FAQ}`} className="text-decoration-none">
+ <MenuItem className="py2" onTouchTap={this._onMenuButtonClick.bind(this)}>
+ FAQ
+ </MenuItem>
+ </Link>
+ </Drawer>
+ );
+ }
+ private _renderDocsMenu(): React.ReactNode {
+ if (
+ (!this._isViewing0xjsDocs() && !this._isViewingSmartContractsDocs() && !this._isViewingConnectDocs()) ||
+ _.isUndefined(this.props.menu)
+ ) {
+ return undefined;
+ }
+
+ const sectionTitle = `${this.props.docsInfo.displayName} Docs`;
+ return (
+ <div className="lg-hide md-hide">
+ <div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}>
+ {sectionTitle}
+ </div>
+ <NestedSidebarMenu
+ topLevelMenu={this.props.menu}
+ menuSubsectionsBySection={this.props.menuSubsectionsBySection}
+ shouldDisplaySectionHeaders={false}
+ onMenuItemClick={this._onMenuButtonClick.bind(this)}
+ selectedVersion={this.props.docsVersion}
+ docPath={this.props.docsInfo.websitePath}
+ versions={this.props.availableDocVersions}
+ />
+ </div>
+ );
+ }
+ private _renderWiki(): React.ReactNode {
+ if (!this._isViewingWiki()) {
+ return undefined;
+ }
+
+ return (
+ <div className="lg-hide md-hide">
+ <div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}>
+ 0x Protocol Wiki
+ </div>
+ <NestedSidebarMenu
+ topLevelMenu={this.props.menuSubsectionsBySection}
+ menuSubsectionsBySection={this.props.menuSubsectionsBySection}
+ shouldDisplaySectionHeaders={false}
+ onMenuItemClick={this._onMenuButtonClick.bind(this)}
+ />
+ </div>
+ );
+ }
+ private _renderPortalMenu(): React.ReactNode {
+ if (!this._isViewingPortal()) {
+ return undefined;
+ }
+
+ return (
+ <div className="lg-hide md-hide">
+ <div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}>
+ Portal DApp
+ </div>
+ <PortalMenu menuItemStyle={{ color: 'black' }} onClick={this._onMenuButtonClick.bind(this)} />
+ </div>
+ );
+ }
+ private _renderUser() {
+ const userAddress = this.props.userAddress;
+ const identiconDiameter = 26;
+ return (
+ <div className="flex right lg-pr0 md-pr2 sm-pr2" style={{ paddingTop: 16 }}>
+ <div style={styles.address} data-tip={true} data-for="userAddressTooltip">
+ {!_.isEmpty(userAddress) ? userAddress : ''}
+ </div>
+ <ReactTooltip id="userAddressTooltip">{userAddress}</ReactTooltip>
+ <div>
+ <Identicon address={userAddress} diameter={identiconDiameter} />
+ </div>
+ </div>
+ );
+ }
+ private _onMenuButtonClick() {
+ this.setState({
+ isDrawerOpen: !this.state.isDrawerOpen,
+ });
+ }
+ private _isViewingPortal() {
+ return _.includes(this.props.location.pathname, WebsitePaths.Portal);
+ }
+ private _isViewingFAQ() {
+ return _.includes(this.props.location.pathname, WebsitePaths.FAQ);
+ }
+ private _isViewing0xjsDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.ZeroExJs);
+ }
+ private _isViewingConnectDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.Connect);
+ }
+ private _isViewingSmartContractsDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.SmartContracts);
+ }
+ private _isViewingWiki() {
+ return _.includes(this.props.location.pathname, WebsitePaths.Wiki);
+ }
+ private _shouldDisplayBottomBar() {
+ return (
+ this._isViewingWiki() ||
+ this._isViewing0xjsDocs() ||
+ this._isViewingFAQ() ||
+ this._isViewingSmartContractsDocs() ||
+ this._isViewingConnectDocs()
+ );
+ }
+}
diff --git a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
new file mode 100644
index 000000000..96ee86142
--- /dev/null
+++ b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
@@ -0,0 +1,52 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+import { Link } from 'react-router-dom';
+import { colors } from 'ts/utils/colors';
+
+const DEFAULT_STYLE = {
+ color: colors.darkestGrey,
+};
+
+interface TopBarMenuItemProps {
+ title: string;
+ path?: string;
+ isPrimary?: boolean;
+ style?: React.CSSProperties;
+ className?: string;
+ isNightVersion?: boolean;
+}
+
+interface TopBarMenuItemState {}
+
+export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarMenuItemState> {
+ public static defaultProps: Partial<TopBarMenuItemProps> = {
+ isPrimary: false,
+ style: DEFAULT_STYLE,
+ className: '',
+ isNightVersion: false,
+ };
+ public render() {
+ const primaryStyles = this.props.isPrimary
+ ? {
+ borderRadius: 4,
+ border: `1px solid ${this.props.isNightVersion ? colors.grey : colors.greyishPink}`,
+ marginTop: 15,
+ paddingLeft: 9,
+ paddingRight: 9,
+ width: 77,
+ }
+ : {};
+ const menuItemColor = this.props.isNightVersion ? 'white' : this.props.style.color;
+ const linkColor = _.isUndefined(menuItemColor) ? colors.darkestGrey : menuItemColor;
+ return (
+ <div
+ className={`center ${this.props.className}`}
+ style={{ ...this.props.style, ...primaryStyles, color: menuItemColor }}
+ >
+ <Link to={this.props.path} className="text-decoration-none" style={{ color: linkColor }}>
+ {this.props.title}
+ </Link>
+ </div>
+ );
+ }
+}