aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts')
-rw-r--r--packages/website/ts/components/documentation/docs_logo.tsx20
-rw-r--r--packages/website/ts/components/documentation/docs_top_bar.tsx162
-rw-r--r--packages/website/ts/components/documentation/tutorial_button.tsx59
-rw-r--r--packages/website/ts/components/dropdowns/developers_drop_down.tsx165
-rw-r--r--packages/website/ts/components/fill_order.tsx5
-rw-r--r--packages/website/ts/components/footer.tsx104
-rw-r--r--packages/website/ts/components/inputs/token_amount_input.tsx6
-rw-r--r--packages/website/ts/components/portal/back_button.tsx6
-rw-r--r--packages/website/ts/components/portal/drawer_menu.tsx2
-rw-r--r--packages/website/ts/components/portal/menu.tsx6
-rw-r--r--packages/website/ts/components/portal/portal.tsx10
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx196
-rw-r--r--packages/website/ts/components/top_bar/top_bar_menu_item.tsx23
-rw-r--r--packages/website/ts/components/ui/container.tsx4
-rw-r--r--packages/website/ts/components/ui/custom_menu_item.tsx (renamed from packages/website/ts/components/ui/menu_item.tsx)15
-rw-r--r--packages/website/ts/components/ui/drop_down.tsx3
-rw-r--r--packages/website/ts/components/ui/simple_menu.tsx4
-rw-r--r--packages/website/ts/components/ui/text.tsx4
-rw-r--r--packages/website/ts/containers/docs_home.ts28
-rw-r--r--packages/website/ts/index.tsx2
-rw-r--r--packages/website/ts/pages/about/about.tsx5
-rw-r--r--packages/website/ts/pages/documentation/doc_page.tsx8
-rw-r--r--packages/website/ts/pages/documentation/home.tsx623
-rw-r--r--packages/website/ts/pages/landing/landing.tsx15
-rw-r--r--packages/website/ts/pages/wiki/wiki.tsx26
-rw-r--r--packages/website/ts/types.ts24
-rw-r--r--packages/website/ts/utils/constants.ts2
-rw-r--r--packages/website/ts/utils/translate.ts7
28 files changed, 1234 insertions, 300 deletions
diff --git a/packages/website/ts/components/documentation/docs_logo.tsx b/packages/website/ts/components/documentation/docs_logo.tsx
new file mode 100644
index 000000000..b727fea36
--- /dev/null
+++ b/packages/website/ts/components/documentation/docs_logo.tsx
@@ -0,0 +1,20 @@
+import { Link } from '@0xproject/react-shared';
+import * as React from 'react';
+import { WebsitePaths } from 'ts/types';
+
+export interface DocsLogoProps {
+ height: number;
+ containerStyle?: React.CSSProperties;
+}
+
+export const DocsLogo: React.StatelessComponent<DocsLogoProps> = props => {
+ return (
+ <Link to={WebsitePaths.Docs}>
+ <img src="/images/docs_logo.svg" height={props.height} />
+ </Link>
+ );
+};
+
+DocsLogo.defaultProps = {
+ containerStyle: {},
+};
diff --git a/packages/website/ts/components/documentation/docs_top_bar.tsx b/packages/website/ts/components/documentation/docs_top_bar.tsx
new file mode 100644
index 000000000..9a2146f9c
--- /dev/null
+++ b/packages/website/ts/components/documentation/docs_top_bar.tsx
@@ -0,0 +1,162 @@
+import { ALink, colors, Link, NestedSidebarMenu } from '@0xproject/react-shared';
+import { ObjectMap } from '@0xproject/types';
+import * as _ from 'lodash';
+import Drawer from 'material-ui/Drawer';
+import * as React from 'react';
+import { DocsLogo } from 'ts/components/documentation/docs_logo';
+import { Container } from 'ts/components/ui/container';
+import { Text } from 'ts/components/ui/text';
+import { Deco, Key, WebsitePaths } from 'ts/types';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+export interface DocsTopBarProps {
+ location: Location;
+ translate: Translate;
+ sectionNameToLinks?: ObjectMap<ALink[]>;
+}
+
+interface DocsTopBarState {
+ isDrawerOpen: boolean;
+}
+
+interface MenuItemInfo {
+ title: string;
+ url: string;
+ iconUrl: string;
+ fontColor: string;
+ fontWeight?: string;
+}
+
+export class DocsTopBar extends React.Component<DocsTopBarProps, DocsTopBarState> {
+ constructor(props: DocsTopBarProps) {
+ super(props);
+ this.state = {
+ isDrawerOpen: false,
+ };
+ }
+ public componentWillReceiveProps(nextProps: DocsTopBarProps): void {
+ if (nextProps.location.pathname !== this.props.location.pathname) {
+ this.setState({
+ isDrawerOpen: false,
+ });
+ }
+ }
+ public render(): React.ReactNode {
+ const menuItemInfos: MenuItemInfo[] = [
+ {
+ title: this.props.translate.get(Key.Github, Deco.Cap),
+ url: constants.URL_GITHUB_ORG,
+ iconUrl: '/images/developers/github_icon.svg',
+ fontColor: colors.linkSectionGrey,
+ },
+ {
+ title: this.props.translate.get(Key.Forum, Deco.Cap),
+ url: constants.URL_FORUM,
+ iconUrl: '/images/developers/forum_icon.svg',
+ fontColor: colors.linkSectionGrey,
+ },
+ {
+ title: this.props.translate.get(Key.LiveChat, Deco.Cap),
+ url: constants.URL_ZEROEX_CHAT,
+ iconUrl: '/images/developers/chat_icon.svg',
+ fontColor: colors.lightLinkBlue,
+ fontWeight: 'bold',
+ },
+ ];
+ return (
+ <Container height={80}>
+ <Container className="flex items-center lg-pt3 md-pt3 sm-pt1 relative" width="100%">
+ <Container className="col col-2 sm-hide xs-hide">
+ <Link
+ to={WebsitePaths.Home}
+ fontColor={colors.linkSectionGrey}
+ className="flex items-center text-decoration-none"
+ >
+ <i className="zmdi zmdi-chevron-left bold" style={{ fontSize: 16 }} />
+ <Container paddingLeft="8px">
+ <Text fontSize="16px" fontColor={colors.linkSectionGrey}>
+ 0xproject.com
+ </Text>
+ </Container>
+ </Link>
+ </Container>
+ <Container className="col col-4 md-hide sm-hide xs-hide" />
+ <Container className="col col-6 md-pl4 md-ml4 sm-hide xs-hide">
+ <Container className="flex items-center justify-between right" width="300px">
+ {this._renderMenuItems(menuItemInfos)}
+ </Container>
+ </Container>
+ <Container className="lg-hide md-hide">
+ <Container paddingTop="6px" paddingLeft="18px">
+ <DocsLogo height={30} />
+ </Container>
+ </Container>
+ <Container className="md-hide lg-hide absolute" right="18px" top="12px">
+ <i
+ className="zmdi zmdi-menu"
+ style={{
+ color: colors.grey700,
+ fontSize: 30,
+ cursor: 'pointer',
+ }}
+ onClick={this._onMenuButtonClick.bind(this)}
+ />
+ </Container>
+ </Container>
+ <Container width={'100%'} height={'1px'} backgroundColor={colors.grey300} marginTop={'11px'} />
+ {this._renderDrawer()}
+ </Container>
+ );
+ }
+ private _renderMenuItems(menuItemInfos: MenuItemInfo[]): React.ReactNode {
+ const menuItems = _.map(menuItemInfos, menuItemInfo => {
+ return (
+ <a
+ key={`menu-item-${menuItemInfo.title}`}
+ href={menuItemInfo.url}
+ target="_blank"
+ className="text-decoration-none"
+ >
+ <Container className="flex">
+ <img src={menuItemInfo.iconUrl} width="18" />
+ <Container className="flex items-center" paddingLeft="4px">
+ <Text
+ fontSize="16px"
+ fontWeight={menuItemInfo.fontWeight || 'normal'}
+ fontColor={menuItemInfo.fontColor}
+ >
+ {menuItemInfo.title}
+ </Text>
+ </Container>
+ </Container>
+ </a>
+ );
+ });
+ return menuItems;
+ }
+ private _renderDrawer(): React.ReactNode {
+ return (
+ <Drawer
+ open={this.state.isDrawerOpen}
+ docked={false}
+ openSecondary={true}
+ onRequestChange={this._onMenuButtonClick.bind(this)}
+ >
+ <Container className="clearfix pl1">
+ <NestedSidebarMenu
+ sectionNameToLinks={this.props.sectionNameToLinks}
+ shouldDisplaySectionHeaders={true}
+ shouldReformatMenuItemNames={false}
+ onMenuItemClick={this._onMenuButtonClick.bind(this)}
+ />
+ </Container>
+ </Drawer>
+ );
+ }
+ private _onMenuButtonClick(): void {
+ this.setState({
+ isDrawerOpen: !this.state.isDrawerOpen,
+ });
+ }
+}
diff --git a/packages/website/ts/components/documentation/tutorial_button.tsx b/packages/website/ts/components/documentation/tutorial_button.tsx
new file mode 100644
index 000000000..dc00bf743
--- /dev/null
+++ b/packages/website/ts/components/documentation/tutorial_button.tsx
@@ -0,0 +1,59 @@
+import { colors, Link } from '@0xproject/react-shared';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { Container } from 'ts/components/ui/container';
+import { Text } from 'ts/components/ui/text';
+import { Deco, Key, TutorialInfo } from 'ts/types';
+import { Translate } from 'ts/utils/translate';
+
+import { styled } from 'ts/style/theme';
+
+export interface TutorialButtonProps {
+ className?: string;
+ translate: Translate;
+ tutorialInfo: TutorialInfo;
+}
+
+const PlainTutorialButton: React.StatelessComponent<TutorialButtonProps> = ({ translate, tutorialInfo, className }) => (
+ <Container className={className}>
+ <Link to={tutorialInfo.link.to} shouldOpenInNewTab={tutorialInfo.link.shouldOpenInNewTab}>
+ <div className="flex relative">
+ <div className="col col-1 flex items-center sm-pr3">
+ <img src={tutorialInfo.iconUrl} height={40} />
+ </div>
+ <div className="lg-pl2 md-pl2 sm-pl3 col col-10">
+ <Text Tag="div" fontSize="18" fontColor={colors.lightLinkBlue} fontWeight="bold">
+ {translate.get(tutorialInfo.link.title as Key, Deco.Cap)}
+ </Text>
+ <Text Tag="div" fontColor={colors.grey750} fontSize="16">
+ {translate.get(tutorialInfo.description as Key, Deco.Cap)}
+ </Text>
+ </div>
+ <div className="col col-1 flex items-center justify-end">
+ <div className="right">
+ <i
+ className="zmdi zmdi-chevron-right bold"
+ style={{ fontSize: 26, color: colors.lightLinkBlue }}
+ />
+ </div>
+ </div>
+ </div>
+ </Link>
+ </Container>
+);
+
+export const TutorialButton = styled(PlainTutorialButton)`
+ border-radius: 4px;
+ border: 1px solid ${colors.grey325};
+ background-color: ${colors.white};
+ &:hover {
+ border: 1px solid ${colors.lightLinkBlue};
+ background-color: ${colors.lightestBlue};
+ }
+ padding: 20px;
+ margin-bottom: 15px;
+`;
+
+TutorialButton.defaultProps = {};
+
+TutorialButton.displayName = 'TutorialButton';
diff --git a/packages/website/ts/components/dropdowns/developers_drop_down.tsx b/packages/website/ts/components/dropdowns/developers_drop_down.tsx
new file mode 100644
index 000000000..df5dc173d
--- /dev/null
+++ b/packages/website/ts/components/dropdowns/developers_drop_down.tsx
@@ -0,0 +1,165 @@
+import { ALink, colors, Link } from '@0xproject/react-shared';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { Container } from 'ts/components/ui/container';
+import { DropDown } from 'ts/components/ui/drop_down';
+import { Text } from 'ts/components/ui/text';
+import { Deco, Key, WebsitePaths } from 'ts/types';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+const gettingStartedKeyToLinkInfo1: ALink[] = [
+ {
+ title: Key.BuildARelayer,
+ to: `${WebsitePaths.Wiki}#Build-A-Relayer`,
+ },
+ {
+ title: Key.OrderBasics,
+ to: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`,
+ },
+];
+const gettingStartedKeyToLinkInfo2: ALink[] = [
+ {
+ title: Key.DevelopOnEthereum,
+ to: `${WebsitePaths.Wiki}#Ethereum-Development`,
+ },
+ {
+ title: Key.UseSharedLiquidity,
+ to: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`,
+ },
+];
+const popularDocsToLinkInfos: ALink[] = [
+ {
+ title: Key.ZeroExJs,
+ to: WebsitePaths.ZeroExJs,
+ },
+ {
+ title: Key.Connect,
+ to: WebsitePaths.Connect,
+ },
+ {
+ title: Key.SmartContract,
+ to: WebsitePaths.SmartContracts,
+ },
+];
+const usefulLinksToLinkInfo: ALink[] = [
+ {
+ title: Key.Github,
+ to: constants.URL_GITHUB_ORG,
+ shouldOpenInNewTab: true,
+ },
+ {
+ title: Key.Whitepaper,
+ to: WebsitePaths.Whitepaper,
+ shouldOpenInNewTab: true,
+ },
+ {
+ title: Key.Sandbox,
+ to: constants.URL_SANDBOX,
+ shouldOpenInNewTab: true,
+ },
+];
+
+interface DevelopersDropDownProps {
+ location: Location;
+ translate: Translate;
+ menuItemStyles: React.CSSProperties;
+ menuIconStyle: React.CSSProperties;
+}
+
+interface DevelopersDropDownState {}
+
+export class DevelopersDropDown extends React.Component<DevelopersDropDownProps, DevelopersDropDownState> {
+ public render(): React.ReactNode {
+ const activeNode = (
+ <Container className="flex relative" paddingRight="10">
+ <Text fontColor={this.props.menuIconStyle.color}>
+ {this.props.translate.get(Key.Developers, Deco.Cap)}
+ </Text>
+ </Container>
+ );
+ return (
+ <DropDown
+ activeNode={activeNode}
+ popoverContent={this._renderDropdownMenu()}
+ anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
+ targetOrigin={{ horizontal: 'left', vertical: 'top' }}
+ style={this.props.menuItemStyles}
+ popoverStyle={{ borderRadius: 4, width: 427, height: 373, marginTop: 10 }}
+ />
+ );
+ }
+ private _renderDropdownMenu(): React.ReactNode {
+ const dropdownMenu = (
+ <Container>
+ <Container padding="1.75rem">
+ {this._renderTitle('Getting started')}
+ <Container className="flex">
+ <Container className="pr4 mr2">
+ {this._renderLinkSection(gettingStartedKeyToLinkInfo1)}
+ </Container>
+ <Container>{this._renderLinkSection(gettingStartedKeyToLinkInfo2)}</Container>
+ </Container>
+ </Container>
+ <Container width="100%" height="1px" backgroundColor={colors.grey300} />
+ <Container className="flex" padding="1.75rem">
+ <Container className="pr4 mr2">
+ <Container>{this._renderTitle('Popular docs')}</Container>
+ <Container>{this._renderLinkSection(popularDocsToLinkInfos)}</Container>
+ </Container>
+ <Container>
+ <Container>{this._renderTitle('Useful links')}</Container>
+ <Container>{this._renderLinkSection(usefulLinksToLinkInfo)}</Container>
+ </Container>
+ </Container>
+ <Link to={WebsitePaths.Docs} fontColor={colors.lightBlueA700}>
+ <Container
+ padding="0.9rem"
+ backgroundColor={colors.lightBgGrey}
+ borderBottomLeftRadius={4}
+ borderBottomRightRadius={4}
+ >
+ <Text fontColor={colors.lightBlueA700} fontWeight="bold" fontSize="14px" textAlign="center">
+ {this.props.translate.get(Key.ViewAllDocumentation, Deco.Upper)}
+ </Text>
+ </Container>
+ </Link>
+ </Container>
+ );
+ return dropdownMenu;
+ }
+ private _renderTitle(title: string): React.ReactNode {
+ return (
+ <Container paddingBottom="12px">
+ <Text letterSpacing={1} fontColor={colors.linkSectionGrey} fontSize="14px" fontWeight={600}>
+ {title.toUpperCase()}
+ </Text>
+ </Container>
+ );
+ }
+ private _renderLinkSection(links: ALink[]): React.ReactNode {
+ const numLinks = links.length;
+ let i = 0;
+ const renderLinks = _.map(links, (link: ALink) => {
+ const isWikiLink = _.startsWith(link.to, WebsitePaths.Wiki) && _.includes(link.to, '#');
+ const isOnWiki = this.props.location.pathname === WebsitePaths.Wiki;
+ let to = link.to;
+ if (isWikiLink && isOnWiki) {
+ to = `${link.to.split('#')[1]}`;
+ }
+ i++;
+ const isLast = i === numLinks;
+ const linkText = this.props.translate.get(link.title as Key, Deco.Cap);
+ return (
+ <Container className={`pr1 pt1 ${!isLast && 'pb1'}`} key={`dev-dropdown-link-${link.title}`}>
+ <Link to={to} shouldOpenInNewTab={!!link.shouldOpenInNewTab}>
+ <Text fontFamily="Roboto, Roboto Mono" fontColor={colors.lightBlueA700}>
+ {linkText}
+ </Text>
+ </Link>
+ </Container>
+ );
+ });
+ return <Container>{renderLinks}</Container>;
+ }
+}
diff --git a/packages/website/ts/components/fill_order.tsx b/packages/website/ts/components/fill_order.tsx
index 3c3155349..c1bbadfde 100644
--- a/packages/website/ts/components/fill_order.tsx
+++ b/packages/website/ts/components/fill_order.tsx
@@ -1,5 +1,5 @@
import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
-import { colors } from '@0xproject/react-shared';
+import { colors, Link } from '@0xproject/react-shared';
import { BigNumber, logUtils } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as accounting from 'accounting';
@@ -8,7 +8,6 @@ import { Card, CardHeader, CardText } from 'material-ui/Card';
import Divider from 'material-ui/Divider';
import RaisedButton from 'material-ui/RaisedButton';
import * as React from 'react';
-import { Link } from 'react-router-dom';
import { Blockchain } from 'ts/blockchain';
import { TrackTokenConfirmationDialog } from 'ts/components/dialogs/track_token_confirmation_dialog';
import { FillOrderJSON } from 'ts/components/fill_order_json';
@@ -324,7 +323,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
return (
<div>
Order successfully filled. See the trade details in your{' '}
- <Link to={`${WebsitePaths.Portal}/trades`} style={{ color: colors.white }}>
+ <Link to={`${WebsitePaths.Portal}/trades`} fontColor={colors.white}>
trade history
</Link>
</div>
diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx
index 6dcb5a0e9..f11ecae19 100644
--- a/packages/website/ts/components/footer.tsx
+++ b/packages/website/ts/components/footer.tsx
@@ -1,31 +1,17 @@
-import { colors } from '@0xproject/react-shared';
+import { ALink, colors, Link } from '@0xproject/react-shared';
+import { ObjectMap } from '@0xproject/types';
import * as _ from 'lodash';
import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';
import * as React from 'react';
-import { Link } from 'react-router-dom';
+
import { Dispatcher } from 'ts/redux/dispatcher';
import { Deco, Key, Language, WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
import { Translate } from 'ts/utils/translate';
-interface MenuItemsBySection {
- [sectionName: string]: FooterMenuItem[];
-}
-
-interface FooterMenuItem {
- title: string;
- path?: string;
- isExternal?: boolean;
-}
-
const ICON_DIMENSION = 16;
-const linkStyle = {
- color: colors.white,
- cursor: 'pointer',
-};
-
const languageToMenuTitle = {
[Language.English]: 'English',
[Language.Russian]: 'Русский',
@@ -51,76 +37,74 @@ export class Footer extends React.Component<FooterProps, FooterState> {
};
}
public render(): React.ReactNode {
- const menuItemsBySection: MenuItemsBySection = {
+ const sectionNameToLinks: ObjectMap<ALink[]> = {
[Key.Documentation]: [
{
title: '0x.js',
- path: WebsitePaths.ZeroExJs,
+ to: WebsitePaths.ZeroExJs,
},
{
title: this.props.translate.get(Key.SmartContracts, Deco.Cap),
- path: WebsitePaths.SmartContracts,
+ to: WebsitePaths.SmartContracts,
},
{
title: this.props.translate.get(Key.Connect, Deco.Cap),
- path: WebsitePaths.Connect,
+ to: WebsitePaths.Connect,
},
{
title: this.props.translate.get(Key.Whitepaper, Deco.Cap),
- path: WebsitePaths.Whitepaper,
- isExternal: true,
+ to: WebsitePaths.Whitepaper,
+ shouldOpenInNewTab: true,
},
{
title: this.props.translate.get(Key.Wiki, Deco.Cap),
- path: WebsitePaths.Wiki,
+ to: WebsitePaths.Wiki,
},
{
title: this.props.translate.get(Key.Faq, Deco.Cap),
- path: WebsitePaths.FAQ,
+ to: WebsitePaths.FAQ,
},
],
[Key.Community]: [
{
title: this.props.translate.get(Key.RocketChat, Deco.Cap),
- isExternal: true,
- path: constants.URL_ZEROEX_CHAT,
+ to: constants.URL_ZEROEX_CHAT,
+ shouldOpenInNewTab: true,
},
{
title: this.props.translate.get(Key.Blog, Deco.Cap),
- isExternal: true,
- path: constants.URL_BLOG,
+ to: constants.URL_BLOG,
+ shouldOpenInNewTab: true,
},
{
title: 'Twitter',
- isExternal: true,
- path: constants.URL_TWITTER,
+ to: constants.URL_TWITTER,
+ shouldOpenInNewTab: true,
},
{
title: 'Reddit',
- isExternal: true,
- path: constants.URL_REDDIT,
+ to: constants.URL_REDDIT,
+ shouldOpenInNewTab: true,
},
{
title: this.props.translate.get(Key.Forum, Deco.Cap),
- isExternal: true,
- path: constants.URL_DISCOURSE_FORUM,
+ to: constants.URL_DISCOURSE_FORUM,
+ shouldOpenInNewTab: true,
},
],
[Key.Organization]: [
{
title: this.props.translate.get(Key.About, Deco.Cap),
- isExternal: false,
- path: WebsitePaths.About,
+ to: WebsitePaths.About,
},
{
title: this.props.translate.get(Key.Careers, Deco.Cap),
- isExternal: false,
- path: WebsitePaths.Careers,
+ to: WebsitePaths.Careers,
},
{
title: this.props.translate.get(Key.Contact, Deco.Cap),
- isExternal: true,
- path: 'mailto:team@0xproject.com',
+ to: 'mailto:team@0xproject.com',
+ shouldOpenInNewTab: true,
},
],
};
@@ -160,19 +144,19 @@ export class Footer extends React.Component<FooterProps, FooterState> {
<div className="col lg-col-4 md-col-4 col-12">
<div className="lg-right md-right sm-center">
{this._renderHeader(Key.Documentation)}
- {_.map(menuItemsBySection[Key.Documentation], this._renderMenuItem.bind(this))}
+ {_.map(sectionNameToLinks[Key.Documentation], this._renderMenuItem.bind(this))}
</div>
</div>
<div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2">
<div className="lg-right md-right sm-center">
{this._renderHeader(Key.Community)}
- {_.map(menuItemsBySection[Key.Community], this._renderMenuItem.bind(this))}
+ {_.map(sectionNameToLinks[Key.Community], this._renderMenuItem.bind(this))}
</div>
</div>
<div className="col lg-col-4 md-col-4 col-12">
<div className="lg-right md-right sm-center">
{this._renderHeader(Key.Organization)}
- {_.map(menuItemsBySection[Key.Organization], this._renderMenuItem.bind(this))}
+ {_.map(sectionNameToLinks[Key.Organization], this._renderMenuItem.bind(this))}
</div>
</div>
</div>
@@ -187,7 +171,7 @@ export class Footer extends React.Component<FooterProps, FooterState> {
</div>
);
}
- private _renderMenuItem(item: FooterMenuItem): React.ReactNode {
+ private _renderMenuItem(link: ALink): React.ReactNode {
const titleToIcon: { [title: string]: string } = {
[this.props.translate.get(Key.RocketChat, Deco.Cap)]: 'rocketchat.png',
[this.props.translate.get(Key.Blog, Deco.Cap)]: 'medium.png',
@@ -195,30 +179,26 @@ export class Footer extends React.Component<FooterProps, FooterState> {
Reddit: 'reddit.png',
[this.props.translate.get(Key.Forum, Deco.Cap)]: 'discourse.png',
};
- const iconIfExists = titleToIcon[item.title];
+ const iconIfExists = titleToIcon[link.title];
return (
- <div key={item.title} className="sm-center" style={{ fontSize: 13, paddingTop: 25 }}>
- {item.isExternal ? (
- <a className="text-decoration-none" style={linkStyle} target="_blank" href={item.path}>
+ <div key={link.title} className="sm-center" style={{ fontSize: 13, paddingTop: 25 }}>
+ <Link
+ to={link.to}
+ shouldOpenInNewTab={link.shouldOpenInNewTab}
+ fontColor={colors.white}
+ className="text-decoration-none"
+ >
+ <div>
{!_.isUndefined(iconIfExists) ? (
<div className="inline-block">
<div className="pr1 table-cell">{this._renderIcon(iconIfExists)}</div>
- <div className="table-cell">{item.title}</div>
+ <div className="table-cell">{link.title}</div>
</div>
) : (
- item.title
+ link.title
)}
- </a>
- ) : (
- <Link to={item.path} style={linkStyle} className="text-decoration-none">
- <div>
- {!_.isUndefined(iconIfExists) && (
- <div className="pr1">{this._renderIcon(iconIfExists)}</div>
- )}
- {item.title}
- </div>
- </Link>
- )}
+ </div>
+ </Link>
</div>
);
}
diff --git a/packages/website/ts/components/inputs/token_amount_input.tsx b/packages/website/ts/components/inputs/token_amount_input.tsx
index db093fb68..134d1cc76 100644
--- a/packages/website/ts/components/inputs/token_amount_input.tsx
+++ b/packages/website/ts/components/inputs/token_amount_input.tsx
@@ -1,9 +1,8 @@
-import { colors } from '@0xproject/react-shared';
+import { colors, Link } from '@0xproject/react-shared';
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import * as React from 'react';
-import { Link } from 'react-router-dom';
import { Blockchain } from 'ts/blockchain';
import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input';
import { Token, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types';
@@ -112,7 +111,8 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
Insufficient allowance.{' '}
<Link
to={`${WebsitePaths.Portal}/account`}
- style={{ cursor: 'pointer', color: colors.darkestGrey }}
+ textDecoration="underline"
+ fontColor={colors.darkestGrey}
>
Set allowance
</Link>
diff --git a/packages/website/ts/components/portal/back_button.tsx b/packages/website/ts/components/portal/back_button.tsx
index ca35abc2b..64a332e07 100644
--- a/packages/website/ts/components/portal/back_button.tsx
+++ b/packages/website/ts/components/portal/back_button.tsx
@@ -1,7 +1,5 @@
-import { Styles } from '@0xproject/react-shared';
+import { Link, Styles } from '@0xproject/react-shared';
import * as React from 'react';
-import { Link } from 'react-router-dom';
-
import { Island } from 'ts/components/ui/island';
import { colors } from 'ts/style/colors';
@@ -27,7 +25,7 @@ const styles: Styles = {
export const BackButton = (props: BackButtonProps) => {
return (
<div style={{ height: 65, paddingTop: 25 }}>
- <Link to={props.to} style={{ textDecoration: 'none' }}>
+ <Link to={props.to}>
<Island className="flex right" style={styles.backButton}>
<div style={{ marginLeft: 12 }}>
<i style={styles.backButtonIcon} className={`zmdi zmdi-arrow-left`} />
diff --git a/packages/website/ts/components/portal/drawer_menu.tsx b/packages/website/ts/components/portal/drawer_menu.tsx
index a6707e86c..3a8c69a70 100644
--- a/packages/website/ts/components/portal/drawer_menu.tsx
+++ b/packages/website/ts/components/portal/drawer_menu.tsx
@@ -39,7 +39,7 @@ export interface DrawerMenuProps {
}
export const DrawerMenu = (props: DrawerMenuProps) => {
const relayerItemEntry = {
- to: `${WebsitePaths.Portal}`,
+ to: WebsitePaths.Portal,
labelText: 'Relayer ecosystem',
iconName: 'zmdi-portable-wifi',
};
diff --git a/packages/website/ts/components/portal/menu.tsx b/packages/website/ts/components/portal/menu.tsx
index 39dab77f5..a3352529c 100644
--- a/packages/website/ts/components/portal/menu.tsx
+++ b/packages/website/ts/components/portal/menu.tsx
@@ -1,7 +1,7 @@
import { Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
-import { MenuItem } from 'ts/components/ui/menu_item';
+import { CustomMenuItem } from 'ts/components/ui/custom_menu_item';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
@@ -67,14 +67,14 @@ export const Menu: React.StatelessComponent<MenuProps> = (props: MenuProps) => {
{_.map(props.menuItemEntries, entry => {
const isSelected = entry.to === props.selectedPath;
return (
- <MenuItem key={entry.to} to={entry.to}>
+ <CustomMenuItem key={entry.to} to={entry.to}>
<MenuItemLabel
title={entry.labelText}
iconName={entry.iconName}
selected={isSelected}
theme={props.theme}
/>
- </MenuItem>
+ </CustomMenuItem>
);
})}
</div>
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx
index b42954f60..b8cd45661 100644
--- a/packages/website/ts/components/portal/portal.tsx
+++ b/packages/website/ts/components/portal/portal.tsx
@@ -1,9 +1,9 @@
-import { colors } from '@0xproject/react-shared';
+import { colors, Link } from '@0xproject/react-shared';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import * as React from 'react';
import * as DocumentTitle from 'react-document-title';
-import { Link, Route, RouteComponentProps, Switch } from 'react-router-dom';
+import { Route, RouteComponentProps, Switch } from 'react-router-dom';
import { Blockchain } from 'ts/blockchain';
import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog';
@@ -317,7 +317,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
};
return (
<Section
- header={<BackButton to={`${WebsitePaths.Portal}`} labelText="back to Relayers" />}
+ header={<BackButton to={WebsitePaths.Portal} labelText="back to Relayers" />}
body={<Menu selectedPath={routeComponentProps.location.pathname} theme={menuTheme} />}
/>
);
@@ -389,9 +389,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
</Container>
);
return !shouldStartOnboarding ? (
- <Link to={{ pathname: `${WebsitePaths.Portal}/account` }} style={{ textDecoration: 'none' }}>
- {startOnboarding}
- </Link>
+ <Link to={`${WebsitePaths.Portal}/account`}>{startOnboarding}</Link>
) : (
startOnboarding
);
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
index 7cf3c6ecb..3297befad 100644
--- a/packages/website/ts/components/top_bar/top_bar.tsx
+++ b/packages/website/ts/components/top_bar/top_bar.tsx
@@ -1,23 +1,16 @@
-import { DocsInfo, DocsMenu } from '@0xproject/react-docs';
-import {
- colors,
- constants as sharedConstants,
- MenuSubsectionsBySection,
- NestedSidebarMenu,
- Styles,
-} from '@0xproject/react-shared';
+import { DocsInfo } from '@0xproject/react-docs';
+import { ALink, colors, constants as sharedConstants, Link, NestedSidebarMenu, Styles } from '@0xproject/react-shared';
+import { ObjectMap } from '@0xproject/types';
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 { Blockchain } from 'ts/blockchain';
+import { DevelopersDropDown } from 'ts/components/dropdowns/developers_drop_down';
import { DrawerMenu } from 'ts/components/portal/drawer_menu';
import { ProviderDisplay } from 'ts/components/top_bar/provider_display';
import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item';
import { Container } from 'ts/components/ui/container';
-import { DropDown } from 'ts/components/ui/drop_down';
import { Dispatcher } from 'ts/redux/dispatcher';
import { Deco, Key, ProviderType, WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
@@ -41,8 +34,8 @@ export interface TopBarProps {
translate: Translate;
docsVersion?: string;
availableDocVersions?: string[];
- menu?: DocsMenu;
- menuSubsectionsBySection?: MenuSubsectionsBySection;
+ sectionNameToLinks?: ObjectMap<ALink[]>;
+ subsectionNameToLinks?: ObjectMap<ALink[]>;
displayType?: TopBarDisplayType;
docsInfo?: DocsInfo;
style?: React.CSSProperties;
@@ -129,111 +122,6 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
? 'flex mx-auto items-center max-width-4'
: 'flex mx-auto items-center';
const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
- 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={this.props.translate.get(Key.SmartContracts, Deco.CapWords)}
- />
- </Link>,
- <Link key="subMenuItem-0xconnect" to={WebsitePaths.Connect} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.Connect, Deco.CapWords)}
- />
- </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={this.props.translate.get(Key.StandardRelayerApi, Deco.CapWords)}
- />
- </a>,
- <Link key="subMenuItem-jsonSchema" to={WebsitePaths.JSONSchemas} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.JsonSchemas, Deco.CapWords)}
- />
- </Link>,
- <Link key="subMenuItem-subproviders" to={WebsitePaths.Subproviders} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.Subproviders, Deco.CapWords)}
- />
- </Link>,
- <Link key="subMenuItem-web3Wrapper" to={WebsitePaths.Web3Wrapper} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.Web3Wrapper, Deco.CapWords)}
- />
- </Link>,
- <Link
- key="subMenuItem-contractWrappers"
- to={WebsitePaths.ContractWrappers}
- className="text-decoration-none"
- >
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.ContractWrappers, Deco.CapWords)}
- />
- </Link>,
- <Link key="subMenuItem-orderUtils" to={WebsitePaths.OrderUtils} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.OrderUtils, Deco.CapWords)}
- />
- </Link>,
- <Link key="subMenuItem-orderWatcher" to={WebsitePaths.OrderWatcher} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.OrderWatcher, Deco.CapWords)}
- />
- </Link>,
- <Link key="subMenuItem-sol-compiler" to={WebsitePaths.SolCompiler} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.SolCompiler, Deco.CapWords)}
- />
- </Link>,
- <Link key="subMenuItem-sol-cov" to={WebsitePaths.SolCov} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.SolCov, Deco.CapWords)}
- />
- </Link>,
- <Link key="subMenuItem-ethereum-types" to={WebsitePaths.EthereumTypes} className="text-decoration-none">
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.EthereumTypes, Deco.CapWords)}
- />
- </Link>,
- <a
- key="subMenuItem-whitePaper"
- target="_blank"
- className="text-decoration-none"
- href={`${WebsitePaths.Whitepaper}`}
- >
- <MenuItem
- style={{ fontSize: styles.menuItem.fontSize }}
- primaryText={this.props.translate.get(Key.Whitepaper, Deco.CapWords)}
- />
- </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>,
- ];
const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {};
const fullWidthClasses = isExpandedDisplayType ? 'pr4' : '';
const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png';
@@ -245,15 +133,6 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
color: isNightVersion ? 'white' : 'black',
cursor: 'pointer',
};
- const activeNode = (
- <div className="flex relative" style={{ color: menuIconStyle.color }}>
- <div style={{ paddingRight: 10 }}>{this.props.translate.get(Key.Developers, Deco.Cap)}</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, ...{ height } }}
@@ -266,56 +145,51 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
paddingLeft={this.props.paddingLeft}
paddingRight={this.props.paddingRight}
>
- <Link to={`${WebsitePaths.Home}`} className="text-decoration-none">
+ <Link to={WebsitePaths.Home}>
<img src={logoUrl} height="30" />
</Link>
<div className="flex-auto" />
{!this._isViewingPortal() && (
<div className={menuClasses}>
<div className="flex items-center justify-between">
- <DropDown
- activeNode={activeNode}
- popoverContent={popoverContent}
- anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }}
- targetOrigin={{ horizontal: 'middle', vertical: 'top' }}
- style={styles.menuItem}
+ <DevelopersDropDown
+ location={this.props.location}
+ menuItemStyles={styles.menuItem}
+ translate={this.props.translate}
+ menuIconStyle={menuIconStyle}
/>
<TopBarMenuItem
title={this.props.translate.get(Key.Wiki, Deco.Cap)}
- path={`${WebsitePaths.Wiki}`}
+ path={WebsitePaths.Wiki}
style={styles.menuItem}
isNightVersion={isNightVersion}
- isExternal={false}
/>
<TopBarMenuItem
title={this.props.translate.get(Key.Blog, Deco.Cap)}
path={constants.URL_BLOG}
style={styles.menuItem}
isNightVersion={isNightVersion}
- isExternal={true}
+ shouldOpenInNewTab={true}
/>
<TopBarMenuItem
title={this.props.translate.get(Key.About, Deco.Cap)}
- path={`${WebsitePaths.About}`}
+ path={WebsitePaths.About}
style={styles.menuItem}
isNightVersion={isNightVersion}
- isExternal={false}
/>
<TopBarMenuItem
title={this.props.translate.get(Key.Careers, Deco.Cap)}
- path={`${WebsitePaths.Careers}`}
+ path={WebsitePaths.Careers}
style={styles.menuItem}
isNightVersion={isNightVersion}
- isExternal={false}
/>
<TopBarMenuItem
title={this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
- path={`${WebsitePaths.Portal}`}
+ path={WebsitePaths.Portal}
isPrimary={true}
style={styles.menuItem}
className={`${isExpandedDisplayType && 'md-hide'}`}
isNightVersion={isNightVersion}
- isExternal={false}
/>
</div>
</div>
@@ -377,20 +251,16 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
<div className="pl1 py1 mt3" style={{ backgroundColor: colors.lightGrey }}>
{this.props.translate.get(Key.Website, Deco.Cap)}
</div>
- <Link to={WebsitePaths.Home} className="text-decoration-none">
+ <Link to={WebsitePaths.Home}>
<MenuItem className="py2">{this.props.translate.get(Key.Home, Deco.Cap)}</MenuItem>
</Link>
- <Link to={`${WebsitePaths.Wiki}`} className="text-decoration-none">
+ <Link to={WebsitePaths.Wiki}>
<MenuItem className="py2">{this.props.translate.get(Key.Wiki, Deco.Cap)}</MenuItem>
</Link>
{_.map(DOC_WEBSITE_PATHS_TO_KEY, (key, websitePath) => {
if (!this._doesUrlInclude(websitePath)) {
return (
- <Link
- key={`drawer-menu-item-${websitePath}`}
- to={websitePath}
- className="text-decoration-none"
- >
+ <Link key={`drawer-menu-item-${websitePath}`} to={websitePath}>
<MenuItem className="py2">
{this.props.translate.get(key, Deco.Cap)}{' '}
{this.props.translate.get(Key.Docs, Deco.Cap)}
@@ -401,25 +271,25 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
return null;
})}
{!this._isViewingPortal() && (
- <Link to={`${WebsitePaths.Portal}`} className="text-decoration-none">
+ <Link to={WebsitePaths.Portal}>
<MenuItem className="py2">
{this.props.translate.get(Key.PortalDApp, Deco.CapWords)}
</MenuItem>
</Link>
)}
- <a className="text-decoration-none" target="_blank" href={`${WebsitePaths.Whitepaper}`}>
+ <Link to={WebsitePaths.Whitepaper} shouldOpenInNewTab={true}>
<MenuItem className="py2">{this.props.translate.get(Key.Whitepaper, Deco.Cap)}</MenuItem>
- </a>
- <Link to={`${WebsitePaths.About}`} className="text-decoration-none">
+ </Link>
+ <Link to={WebsitePaths.About}>
<MenuItem className="py2">{this.props.translate.get(Key.About, Deco.Cap)}</MenuItem>
</Link>
- <Link to={`${WebsitePaths.Careers}`} className="text-decoration-none">
+ <Link to={WebsitePaths.Careers}>
<MenuItem className="py2">{this.props.translate.get(Key.Careers, Deco.Cap)}</MenuItem>
</Link>
- <a className="text-decoration-none" target="_blank" href={constants.URL_BLOG}>
+ <Link to={constants.URL_BLOG} shouldOpenInNewTab={true}>
<MenuItem className="py2">{this.props.translate.get(Key.Blog, Deco.Cap)}</MenuItem>
- </a>
- <Link to={`${WebsitePaths.FAQ}`} className="text-decoration-none">
+ </Link>
+ <Link to={WebsitePaths.FAQ}>
<MenuItem className="py2" onClick={this._onMenuButtonClick.bind(this)}>
{this.props.translate.get(Key.Faq, Deco.Cap)}
</MenuItem>
@@ -436,14 +306,14 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
// because the sidebar renders `react-scroll` links which depend on the scroll container already
// being rendered.
const documentationContainer = document.getElementById(sharedConstants.SCROLL_CONTAINER_ID);
- if (!isViewingDocsPage || _.isUndefined(this.props.menu) || _.isNull(documentationContainer)) {
+ if (!isViewingDocsPage || _.isUndefined(this.props.sectionNameToLinks) || _.isNull(documentationContainer)) {
return undefined;
}
return (
<div className="lg-hide md-hide">
<NestedSidebarMenu
- topLevelMenu={this.props.menu}
- menuSubsectionsBySection={this.props.menuSubsectionsBySection}
+ sectionNameToLinks={this.props.sectionNameToLinks}
+ subsectionNameToLinks={this.props.subsectionNameToLinks}
sidebarHeader={this.props.sidebarHeader}
shouldDisplaySectionHeaders={false}
onMenuItemClick={this._onMenuButtonClick.bind(this)}
@@ -462,8 +332,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
return (
<div className="lg-hide md-hide">
<NestedSidebarMenu
- topLevelMenu={this.props.menuSubsectionsBySection}
- menuSubsectionsBySection={this.props.menuSubsectionsBySection}
+ sectionNameToLinks={this.props.sectionNameToLinks}
+ subsectionNameToLinks={this.props.subsectionNameToLinks}
sidebarHeader={this.props.sidebarHeader}
shouldDisplaySectionHeaders={false}
onMenuItemClick={this._onMenuButtonClick.bind(this)}
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
index 25fab2868..eff5ba66d 100644
--- a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
+++ b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
@@ -1,7 +1,6 @@
-import { colors } from '@0xproject/react-shared';
+import { colors, Link } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
-import { Link } from 'react-router-dom';
import { CallToAction } from 'ts/components/ui/button';
@@ -13,7 +12,7 @@ interface TopBarMenuItemProps {
title: string;
path?: string;
isPrimary?: boolean;
- isExternal: boolean;
+ shouldOpenInNewTab?: boolean;
style?: React.CSSProperties;
className?: string;
isNightVersion?: boolean;
@@ -26,6 +25,7 @@ export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarM
isPrimary: false,
style: DEFAULT_STYLE,
className: '',
+ shouldOpenInNewTab: false,
isNightVersion: false,
};
public render(): React.ReactNode {
@@ -38,20 +38,9 @@ export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarM
);
return (
<div className={`center ${this.props.className}`} style={{ ...this.props.style, color: menuItemColor }}>
- {this.props.isExternal ? (
- <a
- className="text-decoration-none"
- style={{ color: linkColor }}
- target="_blank"
- href={this.props.path}
- >
- {itemContent}
- </a>
- ) : (
- <Link to={this.props.path} className="text-decoration-none" style={{ color: linkColor }}>
- {itemContent}
- </Link>
- )}
+ <Link to={this.props.path} shouldOpenInNewTab={this.props.shouldOpenInNewTab} fontColor={linkColor}>
+ {itemContent}
+ </Link>
</div>
);
}
diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx
index f2ae68b70..ece077563 100644
--- a/packages/website/ts/components/ui/container.tsx
+++ b/packages/website/ts/components/ui/container.tsx
@@ -15,7 +15,11 @@ export interface ContainerProps {
paddingRight?: StringOrNum;
paddingLeft?: StringOrNum;
backgroundColor?: string;
+ background?: string;
borderRadius?: StringOrNum;
+ borderBottomLeftRadius?: StringOrNum;
+ borderBottomRightRadius?: StringOrNum;
+ borderBottom?: StringOrNum;
maxWidth?: StringOrNum;
maxHeight?: StringOrNum;
width?: StringOrNum;
diff --git a/packages/website/ts/components/ui/menu_item.tsx b/packages/website/ts/components/ui/custom_menu_item.tsx
index 0cb4b387c..c25da6be6 100644
--- a/packages/website/ts/components/ui/menu_item.tsx
+++ b/packages/website/ts/components/ui/custom_menu_item.tsx
@@ -1,24 +1,23 @@
+import { Link } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
-import { Link } from 'react-router-dom';
-interface MenuItemProps {
+interface CustomMenuItemProps {
to: string;
- style?: React.CSSProperties;
onClick?: () => void;
className?: string;
}
-interface MenuItemState {
+interface CustomMenuItemState {
isHovering: boolean;
}
-export class MenuItem extends React.Component<MenuItemProps, MenuItemState> {
- public static defaultProps: Partial<MenuItemProps> = {
+export class CustomMenuItem extends React.Component<CustomMenuItemProps, CustomMenuItemState> {
+ public static defaultProps: Partial<CustomMenuItemProps> = {
onClick: _.noop.bind(_),
className: '',
};
- public constructor(props: MenuItemProps) {
+ public constructor(props: CustomMenuItemProps) {
super(props);
this.state = {
isHovering: false,
@@ -30,7 +29,7 @@ export class MenuItem extends React.Component<MenuItemProps, MenuItemState> {
opacity: this.state.isHovering ? 0.5 : 1,
};
return (
- <Link to={this.props.to} style={{ textDecoration: 'none', ...this.props.style }}>
+ <Link to={this.props.to}>
<div
onClick={this.props.onClick.bind(this)}
className={`mx-auto ${this.props.className}`}
diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx
index 4d5caef08..1daaeb1c3 100644
--- a/packages/website/ts/components/ui/drop_down.tsx
+++ b/packages/website/ts/components/ui/drop_down.tsx
@@ -21,6 +21,7 @@ export interface DropDownProps {
zDepth?: number;
activateEvent?: DropdownMouseEvent;
closeEvent?: DropdownMouseEvent;
+ popoverStyle?: React.CSSProperties;
}
interface DropDownState {
@@ -34,6 +35,7 @@ export class DropDown extends React.Component<DropDownProps, DropDownState> {
zDepth: 1,
activateEvent: DropdownMouseEvent.Hover,
closeEvent: DropdownMouseEvent.Hover,
+ popoverStyle: {},
};
private _isHovering: boolean;
private _popoverCloseCheckIntervalId: number;
@@ -77,6 +79,7 @@ export class DropDown extends React.Component<DropDownProps, DropDownState> {
useLayerForClickAway={this.props.closeEvent === DropdownMouseEvent.Click}
animated={false}
zDepth={this.props.zDepth}
+ style={this.props.popoverStyle}
>
<div
onMouseEnter={this._onHover.bind(this)}
diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx
index 8a9349c6d..bdaf0701e 100644
--- a/packages/website/ts/components/ui/simple_menu.tsx
+++ b/packages/website/ts/components/ui/simple_menu.tsx
@@ -1,7 +1,7 @@
+import { Link } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import * as CopyToClipboard from 'react-copy-to-clipboard';
-import { Link } from 'react-router-dom';
import { Container } from 'ts/components/ui/container';
import { Text } from 'ts/components/ui/text';
@@ -72,7 +72,7 @@ export const GoToAccountManagementSimpleMenuItem: React.StatelessComponent<
GoToAccountManagementSimpleMenuItemProps
> = ({ onClick }) => {
return (
- <Link to={`${WebsitePaths.Portal}/account`} style={{ textDecoration: 'none' }}>
+ <Link to={`${WebsitePaths.Portal}/account`}>
<SimpleMenuItem displayText="Manage Account..." onClick={onClick} />
</Link>
);
diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx
index cd8f290e3..4415962b1 100644
--- a/packages/website/ts/components/ui/text.tsx
+++ b/packages/website/ts/components/ui/text.tsx
@@ -19,7 +19,9 @@ export interface TextProps {
textDecorationLine?: string;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
hoverColor?: string;
+ letterSpacing?: string | number;
noWrap?: boolean;
+ textAlign?: string;
display?: string;
}
@@ -34,6 +36,8 @@ export const Text = styled(PlainText)`
font-style: ${props => props.fontStyle};
font-weight: ${props => props.fontWeight};
font-size: ${props => props.fontSize};
+ text-align: ${props => props.textAlign};
+ letter-spacing: ${props => props.letterSpacing};
text-decoration-line: ${props => props.textDecorationLine};
${props => (props.lineHeight ? `line-height: ${props.lineHeight}` : '')};
${props => (props.center ? 'text-align: center' : '')};
diff --git a/packages/website/ts/containers/docs_home.ts b/packages/website/ts/containers/docs_home.ts
new file mode 100644
index 000000000..9c7b70a6f
--- /dev/null
+++ b/packages/website/ts/containers/docs_home.ts
@@ -0,0 +1,28 @@
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { Home as HomeComponent, HomeProps } from 'ts/pages/documentation/home';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { ScreenWidths } from 'ts/types';
+import { Translate } from 'ts/utils/translate';
+
+interface ConnectedState {
+ translate: Translate;
+ screenWidth: ScreenWidths;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, _ownProps: HomeProps): ConnectedState => ({
+ translate: state.translate,
+ screenWidth: state.screenWidth,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const DocsHome: React.ComponentClass<HomeProps> = connect(mapStateToProps, mapDispatchToProps)(HomeComponent);
diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx
index d4a79cc4f..4f0a12f20 100644
--- a/packages/website/ts/index.tsx
+++ b/packages/website/ts/index.tsx
@@ -5,6 +5,7 @@ import { Provider } from 'react-redux';
import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom';
import { MetaTags } from 'ts/components/meta_tags';
import { About } from 'ts/containers/about';
+import { DocsHome } from 'ts/containers/docs_home';
import { FAQ } from 'ts/containers/faq';
import { Jobs } from 'ts/containers/jobs';
import { Landing } from 'ts/containers/landing';
@@ -133,6 +134,7 @@ render(
path={`${WebsitePaths.EthereumTypes}/:version?`}
component={LazyEthereumTypesDocumentation}
/>
+ <Route path={WebsitePaths.Docs} component={DocsHome as any} />
{/* Legacy endpoints */}
<Route
diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx
index 2629f8632..5f42dfa97 100644
--- a/packages/website/ts/pages/about/about.tsx
+++ b/packages/website/ts/pages/about/about.tsx
@@ -1,8 +1,7 @@
-import { colors, Styles } from '@0xproject/react-shared';
+import { colors, Link, Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import * as DocumentTitle from 'react-document-title';
-import { Link } from 'react-router-dom';
import { Footer } from 'ts/components/footer';
import { TopBar } from 'ts/components/top_bar/top_bar';
import { Profile } from 'ts/pages/about/profile';
@@ -388,7 +387,7 @@ export class About extends React.Component<AboutProps, AboutState> {
}}
>
We are seeking outstanding candidates to{' '}
- <Link to={WebsitePaths.Careers} style={{ color: 'black' }}>
+ <Link to={WebsitePaths.Careers} textDecoration="underline" fontColor="black">
join our team
</Link>
. We value passion, diversity and unique perspectives.
diff --git a/packages/website/ts/pages/documentation/doc_page.tsx b/packages/website/ts/pages/documentation/doc_page.tsx
index 87a806b2b..c64751f65 100644
--- a/packages/website/ts/pages/documentation/doc_page.tsx
+++ b/packages/website/ts/pages/documentation/doc_page.tsx
@@ -79,9 +79,9 @@ export class DocPage extends React.Component<DocPageProps, DocPageState> {
this._isUnmounted = true;
}
public render(): React.ReactNode {
- const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat)
+ const subsectionNameToLinks = _.isUndefined(this.state.docAgnosticFormat)
? {}
- : this.props.docsInfo.getMenuSubsectionsBySection(this.state.docAgnosticFormat);
+ : this.props.docsInfo.getSubsectionNameToLinks(this.state.docAgnosticFormat);
const sourceUrl = this._getSourceUrl();
const iconFileName = idToIcon[this.props.docsInfo.id] || DEFAULT_ICON;
const iconUrl = `/images/doc_icons/${iconFileName}`;
@@ -93,8 +93,8 @@ export class DocPage extends React.Component<DocPageProps, DocPageState> {
location={this.props.location}
docsVersion={this.props.docsVersion}
availableDocVersions={this.props.availableDocVersions}
- menu={this.props.docsInfo.menu}
- menuSubsectionsBySection={menuSubsectionsBySection}
+ sectionNameToLinks={this.props.docsInfo.getSectionNameToLinks()}
+ subsectionNameToLinks={subsectionNameToLinks}
docsInfo={this.props.docsInfo}
translate={this.props.translate}
onVersionSelected={this._onVersionSelected.bind(this)}
diff --git a/packages/website/ts/pages/documentation/home.tsx b/packages/website/ts/pages/documentation/home.tsx
new file mode 100644
index 000000000..f7c4839b4
--- /dev/null
+++ b/packages/website/ts/pages/documentation/home.tsx
@@ -0,0 +1,623 @@
+import {
+ ALink,
+ colors,
+ constants as sharedConstants,
+ Link,
+ MarkdownLinkBlock,
+ NestedSidebarMenu,
+ utils as sharedUtils,
+} from '@0xproject/react-shared';
+import { ObjectMap } from '@0xproject/types';
+import * as _ from 'lodash';
+import * as React from 'react';
+import DocumentTitle = require('react-document-title');
+import * as ReactMarkdown from 'react-markdown';
+import { Element as ScrollElement } from 'react-scroll';
+import { DocsLogo } from 'ts/components/documentation/docs_logo';
+import { DocsTopBar } from 'ts/components/documentation/docs_top_bar';
+import { TutorialButton } from 'ts/components/documentation/tutorial_button';
+import { Container } from 'ts/components/ui/container';
+import { Text } from 'ts/components/ui/text';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { Deco, Key, ScreenWidths, TutorialInfo, WebsitePaths } from 'ts/types';
+import { Translate } from 'ts/utils/translate';
+import { utils } from 'ts/utils/utils';
+
+const THROTTLE_TIMEOUT = 100;
+const TOP_BAR_HEIGHT = 80;
+const SCROLLER_WIDTH = 4;
+const TUTORIALS: TutorialInfo[] = [
+ {
+ iconUrl: '/images/developers/tutorials/develop_on_ethereum.svg',
+ description: Key.DevelopOnEthereumDescription,
+ link: {
+ title: Key.DevelopOnEthereum,
+ to: `${WebsitePaths.Wiki}#Ethereum-Development`,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ iconUrl: '/images/developers/tutorials/build_a_relayer.svg',
+ description: Key.BuildARelayerDescription,
+ link: {
+ title: Key.BuildARelayer,
+ to: `${WebsitePaths.Wiki}#Build-A-Relayer`,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ iconUrl: '/images/developers/tutorials/0x_order_basics.svg',
+ description: Key.OrderBasicsDescription,
+ link: {
+ title: Key.OrderBasics,
+ to: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ iconUrl: '/images/developers/tutorials/use_shared_liquidity.svg',
+ description: Key.UseSharedLiquidityDescription,
+ link: {
+ title: Key.UseSharedLiquidity,
+ to: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`,
+ shouldOpenInNewTab: true,
+ },
+ },
+];
+enum Categories {
+ ZeroExProtocol = '0x Protocol',
+ Ethereum = 'Ethereum',
+ CommunityMaintained = 'Community Maintained',
+}
+// TODO(fabio): Move this to it's own file
+const CATEGORY_TO_PACKAGES: { [category: string]: Package[] } = {
+ [Categories.ZeroExProtocol]: [
+ {
+ description:
+ 'A library for interacting with the 0x protocol. It is a high level package which combines a number of smaller specific-purpose packages such as [order-utils](https://0xproject.com/docs/order-utils) and [contract-wrappers](https://0xproject.com/docs/contract-wrappers).',
+ link: {
+ title: '0x.js',
+ to: WebsitePaths.ZeroExJs,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A Typescript starter project that will walk you through the basics of how to interact with 0x Protocol and trade of an SRA relayer',
+ link: {
+ title: '0x starter project',
+ to: 'https://github.com/0xProject/0x-starter-project',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'An http & websocket client for interacting with relayers that have implemented the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api)',
+ link: {
+ title: '@0xproject/connect',
+ to: WebsitePaths.Connect,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'Typescript/Javascript wrappers of the 0x protocol Ethereum smart contracts. Use this library to call methods on the 0x smart contracts, subscribe to contract events and to fetch information stored in contracts.',
+ link: {
+ title: '@0xproject/contract-wrappers',
+ to: WebsitePaths.ContractWrappers,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A collection of 0x-related JSON-schemas (incl. SRA request/response schemas, 0x order message format schema, etc...)',
+ link: {
+ title: '@0xproject/json-schemas',
+ to: WebsitePaths.JSONSchemas,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A set of utils for working with 0x orders. It includes utilities for creating, signing, validating 0x orders, encoding/decoding assetData and much more.',
+ link: {
+ title: '@0xproject/order-utils',
+ to: WebsitePaths.OrderUtils,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ "A daemon that watches a set of 0x orders and emits events when an order's fillability has changed. Can be used by a relayer to prune their orderbook or by a trader to keep their view of the market up-to-date.",
+ link: {
+ title: '@0xproject/order-watcher',
+ to: WebsitePaths.OrderWatcher,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'Contains the Standard Relayer API OpenAPI Spec. The package distributes both a javascript object version and a json version.',
+ link: {
+ title: '@0xproject/sra-spec',
+ to: 'https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-spec',
+ shouldOpenInNewTab: true,
+ },
+ },
+ ],
+ [Categories.Ethereum]: [
+ {
+ description:
+ "This package allows you to generate TypeScript contract wrappers from ABI files. It's heavily inspired by Geth abigen but takes a different approach. You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions.",
+ link: {
+ title: 'abi-gen',
+ to: 'https://github.com/0xProject/0x-monorepo/tree/development/packages/abi-gen',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A collection of Typescript types that are useful when working on an Ethereum-based project (e.g RawLog, Transaction, TxData, SolidityTypes, etc...).',
+ link: {
+ title: 'ethereum-types',
+ to: WebsitePaths.EthereumTypes,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A wrapper around [solc-js](https://github.com/ethereum/solc-js) that adds smart re-compilation, ability to compile an entire project, Solidity version specific compilation, standard input description support and much more.',
+ link: {
+ title: '@0xproject/sol-compiler',
+ to: WebsitePaths.SolCompiler,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A Solidity code coverage tool. Sol-cov uses transaction traces to figure out which lines of your code has been covered by your tests.',
+ link: {
+ title: '@0xproject/sol-cov',
+ to: WebsitePaths.SolCov,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A collection of subproviders to use with [web3-provider-engine](https://www.npmjs.com/package/web3-provider-engine) (e.g subproviders for interfacing with Ledger hardware wallet, Mnemonic wallet, private key wallet, etc...)',
+ link: {
+ title: '@0xproject/subproviders',
+ to: WebsitePaths.Subproviders,
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A raw Ethereum JSON RPC client to simplify interfacing with Ethereum nodes. Also includes some convenience functions for awaiting transactions to be mined, converting between token units, etc...',
+ link: {
+ title: '@0xproject/web3-wrapper',
+ to: WebsitePaths.Web3Wrapper,
+ shouldOpenInNewTab: true,
+ },
+ },
+ ],
+ [Categories.CommunityMaintained]: [
+ {
+ description:
+ 'Node.js worker originally built for 0x Tracker which extracts 0x fill events from the Ethereum blockchain and persists them to MongoDB. Support for both V1 and V2 of the 0x protocol is included with events tagged against the protocol version they belong to.',
+ link: {
+ title: '0x Event Extractor',
+ to: 'https://github.com/0xTracker/0x-event-extractor',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'Node.js worker built for 0x Tracker which performs various ETL tasks related to the 0x protocol trading data and other information used on 0x Tracker.',
+ link: {
+ title: '0x Tracker Worker',
+ to: 'https://github.com/0xTracker/0x-tracker-worker',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ "ERCdex's Javascript SDK for trading on their relayer, as well as other Aquaduct partner relayers",
+ link: {
+ title: 'Aquaduct',
+ to: 'https://www.npmjs.com/package/aqueduct',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'SDKs for automation using Aqueduct & ERC dEX. Aqueduct Server is a lightweight, portable and secure server that runs locally on any workstation. The server exposes a small number of foundational endpoints that enable working with the decentralized Aqueduct liquidity pool from any context or programming language.',
+ link: {
+ title: 'Aquaduct Server SDK',
+ to: 'https://github.com/ERCdEX/aqueduct-server-sdk',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description: 'A node.js SDK for trading on the DDEX relayer',
+ link: {
+ to: 'https://www.npmjs.com/package/ddex-api',
+ title: 'DDEX Node.js SDK',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description: "The ERC dEX Trade Widget let's any website provide token liquidity to it's users",
+ link: {
+ to: 'https://github.com/ERCdEX/widget',
+ title: 'ERCdex Widget',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description: "ERCdex's Java SDK for trading on their relayer, as well as other Aquaduct partner relayers",
+ link: {
+ to: 'https://github.com/ERCdEX/java',
+ title: 'ERCdex Java SDK',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description: "ERCdex's Python SDK for trading on their relayer, as well as other Aquaduct partner relayers",
+ link: {
+ to: 'https://github.com/ERCdEX/python',
+ title: 'ERCdex Python SDK',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A set of command-line tools for creating command-line scripts for interacting with the Ethereum blockchain in general, and 0x in particular',
+ link: {
+ title: 'Massive',
+ to: 'https://github.com/NoteGio/massive',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description: 'An open-source API-only Relayer written in Go',
+ link: {
+ to: 'https://github.com/NoteGio/openrelay',
+ title: 'OpenRelay',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'A JavaScript Library for Interacting with OpenRelay.xyz and other 0x Standard Relayer API Implementations',
+ link: {
+ title: 'OpenRelay.js',
+ to: 'https://github.com/NoteGio/openrelay.js',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'The Radar Relay SDK is a software development kit that simplifies the interactions with Radar Relay’s APIs',
+ link: {
+ title: 'Radar SDK',
+ to: 'https://github.com/RadarRelay/sdk',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description:
+ 'The Ocean provides a simple REST API, WebSockets API, and JavaScript library to help you integrate decentralized trading into your existing trading strategy.',
+ link: {
+ title: 'The Ocean Javascript SDK',
+ to: 'https://github.com/TheOceanTrade/theoceanx-javascript',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description: "Tokenlon SDK provides APIs for developers to trade of imToken's relayer",
+ link: {
+ to: 'https://www.npmjs.com/package/tokenlon-sdk',
+ title: 'Tokenlon Javascript SDK',
+ shouldOpenInNewTab: true,
+ },
+ },
+ {
+ description: 'A small library that implements the 0x order assetData encoding/decoding in Java',
+ link: {
+ to: 'https://github.com/wildnothing/asset-data-decoder',
+ title: 'AssetData decoder library in Java',
+ shouldOpenInNewTab: true,
+ },
+ },
+ ],
+};
+
+interface Package {
+ description: string;
+ link: ALink;
+}
+
+export interface HomeProps {
+ location: Location;
+ translate: Translate;
+ screenWidth: ScreenWidths;
+ dispatcher: Dispatcher;
+}
+
+export interface HomeState {
+ isHoveringSidebar: boolean;
+ isHoveringMainContent: boolean;
+ isSidebarScrolling: boolean;
+}
+
+export class Home extends React.Component<HomeProps, HomeState> {
+ private readonly _throttledScreenWidthUpdate: () => void;
+ private readonly _throttledSidebarScrolling: () => void;
+ private _sidebarScrollClearingInterval: number;
+ constructor(props: HomeProps) {
+ super(props);
+ this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
+ this._throttledSidebarScrolling = _.throttle(this._onSidebarScroll.bind(this), THROTTLE_TIMEOUT);
+ this.state = {
+ isHoveringSidebar: false,
+ isHoveringMainContent: false,
+ isSidebarScrolling: false,
+ };
+ }
+ public componentDidMount(): void {
+ window.addEventListener('resize', this._throttledScreenWidthUpdate);
+ window.scrollTo(0, 0);
+ this._sidebarScrollClearingInterval = window.setInterval(() => {
+ this.setState({
+ isSidebarScrolling: false,
+ });
+ }, 1000);
+ }
+ public componentWillUnmount(): void {
+ window.removeEventListener('resize', this._throttledScreenWidthUpdate);
+ window.clearInterval(this._sidebarScrollClearingInterval);
+ }
+ public render(): React.ReactNode {
+ const scrollableContainerStyles: React.CSSProperties = {
+ position: 'absolute',
+ top: 80,
+ left: 0,
+ bottom: 0,
+ right: 0,
+ overflowX: 'hidden',
+ overflowY: 'scroll',
+ minHeight: `calc(100vh - ${TOP_BAR_HEIGHT}px)`,
+ WebkitOverflowScrolling: 'touch',
+ };
+ const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
+ const mainContentPadding = isSmallScreen ? 20 : 50;
+ const sectionNameToLinks: ObjectMap<ALink[]> = {
+ 'Starter guides': _.map(TUTORIALS, tutorialInfo => {
+ return {
+ ...tutorialInfo.link,
+ title: this.props.translate.get(tutorialInfo.link.title as Key, Deco.Cap),
+ };
+ }),
+ [Categories.ZeroExProtocol]: _.map(CATEGORY_TO_PACKAGES[Categories.ZeroExProtocol], pkg => pkg.link),
+ [Categories.Ethereum]: _.map(CATEGORY_TO_PACKAGES[Categories.Ethereum], pkg => pkg.link),
+ [Categories.CommunityMaintained]: _.map(
+ CATEGORY_TO_PACKAGES[Categories.CommunityMaintained],
+ pkg => pkg.link,
+ ),
+ };
+ return (
+ <Container
+ className="flex items-center overflow-hidden"
+ width="100%"
+ background={`linear-gradient(to right, ${colors.grey100} 0%, ${colors.grey100} 50%, ${
+ colors.white
+ } 50%, ${colors.white} 100%)`}
+ >
+ <DocumentTitle title="0x Docs Home" />
+ <Container className="flex mx-auto" height="100vh">
+ <Container
+ className="sm-hide xs-hide relative"
+ width={234}
+ paddingLeft={22}
+ paddingRight={22}
+ paddingTop={0}
+ backgroundColor={colors.grey100}
+ >
+ <Container
+ borderBottom={this.state.isSidebarScrolling ? `1px solid ${colors.grey300}` : 'none'}
+ >
+ <Container paddingTop="30px" paddingLeft="10px" paddingBottom="8px">
+ <DocsLogo height={36} />
+ </Container>
+ </Container>
+ <div
+ style={{
+ ...scrollableContainerStyles,
+ paddingTop: 27,
+ overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden',
+ }}
+ onMouseEnter={this._onSidebarHover.bind(this, true)}
+ onMouseLeave={this._onSidebarHover.bind(this, false)}
+ onWheel={this._throttledSidebarScrolling}
+ >
+ <Container paddingLeft="22px" paddingRight="22px" paddingBottom="100px">
+ <NestedSidebarMenu
+ sectionNameToLinks={sectionNameToLinks}
+ shouldReformatMenuItemNames={false}
+ />
+ </Container>
+ </div>
+ </Container>
+ <Container
+ className="relative"
+ width={isSmallScreen ? '100vw' : 716}
+ paddingBottom="100px"
+ backgroundColor={colors.white}
+ >
+ <Container paddingLeft={mainContentPadding} paddingRight={mainContentPadding}>
+ <DocsTopBar
+ location={this.props.location}
+ translate={this.props.translate}
+ sectionNameToLinks={sectionNameToLinks}
+ />
+ </Container>
+ <div
+ id={sharedConstants.SCROLL_CONTAINER_ID}
+ className="absolute"
+ style={{
+ ...scrollableContainerStyles,
+ paddingTop: 30,
+ paddingLeft: mainContentPadding,
+ paddingRight: this.state.isHoveringMainContent
+ ? mainContentPadding - SCROLLER_WIDTH
+ : mainContentPadding,
+ overflow: this.state.isHoveringMainContent ? 'auto' : 'hidden',
+ }}
+ onMouseEnter={this._onMainContentHover.bind(this, true)}
+ onMouseOver={this._onMainContentHover.bind(this, true)}
+ onMouseLeave={this._onMainContentHover.bind(this, false)}
+ >
+ <Container>
+ {this._renderSectionTitle(this.props.translate.get(Key.StartBuildOn0x, Deco.Cap))}
+ <Container paddingTop="12px">
+ {this._renderSectionDescription(
+ this.props.translate.get(Key.StartBuildOn0xDescription, Deco.Cap),
+ )}
+ <Container marginTop="36px">
+ {_.map(TUTORIALS, tutorialInfo => (
+ <ScrollElement
+ name={sharedUtils.getIdFromName(
+ this.props.translate.get(tutorialInfo.link.title as Key, Deco.Cap),
+ )}
+ key={`tutorial-${tutorialInfo.link.title}`}
+ >
+ <TutorialButton
+ translate={this.props.translate}
+ tutorialInfo={tutorialInfo}
+ />
+ </ScrollElement>
+ ))}
+ </Container>
+ </Container>
+ <Container marginTop="32px" paddingBottom="100px">
+ {this._renderSectionTitle(
+ this.props.translate.get(Key.LibrariesAndTools, Deco.CapWords),
+ )}
+ <Container paddingTop="12px">
+ {this._renderSectionDescription(
+ this.props.translate.get(Key.LibrariesAndToolsDescription, Deco.Cap),
+ )}
+ <Container marginTop="36px">
+ {_.map(CATEGORY_TO_PACKAGES, (pkgs, category) =>
+ this._renderPackageCategory(category, pkgs),
+ )}
+ </Container>
+ </Container>
+ </Container>
+ </Container>
+ </div>
+ </Container>
+ </Container>
+ </Container>
+ );
+ }
+ private _renderPackageCategory(category: string, pkgs: Package[]): React.ReactNode {
+ return (
+ <Container key={`category-${category}`}>
+ <Text fontSize="18px">{category}</Text>
+ <Container>{_.map(pkgs, pkg => this._renderPackage(pkg))}</Container>
+ </Container>
+ );
+ }
+ private _renderPackage(pkg: Package): React.ReactNode {
+ const id = sharedUtils.getIdFromName(pkg.link.title);
+ return (
+ <ScrollElement name={id} key={`package-${pkg.link.title}`}>
+ <Container className="pb2">
+ <Container width="100%" height="1px" backgroundColor={colors.grey300} marginTop="11px" />
+ <Container className="clearfix mt2 pt1">
+ <Container className="md-col lg-col md-col-4 lg-col-4">
+ <Link
+ to={pkg.link.to}
+ fontColor={colors.lightLinkBlue}
+ shouldOpenInNewTab={!!pkg.link.shouldOpenInNewTab}
+ >
+ <Text Tag="div" fontColor={colors.lightLinkBlue} fontWeight="bold">
+ {pkg.link.title}
+ </Text>
+ </Link>
+ </Container>
+ <Container className="md-col lg-col md-col-6 lg-col-6 sm-py2">
+ <Text fontColor={colors.grey700}>
+ <ReactMarkdown
+ source={pkg.description}
+ renderers={{
+ link: MarkdownLinkBlock,
+ paragraph: 'span',
+ }}
+ />
+ </Text>
+ </Container>
+ <Container className="md-col lg-col md-col-2 lg-col-2 sm-pb2 relative">
+ <Container position="absolute" right="0px">
+ <Link
+ to={pkg.link.to}
+ fontColor={colors.lightLinkBlue}
+ shouldOpenInNewTab={!!pkg.link.shouldOpenInNewTab}
+ >
+ <Container className="flex">
+ <Container>{this.props.translate.get(Key.More, Deco.Cap)}</Container>
+ <Container paddingTop="1px" paddingLeft="6px">
+ <i
+ className="zmdi zmdi-chevron-right bold"
+ style={{ fontSize: 18, color: colors.lightLinkBlue }}
+ />
+ </Container>
+ </Container>
+ </Link>
+ </Container>
+ </Container>
+ </Container>
+ </Container>
+ </ScrollElement>
+ );
+ }
+ private _renderSectionTitle(text: string): React.ReactNode {
+ return (
+ <Text fontColor={colors.projectsGrey} fontSize="30px" fontWeight="bold">
+ {text}
+ </Text>
+ );
+ }
+ private _renderSectionDescription(text: string): React.ReactNode {
+ return (
+ <Text fontColor={colors.linkSectionGrey} fontSize="16px" fontFamily="Roboto Mono">
+ {text}
+ </Text>
+ );
+ }
+ private _onSidebarHover(isHovering: boolean, _event: React.FormEvent<HTMLInputElement>): void {
+ if (isHovering !== this.state.isHoveringSidebar) {
+ this.setState({
+ isHoveringSidebar: isHovering,
+ });
+ }
+ }
+ private _onMainContentHover(isHovering: boolean, _event: React.FormEvent<HTMLInputElement>): void {
+ if (isHovering !== this.state.isHoveringMainContent) {
+ this.setState({
+ isHoveringMainContent: isHovering,
+ });
+ }
+ }
+ private _onSidebarScroll(_event: React.FormEvent<HTMLInputElement>): void {
+ this.setState({
+ isSidebarScrolling: true,
+ });
+ }
+ private _updateScreenWidth(): void {
+ const newScreenWidth = utils.getScreenWidth();
+ this.props.dispatcher.updateScreenWidth(newScreenWidth);
+ }
+} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx
index 388e83d51..395cdabf8 100644
--- a/packages/website/ts/pages/landing/landing.tsx
+++ b/packages/website/ts/pages/landing/landing.tsx
@@ -1,8 +1,7 @@
-import { colors } from '@0xproject/react-shared';
+import { colors, Link } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import DocumentTitle = require('react-document-title');
-import { Link } from 'react-router-dom';
import { Footer } from 'ts/components/footer';
import { SubscribeForm } from 'ts/components/forms/subscribe_form';
import { TopBar } from 'ts/components/top_bar/top_bar';
@@ -213,14 +212,14 @@ export class Landing extends React.Component<LandingProps, LandingState> {
className={`pt3 flex clearfix sm-mx-auto ${isSmallScreen ? 'justify-center' : ''}`}
>
<Container paddingRight="20px">
- <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
+ <Link to={WebsitePaths.ZeroExJs}>
<CallToAction type="light">
{this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
</CallToAction>
</Link>
</Container>
<div>
- <Link to={WebsitePaths.Portal} className="text-decoration-none">
+ <Link to={WebsitePaths.Portal}>
<CallToAction>
{this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
</CallToAction>
@@ -318,11 +317,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
}}
>
{this.props.translate.get(Key.FullListPrompt)}{' '}
- <Link
- to={WebsitePaths.Portal}
- className="text-decoration-none underline"
- style={{ color: colors.landingLinkGrey }}
- >
+ <Link to={WebsitePaths.Portal} textDecoration="underline" fontColor={colors.landingLinkGrey}>
{this.props.translate.get(Key.FullListLink)}
</Link>
</div>
@@ -603,7 +598,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
{this.props.translate.get(Key.FinalCallToAction, Deco.Cap)}
</div>
<div className="sm-center sm-pt2 lg-table-cell md-table-cell">
- <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
+ <Link to={WebsitePaths.ZeroExJs}>
<CallToAction fontSize="15px">
{this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
</CallToAction>
diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx
index 55f532b11..70f54aceb 100644
--- a/packages/website/ts/pages/wiki/wiki.tsx
+++ b/packages/website/ts/pages/wiki/wiki.tsx
@@ -1,4 +1,5 @@
import {
+ ALink,
colors,
constants as sharedConstants,
HeaderSizes,
@@ -7,6 +8,7 @@ import {
Styles,
utils as sharedUtils,
} from '@0xproject/react-shared';
+import { ObjectMap } from '@0xproject/types';
import * as _ from 'lodash';
import CircularProgress from 'material-ui/CircularProgress';
import RaisedButton from 'material-ui/RaisedButton';
@@ -78,9 +80,9 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
window.removeEventListener('hashchange', this._onHashChanged.bind(this), false);
}
public render(): React.ReactNode {
- const menuSubsectionsBySection = _.isUndefined(this.state.articlesBySection)
+ const sectionNameToLinks = _.isUndefined(this.state.articlesBySection)
? {}
- : this._getMenuSubsectionsBySection(this.state.articlesBySection);
+ : this._getSectionNameToLinks(this.state.articlesBySection);
const mainContainersStyle: React.CSSProperties = {
...styles.mainContainers,
overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden',
@@ -92,7 +94,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
<TopBar
blockchainIsLoaded={false}
location={this.props.location}
- menuSubsectionsBySection={menuSubsectionsBySection}
+ sectionNameToLinks={sectionNameToLinks}
translate={this.props.translate}
sidebarHeader={sidebarHeader}
/>
@@ -131,8 +133,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
onMouseLeave={this._onSidebarHoverOff.bind(this)}
>
<NestedSidebarMenu
- topLevelMenu={menuSubsectionsBySection}
- menuSubsectionsBySection={menuSubsectionsBySection}
+ sectionNameToLinks={sectionNameToLinks}
sidebarHeader={sidebarHeader}
/>
</div>
@@ -223,15 +224,20 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
}
}
}
- private _getMenuSubsectionsBySection(articlesBySection: ArticlesBySection): { [section: string]: string[] } {
+ private _getSectionNameToLinks(articlesBySection: ArticlesBySection): ObjectMap<ALink[]> {
const sectionNames = _.keys(articlesBySection);
- const menuSubsectionsBySection: { [section: string]: string[] } = {};
+ const sectionNameToLinks: ObjectMap<ALink[]> = {};
for (const sectionName of sectionNames) {
const articles = articlesBySection[sectionName];
- const articleNames = _.map(articles, article => article.title);
- menuSubsectionsBySection[sectionName] = articleNames;
+ const articleLinks = _.map(articles, article => {
+ return {
+ to: sharedUtils.getIdFromName(article.title),
+ title: article.title,
+ };
+ });
+ sectionNameToLinks[sectionName] = articleLinks;
}
- return menuSubsectionsBySection;
+ return sectionNameToLinks;
}
private _onSidebarHover(_event: React.FormEvent<HTMLInputElement>): void {
this.setState({
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index 4ec45c46e..a3d248a9d 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -1,3 +1,4 @@
+import { ALink } from '@0xproject/react-shared';
import { ObjectMap, SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { Provider } from 'ethereum-types';
@@ -458,6 +459,23 @@ export enum Key {
RocketChat = 'ROCKETCHAT',
TradeCallToAction = 'TRADE_CALL_TO_ACTION',
OurMissionAndValues = 'OUR_MISSION_AND_VALUES',
+ BuildARelayer = 'BUILD_A_RELAYER',
+ BuildARelayerDescription = 'BUILD_A_RELAYER_DESCRIPTION',
+ DevelopOnEthereum = 'DEVELOP_ON_ETHEREUM',
+ DevelopOnEthereumDescription = 'DEVELOP_ON_ETHEREUM_DESCRIPTION',
+ OrderBasics = 'ORDER_BASICS',
+ OrderBasicsDescription = 'ORDER_BASICS_DESCRIPTION',
+ UseSharedLiquidity = 'USE_SHARED_LIQUIDITY',
+ UseSharedLiquidityDescription = 'USE_SHARED_LIQUIDITY_DESCRIPTION',
+ ViewAllDocumentation = 'VIEW_ALL_DOCUMENTATION',
+ Sandbox = 'SANDBOX',
+ Github = 'GITHUB',
+ LiveChat = 'LIVE_CHAT',
+ LibrariesAndTools = 'LIBRARIES_AND_TOOLS',
+ LibrariesAndToolsDescription = 'LIBRARIES_AND_TOOLS_DESCRIPTION',
+ More = 'MORE',
+ StartBuildOn0x = 'START_BUILDING_ON_0X',
+ StartBuildOn0xDescription = 'START_BUILDING_ON_0X_DESCRIPTION',
}
export enum SmartContractDocSections {
@@ -600,4 +618,10 @@ export interface InjectedWeb3 {
getNetwork(cd: (err: Error, networkId: string) => void): void;
};
}
+
+export interface TutorialInfo {
+ iconUrl: string;
+ description: string;
+ link: ALink;
+}
// tslint:disable:max-file-line-count
diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts
index 18a4d8100..0809fb438 100644
--- a/packages/website/ts/utils/constants.ts
+++ b/packages/website/ts/utils/constants.ts
@@ -74,6 +74,7 @@ export const constants = {
URL_TESTNET_FAUCET: 'https://faucet.0xproject.com',
URL_GITHUB_ORG: 'https://github.com/0xProject',
URL_GITHUB_WIKI: 'https://github.com/0xProject/wiki',
+ URL_FORUM: 'https://forum.0xproject.com',
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_COINBASE_WALLET_IOS_APP_STORE: 'https://itunes.apple.com/us/app/coinbase-wallet/id1278383455?mt=8',
@@ -84,6 +85,7 @@ export const constants = {
URL_PARITY_CHROME_STORE:
'https://chrome.google.com/webstore/detail/parity-ethereum-integrati/himekenlppkgeaoeddcliojfddemadig',
URL_REDDIT: 'https://reddit.com/r/0xproject',
+ URL_SANDBOX: 'https://codesandbox.io/s/1qmjyp7p5j',
URL_STANDARD_RELAYER_API_GITHUB: 'https://github.com/0xProject/standard-relayer-api/blob/master/README.md',
URL_TWITTER: 'https://twitter.com/0xproject',
URL_WETH_IO: 'https://weth.io/',
diff --git a/packages/website/ts/utils/translate.ts b/packages/website/ts/utils/translate.ts
index 1ee1a59c5..5595e6e0f 100644
--- a/packages/website/ts/utils/translate.ts
+++ b/packages/website/ts/utils/translate.ts
@@ -80,7 +80,12 @@ export class Translate {
case Deco.CapWords:
const words = text.split(' ');
- const capitalizedWords = _.map(words, w => this._capitalize(w));
+ const capitalizedWords = _.map(words, (w: string, i: number) => {
+ if (w.length === 1) {
+ return w;
+ }
+ return this._capitalize(w);
+ });
text = capitalizedWords.join(' ');
break;