diff options
author | Fred Carlsen <fred@sjelfull.no> | 2018-12-10 18:19:20 +0800 |
---|---|---|
committer | Fred Carlsen <fred@sjelfull.no> | 2018-12-10 18:19:20 +0800 |
commit | c99558606347682c6c5c9bb20d37aa4fbe8ab6be (patch) | |
tree | 3b6927cac22415c7139dc9a2463664aa1dada1a3 /packages/website | |
parent | 8dd738629ad3bc6e07de7499272e3528a26091a3 (diff) | |
download | dexon-sol-tools-c99558606347682c6c5c9bb20d37aa4fbe8ab6be.tar dexon-sol-tools-c99558606347682c6c5c9bb20d37aa4fbe8ab6be.tar.gz dexon-sol-tools-c99558606347682c6c5c9bb20d37aa4fbe8ab6be.tar.bz2 dexon-sol-tools-c99558606347682c6c5c9bb20d37aa4fbe8ab6be.tar.lz dexon-sol-tools-c99558606347682c6c5c9bb20d37aa4fbe8ab6be.tar.xz dexon-sol-tools-c99558606347682c6c5c9bb20d37aa4fbe8ab6be.tar.zst dexon-sol-tools-c99558606347682c6c5c9bb20d37aa4fbe8ab6be.zip |
WIP mobile header + developer dropdown
Diffstat (limited to 'packages/website')
3 files changed, 417 insertions, 32 deletions
diff --git a/packages/website/ts/@next/components/dropdowns/developers_drop_down.tsx b/packages/website/ts/@next/components/dropdowns/developers_drop_down.tsx new file mode 100644 index 000000000..bf75c3b92 --- /dev/null +++ b/packages/website/ts/@next/components/dropdowns/developers_drop_down.tsx @@ -0,0 +1,159 @@ +import { ALink, Link } from '@0x/react-shared'; +import * as _ from 'lodash'; +import * as React from 'react'; + +import { colors } from 'ts/style/colors'; +import { Container } from 'ts/components/ui/container'; +import { DropDown } from 'ts/components/ui/drop_down'; +import { Heading, Paragraph } from 'ts/@next/components/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.UseNetworkedLiquidity, + 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.Wiki, + to: WebsitePaths.Wiki, + }, + { + title: Key.Github, + to: constants.URL_GITHUB_ORG, + shouldOpenInNewTab: true, + }, + { + title: Key.Whitepaper, + to: WebsitePaths.Whitepaper, + shouldOpenInNewTab: true, + }, +]; + +interface DevelopersDropDownProps { + location: Location; +} + +interface DevelopersDropDownState {} + +export class DevelopersDropDown extends React.Component<DevelopersDropDownProps, DevelopersDropDownState> { + public render(): React.ReactNode { + const activeNode = ( + <Paragraph isNoMargin={true}> + Developers + </Paragraph> + ); + return ( + <DropDown + activeNode={activeNode} + popoverContent={this._renderDropdownMenu()} + anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }} + targetOrigin={{ horizontal: 'left', vertical: 'top' }} + popoverStyle={{ borderRadius: 0, width: 420, height: 377, marginTop: 0 }} + /> + ); + } + private _renderDropdownMenu(): React.ReactNode { + const sectionPadding = '26px'; + const dropdownMenu = ( + <Container> + <Container className="flex" padding={sectionPadding}> + <Container paddingRight="45px"> + {this._renderLinkSection(gettingStartedKeyToLinkInfo1, 'Getting started')} + </Container> + <Container>{this._renderLinkSection(gettingStartedKeyToLinkInfo2)}</Container> + </Container> + <Container width="100%" height="1px" backgroundColor={colors.grey300} /> + <Container className="flex" padding={sectionPadding}> + <Container paddingRight="62px"> + <Container>{this._renderLinkSection(popularDocsToLinkInfos, 'Popular docs')}</Container> + </Container> + <Container> + <Container>{this._renderLinkSection(usefulLinksToLinkInfo, 'Useful links')}</Container> + </Container> + </Container> + <Link to={WebsitePaths.Docs} fontColor={colors.brandLight}> + <Container + padding="0.9rem" + backgroundColor={colors.white} + borderBottomLeftRadius={4} + borderBottomRightRadius={4} + > + <Paragraph color={colors.brandLight} isCentered={true} isNoMargin={true}> + View all documentation + </Paragraph> + </Container> + </Link> + </Container> + ); + return dropdownMenu; + } + private _renderLinkSection(links: ALink[], title: string = ''): 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); + const linkText = link.title; + return ( + <Container className={`pr1 pt1 ${!isLast && 'pb1'}`} key={`dev-dropdown-link-${link.title}`}> + <Link to={to} shouldOpenInNewTab={!!link.shouldOpenInNewTab}> + <Paragraph size="small" color={colors.brandDark} isNoMargin={true}> + {linkText} + </Paragraph> + </Link> + </Container> + ); + }); + return ( + <Container> + <Container height="33px"> + {!_.isEmpty(title) && ( + <Heading asElement="h3" size="small"> + {title} + </Heading> + )} + </Container> + {renderLinks} + </Container> + ); + } +} diff --git a/packages/website/ts/@next/components/hamburger.tsx b/packages/website/ts/@next/components/hamburger.tsx new file mode 100644 index 000000000..0eac4a53f --- /dev/null +++ b/packages/website/ts/@next/components/hamburger.tsx @@ -0,0 +1,68 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +interface Props { + isOpen: boolean; + onClick?: () => void; +} + +export const Hamburger: React.FunctionComponent<Props> = (props: Props) => { + return ( + <StyledHamburger isOpen={props.isOpen} onClick={props.onClick}> + <span /> + <span /> + <span /> + </StyledHamburger> + ); +}; + +const StyledHamburger = styled.button<Props>` + background: none; + border: 0; + width: 22px; + height: 16px; + position: relative; + z-index: 2; + padding: 0; + outline: none; + user-select: none; + + @media (min-width: 768px) { + display: none; + } + + span { + display: block; + background-color: #fff; + width: 100%; + height: 2px; + margin-bottom: 5px; + transform-origin: 4px 0px; + transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0), + background-color 0.5s cubic-bezier(0.77,0.2,0.05,1.0), + opacity 0.55s ease; + + &:first-child { + //transform-origin: 0% 0%; + } + + &:last-child { + //transform-origin: 0% 100%; + } + + ${props => props.isOpen && ` + opacity: 1; + transform: rotate(45deg) translate(0, 1px); + background-color: #fff; + + &:nth-child(2) { + opacity: 0; + transform: rotate(0deg) scale(0.2, 0.2); + } + + &:last-child { + transform: rotate(-45deg) translate(1px, -4px); + } + `} + } +`; diff --git a/packages/website/ts/@next/components/header.tsx b/packages/website/ts/@next/components/header.tsx index a6bbe4d65..e4add9ecf 100644 --- a/packages/website/ts/@next/components/header.tsx +++ b/packages/website/ts/@next/components/header.tsx @@ -3,48 +3,206 @@ import * as React from 'react'; import { Link as ReactRouterLink } from 'react-router-dom'; import styled from 'styled-components'; +import { colors } from 'ts/style/colors'; + import { Button, ButtonWrap, Link } from 'ts/@next/components/button'; +import { DevelopersDropDown } from 'ts/@next/components/dropdowns/developers_drop_down'; +import { Hamburger } from 'ts/@next/components/hamburger'; import { Section, Wrap } from 'ts/@next/components/layout'; import { Logo } from 'ts/@next/components/logo'; +import { Paragraph } from 'ts/@next/components/text'; interface HeaderProps { + isOpen: boolean; + location?: Location; +} + +interface HeaderState { + isOpen: boolean; +} + +interface HeaderState { + isOpen: boolean; +} + +interface NavItem { + url?: string; + id?: string; + text?: string; } -const links = [ - { url: '/next/why', text: 'Why 0x' }, - { url: '/next/0x-instant', text: 'Products' }, - { url: '#', text: 'Developers' }, - { url: '/next/about/mission', text: 'About' }, - { url: '#', text: 'Blog' }, +const mobileProductLinks = [ + { url: '/next/0x-instant', text: '0x Instant' }, + { url: '/next/launch-kit', text: '0x Launch Kit' }, +]; + +const navItems: NavItem[] = [ + { id: 'why', url: '/next/why', text: 'Why 0x' }, + { id: 'products', url: '/next/0x-instant', text: 'Products' }, + { id: 'developers', url: '#', text: 'Developers' }, + { id: 'about', url: '/next/about/mission', text: 'About' }, + { id: 'blog', url: '#', text: 'Blog' }, ]; -export const Header: React.StatelessComponent<HeaderProps> = ({}) => ( - <StyledHeader> - <HeaderWrap> - <ReactRouterLink to="/next"> - <Logo/> - </ReactRouterLink> - - <ButtonWrap> - {_.map(links, (link, index) => ( - <Link - key={`hb-${index}`} - href={link.url} - isTransparent={true} - isNoBorder={true} - > - {link.text} - </Link> - ))} - </ButtonWrap> - - <Button href="#">Trade on 0x</Button> - </HeaderWrap> - </StyledHeader> -); - -const StyledHeader = Section.withComponent('header'); +export class Header extends React.Component<HeaderProps, HeaderState> { + constructor(props: HeaderProps) { + super(props); + this.state = { + isOpen: false, + }; + } + public render(): React.ReactNode { + return ( + <StyledHeader isOpen={this.state.isOpen}> + <HeaderWrap> + <ReactRouterLink to="/next"> + <Logo/> + </ReactRouterLink> + <Hamburger isOpen={this.state.isOpen} onClick={this._onMenuButtonClick.bind(this)}/> + <Nav> + <MobileProductLinksWrap> + <Paragraph isNoMargin={true} isMuted={0.5} size="small">Products</Paragraph> + {_.map(mobileProductLinks, (link, index) => ( + <StyledLink + key={`productlink-${index}`} + href={link.url} + isTransparent={true} + isNoBorder={true} + > + {link.text} + </StyledLink> + ))} + </MobileProductLinksWrap> + <StyledButtonWrap> + {_.map(navItems, (link, index) => this._getNavItem(link, index))} + </StyledButtonWrap> + </Nav> + <TradeButton href="#">Trade on 0x</TradeButton> + </HeaderWrap> + </StyledHeader> + ); + } + private _onMenuButtonClick(): void { + this.setState({ + isOpen: !this.state.isOpen, + }); + } + private _getNavItem(link: NavItem, index: number): React.ReactNode { + if (link.id === 'developers') { + return ( + <DevelopersDropDown + location={window.location} + /> + ); + } + + return ( + <StyledLink + key={`header-nav-item-${index}`} + href={link.url} + isTransparent={true} + isNoBorder={true} + > + {link.text} + </StyledLink> + ) + } +} + +const StyledHeader = styled(Section.withComponent('header'))<HeaderProps>` + @media (max-width: 768px) { + overflow: hidden; + min-height: ${props => props.isOpen ? '385px' : '70px'}; + position: relative; + transition: min-height 0.25s ease-in-out; + :root & { + padding: 20px 20px 0 !important; + } + } +`; + const HeaderWrap = styled(Wrap)` justify-content: space-between; align-items: center; + + @media (max-width: 768px) { + padding-top: 0; + display: flex; + padding-bottom: 0; + } +`; + +const StyledButtonWrap = styled(ButtonWrap)` + display: flex; + @media (max-width: 768px) { + background-color: #022924; + display: flex; + flex-wrap: wrap; + padding: 20px 20px; + + a { + text-align: left; + padding-left: 0; + } + } + + button + button, + a + a, + a + button, + button + a { + margin-left: 0; + + @media (min-width: 768px) { + margin-left: 10px; + } + } +`; + +const MobileProductLinksWrap = styled(StyledButtonWrap)` + display: none; + + @media (max-width: 768px) { + display: block; + background-color: transparent; + flex-direction: column; + + a { + display: block; + width: 100%; + } + } +`; + +const StyledLink = styled(Link)` + width: 50%; + text-align: left; + @media (max-width: 768px) { + } + + @media (min-width: 768px) { + width: auto; + text-align: center; + } +`; + +const Nav = styled.div` + @media (max-width: 768px) { + background-color: ${colors.brandDark}; + position: absolute; + top: 0; + left: 0; + right: 0; + padding-top: 65px; + } + + @media (min-width: 768px) { + width: auto; + text-align: center; + } +`; + +const TradeButton = styled(Button)` + @media (max-width: 768px) { + display: none; + } `; |