diff options
Diffstat (limited to 'packages/website/ts/@next/components')
13 files changed, 179 insertions, 73 deletions
diff --git a/packages/website/ts/@next/components/banner.tsx b/packages/website/ts/@next/components/banner.tsx index e779c5889..2620b92ef 100644 --- a/packages/website/ts/@next/components/banner.tsx +++ b/packages/website/ts/@next/components/banner.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; import styled from 'styled-components'; +import { colors } from 'ts/style/colors'; + import {Button} from 'ts/@next/components/button'; import {ThemeInterface} from 'ts/@next/components/siteWrap'; import {Paragraph} from 'ts/@next/components/text'; @@ -46,7 +48,7 @@ export const Banner: React.StatelessComponent<Props> = (props: Props) => { <CustomHeading>{heading}</CustomHeading> {subline && - <Paragraph isMuted={0.5} isNoMargin={true}> + <Paragraph color={colors.white} isMuted={0.5} isNoMargin={true}> {subline} </Paragraph> } @@ -55,6 +57,7 @@ export const Banner: React.StatelessComponent<Props> = (props: Props) => { <ButtonWrap> {mainCta && <Button + color={colors.white} isTransparent={false} href={mainCta.href} > @@ -64,6 +67,7 @@ export const Banner: React.StatelessComponent<Props> = (props: Props) => { {secondaryCta && <Button + color={colors.white} href={secondaryCta.href} onClick={secondaryCta.onClick} isTransparent={true} @@ -78,6 +82,7 @@ export const Banner: React.StatelessComponent<Props> = (props: Props) => { }; const CustomSection = styled(Section)` + color: ${colors.white}; margin-top: 30px; @media (max-width: 900px) { @@ -137,4 +142,11 @@ const Border = styled.div<BorderProps>` top: ${props => !props.isBottom && 0 }; bottom: ${props => props.isBottom && 0 }; transform: translate(-112px); + + @media (max-width: 768px) { + width: calc(100% + 82px); + height: 40px; + transform: translate(-41px); + background-size: auto 80px; + } `; diff --git a/packages/website/ts/@next/components/button.tsx b/packages/website/ts/@next/components/button.tsx index 05afa3534..ab804b758 100644 --- a/packages/website/ts/@next/components/button.tsx +++ b/packages/website/ts/@next/components/button.tsx @@ -62,6 +62,7 @@ const ButtonBase = styled.button<ButtonInterface>` border-color: ${props => (props.isTransparent && !props.isWithArrow) && 'rgba(255, 255, 255, .4)'}; color: ${props => props.isAccentColor ? props.theme.linkColor : (props.color || props.theme.textColor)}; padding: ${props => (!props.isNoPadding && !props.isWithArrow) && '18px 30px'}; + white-space: ${props => props.isWithArrow && 'nowrap'}; text-align: center; font-size: ${props => props.isWithArrow ? '20px' : '18px'}; text-decoration: none; diff --git a/packages/website/ts/@next/components/definition.tsx b/packages/website/ts/@next/components/definition.tsx index d556bc647..77f837294 100644 --- a/packages/website/ts/@next/components/definition.tsx +++ b/packages/website/ts/@next/components/definition.tsx @@ -116,10 +116,21 @@ const TextWrap = styled.div<Props>` `; const LinkWrap = styled.div` - display: inline-flex; margin-top: 60px; - a + a { - margin-left: 60px; + @media (min-width: 768px) { + display: inline-flex; + + a + a { + margin-left: 60px; + } + } + + @media (max-width: 768px) { + max-width: 250px; + + a + a { + margin-top: 15px; + } } `; diff --git a/packages/website/ts/@next/components/footer.tsx b/packages/website/ts/@next/components/footer.tsx index 5e5106ff3..155f46979 100644 --- a/packages/website/ts/@next/components/footer.tsx +++ b/packages/website/ts/@next/components/footer.tsx @@ -160,10 +160,10 @@ const Link = styled(ReactRouterLink)` display: block; font-size: 16px; line-height: 20px; - transition: color 0.25s ease-in-out; + transition: opacity 0.25s; text-decoration: none; &:hover { - color: rgba(255, 255, 255, 1); + opacity: 0.8; } `; diff --git a/packages/website/ts/@next/components/hamburger.tsx b/packages/website/ts/@next/components/hamburger.tsx index 3ca276705..b5c01a2b0 100644 --- a/packages/website/ts/@next/components/hamburger.tsx +++ b/packages/website/ts/@next/components/hamburger.tsx @@ -53,7 +53,6 @@ const StyledHamburger = styled.button<Props>` ${props => props.isOpen && ` opacity: 1; transform: rotate(45deg) translate(0, 1px); - background-color: #fff; &:nth-child(2) { opacity: 0; diff --git a/packages/website/ts/@next/components/header.tsx b/packages/website/ts/@next/components/header.tsx index fde549642..544a7daf1 100644 --- a/packages/website/ts/@next/components/header.tsx +++ b/packages/website/ts/@next/components/header.tsx @@ -4,6 +4,8 @@ import MediaQuery from 'react-responsive'; import { NavLink as ReactRouterLink } from 'react-router-dom'; import styled, { withTheme } from 'styled-components'; +import Headroom from 'react-headroom'; + import { Button } from 'ts/@next/components/button'; import { DropdownDevelopers } from 'ts/@next/components/dropdowns/dropdown_developers'; import { DropdownProducts } from 'ts/@next/components/dropdowns/dropdown_products'; @@ -66,39 +68,47 @@ const navItems: NavItemProps[] = [ ]; class HeaderBase extends React.Component<HeaderProps> { + public onUnpin = () => { + if (this.props.isNavToggled) { + this.props.toggleMobileNav(); + } + } + public render(): React.ReactNode { const { isNavToggled, toggleMobileNav, theme } = this.props; return ( - <StyledHeader> - <HeaderWrap> - <ReactRouterLink to={WebsitePaths.Home}> - <Logo /> - </ReactRouterLink> - - <NavLinks> - {_.map(navItems, (link, index) => ( - <NavItem - key={`navlink-${index}`} - link={link} - /> - ))} - </NavLinks> - - <MediaQuery minWidth={990}> - <TradeButton - bgColor={theme.headerButtonBg} - color="#ffffff" - href="https://0x.org/portal" - > - Trade on 0x - </TradeButton> - </MediaQuery> - - <Hamburger isOpen={isNavToggled} onClick={toggleMobileNav} /> - <MobileNav isToggled={isNavToggled} toggleMobileNav={toggleMobileNav} /> - </HeaderWrap> - </StyledHeader> + <Headroom onUnpin={this.onUnpin} downTolerance={4} upTolerance={10}> + <StyledHeader isNavToggled={isNavToggled}> + <HeaderWrap> + <ReactRouterLink to={WebsitePaths.Home}> + <Logo /> + </ReactRouterLink> + + <NavLinks> + {_.map(navItems, (link, index) => ( + <NavItem + key={`navlink-${index}`} + link={link} + /> + ))} + </NavLinks> + + <MediaQuery minWidth={990}> + <TradeButton + bgColor={theme.headerButtonBg} + color="#ffffff" + href="/portal" + > + Trade on 0x + </TradeButton> + </MediaQuery> + + <Hamburger isOpen={isNavToggled} onClick={toggleMobileNav} /> + <MobileNav isToggled={isNavToggled} toggleMobileNav={toggleMobileNav} /> + </HeaderWrap> + </StyledHeader> + </Headroom> ); } } @@ -126,6 +136,7 @@ const NavItem = (props: { link: NavItemProps; key: string }) => { const StyledHeader = styled.header<HeaderProps>` padding: 30px; + background-color: ${props => props.theme.bgColor}; `; const LinkWrap = styled.li` diff --git a/packages/website/ts/@next/components/mobileNav.tsx b/packages/website/ts/@next/components/mobileNav.tsx index 52a46ed69..8b5ffd7e8 100644 --- a/packages/website/ts/@next/components/mobileNav.tsx +++ b/packages/website/ts/@next/components/mobileNav.tsx @@ -24,12 +24,12 @@ export class MobileNav extends React.PureComponent<Props> { <ul> <li> - <Link to="#"> - 0x instant + <Link to={WebsitePaths.Instant}> + 0x Instant </Link> </li> <li> - <Link to="#"> + <Link to={WebsitePaths.LaunchKit}> 0x Launch Kit </Link> </li> @@ -49,9 +49,9 @@ export class MobileNav extends React.PureComponent<Props> { </Link> </li> <li> - <Link to="https://blog.0x.org/latest"> + <a href="https://blog.0x.org/latest" target="_blank"> Blog - </Link> + </a> </li> </Grid> </Section> @@ -70,8 +70,9 @@ const Wrap = styled.nav<{ isToggled: boolean }>` height: 357px; background-color: ${props => props.theme.mobileNavBgUpper}; color: ${props => props.theme.mobileNavColor}; - transition: transform 0.5s; + transition: ${props => props.isToggled ? 'visibility 0s, transform 0.5s' : 'visibility 0s 0.5s, transform 0.5s'}; transform: translate3d(0, ${props => props.isToggled ? 0 : '-100%'}, 0); + visibility: ${props => !props.isToggled && 'hidden'}; position: fixed; display: flex; flex-direction: column; @@ -109,6 +110,8 @@ const Section = styled.div<{ isDark?: boolean }>` `; const Grid = styled(WrapGrid)<WrapProps>` + justify-content: flex-start; + li { width: 50%; flex-shrink: 0; diff --git a/packages/website/ts/@next/components/modals/input.tsx b/packages/website/ts/@next/components/modals/input.tsx index 61663d906..d4d9206a2 100644 --- a/packages/website/ts/@next/components/modals/input.tsx +++ b/packages/website/ts/@next/components/modals/input.tsx @@ -11,27 +11,37 @@ interface InputProps { width?: InputWidth; label: string; type?: string; + errors?: ErrorProps; + isErrors?: boolean; } interface LabelProps { string: boolean; } +interface ErrorProps { + [key: string]: string; +} + export const Input = React.forwardRef((props: InputProps, ref?: React.Ref<HTMLInputElement>) => { - const { name, label, type } = props; + const { name, label, type, errors } = props; const id = `input-${name}`; const componentType = type === 'textarea' ? 'textarea' : 'input'; + const isErrors = errors.hasOwnProperty(name) && errors[name] !== null; + const errorMessage = isErrors ? errors[name] : null; return ( <InputWrapper {...props}> <Label htmlFor={id}>{label}</Label> - <StyledInput as={componentType} ref={ref} id={id} placeholder={label} {...props} /> + <StyledInput as={componentType} ref={ref} id={id} placeholder={label} isErrors={isErrors} {...props} /> + {isErrors && <Error>{errorMessage}</Error>} </InputWrapper> ); }); Input.defaultProps = { width: InputWidth.Full, + errors: {}, }; const StyledInput = styled.input` @@ -45,6 +55,9 @@ const StyledInput = styled.input` width: 100%; min-height: ${props => props.type === 'textarea' && `120px`}; + background-color: ${(props: InputProps) => props.isErrors && `#FDEDED`}; + border-color: ${(props: InputProps) => props.isErrors && `#FD0000`}; + &::placeholder { color: #C3C3C3; } @@ -68,3 +81,15 @@ const Label = styled.label` margin-bottom: 10px; display: inline-block; `; + +const Error = styled.span` + color: #FD0000; + font-size: .833333333rem; + line-height: 1em; + display: inline-block; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + transform: translateY(24px); +`; diff --git a/packages/website/ts/@next/components/modals/modal_contact.tsx b/packages/website/ts/@next/components/modals/modal_contact.tsx index f107b9174..b595c236d 100644 --- a/packages/website/ts/@next/components/modals/modal_contact.tsx +++ b/packages/website/ts/@next/components/modals/modal_contact.tsx @@ -24,6 +24,20 @@ interface FormProps { isSubmitting?: boolean; } +interface ErrorResponseProps { + param: string; + location: string; + msg: string; +} + +interface ErrorResponse { + errors: ErrorResponseProps[]; +} + +interface ErrorProps { + [key: string]: string; +} + export class ModalContact extends React.Component<Props> { public state = { isSubmitting: false, @@ -40,7 +54,7 @@ export class ModalContact extends React.Component<Props> { } public render(): React.ReactNode { const {isOpen, onDismiss} = this.props; - const {isSuccessful} = this.state; + const {isSuccessful, errors} = this.state; return ( <> @@ -61,6 +75,7 @@ export class ModalContact extends React.Component<Props> { width={InputWidth.Half} ref={this.nameRef} required={true} + errors={errors} /> <Input name="email" @@ -68,6 +83,7 @@ export class ModalContact extends React.Component<Props> { type="email" ref={this.emailRef} required={true} + errors={errors} width={InputWidth.Half} /> </InputRow> @@ -78,6 +94,7 @@ export class ModalContact extends React.Component<Props> { type="text" ref={this.companyProjectRef} required={true} + errors={errors} /> </InputRow> <InputRow> @@ -86,6 +103,7 @@ export class ModalContact extends React.Component<Props> { label="Do you have any documentation or a website?" type="text" ref={this.linkRef} + errors={errors} /> </InputRow> <InputRow> @@ -94,6 +112,7 @@ export class ModalContact extends React.Component<Props> { label="Anything else?" type="textarea" ref={this.commentsRef} + errors={errors} /> </InputRow> <ButtonRow> @@ -129,24 +148,42 @@ export class ModalContact extends React.Component<Props> { const link = this.linkRef.current.value; const comments = this.commentsRef.current.value; - this.setState({ ...this.state, isSubmitting: true }); + this.setState({ ...this.state, errors: [], isSubmitting: true }); try { - await fetch('https://website-api.0x.org/leads', { + const response = await fetch('https://website-api.0x.org/leads', { method: 'post', mode: 'cors', credentials: 'same-origin', headers: { 'content-type': 'application/json; charset=utf-8', }, - body: JSON.stringify({ name, email, projectOrCompany, link, comments }), + body: JSON.stringify(_.omitBy({ name, email, projectOrCompany, link, comments }, _.isEmpty)), }); + if (!response.ok) { + const errorResponse: ErrorResponse = await response.json(); + const errors = this._parseErrors(errorResponse.errors); + this.setState({ ...this.state, isSubmitting: false, errors }); + + throw new Error('Request failed'); + } + this.setState({ ...this.state, isSuccessful: true }); } catch (e) { - this.setState({ ...this.state, errors: [] }); + // Empty block } } + private _parseErrors(errors: ErrorResponseProps[]): ErrorProps { + return _ + .reduce(errors, (hash: ErrorProps, error: ErrorResponseProps) => { + const { param, msg } = error; + const key = param; + hash[key] = msg; + + return hash; + }, {}); + } } // Handle errors: {"errors":[{"location":"body","param":"name","msg":"Invalid value"},{"location":"body","param":"email","msg":"Invalid value"}]} diff --git a/packages/website/ts/@next/components/newsletter_form.tsx b/packages/website/ts/@next/components/newsletter_form.tsx index 859cd1d9c..6dc4bf678 100644 --- a/packages/website/ts/@next/components/newsletter_form.tsx +++ b/packages/website/ts/@next/components/newsletter_form.tsx @@ -1,13 +1,20 @@ import * as React from 'react'; -import styled from 'styled-components'; +import styled, { withTheme } from 'styled-components'; import { colors } from 'ts/style/colors'; +import {ThemeValuesInterface} from 'ts/@next/components/siteWrap'; + +interface FormProps { + theme: ThemeValuesInterface; +} + interface InputProps { isSubmitted: boolean; name: string; type: string; label: string; + textColor: string; } interface ArrowProps { @@ -26,18 +33,19 @@ const Input = React.forwardRef((props: InputProps, ref: React.Ref<HTMLInputEleme ); }); -export class NewsletterForm extends React.Component { +class Form extends React.Component<FormProps> { public emailInput = React.createRef<HTMLInputElement>(); public state = { isSubmitted: false, }; public render(): React.ReactNode { const {isSubmitted} = this.state; + const {theme} = this.props; return ( <StyledForm onSubmit={this._onSubmitAsync.bind(this)}> <InputWrapper> - <Input isSubmitted={isSubmitted} name="email" type="email" label="Email Address" ref={this.emailInput} required={true} /> + <Input isSubmitted={isSubmitted} name="email" type="email" label="Email Address" ref={this.emailInput} required={true} textColor={theme.textColor} /> <SubmitButton> <Arrow isSubmitted={isSubmitted} width="22" height="17" fill="none" xmlns="http://www.w3.org/2000/svg"> @@ -74,6 +82,8 @@ export class NewsletterForm extends React.Component { } } +export const NewsletterForm = withTheme(Form); + const StyledForm = styled.form` appearance: none; border: 0; @@ -82,12 +92,12 @@ const StyledForm = styled.form` margin-top: 27px; `; -const StyledInput = styled.input` +const StyledInput = styled.input<InputProps>` appearance: none; background-color: transparent; border: 0; border-bottom: 1px solid #393939; - color: #fff; + color: ${props => props.textColor || '#fff'}; font-size: 1.294117647rem; padding: 15px 0; outline: none; diff --git a/packages/website/ts/@next/components/sections/landing/about.tsx b/packages/website/ts/@next/components/sections/landing/about.tsx index 700d5e7d2..ee1cfb434 100644 --- a/packages/website/ts/@next/components/sections/landing/about.tsx +++ b/packages/website/ts/@next/components/sections/landing/about.tsx @@ -26,7 +26,7 @@ export const SectionLandingAbout = () => ( isMuted={1} padding={['large', 0, 'default', 0]} > - Anyone in the world can use 0x to service a wide variety of markets ranging from gaming items to financial instruments to assets that could have near existed before. + Anyone in the world can use 0x to service a wide variety of markets ranging from gaming items to financial instruments to assets that could have never existed before. </Paragraph> <Button diff --git a/packages/website/ts/@next/components/sections/landing/clients.tsx b/packages/website/ts/@next/components/sections/landing/clients.tsx index 8e2347d02..e411feeb0 100644 --- a/packages/website/ts/@next/components/sections/landing/clients.tsx +++ b/packages/website/ts/@next/components/sections/landing/clients.tsx @@ -18,39 +18,40 @@ interface StyledProjectInterface { const projects: ProjectLogo[] = [ { name: 'Radar Relay', - imageUrl: 'images/@next/clients/client-radar.png', + imageUrl: 'images/@next/clients/radar-relay.svg', persistOnMobile: true, }, { name: 'Paradex', - imageUrl: 'images/@next/clients/client-paradex.png', + imageUrl: 'images/@next/clients/paradex.svg', persistOnMobile: true, }, { - name: 'The Ocean X', - imageUrl: 'images/@next/clients/client-oceanx.png', + name: 'Star Bit Ex', + imageUrl: 'images/@next/clients/starbitex.svg', }, { - name: 'Decent EX', - imageUrl: 'images/@next/clients/client-decent.png', + name: 'LedgerDex', + imageUrl: 'images/@next/clients/ledgerdex.svg', }, { - name: 'dEX', - imageUrl: 'images/@next/clients/client-dex.png', + name: 'OpenRelay', + imageUrl: 'images/@next/clients/openrelay.svg', + persistOnMobile: true, }, { - name: 'OpenRelay', - imageUrl: 'images/@next/clients/client-openrelay.png', + name: 'Bamboo Relay', + imageUrl: 'images/@next/clients/bamboo.svg', persistOnMobile: true, }, { - name: 'Amadeus', - imageUrl: 'images/@next/clients/client-amadeus.png', + name: 'Shark Relay', + imageUrl: 'images/@next/clients/sharkrelay.svg', persistOnMobile: true, }, { - name: 'DDEX', - imageUrl: 'images/@next/clients/client-ddex.png', + name: 'dEX', + imageUrl: 'images/@next/clients/ercdex.svg', persistOnMobile: true, }, ]; diff --git a/packages/website/ts/@next/components/siteWrap.tsx b/packages/website/ts/@next/components/siteWrap.tsx index c1513c647..ad7691885 100644 --- a/packages/website/ts/@next/components/siteWrap.tsx +++ b/packages/website/ts/@next/components/siteWrap.tsx @@ -109,9 +109,6 @@ export class SiteWrap extends React.Component<Props, State> { public toggleMobileNav = () => { this.setState({ isMobileNavOpen: !this.state.isMobileNavOpen, - }, () => { - const overflow = this.state.isMobileNavOpen ? 'hidden' : 'auto'; - document.documentElement.style.overflowY = overflow; }); } @@ -148,6 +145,5 @@ export class SiteWrap extends React.Component<Props, State> { const Main = styled.main<MainProps>` transition: transform 0.5s, opacity 0.5s; - transform: translate3d(0, ${props => props.isNavToggled ? '357px' : 0}, 0); opacity: ${props => props.isNavToggled && '0.5'}; `; |