feat: remove unused files
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
"scripts": {
|
||||
"build": "yarn build:dev",
|
||||
"build:prod": "node --max_old_space_size=8192 ../../node_modules/.bin/webpack --mode production",
|
||||
"build:dev": "../../node_modules/.bin/webpack --mode development",
|
||||
"build:dev": "../../node_modules/.bin/webpack --mode development --json",
|
||||
"clean": "shx rm -f public/bundle*",
|
||||
"lint": "tslint --format stylish --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
|
||||
"dev": "webpack-dev-server --mode development --content-base public --https",
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { colors } from '@0x/react-shared';
|
||||
import Dialog from 'material-ui/Dialog';
|
||||
import FlatButton from 'material-ui/FlatButton';
|
||||
import * as React from 'react';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
|
||||
interface U2fNotSupportedDialogProps {
|
||||
isOpen: boolean;
|
||||
onToggleDialog: () => void;
|
||||
}
|
||||
|
||||
export const U2fNotSupportedDialog = (props: U2fNotSupportedDialogProps) => {
|
||||
return (
|
||||
<Dialog
|
||||
title="U2F Not Supported"
|
||||
titleStyle={{ fontWeight: 100 }}
|
||||
actions={[<FlatButton key="u2fNo" label="Ok" onClick={props.onToggleDialog} />]}
|
||||
open={props.isOpen}
|
||||
onRequestClose={props.onToggleDialog}
|
||||
autoScrollBodyContent={true}
|
||||
>
|
||||
<div className="pt2" style={{ color: colors.grey700 }}>
|
||||
<div>
|
||||
It looks like your browser does not support U2F connections required for us to communicate with your
|
||||
hardware wallet. Please use a browser that supports U2F connections and try again.
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li className="pb1">Chrome version 38 or later</li>
|
||||
<li className="pb1">Opera version 40 of later</li>
|
||||
<li>
|
||||
Firefox with{' '}
|
||||
<a
|
||||
href={constants.URL_FIREFOX_U2F_ADDON}
|
||||
target="_blank"
|
||||
style={{ textDecoration: 'underline' }}
|
||||
>
|
||||
this extension
|
||||
</a>.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
import Dialog from 'material-ui/Dialog';
|
||||
import FlatButton from 'material-ui/FlatButton';
|
||||
import { colors } from 'material-ui/styles';
|
||||
import * as React from 'react';
|
||||
|
||||
interface WrappedEthSectionNoticeDialogProps {
|
||||
isOpen: boolean;
|
||||
onToggleDialog: () => void;
|
||||
}
|
||||
|
||||
export const WrappedEthSectionNoticeDialog = (props: WrappedEthSectionNoticeDialogProps) => {
|
||||
return (
|
||||
<Dialog
|
||||
title="Dedicated Wrapped Ether Section"
|
||||
titleStyle={{ fontWeight: 100 }}
|
||||
actions={[
|
||||
<FlatButton key="acknowledgeWrapEthSection" label="Sounds good" onClick={props.onToggleDialog} />,
|
||||
]}
|
||||
open={props.isOpen}
|
||||
onRequestClose={props.onToggleDialog}
|
||||
autoScrollBodyContent={true}
|
||||
modal={true}
|
||||
>
|
||||
<div className="pt2" style={{ color: colors.grey700 }}>
|
||||
<div>
|
||||
We have recently updated the Wrapped Ether token (WETH) used by 0x Portal. Don't worry, unwrapping
|
||||
Ether tied to the old Wrapped Ether token can be done at any time by clicking on the "Wrap ETH"
|
||||
section in the menu to the left.
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -1,127 +0,0 @@
|
||||
import { colors } from '@0x/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Button } from 'ts/components/ui/button';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Input } from 'ts/components/ui/input';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { analytics } from 'ts/utils/analytics';
|
||||
import { backendClient } from 'ts/utils/backend_client';
|
||||
|
||||
export interface SubscribeFormProps {}
|
||||
|
||||
export enum SubscribeFormStatus {
|
||||
None,
|
||||
Error,
|
||||
Success,
|
||||
Loading,
|
||||
Other,
|
||||
}
|
||||
|
||||
export interface SubscribeFormState {
|
||||
emailText: string;
|
||||
lastSubmittedEmail: string;
|
||||
status: SubscribeFormStatus;
|
||||
}
|
||||
|
||||
const FORM_FONT_SIZE = '15px';
|
||||
|
||||
// TODO: Translate visible strings. https://app.asana.com/0/628666249318202/697485674422001
|
||||
export class SubscribeForm extends React.Component<SubscribeFormProps, SubscribeFormState> {
|
||||
public state = {
|
||||
emailText: '',
|
||||
lastSubmittedEmail: '',
|
||||
status: SubscribeFormStatus.None,
|
||||
};
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<Container className="flex flex-column items-center justify-between md-mx2 sm-mx2">
|
||||
<Container marginBottom="15px">
|
||||
<Text fontFamily="Roboto Mono" fontColor={colors.grey} center={true}>
|
||||
Subscribe to our newsletter for 0x relayer and dApp updates
|
||||
</Text>
|
||||
</Container>
|
||||
<form onSubmit={this._handleFormSubmitAsync.bind(this)}>
|
||||
<Container className="flex flex-wrap justify-center items-center">
|
||||
<Container marginTop="15px">
|
||||
<Input
|
||||
placeholder="you@email.com"
|
||||
value={this.state.emailText}
|
||||
fontColor={colors.white}
|
||||
fontSize={FORM_FONT_SIZE}
|
||||
backgroundColor={colors.projectsGrey}
|
||||
width="300px"
|
||||
onChange={this._handleEmailInputChange.bind(this)}
|
||||
/>
|
||||
</Container>
|
||||
<Container marginLeft="15px" marginTop="15px">
|
||||
<Button
|
||||
type="submit"
|
||||
backgroundColor={colors.darkestGrey}
|
||||
fontColor={colors.white}
|
||||
fontSize={FORM_FONT_SIZE}
|
||||
>
|
||||
Subscribe
|
||||
</Button>
|
||||
</Container>
|
||||
</Container>
|
||||
</form>
|
||||
{this._renderMessage()}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private _renderMessage(): React.ReactNode {
|
||||
let message = null;
|
||||
switch (this.state.status) {
|
||||
case SubscribeFormStatus.Error:
|
||||
message = 'Sorry, something went wrong. Try again later.';
|
||||
break;
|
||||
case SubscribeFormStatus.Loading:
|
||||
message = 'One second...';
|
||||
break;
|
||||
case SubscribeFormStatus.Success:
|
||||
message = `Thanks! ${this.state.lastSubmittedEmail} is now on the mailing list.`;
|
||||
break;
|
||||
case SubscribeFormStatus.None:
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
'The SubscribeFormStatus switch statement is not exhaustive when choosing an error message.',
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Container isHidden={!message} marginTop="30px">
|
||||
<Text center={true} fontFamily="Roboto Mono" fontColor={colors.grey}>
|
||||
{message || 'spacer text (never shown to user)'}
|
||||
</Text>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private _handleEmailInputChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
this.setState({ emailText: event.target.value });
|
||||
}
|
||||
private async _handleFormSubmitAsync(event: React.FormEvent<HTMLInputElement>): Promise<void> {
|
||||
event.preventDefault();
|
||||
if (_.isUndefined(this.state.emailText) || _.isEmpty(this.state.emailText)) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
status: SubscribeFormStatus.Loading,
|
||||
lastSubmittedEmail: this.state.emailText,
|
||||
});
|
||||
try {
|
||||
const response = await backendClient.subscribeToNewsletterAsync(this.state.emailText);
|
||||
const status = response.status === 200 ? SubscribeFormStatus.Success : SubscribeFormStatus.Error;
|
||||
if (status === SubscribeFormStatus.Success) {
|
||||
analytics.identify(this.state.emailText, 'email');
|
||||
}
|
||||
this.setState({ status, emailText: '' });
|
||||
} catch (error) {
|
||||
this._setStatus(SubscribeFormStatus.Error);
|
||||
}
|
||||
}
|
||||
private _setStatus(status: SubscribeFormStatus): void {
|
||||
this.setState({ status });
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import { getCSSPadding, PADDING_SIZES, PaddingInterface } from 'ts/constants/utilities';
|
||||
|
||||
interface WrapWidths {
|
||||
default: string;
|
||||
full: string;
|
||||
medium: string;
|
||||
narrow: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
interface ColumnWidths {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
interface SectionProps {
|
||||
isNoPadding?: boolean;
|
||||
isPadLarge?: boolean;
|
||||
isNoMargin?: boolean;
|
||||
bgColor?: string;
|
||||
isFullWidth?: boolean;
|
||||
isRelative?: boolean;
|
||||
}
|
||||
|
||||
interface WrapProps extends PaddingInterface {
|
||||
width?: 'default' | 'full' | 'medium' | 'narrow';
|
||||
bgColor?: string;
|
||||
isWrapped?: boolean;
|
||||
isCentered?: boolean;
|
||||
isReversed?: boolean;
|
||||
}
|
||||
|
||||
interface ColumnProps {
|
||||
colWidth?: '1/4' | '1/3' | '1/2' | '2/3';
|
||||
isNoPadding?: boolean;
|
||||
isNoMargin?: boolean;
|
||||
isPadLarge?: boolean;
|
||||
isFlexGrow?: boolean;
|
||||
isMobileCentered?: boolean;
|
||||
bgColor?: string;
|
||||
}
|
||||
|
||||
interface GetColWidthArgs {
|
||||
span?: number;
|
||||
columns: number;
|
||||
}
|
||||
|
||||
export interface WrapStickyInterface {
|
||||
offsetTop?: string;
|
||||
}
|
||||
|
||||
const _getColumnWidth = (args: GetColWidthArgs): string => {
|
||||
const { span = 1, columns } = args;
|
||||
const percentWidth = span / columns * 100;
|
||||
const gutterDiff = GUTTER * (columns - 1) / columns;
|
||||
return `calc(${percentWidth}% - ${gutterDiff}px)`;
|
||||
};
|
||||
|
||||
const GUTTER = 30 as number;
|
||||
const MAX_WIDTH = 1500;
|
||||
export const BREAKPOINTS = {
|
||||
mobile: '768px',
|
||||
};
|
||||
const WRAPPER_WIDTHS: WrapWidths = {
|
||||
default: `${MAX_WIDTH}px`, // tbd
|
||||
full: '100%',
|
||||
medium: '1136px',
|
||||
narrow: '930px',
|
||||
};
|
||||
const COLUMN_WIDTHS: ColumnWidths = {
|
||||
'1/4': _getColumnWidth({ columns: 4 }),
|
||||
'1/3': _getColumnWidth({ columns: 3 }),
|
||||
'1/2': _getColumnWidth({ columns: 2 }),
|
||||
'2/3': _getColumnWidth({ span: 2, columns: 3 }),
|
||||
};
|
||||
|
||||
export const Main = styled.main`
|
||||
max-width: ${MAX_WIDTH}px;
|
||||
margin: 0 auto;
|
||||
|
||||
@media (min-width: ${BREAKPOINTS.mobile}) {
|
||||
width: calc(100% - 60px);
|
||||
}
|
||||
`;
|
||||
|
||||
// We can also turn Section into a stateless comp,
|
||||
// passing a asElement (same patter nas Heading) so we dont have to
|
||||
// make a const on every route to withComponent-size it.
|
||||
// just <Section asElement?="div/section/footer/header/whatever" /> ?
|
||||
export const Section =
|
||||
styled.section <
|
||||
SectionProps >
|
||||
`
|
||||
width: ${props => (props.isFullWidth ? `calc(100% + ${GUTTER * 2}px)` : '100%')};
|
||||
padding: ${props => !props.isNoPadding && (props.isPadLarge ? `${PADDING_SIZES.large}` : PADDING_SIZES.default)};
|
||||
background-color: ${props => props.bgColor};
|
||||
position: ${props => props.isRelative && 'relative'};
|
||||
overflow: ${props => props.isRelative && 'hidden'};
|
||||
margin-bottom: ${props => !props.isNoMargin && `${GUTTER}px`};
|
||||
|
||||
@media (min-width: 1560px) {
|
||||
width: ${props => props.isFullWidth && '100vw'};
|
||||
margin-left: ${props => props.isFullWidth && `calc(750px - 50vw)`};
|
||||
}
|
||||
|
||||
@media (max-width: ${BREAKPOINTS.mobile}) {
|
||||
margin-bottom: ${props => !props.isNoMargin && `${GUTTER / 2}px`};
|
||||
padding: ${props =>
|
||||
props.isPadLarge ? `${PADDING_SIZES.large} ${PADDING_SIZES.default}` : PADDING_SIZES.default};
|
||||
}
|
||||
`;
|
||||
|
||||
const WrapBase =
|
||||
styled.div <
|
||||
WrapProps >
|
||||
`
|
||||
max-width: ${props => WRAPPER_WIDTHS[props.width || 'default']};
|
||||
padding: ${props => props.padding && getCSSPadding(props.padding)};
|
||||
background-color: ${props => props.bgColor};
|
||||
margin: 0 auto;
|
||||
`;
|
||||
|
||||
export const Wrap = styled(WrapBase)`
|
||||
@media (min-width: ${BREAKPOINTS.mobile}) {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: ${props => props.isReversed && 'row-reverse'};
|
||||
}
|
||||
`;
|
||||
|
||||
export const WrapCentered = styled(WrapBase)`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
export const WrapSticky =
|
||||
styled.div <
|
||||
WrapStickyInterface >
|
||||
`
|
||||
position: sticky;
|
||||
top: ${props => props.offsetTop || '60px'};
|
||||
`;
|
||||
|
||||
export const WrapGrid = styled(WrapBase)`
|
||||
display: flex;
|
||||
flex-wrap: ${props => props.isWrapped && `wrap`};
|
||||
justify-content: ${props => (props.isCentered ? `center` : 'space-between')};
|
||||
`;
|
||||
|
||||
export const Column =
|
||||
styled.div <
|
||||
ColumnProps >
|
||||
`
|
||||
background-color: ${props => props.bgColor};
|
||||
flex-grow: ${props => props.isFlexGrow && 1};
|
||||
|
||||
@media (min-width: ${BREAKPOINTS.mobile}) {
|
||||
padding: ${props =>
|
||||
!props.isNoPadding &&
|
||||
(props.isPadLarge ? `${PADDING_SIZES.large} ${PADDING_SIZES.default}` : PADDING_SIZES.default)};
|
||||
width: ${props => (props.colWidth ? COLUMN_WIDTHS[props.colWidth] : '100%')};
|
||||
}
|
||||
|
||||
@media (max-width: ${BREAKPOINTS.mobile}) {
|
||||
padding: ${props => !props.isNoPadding && (props.isPadLarge ? '40px 30px' : 0)};
|
||||
margin-bottom: 20px;
|
||||
text-align: ${props => props.isMobileCentered && 'center'};
|
||||
}
|
||||
`;
|
||||
|
||||
WrapGrid.defaultProps = {
|
||||
isCentered: true,
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
import { constants } from 'ts/utils/constants';
|
||||
|
||||
interface RedirectorProps {
|
||||
location: string;
|
||||
}
|
||||
|
||||
export function Redirector(_props: RedirectorProps): void {
|
||||
window.location.href = constants.URL_ANGELLIST;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Separator = styled.hr`
|
||||
background: #eaeaea;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
`;
|
||||
@@ -1,18 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface FilledImageProps {
|
||||
src: string;
|
||||
}
|
||||
export const FilledImage = (props: FilledImageProps) => (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
backgroundImage: `url(${props.src})`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
backgroundSize: 'cover',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -1,49 +0,0 @@
|
||||
import { colors } from '@0x/react-shared';
|
||||
import * as React from 'react';
|
||||
import { styled } from 'ts/style/theme';
|
||||
|
||||
export interface InputProps {
|
||||
className?: string;
|
||||
value?: string;
|
||||
width?: string;
|
||||
fontSize?: string;
|
||||
fontColor?: string;
|
||||
border?: string;
|
||||
padding?: string;
|
||||
placeholderColor?: string;
|
||||
placeholder?: string;
|
||||
backgroundColor?: string;
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
const PlainInput: React.StatelessComponent<InputProps> = ({ value, className, placeholder, onChange }) => (
|
||||
<input className={className} value={value} onChange={onChange} placeholder={placeholder} />
|
||||
);
|
||||
|
||||
export const Input = styled(PlainInput)`
|
||||
font-size: ${props => props.fontSize};
|
||||
width: ${props => props.width};
|
||||
padding: ${props => props.padding};
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Roboto Mono';
|
||||
color: ${props => props.fontColor};
|
||||
border: ${props => props.border};
|
||||
outline: none;
|
||||
background-color: ${props => props.backgroundColor};
|
||||
&::placeholder {
|
||||
color: ${props => props.placeholderColor};
|
||||
}
|
||||
`;
|
||||
|
||||
Input.defaultProps = {
|
||||
width: 'auto',
|
||||
backgroundColor: colors.white,
|
||||
fontColor: colors.darkestGrey,
|
||||
placeholderColor: colors.darkGrey,
|
||||
fontSize: '12px',
|
||||
border: 'none',
|
||||
padding: '0.8em 1.2em',
|
||||
};
|
||||
|
||||
Input.displayName = 'Input';
|
||||
@@ -1,17 +0,0 @@
|
||||
import CircularProgress from 'material-ui/CircularProgress';
|
||||
import * as React from 'react';
|
||||
|
||||
export interface SimpleLoadingProps {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export const SimpleLoading = (props: SimpleLoadingProps) => {
|
||||
return (
|
||||
<div className="mx-auto pt3" style={{ maxWidth: 400, height: 409 }}>
|
||||
<div className="relative" style={{ top: '50%', transform: 'translateY(-50%)', height: 95 }}>
|
||||
<CircularProgress />
|
||||
<div className="pt3 pb3">{props.message}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,75 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import Typist from 'react-typist';
|
||||
|
||||
import { Text, TextProps } from 'ts/components/ui/text';
|
||||
|
||||
import 'react-typist/dist/Typist.css';
|
||||
|
||||
export interface TypedTextProps extends TextProps {
|
||||
textList: string[];
|
||||
shouldRepeat?: boolean;
|
||||
wordDelayMs?: number;
|
||||
avgKeystrokeDelayMs?: number;
|
||||
stdKeystrokeDelay?: number;
|
||||
}
|
||||
|
||||
export interface TypedTextState {
|
||||
cycleCount: number;
|
||||
}
|
||||
|
||||
export class TypedText extends React.Component<TypedTextProps, TypedTextState> {
|
||||
public static defaultProps = {
|
||||
shouldRepeat: false,
|
||||
avgKeystrokeDelayMs: 90,
|
||||
wordDelayMs: 1000,
|
||||
};
|
||||
public state = {
|
||||
cycleCount: 0,
|
||||
};
|
||||
public render(): React.ReactNode {
|
||||
const {
|
||||
textList,
|
||||
shouldRepeat,
|
||||
wordDelayMs,
|
||||
avgKeystrokeDelayMs,
|
||||
stdKeystrokeDelay,
|
||||
// tslint:disable-next-line
|
||||
...textProps
|
||||
} = this.props;
|
||||
const { cycleCount } = this.state;
|
||||
if (_.isEmpty(textList)) {
|
||||
return null;
|
||||
}
|
||||
const typistChildren: React.ReactNode[] = [];
|
||||
_.forEach(textList, text => {
|
||||
typistChildren.push(
|
||||
<Text key={`text-${text}-${cycleCount}`} {...textProps}>
|
||||
{text}
|
||||
</Text>,
|
||||
);
|
||||
if (wordDelayMs) {
|
||||
typistChildren.push(<Typist.Delay key={`delay-${text}-${cycleCount}`} ms={wordDelayMs} />);
|
||||
}
|
||||
typistChildren.push(<Typist.Backspace key={`backspace-${text}-${cycleCount}`} count={text.length} />);
|
||||
});
|
||||
return (
|
||||
<Typist
|
||||
avgTypingDelay={avgKeystrokeDelayMs}
|
||||
stdTypingDelay={stdKeystrokeDelay}
|
||||
className="inline"
|
||||
key={`typist-key-${cycleCount}`}
|
||||
onTypingDone={this._onTypingDone.bind(this)}
|
||||
>
|
||||
{typistChildren}
|
||||
</Typist>
|
||||
);
|
||||
}
|
||||
private _onTypingDone(): void {
|
||||
if (this.props.shouldRepeat) {
|
||||
this.setState({
|
||||
cycleCount: this.state.cycleCount + 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { About as AboutComponent, AboutProps } from 'ts/pages/about/about';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { State } from 'ts/redux/reducer';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
|
||||
interface ConnectedState {
|
||||
translate: Translate;
|
||||
}
|
||||
|
||||
interface ConnectedDispatch {
|
||||
dispatcher: Dispatcher;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State, _ownProps: AboutProps): ConnectedState => ({
|
||||
translate: state.translate,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
|
||||
dispatcher: new Dispatcher(dispatch),
|
||||
});
|
||||
|
||||
export const About: React.ComponentClass<AboutProps> = connect(mapStateToProps, mapDispatchToProps)(AboutComponent);
|
||||
@@ -1,28 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { Jobs as JobsComponent, JobsProps } from 'ts/pages/jobs/jobs';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { State } from 'ts/redux/reducer';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
|
||||
interface ConnectedState {
|
||||
translate: Translate;
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
interface ConnectedDispatch {
|
||||
dispatcher: Dispatcher;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State, _ownProps: JobsProps): ConnectedState => ({
|
||||
translate: state.translate,
|
||||
screenWidth: state.screenWidth,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
|
||||
dispatcher: new Dispatcher(dispatch),
|
||||
});
|
||||
|
||||
export const Jobs: React.ComponentClass<JobsProps> = connect(mapStateToProps, mapDispatchToProps)(JobsComponent);
|
||||
@@ -1,27 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { Landing as LandingComponent, LandingProps } from 'ts/pages/landing/landing';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { State } from 'ts/redux/reducer';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
|
||||
interface ConnectedState {
|
||||
translate: Translate;
|
||||
}
|
||||
|
||||
interface ConnectedDispatch {
|
||||
dispatcher: Dispatcher;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State, _ownProps: LandingProps): ConnectedState => ({
|
||||
translate: state.translate,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
|
||||
dispatcher: new Dispatcher(dispatch),
|
||||
});
|
||||
|
||||
export const Landing: React.ComponentClass<LandingProps> = connect(mapStateToProps, mapDispatchToProps)(
|
||||
LandingComponent,
|
||||
);
|
||||
@@ -1,27 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { LaunchKit as LaunchKitComponent, LaunchKitProps } from 'ts/pages/launch_kit/launch_kit';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { State } from 'ts/redux/reducer';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
|
||||
interface ConnectedState {
|
||||
translate: Translate;
|
||||
}
|
||||
|
||||
interface ConnectedDispatch {
|
||||
dispatcher: Dispatcher;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State, _ownProps: LaunchKitProps): ConnectedState => ({
|
||||
translate: state.translate,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
|
||||
dispatcher: new Dispatcher(dispatch),
|
||||
});
|
||||
|
||||
export const LaunchKit: React.ComponentClass<LaunchKitProps> = connect(mapStateToProps, mapDispatchToProps)(
|
||||
LaunchKitComponent,
|
||||
);
|
||||
1
packages/website/ts/icons/form-arrow.svg
generated
1
packages/website/ts/icons/form-arrow.svg
generated
@@ -1 +0,0 @@
|
||||
<svg 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"/></svg>
|
||||
|
Before Width: | Height: | Size: 198 B |
@@ -1,421 +0,0 @@
|
||||
import { colors, Link, Styles } from '@0x/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import * as DocumentTitle from 'react-document-title';
|
||||
import { Footer } from 'ts/components/old_footer';
|
||||
import { TopBar } from 'ts/components/top_bar/top_bar';
|
||||
import { Profile } from 'ts/pages/about/profile';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { ProfileInfo, WebsitePaths } from 'ts/types';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
const teamRow1: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Will Warren',
|
||||
title: 'Co-founder & CEO',
|
||||
description: `Smart contract R&D. Previously applied physics at Los Alamos \
|
||||
Nat Lab. Mechanical engineering at UC San Diego. PhD dropout.`,
|
||||
image: '/images/team/will.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/will-warren-92aab62b/',
|
||||
github: 'https://github.com/willwarren89',
|
||||
medium: 'https://medium.com/@willwarren89',
|
||||
},
|
||||
{
|
||||
name: 'Amir Bandeali',
|
||||
title: 'Co-founder & CTO',
|
||||
description: `Smart contract R&D. Previously fixed income trader at DRW. \
|
||||
Finance at University of Illinois, Urbana-Champaign.`,
|
||||
image: '/images/team/amir.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/abandeali1/',
|
||||
github: 'https://github.com/abandeali1',
|
||||
medium: 'https://medium.com/@abandeali1',
|
||||
},
|
||||
{
|
||||
name: 'Fabio Berger',
|
||||
title: 'Senior Engineer',
|
||||
description: `Full-stack blockchain engineer. Previously software engineer \
|
||||
at Airtable and founder of WealthLift. Computer Science at Duke.`,
|
||||
image: '/images/team/fabio.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/fabio-berger-03ab261a/',
|
||||
github: 'https://github.com/fabioberger',
|
||||
medium: 'https://medium.com/@fabioberger',
|
||||
},
|
||||
];
|
||||
|
||||
const teamRow2: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Alex Xu',
|
||||
title: 'Director of Operations',
|
||||
description: `Strategy and operations. Previously digital marketing at Google \
|
||||
and vendor management at Amazon. Economics at UC San Diego.`,
|
||||
image: '/images/team/alex.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/alex-xu/',
|
||||
github: '',
|
||||
medium: 'https://medium.com/@aqxu',
|
||||
},
|
||||
{
|
||||
name: 'Leonid Logvinov',
|
||||
title: 'Engineer',
|
||||
description: `Full-stack blockchain engineer. Previously blockchain engineer \
|
||||
at Neufund. Computer Science at University of Warsaw.`,
|
||||
image: '/images/team/leonid.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/leonidlogvinov/',
|
||||
github: 'https://github.com/LogvinovLeon',
|
||||
medium: 'https://medium.com/@Logvinov',
|
||||
},
|
||||
{
|
||||
name: 'Ben Burns',
|
||||
title: 'Designer',
|
||||
description: `Product, motion, and graphic designer. Previously designer \
|
||||
at Airtable and Apple. Digital Design at University of Cincinnati.`,
|
||||
image: '/images/team/ben.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/ben-burns-30170478/',
|
||||
github: '',
|
||||
medium: '',
|
||||
},
|
||||
];
|
||||
|
||||
const teamRow3: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Brandon Millman',
|
||||
title: 'Senior Engineer',
|
||||
description: `Full-stack engineer. Previously senior software engineer at \
|
||||
Twitter. Computer Science and Electrical Engineering at Duke.`,
|
||||
image: '/images/team/brandon.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/brandon-millman-b093a022/',
|
||||
github: 'https://github.com/BMillman19',
|
||||
medium: 'https://medium.com/@bchillman',
|
||||
},
|
||||
{
|
||||
name: 'Tom Schmidt',
|
||||
title: 'Product Manager',
|
||||
description: `Previously engineering at Apple, product management at Facebook and Instagram. Computer Science at Stanford.`,
|
||||
image: '/images/team/tom.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/tomhschmidt/',
|
||||
github: 'https://github.com/tomhschmidt',
|
||||
medium: '',
|
||||
},
|
||||
{
|
||||
name: 'Jacob Evans',
|
||||
title: 'Ecosystem Engineer',
|
||||
description: `Previously software engineer at Qantas and RSA Security.`,
|
||||
image: '/images/team/jacob.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/dekzter/',
|
||||
github: 'https://github.com/dekz',
|
||||
medium: '',
|
||||
},
|
||||
];
|
||||
|
||||
const teamRow4: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Blake Henderson',
|
||||
title: 'Operations Associate',
|
||||
description: `Operations and Analytics. Previously analytics at LinkedIn. Economics at UC San Diego.`,
|
||||
image: '/images/team/blake.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/blakerhenderson/',
|
||||
github: '',
|
||||
medium: '',
|
||||
},
|
||||
{
|
||||
name: 'Zack Skelly',
|
||||
title: 'Lead Recruiter',
|
||||
description: `Talent. Previously first recruiter at Heap, recruiting at Dropbox and Google. English Rhetoric and Composition at Pepperdine.`,
|
||||
image: '/images/team/zach.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/zackaryskelly/',
|
||||
github: '',
|
||||
medium: '',
|
||||
},
|
||||
{
|
||||
name: 'Greg Hysen',
|
||||
title: 'Blockchain Engineer',
|
||||
description: `Smart contract R&D. Previously lead distributed systems engineer at Hivemapper. Computer Science at University of Waterloo.`,
|
||||
image: '/images/team/greg.jpeg',
|
||||
linkedIn: 'https://www.linkedin.com/in/gregory-hysen-71741463/',
|
||||
github: 'https://github.com/hysz',
|
||||
medium: '',
|
||||
},
|
||||
];
|
||||
|
||||
const teamRow5: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Remco Bloemen',
|
||||
title: 'Technical Fellow',
|
||||
description: `Previously cofounder at Neufund and Coblue. Part III at Cambridge. PhD dropout at Twente Business School.`,
|
||||
image: '/images/team/remco.jpeg',
|
||||
linkedIn: 'https://www.linkedin.com/in/remcobloemen/',
|
||||
github: 'http://github.com/recmo',
|
||||
medium: '',
|
||||
},
|
||||
{
|
||||
name: 'Francesco Agosti',
|
||||
title: 'Engineer',
|
||||
description: `Full-stack engineer. Previously senior software engineer at Yelp. Computer Science at Duke.`,
|
||||
image: 'images/team/fragosti.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/fragosti/',
|
||||
github: 'http://github.com/fragosti',
|
||||
},
|
||||
{
|
||||
name: 'Mel Oberto',
|
||||
title: 'Office Ops / Executive Assistant',
|
||||
description: `Daily Operations. Previously People Operations Associate at Heap. Marketing and MBA at Sacred Heart University.`,
|
||||
image: 'images/team/mel.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/melanieoberto',
|
||||
},
|
||||
];
|
||||
|
||||
const teamRow6: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Alex Browne',
|
||||
title: 'Engineer in Residence',
|
||||
description: `Full-stack blockchain engineer. Previously at Plaid. Open source guru and footgun dismantler. Computer Science and Electrical Engineering at Duke.`,
|
||||
image: 'images/team/alexbrowne.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/stephenalexbrowne/',
|
||||
github: 'http://github.com/albrow',
|
||||
},
|
||||
{
|
||||
name: 'Peter Zeitz',
|
||||
title: 'Research Fellow',
|
||||
description: `Researching decentralized governance. Previously Assistant Professor of Economics at National University of Singapore Business School. PhD in Economics at UCLA.`,
|
||||
image: 'images/team/peter.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/peter-z-7b9595163/',
|
||||
},
|
||||
{
|
||||
name: 'Chris Kalani',
|
||||
title: 'Director of Design',
|
||||
description: `Previously founded Wake (acquired by InVision). Early Facebook product designer.`,
|
||||
image: 'images/team/chris.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/chriskalani/',
|
||||
github: 'https://github.com/chriskalani',
|
||||
},
|
||||
];
|
||||
|
||||
const teamRow7: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Clay Robbins',
|
||||
title: 'Ecosystem Development Lead',
|
||||
description: `Growth & Business Development. Previously product and partnerships at Square. Economics at Dartmouth College.`,
|
||||
image: 'images/team/clay.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/robbinsclay/',
|
||||
},
|
||||
{
|
||||
name: 'Matt Taylor',
|
||||
title: 'Marketing Lead',
|
||||
description: `Growth & Marketing. Previously marketing at Abra and Square. Economics and Philosophy at Claremont McKenna College.`,
|
||||
image: 'images/team/matt.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/mattytay/',
|
||||
},
|
||||
{
|
||||
name: 'Eugene Aumson',
|
||||
title: 'Engineer',
|
||||
description: `Developer Experience. Previously senior software engineer in foreign exchange applications at Bloomberg LP.`,
|
||||
image: 'images/team/gene.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/aumson/',
|
||||
github: 'https://github.com/feuGeneA',
|
||||
},
|
||||
];
|
||||
|
||||
const teamRow8: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Weijie Wu',
|
||||
title: 'Research Fellow',
|
||||
description: `Researching decentralized governance. Previously Researcher at Huawei and Assistant Professor at Shanghai Jiao Tong University. PhD in Computer Science at The Chinese University of Hong Kong.`,
|
||||
image: 'images/team/weijie.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/weijiewu/',
|
||||
},
|
||||
{
|
||||
name: 'Rahul Singireddy',
|
||||
title: 'Relayer Success Manager',
|
||||
description: `Previously community at Zeppelin, growth at Dharma, and cryptocurrency contributor at Forbes. Symbolic Systems at Stanford.`,
|
||||
image: 'images/team/rahul.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/rahul-singireddy-3037908a/',
|
||||
},
|
||||
{
|
||||
name: 'Jason Somensatto',
|
||||
title: 'Strategic Legal Counsel',
|
||||
description: `Legal. Previously head of blockchain and crypto practice at Orrick. JD from George Washington University and undergrad at UVA.`,
|
||||
image: 'images/team/jason.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/jasonsomensatto/',
|
||||
},
|
||||
];
|
||||
|
||||
const teamRow9: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Steve Klebanoff',
|
||||
title: 'Senior Engineer',
|
||||
description: ` Full-stack engineer. Previously Staff Software Engineer at AppFolio. Computer Science & Cognitive Psychology at Northeastern University.`,
|
||||
image: 'images/team/steve.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/steveklebanoff/',
|
||||
github: 'https://github.com/steveklebanoff',
|
||||
},
|
||||
{
|
||||
name: 'Xianny Ng',
|
||||
title: 'Engineer',
|
||||
description: `Developer Experience. Previously telemetry at Mapbox and platform engineering at Bench Accounting.`,
|
||||
image: 'images/team/xianny.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/xianny/',
|
||||
github: 'https://github.com/xianny',
|
||||
},
|
||||
];
|
||||
|
||||
const advisors1: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Fred Ehrsam',
|
||||
description: 'Co-founder of Coinbase. Previously FX trader at Goldman Sachs.',
|
||||
image: '/images/advisors/fred.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/fredehrsam/',
|
||||
medium: 'https://medium.com/@FEhrsam',
|
||||
twitter: 'https://twitter.com/FEhrsam',
|
||||
},
|
||||
{
|
||||
name: 'Olaf Carlson-Wee',
|
||||
image: '/images/advisors/olaf.png',
|
||||
description: 'Founder of Polychain Capital. First hire at Coinbase. Angel investor.',
|
||||
linkedIn: 'https://www.linkedin.com/in/olafcw/',
|
||||
angellist: 'https://angel.co/olafcw',
|
||||
},
|
||||
{
|
||||
name: 'Joey Krug',
|
||||
description: `Co-CIO at Pantera Capital. Founder of Augur. Thiel 20 Under 20 Fellow.`,
|
||||
image: '/images/advisors/joey.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/joeykrug/',
|
||||
github: 'https://github.com/joeykrug',
|
||||
angellist: 'https://angel.co/joeykrug',
|
||||
},
|
||||
];
|
||||
|
||||
const advisors2: ProfileInfo[] = [
|
||||
{
|
||||
name: 'Linda Xie',
|
||||
description: 'Co-founder of Scalar Capital. Previously PM at Coinbase.',
|
||||
image: '/images/advisors/linda.jpg',
|
||||
linkedIn: 'https://www.linkedin.com/in/lindaxie/',
|
||||
medium: 'https://medium.com/@linda.xie',
|
||||
twitter: 'https://twitter.com/ljxie',
|
||||
},
|
||||
{
|
||||
name: 'David Sacks',
|
||||
description: 'General Partner at Craft Ventures. Original COO of PayPal. Founder of Yammer.',
|
||||
image: '/images/advisors/david.png',
|
||||
linkedIn: 'https://www.linkedin.com/in/davidoliversacks/',
|
||||
medium: 'https://medium.com/@davidsacks',
|
||||
twitter: 'https://twitter.com/DavidSacks',
|
||||
},
|
||||
];
|
||||
|
||||
export interface AboutProps {
|
||||
source: string;
|
||||
location: Location;
|
||||
translate: Translate;
|
||||
dispatcher: Dispatcher;
|
||||
}
|
||||
|
||||
interface AboutState {}
|
||||
|
||||
const styles: Styles = {
|
||||
header: {
|
||||
fontFamily: 'Roboto Mono',
|
||||
fontSize: 36,
|
||||
color: 'black',
|
||||
paddingTop: 110,
|
||||
},
|
||||
weAreHiring: {
|
||||
fontSize: 30,
|
||||
color: colors.darkestGrey,
|
||||
fontFamily: 'Roboto Mono',
|
||||
letterSpacing: 7.5,
|
||||
},
|
||||
};
|
||||
|
||||
export class About extends React.Component<AboutProps, AboutState> {
|
||||
public componentDidMount(): void {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<div style={{ backgroundColor: colors.lightestGrey }}>
|
||||
<DocumentTitle title="0x About Us" />
|
||||
<TopBar
|
||||
blockchainIsLoaded={false}
|
||||
location={this.props.location}
|
||||
style={{ backgroundColor: colors.lightestGrey }}
|
||||
translate={this.props.translate}
|
||||
/>
|
||||
<div id="about" className="mx-auto max-width-4 py4" style={{ color: colors.grey800 }}>
|
||||
<div className="mx-auto pb4 sm-px3" style={{ maxWidth: 435 }}>
|
||||
<div style={styles.header}>About us:</div>
|
||||
<div
|
||||
className="pt3"
|
||||
style={{
|
||||
fontSize: 17,
|
||||
color: colors.darkestGrey,
|
||||
lineHeight: 1.5,
|
||||
}}
|
||||
>
|
||||
Our team is a globally distributed group with backgrounds in engineering, research, business
|
||||
and design. We are passionate about decentralized technology and its potential to act as an
|
||||
equalizing force in the world.
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt3 md-px4 lg-px0">
|
||||
<div className="clearfix pb3">{this._renderProfiles(teamRow1)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(teamRow2)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(teamRow3)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(teamRow4)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(teamRow5)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(teamRow6)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(teamRow7)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(teamRow8)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(teamRow9)}</div>
|
||||
</div>
|
||||
<div className="pt3 pb2">
|
||||
<div
|
||||
className="pt2 pb3 sm-center md-pl4 lg-pl0 md-ml3"
|
||||
style={{
|
||||
color: colors.grey,
|
||||
fontSize: 24,
|
||||
fontFamily: 'Roboto Mono',
|
||||
}}
|
||||
>
|
||||
Advisors:
|
||||
</div>
|
||||
<div className="clearfix">{this._renderProfiles(advisors1)}</div>
|
||||
<div className="clearfix">{this._renderProfiles(advisors2)}</div>
|
||||
</div>
|
||||
<div className="mx-auto py4 sm-px3" style={{ maxWidth: 308 }}>
|
||||
<div className="pb2" style={styles.weAreHiring}>
|
||||
WE'RE HIRING
|
||||
</div>
|
||||
<div
|
||||
className="pb4 mb4"
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: colors.darkestGrey,
|
||||
lineHeight: 1.5,
|
||||
letterSpacing: '0.5px',
|
||||
}}
|
||||
>
|
||||
We are seeking outstanding candidates to{' '}
|
||||
<Link to={WebsitePaths.Careers} textDecoration="underline" fontColor="black">
|
||||
join our team
|
||||
</Link>
|
||||
. We value passion, diversity and unique perspectives.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderProfiles(profiles: ProfileInfo[]): React.ReactNode {
|
||||
const numIndiv = profiles.length;
|
||||
const colSize = utils.getColSize(numIndiv);
|
||||
return _.map(profiles, profile => {
|
||||
return (
|
||||
<div key={`profile-${profile.name}`}>
|
||||
<Profile colSize={colSize} profileInfo={profile} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import { colors, Styles } from '@0x/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import { ProfileInfo } from 'ts/types';
|
||||
|
||||
const IMAGE_DIMENSION = 149;
|
||||
const styles: Styles = {
|
||||
subheader: {
|
||||
textTransform: 'uppercase',
|
||||
fontSize: 32,
|
||||
margin: 0,
|
||||
},
|
||||
imageContainer: {
|
||||
width: IMAGE_DIMENSION,
|
||||
height: IMAGE_DIMENSION,
|
||||
boxShadow: 'rgba(0, 0, 0, 0.19) 2px 5px 10px',
|
||||
},
|
||||
};
|
||||
|
||||
interface ProfileProps {
|
||||
colSize: number;
|
||||
profileInfo: ProfileInfo;
|
||||
}
|
||||
|
||||
export const Profile = (props: ProfileProps) => {
|
||||
return (
|
||||
<div className={`lg-col md-col lg-col-${props.colSize} md-col-6`}>
|
||||
<div style={{ maxWidth: 300 }} className="mx-auto lg-px3 md-px3 sm-px4 sm-pb3">
|
||||
<div className="circle overflow-hidden mx-auto" style={styles.imageContainer}>
|
||||
<img width={IMAGE_DIMENSION} src={props.profileInfo.image} />
|
||||
</div>
|
||||
<div className="center" style={{ fontSize: 18, fontWeight: 'bold', paddingTop: 20 }}>
|
||||
{props.profileInfo.name}
|
||||
</div>
|
||||
{!_.isUndefined(props.profileInfo.title) && (
|
||||
<div
|
||||
className="pt1 center"
|
||||
style={{
|
||||
fontSize: 14,
|
||||
fontFamily: 'Roboto Mono',
|
||||
color: colors.darkGrey,
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{props.profileInfo.title.toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<div style={{ minHeight: 60, lineHeight: 1.4 }} className="pt1 pb2 mx-auto lg-h6 md-h6 sm-h5 sm-center">
|
||||
{props.profileInfo.description}
|
||||
</div>
|
||||
<div className="flex pb3 sm-hide xs-hide" style={{ width: 280, opacity: 0.5 }}>
|
||||
{renderSocialMediaIcons(props.profileInfo)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function renderSocialMediaIcons(profileInfo: ProfileInfo): React.ReactNode {
|
||||
const icons = [
|
||||
renderSocialMediaIcon('zmdi-github-box', profileInfo.github),
|
||||
renderSocialMediaIcon('zmdi-linkedin-box', profileInfo.linkedIn),
|
||||
renderSocialMediaIcon('zmdi-twitter-box', profileInfo.twitter),
|
||||
];
|
||||
return icons;
|
||||
}
|
||||
|
||||
function renderSocialMediaIcon(iconName: string, url: string): React.ReactNode {
|
||||
if (_.isEmpty(url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={url} className="pr1">
|
||||
<a href={url} style={{ color: 'inherit' }} target="_blank" className="text-decoration-none">
|
||||
<i className={`zmdi ${iconName}`} style={{ ...styles.socalIcon }} />
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Button } from 'ts/components/ui/button';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
|
||||
export interface Introducing0xInstantProps {
|
||||
screenWidth: ScreenWidths;
|
||||
onCTAClick: () => void;
|
||||
}
|
||||
|
||||
export const Introducing0xInstant = (props: Introducing0xInstantProps) => {
|
||||
const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
|
||||
const zero = (
|
||||
<Text fontColor={colors.white} fontSize="42px" fontWeight="600" fontFamily="Roboto Mono" Tag="span">
|
||||
0
|
||||
</Text>
|
||||
);
|
||||
const title = isSmallScreen ? (
|
||||
<div>
|
||||
Introducing<br />
|
||||
{zero}x Instant
|
||||
</div>
|
||||
) : (
|
||||
<div>Introducing {zero}x Instant</div>
|
||||
);
|
||||
return (
|
||||
<div className="clearfix center lg-pt4 md-pt4" style={{ backgroundColor: colors.instantPrimaryBackground }}>
|
||||
<div className="mx-auto inline-block align-middle py4" style={{ lineHeight: '44px', textAlign: 'center' }}>
|
||||
<Container className="sm-center sm-pt3">
|
||||
<Text fontColor={colors.white} fontSize="42px" lineHeight="52px" fontWeight="600">
|
||||
{title}
|
||||
</Text>
|
||||
</Container>
|
||||
<Container className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 sm-center" maxWidth="600px">
|
||||
<Text fontColor={colors.grey500} fontSize="20px" lineHeight="32px" fontFamily="Roboto Mono">
|
||||
A free and flexible way to offer simple crypto
|
||||
<br /> purchasing in any app or website.
|
||||
</Text>
|
||||
</Container>
|
||||
<div className="py3">
|
||||
<Button
|
||||
type="button"
|
||||
backgroundColor={colors.mediumBlue}
|
||||
fontColor={colors.white}
|
||||
fontSize="18px"
|
||||
onClick={props.onCTAClick}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Button } from 'ts/components/ui/button';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { ScreenWidths, WebsitePaths } from 'ts/types';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
export interface NeedMoreProps {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
export const NeedMore = (props: NeedMoreProps) => {
|
||||
const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
|
||||
const backgroundColor = isSmallScreen ? colors.instantTertiaryBackground : colors.instantSecondaryBackground;
|
||||
const className = isSmallScreen ? 'flex flex-column items-center' : 'flex';
|
||||
const marginRight = isSmallScreen ? undefined : '200px';
|
||||
return (
|
||||
<Container className="flex flex-column items-center py4 px3" backgroundColor={backgroundColor}>
|
||||
<Container className={className}>
|
||||
<Container className="sm-center" marginRight={marginRight}>
|
||||
<Text fontColor={colors.white} fontSize="32px" lineHeight="45px">
|
||||
Need more flexibility?
|
||||
</Text>
|
||||
<Text fontColor={colors.grey500} fontSize="18px" lineHeight="27px">
|
||||
View our full documentation or reach out if you have any questions.
|
||||
</Text>
|
||||
</Container>
|
||||
<Container className="py3 flex">
|
||||
<Container marginRight="20px">
|
||||
<Button
|
||||
type="button"
|
||||
backgroundColor={colors.white}
|
||||
fontColor={backgroundColor}
|
||||
fontSize="18px"
|
||||
onClick={onGetInTouchClick}
|
||||
>
|
||||
Get in Touch
|
||||
</Button>
|
||||
</Container>
|
||||
<Button
|
||||
type="button"
|
||||
backgroundColor={colors.mediumBlue}
|
||||
fontColor={colors.white}
|
||||
fontSize="18px"
|
||||
onClick={onDocsClick}
|
||||
>
|
||||
Explore the Docs
|
||||
</Button>
|
||||
</Container>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
const onGetInTouchClick = () => {
|
||||
utils.openUrl(constants.URL_ZEROEX_CHAT);
|
||||
};
|
||||
const onDocsClick = () => {
|
||||
utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`);
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
|
||||
export interface ScreenshotsProps {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
export const Screenshots = (props: ScreenshotsProps) => {
|
||||
const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
|
||||
const images = isSmallScreen
|
||||
? [
|
||||
'images/instant/rep_screenshot.png',
|
||||
'images/instant/dai_screenshot.png',
|
||||
'images/instant/gods_screenshot.png',
|
||||
]
|
||||
: [
|
||||
'images/instant/nmr_screenshot.png',
|
||||
'images/instant/kitty_screenshot.png',
|
||||
'images/instant/rep_screenshot.png',
|
||||
'images/instant/dai_screenshot.png',
|
||||
'images/instant/gods_screenshot.png',
|
||||
'images/instant/gnt_screenshot.png',
|
||||
];
|
||||
return (
|
||||
<Container backgroundColor={colors.instantPrimaryBackground} className="py3 flex justify-center">
|
||||
{_.map(images, image => {
|
||||
return <img className="px1 flex-none" width="300px" height="420px" src={image} key={image} />;
|
||||
})}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
@@ -1,158 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Circle } from 'ts/components/ui/circle';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Image } from 'ts/components/ui/image';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { styled } from 'ts/style/theme';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
|
||||
const BENEFITS = [
|
||||
'Comprehensive insurance (medical, dental, and vision)',
|
||||
'Unlimited vacation (three weeks per year minimum)',
|
||||
'Meals and snacks provided in-office daily',
|
||||
'Flexible hours and liberal work-from-home-policy',
|
||||
'Supportive remote working environment',
|
||||
'Transportation, phone, and wellness expense',
|
||||
'Relocation assistance',
|
||||
'Optional team excursions (fully paid, often international)',
|
||||
'Competitive salary and cryptocurrency-based compensation',
|
||||
];
|
||||
|
||||
interface Value {
|
||||
iconSrc: string;
|
||||
text: string;
|
||||
}
|
||||
const VALUES: Value[] = [
|
||||
{
|
||||
iconSrc: 'images/jobs/heart-icon.svg',
|
||||
text: 'Do the right thing',
|
||||
},
|
||||
{
|
||||
iconSrc: 'images/jobs/ship-icon.svg',
|
||||
text: 'Consistently ship',
|
||||
},
|
||||
{
|
||||
iconSrc: 'images/jobs/calendar-icon.svg',
|
||||
text: 'Focus on long term impact',
|
||||
},
|
||||
];
|
||||
|
||||
export interface BenefitsProps {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
export const Benefits = (props: BenefitsProps) => {
|
||||
const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
|
||||
return (
|
||||
<Container className="flex flex-column items-center py4 px3" backgroundColor={colors.white}>
|
||||
{!isSmallScreen ? (
|
||||
<Container className="flex" maxWidth="1200px">
|
||||
<BenefitsList />
|
||||
<Container marginLeft="120px">
|
||||
<ValuesList />
|
||||
</Container>
|
||||
</Container>
|
||||
) : (
|
||||
<Container className="flex-column">
|
||||
<BenefitsList />
|
||||
<Container marginTop="50px">
|
||||
<ValuesList />
|
||||
</Container>
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
const Header: React.StatelessComponent = ({ children }) => (
|
||||
<Container marginBottom="30px">
|
||||
<Text fontFamily="Roboto Mono" fontSize="24px" fontColor={colors.black}>
|
||||
{children}
|
||||
</Text>
|
||||
</Container>
|
||||
);
|
||||
|
||||
interface BenefitsListProps {
|
||||
className?: string;
|
||||
}
|
||||
const PlainBenefitsList: React.StatelessComponent<BenefitsListProps> = ({ className }) => {
|
||||
return (
|
||||
<Container className={className}>
|
||||
<Header>Benefits</Header>
|
||||
{_.map(BENEFITS, benefit => <BenefitItem key={benefit} description={benefit} />)}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
const BenefitsList = styled(PlainBenefitsList)`
|
||||
transform: translateY(30px);
|
||||
`;
|
||||
|
||||
interface BenefitItemProps {
|
||||
description: string;
|
||||
}
|
||||
|
||||
const BenefitItem: React.StatelessComponent<BenefitItemProps> = ({ description }) => (
|
||||
<Container marginBottom="15px">
|
||||
<div className="flex">
|
||||
<Circle className="flex-none pr2 pt1" diameter={8} fillColor={colors.black} />
|
||||
<div className="flex-auto">
|
||||
<Text fontSize="14px" lineHeight="24px">
|
||||
{description}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
|
||||
interface ValuesListProps {
|
||||
className?: string;
|
||||
}
|
||||
const PlainValuesList: React.StatelessComponent<ValuesListProps> = ({ className }) => {
|
||||
return (
|
||||
<Container className={className} maxWidth="270px">
|
||||
<Header>Our Values</Header>
|
||||
{_.map(VALUES, value => <ValueItem key={value.text} {...value} />)}
|
||||
<Text fontSize="14px" lineHeight="26px">
|
||||
We care deeply about our culture and values, and encourage you to{' '}
|
||||
<a
|
||||
style={{ color: colors.mediumBlue, textDecoration: 'none' }}
|
||||
target="_blank"
|
||||
href={constants.URL_MISSION_AND_VALUES_BLOG_POST}
|
||||
>
|
||||
read more on our blog
|
||||
</a>.
|
||||
</Text>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
const ValuesList = styled(PlainValuesList)`
|
||||
border-color: ${colors.beigeWhite};
|
||||
border-radius: 7px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
padding-left: 38px;
|
||||
padding-right: 38px;
|
||||
padding-top: 28px;
|
||||
padding-bottom: 28px;
|
||||
`;
|
||||
|
||||
type ValueItemProps = Value;
|
||||
const ValueItem: React.StatelessComponent<ValueItemProps> = ({ iconSrc, text }) => {
|
||||
return (
|
||||
<Container marginBottom="25px">
|
||||
<div className="flex items-center">
|
||||
<Image className="flex-none pr2" width="20px" src={iconSrc} />
|
||||
<div className="flex-auto">
|
||||
<Text fontSize="14px" lineHeight="24px" fontWeight="bold">
|
||||
{text}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
@@ -1,71 +0,0 @@
|
||||
import { colors, utils as sharedUtils } from '@0x/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import * as DocumentTitle from 'react-document-title';
|
||||
|
||||
import { MetaTags } from 'ts/components/meta_tags';
|
||||
import { Footer } from 'ts/components/old_footer';
|
||||
import { TopBar } from 'ts/components/top_bar/top_bar';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Benefits } from 'ts/pages/jobs/benefits';
|
||||
import { Join0x } from 'ts/pages/jobs/join_0x';
|
||||
import { Mission } from 'ts/pages/jobs/mission';
|
||||
import { OpenPositions } from 'ts/pages/jobs/open_positions';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
const OPEN_POSITIONS_HASH = 'positions';
|
||||
const THROTTLE_TIMEOUT = 100;
|
||||
const DOCUMENT_TITLE = 'Careers at 0x';
|
||||
const DOCUMENT_DESCRIPTION = 'Join 0x in creating a tokenized world where all value can flow freely';
|
||||
|
||||
export interface JobsProps {
|
||||
location: Location;
|
||||
translate: Translate;
|
||||
dispatcher: Dispatcher;
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
export interface JobsState {}
|
||||
|
||||
export class Jobs extends React.Component<JobsProps, JobsState> {
|
||||
// TODO: consolidate this small screen scaffolding into one place (its being used in portal and docs as well)
|
||||
private readonly _throttledScreenWidthUpdate: () => void;
|
||||
public constructor(props: JobsProps) {
|
||||
super(props);
|
||||
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
||||
}
|
||||
public componentDidMount(): void {
|
||||
window.addEventListener('resize', this._throttledScreenWidthUpdate);
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<Container overflowX="hidden">
|
||||
<MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} />
|
||||
<DocumentTitle title={DOCUMENT_TITLE} />
|
||||
<TopBar
|
||||
blockchainIsLoaded={false}
|
||||
location={this.props.location}
|
||||
style={{ backgroundColor: colors.white, position: 'relative' }}
|
||||
translate={this.props.translate}
|
||||
/>
|
||||
<Join0x onCallToActionClick={this._onJoin0xCallToActionClick.bind(this)} />
|
||||
<Mission screenWidth={this.props.screenWidth} />
|
||||
<Benefits screenWidth={this.props.screenWidth} />
|
||||
<OpenPositions hash={OPEN_POSITIONS_HASH} screenWidth={this.props.screenWidth} />
|
||||
<Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private _onJoin0xCallToActionClick(): void {
|
||||
sharedUtils.setUrlHash(OPEN_POSITIONS_HASH);
|
||||
sharedUtils.scrollToHash(OPEN_POSITIONS_HASH, '');
|
||||
}
|
||||
private _updateScreenWidth(): void {
|
||||
const newScreenWidth = utils.getScreenWidth();
|
||||
this.props.dispatcher.updateScreenWidth(newScreenWidth);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { colors } from '@0x/react-shared';
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { Button } from 'ts/components/ui/button';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Image } from 'ts/components/ui/image';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
|
||||
const BUTTON_TEXT = 'View open positions';
|
||||
|
||||
export interface Join0xProps {
|
||||
onCallToActionClick: () => void;
|
||||
}
|
||||
|
||||
export const Join0x = (props: Join0xProps) => (
|
||||
<div className="clearfix center lg-py4 md-py4" style={{ backgroundColor: colors.white, color: colors.black }}>
|
||||
<div
|
||||
className="mx-auto inline-block align-middle py4"
|
||||
style={{ lineHeight: '44px', textAlign: 'center', position: 'relative' }}
|
||||
>
|
||||
<Container className="sm-hide xs-hide" position="absolute" left="100%" marginLeft="80px">
|
||||
<Image src="images/jobs/hero-dots-right.svg" width="400px" />
|
||||
</Container>
|
||||
<Container className="sm-hide xs-hide" position="absolute" right="100%" marginRight="80px">
|
||||
<Image src="images/jobs/hero-dots-left.svg" width="400px" />
|
||||
</Container>
|
||||
<div className="h2 sm-center sm-pt3" style={{ fontFamily: 'Roboto Mono' }}>
|
||||
Join Us in Our Mission
|
||||
</div>
|
||||
<Container className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 sm-center" maxWidth="537px">
|
||||
<Text fontSize="14px" lineHeight="30px">
|
||||
At 0x, our mission is to create a tokenized world where all value can flow freely.
|
||||
<br />
|
||||
<br />We are powering a growing ecosystem of decentralized applications and solving novel challenges
|
||||
to make our technology intuitive, flexible, and accessible to all.{' '}
|
||||
<a
|
||||
style={{ color: colors.mediumBlue, textDecoration: 'none' }}
|
||||
target="_blank"
|
||||
href={constants.URL_MISSION_AND_VALUES_BLOG_POST}
|
||||
>
|
||||
Read more
|
||||
</a>{' '}
|
||||
about our mission, and join us in building financial infrastructure upon which the exchange of
|
||||
anything of value will take place.
|
||||
</Text>
|
||||
</Container>
|
||||
<div className="py3">
|
||||
<Button
|
||||
type="button"
|
||||
backgroundColor={colors.black}
|
||||
width="290px"
|
||||
fontColor={colors.white}
|
||||
fontSize="18px"
|
||||
fontFamily="Roboto Mono"
|
||||
onClick={props.onCallToActionClick}
|
||||
>
|
||||
{BUTTON_TEXT}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -1,47 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Image } from 'ts/components/ui/image';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
|
||||
export interface MissionProps {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
export const Mission = (props: MissionProps) => {
|
||||
const shouldShowImage = props.screenWidth === ScreenWidths.Lg;
|
||||
const image = <Image src="/images/jobs/world-map.svg" maxWidth="500px" maxHeight="280px" />;
|
||||
const missionStatementClassName = !shouldShowImage ? 'center' : undefined;
|
||||
const missionStatement = (
|
||||
<Container className={missionStatementClassName} maxWidth="388px">
|
||||
<Text fontFamily="Roboto Mono" fontSize="22px" lineHeight="31px">
|
||||
Powered by a Diverse<br />Worldwide Community
|
||||
</Text>
|
||||
<Container marginTop="32px">
|
||||
<Text fontSize="14px" lineHeight="2em">
|
||||
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 globally. We're passionate about
|
||||
open-source software and decentralized technology's potential to act as an equalizing force in the
|
||||
world.
|
||||
</Text>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
return (
|
||||
<div
|
||||
className="flex flex-column items-center py4 px3"
|
||||
style={{ backgroundColor: colors.jobsPageBackground, color: colors.black }}
|
||||
>
|
||||
{shouldShowImage ? (
|
||||
<Container className="flex items-center" maxWidth="1200px">
|
||||
{image}
|
||||
<Container marginLeft="115px">{missionStatement}</Container>
|
||||
</Container>
|
||||
) : (
|
||||
<Container className="flex flex-column items-center">{missionStatement}</Container>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,179 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import CircularProgress from 'material-ui/CircularProgress';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Retry } from 'ts/components/ui/retry';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { styled } from 'ts/style/theme';
|
||||
import { ScreenWidths, WebsiteBackendJobInfo } from 'ts/types';
|
||||
import { backendClient } from 'ts/utils/backend_client';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
const TABLE_ROW_MIN_HEIGHT = 100;
|
||||
|
||||
export interface OpenPositionsProps {
|
||||
hash: string;
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
export interface OpenPositionsState {
|
||||
jobInfos?: WebsiteBackendJobInfo[];
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
export class OpenPositions extends React.Component<OpenPositionsProps, OpenPositionsState> {
|
||||
private _isUnmounted: boolean;
|
||||
constructor(props: OpenPositionsProps) {
|
||||
super(props);
|
||||
this._isUnmounted = false;
|
||||
this.state = {
|
||||
jobInfos: undefined,
|
||||
error: undefined,
|
||||
};
|
||||
}
|
||||
public componentWillMount(): void {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this._fetchJobInfosAsync();
|
||||
}
|
||||
public componentWillUnmount(): void {
|
||||
this._isUnmounted = true;
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.jobInfos);
|
||||
const isSmallScreen = utils.isMobileWidth(this.props.screenWidth);
|
||||
return (
|
||||
<Container id={this.props.hash} className="mx-auto pb4 px3 max-width-4">
|
||||
{!isSmallScreen && (
|
||||
<hr style={{ border: 0, borderTop: 1, borderStyle: 'solid', borderColor: colors.beigeWhite }} />
|
||||
)}
|
||||
<Container marginTop="64px" marginBottom="50px">
|
||||
<Text fontFamily="Roboto Mono" fontSize="24px" fontColor={colors.black}>
|
||||
Open Positions
|
||||
</Text>
|
||||
</Container>
|
||||
{isReadyToRender ? this._renderTable() : this._renderLoading()}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private _renderLoading(): React.ReactNode {
|
||||
return (
|
||||
// TODO: consolidate this loading component with the one in portal and RelayerIndex
|
||||
// TODO: possibly refactor into a generic loading container with spinner and retry UI
|
||||
<div className="center">
|
||||
{_.isUndefined(this.state.error) ? (
|
||||
<CircularProgress size={40} thickness={5} />
|
||||
) : (
|
||||
<Retry onRetry={this._fetchJobInfosAsync.bind(this)} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderTable(): React.ReactNode {
|
||||
return (
|
||||
<Container width="100%">
|
||||
<div>
|
||||
{_.map(this.state.jobInfos, jobInfo => {
|
||||
return (
|
||||
<JobInfoTableRow
|
||||
key={jobInfo.id}
|
||||
screenWidth={this.props.screenWidth}
|
||||
jobInfo={jobInfo}
|
||||
onClick={this._openJobInfoUrl.bind(this, jobInfo)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Container className="center" marginTop="70px">
|
||||
<Text fontStyle="italic" fontSize="14px">
|
||||
Interested in telling us why you'd be a valuable addition to the team outside of the positions
|
||||
listed above?{' '}
|
||||
<a
|
||||
style={{ color: colors.mediumBlue, textDecoration: 'none' }}
|
||||
href={`mailto:${constants.EMAIL_JOBS}`}
|
||||
>
|
||||
Email us!
|
||||
</a>
|
||||
</Text>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private async _fetchJobInfosAsync(): Promise<void> {
|
||||
try {
|
||||
if (!this._isUnmounted) {
|
||||
this.setState({
|
||||
jobInfos: undefined,
|
||||
error: undefined,
|
||||
});
|
||||
}
|
||||
const jobInfos = await backendClient.getJobInfosAsync();
|
||||
if (!this._isUnmounted) {
|
||||
this.setState({
|
||||
jobInfos,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
if (!this._isUnmounted) {
|
||||
this.setState({
|
||||
error,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
private _openJobInfoUrl(jobInfo: WebsiteBackendJobInfo): void {
|
||||
const url = jobInfo.url;
|
||||
utils.openUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
export interface JobInfoTableRowProps {
|
||||
className?: string;
|
||||
screenWidth: ScreenWidths;
|
||||
jobInfo: WebsiteBackendJobInfo;
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
}
|
||||
|
||||
const PlainJobInfoTableRow: React.StatelessComponent<JobInfoTableRowProps> = ({
|
||||
className,
|
||||
screenWidth,
|
||||
jobInfo,
|
||||
onClick,
|
||||
}) => {
|
||||
const isSmallScreen = screenWidth === ScreenWidths.Sm;
|
||||
const titleClassName = isSmallScreen ? 'col col-12 center' : 'col col-5';
|
||||
const paddingLeft = isSmallScreen ? undefined : '30px';
|
||||
return (
|
||||
<Container className={className} onClick={onClick} marginBottom="30px" paddingLeft={paddingLeft}>
|
||||
<Container className="flex items-center" minHeight={TABLE_ROW_MIN_HEIGHT} width="100%">
|
||||
<Container className="clearfix container" width="100%">
|
||||
<Container className={titleClassName}>
|
||||
<Text fontSize="16px" fontWeight="bold" fontColor={colors.mediumBlue}>
|
||||
{jobInfo.title}
|
||||
</Text>
|
||||
</Container>
|
||||
{!isSmallScreen && (
|
||||
<Container className="col col-3">
|
||||
<Text fontSize="16px">{jobInfo.department}</Text>
|
||||
</Container>
|
||||
)}
|
||||
{!isSmallScreen && (
|
||||
<Container className="col col-4 center">
|
||||
<Text fontSize="16px">{jobInfo.office}</Text>
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export const JobInfoTableRow = styled(PlainJobInfoTableRow)`
|
||||
cursor: pointer;
|
||||
background-color: ${colors.grey100};
|
||||
border-radius: 7px;
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
`;
|
||||
@@ -1,22 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { FilledImage } from 'ts/components/ui/filled_image';
|
||||
|
||||
export interface PhotoRailProps {
|
||||
images: string[];
|
||||
}
|
||||
|
||||
export const PhotoRail = (props: PhotoRailProps) => {
|
||||
return (
|
||||
<div className="clearfix" style={{ height: 490 }}>
|
||||
{_.map(props.images, (image: string) => {
|
||||
return (
|
||||
<div key={image} className="col lg-col-4 md-col-4 col-12 center" style={{ height: '100%' }}>
|
||||
<FilledImage src={image} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,620 +0,0 @@
|
||||
import { colors, Link } from '@0x/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import DocumentTitle from 'react-document-title';
|
||||
import { SubscribeForm } from 'ts/components/forms/subscribe_form';
|
||||
import { Footer } from 'ts/components/old_footer';
|
||||
import { TopBar } from 'ts/components/top_bar/top_bar';
|
||||
import { CallToAction } from 'ts/components/ui/button';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Image } from 'ts/components/ui/image';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { TypedText } from 'ts/components/ui/typed_text';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { Deco, Key, Language, ScreenWidths, WebsitePaths } from 'ts/types';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
interface BoxContent {
|
||||
title: string;
|
||||
description: string;
|
||||
imageUrl: string;
|
||||
classNames: string;
|
||||
maxWidth: number;
|
||||
}
|
||||
interface UseCase {
|
||||
imageUrl: string;
|
||||
type: string;
|
||||
description: string;
|
||||
classNames: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
interface Project {
|
||||
logoFileName: string;
|
||||
projectUrl: string;
|
||||
}
|
||||
|
||||
const THROTTLE_TIMEOUT = 100;
|
||||
const WHATS_NEW_TITLE = 'Introducing 0x Instant';
|
||||
const WHATS_NEW_URL = WebsitePaths.Instant;
|
||||
const TITLE_STYLE: React.CSSProperties = {
|
||||
fontFamily: 'Roboto Mono',
|
||||
color: colors.grey,
|
||||
fontWeight: 300,
|
||||
letterSpacing: 3,
|
||||
};
|
||||
const ROTATING_LIST = [
|
||||
'tokens',
|
||||
'game items',
|
||||
'digital art',
|
||||
'futures',
|
||||
'stocks',
|
||||
'derivatives',
|
||||
'loans',
|
||||
'cats',
|
||||
'everything',
|
||||
];
|
||||
|
||||
const relayerProjects: Project[] = [
|
||||
{
|
||||
logoFileName: 'ethfinex.png',
|
||||
projectUrl: constants.PROJECT_URL_ETHFINEX,
|
||||
},
|
||||
{
|
||||
logoFileName: 'radar_relay.png',
|
||||
projectUrl: constants.PROJECT_URL_RADAR_RELAY,
|
||||
},
|
||||
{
|
||||
logoFileName: 'paradex.png',
|
||||
projectUrl: constants.PROJECT_URL_PARADEX,
|
||||
},
|
||||
{
|
||||
logoFileName: 'the_ocean.png',
|
||||
projectUrl: constants.PROJECT_URL_0CEAN,
|
||||
},
|
||||
{
|
||||
logoFileName: 'amadeus.png',
|
||||
projectUrl: constants.PROJECT_URL_AMADEUS,
|
||||
},
|
||||
{
|
||||
logoFileName: 'ddex.png',
|
||||
projectUrl: constants.PROJECT_URL_DDEX,
|
||||
},
|
||||
{
|
||||
logoFileName: 'decent_ex.png',
|
||||
projectUrl: constants.PROJECT_URL_DECENT_EX,
|
||||
},
|
||||
{
|
||||
logoFileName: 'dextroid.png',
|
||||
projectUrl: constants.PROJECT_URL_DEXTROID,
|
||||
},
|
||||
{
|
||||
logoFileName: 'ercdex.png',
|
||||
projectUrl: constants.PROJECT_URL_ERC_DEX,
|
||||
},
|
||||
{
|
||||
logoFileName: 'open_relay.png',
|
||||
projectUrl: constants.PROJECT_URL_OPEN_RELAY,
|
||||
},
|
||||
{
|
||||
logoFileName: 'idt.png',
|
||||
projectUrl: constants.PROJECT_URL_IDT,
|
||||
},
|
||||
{
|
||||
logoFileName: 'imtoken.png',
|
||||
projectUrl: constants.PROJECT_URL_IMTOKEN,
|
||||
},
|
||||
];
|
||||
|
||||
export interface LandingProps {
|
||||
location: Location;
|
||||
translate: Translate;
|
||||
dispatcher: Dispatcher;
|
||||
}
|
||||
|
||||
interface LandingState {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
export class Landing extends React.Component<LandingProps, LandingState> {
|
||||
private readonly _throttledScreenWidthUpdate: () => void;
|
||||
constructor(props: LandingProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
screenWidth: utils.getScreenWidth(),
|
||||
};
|
||||
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
||||
}
|
||||
public componentDidMount(): void {
|
||||
window.addEventListener('resize', this._throttledScreenWidthUpdate);
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
public componentWillUnmount(): void {
|
||||
window.removeEventListener('resize', this._throttledScreenWidthUpdate);
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<div id="landing" className="clearfix" style={{ color: colors.grey500 }}>
|
||||
<DocumentTitle title="0x Protocol" />
|
||||
<TopBar
|
||||
blockchainIsLoaded={false}
|
||||
location={this.props.location}
|
||||
isNightVersion={true}
|
||||
style={{ backgroundColor: colors.heroGrey, position: 'relative' }}
|
||||
translate={this.props.translate}
|
||||
/>
|
||||
{this._renderHero()}
|
||||
{this._renderProjects(
|
||||
relayerProjects,
|
||||
this.props.translate.get(Key.RelayersHeader, Deco.Upper),
|
||||
colors.projectsGrey,
|
||||
true,
|
||||
)}
|
||||
{this._renderInfoBoxes()}
|
||||
{this._renderTokenizationSection()}
|
||||
{this._renderUseCases()}
|
||||
{this._renderCallToAction()}
|
||||
<Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderHero(): React.ReactNode {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
const left = 'col lg-col-6 md-col-6 col-12 lg-pl4 md-pl4 sm-pl0 sm-px3 sm-center';
|
||||
const flexClassName = isSmallScreen
|
||||
? 'flex items-center flex-column justify-center'
|
||||
: 'flex items-center justify-center';
|
||||
return (
|
||||
<div className="clearfix py4" style={{ backgroundColor: colors.heroGrey }}>
|
||||
<div className="mx-auto max-width-4 clearfix">
|
||||
{this._renderWhatsNew()}
|
||||
<div className={`${flexClassName} lg-pt4 md-pt4 sm-pt2 lg-pb4 md-pb4 lg-mt4 md-mt4 sm-mt2 sm-mb4`}>
|
||||
<Container marginTop="30px" marginBottom="30px" marginLeft="15px" marginRight="15px">
|
||||
<Image src="/images/landing/0x_homepage.svg" maxWidth="100%" height="auto" />
|
||||
</Container>
|
||||
<div className={left} style={{ color: colors.white, height: 390, lineHeight: '390px' }}>
|
||||
<div
|
||||
className="inline-block lg-align-middle md-align-middle sm-align-top"
|
||||
style={{
|
||||
paddingLeft: isSmallScreen ? 0 : 12,
|
||||
lineHeight: '36px',
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
className="sm-pb2"
|
||||
fontFamily="Roboto"
|
||||
display="inline-block"
|
||||
fontColor={colors.grey300}
|
||||
fontWeight={500}
|
||||
lineHeight="1.3em"
|
||||
fontSize={isSmallScreen ? '28px' : '36px'}
|
||||
>
|
||||
{this.props.translate.get(Key.TopHeader, Deco.Cap)}
|
||||
{this.props.translate.getLanguage() === Language.English && (
|
||||
<React.Fragment>
|
||||
{' '}
|
||||
for{' '}
|
||||
<TypedText
|
||||
fontFamily="Roboto"
|
||||
display="inline-block"
|
||||
fontColor={colors.white}
|
||||
fontWeight={700}
|
||||
lineHeight="1.3em"
|
||||
fontSize={isSmallScreen ? '28px' : '36px'}
|
||||
textList={ROTATING_LIST}
|
||||
shouldRepeat={true}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Text>
|
||||
<Container
|
||||
className={`pt3 flex clearfix sm-mx-auto ${isSmallScreen ? 'justify-center' : ''}`}
|
||||
>
|
||||
<Container paddingRight="20px">
|
||||
<Link to={WebsitePaths.Docs}>
|
||||
<CallToAction type="light">
|
||||
{this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
|
||||
</CallToAction>
|
||||
</Link>
|
||||
</Container>
|
||||
<div>
|
||||
<Link to={WebsitePaths.Portal}>
|
||||
<CallToAction>
|
||||
{this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
|
||||
</CallToAction>
|
||||
</Link>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{this.props.translate.getLanguage() === Language.English && <SubscribeForm />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderWhatsNew(): React.ReactNode {
|
||||
return (
|
||||
<div className="sm-center sm-px1">
|
||||
<a href={WHATS_NEW_URL} className="inline-block text-decoration-none">
|
||||
<div className="flex items-center sm-pl0 md-pl2 lg-pl0">
|
||||
<Container
|
||||
paddingTop="3px"
|
||||
paddingLeft="8px"
|
||||
paddingBottom="3px"
|
||||
paddingRight="8px"
|
||||
backgroundColor={colors.white}
|
||||
borderRadius={6}
|
||||
>
|
||||
<Text fontSize="14px" fontWeight={500} fontColor={colors.heroGrey}>
|
||||
New
|
||||
</Text>
|
||||
</Container>
|
||||
<Container marginLeft="12px">
|
||||
<Text fontSize="16px" fontWeight={500} fontColor={colors.grey300}>
|
||||
{WHATS_NEW_TITLE}
|
||||
</Text>
|
||||
</Container>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderProjects(
|
||||
projects: Project[],
|
||||
title: string,
|
||||
backgroundColor: string,
|
||||
isTitleCenter: boolean,
|
||||
): React.ReactNode {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
const projectList = _.map(projects, (project: Project, i: number) => {
|
||||
const isRelayersOnly = projects.length === 12;
|
||||
let colWidth: number;
|
||||
switch (this.state.screenWidth) {
|
||||
case ScreenWidths.Sm:
|
||||
colWidth = 4;
|
||||
break;
|
||||
|
||||
case ScreenWidths.Md:
|
||||
colWidth = 3;
|
||||
break;
|
||||
|
||||
case ScreenWidths.Lg:
|
||||
colWidth = isRelayersOnly ? 2 : 2 - i % 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Encountered unknown ScreenWidths value: ${this.state.screenWidth}`);
|
||||
}
|
||||
return (
|
||||
<div key={`project-${project.logoFileName}`} className={`col col-${colWidth} center`}>
|
||||
<div>
|
||||
<a href={project.projectUrl} target="_blank" className="text-decoration-none">
|
||||
<img
|
||||
src={`/images/landing/project_logos/${project.logoFileName}`}
|
||||
height={isSmallScreen ? 60 : 92}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<div className={`clearfix py4 ${isTitleCenter && 'center'}`} style={{ backgroundColor }}>
|
||||
<div className="mx-auto max-width-4 clearfix sm-px3">
|
||||
<div className="h4 pb3 lg-pl0 md-pl3 sm-pl2" style={TITLE_STYLE}>
|
||||
{title}
|
||||
</div>
|
||||
<div className="clearfix">{projectList}</div>
|
||||
<div
|
||||
className="pt3 mx-auto center"
|
||||
style={{
|
||||
color: colors.landingLinkGrey,
|
||||
fontFamily: 'Roboto Mono',
|
||||
maxWidth: 300,
|
||||
fontSize: 14,
|
||||
}}
|
||||
>
|
||||
{this.props.translate.get(Key.FullListPrompt)}{' '}
|
||||
<Link to={WebsitePaths.Portal} textDecoration="underline" fontColor={colors.landingLinkGrey}>
|
||||
{this.props.translate.get(Key.FullListLink)}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderTokenizationSection(): React.ReactNode {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
return (
|
||||
<div className="clearfix lg-py4 md-py4 sm-pb4 sm-pt2" style={{ backgroundColor: colors.grey100 }}>
|
||||
<div className="mx-auto max-width-4 py4 clearfix">
|
||||
{isSmallScreen && this._renderTokenCloud()}
|
||||
<div
|
||||
className="col lg-col-6 md-col-6 col-12 center"
|
||||
style={{ color: colors.darkestGrey, height: 364, lineHeight: '364px' }}
|
||||
>
|
||||
<div
|
||||
className="mx-auto inline-block lg-align-middle md-align-middle sm-align-top"
|
||||
style={{ maxWidth: 385, lineHeight: '44px', textAlign: 'left' }}
|
||||
>
|
||||
<div className="lg-h1 md-h1 sm-h2 sm-center sm-pt3" style={{ fontFamily: 'Roboto Mono' }}>
|
||||
{this.props.translate.get(Key.TokenizedSectionHeader, Deco.Cap)}
|
||||
</div>
|
||||
<div
|
||||
className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 h5 sm-center"
|
||||
style={{ fontFamily: 'Roboto Mono', lineHeight: 1.7, maxWidth: 370 }}
|
||||
>
|
||||
{this.props.translate.get(Key.TokenizedSectionDescription, Deco.Cap)}
|
||||
</div>
|
||||
<div className="flex pt1 sm-px3">{this._renderMissionAndValuesButton()}</div>
|
||||
</div>
|
||||
</div>
|
||||
{!isSmallScreen && this._renderTokenCloud()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderTokenCloud(): React.ReactNode {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
return (
|
||||
<div className="col lg-col-6 md-col-6 col-12 center">
|
||||
<img src="/images/landing/tokenized_world.png" height={isSmallScreen ? 280 : 364.5} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderMissionAndValuesButton(): React.ReactNode {
|
||||
return (
|
||||
<a
|
||||
href={constants.URL_MISSION_AND_VALUES_BLOG_POST}
|
||||
target="_blank"
|
||||
className="inline-block text-decoration-none"
|
||||
>
|
||||
<CallToAction>{this.props.translate.get(Key.OurMissionAndValues, Deco.CapWords)}</CallToAction>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
private _renderInfoBoxes(): React.ReactNode {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
const boxStyle: React.CSSProperties = {
|
||||
maxWidth: 253,
|
||||
height: 402,
|
||||
backgroundColor: colors.grey50,
|
||||
borderRadius: 5,
|
||||
padding: '10px 24px 24px',
|
||||
};
|
||||
const boxContents: BoxContent[] = [
|
||||
{
|
||||
title: this.props.translate.get(Key.BenefitOneTitle, Deco.Cap),
|
||||
description: this.props.translate.get(Key.BenefitOneDescription, Deco.Cap),
|
||||
imageUrl: '/images/landing/distributed_network.png',
|
||||
classNames: '',
|
||||
maxWidth: 160,
|
||||
},
|
||||
{
|
||||
title: this.props.translate.get(Key.BenefitTwoTitle, Deco.Cap),
|
||||
description: this.props.translate.get(Key.BenefitTwoDescription, Deco.Cap),
|
||||
imageUrl: '/images/landing/liquidity.png',
|
||||
classNames: 'mx-auto',
|
||||
maxWidth: 160,
|
||||
},
|
||||
{
|
||||
title: this.props.translate.get(Key.BenefitThreeTitle, Deco.Cap),
|
||||
description: this.props.translate.get(Key.BenefitThreeDescription, Deco.Cap),
|
||||
imageUrl: '/images/landing/exchange_everywhere.png',
|
||||
classNames: 'right',
|
||||
maxWidth: 130,
|
||||
},
|
||||
];
|
||||
const boxes = _.map(boxContents, (boxContent: BoxContent) => {
|
||||
return (
|
||||
<div key={`box-${boxContent.title}`} className="col lg-col-4 md-col-4 col-12 sm-pb4">
|
||||
<div className={`center sm-mx-auto ${!isSmallScreen && boxContent.classNames}`} style={boxStyle}>
|
||||
<Container className="flex items-center" height="210px">
|
||||
<img
|
||||
className="mx-auto"
|
||||
src={boxContent.imageUrl}
|
||||
style={{ height: 'auto', maxWidth: boxContent.maxWidth }}
|
||||
/>
|
||||
</Container>
|
||||
<div className="h3" style={{ color: 'black', fontFamily: 'Roboto Mono' }}>
|
||||
{boxContent.title}
|
||||
</div>
|
||||
<div className="pt2 pb2" style={{ fontFamily: 'Roboto Mono', fontSize: 14 }}>
|
||||
{boxContent.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<div className="clearfix" style={{ backgroundColor: colors.heroGrey }}>
|
||||
<div className="center pb3 pt4" style={TITLE_STYLE}>
|
||||
{this.props.translate.get(Key.BenefitsHeader, Deco.Upper)}
|
||||
</div>
|
||||
<div className="mx-auto pb4 sm-mt2 clearfix" style={{ maxWidth: '60em' }}>
|
||||
{boxes}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _getUseCases(): UseCase[] {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
const isEnglish = this.props.translate.getLanguage() === Language.English;
|
||||
if (isEnglish) {
|
||||
return [
|
||||
{
|
||||
imageUrl: '/images/landing/governance_icon.png',
|
||||
type: this.props.translate.get(Key.GamingAndCollectables, Deco.Upper),
|
||||
description: this.props.translate.get(Key.GamingAndCollectablesDescription, Deco.Cap),
|
||||
classNames: 'lg-px2 md-px2',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/landing/prediction_market_icon.png',
|
||||
type: this.props.translate.get(Key.PredictionMarkets, Deco.Upper),
|
||||
description: this.props.translate.get(Key.PredictionMarketsDescription, Deco.Cap),
|
||||
classNames: 'lg-px2 md-px2',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/landing/fund_management_icon.png',
|
||||
type: this.props.translate.get(Key.OrderBooks, Deco.Upper),
|
||||
description: this.props.translate.get(Key.OrderBooksDescription, Deco.Cap),
|
||||
classNames: 'lg-px2 md-px2',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/landing/loans_icon.png',
|
||||
type: this.props.translate.get(Key.DecentralizedLoans, Deco.Upper),
|
||||
description: this.props.translate.get(Key.DecentralizedLoansDescription, Deco.Cap),
|
||||
classNames: 'lg-pr2 md-pr2 lg-col-6 md-col-6',
|
||||
style: {
|
||||
width: 291,
|
||||
float: 'right',
|
||||
marginTop: !isSmallScreen ? 38 : 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/landing/stable_tokens_icon.png',
|
||||
type: this.props.translate.get(Key.StableTokens, Deco.Upper),
|
||||
description: this.props.translate.get(Key.StableTokensDescription, Deco.Cap),
|
||||
classNames: 'lg-pl2 md-pl2 lg-col-6 md-col-6',
|
||||
style: { width: 291, marginTop: !isSmallScreen ? 38 : 0 },
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
imageUrl: '/images/landing/governance_icon.png',
|
||||
type: this.props.translate.get(Key.DecentralizedGovernance, Deco.Upper),
|
||||
description: this.props.translate.get(Key.DecentralizedGovernanceDescription, Deco.Cap),
|
||||
classNames: 'lg-px2 md-px2',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/landing/prediction_market_icon.png',
|
||||
type: this.props.translate.get(Key.PredictionMarkets, Deco.Upper),
|
||||
description: this.props.translate.get(Key.PredictionMarketsDescription, Deco.Cap),
|
||||
classNames: 'lg-px2 md-px2',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/landing/stable_tokens_icon.png',
|
||||
type: this.props.translate.get(Key.StableTokens, Deco.Upper),
|
||||
description: this.props.translate.get(Key.StableTokensDescription, Deco.Cap),
|
||||
classNames: 'lg-px2 md-px2',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/landing/loans_icon.png',
|
||||
type: this.props.translate.get(Key.DecentralizedLoans, Deco.Upper),
|
||||
description: this.props.translate.get(Key.DecentralizedLoansDescription, Deco.Cap),
|
||||
classNames: 'lg-pr2 md-pr2 lg-col-6 md-col-6',
|
||||
style: {
|
||||
width: 291,
|
||||
float: 'right',
|
||||
marginTop: !isSmallScreen ? 38 : 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/landing/fund_management_icon.png',
|
||||
type: this.props.translate.get(Key.FundManagement, Deco.Upper),
|
||||
description: this.props.translate.get(Key.FundManagementDescription, Deco.Cap),
|
||||
classNames: 'lg-pl2 md-pl2 lg-col-6 md-col-6',
|
||||
style: { width: 291, marginTop: !isSmallScreen ? 38 : 0 },
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
private _renderUseCases(): React.ReactNode {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
const useCases = this._getUseCases();
|
||||
const cases = _.map(useCases, (useCase: UseCase) => {
|
||||
const style = _.isUndefined(useCase.style) || isSmallScreen ? {} : useCase.style;
|
||||
const useCaseBoxStyle = {
|
||||
color: colors.grey,
|
||||
border: `1px solid ${colors.grey750}`,
|
||||
borderRadius: 4,
|
||||
maxWidth: isSmallScreen ? 375 : 'none',
|
||||
...style,
|
||||
};
|
||||
const typeStyle: React.CSSProperties = {
|
||||
color: colors.lightGrey,
|
||||
fontSize: 13,
|
||||
textTransform: 'uppercase',
|
||||
fontFamily: 'Roboto Mono',
|
||||
fontWeight: 300,
|
||||
};
|
||||
return (
|
||||
<div
|
||||
key={`useCase-${useCase.type}`}
|
||||
className={`col lg-col-4 md-col-4 col-12 sm-pt3 sm-px3 sm-pb3 ${useCase.classNames}`}
|
||||
>
|
||||
<div className="relative p2 pb2 sm-mx-auto" style={useCaseBoxStyle}>
|
||||
<div className="absolute center" style={{ top: -35, width: 'calc(100% - 32px)' }}>
|
||||
<img src={useCase.imageUrl} style={{ height: 50 }} />
|
||||
</div>
|
||||
<div className="pt2 center" style={typeStyle}>
|
||||
{useCase.type}
|
||||
</div>
|
||||
<div
|
||||
className="pt2"
|
||||
style={{
|
||||
lineHeight: 1.5,
|
||||
fontSize: 14,
|
||||
overflow: 'hidden',
|
||||
height: 124,
|
||||
}}
|
||||
>
|
||||
{useCase.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<div className="clearfix py4" style={{ backgroundColor: colors.heroGrey }}>
|
||||
<div className="center h4 pb3 lg-pl0 md-pl3 sm-pl2" style={TITLE_STYLE}>
|
||||
{this.props.translate.get(Key.UseCasesHeader, Deco.Upper)}
|
||||
</div>
|
||||
<div className="mx-auto pb4 pt3 mt1 sm-mt2 clearfix" style={{ maxWidth: '67em' }}>
|
||||
{cases}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderCallToAction(): React.ReactNode {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
const callToActionClassNames =
|
||||
'lg-pr3 md-pr3 lg-right-align md-right-align sm-center sm-px3 h4 lg-table-cell md-table-cell';
|
||||
return (
|
||||
<div className="clearfix pb4" style={{ backgroundColor: colors.heroGrey }}>
|
||||
<div className="mx-auto max-width-4 pb4 mb3 clearfix center">
|
||||
<div className="center inline-block" style={{ textAlign: 'left' }}>
|
||||
<div
|
||||
className={callToActionClassNames}
|
||||
style={{
|
||||
fontFamily: 'Roboto Mono',
|
||||
color: colors.white,
|
||||
lineHeight: isSmallScreen ? 1.7 : 3,
|
||||
}}
|
||||
>
|
||||
{this.props.translate.get(Key.FinalCallToAction, Deco.Cap)}
|
||||
</div>
|
||||
<div className="sm-center sm-pt2 lg-table-cell md-table-cell">
|
||||
<Link to={WebsitePaths.Docs}>
|
||||
<CallToAction fontSize="15px">
|
||||
{this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
|
||||
</CallToAction>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _updateScreenWidth(): void {
|
||||
const newScreenWidth = utils.getScreenWidth();
|
||||
if (newScreenWidth !== this.state.screenWidth) {
|
||||
this.setState({
|
||||
screenWidth: newScreenWidth,
|
||||
});
|
||||
}
|
||||
}
|
||||
} // tslint:disable:max-file-line-count
|
||||
@@ -1,335 +0,0 @@
|
||||
import { colors, Link } from '@0x/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import DocumentTitle from 'react-document-title';
|
||||
import { Footer } from 'ts/components/old_footer';
|
||||
import { TopBar } from 'ts/components/top_bar/top_bar';
|
||||
import { Button } from 'ts/components/ui/button';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Image } from 'ts/components/ui/image';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { Deco, Key, ScreenWidths } from 'ts/types';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
export interface LaunchKitProps {
|
||||
location: Location;
|
||||
translate: Translate;
|
||||
dispatcher: Dispatcher;
|
||||
}
|
||||
|
||||
interface LaunchKitState {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
const THROTTLE_TIMEOUT = 100;
|
||||
const lighterBackgroundColor = '#222222';
|
||||
const darkerBackgroundColor = '#1B1B1B';
|
||||
const grayText = '#999999';
|
||||
|
||||
interface Benefit {
|
||||
icon: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export class LaunchKit extends React.Component<LaunchKitProps, LaunchKitState> {
|
||||
private readonly _throttledScreenWidthUpdate: () => void;
|
||||
constructor(props: LaunchKitProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
screenWidth: utils.getScreenWidth(),
|
||||
};
|
||||
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
||||
}
|
||||
public componentDidMount(): void {
|
||||
window.addEventListener('resize', this._throttledScreenWidthUpdate);
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
public componentWillUnmount(): void {
|
||||
window.removeEventListener('resize', this._throttledScreenWidthUpdate);
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<div id="launchKit" className="clearfix" style={{ color: colors.grey500 }}>
|
||||
<DocumentTitle title="0x Launch Kit" />
|
||||
<TopBar
|
||||
blockchainIsLoaded={false}
|
||||
location={this.props.location}
|
||||
isNightVersion={true}
|
||||
style={{ backgroundColor: lighterBackgroundColor, position: 'relative' }}
|
||||
translate={this.props.translate}
|
||||
/>
|
||||
{this._renderHero()}
|
||||
{this._renderSection()}
|
||||
{this._renderCallToAction()}
|
||||
{this._renderDisclaimer()}
|
||||
<Footer
|
||||
backgroundColor={darkerBackgroundColor}
|
||||
translate={this.props.translate}
|
||||
dispatcher={this.props.dispatcher}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderHero(): React.ReactNode {
|
||||
const BENEFITS_1: Benefit[] = [
|
||||
{
|
||||
icon: '/images/launch_kit/shared_liquidity.svg',
|
||||
description: this.props.translate.get(Key.TapIntoAndShare, Deco.Cap),
|
||||
},
|
||||
{
|
||||
icon: '/images/launch_kit/fork.svg',
|
||||
description: this.props.translate.get(Key.ForkAndExtend, Deco.Cap),
|
||||
},
|
||||
{
|
||||
icon: '/images/launch_kit/enable_trading.svg',
|
||||
description: this.props.translate.get(Key.EnableTrading, Deco.Cap),
|
||||
},
|
||||
];
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
const smallButtonPadding = '12px 30px 12px 30px';
|
||||
const largeButtonPadding = '14px 60px 14px 60px';
|
||||
const left = 'col lg-col-6 md-col-6 col-12 lg-pl2 md-pl2 sm-pl0 sm-px3 sm-center';
|
||||
const flexClassName = isSmallScreen
|
||||
? 'flex items-center flex-column justify-center'
|
||||
: 'flex items-center justify-center';
|
||||
return (
|
||||
<div className="clearfix pt4" style={{ backgroundColor: lighterBackgroundColor }}>
|
||||
<div className="mx-auto max-width-4 clearfix">
|
||||
<div className={`${flexClassName} lg-pb4 md-pb4 sm-mb4`}>
|
||||
<div className={left} style={{ color: colors.white }}>
|
||||
<div
|
||||
className="inline-block lg-align-middle md-align-middle sm-align-top"
|
||||
style={{
|
||||
paddingLeft: isSmallScreen ? 0 : 12,
|
||||
lineHeight: '36px',
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
className="sm-pb2"
|
||||
fontFamily="Roboto"
|
||||
display="inline-block"
|
||||
fontColor={colors.white}
|
||||
fontWeight="bold"
|
||||
lineHeight="1.3em"
|
||||
letterSpacing="1px"
|
||||
fontSize={isSmallScreen ? '38px' : '46px'}
|
||||
>
|
||||
{this.props.translate.get(Key.LaunchKit, Deco.CapWords)}
|
||||
</Text>
|
||||
<Container paddingTop="18px">
|
||||
<Text fontColor={colors.linkSectionGrey} fontSize="18px">
|
||||
{this.props.translate.get(Key.LaunchKitPitch, Deco.Cap)}
|
||||
</Text>
|
||||
</Container>
|
||||
<Container
|
||||
paddingTop="54px"
|
||||
className={`flex clearfix sm-mx-auto ${isSmallScreen ? 'justify-center' : ''}`}
|
||||
>
|
||||
<Container paddingRight="20px">
|
||||
<Link to={constants.URL_LAUNCH_KIT} shouldOpenInNewTab={true}>
|
||||
<Button
|
||||
padding={isSmallScreen ? smallButtonPadding : largeButtonPadding}
|
||||
borderRadius="4px"
|
||||
borderColor={colors.white}
|
||||
>
|
||||
<Text fontSize="16px" fontWeight="bold">
|
||||
{this.props.translate.get(Key.GetStarted, Deco.Cap)}
|
||||
</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
</Container>
|
||||
<div>
|
||||
<Link to={constants.URL_LAUNCH_KIT_BLOG_POST} shouldOpenInNewTab={true}>
|
||||
<Button
|
||||
backgroundColor={lighterBackgroundColor}
|
||||
borderColor={colors.white}
|
||||
fontColor={colors.white}
|
||||
padding={isSmallScreen ? smallButtonPadding : largeButtonPadding}
|
||||
borderRadius="4px"
|
||||
>
|
||||
<Text fontSize="16px" fontWeight="bold" fontColor={colors.white}>
|
||||
{this.props.translate.get(Key.LearnMore, Deco.Cap)}
|
||||
</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</div>
|
||||
<Container
|
||||
marginTop={isSmallScreen ? '60px' : '30px'}
|
||||
marginBottom="30px"
|
||||
marginLeft="15px"
|
||||
marginRight="15px"
|
||||
>
|
||||
<Image
|
||||
src="/images/launch_kit/0x_cupboard.svg"
|
||||
maxWidth={isSmallScreen ? '75%' : '100%'}
|
||||
height="auto"
|
||||
/>
|
||||
</Container>
|
||||
</div>
|
||||
</div>
|
||||
{this._renderBenefits(BENEFITS_1)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderSection(): React.ReactNode {
|
||||
const BENEFITS_2: Benefit[] = [
|
||||
{
|
||||
icon: '/images/launch_kit/secondary_market.svg',
|
||||
description: this.props.translate.get(Key.QuicklyLaunch, Deco.Cap),
|
||||
},
|
||||
{
|
||||
icon: '/images/launch_kit/in_game_marketplace.svg',
|
||||
description: this.props.translate.get(Key.SeemlesslyCreate, Deco.Cap),
|
||||
},
|
||||
{
|
||||
icon: '/images/launch_kit/local_market.svg',
|
||||
description: this.props.translate.get(Key.LocalMarket, Deco.Cap),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="clearfix pb4" style={{ backgroundColor: darkerBackgroundColor }}>
|
||||
<Container
|
||||
className="mx-auto"
|
||||
textAlign="center"
|
||||
paddingTop="89px"
|
||||
paddingBottom="89px"
|
||||
maxWidth="421px"
|
||||
paddingLeft="10px"
|
||||
paddingRight="10px"
|
||||
>
|
||||
<Text fontSize="26px" lineHeight="37px" fontWeight="medium" fontColor={colors.white}>
|
||||
{this.props.translate.get(Key.PerfectForDevelopers, Deco.Cap)}
|
||||
</Text>
|
||||
</Container>
|
||||
{this._renderBenefits(BENEFITS_2)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderCallToAction(): React.ReactNode {
|
||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||
const smallButtonPadding = '8px 14px 8px 14px';
|
||||
const largeButtonPadding = '8px 14px 8px 14px';
|
||||
return (
|
||||
<Container
|
||||
className="clearfix"
|
||||
backgroundColor={lighterBackgroundColor}
|
||||
paddingTop="90px"
|
||||
paddingBottom="90px"
|
||||
>
|
||||
<Container className="clearfix mx-auto" maxWidth="850px">
|
||||
<Container className="lg-left md-left sm-mx-auto sm-pb3" width="348px">
|
||||
<Text fontColor={colors.white} fontSize="18px">
|
||||
View our comprehensive documentation to start building today.
|
||||
</Text>
|
||||
</Container>
|
||||
<Container
|
||||
className={`lg-right md-right flex clearfix sm-mx-auto ${
|
||||
isSmallScreen ? 'justify-center' : ''
|
||||
}`}
|
||||
paddingTop="5px"
|
||||
>
|
||||
<Container paddingRight="20px">
|
||||
<Link to={`${constants.URL_LAUNCH_KIT}/#table-of-contents`} shouldOpenInNewTab={true}>
|
||||
<Button
|
||||
padding={isSmallScreen ? smallButtonPadding : largeButtonPadding}
|
||||
borderRadius="4px"
|
||||
backgroundColor={lighterBackgroundColor}
|
||||
borderColor={colors.white}
|
||||
>
|
||||
<Text fontSize="16px" fontWeight="bold" fontColor={colors.white}>
|
||||
{this.props.translate.get(Key.ExploreTheDocs, Deco.Cap)}
|
||||
</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
</Container>
|
||||
<div>
|
||||
<Link to={constants.URL_ZEROEX_CHAT} shouldOpenInNewTab={true}>
|
||||
<Button
|
||||
padding={isSmallScreen ? smallButtonPadding : largeButtonPadding}
|
||||
borderRadius="4px"
|
||||
>
|
||||
<Text fontSize="16px" fontWeight="bold">
|
||||
{this.props.translate.get(Key.GetInTouch, Deco.Cap)}
|
||||
</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</Container>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private _renderBenefits(benefits: Benefit[]): React.ReactNode {
|
||||
return (
|
||||
<Container className="lg-flex md-flex justify-between mx-auto pb4" maxWidth="890px">
|
||||
{_.map(benefits, benefit => {
|
||||
return (
|
||||
<Container className="mx-auto sm-pb4" width="240px">
|
||||
<Container textAlign="center">
|
||||
<img src={benefit.icon} />
|
||||
</Container>
|
||||
<Container paddingTop="26px">
|
||||
<Text
|
||||
fontSize="18px"
|
||||
lineHeight="28px"
|
||||
textAlign="center"
|
||||
fontColor={colors.linkSectionGrey}
|
||||
>
|
||||
{benefit.description}
|
||||
</Text>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
})}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private _renderDisclaimer(): React.ReactNode {
|
||||
return (
|
||||
<Container
|
||||
className="clearfix"
|
||||
backgroundColor={darkerBackgroundColor}
|
||||
paddingTop="70px"
|
||||
paddingBottom="70px"
|
||||
>
|
||||
<Container className="mx-auto" maxWidth="850px" paddingLeft="20px" paddingRight="20px">
|
||||
<Text fontColor={grayText} fontSize="10px">
|
||||
<b>Disclaimer:</b> 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.
|
||||
</Text>
|
||||
<Container paddingTop="15px">
|
||||
<Text fontColor={grayText} fontSize="10px">
|
||||
See the{' '}
|
||||
<Link
|
||||
to={constants.URL_APACHE_LICENSE}
|
||||
shouldOpenInNewTab={true}
|
||||
textDecoration="underline"
|
||||
>
|
||||
Apache License, Version 2.0
|
||||
</Link>{' '}
|
||||
for the specific language governing all applicable permissions and limitations.
|
||||
</Text>
|
||||
</Container>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private _updateScreenWidth(): void {
|
||||
const newScreenWidth = utils.getScreenWidth();
|
||||
if (newScreenWidth !== this.state.screenWidth) {
|
||||
this.setState({
|
||||
screenWidth: newScreenWidth,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user