diff options
Diffstat (limited to 'packages/website/ts')
-rw-r--r-- | packages/website/ts/components/ui/image.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/components/ui/text.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/containers/instant.ts | 30 | ||||
-rw-r--r-- | packages/website/ts/index.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/configurator.tsx | 12 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/features.tsx | 146 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/instant.tsx | 87 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/introducing_0x_instant.tsx | 57 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/need_more.tsx | 62 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/screenshots.tsx | 35 | ||||
-rw-r--r-- | packages/website/ts/style/colors.ts | 3 | ||||
-rw-r--r-- | packages/website/ts/types.ts | 1 |
12 files changed, 438 insertions, 1 deletions
diff --git a/packages/website/ts/components/ui/image.tsx b/packages/website/ts/components/ui/image.tsx index c8d39352b..d698ddaa0 100644 --- a/packages/website/ts/components/ui/image.tsx +++ b/packages/website/ts/components/ui/image.tsx @@ -10,6 +10,7 @@ export interface ImageProps { height?: string | number; maxWidth?: string | number; maxHeight?: string | number; + additionalStyle?: React.CSSProperties; } interface ImageState { imageLoadFailed: boolean; @@ -30,6 +31,7 @@ export class Image extends React.Component<ImageProps, ImageState> { onError={this._onError.bind(this)} src={src} style={{ + ...this.props.additionalStyle, borderRadius: this.props.borderRadius, maxWidth: this.props.maxWidth, maxHeight: this.props.maxHeight, diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx index c13e21913..87239a021 100644 --- a/packages/website/ts/components/ui/text.tsx +++ b/packages/website/ts/components/ui/text.tsx @@ -3,7 +3,7 @@ import { darken } from 'polished'; import * as React from 'react'; import { styled } from 'ts/style/theme'; -export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i'; +export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i' | 'span'; export interface TextProps { className?: string; diff --git a/packages/website/ts/containers/instant.ts b/packages/website/ts/containers/instant.ts new file mode 100644 index 000000000..12ae7454e --- /dev/null +++ b/packages/website/ts/containers/instant.ts @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Instant as InstantComponent, InstantProps } from 'ts/pages/instant/instant'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { ScreenWidths } from 'ts/types'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + translate: Translate; + screenWidth: ScreenWidths; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, _ownProps: InstantProps): ConnectedState => ({ + translate: state.translate, + screenWidth: state.screenWidth, +}); + +const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Instant: React.ComponentClass<InstantProps> = connect(mapStateToProps, mapDispatchToProps)( + InstantComponent, +); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index faf7d8c87..050c201a3 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -7,6 +7,7 @@ import { MetaTags } from 'ts/components/meta_tags'; import { About } from 'ts/containers/about'; import { DocsHome } from 'ts/containers/docs_home'; import { FAQ } from 'ts/containers/faq'; +import { Instant } from 'ts/containers/instant'; import { Jobs } from 'ts/containers/jobs'; import { Landing } from 'ts/containers/landing'; import { LaunchKit } from 'ts/containers/launch_kit'; @@ -92,6 +93,7 @@ render( <Route exact={true} path="/" component={Landing as any} /> <Redirect from="/otc" to={`${WebsitePaths.Portal}`} /> <Route path={WebsitePaths.LaunchKit} component={LaunchKit as any} /> + <Route path={WebsitePaths.Instant} component={Instant as any} /> <Route path={WebsitePaths.Careers} component={Jobs as any} /> <Route path={WebsitePaths.Portal} component={LazyPortal} /> <Route path={WebsitePaths.FAQ} component={FAQ as any} /> diff --git a/packages/website/ts/pages/instant/configurator.tsx b/packages/website/ts/pages/instant/configurator.tsx new file mode 100644 index 000000000..c836739bb --- /dev/null +++ b/packages/website/ts/pages/instant/configurator.tsx @@ -0,0 +1,12 @@ +import * as React from 'react'; + +import { Container } from 'ts/components/ui/container'; +import { colors } from 'ts/style/colors'; + +export interface ConfiguratorProps { + hash: string; +} + +export const Configurator = (props: ConfiguratorProps) => ( + <Container id={props.hash} height="400px" backgroundColor={colors.instantTertiaryBackground} /> +); diff --git a/packages/website/ts/pages/instant/features.tsx b/packages/website/ts/pages/instant/features.tsx new file mode 100644 index 000000000..9c1668c1c --- /dev/null +++ b/packages/website/ts/pages/instant/features.tsx @@ -0,0 +1,146 @@ +import * as _ from 'lodash'; +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'; +import { utils } from 'ts/utils/utils'; + +export interface FeatureProps { + screenWidth: ScreenWidths; + onGetStartedClick: () => void; +} + +export const Features = (props: FeatureProps) => { + const isSmallScreen = props.screenWidth === ScreenWidths.Sm; + const getStartedLinkInfo = { + displayText: 'Get started', + onClick: props.onGetStartedClick, + }; + const exploreTheDocsLinkInfo = { + displayText: 'Explore the docs', + linkSrc: `${utils.getCurrentBaseUrl()}/wiki#Get-Started`, + }; + const tokenLinkInfos = isSmallScreen ? [getStartedLinkInfo] : [getStartedLinkInfo, exploreTheDocsLinkInfo]; + return ( + <Container backgroundColor={colors.instantSecondaryBackground} className="py3 flex flex-column px3"> + <FeatureItem + imgSrc="images/instant/feature_1.svg" + title="Support ERC-20 and ERC-721 tokens" + description="Seamlessly integrate token purchasing into your product experience by offering digital assets ranging from in-game items to stablecoins." + linkInfos={tokenLinkInfos} + screenWidth={props.screenWidth} + /> + <FeatureItem + imgSrc="images/instant/feature_2.svg" + title="Generate revenue for your business" + description="With just a few lines of code, you can earn up to 5% in affiliate fees on every transaction from your crypto wallet or dApp." + linkInfos={[ + { + displayText: 'Learn about affiliate fees', + linkSrc: `${utils.getCurrentBaseUrl()}/wiki#Learn-About-Affiliate-Fees`, + }, + ]} + screenWidth={props.screenWidth} + /> + <FeatureItem + imgSrc="images/instant/feature_3.svg" + title="Easy and Flexible Integration" + description="Use our out-of-the-box design or customize the user interface by integrating the AssetBuyer engine. You can also tap into 0x networked liquidity or choose your own liquidity pool." + linkInfos={[ + { + displayText: 'Explore AssetBuyer', + linkSrc: `${utils.getCurrentBaseUrl()}/docs/asset-buyer`, + }, + ]} + screenWidth={props.screenWidth} + /> + </Container> + ); +}; + +interface LinkInfo { + displayText: string; + linkSrc?: string; + onClick?: () => void; +} + +interface FeatureItemProps { + imgSrc: string; + title: string; + description: string; + linkInfos: LinkInfo[]; + screenWidth: ScreenWidths; +} + +const FeatureItem = (props: FeatureItemProps) => { + const { imgSrc, title, description, linkInfos, screenWidth } = props; + const isLargeScreen = screenWidth === ScreenWidths.Lg; + const maxWidth = isLargeScreen ? '500px' : undefined; + const image = ( + <Container className="center" minWidth="435px" maxHeight="225px"> + <Image src={imgSrc} additionalStyle={{ filter: 'drop-shadow(0px 4px 4px rgba(0,0,0,.25))' }} /> + </Container> + ); + const info = ( + <Container maxWidth={maxWidth}> + <Text fontSize="24px" lineHeight="34px" fontColor={colors.white} fontWeight={500}> + {title} + </Text> + <Container marginTop="28px"> + <Text fontFamily="Roboto Mono" fontSize="14px" lineHeight="2em" fontColor={colors.grey500}> + {description} + </Text> + </Container> + <Container className="flex" marginTop="28px"> + {_.map(linkInfos, linkInfo => { + const onClick = (event: React.MouseEvent<HTMLElement>) => { + if (!_.isUndefined(linkInfo.onClick)) { + linkInfo.onClick(); + } else if (!_.isUndefined(linkInfo.linkSrc)) { + utils.openUrl(linkInfo.linkSrc); + } + }; + return ( + <Container + key={linkInfo.linkSrc} + className="flex items-center" + marginRight="32px" + onClick={onClick} + cursor="pointer" + > + <Container> + <Text fontSize="16px" fontColor={colors.white}> + {linkInfo.displayText} + </Text> + </Container> + <Container paddingTop="1px" paddingLeft="6px"> + <i + className="zmdi zmdi-chevron-right bold" + style={{ fontSize: 16, color: colors.white }} + /> + </Container> + </Container> + ); + })} + </Container> + </Container> + ); + return ( + <Container className="flex flex-column items-center py4 px3"> + {isLargeScreen ? ( + <Container className="flex"> + {image} + <Container marginLeft="115px">{info}</Container> + </Container> + ) : ( + <Container className="flex flex-column items-center" width="100%"> + {image} + <Container marginTop="48px">{info}</Container> + </Container> + )} + </Container> + ); +}; diff --git a/packages/website/ts/pages/instant/instant.tsx b/packages/website/ts/pages/instant/instant.tsx new file mode 100644 index 000000000..fa6bd1c33 --- /dev/null +++ b/packages/website/ts/pages/instant/instant.tsx @@ -0,0 +1,87 @@ +import { utils as sharedUtils } from '@0x/react-shared'; +import * as _ from 'lodash'; +import * as React from 'react'; +import * as DocumentTitle from 'react-document-title'; + +import { Footer } from 'ts/components/footer'; +import { MetaTags } from 'ts/components/meta_tags'; +import { TopBar } from 'ts/components/top_bar/top_bar'; +import { Container } from 'ts/components/ui/container'; +import { Configurator } from 'ts/pages/instant/configurator'; +import { Features } from 'ts/pages/instant/features'; +import { Introducing0xInstant } from 'ts/pages/instant/introducing_0x_instant'; +import { NeedMore } from 'ts/pages/instant/need_more'; +import { Screenshots } from 'ts/pages/instant/screenshots'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { colors } from 'ts/style/colors'; +import { ScreenWidths } from 'ts/types'; +import { Translate } from 'ts/utils/translate'; +import { utils } from 'ts/utils/utils'; + +export interface InstantProps { + location: Location; + translate: Translate; + dispatcher: Dispatcher; + screenWidth: ScreenWidths; +} + +export interface InstantState {} + +const CONFIGURATOR_HASH = 'configure'; +const THROTTLE_TIMEOUT = 100; +const DOCUMENT_TITLE = '0x Instant'; +const DOCUMENT_DESCRIPTION = '0x Instant'; + +export class Instant extends React.Component<InstantProps, InstantState> { + // TODO: consolidate this small screen scaffolding into one place (its being used in portal and docs as well) + private readonly _throttledScreenWidthUpdate: () => void; + public constructor(props: InstantProps) { + super(props); + this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + } + public componentDidMount(): void { + window.addEventListener('resize', this._throttledScreenWidthUpdate); + window.scrollTo(0, 0); + } + public render(): React.ReactNode { + return ( + <Container overflowX="hidden"> + <MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} /> + <DocumentTitle title={DOCUMENT_TITLE} /> + <TopBar + blockchainIsLoaded={false} + location={this.props.location} + style={{ backgroundColor: colors.instantPrimaryBackground, position: 'relative' }} + translate={this.props.translate} + isNightVersion={true} + /> + <Container backgroundColor={colors.instantPrimaryBackground} /> + <Introducing0xInstant screenWidth={this.props.screenWidth} onCTAClick={this._onGetStartedClick} /> + <Screenshots screenWidth={this.props.screenWidth} /> + <Features screenWidth={this.props.screenWidth} onGetStartedClick={this._onGetStartedClick} /> + {!this._isSmallScreen() && <Configurator hash={CONFIGURATOR_HASH} />} + <NeedMore screenWidth={this.props.screenWidth} /> + <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} /> + </Container> + ); + } + private readonly _onGetStartedClick = () => { + if (this._isSmallScreen()) { + utils.openUrl(`${utils.getCurrentBaseUrl()}/wiki#Get-Started`); + } else { + this._scrollToConfigurator(); + } + }; + private _isSmallScreen(): boolean { + const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; + return isSmallScreen; + } + private _scrollToConfigurator(): void { + sharedUtils.setUrlHash(CONFIGURATOR_HASH); + sharedUtils.scrollToHash(CONFIGURATOR_HASH, ''); + } + private _updateScreenWidth(): void { + const newScreenWidth = utils.getScreenWidth(); + this.props.dispatcher.updateScreenWidth(newScreenWidth); + } +} diff --git a/packages/website/ts/pages/instant/introducing_0x_instant.tsx b/packages/website/ts/pages/instant/introducing_0x_instant.tsx new file mode 100644 index 000000000..da3f09faa --- /dev/null +++ b/packages/website/ts/pages/instant/introducing_0x_instant.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; + +import { Button } from 'ts/components/ui/button'; +import { Container } from 'ts/components/ui/container'; +import { Text } from 'ts/components/ui/text'; +import { colors } from 'ts/style/colors'; +import { ScreenWidths } from 'ts/types'; + +export interface Introducing0xInstantProps { + screenWidth: ScreenWidths; + onCTAClick: () => void; +} + +export const Introducing0xInstant = (props: Introducing0xInstantProps) => { + const isSmallScreen = props.screenWidth === ScreenWidths.Sm; + const zero = ( + <Text fontColor={colors.white} fontSize="42px" fontWeight="600" fontFamily="Roboto Mono" Tag="span"> + 0 + </Text> + ); + const title = isSmallScreen ? ( + <div> + Introducing<br /> + {zero}x Instant + </div> + ) : ( + <div>Introducing {zero}x Instant</div> + ); + return ( + <div className="clearfix center lg-pt4 md-pt4" style={{ backgroundColor: colors.instantPrimaryBackground }}> + <div className="mx-auto inline-block align-middle py4" style={{ lineHeight: '44px', textAlign: 'center' }}> + <Container className="sm-center sm-pt3"> + <Text fontColor={colors.white} fontSize="42px" lineHeight="52px" fontWeight="600"> + {title} + </Text> + </Container> + <Container className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 sm-center" maxWidth="600px"> + <Text fontColor={colors.grey500} fontSize="20px" lineHeight="32px" fontFamily="Roboto Mono"> + A free and flexible way to offer simple crypto + <br /> purchasing in any app or website. + </Text> + </Container> + <div className="py3"> + <Button + type="button" + backgroundColor={colors.mediumBlue} + fontColor={colors.white} + fontSize="18px" + onClick={props.onCTAClick} + > + Get Started + </Button> + </div> + </div> + </div> + ); +}; diff --git a/packages/website/ts/pages/instant/need_more.tsx b/packages/website/ts/pages/instant/need_more.tsx new file mode 100644 index 000000000..e6d5c3694 --- /dev/null +++ b/packages/website/ts/pages/instant/need_more.tsx @@ -0,0 +1,62 @@ +import * as React from 'react'; + +import { Button } from 'ts/components/ui/button'; +import { Container } from 'ts/components/ui/container'; +import { Text } from 'ts/components/ui/text'; +import { colors } from 'ts/style/colors'; +import { ScreenWidths } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; + +export interface NeedMoreProps { + screenWidth: ScreenWidths; +} +export const NeedMore = (props: NeedMoreProps) => { + const isSmallScreen = props.screenWidth === ScreenWidths.Sm; + const backgroundColor = isSmallScreen ? colors.instantTertiaryBackground : colors.instantSecondaryBackground; + const className = isSmallScreen ? 'flex flex-column items-center' : 'flex'; + const marginRight = isSmallScreen ? undefined : '200px'; + return ( + <Container className="flex flex-column items-center py4 px3" backgroundColor={backgroundColor}> + <Container className={className}> + <Container className="sm-center" marginRight={marginRight}> + <Text fontColor={colors.white} fontSize="32px" lineHeight="45px"> + Need more flexibility? + </Text> + <Text fontColor={colors.grey500} fontSize="18px" lineHeight="27px"> + View our full documentation or reach out if you have any questions. + </Text> + </Container> + <Container className="py3 flex"> + <Container marginRight="20px"> + <Button + type="button" + backgroundColor={colors.white} + fontColor={backgroundColor} + fontSize="18px" + onClick={onGetInTouchClick} + > + Get in Touch + </Button> + </Container> + <Button + type="button" + backgroundColor={colors.mediumBlue} + fontColor={colors.white} + fontSize="18px" + onClick={onDocsClick} + > + Explore the Docs + </Button> + </Container> + </Container> + </Container> + ); +}; + +const onGetInTouchClick = () => { + utils.openUrl(constants.URL_ZEROEX_CHAT); +}; +const onDocsClick = () => { + utils.openUrl(`${utils.getCurrentBaseUrl()}/wiki#Get-Started`); +}; diff --git a/packages/website/ts/pages/instant/screenshots.tsx b/packages/website/ts/pages/instant/screenshots.tsx new file mode 100644 index 000000000..7dcf17fd1 --- /dev/null +++ b/packages/website/ts/pages/instant/screenshots.tsx @@ -0,0 +1,35 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { Container } from 'ts/components/ui/container'; +import { colors } from 'ts/style/colors'; +import { ScreenWidths } from 'ts/types'; + +export interface ScreenshotsProps { + screenWidth: ScreenWidths; +} + +export const Screenshots = (props: ScreenshotsProps) => { + const isSmallScreen = props.screenWidth === ScreenWidths.Sm; + const images = isSmallScreen + ? [ + 'images/instant/rep_screenshot.png', + 'images/instant/dai_screenshot.png', + 'images/instant/gods_screenshot.png', + ] + : [ + 'images/instant/nmr_screenshot.png', + 'images/instant/kitty_screenshot.png', + 'images/instant/rep_screenshot.png', + 'images/instant/dai_screenshot.png', + 'images/instant/gods_screenshot.png', + 'images/instant/gnt_screenshot.png', + ]; + return ( + <Container backgroundColor={colors.instantPrimaryBackground} className="py3 flex justify-center"> + {_.map(images, image => { + return <img className="px1 flex-none" width="300px" height="420px" src={image} key={image} />; + })} + </Container> + ); +}; diff --git a/packages/website/ts/style/colors.ts b/packages/website/ts/style/colors.ts index 0620bae0f..f89dfc86e 100644 --- a/packages/website/ts/style/colors.ts +++ b/packages/website/ts/style/colors.ts @@ -13,6 +13,9 @@ const appColors = { jobsPageOpenPositionRow: sharedColors.grey100, metaMaskOrange: '#f68c24', metaMaskTransparentOrange: 'rgba(255, 248, 242, 0.8)', + instantPrimaryBackground: '#222222', + instantSecondaryBackground: '#333333', + instantTertiaryBackground: '#444444', }; export const colors = { diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 89c477085..9c4b8a018 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -353,6 +353,7 @@ export enum WebsitePaths { FAQ = '/faq', About = '/about', LaunchKit = '/launch-kit', + Instant = '/instant', Whitepaper = '/pdfs/0x_white_paper.pdf', SmartContracts = '/docs/contracts', Connect = '/docs/connect', |