From c99558606347682c6c5c9bb20d37aa4fbe8ab6be Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Mon, 10 Dec 2018 11:19:20 +0100 Subject: WIP mobile header + developer dropdown --- .../components/dropdowns/developers_drop_down.tsx | 159 +++++++++++++++ packages/website/ts/@next/components/hamburger.tsx | 68 +++++++ packages/website/ts/@next/components/header.tsx | 222 ++++++++++++++++++--- 3 files changed, 417 insertions(+), 32 deletions(-) create mode 100644 packages/website/ts/@next/components/dropdowns/developers_drop_down.tsx create mode 100644 packages/website/ts/@next/components/hamburger.tsx 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 { + public render(): React.ReactNode { + const activeNode = ( + + Developers + + ); + return ( + + ); + } + private _renderDropdownMenu(): React.ReactNode { + const sectionPadding = '26px'; + const dropdownMenu = ( + + + + {this._renderLinkSection(gettingStartedKeyToLinkInfo1, 'Getting started')} + + {this._renderLinkSection(gettingStartedKeyToLinkInfo2)} + + + + + {this._renderLinkSection(popularDocsToLinkInfos, 'Popular docs')} + + + {this._renderLinkSection(usefulLinksToLinkInfo, 'Useful links')} + + + + + + View all documentation + + + + + ); + 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 ( + + + + {linkText} + + + + ); + }); + return ( + + + {!_.isEmpty(title) && ( + + {title} + + )} + + {renderLinks} + + ); + } +} 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) => { + return ( + + + + + + ); +}; + +const StyledHamburger = styled.button` + 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 = ({}) => ( - - - - - - - - {_.map(links, (link, index) => ( - - {link.text} - - ))} - - - - - -); - -const StyledHeader = Section.withComponent('header'); +export class Header extends React.Component { + constructor(props: HeaderProps) { + super(props); + this.state = { + isOpen: false, + }; + } + public render(): React.ReactNode { + return ( + + + + + + + + Trade on 0x + + + ); + } + private _onMenuButtonClick(): void { + this.setState({ + isOpen: !this.state.isOpen, + }); + } + private _getNavItem(link: NavItem, index: number): React.ReactNode { + if (link.id === 'developers') { + return ( + + ); + } + + return ( + + {link.text} + + ) + } +} + +const StyledHeader = styled(Section.withComponent('header'))` + @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; + } `; -- cgit