diff options
Diffstat (limited to 'packages/website')
-rw-r--r-- | packages/website/package.json | 1 | ||||
-rw-r--r-- | packages/website/ts/@next/components/blockIconLink.tsx | 36 | ||||
-rw-r--r-- | packages/website/ts/@next/components/button.tsx | 4 | ||||
-rw-r--r-- | packages/website/ts/@next/components/modals/input.tsx | 65 | ||||
-rw-r--r-- | packages/website/ts/@next/components/modals/modal_contact.tsx | 198 | ||||
-rw-r--r-- | packages/website/ts/@next/components/sections/landing/cta.tsx | 8 | ||||
-rw-r--r-- | packages/website/ts/@next/pages/landing.tsx | 38 |
7 files changed, 326 insertions, 24 deletions
diff --git a/packages/website/package.json b/packages/website/package.json index 629cbffc2..fc98a1a1b 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -32,6 +32,7 @@ "@0x/typescript-typings": "^3.0.4", "@0x/utils": "^2.0.6", "@0x/web3-wrapper": "^3.1.6", + "@reach/dialog": "^0.1.2", "@types/react-lazyload": "^2.3.1", "@types/react-loadable": "^5.4.2", "@types/react-syntax-highlighter": "^0.0.8", diff --git a/packages/website/ts/@next/components/blockIconLink.tsx b/packages/website/ts/@next/components/blockIconLink.tsx index cc3e88280..42b260731 100644 --- a/packages/website/ts/@next/components/blockIconLink.tsx +++ b/packages/website/ts/@next/components/blockIconLink.tsx @@ -1,14 +1,15 @@ import * as React from 'react'; import styled from 'styled-components'; -import {Link} from 'ts/@next/components/button'; +import {Button, Link} from 'ts/@next/components/button'; import {Icon} from 'ts/@next/components/icon'; interface Props { icon: string; title: string; linkLabel: string; - linkUrl: string; + linkUrl?: string; + onClick?: () => void; } export const BlockIconLink = (props: Props) => ( @@ -24,14 +25,29 @@ export const BlockIconLink = (props: Props) => ( {props.title} </Title> - <Link - isWithArrow={true} - isTransparent={true} - isNoBorder={true} - href={props.linkUrl} - > - {props.linkLabel} - </Link> + {props.linkUrl && + <Link + isWithArrow={true} + isTransparent={true} + isNoBorder={true} + href={props.linkUrl} + onClick={props.onClick} + > + {props.linkLabel} + </Link> + } + + {props.onClick && + <Button + isWithArrow={true} + isTransparent={true} + isNoBorder={true} + href={props.linkUrl} + onClick={props.onClick} + > + {props.linkLabel} + </Button> + } </div> </Wrap> ); diff --git a/packages/website/ts/@next/components/button.tsx b/packages/website/ts/@next/components/button.tsx index 3f14b59bd..5d44f1ce5 100644 --- a/packages/website/ts/@next/components/button.tsx +++ b/packages/website/ts/@next/components/button.tsx @@ -16,6 +16,8 @@ interface ButtonInterface { isWithArrow?: boolean; isAccentColor?: boolean; hasIcon?: boolean | string; + isInline?: boolean; + type?: string; href?: string; onClick?: () => any; theme?: { @@ -57,7 +59,7 @@ export const Button = styled.button<ButtonInterface>` } `; -export const Link = (props: ButtonInterface) => { +export const Link: React.ReactNode = (props: ButtonInterface) => { const { children, href, diff --git a/packages/website/ts/@next/components/modals/input.tsx b/packages/website/ts/@next/components/modals/input.tsx new file mode 100644 index 000000000..eee2d4102 --- /dev/null +++ b/packages/website/ts/@next/components/modals/input.tsx @@ -0,0 +1,65 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +export enum InputWidth { + Half, + Full, +} + +interface InputProps { + name: string; + width: InputWidth; + label: string; + type?: string; +} + +interface LabelProps { + string: boolean; +} + +export const Input = React.forwardRef((props: InputProps, ref) => { + const { name, label, type } = props; + const id = `input-${name}`; + + return ( + <InputWrapper {...props}> + <Label htmlFor={id}>{label}</Label> + <StyledInput ref={ref} id={id} placeholder={label} {...props} /> + </InputWrapper> + ); +}); + +Input.defaultProps = { + width: InputWidth.Full, +}; + +const StyledInput = styled.input` + appearance: none; + background-color: #fff; + border: 1px solid #D5D5D5; + color: #000; + font-size: 1.294117647rem; + padding: 16px 15px; + outline: none; + width: 100%; + + &::placeholder { + color: #9D9D9D; + } +`; + +const InputWrapper = styled.div<InputProps>` + position: relative; + flex-grow: ${props => props.width === InputWidth.Full && 1}; + width: ${props => props.width === InputWidth.Half && `calc(50% - 15px)`}; +`; + +const Label = styled.label` + color: #000; + font-size: 1.111111111rem; + line-height: 1.4em; + margin-bottom: 10px; + display: inline-block; +`; diff --git a/packages/website/ts/@next/components/modals/modal_contact.tsx b/packages/website/ts/@next/components/modals/modal_contact.tsx new file mode 100644 index 000000000..cd6335103 --- /dev/null +++ b/packages/website/ts/@next/components/modals/modal_contact.tsx @@ -0,0 +1,198 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import {Link as RouterLink} from 'react-router-dom'; +import styled, {withTheme} from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { + Dialog, + DialogOverlay, + DialogContent + } from "@reach/dialog"; +import "@reach/dialog/styles.css"; + +import {Button} from 'ts/@next/components/button'; +import {Column, Wrap, WrapGrid} from 'ts/@next/components/layout'; +import { Icon } from 'ts/@next/components/icon'; +import {Input, InputWidth} from 'ts/@next/components/modals/input'; +import {Heading, Paragraph} from 'ts/@next/components/text'; +import {GlobalStyle} from 'ts/@next/constants/globalStyle'; + +interface Props { + theme?: GlobalStyle; + isOpen?: boolean; + onDismiss?: () => void; +} + +interface FormProps { + isSuccessful?: boolean; + isSubmitting?: boolean; +} + +export class ModalContact extends React.Component<Props> { + public state = { + isSubmitting: false, + isSuccessful: false, + }; + public constructor(props: Props) { + super(props); + } + public render(): React.ReactNode { + const {isOpen, onDismiss} = this.props; + const {isSuccessful} = this.state; + + return ( + <> + <DialogOverlay + style={{ background: 'rgba(0, 0, 0, 0.75)' }} + isOpen={isOpen} + > + <StyledDialogContent> + <Form onSubmit={this._onSubmit.bind(this)} isSuccessful={isSuccessful}> + <Heading color={colors.textDarkPrimary} size={34} asElement="h2">Contact the 0x Core Team</Heading> + <Paragraph isMuted={true} color={colors.textDarkPrimary}>If you're considering building on 0x, we're happy to answer your questions. Fill out the form so we can connect you with the right person to help you get started.</Paragraph> + <InputRow> + <Input + name="name" + label="Your name" + type="text" + width={InputWidth.Half} + /> + <Input + name="email" + label="Your email" + type="email" + width={InputWidth.Half} + /> + </InputRow> + <InputRow> + <Input + name="companyOrProject" + label="Name of your project / company" + type="text" + /> + </InputRow> + <InputRow> + <Input + name="link" + label="Do you have any documentation or a website?" + type="text" + /> + </InputRow> + <InputRow> + <Input + name="comments" + label="Anything else?" + type="text" + /> + </InputRow> + <InputRow> + <Button + color="#5C5C5C" + isNoBorder={true} + isTransparent={true} + type="button" + onClick={this.props.onDismiss} + > + Back + </Button> + <Button>Submit</Button> + </InputRow> + </Form> + <Confirmation isSuccessful={isSuccessful}> + <Icon name="checkmark" size="large" /> + <Heading color={colors.textDarkPrimary} size={34} asElement="h2">Thanks for contacting us.</Heading> + <Paragraph isMuted={true} color={colors.textDarkPrimary}>We'll get back to you soon. If you need quick support in the meantime, reach out to the 0x team on Discord.</Paragraph> + <Button onClick={this.props.onDismiss}>Done</Button> + </Confirmation> + </StyledDialogContent> + </DialogOverlay> + </> + ); + } + private async _onSubmit(e): void { + e.preventDefault(); + + // const email = this.emailInput.current.value; + const email = 'fred@sjelfull.no'; + + this.setState({ ...this.state, isSubmitting: true }); + + try { + const response = await fetch('/email', { + method: 'post', + headers: { + 'content-type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ email }), + }); + const json = await response.json(); + + console.log(response.json()); + } catch (e) { + console.log(e); + } + + this.setState({ ...this.state, isSuccessful: true }); + } + private async _onDone(e): void { + e.preventDefault(); + + this.props.onDismiss(); + } +}; + +const StyledWrap = styled(Wrap)` + padding-top: 20px; + margin-top: 30px; + position: relative; + + &:before { + content: ''; + width: 100%; + height: 1px; + background-color: ${props => props.theme.dropdownColor}; + opacity: 0.15; + position: absolute; + top: 0; + left:0; + } +`; + +const InputRow = styled.div` + display: flex; + justify-content: space-between; + margin-bottom: 30px; + width: 100%; + flex: 0 0 auto; +`; + +const StyledDialogContent = styled(DialogContent)` + position: relative; + max-width: 800px; + background-color: #F6F6F6 !important; + padding: 60px 60px !important; +`; + +const Form = styled.form<FormProps>` + position: relative; + transition: opacity 0.30s ease-in-out, visibility 0.30s ease-in-out; + + opacity: ${props => props.isSuccessful && `0`}; + visibility: ${props => props.isSuccessful && `hidden`}; +`; + +const Confirmation = styled.div<FormProps>` + position: absolute; + top: 50%; + text-align: center; + width: 100%; + left: 0; + transition: opacity 0.30s ease-in-out, visibility 0.30s ease-in-out; + transition-delay: 0.40s; + padding: 60px 60px; + transform: translateY(-50%); + opacity: ${props => props.isSuccessful ? `1` : `0`}; + visibility: ${props => props.isSuccessful ? 'visible' : `hidden`}; +`; diff --git a/packages/website/ts/@next/components/sections/landing/cta.tsx b/packages/website/ts/@next/components/sections/landing/cta.tsx index 4c06982e4..b90b4070e 100644 --- a/packages/website/ts/@next/components/sections/landing/cta.tsx +++ b/packages/website/ts/@next/components/sections/landing/cta.tsx @@ -8,7 +8,11 @@ import {Column, Section} from 'ts/@next/components/newLayout'; import {BlockIconLink} from 'ts/@next/components/blockIconLink'; -export const SectionLandingCta = () => ( +interface Props { + onContactClick?: () => void; +} + +export const SectionLandingCta = (props: Props) => ( <Section isPadded={false} isFullWidth={true} @@ -25,7 +29,7 @@ export const SectionLandingCta = () => ( icon="coin" title="Wat help from the 0x team?" linkLabel="Get in Touch" - linkUrl="#" + onClick={props.onContactClick} /> </Section> ); diff --git a/packages/website/ts/@next/pages/landing.tsx b/packages/website/ts/@next/pages/landing.tsx index fab5e62b6..5ead1b6b5 100644 --- a/packages/website/ts/@next/pages/landing.tsx +++ b/packages/website/ts/@next/pages/landing.tsx @@ -7,9 +7,7 @@ import {SectionLandingClients} from 'ts/@next/components/sections/landing/client import {SectionLandingCta} from 'ts/@next/components/sections/landing/cta'; import {SectionLandingHero} from 'ts/@next/components/sections/landing/hero'; -import {Button} from 'ts/@next/components/button'; -import {Hero} from 'ts/@next/components/hero'; -import {LandingAnimation} from 'ts/@next/components/heroImage'; +import { ModalContact } from 'ts/@next/components/modals/modal_contact'; import LogoOutlined from 'ts/@next/icons/illustrations/logo-outlined.svg'; @@ -21,11 +19,29 @@ interface Props { }; } -export const NextLanding: React.StatelessComponent<{}> = (props: Props) => ( - <SiteWrap theme="dark"> - <SectionLandingHero /> - <SectionLandingAbout /> - <SectionLandingClients /> - <SectionLandingCta /> - </SiteWrap> -); +export class NextLanding extends React.Component<Props> { + public state = { + isContactModalOpen: false, + }; + public render(): React.ReactNode { + return ( + <SiteWrap theme="dark"> + <SectionLandingHero /> + <SectionLandingAbout /> + <SectionLandingClients /> + <SectionLandingCta onContactClick={this._onOpenContactModal.bind(this)} /> + <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal.bind(this)} /> + </SiteWrap> + ); + } + + private _onOpenContactModal(e): void { + e.preventDefault(); + + this.setState({ isContactModalOpen: true }); + } + + private _onDismissContactModal(): void { + this.setState({ isContactModalOpen: false }); + } +} |