diff options
author | Fabio Berger <me@fabioberger.com> | 2018-10-03 03:10:59 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2018-10-03 03:10:59 +0800 |
commit | c07412a992284b2f3045be1c620ea2e0a351139a (patch) | |
tree | 5d1baea6ae5c1bb70b4bf61a28bd131026098f8f /packages/website/ts | |
parent | 0c996803969e7ff3f62c023651f64468b3f76bd3 (diff) | |
download | dexon-sol-tools-c07412a992284b2f3045be1c620ea2e0a351139a.tar.gz dexon-sol-tools-c07412a992284b2f3045be1c620ea2e0a351139a.tar.zst dexon-sol-tools-c07412a992284b2f3045be1c620ea2e0a351139a.zip |
Use new Link UI component everywhere, and add complementary ALink type
Diffstat (limited to 'packages/website/ts')
20 files changed, 424 insertions, 347 deletions
diff --git a/packages/website/ts/components/documentation/docs_content_top_bar.tsx b/packages/website/ts/components/documentation/docs_content_top_bar.tsx index b5f51e1aa..7edb51587 100644 --- a/packages/website/ts/components/documentation/docs_content_top_bar.tsx +++ b/packages/website/ts/components/documentation/docs_content_top_bar.tsx @@ -1,19 +1,19 @@ -import { DocsMenu } from '@0xproject/react-docs'; import { colors, 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 { Link } from 'ts/components/ui/link'; -import { Deco, Key, WebsitePaths } from 'ts/types'; +import { ALink, Deco, Key, WebsitePaths } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; export interface DocsContentTopBarProps { location: Location; translate: Translate; - menu?: DocsMenu; + sectionNameToLinks?: ObjectMap<ALink[]>; } interface DocsContentTopBarState { @@ -146,12 +146,13 @@ export class DocsContentTopBar extends React.Component<DocsContentTopBarProps, D onRequestChange={this._onMenuButtonClick.bind(this)} > <div className="clearfix pl1"> - <NestedSidebarMenu + TODO + {/* <NestedSidebarMenu topLevelMenu={this.props.menu} shouldDisplaySectionHeaders={true} shouldReformatMenuItemNames={false} onMenuItemClick={this._onMenuButtonClick.bind(this)} - /> + /> */} </div> </Drawer> ); diff --git a/packages/website/ts/components/documentation/docs_logo.tsx b/packages/website/ts/components/documentation/docs_logo.tsx index 570a81bca..9bd742749 100644 --- a/packages/website/ts/components/documentation/docs_logo.tsx +++ b/packages/website/ts/components/documentation/docs_logo.tsx @@ -10,7 +10,7 @@ export interface DocsLogoProps { export const DocsLogo: React.StatelessComponent<DocsLogoProps> = props => { return ( <div style={props.containerStyle}> - <Link to={`${WebsitePaths.Docs}`} className="text-decoration-none"> + <Link to={WebsitePaths.Docs}> <img src="/images/docs_logo.svg" height={props.height} /> </Link> </div> diff --git a/packages/website/ts/components/documentation/tutorial_button.tsx b/packages/website/ts/components/documentation/tutorial_button.tsx index 094bc3d92..7ed9c6e4e 100644 --- a/packages/website/ts/components/documentation/tutorial_button.tsx +++ b/packages/website/ts/components/documentation/tutorial_button.tsx @@ -25,8 +25,7 @@ export class TutorialButton extends React.Component<TutorialButtonProps, Tutoria public render(): React.ReactNode { return ( <Link - to={this.props.tutorialInfo.location} - className="text-decoration-none" + to={this.props.tutorialInfo.link.to} onMouseEnter={this._onHover.bind(this)} onMouseOver={this._onHover.bind(this)} onMouseLeave={this._onHoverOff.bind(this)} @@ -46,7 +45,7 @@ export class TutorialButton extends React.Component<TutorialButtonProps, Tutoria </div> <div className="lg-pl2 md-pl2 sm-pl3 col col-10"> <Text Tag="div" fontSize="18" fontColor={colors.lightLinkBlue} fontWeight="bold"> - {this.props.translate.get(this.props.tutorialInfo.title as Key, Deco.Cap)} + {this.props.translate.get(this.props.tutorialInfo.link.title as Key, Deco.Cap)} </Text> <Text Tag="div" fontColor={colors.grey750} fontSize="16"> {this.props.translate.get(this.props.tutorialInfo.description as Key, Deco.Cap)} diff --git a/packages/website/ts/components/dropdowns/developers_drop_down.tsx b/packages/website/ts/components/dropdowns/developers_drop_down.tsx index 88522b665..675357f41 100644 --- a/packages/website/ts/components/dropdowns/developers_drop_down.tsx +++ b/packages/website/ts/components/dropdowns/developers_drop_down.tsx @@ -1,61 +1,68 @@ import { colors } from '@0xproject/react-shared'; -import { ObjectMap } from '@0xproject/types'; 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 { Link } from 'ts/components/ui/link'; import { Text } from 'ts/components/ui/text'; -import { Deco, Key, WebsitePaths } from 'ts/types'; +import { ALink, Deco, Key, LinkType, WebsitePaths } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; -interface LinkInfo { - link: string; - shouldOpenInNewTab?: boolean; -} - -const gettingStartedKeyToLinkInfo1: ObjectMap<LinkInfo> = { - [Key.BuildARelayer]: { - link: `${WebsitePaths.Wiki}#Build-A-Relayer`, +const gettingStartedKeyToLinkInfo1: ALink[] = [ + { + title: Key.BuildARelayer, + to: `${WebsitePaths.Wiki}#Build-A-Relayer`, }, - [Key.OrderBasics]: { - link: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`, + { + title: Key.OrderBasics, + to: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`, }, -}; -const gettingStartedKeyToLinkInfo2: ObjectMap<LinkInfo> = { - [Key.DevelopOnEthereum]: { - link: `${WebsitePaths.Wiki}#Ethereum-Development`, +]; +const gettingStartedKeyToLinkInfo2: ALink[] = [ + { + title: Key.DevelopOnEthereum, + to: `${WebsitePaths.Wiki}#Ethereum-Development`, }, - [Key.UseSharedLiquidity]: { - link: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`, + { + title: Key.UseSharedLiquidity, + to: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`, }, -}; -const popularDocsToLinkInfos: ObjectMap<LinkInfo> = { - [Key.ZeroExJs]: { - link: WebsitePaths.ZeroExJs, +]; +const popularDocsToLinkInfos: ALink[] = [ + { + title: Key.ZeroExJs, + to: WebsitePaths.ZeroExJs, }, - [Key.Connect]: { - link: WebsitePaths.Connect, + { + title: Key.Connect, + to: WebsitePaths.Connect, }, - [Key.SmartContract]: { - link: WebsitePaths.SmartContracts, + { + title: Key.SmartContract, + to: WebsitePaths.SmartContracts, }, -}; -const usefulLinksToLinkInfo: ObjectMap<LinkInfo> = { - [Key.Github]: { - link: constants.URL_GITHUB_ORG, +]; +const usefulLinksToLinkInfo: ALink[] = [ + { + title: Key.Github, + to: constants.URL_GITHUB_ORG, + type: LinkType.External, shouldOpenInNewTab: true, }, - [Key.Whitepaper]: { - link: WebsitePaths.Whitepaper, + { + title: Key.Whitepaper, + to: WebsitePaths.Whitepaper, + type: LinkType.External, shouldOpenInNewTab: true, }, - [Key.Sandbox]: { - link: constants.URL_SANDBOX, + { + title: Key.Sandbox, + to: constants.URL_SANDBOX, + type: LinkType.External, shouldOpenInNewTab: true, }, -}; +]; interface DevelopersDropDownProps { translate: Translate; @@ -123,7 +130,6 @@ export class DevelopersDropDown extends React.Component<DevelopersDropDownProps, > <Link to={WebsitePaths.Docs} - className="text-decoration-none" style={{ color: colors.lightBlueA700, fontWeight: 'bold', @@ -152,31 +158,25 @@ export class DevelopersDropDown extends React.Component<DevelopersDropDownProps, </div> ); } - private _renderLinkSection(keyToLinkInfo: ObjectMap<LinkInfo>): React.ReactNode { + private _renderLinkSection(links: ALink[]): React.ReactNode { const linkStyle: React.CSSProperties = { color: colors.lightBlueA700, fontFamily: 'Roboto, Roboto Mono', }; - const numLinks = _.size(keyToLinkInfo); + const numLinks = links.length; let i = 0; - const links = _.map(keyToLinkInfo, (linkInfo: LinkInfo, key: string) => { + const renderLinks = _.map(links, (link: ALink) => { i++; const isLast = i === numLinks; - const linkText = this.props.translate.get(key as Key, Deco.Cap); + const linkText = this.props.translate.get(link.title as Key, Deco.Cap); return ( - <div className={`pr1 pt1 ${!isLast && 'pb1'}`} key={`dev-dropdown-link-${key}`}> - <Link - to={linkInfo.link} - isExternal={!!linkInfo.shouldOpenInNewTab} - shouldOpenInNewTab={linkInfo.shouldOpenInNewTab} - className="text-decoration-none" - style={linkStyle} - > + <div className={`pr1 pt1 ${!isLast && 'pb1'}`} key={`dev-dropdown-link-${link.title}`}> + <Link to={link.to} type={link.type} shouldOpenInNewTab={link.shouldOpenInNewTab} style={linkStyle}> {linkText} </Link> </div> ); }); - return <div>{links}</div>; + return <div>{renderLinks}</div>; } } diff --git a/packages/website/ts/components/fill_order.tsx b/packages/website/ts/components/fill_order.tsx index 3c3155349..ec1d698f3 100644 --- a/packages/website/ts/components/fill_order.tsx +++ b/packages/website/ts/components/fill_order.tsx @@ -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'; @@ -17,6 +16,7 @@ import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; import { Alert } from 'ts/components/ui/alert'; import { EthereumAddress } from 'ts/components/ui/ethereum_address'; import { Identicon } from 'ts/components/ui/identicon'; +import { Link } from 'ts/components/ui/link'; import { VisualOrder } from 'ts/components/visual_order'; import { Dispatcher } from 'ts/redux/dispatcher'; import { portalOrderSchema } from 'ts/schemas/portal_order_schema'; diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx index 6dcb5a0e9..bec3c17f7 100644 --- a/packages/website/ts/components/footer.tsx +++ b/packages/website/ts/components/footer.tsx @@ -1,24 +1,16 @@ import { colors } 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 { Link } from 'ts/components/ui/link'; + import { Dispatcher } from 'ts/redux/dispatcher'; -import { Deco, Key, Language, WebsitePaths } from 'ts/types'; +import { ALink, Deco, Key, Language, LinkType, 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 = { @@ -51,76 +43,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, + type: LinkType.External, }, { 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, + type: LinkType.External, + to: constants.URL_ZEROEX_CHAT, }, { title: this.props.translate.get(Key.Blog, Deco.Cap), - isExternal: true, - path: constants.URL_BLOG, + type: LinkType.External, + to: constants.URL_BLOG, }, { title: 'Twitter', - isExternal: true, - path: constants.URL_TWITTER, + type: LinkType.External, + to: constants.URL_TWITTER, }, { title: 'Reddit', - isExternal: true, - path: constants.URL_REDDIT, + type: LinkType.External, + to: constants.URL_REDDIT, }, { title: this.props.translate.get(Key.Forum, Deco.Cap), - isExternal: true, - path: constants.URL_DISCOURSE_FORUM, + type: LinkType.External, + to: constants.URL_DISCOURSE_FORUM, }, ], [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', + type: LinkType.External, + to: 'mailto:team@0xproject.com', }, ], }; @@ -160,19 +150,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 +177,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 +185,21 @@ 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} type={link.type} style={linkStyle} 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..adf96f9ee 100644 --- a/packages/website/ts/components/inputs/token_amount_input.tsx +++ b/packages/website/ts/components/inputs/token_amount_input.tsx @@ -3,9 +3,9 @@ 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 { Link } from 'ts/components/ui/link'; import { Token, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; interface TokenAmountInputProps { @@ -112,7 +112,7 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok Insufficient allowance.{' '} <Link to={`${WebsitePaths.Portal}/account`} - style={{ cursor: 'pointer', color: colors.darkestGrey }} + style={{ cursor: 'pointer', color: colors.darkestGrey, textDecoration: 'underline' }} > 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..bdbcef343 100644 --- a/packages/website/ts/components/portal/back_button.tsx +++ b/packages/website/ts/components/portal/back_button.tsx @@ -1,6 +1,6 @@ import { Styles } from '@0xproject/react-shared'; import * as React from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'ts/components/ui/link'; import { Island } from 'ts/components/ui/island'; import { colors } from 'ts/style/colors'; @@ -27,7 +27,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..a9ccf9e11 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -3,7 +3,8 @@ 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 { Link } from 'ts/components/ui/link'; import { Blockchain } from 'ts/blockchain'; import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; @@ -317,7 +318,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 +390,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 c2d753e31..3da2307e0 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -10,15 +10,15 @@ import * as _ from 'lodash'; import Drawer from 'material-ui/Drawer'; 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 { Link } from 'ts/components/ui/link'; import { Dispatcher } from 'ts/redux/dispatcher'; -import { Deco, Key, ProviderType, WebsitePaths } from 'ts/types'; +import { Deco, Key, LinkType, ProviderType, WebsitePaths } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; @@ -151,7 +151,7 @@ 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" /> @@ -165,40 +165,36 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { /> <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} + linkType={LinkType.External} /> <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> @@ -260,20 +256,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)} @@ -284,25 +276,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} type={LinkType.External} 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} type={LinkType.External} 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> 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..89fd9e8a8 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,8 @@ import { colors } from '@0xproject/react-shared'; import * as _ from 'lodash'; import * as React from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'ts/components/ui/link'; +import { LinkType } from 'ts/types'; import { CallToAction } from 'ts/components/ui/button'; @@ -13,7 +14,7 @@ interface TopBarMenuItemProps { title: string; path?: string; isPrimary?: boolean; - isExternal: boolean; + linkType: LinkType; style?: React.CSSProperties; className?: string; isNightVersion?: boolean; @@ -38,20 +39,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} type={this.props.linkType} style={{ color: linkColor }}> + {itemContent} + </Link> </div> ); } diff --git a/packages/website/ts/components/ui/menu_item.tsx b/packages/website/ts/components/ui/custom_menu_item.tsx index 0cb4b387c..c51095709 100644 --- a/packages/website/ts/components/ui/menu_item.tsx +++ b/packages/website/ts/components/ui/custom_menu_item.tsx @@ -1,24 +1,24 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'ts/components/ui/link'; -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 +30,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} style={this.props.style}> <div onClick={this.props.onClick.bind(this)} className={`mx-auto ${this.props.className}`} diff --git a/packages/website/ts/components/ui/link.tsx b/packages/website/ts/components/ui/link.tsx index f7bca370b..ae62aad0c 100644 --- a/packages/website/ts/components/ui/link.tsx +++ b/packages/website/ts/components/ui/link.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import { Link as ReactRounterLink } from 'react-router-dom'; +import { LinkType } from 'ts/types'; export interface LinkProps { to: string; - isExternal?: boolean; + type?: LinkType; shouldOpenInNewTab?: boolean; style?: React.CSSProperties; className?: string; @@ -17,29 +18,39 @@ export interface LinkProps { export const Link: React.StatelessComponent<LinkProps> = ({ style, className, - isExternal, + type, to, shouldOpenInNewTab, children, }) => { - if (isExternal) { - return ( - <a target={shouldOpenInNewTab && '_blank'} className={className} style={style} href={to}> - {children} - </a> - ); - } else { - return ( - <ReactRounterLink to={to} className={className} style={style}> - {children} - </ReactRounterLink> - ); + const styleWithDefault = { + textDecoration: 'none', + ...style, + }; + + switch (type) { + case LinkType.External: + return ( + <a target={shouldOpenInNewTab && '_blank'} className={className} style={styleWithDefault} href={to}> + {children} + </a> + ); + case LinkType.ReactRoute: + return ( + <ReactRounterLink to={to} className={className} style={styleWithDefault}> + {children} + </ReactRounterLink> + ); + case LinkType.ReactScroll: + return <div>TODO</div>; + default: + throw new Error(`Unrecognized LinkType: ${type}`); } }; Link.defaultProps = { - isExternal: false, - shouldOpenInNewTab: false, + type: LinkType.ReactRoute, + shouldOpenInNewTab: true, style: {}, className: '', }; diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx index 8a9349c6d..767da3675 100644 --- a/packages/website/ts/components/ui/simple_menu.tsx +++ b/packages/website/ts/components/ui/simple_menu.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import * as CopyToClipboard from 'react-copy-to-clipboard'; -import { Link } from 'react-router-dom'; +import { Link } from 'ts/components/ui/link'; 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/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx index e097578bc..ba1b423b9 100644 --- a/packages/website/ts/pages/about/about.tsx +++ b/packages/website/ts/pages/about/about.tsx @@ -2,9 +2,9 @@ import { colors, 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 { Link } from 'ts/components/ui/link'; import { Profile } from 'ts/pages/about/profile'; import { Dispatcher } from 'ts/redux/dispatcher'; import { ProfileInfo, WebsitePaths } from 'ts/types'; @@ -370,7 +370,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} style={{ color: 'black', textDecoration: 'underline' }}> join our team </Link> . We value passion, diversity and unique perspectives. diff --git a/packages/website/ts/pages/documentation/home.tsx b/packages/website/ts/pages/documentation/home.tsx index 6bb30b368..42ed1db8c 100644 --- a/packages/website/ts/pages/documentation/home.tsx +++ b/packages/website/ts/pages/documentation/home.tsx @@ -1,11 +1,7 @@ -import { - colors, - constants as sharedConstants, - MarkdownLinkBlock, - NestedSidebarMenu, - utils as sharedUtils, -} from '@0xproject/react-shared'; +import { colors, constants as sharedConstants, MarkdownLinkBlock, utils as sharedUtils } from '@0xproject/react-shared'; +import { ObjectMap } from '@0xproject/types'; import * as _ from 'lodash'; +import MenuItem from 'material-ui/MenuItem'; import * as React from 'react'; import DocumentTitle = require('react-document-title'); import * as ReactMarkdown from 'react-markdown'; @@ -17,7 +13,7 @@ import { Container } from 'ts/components/ui/container'; import { Link } from 'ts/components/ui/link'; import { Text } from 'ts/components/ui/text'; import { Dispatcher } from 'ts/redux/dispatcher'; -import { Deco, Key, ScreenWidths, TutorialInfo, WebsitePaths } from 'ts/types'; +import { ALink, Deco, Key, LinkType, ScreenWidths, TutorialInfo, WebsitePaths } from 'ts/types'; import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; @@ -26,28 +22,36 @@ const TOP_BAR_HEIGHT = 80; const SCROLLER_WIDTH = 4; const TUTORIALS: TutorialInfo[] = [ { - title: Key.DevelopOnEthereum, iconUrl: '/images/developers/tutorials/develop_on_ethereum.svg', description: Key.DevelopOnEthereumDescription, - location: `${WebsitePaths.Wiki}#Ethereum-Development`, + link: { + title: Key.DevelopOnEthereum, + to: `${WebsitePaths.Wiki}#Ethereum-Development`, + }, }, { - title: Key.BuildARelayer, iconUrl: '/images/developers/tutorials/build_a_relayer.svg', description: Key.BuildARelayerDescription, - location: `${WebsitePaths.Wiki}#Build-A-Relayer`, + link: { + title: Key.BuildARelayer, + to: `${WebsitePaths.Wiki}#Build-A-Relayer`, + }, }, { - title: Key.OrderBasics, iconUrl: '/images/developers/tutorials/0x_order_basics.svg', description: Key.OrderBasicsDescription, - location: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`, + link: { + title: Key.OrderBasics, + to: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`, + }, }, { - title: Key.UseSharedLiquidity, iconUrl: '/images/developers/tutorials/use_shared_liquidity.svg', description: Key.UseSharedLiquidityDescription, - location: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`, + link: { + title: Key.UseSharedLiquidity, + to: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`, + }, }, ]; enum Categories { @@ -59,221 +63,276 @@ enum Categories { const CATEGORY_TO_PACKAGES: { [category: string]: Package[] } = { [Categories.ZeroExProtocol]: [ { - name: '0x.js', 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).', - to: WebsitePaths.ZeroExJs, + link: { + title: '0x.js', + to: WebsitePaths.ZeroExJs, + }, }, { - name: '0x starter project', 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', - to: 'https://github.com/0xProject/0x-starter-project', - isExternal: true, - shouldOpenInNewTab: true, + link: { + title: '0x starter project', + to: 'https://github.com/0xProject/0x-starter-project', + type: LinkType.External, + shouldOpenInNewTab: true, + }, }, { - name: '@0xproject/connect', description: 'An http & websocket client for interacting with relayers that have implemented the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api)', - to: WebsitePaths.Connect, + link: { + title: '@0xproject/connect', + to: WebsitePaths.Connect, + }, }, { - name: '@0xproject/contract-wrappers', 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.', - to: WebsitePaths.ContractWrappers, + link: { + title: '@0xproject/contract-wrappers', + to: WebsitePaths.ContractWrappers, + }, }, { - name: '@0xproject/json-schemas', description: 'A collection of 0x-related JSON-schemas (incl. SRA request/response schemas, 0x order message format schema, etc...)', - to: WebsitePaths.JSONSchemas, + link: { + title: '@0xproject/json-schemas', + to: WebsitePaths.JSONSchemas, + }, }, { - name: '@0xproject/order-utils', 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.', - to: WebsitePaths.OrderUtils, + link: { + title: '@0xproject/order-utils', + to: WebsitePaths.OrderUtils, + }, }, { - name: '@0xproject/order-watcher', 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.", - to: WebsitePaths.OrderWatcher, + link: { + title: '@0xproject/order-watcher', + to: WebsitePaths.OrderWatcher, + }, }, { - name: '@0xproject/sra-spec', description: 'Contains the Standard Relayer API OpenAPI Spec. The package distributes both a javascript object version and a json version.', - to: 'https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-spec', - isExternal: true, - shouldOpenInNewTab: true, + link: { + title: '@0xproject/sra-spec', + to: 'https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-spec', + type: LinkType.External, + shouldOpenInNewTab: true, + }, }, ], [Categories.Ethereum]: [ { - name: 'abi-gen', 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.", - to: 'https://github.com/0xProject/0x-monorepo/tree/development/packages/abi-gen', - isExternal: true, - shouldOpenInNewTab: true, + link: { + title: 'abi-gen', + to: 'https://github.com/0xProject/0x-monorepo/tree/development/packages/abi-gen', + type: LinkType.External, + shouldOpenInNewTab: true, + }, }, { - name: 'ethereum-types', description: 'A collection of Typescript types that are useful when working on an Ethereum-based project (e.g RawLog, Transaction, TxData, SolidityTypes, etc...).', - to: WebsitePaths.EthereumTypes, + link: { + title: 'ethereum-types', + to: WebsitePaths.EthereumTypes, + }, }, { - name: '@0xproject/sol-compiler', 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.', - to: WebsitePaths.SolCompiler, + link: { + title: '@0xproject/sol-compiler', + to: WebsitePaths.SolCompiler, + }, }, { - name: '@0xproject/sol-cov', 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.', - to: WebsitePaths.SolCov, + link: { + title: '@0xproject/sol-cov', + to: WebsitePaths.SolCov, + }, }, { - name: '@0xproject/subproviders', 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...)', - to: WebsitePaths.Subproviders, + link: { + title: '@0xproject/subproviders', + to: WebsitePaths.Subproviders, + }, }, { - name: '@0xproject/web3-wrapper', 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...', - to: WebsitePaths.Web3Wrapper, + link: { + title: '@0xproject/web3-wrapper', + to: WebsitePaths.Web3Wrapper, + }, }, ], [Categories.CommunityMaintained]: [ { - name: '0x Event Extractor', 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.', - to: 'https://github.com/0xTracker/0x-event-extractor', - shouldOpenInNewTab: true, - isExternal: true, + link: { + title: '0x Event Extractor', + to: 'https://github.com/0xTracker/0x-event-extractor', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: '0x Tracker Worker', 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.', - to: 'https://github.com/0xTracker/0x-tracker-worker', - shouldOpenInNewTab: true, - isExternal: true, + link: { + title: '0x Tracker Worker', + to: 'https://github.com/0xTracker/0x-tracker-worker', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'Aquaduct', description: "ERCdex's Javascript SDK for trading on their relayer, as well as other Aquaduct partner relayers", - to: 'https://www.npmjs.com/package/aqueduct', - shouldOpenInNewTab: true, - isExternal: true, + link: { + title: 'Aquaduct', + to: 'https://www.npmjs.com/package/aqueduct', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'Aquaduct Server SDK', 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.', - to: 'https://github.com/ERCdEX/aqueduct-server-sdk', - shouldOpenInNewTab: true, - isExternal: true, + link: { + title: 'Aquaduct Server SDK', + to: 'https://github.com/ERCdEX/aqueduct-server-sdk', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'DDEX Node.js SDK', description: 'A node.js SDK for trading on the DDEX relayer', - to: 'https://www.npmjs.com/package/ddex-api', - shouldOpenInNewTab: true, - isExternal: true, + link: { + to: 'https://www.npmjs.com/package/ddex-api', + title: 'DDEX Node.js SDK', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'ERCdex Widget', description: "The ERC dEX Trade Widget let's any website provide token liquidity to it's users", - to: 'https://github.com/ERCdEX/widget', - shouldOpenInNewTab: true, - isExternal: true, + link: { + to: 'https://github.com/ERCdEX/widget', + title: 'ERCdex Widget', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'ERCdex Java SDK', description: "ERCdex's Java SDK for trading on their relayer, as well as other Aquaduct partner relayers", - to: 'https://github.com/ERCdEX/java', - shouldOpenInNewTab: true, - isExternal: true, + link: { + to: 'https://github.com/ERCdEX/java', + title: 'ERCdex Java SDK', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'ERCdex Python SDK', description: "ERCdex's Python SDK for trading on their relayer, as well as other Aquaduct partner relayers", - to: 'https://github.com/ERCdEX/python', - shouldOpenInNewTab: true, - isExternal: true, + link: { + to: 'https://github.com/ERCdEX/python', + title: 'ERCdex Python SDK', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'Massive', description: 'A set of command-line tools for creating command-line scripts for interacting with the Ethereum blockchain in general, and 0x in particular', - to: 'https://github.com/NoteGio/massive', - shouldOpenInNewTab: true, - isExternal: true, + link: { + title: 'Massive', + to: 'https://github.com/NoteGio/massive', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'OpenRelay', description: 'An open-source API-only Relayer written in Go', - to: 'https://github.com/NoteGio/openrelay', - shouldOpenInNewTab: true, - isExternal: true, + link: { + to: 'https://github.com/NoteGio/openrelay', + title: 'OpenRelay', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'OpenRelay.js', description: 'A JavaScript Library for Interacting with OpenRelay.xyz and other 0x Standard Relayer API Implementations', - to: 'https://github.com/NoteGio/openrelay.js', - shouldOpenInNewTab: true, - isExternal: true, + link: { + title: 'OpenRelay.js', + to: 'https://github.com/NoteGio/openrelay.js', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'Radar SDK', description: 'The Radar Relay SDK is a software development kit that simplifies the interactions with Radar Relay’s APIs', - to: 'https://github.com/RadarRelay/sdk', - shouldOpenInNewTab: true, - isExternal: true, + link: { + title: 'Radar SDK', + to: 'https://github.com/RadarRelay/sdk', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'The Ocean Javascript SDK', description: 'The Ocean provides a simple REST API, WebSockets API, and JavaScript library to help you integrate decentralized trading into your existing trading strategy.', - to: 'https://github.com/TheOceanTrade/theoceanx-javascript', - shouldOpenInNewTab: true, - isExternal: true, + link: { + title: 'The Ocean Javascript SDK', + to: 'https://github.com/TheOceanTrade/theoceanx-javascript', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'Tokenlon Javascript SDK', description: "Tokenlon SDK provides APIs for developers to trade of imToken's relayer", - to: 'https://www.npmjs.com/package/tokenlon-sdk', - shouldOpenInNewTab: true, - isExternal: true, + link: { + to: 'https://www.npmjs.com/package/tokenlon-sdk', + title: 'Tokenlon Javascript SDK', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, { - name: 'AssetData decoder library in Java', description: 'A small library that implements the 0x order assetData encoding/decoding in Java', - to: 'https://github.com/wildnothing/asset-data-decoder', - shouldOpenInNewTab: true, - isExternal: true, + link: { + to: 'https://github.com/wildnothing/asset-data-decoder', + title: 'AssetData decoder library in Java', + shouldOpenInNewTab: true, + type: LinkType.External, + }, }, ], }; interface Package { - name: string; description: string; - to: string; - isExternal?: boolean; - shouldOpenInNewTab?: boolean; + link: ALink; } export interface HomeProps { @@ -319,15 +378,18 @@ export class Home extends React.Component<HomeProps, HomeState> { }; const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; const mainContentPadding = isSmallScreen ? 20 : 50; - const topLevelMenu = { - 'Starter guides': _.map(TUTORIALS, tutorialInfo => - this.props.translate.get(tutorialInfo.title as Key, Deco.Cap), - ), - [Categories.ZeroExProtocol]: _.map(CATEGORY_TO_PACKAGES[Categories.ZeroExProtocol], pkg => pkg.name), - [Categories.Ethereum]: _.map(CATEGORY_TO_PACKAGES[Categories.Ethereum], pkg => pkg.name), + 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.name, + pkg => pkg.link, ), }; return ( @@ -358,11 +420,7 @@ export class Home extends React.Component<HomeProps, HomeState> { onMouseEnter={this._onSidebarHover.bind(this, true)} onMouseLeave={this._onSidebarHover.bind(this, false)} > - <NestedSidebarMenu - topLevelMenu={topLevelMenu} - shouldDisplaySectionHeaders={true} - shouldReformatMenuItemNames={false} - /> + {this._renderMenu(sectionNameToLinks)} </div> </Container> <Container @@ -375,7 +433,7 @@ export class Home extends React.Component<HomeProps, HomeState> { <DocsContentTopBar location={this.props.location} translate={this.props.translate} - menu={topLevelMenu} + sectionNameToLinks={sectionNameToLinks} /> </Container> <div @@ -404,9 +462,9 @@ export class Home extends React.Component<HomeProps, HomeState> { {_.map(TUTORIALS, tutorialInfo => ( <ScrollElement name={sharedUtils.getIdFromName( - this.props.translate.get(tutorialInfo.title as Key, Deco.Cap), + this.props.translate.get(tutorialInfo.link.title as Key, Deco.Cap), )} - key={`tutorial-${tutorialInfo.title}`} + key={`tutorial-${tutorialInfo.link.title}`} > <TutorialButton translate={this.props.translate} @@ -438,6 +496,42 @@ export class Home extends React.Component<HomeProps, HomeState> { </Container> ); } + private _renderMenu(sectionNameToLinks: ObjectMap<ALink[]>): React.ReactNode { + const navigation = _.map(sectionNameToLinks, (links: ALink[], sectionName: string) => { + // tslint:disable-next-line:no-unused-variable + return ( + <div key={`section-${sectionName}`} className="py1" style={{ color: colors.linkSectionGrey }}> + <div style={{ fontWeight: 'bold', fontSize: 15, letterSpacing: 0.5 }} className="py1"> + {sectionName.toUpperCase()} + </div> + {this._renderMenuItems(links)} + </div> + ); + }); + return <div className="pl1">{navigation}</div>; + } + private _renderMenuItems(links: ALink[]): React.ReactNode { + const menuItems = _.map(links, link => { + return ( + <div key={`menuItem-${link.title}`}> + <Link to={link.to} shouldOpenInNewTab={link.shouldOpenInNewTab} type={link.type}> + <MenuItem + style={{ minHeight: 0 }} + innerDivStyle={{ + color: colors.grey800, + fontSize: 14, + lineHeight: 2, + padding: 0, + }} + > + {link.title} + </MenuItem> + </Link> + </div> + ); + }); + return menuItems; + } private _renderPackageCategory(category: string, pkgs: Package[]): React.ReactNode { return ( <div key={`category-${category}`}> @@ -447,22 +541,21 @@ export class Home extends React.Component<HomeProps, HomeState> { ); } private _renderPackage(pkg: Package): React.ReactNode { - const id = sharedUtils.getIdFromName(pkg.name); + const id = sharedUtils.getIdFromName(pkg.link.title); return ( - <ScrollElement name={id} key={`package-${pkg.name}`}> + <ScrollElement name={id} key={`package-${pkg.link.title}`}> <div className="pb2"> <Container width="100%" height="1px" backgroundColor={colors.grey300} marginTop="11px" /> <div className="clearfix mt2 pt1"> <div className="md-col lg-col md-col-4 lg-col-4"> <Link - to={pkg.to} - className="text-decoration-none" + to={pkg.link.to} style={{ color: colors.lightLinkBlue }} - isExternal={!!pkg.isExternal} - shouldOpenInNewTab={!!pkg.shouldOpenInNewTab} + type={pkg.link.type} + shouldOpenInNewTab={!!pkg.link.shouldOpenInNewTab} > <Text Tag="div" fontColor={colors.lightLinkBlue} fontWeight="bold"> - {pkg.name} + {pkg.link.title} </Text> </Link> </div> @@ -476,11 +569,11 @@ export class Home extends React.Component<HomeProps, HomeState> { </div> <div className="md-col lg-col md-col-2 lg-col-2 sm-pb2 relative"> <Link - to={pkg.to} - className="text-decoration-none absolute" + to={pkg.link.to} + className="absolute" style={{ right: 0, color: colors.lightLinkBlue }} - isExternal={!!pkg.isExternal} - shouldOpenInNewTab={!!pkg.shouldOpenInNewTab} + type={pkg.link.type} + shouldOpenInNewTab={!!pkg.link.shouldOpenInNewTab} > <div className="flex"> <div>{this.props.translate.get(Key.More, Deco.Cap)}</div> diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx index 388e83d51..b4462407f 100644 --- a/packages/website/ts/pages/landing/landing.tsx +++ b/packages/website/ts/pages/landing/landing.tsx @@ -2,13 +2,13 @@ import { colors } 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'; import { CallToAction } from 'ts/components/ui/button'; import { Container } from 'ts/components/ui/container'; import { Image } from 'ts/components/ui/image'; +import { Link } from 'ts/components/ui/link'; import { Text } from 'ts/components/ui/text'; import { TypedText } from 'ts/components/ui/typed_text'; import { Dispatcher } from 'ts/redux/dispatcher'; @@ -213,14 +213,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> @@ -320,8 +320,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 }} + style={{ color: colors.landingLinkGrey, textDecoration: 'underline' }} > {this.props.translate.get(Key.FullListLink)} </Link> @@ -603,7 +602,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/types.ts b/packages/website/ts/types.ts index f93d998b6..7c79b271f 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -618,10 +618,22 @@ export interface InjectedWeb3 { }; } -export interface TutorialInfo { +export interface ALink { title: string; + to: string; + shouldOpenInNewTab?: boolean; + type?: LinkType; +} + +export interface TutorialInfo { iconUrl: string; description: string; - location: string; + link: ALink; +} + +export enum LinkType { + External = 'EXTERNAL', + ReactScroll = 'REACT_SCROLL', + ReactRoute = 'REACT_ROUTE', } // tslint:disable:max-file-line-count |