aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/@next/components
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/@next/components')
-rw-r--r--packages/website/ts/@next/components/banner.tsx14
-rw-r--r--packages/website/ts/@next/components/button.tsx1
-rw-r--r--packages/website/ts/@next/components/definition.tsx17
-rw-r--r--packages/website/ts/@next/components/footer.tsx4
-rw-r--r--packages/website/ts/@next/components/hamburger.tsx1
-rw-r--r--packages/website/ts/@next/components/header.tsx69
-rw-r--r--packages/website/ts/@next/components/mobileNav.tsx15
-rw-r--r--packages/website/ts/@next/components/modals/input.tsx29
-rw-r--r--packages/website/ts/@next/components/modals/modal_contact.tsx47
-rw-r--r--packages/website/ts/@next/components/newsletter_form.tsx20
-rw-r--r--packages/website/ts/@next/components/sections/landing/about.tsx2
-rw-r--r--packages/website/ts/@next/components/sections/landing/clients.tsx29
-rw-r--r--packages/website/ts/@next/components/siteWrap.tsx4
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'};
`;