Files
protocol/packages/website/ts/pages/landing/landing.tsx
Fabio Berger cbfed99bc6 Merge branch 'v2-prototype' into fixes/misc-small-fixes
* v2-prototype:
  Remove TranslatedText
  Fix prettier
  Add back UMD bundles for 0x.js
  Move portal disclaimer to the account management section
  Move prices into portal
  Use stricter check for subscribe input text
  Make buttons stack on mobile
  Do not show subscribe form if language is not english
  Address PR feedback
  Lint and cleanup
  Implement subscription form
  Add styled-components and polished
  Have basic newsletter subscribe form working
2018-06-06 11:10:27 +02:00

803 lines
33 KiB
TypeScript

import { colors } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import DocumentTitle = require('react-document-title');
import { Link } from 'react-router-dom';
import { Footer } from 'ts/components/footer';
import { SubscribeForm } from 'ts/components/forms/subscribe_form';
import { TopBar } from 'ts/components/top_bar/top_bar';
import { CallToAction } from 'ts/components/ui/button';
import { Container } from 'ts/components/ui/container';
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;
}
interface AssetType {
title: string;
imageUrl: string;
style?: React.CSSProperties;
}
interface UseCase {
imageUrl: string;
type: string;
description: string;
classNames: string;
style?: React.CSSProperties;
projectIconUrls: string[];
}
interface Project {
logoFileName: string;
projectUrl: string;
}
const THROTTLE_TIMEOUT = 100;
const WHATS_NEW_TITLE = '18 ideas for 0x relayers in 2018';
const WHATS_NEW_URL = 'https://blog.0xproject.com/18-ideas-for-0x-relayers-in-2018-80a1498b955f';
const relayersAndDappProjects: Project[] = [
{
logoFileName: 'ercdex.png',
projectUrl: constants.PROJECT_URL_ERC_DEX,
},
{
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: 'dydx.png',
projectUrl: constants.PROJECT_URL_DYDX,
},
{
logoFileName: 'ethfinex.png',
projectUrl: constants.PROJECT_URL_ETHFINEX,
},
{
logoFileName: 'melonport.png',
projectUrl: constants.PROJECT_URL_MELONPORT,
},
{
logoFileName: 'maker.png',
projectUrl: constants.PROJECT_URL_MAKER,
},
{
logoFileName: 'dharma.png',
projectUrl: constants.PROJECT_URL_DHARMA,
},
{
logoFileName: 'lendroid.png',
projectUrl: constants.PROJECT_URL_LENDROID,
},
{
logoFileName: 'district0x.png',
projectUrl: constants.PROJECT_URL_DISTRICT_0X,
},
{
logoFileName: 'aragon.png',
projectUrl: constants.PROJECT_URL_ARAGON,
},
{
logoFileName: 'blocknet.png',
projectUrl: constants.PROJECT_URL_BLOCKNET,
},
{
logoFileName: 'imtoken.png',
projectUrl: constants.PROJECT_URL_IMTOKEN,
},
{
logoFileName: 'augur.png',
projectUrl: constants.PROJECT_URL_AUGUR,
},
{
logoFileName: 'anx.png',
projectUrl: constants.PROJECT_URL_OPEN_ANX,
},
];
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 _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(
relayersAndDappProjects,
this.props.translate.get(Key.ProjectsHeader, Deco.Upper),
colors.projectsGrey,
false,
)}
{this._renderTokenizationSection()}
{this._renderProtocolSection()}
{this._renderProjects(
relayerProjects,
this.props.translate.get(Key.RelayersHeader, Deco.Upper),
colors.heroGrey,
true,
)}
{this._renderInfoBoxes()}
{this._renderBuildingBlocksSection()}
{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 buttonLabelStyle: React.CSSProperties = {
textTransform: 'none',
fontSize: isSmallScreen ? 12 : 14,
fontWeight: 400,
};
const lightButtonStyle: React.CSSProperties = {
borderRadius: 6,
border: '1px solid #D8D8D8',
lineHeight: '33px',
height: 38,
};
const left = 'col lg-col-7 md-col-7 col-12 lg-pl4 md-pl4 sm-pl0 sm-px3 sm-center';
return (
<div className="clearfix py4" style={{ backgroundColor: colors.heroGrey }}>
<div className="mx-auto max-width-4 clearfix">
{this._renderWhatsNew()}
<div className="lg-pt4 md-pt4 sm-pt2 lg-pb4 md-pb4 lg-mt4 md-mt4 sm-mt2 sm-mb4 clearfix">
<div className="col lg-col-5 md-col-5 col-12 sm-center">
<img src="/images/landing/hero_chip_image.png" height={isSmallScreen ? 300 : 395} />
</div>
<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',
}}
>
<div
className="sm-pb2"
style={{
fontFamily: 'Roboto Mono',
fontSize: isSmallScreen ? 26 : 34,
}}
>
{this.props.translate.get(Key.TopHeader, Deco.Cap)}
</div>
<div
className="pt2 h5 sm-mx-auto"
style={{
maxWidth: 446,
fontFamily: 'Roboto Mono',
lineHeight: 1.7,
fontWeight: 300,
}}
>
{this.props.translate.get(Key.TopTagline)}
</div>
<Container className="pt3 clearfix sm-mx-auto" maxWidth="390px">
<div className="lg-pr2 md-pr2 lg-col lg-col-6 sm-center sm-col sm-col-12 mb2">
<Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
<CallToAction width="175px" type="light">
{this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
</CallToAction>
</Link>
</div>
<div className="lg-col lg-col-6 sm-center sm-col sm-col-12">
<a
href={constants.URL_ZEROEX_CHAT}
target="_blank"
className="text-decoration-none"
>
<CallToAction width="175px">
{this.props.translate.get(Key.CommunityCallToAction, Deco.Cap)}
</CallToAction>
</a>
</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} target="_blank" className="inline-block text-decoration-none">
<div className="flex sm-pl0 md-pl2 lg-pl0" style={{ fontFamily: 'Roboto Mono', fontWeight: 600 }}>
<div
className="mr1 px1"
style={{
backgroundColor: colors.lightTurquois,
borderRadius: 3,
color: colors.heroGrey,
height: 23,
}}
>
New
</div>
<div style={{ color: colors.darkGrey }}>{WHATS_NEW_TITLE}</div>
</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>
);
});
const titleStyle: React.CSSProperties = {
fontFamily: 'Roboto Mono',
color: colors.grey,
fontWeight: 300,
letterSpacing: 3,
};
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={titleStyle}>
{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.Wiki}#List-of-Projects-Using-0x-Protocol`}
className="text-decoration-none underline"
style={{ color: 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._renderAssetTypes()}</div>
</div>
</div>
{!isSmallScreen && this._renderTokenCloud()}
</div>
</div>
);
}
private _renderProtocolSection(): React.ReactNode {
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
return (
<div className="clearfix pt4" style={{ backgroundColor: colors.heroGrey }}>
<div className="mx-auto max-width-4 pt4 clearfix">
<div className="col lg-col-6 md-col-6 col-12 sm-center">
<img src="/images/landing/relayer_diagram.png" height={isSmallScreen ? 326 : 426} />
</div>
<div
className="col lg-col-6 md-col-6 col-12 lg-pr3 md-pr3 sm-mx-auto"
style={{
color: colors.beigeWhite,
maxWidth: isSmallScreen ? 'none' : 445,
height: 430,
lineHeight: '430px',
}}
>
<div
className="inline-block lg-align-middle md-align-middle sm-align-top"
style={{ lineHeight: '43px' }}
>
<div
className="lg-h1 md-h1 sm-h2 pb1 sm-pt3 sm-center"
style={{ fontFamily: 'Roboto Mono' }}
>
<div>{this.props.translate.get(Key.OffChainOrderRelay, Deco.Cap)}</div>
<div> {this.props.translate.get(Key.OonChainSettlement, Deco.Cap)}</div>
</div>
<div
className="pb2 pt2 h5 sm-center sm-px3 sm-mx-auto"
style={{
fontFamily: 'Roboto Mono',
lineHeight: 1.7,
fontWeight: 300,
maxWidth: 445,
}}
>
{this.props.translate.get(Key.OffChainOnChainDescription, Deco.Cap)}
</div>
</div>
</div>
</div>
</div>
);
}
private _renderBuildingBlocksSection(): React.ReactNode {
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
const descriptionStyle: React.CSSProperties = {
fontFamily: 'Roboto Mono',
lineHeight: isSmallScreen ? 1.5 : 2,
fontWeight: 300,
fontSize: 15,
maxWidth: isSmallScreen ? 375 : 'none',
};
const callToActionStyle: React.CSSProperties = {
fontFamily: 'Roboto Mono',
fontSize: 15,
fontWeight: 300,
maxWidth: isSmallScreen ? 375 : 441,
};
return (
<div className="clearfix lg-pt4 md-pt4" style={{ backgroundColor: colors.heroGrey }}>
<div className="mx-auto max-width-4 lg-pt4 md-pt4 lg-mb4 md-mb4 sm-mb2 clearfix">
{isSmallScreen && this._renderBlockChipImage()}
<div
className="col lg-col-6 md-col-6 col-12 lg-pr3 md-pr3 sm-px3"
style={{ color: colors.beigeWhite }}
>
<div
className="pb1 lg-pt4 md-pt4 sm-pt3 lg-h1 md-h1 sm-h2 sm-px3 sm-center"
style={{ fontFamily: 'Roboto Mono' }}
>
{this.props.translate.get(Key.BuildingBlockSectionHeader, Deco.Cap)}
</div>
<div className="pb3 pt2 sm-mx-auto sm-center" style={descriptionStyle}>
{this.props.translate.get(Key.BuildingBlockSectionDescription, Deco.Cap)}
</div>
<div className="sm-mx-auto sm-center" style={callToActionStyle}>
{this.props.translate.get(Key.DevToolsPrompt, Deco.Cap)}{' '}
<Link
to={WebsitePaths.ZeroExJs}
className="text-decoration-none underline"
style={{ color: colors.beigeWhite, fontFamily: 'Roboto Mono' }}
>
0x.js
</Link>{' '}
{this.props.translate.get(Key.And)}{' '}
<Link
to={WebsitePaths.SmartContracts}
className="text-decoration-none underline"
style={{ color: colors.beigeWhite, fontFamily: 'Roboto Mono' }}
>
{this.props.translate.get(Key.SmartContract)}
</Link>{' '}
{this.props.translate.get(Key.Docs)}
</div>
</div>
{!isSmallScreen && this._renderBlockChipImage()}
</div>
</div>
);
}
private _renderBlockChipImage(): React.ReactNode {
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
return (
<div className="col lg-col-6 md-col-6 col-12 sm-center">
<img src="/images/landing/0x_chips.png" height={isSmallScreen ? 240 : 368} />
</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 _renderAssetTypes(): React.ReactNode {
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
const assetTypes: AssetType[] = [
{
title: this.props.translate.get(Key.Currency, Deco.Cap),
imageUrl: '/images/landing/currency.png',
},
{
title: this.props.translate.get(Key.TraditionalAssets, Deco.Cap),
imageUrl: '/images/landing/stocks.png',
style: {
paddingLeft: isSmallScreen ? 41 : 56,
paddingRight: isSmallScreen ? 41 : 56,
},
},
{
title: this.props.translate.get(Key.DigitalGoods, Deco.Cap),
imageUrl: '/images/landing/digital_goods.png',
},
];
const assets = _.map(assetTypes, (assetType: AssetType) => {
const style = _.isUndefined(assetType.style) ? {} : assetType.style;
return (
<div key={`asset-${assetType.title}`} className="center" style={{ opacity: 0.8, ...style }}>
<div>
<img src={assetType.imageUrl} height="80" />
</div>
<div
style={{
fontFamily: 'Roboto Mono',
fontSize: 13.5,
fontWeight: 400,
color: colors.darkestGrey,
lineHeight: 1.4,
}}
>
{assetType.title}
</div>
</div>
);
});
return assets;
}
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: '',
},
{
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',
},
{
title: this.props.translate.get(Key.BenefitThreeTitle, Deco.Cap),
description: this.props.translate.get(Key.BenefitThreeDescription, Deco.Cap),
imageUrl: '/images/landing/open_source.png',
classNames: 'right',
},
];
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}>
<div>
<img src={boxContent.imageUrl} style={{ height: 210 }} />
</div>
<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>
);
});
const titleStyle: React.CSSProperties = {
fontFamily: 'Roboto Mono',
color: colors.grey,
fontWeight: 300,
letterSpacing: 3,
};
return (
<div className="clearfix" style={{ backgroundColor: colors.heroGrey }}>
<div className="center pb3 pt4" style={titleStyle}>
{this.props.translate.get(Key.BenefitsHeader, Deco.Upper)}
</div>
<div className="mx-auto pb4 sm-mt2 clearfix" style={{ maxWidth: '60em' }}>
{boxes}
</div>
</div>
);
}
private _renderUseCases(): React.ReactNode {
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
const useCases: UseCase[] = [
{
imageUrl: '/images/landing/governance_icon.png',
type: this.props.translate.get(Key.DecentralizedGovernance, Deco.Upper),
description: this.props.translate.get(Key.DecentralizedGovernanceDescription, Deco.Cap),
projectIconUrls: ['/images/landing/aragon.png'],
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),
projectIconUrls: ['/images/landing/augur.png'],
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),
projectIconUrls: ['/images/landing/maker.png'],
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),
projectIconUrls: ['/images/landing/dharma.png', '/images/landing/lendroid.png'],
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),
projectIconUrls: ['/images/landing/melonport.png'],
classNames: 'lg-pl2 md-pl2 lg-col-6 md-col-6',
style: { width: 291, marginTop: !isSmallScreen ? 38 : 0 },
},
];
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: 104,
}}
>
{useCase.description}
</div>
</div>
</div>
);
});
return (
<div className="clearfix pb4 lg-pt2 md-pt2 sm-pt4" style={{ backgroundColor: colors.heroGrey }}>
<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 buttonLabelStyle: React.CSSProperties = {
textTransform: 'none',
fontSize: 15,
fontWeight: 400,
};
const lightButtonStyle: React.CSSProperties = {
borderRadius: 6,
border: `1px solid ${colors.grey500}`,
lineHeight: '33px',
height: 49,
};
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.ZeroExJs} className="text-decoration-none">
<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,
});
}
}
private _onLanguageSelected(language: Language): void {
this.props.dispatcher.updateSelectedLanguage(language);
}
} // tslint:disable:max-file-line-count