Merge pull request #893 from 0xProject/feature/website/jobs-page-part2
Jobs page
15
packages/website/public/images/jobs/calendar-icon.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<svg width="36" height="34" viewBox="0 0 36 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.5337 0.542553H13.1244V0H12.1554V0.542553H4.66839V0H3.78756V0.542553H2.37824C1.05699 0.542553 0 1.62766 0 2.98404V14.5585C0 15.9149 1.05699 17 2.37824 17H14.6218C15.943 17 17 15.9149 17 14.5585V5.33511V4.43085V2.98404C16.9119 1.62766 15.8549 0.542553 14.5337 0.542553Z" transform="translate(0.410645) scale(2)" fill="black"/>
|
||||
<path d="M0.61658 2.53191H1.84974C2.20207 2.53191 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53191 0.61658 2.53191Z" transform="translate(4.63916 24.5938) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.53191H1.84974C2.20207 2.53191 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53191 0.61658 2.53191Z" transform="translate(11.5103 24.5938) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.53191H1.84974C2.20207 2.53191 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53191 0.61658 2.53191Z" transform="translate(18.5571 24.5938) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.53191H1.84974C2.20207 2.53191 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53191 0.61658 2.53191Z" transform="translate(25.6035 24.5938) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.53192H1.84974C2.20207 2.53192 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53192 0.61658 2.53192Z" transform="translate(4.63916 17.1797) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.53192H1.84974C2.20207 2.53192 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53192 0.61658 2.53192Z" transform="translate(11.5103 17.1797) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.53192H1.84974C2.20207 2.53192 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53192 0.61658 2.53192Z" transform="translate(18.5571 17.1797) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.53192H1.84974C2.20207 2.53192 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53192 0.61658 2.53192Z" transform="translate(25.6035 17.1797) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.44149H1.84974C2.20207 2.44149 2.46632 2.17021 2.46632 1.80851V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.17021 0.264249 2.44149 0.61658 2.44149Z" transform="translate(4.63916 9.76562) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.44149H1.84974C2.20207 2.44149 2.46632 2.17021 2.46632 1.80851V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.17021 0.264249 2.44149 0.61658 2.44149Z" transform="translate(11.5103 9.76562) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.44149H1.84974C2.20207 2.44149 2.46632 2.17021 2.46632 1.80851V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.17021 0.264249 2.44149 0.61658 2.44149Z" transform="translate(18.5571 9.76562) scale(2)" fill="white"/>
|
||||
<path d="M0.61658 2.44149H1.84974C2.20207 2.44149 2.46632 2.17021 2.46632 1.80851V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.17021 0.264249 2.44149 0.61658 2.44149Z" transform="translate(25.6035 9.76562) scale(2)" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
3
packages/website/public/images/jobs/heart-icon.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="42" height="36" viewBox="0 0 42 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9861 5.40966C19.9861 6.40787 19.7347 7.34168 19.2634 8.14669C19.1691 8.30769 19.0434 8.46869 18.9491 8.6297L17.9435 9.66011L10.0245 18L1.66551 9.3703C1.66551 9.3703 1.66551 9.3703 1.63409 9.3381L1.44554 9.1449C1.16271 8.8551 0.942742 8.50089 0.722769 8.14669C0.251398 7.37388 0 6.40787 0 5.40966C0 2.41503 2.35685 0 5.24793 0C7.32196 0 9.11317 1.25581 9.99306 3.05903C10.8415 1.25581 12.6327 0 14.7068 0C17.6293 0 19.9861 2.41503 19.9861 5.40966Z" transform="translate(0.0483398) scale(2)" fill="#FF573F"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 663 B |
17
packages/website/public/images/jobs/hero-dots-left.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg width="730" height="566" viewBox="0 0 730 566" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(569.231 541.863) scale(2)" fill="black"/>
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(620.402 302.363) scale(2)" fill="black"/>
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(425.944 249.332) scale(2)" fill="black"/>
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(707.397 74.8438) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(444.712 430.668) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(180.317 546.992) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(620.402 165.508) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(265.602 182.617) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(705.691 444.352) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(269.014 386.188) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(1.95703 458) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(1.95703) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(77.9043 262) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(465.178 86.8164) scale(2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(159.847 86.8164) scale(2)" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
16
packages/website/public/images/jobs/hero-dots-right.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg width="680" height="506" viewBox="0 0 680 506" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(117.916 483.762) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(66.7402 196.73) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(244.141 280.555) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(494.888 148.828) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(221.969 22.2383) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(293.61 409.672) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(508.535 482.051) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(15.5688 25.6602) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(522.182) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(15.5688 372.93) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(435.188 314.766) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(653.747 352) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(679.729 76) scale(-2 2)" fill="black"/>
|
||||
<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(305.551 138.566) scale(-2 2)" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 644 KiB |
|
Before Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 282 KiB |
|
Before Width: | Height: | Size: 265 KiB |
|
Before Width: | Height: | Size: 471 KiB |
|
Before Width: | Height: | Size: 469 KiB |
|
Before Width: | Height: | Size: 469 KiB |
6
packages/website/public/images/jobs/ship-icon.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="42" height="28" viewBox="0 0 42 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4071 11.6878H1.76832C0.771632 11.6878 0 10.9065 0 9.96896V1.71879C0 0.781267 0.803783 0 1.76832 0H13.3749C14.3716 0 15.1433 0.781267 15.1433 1.71879L16.1078 9.93771C16.14 10.9065 14.3716 11.6878 13.4071 11.6878Z" transform="translate(0.410645) scale(2)" fill="#04060C"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.32719 7.1564H0.96454C0.417967 7.1564 0 6.75015 0 6.21888V0.93752C0 0.406259 0.417967 0 0.96454 0H8.29504C8.84161 0 9.25958 0.406259 9.25958 0.93752V6.18763C9.29173 6.71889 8.84161 7.1564 8.32719 7.1564Z" transform="translate(21.8877 9.06641) scale(2)" fill="#04060C"/>
|
||||
<path d="M2.3792 4.6251C3.69319 4.6251 4.7584 3.58974 4.7584 2.31255C4.7584 1.03536 3.69319 0 2.3792 0C1.0652 0 0 1.03536 0 2.31255C0 3.58974 1.0652 4.6251 2.3792 4.6251Z" transform="translate(4.20508 18.75) scale(2)" fill="#04060C"/>
|
||||
<path d="M2.3792 4.6251C3.69319 4.6251 4.7584 3.58974 4.7584 2.31255C4.7584 1.03536 3.69319 0 2.3792 0C1.0652 0 0 1.03536 0 2.31255C0 3.58974 1.0652 4.6251 2.3792 4.6251Z" transform="translate(26.3887 18.75) scale(2)" fill="#04060C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
64
packages/website/public/images/jobs/world-map.svg
Normal file
|
After Width: | Height: | Size: 168 KiB |
@@ -115,7 +115,7 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
||||
{
|
||||
title: this.props.translate.get(Key.Careers, Deco.Cap),
|
||||
isExternal: false,
|
||||
path: WebsitePaths.Jobs,
|
||||
path: WebsitePaths.Careers,
|
||||
},
|
||||
{
|
||||
title: this.props.translate.get(Key.Contact, Deco.Cap),
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface ContainerProps {
|
||||
marginBottom?: StringOrNum;
|
||||
marginRight?: StringOrNum;
|
||||
marginLeft?: StringOrNum;
|
||||
padding?: StringOrNum;
|
||||
paddingTop?: StringOrNum;
|
||||
paddingBottom?: StringOrNum;
|
||||
paddingRight?: StringOrNum;
|
||||
@@ -31,13 +32,15 @@ export interface ContainerProps {
|
||||
bottom?: string;
|
||||
zIndex?: number;
|
||||
Tag?: ContainerTag;
|
||||
id?: string;
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
}
|
||||
|
||||
export const Container: React.StatelessComponent<ContainerProps> = props => {
|
||||
const { children, className, Tag, isHidden, ...style } = props;
|
||||
const { children, className, Tag, isHidden, id, onClick, ...style } = props;
|
||||
const visibility = isHidden ? 'hidden' : undefined;
|
||||
return (
|
||||
<Tag style={{ ...style, visibility }} className={className}>
|
||||
<Tag id={id} style={{ ...style, visibility }} className={className} onClick={onClick}>
|
||||
{children}
|
||||
</Tag>
|
||||
);
|
||||
|
||||
@@ -5,9 +5,11 @@ export interface ImageProps {
|
||||
className?: string;
|
||||
src?: string;
|
||||
fallbackSrc?: string;
|
||||
height?: string | number;
|
||||
borderRadius?: string;
|
||||
width?: string | number;
|
||||
height?: string | number;
|
||||
maxWidth?: string | number;
|
||||
maxHeight?: string | number;
|
||||
}
|
||||
interface ImageState {
|
||||
imageLoadFailed: boolean;
|
||||
@@ -29,6 +31,8 @@ export class Image extends React.Component<ImageProps, ImageState> {
|
||||
src={src}
|
||||
style={{
|
||||
borderRadius: this.props.borderRadius,
|
||||
maxWidth: this.props.maxWidth,
|
||||
maxHeight: this.props.maxHeight,
|
||||
}}
|
||||
height={this.props.height}
|
||||
width={this.props.width}
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface TextProps {
|
||||
Tag?: TextTag;
|
||||
fontSize?: string;
|
||||
fontFamily?: string;
|
||||
fontStyle?: string;
|
||||
fontColor?: string;
|
||||
lineHeight?: string;
|
||||
minHeight?: string;
|
||||
@@ -28,6 +29,7 @@ const PlainText: React.StatelessComponent<TextProps> = ({ children, className, o
|
||||
|
||||
export const Text = styled(PlainText)`
|
||||
font-family: ${props => props.fontFamily};
|
||||
font-style: ${props => props.fontStyle};
|
||||
font-weight: ${props => props.fontWeight};
|
||||
font-size: ${props => props.fontSize};
|
||||
text-decoration-line: ${props => props.textDecorationLine};
|
||||
@@ -44,6 +46,7 @@ export const Text = styled(PlainText)`
|
||||
|
||||
Text.defaultProps = {
|
||||
fontFamily: 'Roboto',
|
||||
fontStyle: 'normal',
|
||||
fontWeight: 400,
|
||||
fontColor: colors.black,
|
||||
fontSize: '15px',
|
||||
|
||||
@@ -77,10 +77,8 @@ render(
|
||||
<Route exact={true} path="/" component={Landing as any} />
|
||||
<Redirect from="/otc" to={`${WebsitePaths.Portal}`} />
|
||||
{/* TODO: Remove this once we ship the jobs page*/}
|
||||
{utils.shouldShowJobsPage() ? (
|
||||
<Route path={WebsitePaths.Jobs} component={Jobs as any} />
|
||||
) : (
|
||||
<Route path={WebsitePaths.Jobs} component={Redirector as any} />
|
||||
{utils.shouldShowJobsPage() && (
|
||||
<Route path={WebsitePaths.Careers} component={Jobs as any} />
|
||||
)}
|
||||
<Route path={WebsitePaths.Portal} component={LazyPortal} />
|
||||
<Route path={WebsitePaths.FAQ} component={FAQ as any} />
|
||||
@@ -131,6 +129,12 @@ render(
|
||||
path={`${WebsiteLegacyPaths.Deployer}/:version?`}
|
||||
component={LazySolCompilerDocumentation}
|
||||
/>
|
||||
{/* TODO: Remove this once we ship the jobs page*/}
|
||||
{utils.shouldShowJobsPage() ? (
|
||||
<Route path={WebsiteLegacyPaths.Jobs} component={Jobs as any} />
|
||||
) : (
|
||||
<Route path={WebsiteLegacyPaths.Jobs} component={Redirector as any} />
|
||||
)}
|
||||
|
||||
<Route path={`${WebsitePaths.Docs}`} component={LazyZeroExJSDocumentation} />
|
||||
<Route component={NotFound as any} />
|
||||
|
||||
@@ -314,7 +314,7 @@ export class About extends React.Component<AboutProps, AboutState> {
|
||||
}}
|
||||
>
|
||||
We are seeking outstanding candidates to{' '}
|
||||
<Link to={WebsitePaths.Jobs} style={{ color: 'black' }}>
|
||||
<Link to={WebsitePaths.Careers} style={{ color: 'black' }}>
|
||||
join our team
|
||||
</Link>
|
||||
. We value passion, diversity and unique perspectives.
|
||||
|
||||
@@ -1,109 +1,159 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { FilledImage } from 'ts/components/ui/filled_image';
|
||||
import { HeaderItem } from 'ts/pages/jobs/list/header_item';
|
||||
import { ListItem } from 'ts/pages/jobs/list/list_item';
|
||||
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 { media } from 'ts/style/media';
|
||||
import { styled } from 'ts/style/theme';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
|
||||
const IMAGE_PATHS = ['/images/jobs/location1.png', '/images/jobs/location2.png', '/images/jobs/location3.png'];
|
||||
const BENEFIT_ITEM_PROPS_LIST: BenefitItemProps[] = [
|
||||
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[] = [
|
||||
{
|
||||
bulletColor: '#6FCF97',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
iconSrc: 'images/jobs/heart-icon.svg',
|
||||
text: 'Do the right thing',
|
||||
},
|
||||
{
|
||||
bulletColor: '#56CCF2',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
iconSrc: 'images/jobs/ship-icon.svg',
|
||||
text: 'Consistently ship',
|
||||
},
|
||||
{
|
||||
bulletColor: '#EB5757',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
},
|
||||
{
|
||||
bulletColor: '#6FCF97',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
},
|
||||
{
|
||||
bulletColor: '#56CCF2',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
iconSrc: 'images/jobs/calendar-icon.svg',
|
||||
text: 'Focus on long term impact',
|
||||
},
|
||||
];
|
||||
const LARGE_LAYOUT_HEIGHT = 937;
|
||||
const LARGE_LAYOUT_BENEFITS_LIST_PADDING_LEFT = 205;
|
||||
const HEADER_TEXT = 'Benefits';
|
||||
const BENEFIT_ITEM_MIN_HEIGHT = 150;
|
||||
|
||||
export interface BenefitsProps {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
export const Benefits = (props: BenefitsProps) => (
|
||||
<div style={{ backgroundColor: colors.jobsPageBackground }}>
|
||||
{props.screenWidth === ScreenWidths.Sm ? <SmallLayout /> : <LargeLayout />}
|
||||
</div>
|
||||
);
|
||||
|
||||
const LargeLayout = () => (
|
||||
<div className="flex" style={{ height: LARGE_LAYOUT_HEIGHT }}>
|
||||
<div style={{ width: '43%', height: '100%' }}>
|
||||
<ImageGrid />
|
||||
</div>
|
||||
<div
|
||||
className="pr4"
|
||||
style={{ paddingLeft: LARGE_LAYOUT_BENEFITS_LIST_PADDING_LEFT, width: '57%', height: '100%' }}
|
||||
>
|
||||
<BenefitsList />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const SmallLayout = () => (
|
||||
<div>
|
||||
<FilledImage src={_.head(IMAGE_PATHS)} />
|
||||
<BenefitsList />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const BenefitsList = () => {
|
||||
export const Benefits = (props: BenefitsProps) => {
|
||||
const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
|
||||
return (
|
||||
<div>
|
||||
<HeaderItem headerText={HEADER_TEXT} />
|
||||
{_.map(BENEFIT_ITEM_PROPS_LIST, valueItemProps => <BenefitItem {...valueItemProps} />)}
|
||||
</div>
|
||||
<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 {
|
||||
bulletColor: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const BenefitItem: React.StatelessComponent<BenefitItemProps> = ({ bulletColor, description }) => (
|
||||
<div style={{ minHeight: BENEFIT_ITEM_MIN_HEIGHT }}>
|
||||
<ListItem bulletColor={bulletColor}>
|
||||
<div style={{ fontSize: 16, lineHeight: 1.5 }}>{description}</div>
|
||||
</ListItem>
|
||||
</div>
|
||||
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>
|
||||
);
|
||||
|
||||
const ImageGrid = () => (
|
||||
<div style={{ width: '100%', height: '100%' }}>
|
||||
<div className="flex" style={{ height: '67%' }}>
|
||||
<FilledImage src={IMAGE_PATHS[0]} />
|
||||
</div>
|
||||
<div className="clearfix" style={{ height: '33%' }}>
|
||||
<div className="col lg-col-6 md-col-6 col-12" style={{ height: '100%' }}>
|
||||
<FilledImage src={IMAGE_PATHS[1]} />
|
||||
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>
|
||||
<div className="col lg-col-6 md-col-6 col-12" style={{ height: '100%' }}>
|
||||
<FilledImage src={IMAGE_PATHS[2]} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,14 +5,10 @@ import * as DocumentTitle from 'react-document-title';
|
||||
|
||||
import { Footer } from 'ts/components/footer';
|
||||
import { TopBar } from 'ts/components/top_bar/top_bar';
|
||||
import { FilledImage } from 'ts/components/ui/filled_image';
|
||||
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 { PhotoRail } from 'ts/pages/jobs/photo_rail';
|
||||
import { Teams } from 'ts/pages/jobs/teams';
|
||||
import { Values } from 'ts/pages/jobs/values';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
@@ -20,7 +16,6 @@ import { utils } from 'ts/utils/utils';
|
||||
|
||||
const OPEN_POSITIONS_HASH = 'positions';
|
||||
const THROTTLE_TIMEOUT = 100;
|
||||
const PHOTO_RAIL_IMAGES = ['/images/jobs/office1.png', '/images/jobs/office2.png', '/images/jobs/office3.png'];
|
||||
|
||||
export interface JobsProps {
|
||||
location: Location;
|
||||
@@ -45,7 +40,7 @@ export class Jobs extends React.Component<JobsProps, JobsState> {
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<div>
|
||||
<DocumentTitle title="Jobs" />
|
||||
<DocumentTitle title="Careers at 0x" />
|
||||
<TopBar
|
||||
blockchainIsLoaded={false}
|
||||
location={this.props.location}
|
||||
@@ -54,14 +49,7 @@ export class Jobs extends React.Component<JobsProps, JobsState> {
|
||||
/>
|
||||
<Join0x onCallToActionClick={this._onJoin0xCallToActionClick.bind(this)} />
|
||||
<Mission screenWidth={this.props.screenWidth} />
|
||||
{this._isSmallScreen() ? (
|
||||
<FilledImage src={_.head(PHOTO_RAIL_IMAGES)} />
|
||||
) : (
|
||||
<PhotoRail images={PHOTO_RAIL_IMAGES} />
|
||||
)}
|
||||
<Values />
|
||||
<Benefits screenWidth={this.props.screenWidth} />
|
||||
<Teams screenWidth={this.props.screenWidth} />
|
||||
<OpenPositions hash={OPEN_POSITIONS_HASH} screenWidth={this.props.screenWidth} />
|
||||
<Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
|
||||
</div>
|
||||
@@ -69,13 +57,10 @@ export class Jobs extends React.Component<JobsProps, JobsState> {
|
||||
}
|
||||
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);
|
||||
}
|
||||
private _isSmallScreen(): boolean {
|
||||
const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
|
||||
return isSmallScreen;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,12 @@ import { colors } from '@0xproject/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';
|
||||
const BUTTON_TEXT = 'View open positions';
|
||||
|
||||
export interface Join0xProps {
|
||||
onCallToActionClick: () => void;
|
||||
@@ -12,17 +16,36 @@ export interface Join0xProps {
|
||||
|
||||
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' }}>
|
||||
<div
|
||||
className="mx-auto inline-block align-middle py4"
|
||||
style={{ lineHeight: '44px', textAlign: 'center', position: 'relative' }}
|
||||
>
|
||||
<Container className="sm-hide xs-hide md-hide" position="absolute" left="100%" marginLeft="80px">
|
||||
<Image src="images/jobs/hero-dots-right.svg" width="400px" />
|
||||
</Container>
|
||||
<Container className="sm-hide xs-hide md-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 0x
|
||||
</div>
|
||||
<div
|
||||
className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 h4 sm-center"
|
||||
style={{ fontFamily: 'Roboto', lineHeight: 2, maxWidth: 537 }}
|
||||
>
|
||||
0x is transforming the way that value is exchanged on a global scale. Come join us in San Francisco or
|
||||
work remotely anywhere in the world to help create the infrastructure of a new tokenized economy.
|
||||
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"
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { ListItem } from 'ts/pages/jobs/list/list_item';
|
||||
import { colors } from 'ts/style/colors';
|
||||
|
||||
export interface HeaderItemProps {
|
||||
headerText?: string;
|
||||
}
|
||||
export const HeaderItem: React.StatelessComponent<HeaderItemProps> = ({ headerText }) => {
|
||||
return (
|
||||
<div className="h2 lg-py4 md-py4 sm-py3">
|
||||
<ListItem>
|
||||
<Text
|
||||
fontFamily="Roboto Mono"
|
||||
fontSize="24px"
|
||||
lineHeight="1.25"
|
||||
minHeight="1.25em"
|
||||
fontColor={colors.black}
|
||||
>
|
||||
{headerText}
|
||||
</Text>
|
||||
</ListItem>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Circle } from 'ts/components/ui/circle';
|
||||
|
||||
export interface ListItemProps {
|
||||
bulletColor?: string;
|
||||
}
|
||||
export const ListItem: React.StatelessComponent<ListItemProps> = ({ bulletColor, children }) => {
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<Circle className="flex-none lg-px2 md-px2 sm-pl2" diameter={26} fillColor={bulletColor || 'transparent'} />
|
||||
<div className="flex-auto px2">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,8 @@
|
||||
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';
|
||||
|
||||
@@ -7,50 +10,38 @@ export interface MissionProps {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
export const Mission = (props: MissionProps) => {
|
||||
const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
|
||||
const image = (
|
||||
<div className="col lg-col-6 md-col-6 col-12 sm-py2 px2 center">
|
||||
<img src="/images/jobs/map.png" style={{ width: '100%' }} />
|
||||
</div>
|
||||
);
|
||||
const missionStatementStyle = !isSmallScreen ? { height: 364, lineHeight: '364px' } : undefined;
|
||||
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 = (
|
||||
<div className="col lg-col-6 md-col-6 col-12 center" style={missionStatementStyle}>
|
||||
<div
|
||||
className="mx-auto inline-block align-middle"
|
||||
style={{ maxWidth: 385, lineHeight: '44px', textAlign: 'center' }}
|
||||
>
|
||||
<div className="h2 sm-center sm-pt3" style={{ fontFamily: 'Roboto Mono' }}>
|
||||
Our Mission
|
||||
</div>
|
||||
<div
|
||||
className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 h4 sm-center"
|
||||
style={{ fontFamily: 'Roboto', lineHeight: 2, maxWidth: 537 }}
|
||||
>
|
||||
We believe a system can exist in which all world value is accessible to anyone, anywhere, regardless
|
||||
of where you happen to be born.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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="container lg-py4 md-py4"
|
||||
className="flex flex-column items-center py4 px3"
|
||||
style={{ backgroundColor: colors.jobsPageBackground, color: colors.black }}
|
||||
>
|
||||
<div className="mx-auto clearfix sm-py4">
|
||||
{isSmallScreen ? (
|
||||
<div>
|
||||
{missionStatement}
|
||||
{image}
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
{image}
|
||||
{missionStatement}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{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,20 +1,17 @@
|
||||
import * as _ from 'lodash';
|
||||
import CircularProgress from 'material-ui/CircularProgress';
|
||||
import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
|
||||
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 { HeaderItem } from 'ts/pages/jobs/list/header_item';
|
||||
import { ListItem } from 'ts/pages/jobs/list/list_item';
|
||||
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 labelStyle = { fontFamily: 'Roboto Mono', fontSize: 18 };
|
||||
const HEADER_TEXT = 'Open Positions';
|
||||
const TABLE_ROW_MIN_HEIGHT = 100;
|
||||
|
||||
export interface OpenPositionsProps {
|
||||
@@ -45,16 +42,21 @@ export class OpenPositions extends React.Component<OpenPositionsProps, OpenPosit
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.jobInfos);
|
||||
const isSmallScreen = utils.isMobileWidth(this.props.screenWidth);
|
||||
return (
|
||||
<div id={this.props.hash} className="mx-auto max-width-4">
|
||||
{isReadyToRender ? this._renderBody() : this._renderLoading()}
|
||||
</div>
|
||||
<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 _renderBody(): React.ReactNode {
|
||||
const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
|
||||
return isSmallScreen ? this._renderList() : this._renderTable();
|
||||
}
|
||||
private _renderLoading(): React.ReactNode {
|
||||
return (
|
||||
// TODO: consolidate this loading component with the one in portal and RelayerIndex
|
||||
@@ -68,66 +70,34 @@ export class OpenPositions extends React.Component<OpenPositionsProps, OpenPosit
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderList(): React.ReactNode {
|
||||
return (
|
||||
<div style={{ backgroundColor: colors.jobsPageBackground }}>
|
||||
<HeaderItem headerText={HEADER_TEXT} />
|
||||
{_.map(this.state.jobInfos, jobInfo => (
|
||||
<JobInfoListItem
|
||||
key={jobInfo.id}
|
||||
title={jobInfo.title}
|
||||
description={jobInfo.department}
|
||||
onClick={this._openJobInfoUrl.bind(this, jobInfo)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderTable(): React.ReactNode {
|
||||
return (
|
||||
<div>
|
||||
<HeaderItem headerText={HEADER_TEXT} />
|
||||
<Table selectable={false} onCellClick={this._onCellClick.bind(this)}>
|
||||
<TableHeader displaySelectAll={false} adjustForCheckbox={false}>
|
||||
<TableRow>
|
||||
<TableHeaderColumn colSpan={5} style={labelStyle}>
|
||||
Position
|
||||
</TableHeaderColumn>
|
||||
<TableHeaderColumn colSpan={3} style={labelStyle}>
|
||||
Department
|
||||
</TableHeaderColumn>
|
||||
<TableHeaderColumn colSpan={4} style={labelStyle}>
|
||||
Office
|
||||
</TableHeaderColumn>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody displayRowCheckbox={false} showRowHover={true}>
|
||||
{_.map(this.state.jobInfos, jobInfo => {
|
||||
return this._renderJobInfoTableRow(jobInfo);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private _renderJobInfoTableRow(jobInfo: WebsiteBackendJobInfo): React.ReactNode {
|
||||
return (
|
||||
<TableRow
|
||||
key={jobInfo.id}
|
||||
hoverable={true}
|
||||
displayBorder={false}
|
||||
style={{ height: TABLE_ROW_MIN_HEIGHT, border: 2 }}
|
||||
>
|
||||
<TableRowColumn colSpan={5} style={labelStyle}>
|
||||
{jobInfo.title}
|
||||
</TableRowColumn>
|
||||
<TableRowColumn colSpan={3} style={labelStyle}>
|
||||
{jobInfo.department}
|
||||
</TableRowColumn>
|
||||
<TableRowColumn colSpan={4} style={labelStyle}>
|
||||
{jobInfo.office}
|
||||
</TableRowColumn>
|
||||
</TableRow>
|
||||
<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> {
|
||||
@@ -152,41 +122,57 @@ export class OpenPositions extends React.Component<OpenPositionsProps, OpenPosit
|
||||
}
|
||||
}
|
||||
}
|
||||
private _onCellClick(rowNumber: number): void {
|
||||
if (_.isUndefined(this.state.jobInfos)) {
|
||||
return;
|
||||
}
|
||||
const jobInfo = this.state.jobInfos[rowNumber];
|
||||
this._openJobInfoUrl(jobInfo);
|
||||
}
|
||||
|
||||
private _openJobInfoUrl(jobInfo: WebsiteBackendJobInfo): void {
|
||||
const url = jobInfo.url;
|
||||
utils.openUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
export interface JobInfoListItemProps {
|
||||
title?: string;
|
||||
description?: string;
|
||||
export interface JobInfoTableRowProps {
|
||||
className?: string;
|
||||
screenWidth: ScreenWidths;
|
||||
jobInfo: WebsiteBackendJobInfo;
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
}
|
||||
|
||||
const PlainJobInfoListItem: React.StatelessComponent<JobInfoListItemProps> = ({ title, description, onClick }) => (
|
||||
<div className="mb3" onClick={onClick}>
|
||||
<ListItem>
|
||||
<Text fontWeight="bold" fontSize="16px" fontColor={colors.mediumBlue}>
|
||||
{title + ' ›'}
|
||||
</Text>
|
||||
<Text className="pt1" fontSize="16px" fontColor={colors.darkGrey}>
|
||||
{description}
|
||||
</Text>
|
||||
</ListItem>
|
||||
</div>
|
||||
);
|
||||
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 JobInfoListItem = styled(PlainJobInfoListItem)`
|
||||
export const JobInfoTableRow = styled(PlainJobInfoTableRow)`
|
||||
cursor: pointer;
|
||||
background-color: ${colors.grey100};
|
||||
border-radius: 7px;
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { HeaderItem } from 'ts/pages/jobs/list/header_item';
|
||||
import { ListItem } from 'ts/pages/jobs/list/list_item';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
|
||||
const TEAM_ITEM_PROPS_COLUMN1: TeamItemProps[] = [
|
||||
{
|
||||
bulletColor: '#EB5757',
|
||||
title: 'User Growth',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
},
|
||||
{
|
||||
bulletColor: '#EB5757',
|
||||
title: 'Governance',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
},
|
||||
];
|
||||
const TEAM_ITEM_PROPS_COLUMN2: TeamItemProps[] = [
|
||||
{
|
||||
bulletColor: '#EB5757',
|
||||
title: 'Developer Tools',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
},
|
||||
{
|
||||
bulletColor: '#EB5757',
|
||||
title: 'Marketing',
|
||||
description:
|
||||
'Donec eget auctor mauris, a imperdiet ante. Ut a tellus ullamcorper, pharetra nibh sed, dignissim mauris. Quisque vel magna vitae nisi scelerisque commodo sed eget dolor. Maecenas vehicula orci',
|
||||
},
|
||||
];
|
||||
const HEADER_TEXT = 'Our Teams';
|
||||
const MINIMUM_ITEM_HEIGHT = 240;
|
||||
|
||||
export interface TeamsProps {
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
export const Teams = (props: TeamsProps) => (props.screenWidth === ScreenWidths.Sm ? <SmallLayout /> : <LargeLayout />);
|
||||
|
||||
const LargeLayout = () => (
|
||||
<div className="mx-auto max-width-4 clearfix pb4">
|
||||
<div className="col lg-col-6 md-col-6 col-12">
|
||||
<HeaderItem headerText={HEADER_TEXT} />
|
||||
{_.map(TEAM_ITEM_PROPS_COLUMN1, teamItemProps => <TeamItem {...teamItemProps} />)}
|
||||
</div>
|
||||
<div className="col lg-col-6 md-col-6 col-12">
|
||||
<HeaderItem headerText=" " />
|
||||
{_.map(TEAM_ITEM_PROPS_COLUMN2, teamItemProps => <TeamItem {...teamItemProps} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const SmallLayout = () => (
|
||||
<div>
|
||||
<HeaderItem headerText={HEADER_TEXT} />
|
||||
{_.map(_.concat(TEAM_ITEM_PROPS_COLUMN1, TEAM_ITEM_PROPS_COLUMN2), teamItemProps => (
|
||||
<TeamItem {...teamItemProps} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
interface TeamItemProps {
|
||||
bulletColor: string;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const TeamItem: React.StatelessComponent<TeamItemProps> = ({ bulletColor, title, description }) => {
|
||||
return (
|
||||
<div style={{ minHeight: MINIMUM_ITEM_HEIGHT }}>
|
||||
<ListItem bulletColor={bulletColor}>
|
||||
<Text fontWeight="bold" fontSize="16px" fontColor={colors.black}>
|
||||
{title}
|
||||
</Text>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Text className="pt1" fontSize="16px" lineHeight="2em" fontColor={colors.black}>
|
||||
{description}
|
||||
</Text>
|
||||
</ListItem>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { HeaderItem } from 'ts/pages/jobs/list/header_item';
|
||||
import { ListItem } from 'ts/pages/jobs/list/list_item';
|
||||
import { colors } from 'ts/style/colors';
|
||||
|
||||
const VALUE_ITEM_PROPS_LIST: ValueItemProps[] = [
|
||||
{
|
||||
bulletColor: '#6FCF97',
|
||||
title: 'Ethics/Doing the right thing',
|
||||
description: 'orem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
},
|
||||
{
|
||||
bulletColor: '#56CCF2',
|
||||
title: 'Consistently ship',
|
||||
description: 'orem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
},
|
||||
{
|
||||
bulletColor: '#EB5757',
|
||||
title: 'Focus on long term impact',
|
||||
description: 'orem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
},
|
||||
];
|
||||
|
||||
const HEADER_TEXT = 'Our Values';
|
||||
const VALUE_ITEM_MIN_HEIGHT = 150;
|
||||
|
||||
export const Values = () => {
|
||||
return (
|
||||
<div className="mx-auto max-width-4">
|
||||
<HeaderItem headerText={HEADER_TEXT} />
|
||||
{_.map(VALUE_ITEM_PROPS_LIST, valueItemProps => <ValueItem {...valueItemProps} />)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface ValueItemProps {
|
||||
bulletColor: string;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const ValueItem: React.StatelessComponent<ValueItemProps> = ({ bulletColor, title, description }) => {
|
||||
return (
|
||||
<div style={{ minHeight: VALUE_ITEM_MIN_HEIGHT }}>
|
||||
<ListItem bulletColor={bulletColor}>
|
||||
<Text fontWeight="bold" fontSize="16x" fontColor={colors.black}>
|
||||
{title}
|
||||
</Text>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Text className="pt1" fontSize="16x" lineHeight="2em" fontColor={colors.black}>
|
||||
{description}
|
||||
</Text>
|
||||
</ListItem>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -356,6 +356,7 @@ export enum WebsiteLegacyPaths {
|
||||
ZeroExJs = '/docs/0xjs',
|
||||
Web3Wrapper = '/docs/web3_wrapper',
|
||||
Deployer = '/docs/deployer',
|
||||
Jobs = '/jobs',
|
||||
}
|
||||
|
||||
export enum WebsitePaths {
|
||||
@@ -376,7 +377,7 @@ export enum WebsitePaths {
|
||||
Subproviders = '/docs/subproviders',
|
||||
OrderUtils = '/docs/order-utils',
|
||||
EthereumTypes = '/docs/ethereum-types',
|
||||
Jobs = '/jobs',
|
||||
Careers = '/careers',
|
||||
}
|
||||
|
||||
export enum DocPackages {
|
||||
|
||||
@@ -41,6 +41,7 @@ export const constants = {
|
||||
TAKER_FEE: new BigNumber(0),
|
||||
TESTNET_NAME: 'Kovan',
|
||||
NUMERAL_USD_FORMAT: '$0,0.00',
|
||||
EMAIL_JOBS: 'jobs@0xproject.com',
|
||||
PROJECT_URL_ETHFINEX: 'https://www.ethfinex.com/',
|
||||
PROJECT_URL_AMADEUS: 'http://amadeusrelay.org',
|
||||
PROJECT_URL_DDEX: 'https://ddex.io',
|
||||
@@ -92,4 +93,5 @@ export const constants = {
|
||||
URL_WEB3_LOG_ENTRY_EVENT: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L127',
|
||||
URL_WEB3_PROVIDER_DOCS: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L150',
|
||||
URL_BIGNUMBERJS_GITHUB: 'http://mikemcl.github.io/bignumber.js',
|
||||
URL_MISSION_AND_VALUES_BLOG_POST: 'https://blog.0xproject.com/the-0x-mission-and-values-181a58706f9f',
|
||||
};
|
||||
|
||||