diff options
Diffstat (limited to 'packages/website')
-rw-r--r-- | packages/website/ts/@next/components/button.tsx | 47 | ||||
-rw-r--r-- | packages/website/ts/@next/components/definition.tsx | 37 | ||||
-rw-r--r-- | packages/website/ts/@next/components/link.tsx | 1 | ||||
-rw-r--r-- | packages/website/ts/@next/components/newsletter_form.tsx | 65 | ||||
-rw-r--r-- | packages/website/ts/@next/components/sections/landing/about.tsx | 47 | ||||
-rw-r--r-- | packages/website/ts/@next/pages/about/jobs.tsx | 248 | ||||
-rw-r--r-- | packages/website/ts/@next/pages/instant.tsx | 129 | ||||
-rw-r--r-- | packages/website/ts/@next/pages/instant/config_generator.tsx | 32 | ||||
-rw-r--r-- | packages/website/ts/@next/pages/instant/configurator.tsx | 13 | ||||
-rw-r--r-- | packages/website/ts/@next/pages/instant/select.tsx | 30 | ||||
-rw-r--r-- | packages/website/ts/components/onboarding/onboarding_flow.tsx | 4 | ||||
-rw-r--r-- | packages/website/ts/components/ui/animation.tsx | 42 | ||||
-rw-r--r-- | packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx | 32 | ||||
-rw-r--r-- | packages/website/ts/index.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/utils/configs.ts | 4 |
15 files changed, 424 insertions, 309 deletions
diff --git a/packages/website/ts/@next/components/button.tsx b/packages/website/ts/@next/components/button.tsx index ab804b758..b686b27a2 100644 --- a/packages/website/ts/@next/components/button.tsx +++ b/packages/website/ts/@next/components/button.tsx @@ -19,52 +19,55 @@ interface ButtonInterface { isInline?: boolean; href?: string; type?: string; + target?: string; to?: string; onClick?: () => any; theme?: ThemeInterface; + useAnchorTag?: boolean; } export const Button = (props: ButtonInterface) => { - const { - children, - href, - isWithArrow, - to, - } = props; + const { children, href, isWithArrow, to, useAnchorTag, target } = props; let linkElem; - if (href) { linkElem = 'a'; } - if (to) { linkElem = ReactRouterLink; } + if (href || useAnchorTag) { + linkElem = 'a'; + } + if (to) { + linkElem = ReactRouterLink; + } const Component = linkElem ? ButtonBase.withComponent(linkElem) : ButtonBase; + const targetProp = href && target ? { target } : {}; return ( - <Component {...props}> + <Component {...props} {...targetProp}> {children} - { isWithArrow && + {isWithArrow && ( <svg width="16" height="15" fill="none" xmlns="http://www.w3.org/2000/svg"> - <path - d="M4.484.246l.024 1.411 8.146.053L.817 13.547l.996.996L13.65 2.706l.052 8.146 1.412.024L15.045.315 4.484.246z" - /> + <path d="M4.484.246l.024 1.411 8.146.053L.817 13.547l.996.996L13.65 2.706l.052 8.146 1.412.024L15.045.315 4.484.246z" /> </svg> - } + )} </Component> ); }; -const ButtonBase = styled.button<ButtonInterface>` +const ButtonBase = + styled.button < + ButtonInterface > + ` appearance: none; border: 1px solid transparent; display: inline-block; background-color: ${props => props.bgColor || colors.brandLight}; background-color: ${props => (props.isTransparent || props.isWithArrow) && 'transparent'}; - 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'}; + 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'}; + font-size: ${props => (props.isWithArrow ? '20px' : '18px')}; text-decoration: none; cursor: pointer; outline: none; @@ -77,12 +80,12 @@ const ButtonBase = styled.button<ButtonInterface>` } path { - fill: ${props => props.isAccentColor ? props.theme.linkColor : (props.color || props.theme.textColor)}; + fill: ${props => (props.isAccentColor ? props.theme.linkColor : props.color || props.theme.textColor)}; } &:hover { - background-color: ${props => (!props.isTransparent && !props.isWithArrow) && '#04BEA8'}; - border-color: ${props => (props.isTransparent && !props.isNoBorder && !props.isWithArrow) && '#00AE99'}; + background-color: ${props => !props.isTransparent && !props.isWithArrow && '#04BEA8'}; + border-color: ${props => props.isTransparent && !props.isNoBorder && !props.isWithArrow && '#00AE99'}; svg { transform: translate3d(2px, -2px, 0); diff --git a/packages/website/ts/@next/components/definition.tsx b/packages/website/ts/@next/components/definition.tsx index 77f837294..d203151b9 100644 --- a/packages/website/ts/@next/components/definition.tsx +++ b/packages/website/ts/@next/components/definition.tsx @@ -7,7 +7,9 @@ import { Heading, Paragraph } from 'ts/@next/components/text'; interface Action { label: string; - url: string; + url?: string; + onClick?: () => void; + useAnchorTag?: boolean; } interface Props { @@ -25,11 +27,7 @@ interface Props { export const Definition = (props: Props) => ( <Wrap {...props}> - <Icon - name={props.icon} - size={props.iconSize || 'medium'} - margin={[0, 0, 'default', 0]} - /> + <Icon name={props.icon} size={props.iconSize || 'medium'} margin={[0, 0, 'default', 0]} /> <TextWrap {...props}> <Heading @@ -42,34 +40,36 @@ export const Definition = (props: Props) => ( </Heading> {typeof props.description === 'string' ? ( - <Paragraph isMuted={true}> - {props.description} - </Paragraph> + <Paragraph isMuted={true}>{props.description}</Paragraph> ) : ( - <> - {props.description} - </> + <>{props.description}</> )} - {props.actions && + {props.actions && ( <LinkWrap> {props.actions.map((item, index) => ( <Button key={`dlink-${index}`} href={item.url} + onClick={item.onClick} isWithArrow={true} isAccentColor={true} + useAnchorTag={item.useAnchorTag} + target="_blank" > {item.label} </Button> ))} </LinkWrap> - } + )} </TextWrap> </Wrap> ); -const Wrap = styled.div<Props>` +const Wrap = + styled.div < + Props > + ` max-width: ${props => props.isInline && '354px'}; & + & { @@ -78,7 +78,7 @@ const Wrap = styled.div<Props>` } @media (min-width: 768px) { - width: ${props => props.isInline ? 'calc(33.3333% - 30px)' : '100%'}; + width: ${props => (props.isInline ? 'calc(33.3333% - 30px)' : '100%')}; display: ${props => props.isInlineIcon && 'flex'}; justify-content: ${props => props.isInlineIcon && 'space-between'}; align-items: ${props => props.isInlineIcon && 'center'}; @@ -94,7 +94,10 @@ const Wrap = styled.div<Props>` } `; -const TextWrap = styled.div<Props>` +const TextWrap = + styled.div < + Props > + ` width: 100%; max-width: 560px; diff --git a/packages/website/ts/@next/components/link.tsx b/packages/website/ts/@next/components/link.tsx index 6ca1e44c1..a7711451b 100644 --- a/packages/website/ts/@next/components/link.tsx +++ b/packages/website/ts/@next/components/link.tsx @@ -13,6 +13,7 @@ interface LinkInterface { theme?: { textColor: string; }; + shouldOpenInNewTab?: boolean; } export const Link = (props: LinkInterface) => { diff --git a/packages/website/ts/@next/components/newsletter_form.tsx b/packages/website/ts/@next/components/newsletter_form.tsx index 6dc4bf678..eef496982 100644 --- a/packages/website/ts/@next/components/newsletter_form.tsx +++ b/packages/website/ts/@next/components/newsletter_form.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import styled, { withTheme } from 'styled-components'; +import { ThemeValuesInterface } from 'ts/@next/components/siteWrap'; import { colors } from 'ts/style/colors'; - -import {ThemeValuesInterface} from 'ts/@next/components/siteWrap'; +import { errorReporter } from 'ts/utils/error_reporter'; interface FormProps { theme: ThemeValuesInterface; @@ -27,7 +27,9 @@ const Input = React.forwardRef((props: InputProps, ref: React.Ref<HTMLInputEleme return ( <InnerInputWrapper {...props}> - <label className="visuallyHidden" htmlFor={id}>{label}</label> + <label className="visuallyHidden" htmlFor={id}> + {label} + </label> <StyledInput ref={ref} id={id} placeholder={label} type={type || 'text'} {...props} /> </InnerInputWrapper> ); @@ -39,17 +41,34 @@ class Form extends React.Component<FormProps> { isSubmitted: false, }; public render(): React.ReactNode { - const {isSubmitted} = this.state; - const {theme} = this.props; + 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} textColor={theme.textColor} /> + <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"> - <path d="M13.066 0l-1.068 1.147 6.232 6.557H0v1.592h18.23l-6.232 6.557L13.066 17l8.08-8.5-8.08-8.5z" fill="#CBCBCB"/> + <Arrow + isSubmitted={isSubmitted} + width="22" + height="17" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M13.066 0l-1.068 1.147 6.232 6.557H0v1.592h18.23l-6.232 6.557L13.066 17l8.08-8.5-8.08-8.5z" + fill="#CBCBCB" + /> </Arrow> </SubmitButton> <SuccessText isSubmitted={isSubmitted}>🎉 Thank you for signing up!</SuccessText> @@ -67,6 +86,10 @@ class Form extends React.Component<FormProps> { this.setState({ isSubmitted: true }); + if (email === 'triggererror@0xproject.org') { + throw new Error('Manually triggered error'); + } + try { const response = await fetch('https://website-api.0x.org/newsletter_subscriber/substack', { method: 'post', @@ -77,7 +100,7 @@ class Form extends React.Component<FormProps> { body: JSON.stringify({ email, referrer }), }); } catch (e) { - // dosomething + errorReporter.report(e); } } } @@ -92,7 +115,10 @@ const StyledForm = styled.form` margin-top: 27px; `; -const StyledInput = styled.input<InputProps>` +const StyledInput = + styled.input < + InputProps > + ` appearance: none; background-color: transparent; border: 0; @@ -112,7 +138,10 @@ const InputWrapper = styled.div` position: relative; `; -const InnerInputWrapper = styled.div<ArrowProps>` +const InnerInputWrapper = + styled.div < + ArrowProps > + ` opacity: ${props => props.isSubmitted && 0}; visibility: ${props => props.isSubmitted && 'hidden'}; transition: opacity 0.25s ease-in-out, visibility 0.25s ease-in-out; @@ -143,7 +172,10 @@ const Text = styled.p` margin-top: 15px; `; -const SuccessText = styled.p<ArrowProps>` +const SuccessText = + styled.p < + ArrowProps > + ` color: #B1B1B1; font-size: 1rem; font-weight: 300; @@ -154,13 +186,16 @@ const SuccessText = styled.p<ArrowProps>` top: 0; text-align: left; right: 50px; - opacity: ${props => props.isSubmitted ? 1 : 0}; - visibility: ${props => props.isSubmitted ? 'visible' : 'hidden'}; + opacity: ${props => (props.isSubmitted ? 1 : 0)}; + visibility: ${props => (props.isSubmitted ? 'visible' : 'hidden')}; transition: opacity 0.25s ease-in-out, visibility 0.25s ease-in-out; transition-delay: 0.55s; `; -const Arrow = styled.svg<ArrowProps>` +const Arrow = + styled.svg < + ArrowProps > + ` transform: ${props => props.isSubmitted && `translateX(44px)`}; transition: transform 0.25s ease-in-out; `; diff --git a/packages/website/ts/@next/components/sections/landing/about.tsx b/packages/website/ts/@next/components/sections/landing/about.tsx index ee1cfb434..9c2c29446 100644 --- a/packages/website/ts/@next/components/sections/landing/about.tsx +++ b/packages/website/ts/@next/components/sections/landing/about.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import styled from 'styled-components'; -import {Button} from 'ts/@next/components/button'; -import {Icon, InlineIconWrap} from 'ts/@next/components/icon'; -import {Column, FlexWrap, Section} from 'ts/@next/components/newLayout'; -import {Paragraph} from 'ts/@next/components/text'; +import { Button } from 'ts/@next/components/button'; +import { Icon, InlineIconWrap } from 'ts/@next/components/icon'; +import { Column, FlexWrap, Section } from 'ts/@next/components/newLayout'; +import { Paragraph } from 'ts/@next/components/text'; interface FigureProps { value: string; @@ -20,20 +20,12 @@ export const SectionLandingAbout = () => ( <Icon name="descriptionBolt" size="small" /> </InlineIconWrap> - <Paragraph - size="large" - isCentered={true} - 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 never existed before. + <Paragraph size="large" isCentered={true} 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 never existed before. </Paragraph> - <Button - href="#" - isWithArrow={true} - isAccentColor={true} - > + <Button href="#" isWithArrow={true} isAccentColor={true}> Discover how developers use 0x </Button> @@ -46,32 +38,19 @@ export const SectionLandingAbout = () => ( /> <FlexWrap as="dl"> - <Figure - value="873,435" - description="Number of Transactions" - /> + <Figure value="166,976" description="Total Transactions" /> - <Figure - value="$203M" - description="Total Volume" - /> + <Figure value="$216M" description="Total Volume" /> - <Figure - value="227,372" - description="Number of Relayers" - /> + <Figure value="30+" description="Total Projects" /> </FlexWrap> </Section> ); const Figure = (props: FigureProps) => ( <Column padding="0 30px"> - <FigureValue> - {props.value} - </FigureValue> - <FigureDescription> - {props.description} - </FigureDescription> + <FigureValue>{props.value}</FigureValue> + <FigureDescription>{props.description}</FigureDescription> </Column> ); diff --git a/packages/website/ts/@next/pages/about/jobs.tsx b/packages/website/ts/@next/pages/about/jobs.tsx index e4a9bb1ad..1e9d54609 100644 --- a/packages/website/ts/@next/pages/about/jobs.tsx +++ b/packages/website/ts/@next/pages/about/jobs.tsx @@ -3,9 +3,12 @@ import * as React from 'react'; import styled from 'styled-components'; import { AboutPageLayout } from 'ts/@next/components/aboutPageLayout'; -import { Link } from 'ts/@next/components/link'; import { Column, FlexWrap, Section } from 'ts/@next/components/newLayout'; import { Heading, Paragraph } from 'ts/@next/components/text'; +import { WebsiteBackendJobInfo } from 'ts/types'; +import { backendClient } from 'ts/utils/backend_client'; + +const OPEN_POSITIONS_HASH = 'positions'; interface PositionProps { title: string; @@ -17,118 +20,165 @@ interface PositionItemProps { position: PositionProps; } -const positions: PositionProps[] = [ - { - title: 'Product Designer', - location: 'San Francisco, Remote', - href: '#', - }, - { - title: 'Product Designer', - location: 'San Francisco, Remote', - href: '#', - }, - { - title: 'Product Designer', - location: 'San Francisco, Remote', - href: '#', - }, - { - title: 'Open Positition', - location: "We're always interested in talking to talented people. Send us an application if you think you're the right fit.", - href: '#', - }, -]; - -export const NextAboutJobs = () => ( - <AboutPageLayout - title="Join Us in Our Mission" - description={ - <> - <Paragraph size="medium"> - To create a tokenized world where all value can flow freely. - </Paragraph> - <Paragraph size="medium"> - We are growing an ecosystem of businesses and projects by solving difficult challenges to make our technology intuitive, flexible, and accessible to all. Join us in building infrastructure upon which the exchange of all assets will take place. - </Paragraph> - </> - } - linkLabel="Our mission and values" - linkUrl="/about/mission" - > - <Section bgColor="#F3F6F4" isFlex={true} maxWidth="1170px" wrapWidth="100%"> - <Column maxWidth="442px"> - <Heading size="medium" marginBottom="30px"> - Powered by a Diverse, Global Community - </Heading> - - <Paragraph> - We're a highly technical team with varied backgrounds in engineering, science, business, finance, and research. While the Core Team is headquartered in San Francisco, there are 30+ teams building on 0x and hundreds of thousands of participants behind our efforts worldwide. We're passionate about open-source software and decentralized technology's potential to act as an equalizing force in the world. - </Paragraph> - </Column> - - <Column maxWidth="600px"> - <ImageWrap> - <img src="/images/@next/jobs/map@2x.png" height="365" alt="Map of community"/> - </ImageWrap> - </Column> - </Section> - - <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> - <Column> - <Heading size="medium">Benefits</Heading> - </Column> - - <Column maxWidth="826px"> - <BenefitsList> - <li>Comprehensive Insurance</li> - <li>Unlimited Vacation</li> - <li>Meals and snacks provided daily</li> - <li>Flexible hours and liberal work-from-home-policy</li> - <li>Supportive of remote working</li> - <li>Transportation, phone, and wellness expense</li> - <li>Relocation assistance</li> - <li>Optional team excursions</li> - <li>Competitive salary</li> - <li>Cryptocurrency based compensation</li> - </BenefitsList> - </Column> - </Section> - - <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> - <Column> - <Heading size="medium">Current<br/>Openings</Heading> - </Column> - - <Column maxWidth="826px"> - - {_.map(positions, (position, index) => ( - <Position key={`position-${index}`} position={position} /> - ))} - </Column> - </Section> - </AboutPageLayout> -); - -export const Position: React.FunctionComponent<PositionItemProps> = (props: PositionItemProps) => { +const Position: React.FunctionComponent<PositionItemProps> = (props: PositionItemProps) => { const { position } = props; return ( <PositionWrap> <StyledColumn width="30%"> - <Heading asElement="h3" size="small" fontWeight="400" marginBottom="0"><a href={position.href}>{position.title}</a></Heading> + <Heading asElement="h3" size="small" fontWeight="400" marginBottom="0"> + <a href={position.href} target="_blank"> + {position.title} + </a> + </Heading> </StyledColumn> <StyledColumn width="50%" padding="0 40px 0 0"> - <Paragraph isMuted={true} marginBottom="0">{position.location}</Paragraph> + <Paragraph isMuted={true} marginBottom="0"> + {position.location} + </Paragraph> </StyledColumn> <StyledColumn width="20%"> - <Paragraph marginBottom="0" textAlign="right"><Link href={position.href}>Apply</Link></Paragraph> + <Paragraph marginBottom="0" textAlign="right"> + <a href={position.href} target="_blank"> + Apply + </a> + </Paragraph> </StyledColumn> </PositionWrap> ); }; +export interface NextAboutJobsProps {} +interface NextAboutJobsState { + jobInfos: WebsiteBackendJobInfo[]; +} + +export class NextAboutJobs extends React.Component<NextAboutJobsProps, NextAboutJobsState> { + private _isUnmounted: boolean; + private static _convertJobInfoToPositionProps(jobInfo: WebsiteBackendJobInfo): PositionProps { + return { + title: jobInfo.title, + location: jobInfo.office, + href: jobInfo.url, + }; + } + constructor(props: NextAboutJobsProps) { + super(props); + this.state = { + jobInfos: [], + }; + } + + public componentWillMount(): void { + // tslint:disable-next-line:no-floating-promises + this._fetchJobInfosAsync(); + } + public componentWillUnmount(): void { + this._isUnmounted = true; + } + public render(): React.ReactNode { + const positions = this.state.jobInfos.map(jobInfo => NextAboutJobs._convertJobInfoToPositionProps(jobInfo)); + return ( + <AboutPageLayout + title="Join Us in Our Mission" + description={ + <> + <Paragraph size="medium"> + To create a tokenized world where all value can flow freely. + </Paragraph> + <Paragraph size="medium"> + We are growing an ecosystem of businesses and projects by solving difficult challenges to + make our technology intuitive, flexible, and accessible to all. Join us in building + infrastructure upon which the exchange of all assets will take place. + </Paragraph> + </> + } + linkLabel="Our mission and values" + linkUrl="/about/mission" + > + <Section bgColor="#F3F6F4" isFlex={true} maxWidth="1170px" wrapWidth="100%"> + <Column maxWidth="442px"> + <Heading size="medium" marginBottom="30px"> + Powered by a Diverse, Global Community + </Heading> + + <Paragraph> + We're a highly technical team with varied backgrounds in engineering, science, business, + finance, and research. While the Core Team is headquartered in San Francisco, there are 30+ + teams building on 0x and hundreds of thousands of participants behind our efforts worldwide. + We're passionate about open-source software and decentralized technology's potential to act + as an equalizing force in the world. + </Paragraph> + </Column> + + <Column maxWidth="600px"> + <ImageWrap> + <img src="/images/@next/jobs/map@2x.png" height="365" alt="Map of community" /> + </ImageWrap> + </Column> + </Section> + + <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> + <Column> + <Heading size="medium">Benefits</Heading> + </Column> + + <Column maxWidth="826px"> + <BenefitsList> + <li>Comprehensive Insurance</li> + <li>Unlimited Vacation</li> + <li>Meals and snacks provided daily</li> + <li>Flexible hours and liberal work-from-home-policy</li> + <li>Supportive of remote working</li> + <li>Transportation, phone, and wellness expense</li> + <li>Relocation assistance</li> + <li>Optional team excursions</li> + <li>Competitive salary</li> + <li>Cryptocurrency based compensation</li> + </BenefitsList> + </Column> + </Section> + + <Section id={OPEN_POSITIONS_HASH} isFlex={true} maxWidth="1170px" wrapWidth="100%"> + <Column> + <Heading size="medium"> + Current<br />Openings + </Heading> + </Column> + + <Column maxWidth="826px"> + {_.map(positions, (position, index) => ( + <Position key={`position-${index}`} position={position} /> + ))} + </Column> + </Section> + </AboutPageLayout> + ); + } + private async _fetchJobInfosAsync(): Promise<void> { + try { + if (!this._isUnmounted) { + this.setState({ + jobInfos: [], + }); + } + const jobInfos = await backendClient.getJobInfosAsync(); + if (!this._isUnmounted) { + this.setState({ + jobInfos, + }); + } + } catch (error) { + if (!this._isUnmounted) { + this.setState({ + jobInfos: [], + }); + } + } + } +} + const BenefitsList = styled.ul` color: #000; font-weight: 300; @@ -173,6 +223,6 @@ const PositionWrap = styled(FlexWrap)` bottom: 0; left: 0; height: 1px; - background-color: #E3E3E3; + background-color: #e3e3e3; } `; diff --git a/packages/website/ts/@next/pages/instant.tsx b/packages/website/ts/@next/pages/instant.tsx index d86fa2203..a2df3ffc6 100644 --- a/packages/website/ts/@next/pages/instant.tsx +++ b/packages/website/ts/@next/pages/instant.tsx @@ -1,59 +1,73 @@ +import { utils as sharedUtils } from '@0x/react-shared'; import * as _ from 'lodash'; import * as React from 'react'; import styled, { keyframes } from 'styled-components'; -import {colors} from 'ts/style/colors'; +import { colors } from 'ts/style/colors'; -import {Banner} from 'ts/@next/components/banner'; -import {Hero} from 'ts/@next/components/hero'; +import { Banner } from 'ts/@next/components/banner'; +import { Hero } from 'ts/@next/components/hero'; -import {Button} from 'ts/@next/components/button'; -import {Definition} from 'ts/@next/components/definition'; -import {Section, SectionProps} from 'ts/@next/components/newLayout'; -import {SiteWrap} from 'ts/@next/components/siteWrap'; -import {Heading, Paragraph} from 'ts/@next/components/text'; +import { Button } from 'ts/@next/components/button'; +import { Definition } from 'ts/@next/components/definition'; +import { Section, SectionProps } from 'ts/@next/components/newLayout'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; +import { Heading, Paragraph } from 'ts/@next/components/text'; import { Configurator } from 'ts/@next/pages/instant/configurator'; +import { WebsitePaths } from 'ts/types'; +import { utils } from 'ts/utils/utils'; import { ModalContact } from '../components/modals/modal_contact'; +const CONFIGURATOR_MIN_WIDTH_PX = 1050; + +export const getStartedClick = () => { + if (window.innerWidth < CONFIGURATOR_MIN_WIDTH_PX) { + utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`); + } else { + sharedUtils.setUrlHash('configurator'); + sharedUtils.scrollToHash('configurator', ''); + } +}; + const featuresData = [ { title: 'Support ERC-20 and ERC-721 tokens', icon: 'supportForAllEthereumStandards-large', - description: 'Seamlessly integrate token purchasing into your product experience by offering digital assets ranging from in-game items to stablecoins.', + description: + 'Seamlessly integrate token purchasing into your product experience by offering digital assets ranging from in-game items to stablecoins.', links: [ { label: 'Get Started', - url: '#', + onClick: getStartedClick, + useAnchorTag: true, }, { label: 'Explore the Docs', - url: '#', + url: `${WebsitePaths.Wiki}#Get-Started-With-Instant`, }, ], }, { title: 'Generate revenue for your business', icon: 'generateRevenueForYourBusiness-large', - description: 'With just a few lines of code, you can earn up to 5% in affiliate fees on every transaction from your crypto wallet or dApp.', + description: + 'With just a few lines of code, you can earn up to 5% in affiliate fees on every transaction from your crypto wallet or dApp.', links: [ { label: 'Learn about affiliate fees', - url: '#', + url: `${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`, }, ], }, { title: 'Easy and flexible integration', icon: 'flexibleIntegration0xInstant', - description: 'Use our out-of-the-box design or customize the user interface by integrating via the AssetBuyer engine.. You can also tap into 0x networked liquidity or choose your own liquidity pool.', + description: + 'Use our out-of-the-box design or customize the user interface by integrating via the AssetBuyer engine.. You can also tap into 0x networked liquidity or choose your own liquidity pool.', links: [ { label: 'Explore AssetBuyer', - url: '#', - }, - { - label: 'Learn about liquidity', - url: '#', + url: `${WebsitePaths.Docs}/asset-buyer`, }, ], }, @@ -72,24 +86,24 @@ export class Next0xInstant extends React.Component<Props> { isContactModalOpen: false, }; public render(): React.ReactNode { - return ( + return ( <SiteWrap> <Hero title="Introducing 0x Instant" description="A free and flexible way to offer simple crypto purchasing in any app or website" - actions={<Button href="#configurator">Get Started</Button>} + actions={<Button onClick={getStartedClick}>Get Started</Button>} /> <Section isFullWidth={true} isPadded={false} padding="30px 0"> - <MarqueeWrap> - <div> - {[...Array(18)].map((item, index) => ( - <Card key={`card-${index}`} index={index}> - <img src={`/images/@next/0x-instant/widget-${(index % 6) + 1}.png`} /> - </Card> - ))} - </div> - </MarqueeWrap> + <MarqueeWrap> + <div> + {[...Array(18)].map((item, index) => ( + <Card key={`card-${index}`} index={index}> + <img src={`/images/@next/0x-instant/widget-${index % 6 + 1}.png`} /> + </Card> + ))} + </div> + </MarqueeWrap> </Section> <Section> @@ -106,7 +120,12 @@ export class Next0xInstant extends React.Component<Props> { ))} </Section> - <ConfiguratorSection id="configurator" maxWidth="1386px" padding="0 58px 70px" bgColor={colors.backgroundDark}> + <ConfiguratorSection + id="configurator" + maxWidth="1386px" + padding="0 58px 70px" + bgColor={colors.backgroundDark} + > <Heading>0x Instant Configurator</Heading> <Configurator /> </ConfiguratorSection> @@ -114,14 +133,24 @@ export class Next0xInstant extends React.Component<Props> { <Banner heading="Need more flexibility?" subline="Dive into our docs, or contact us if needed" - mainCta={{ text: 'Explore the Docs', href: '/docs' }} + mainCta={{ text: 'Explore the Docs', href: `${WebsitePaths.Wiki}#Get-Started-With-Instant` }} secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} /> <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> <Section maxWidth="1170px" isPadded={false} padding="60px 0"> - <Paragraph size="small" isMuted={0.5}>Disclaimer: The laws and regulations applicable to the use and exchange of digital assets and blockchain-native tokens, including through any software developed using the licensed work created by ZeroEx Intl. (the “Work”), vary by jurisdiction. As set forth in the Apache License, Version 2.0 applicable to the Work, developers are “solely responsible for determining the appropriateness of using or redistributing the Work,” which includes responsibility for ensuring compliance with any such applicable laws and regulations.</Paragraph> - <Paragraph size="small" isMuted={0.5}>See the Apache License, Version 2.0 for the specific language governing all applicable permissions and limitations.</Paragraph> + <Paragraph size="small" isMuted={0.5}> + Disclaimer: The laws and regulations applicable to the use and exchange of digital assets and + blockchain-native tokens, including through any software developed using the licensed work + created by ZeroEx Intl. (the “Work”), vary by jurisdiction. As set forth in the Apache License, + Version 2.0 applicable to the Work, developers are “solely responsible for determining the + appropriateness of using or redistributing the Work,” which includes responsibility for ensuring + compliance with any such applicable laws and regulations. + </Paragraph> + <Paragraph size="small" isMuted={0.5}> + See the Apache License, Version 2.0 for the specific language governing all applicable + permissions and limitations. + </Paragraph> </Section> </SiteWrap> ); @@ -129,11 +158,11 @@ export class Next0xInstant extends React.Component<Props> { public _onOpenContactModal = (): void => { this.setState({ isContactModalOpen: true }); - } + }; public _onDismissContactModal = (): void => { this.setState({ isContactModalOpen: false }); - } + }; } // scroll animation calc is simply (imageWidth * totalRepetitions) / 2 @@ -159,8 +188,11 @@ const fadeUp = keyframes` } `; -const ConfiguratorSection = styled(Section)<SectionProps>` - @media (max-width: 1050px) { +const ConfiguratorSection = + styled(Section) < + SectionProps > + ` + @media (max-width: ${CONFIGURATOR_MIN_WIDTH_PX}px) { display: none; } `; @@ -180,21 +212,24 @@ const MarqueeWrap = styled.div` } @media (min-width: 768px) { - > div { - width: 6660px; - animation: ${scroll} 70s linear infinite; - } + > div { + width: 6660px; + animation: ${scroll} 70s linear infinite; + } } @media (max-width: 768px) { - > div { - width: 5400px; - animation: ${scrollMobile} 70s linear infinite; - } + > div { + width: 5400px; + animation: ${scrollMobile} 70s linear infinite; + } } `; -const Card = styled.div<{index: number}>` +const Card = + styled.div < + { index: number } > + ` opacity: 0; flex-shrink: 0; transform: translateY(10px); diff --git a/packages/website/ts/@next/pages/instant/config_generator.tsx b/packages/website/ts/@next/pages/instant/config_generator.tsx index 4f837d7fa..a1263da58 100644 --- a/packages/website/ts/@next/pages/instant/config_generator.tsx +++ b/packages/website/ts/@next/pages/instant/config_generator.tsx @@ -64,7 +64,13 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps, Confi return ( <Container minWidth="350px"> <ConfigGeneratorSection title="Liquidity Source"> - <Select id="" value={value.orderSource} items={this._generateItems()} onChange={this._handleSRASelection.bind(this)} /> + <Select + includeEmpty={false} + id="" + value={value.orderSource} + items={this._generateItems()} + onChange={this._handleSRASelection.bind(this)} + /> </ConfigGeneratorSection> <ConfigGeneratorSection {...this._getTokenSelectorProps()}> {this._renderTokenMultiSelectOrSpinner()} @@ -257,7 +263,9 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps, Confi <Container marginRight="10px"> <CheckMark isChecked={isSelected} color={colors.brandLight} /> </Container> - <CheckboxText isSelected={isSelected}>{metaData.symbol.toUpperCase()} — {metaData.name}</CheckboxText> + <CheckboxText isSelected={isSelected}> + {metaData.symbol.toUpperCase()} — {metaData.name} + </CheckboxText> </Container> ), onClick: this._handleTokenClick.bind(this, assetData), @@ -287,18 +295,9 @@ export const ConfigGeneratorSection: React.StatelessComponent<ConfigGeneratorSec <Container marginBottom="10px" className="flex justify-between items-center"> <Heading size="small" marginBottom="0" isFlex={true}> <span>{title}</span> - {isOptional && ( - <OptionalText> - {' '} - Optional - </OptionalText> - )} + {isOptional && <OptionalText> Optional</OptionalText>} </Heading> - {actionText && ( - <OptionalAction onClick={onActionTextClick}> - {actionText} - </OptionalAction> - )} + {actionText && <OptionalAction onClick={onActionTextClick}>{actionText}</OptionalAction>} </Container> {children} </Container> @@ -319,10 +318,13 @@ interface CheckboxTextProps { isSelected?: boolean; } -const CheckboxText = styled.span<CheckboxTextProps>` +const CheckboxText = + styled.span < + CheckboxTextProps > + ` font-size: 14px; line-height: 18px; - color: ${props => props.isSelected ? colors.brandDark : '#666666'} + color: ${props => (props.isSelected ? colors.brandDark : '#666666')} `; const OptionalAction = styled(OptionalText)` diff --git a/packages/website/ts/@next/pages/instant/configurator.tsx b/packages/website/ts/@next/pages/instant/configurator.tsx index 007526396..7c67e6333 100644 --- a/packages/website/ts/@next/pages/instant/configurator.tsx +++ b/packages/website/ts/@next/pages/instant/configurator.tsx @@ -30,19 +30,16 @@ export class Configurator extends React.Component { public render(): React.ReactNode { const codeToDisplay = this._generateCodeDemoCode(); return ( - <FlexWrap - isFlex={true} - > + <FlexWrap isFlex={true}> <Column width="442px" padding="0 70px 0 0"> <ConfigGenerator value={this.state.instantConfig} onConfigChange={this._handleConfigChange} /> </Column> <Column width="100%"> <HeadingWrapper> - <Heading size="small" marginBottom="15px">Code Snippet</Heading> - <Link - href={`${WebsitePaths.Wiki}#Get-Started-With-Instant`} - isBlock={true} - > + <Heading size="small" marginBottom="15px"> + Code Snippet + </Heading> + <Link href={`${WebsitePaths.Wiki}#Get-Started-With-Instant`} isBlock={true} target="_blank"> Explore the Docs </Link> </HeadingWrapper> diff --git a/packages/website/ts/@next/pages/instant/select.tsx b/packages/website/ts/@next/pages/instant/select.tsx index 422818f9f..f5b5e60c8 100644 --- a/packages/website/ts/@next/pages/instant/select.tsx +++ b/packages/website/ts/@next/pages/instant/select.tsx @@ -12,23 +12,43 @@ interface SelectProps { id: string; items: SelectItemConfig[]; emptyText?: string; - onChange?: () => void; + onChange?: (ev: React.ChangeEvent<HTMLSelectElement>) => void; + includeEmpty: boolean; } -export const Select: React.FunctionComponent<SelectProps> = ({ value, id, items, emptyText, onChange }) => { +export const Select: React.FunctionComponent<SelectProps> = ({ + value, + id, + items, + includeEmpty, + emptyText, + onChange, +}) => { return ( <Container> <StyledSelect id={id} onChange={onChange}> - <option value="">{emptyText}</option> - {items.map((item, index) => <option key={`${id}-item-${index}`} value={item.value} selected={item.value === value} onClick={item.onClick}>{item.label}</option>)} + {includeEmpty && <option value="">{emptyText}</option>} + {items.map((item, index) => ( + <option + key={`${id}-item-${index}`} + value={item.value} + selected={item.value === value} + onClick={item.onClick} + > + {item.label} + </option> + ))} </StyledSelect> - <Caret width="12" height="7" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11 1L6 6 1 1" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></Caret> + <Caret width="12" height="7" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M11 1L6 6 1 1" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> + </Caret> </Container> ); }; Select.defaultProps = { emptyText: 'Select...', + includeEmpty: true, }; const Container = styled.div` diff --git a/packages/website/ts/components/onboarding/onboarding_flow.tsx b/packages/website/ts/components/onboarding/onboarding_flow.tsx index 91d5f2476..ec1b5bc42 100644 --- a/packages/website/ts/components/onboarding/onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/onboarding_flow.tsx @@ -7,8 +7,8 @@ import { OnboardingTooltip, TooltipPointerDisplay, } from 'ts/components/onboarding/onboarding_tooltip'; -import { Animation } from 'ts/components/ui/animation'; import { Container } from 'ts/components/ui/container'; +import { EaseUpFromBottomAnimation } from 'ts/components/ui/ease_up_from_bottom_animation'; import { Overlay } from 'ts/components/ui/overlay'; import { zIndex } from 'ts/style/z_index'; @@ -66,7 +66,7 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> { let onboardingElement = null; const currentStep = this._getCurrentStep(); if (this.props.isMobile) { - onboardingElement = <Animation type="easeUpFromBottom">{this._renderOnboardingCard()}</Animation>; + onboardingElement = <EaseUpFromBottomAnimation>{this._renderOnboardingCard()}</EaseUpFromBottomAnimation>; } else if (currentStep.position.type === 'target') { const { placement, target } = currentStep.position; onboardingElement = ( diff --git a/packages/website/ts/components/ui/animation.tsx b/packages/website/ts/components/ui/animation.tsx deleted file mode 100644 index 943e3bf28..000000000 --- a/packages/website/ts/components/ui/animation.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import * as React from 'react'; -import { keyframes, styled } from 'ts/style/theme'; - -export type AnimationType = 'easeUpFromBottom'; - -export interface AnimationProps { - type: AnimationType; -} - -const PlainAnimation: React.StatelessComponent<AnimationProps> = props => <div {...props} />; - -const appearFromBottomFrames = keyframes` - from { - position: fixed; - bottom: -500px; - left: 0px; - right: 0px; - } - - to { - position: fixed; - bottom: 0px; - left: 0px; - right: 0px; - } -`; - -const stylesForAnimation: { [K in AnimationType]: string } = { - // Needed for safari - easeUpFromBottom: `position: fixed`, -}; - -const animations: { [K in AnimationType]: string } = { - easeUpFromBottom: `${appearFromBottomFrames} 1s ease 0s 1 forwards`, -}; - -export const Animation = styled(PlainAnimation)` - animation: ${props => animations[props.type]}; - ${props => stylesForAnimation[props.type]}; -`; - -Animation.displayName = 'Animation'; diff --git a/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx b/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx new file mode 100644 index 000000000..176c9410c --- /dev/null +++ b/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx @@ -0,0 +1,32 @@ +import * as React from 'react'; +import { css, keyframes, styled } from 'ts/style/theme'; + +const appearFromBottomFrames = keyframes` + from { + position: fixed; + bottom: -500px; + left: 0px; + right: 0px; + } + + to { + position: fixed; + bottom: 0px; + left: 0px; + right: 0px; + } +`; + +const stylesForAnimation = css` + position: fixed; +`; +const animations = css` + animation: ${appearFromBottomFrames} 1s ease 0s 1 forwards; +`; + +export const EaseUpFromBottomAnimation = styled.div` + ${props => animations}; + ${props => stylesForAnimation}; +`; + +EaseUpFromBottomAnimation.displayName = 'EaseUpFromBottomAnimation'; diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 3e3dced1a..915d28aaa 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -191,7 +191,7 @@ render( path={`${WebsiteLegacyPaths.Deployer}/:version?`} component={LazySolCompilerDocumentation} /> - <Route path={WebsiteLegacyPaths.Jobs} component={Jobs as any} /> + <Redirect from={WebsiteLegacyPaths.Jobs} to={WebsitePaths.AboutJobs} /> <Route component={NotFound as any} /> </Switch> </div> diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts index 7cc854ca0..663f90249 100644 --- a/packages/website/ts/utils/configs.ts +++ b/packages/website/ts/utils/configs.ts @@ -5,8 +5,8 @@ const INFURA_API_KEY = 'T5WSC8cautR4KXyYgsRs'; export const configs = { AMOUNT_DISPLAY_PRECSION: 5, - BACKEND_BASE_PROD_URL: 'https://website-api.0x.org', - BACKEND_BASE_STAGING_URL: 'https://staging-website-api.0x.org', + BACKEND_BASE_PROD_URL: 'https://website-api.0xproject.com', + BACKEND_BASE_STAGING_URL: 'https://staging-website-api.0xproject.com', BASE_URL, BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208', DEFAULT_DERIVATION_PATH: `44'/60'/0'`, |