diff options
author | Brandon Millman <brandon@0xproject.com> | 2018-07-26 06:31:54 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-26 06:31:54 +0800 |
commit | 35113487f1239a788d1bf975d716a911d8b69f56 (patch) | |
tree | 92fd5399435666136aac776690d34c018bc4bdd6 /packages/website/ts | |
parent | d836b0f81502baae5cfbd8949560e7f5ec37f780 (diff) | |
parent | 9ce8e10115c7a673ae03f3d9979b6a064d442238 (diff) | |
download | dexon-0x-contracts-35113487f1239a788d1bf975d716a911d8b69f56.tar.gz dexon-0x-contracts-35113487f1239a788d1bf975d716a911d8b69f56.tar.zst dexon-0x-contracts-35113487f1239a788d1bf975d716a911d8b69f56.zip |
Merge pull request #893 from 0xProject/feature/website/jobs-page-part2
Jobs page
Diffstat (limited to 'packages/website/ts')
-rw-r--r-- | packages/website/ts/components/footer.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/components/ui/container.tsx | 7 | ||||
-rw-r--r-- | packages/website/ts/components/ui/image.tsx | 6 | ||||
-rw-r--r-- | packages/website/ts/components/ui/text.tsx | 3 | ||||
-rw-r--r-- | packages/website/ts/index.tsx | 12 | ||||
-rw-r--r-- | packages/website/ts/pages/about/about.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/benefits.tsx | 206 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/jobs.tsx | 19 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/join_0x.tsx | 43 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/list/header_item.tsx | 26 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/list/list_item.tsx | 15 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/mission.tsx | 67 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/open_positions.tsx | 174 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/teams.tsx | 90 | ||||
-rw-r--r-- | packages/website/ts/pages/jobs/values.tsx | 60 | ||||
-rw-r--r-- | packages/website/ts/types.ts | 3 | ||||
-rw-r--r-- | packages/website/ts/utils/constants.ts | 2 |
17 files changed, 299 insertions, 438 deletions
diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx index 9fb332a98..6dcb5a0e9 100644 --- a/packages/website/ts/components/footer.tsx +++ b/packages/website/ts/components/footer.tsx @@ -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), diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx index 427cc6cc7..502069dee 100644 --- a/packages/website/ts/components/ui/container.tsx +++ b/packages/website/ts/components/ui/container.tsx @@ -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> ); diff --git a/packages/website/ts/components/ui/image.tsx b/packages/website/ts/components/ui/image.tsx index c4ff93531..c8d39352b 100644 --- a/packages/website/ts/components/ui/image.tsx +++ b/packages/website/ts/components/ui/image.tsx @@ -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} diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx index 315f72854..b71d8225b 100644 --- a/packages/website/ts/components/ui/text.tsx +++ b/packages/website/ts/components/ui/text.tsx @@ -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', diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 2a5c5e4f1..904a5f6df 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -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} /> diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx index 33581c938..b9bc906bd 100644 --- a/packages/website/ts/pages/about/about.tsx +++ b/packages/website/ts/pages/about/about.tsx @@ -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. diff --git a/packages/website/ts/pages/jobs/benefits.tsx b/packages/website/ts/pages/jobs/benefits.tsx index 006facc83..10443bfae 100644 --- a/packages/website/ts/pages/jobs/benefits.tsx +++ b/packages/website/ts/pages/jobs/benefits.tsx @@ -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[] = [ - { - 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', - }, +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: '#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', + iconSrc: 'images/jobs/heart-icon.svg', + text: 'Do the right thing', }, { - 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/ship-icon.svg', + text: 'Consistently ship', }, { - 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> -); +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 SmallLayout = () => ( - <div> - <FilledImage src={_.head(IMAGE_PATHS)} /> - <BenefitsList /> - </div> +const Header: React.StatelessComponent = ({ children }) => ( + <Container marginBottom="30px"> + <Text fontFamily="Roboto Mono" fontSize="24px" fontColor={colors.black}> + {children} + </Text> + </Container> ); -export const BenefitsList = () => { +interface BenefitsListProps { + className?: string; +} +const PlainBenefitsList: React.StatelessComponent<BenefitsListProps> = ({ className }) => { return ( - <div> - <HeaderItem headerText={HEADER_TEXT} /> - {_.map(BENEFIT_ITEM_PROPS_LIST, valueItemProps => <BenefitItem {...valueItemProps} />)} - </div> + <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 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]} /> - </div> - <div className="col lg-col-6 md-col-6 col-12" style={{ height: '100%' }}> - <FilledImage src={IMAGE_PATHS[2]} /> +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> - </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> + ); +}; diff --git a/packages/website/ts/pages/jobs/jobs.tsx b/packages/website/ts/pages/jobs/jobs.tsx index 38cefa832..5c45d79fa 100644 --- a/packages/website/ts/pages/jobs/jobs.tsx +++ b/packages/website/ts/pages/jobs/jobs.tsx @@ -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; - } } diff --git a/packages/website/ts/pages/jobs/join_0x.tsx b/packages/website/ts/pages/jobs/join_0x.tsx index 72cce3b89..daddb0dcf 100644 --- a/packages/website/ts/pages/jobs/join_0x.tsx +++ b/packages/website/ts/pages/jobs/join_0x.tsx @@ -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" diff --git a/packages/website/ts/pages/jobs/list/header_item.tsx b/packages/website/ts/pages/jobs/list/header_item.tsx deleted file mode 100644 index ac214904c..000000000 --- a/packages/website/ts/pages/jobs/list/header_item.tsx +++ /dev/null @@ -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> - ); -}; diff --git a/packages/website/ts/pages/jobs/list/list_item.tsx b/packages/website/ts/pages/jobs/list/list_item.tsx deleted file mode 100644 index 192433d39..000000000 --- a/packages/website/ts/pages/jobs/list/list_item.tsx +++ /dev/null @@ -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> - ); -}; diff --git a/packages/website/ts/pages/jobs/mission.tsx b/packages/website/ts/pages/jobs/mission.tsx index f7f874e04..28546f985 100644 --- a/packages/website/ts/pages/jobs/mission.tsx +++ b/packages/website/ts/pages/jobs/mission.tsx @@ -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> ); }; diff --git a/packages/website/ts/pages/jobs/open_positions.tsx b/packages/website/ts/pages/jobs/open_positions.tsx index e789795c1..b8442a9c4 100644 --- a/packages/website/ts/pages/jobs/open_positions.tsx +++ b/packages/website/ts/pages/jobs/open_positions.tsx @@ -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; } diff --git a/packages/website/ts/pages/jobs/teams.tsx b/packages/website/ts/pages/jobs/teams.tsx deleted file mode 100644 index 80b036396..000000000 --- a/packages/website/ts/pages/jobs/teams.tsx +++ /dev/null @@ -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> - ); -}; diff --git a/packages/website/ts/pages/jobs/values.tsx b/packages/website/ts/pages/jobs/values.tsx deleted file mode 100644 index c7c4d5726..000000000 --- a/packages/website/ts/pages/jobs/values.tsx +++ /dev/null @@ -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> - ); -}; diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 4d0496f6c..e1b5be39a 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -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 { diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts index 20441cd75..005d17823 100644 --- a/packages/website/ts/utils/constants.ts +++ b/packages/website/ts/utils/constants.ts @@ -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', }; |