diff options
Diffstat (limited to 'packages/website/ts/pages/instant')
-rw-r--r-- | packages/website/ts/pages/instant/action_link.tsx | 46 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/code_demo.tsx | 30 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/config_generator.tsx | 79 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/config_generator_address_input.tsx | 55 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/configurator.tsx | 72 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/features.tsx | 115 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/fee_percentage_slider.tsx | 77 | ||||
-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/rc-slider.css | 295 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/screenshots.tsx | 35 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/select.tsx | 74 |
13 files changed, 550 insertions, 534 deletions
diff --git a/packages/website/ts/pages/instant/action_link.tsx b/packages/website/ts/pages/instant/action_link.tsx deleted file mode 100644 index c196f03ef..000000000 --- a/packages/website/ts/pages/instant/action_link.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { colors } from 'ts/style/colors'; -import { utils } from 'ts/utils/utils'; - -export interface ActionLinkProps { - displayText: string; - linkSrc?: string; - onClick?: () => void; - fontSize?: number; - color?: string; - className?: string; -} - -export class ActionLink extends React.Component<ActionLinkProps> { - public static defaultProps = { - fontSize: 16, - color: colors.white, - }; - public render(): React.ReactNode { - const { displayText, fontSize, color, className } = this.props; - return ( - <Container className={`flex items-center ${className}`} onClick={this._handleClick} cursor="pointer"> - <Container> - <Text fontSize="16px" fontColor={color}> - {displayText} - </Text> - </Container> - <Container paddingTop="1px" paddingLeft="6px"> - <i className="zmdi zmdi-chevron-right bold" style={{ fontSize, color }} /> - </Container> - </Container> - ); - } - - private readonly _handleClick = (event: React.MouseEvent<HTMLElement>) => { - if (!_.isUndefined(this.props.onClick)) { - this.props.onClick(); - } else if (!_.isUndefined(this.props.linkSrc)) { - utils.openUrl(this.props.linkSrc); - } - }; -} diff --git a/packages/website/ts/pages/instant/code_demo.tsx b/packages/website/ts/pages/instant/code_demo.tsx index a3b5fe847..c59f148b8 100644 --- a/packages/website/ts/pages/instant/code_demo.tsx +++ b/packages/website/ts/pages/instant/code_demo.tsx @@ -2,9 +2,8 @@ import * as React from 'react'; import * as CopyToClipboard from 'react-copy-to-clipboard'; import SyntaxHighlighter from 'react-syntax-highlighter'; -import { Button } from 'ts/components/ui/button'; +import { Button } from 'ts/components/button'; import { Container } from 'ts/components/ui/container'; -import { colors } from 'ts/style/colors'; import { styled } from 'ts/style/theme'; import { zIndex } from 'ts/style/z_index'; @@ -12,7 +11,7 @@ const CustomPre = styled.pre` margin: 0px; line-height: 24px; overflow: scroll; - width: 600px; + width: 100%; height: 100%; max-height: 800px; border-radius: 4px; @@ -23,19 +22,21 @@ const CustomPre = styled.pre` border: none; } code:first-of-type { - background-color: #2a2a2a !important; + background-color: #060d0d !important; color: #999; - min-height: 98%; + min-height: 100%; text-align: center; - padding-right: 5px !important; - padding-left: 5px; margin-right: 15px; line-height: 25px; - padding-top: 10px; + padding: 10px 7px !important; } code:last-of-type { position: relative; top: 10px; + top: 0; + padding-top: 11px; + display: inline-block; + line-height: 25px; } `; @@ -130,7 +131,7 @@ const customStyle = { hljs: { display: 'block', overflowX: 'hidden', - background: colors.instantSecondaryBackground, + background: '#1B2625', color: 'white', fontSize: '12px', }, @@ -160,9 +161,7 @@ export class CodeDemo extends React.Component<CodeDemoProps, CodeDemoState> { <Container position="relative" height="100%"> <Container position="absolute" top="10px" right="10px" zIndex={zIndex.overlay - 1}> <CopyToClipboard text={this.props.children} onCopy={this._handleCopyClick}> - <Button fontSize="14px"> - <b>{copyButtonText}</b> - </Button> + <StyledButton>{copyButtonText}</StyledButton> </CopyToClipboard> </Container> <SyntaxHighlighter language="html" style={customStyle} showLineNumbers={true} PreTag={CustomPre}> @@ -175,3 +174,10 @@ export class CodeDemo extends React.Component<CodeDemoProps, CodeDemoState> { this.setState({ didCopyCode: true }); }; } + +const StyledButton = styled(Button)` + border-radius: 4px; + font-size: 15px; + font-weight: 400; + padding: 9px 21px 7px; +`; diff --git a/packages/website/ts/pages/instant/config_generator.tsx b/packages/website/ts/pages/instant/config_generator.tsx index fbeeeaeaf..e43d47119 100644 --- a/packages/website/ts/pages/instant/config_generator.tsx +++ b/packages/website/ts/pages/instant/config_generator.tsx @@ -4,11 +4,11 @@ import { assetDataUtils } from '@0x/order-utils'; import { ObjectMap } from '@0x/types'; import * as _ from 'lodash'; import * as React from 'react'; +import styled from 'styled-components'; import { CheckMark } from 'ts/components/ui/check_mark'; import { Container } from 'ts/components/ui/container'; import { MultiSelect } from 'ts/components/ui/multi_select'; -import { Select, SelectItemConfig } from 'ts/components/ui/select'; import { Spinner } from 'ts/components/ui/spinner'; import { Text } from 'ts/components/ui/text'; import { ConfigGeneratorAddressInput } from 'ts/pages/instant/config_generator_address_input'; @@ -17,6 +17,10 @@ import { colors } from 'ts/style/colors'; import { WebsitePaths } from 'ts/types'; import { constants } from 'ts/utils/constants'; +// New components +import { Heading } from 'ts/components/text'; +import { Select, SelectItemConfig } from 'ts/pages/instant/select'; + import { assetMetaDataMap } from '../../../../instant/src/data/asset_meta_data_map'; import { ERC20AssetMetaData, ZeroExInstantBaseConfig } from '../../../../instant/src/types'; @@ -59,8 +63,14 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps, Confi } return ( <Container minWidth="350px"> - <ConfigGeneratorSection title="Standard relayer API endpoint"> - <Select value={value.orderSource} items={this._generateItems()} /> + <ConfigGeneratorSection title="Liquidity Source"> + <Select + shouldIncludeEmpty={false} + id="" + value={value.orderSource} + items={this._generateItems()} + onChange={this._handleSRASelection.bind(this)} + /> </ConfigGeneratorSection> <ConfigGeneratorSection {...this._getTokenSelectorProps()}> {this._renderTokenMultiSelectOrSpinner()} @@ -110,14 +120,16 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps, Confi }; private readonly _generateItems = (): SelectItemConfig[] => { return _.map(SRA_ENDPOINTS, endpoint => ({ - text: endpoint, + label: endpoint, + value: endpoint, onClick: this._handleSRASelection.bind(this, endpoint), })); }; private readonly _handleAffiliatePercentageLearnMoreClick = (): void => { window.open(`${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`, '_blank'); }; - private readonly _handleSRASelection = (sraEndpoint: string) => { + private readonly _handleSRASelection = (event: React.ChangeEvent<HTMLSelectElement>) => { + const sraEndpoint = event.target.value; const newConfig: ZeroExInstantBaseConfig = { ...this.props.value, orderSource: sraEndpoint, @@ -249,15 +261,11 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps, Confi renderItemContent: (isSelected: boolean) => ( <Container className="flex items-center"> <Container marginRight="10px"> - <CheckMark isChecked={isSelected} /> + <CheckMark isChecked={isSelected} color={colors.brandLight} /> </Container> - <Text - fontSize="16px" - fontColor={isSelected ? colors.mediumBlue : colors.darkerGrey} - fontWeight={300} - > - <b>{metaData.symbol.toUpperCase()}</b> — {metaData.name} - </Text> + <CheckboxText isSelected={isSelected}> + {metaData.symbol.toUpperCase()} — {metaData.name} + </CheckboxText> </Container> ), onClick: this._handleTokenClick.bind(this, assetData), @@ -285,22 +293,11 @@ export const ConfigGeneratorSection: React.StatelessComponent<ConfigGeneratorSec }) => ( <Container marginBottom={marginBottom}> <Container marginBottom="10px" className="flex justify-between items-center"> - <Container> - <Text fontColor={colors.white} fontSize="16px" lineHeight="18px" display="inline"> - {title} - </Text> - {isOptional && ( - <Text fontColor={colors.grey} fontSize="16px" lineHeight="18px" display="inline"> - {' '} - (optional) - </Text> - )} - </Container> - {actionText && ( - <Text fontSize="12px" fontColor={colors.grey} onClick={onActionTextClick}> - {actionText} - </Text> - )} + <Heading size="small" marginBottom="0" isFlex={true}> + <span>{title}</span> + {isOptional && <OptionalText> Optional</OptionalText>} + </Heading> + {actionText && <OptionalAction onClick={onActionTextClick}>{actionText}</OptionalAction>} </Container> {children} </Container> @@ -309,3 +306,27 @@ export const ConfigGeneratorSection: React.StatelessComponent<ConfigGeneratorSec ConfigGeneratorSection.defaultProps = { marginBottom: '30px', }; + +const OptionalText = styled.span` + display: inline; + font-size: 14px; + color: #999999; + flex-shrink: 0; +`; + +interface CheckboxTextProps { + isSelected?: boolean; +} + +const CheckboxText = + styled.span < + CheckboxTextProps > + ` + font-size: 14px; + line-height: 18px; + color: ${props => (props.isSelected ? colors.brandDark : '#666666')} +`; + +const OptionalAction = styled(OptionalText)` + cursor: pointer; +`; diff --git a/packages/website/ts/pages/instant/config_generator_address_input.tsx b/packages/website/ts/pages/instant/config_generator_address_input.tsx index ccbaf4482..890e39da6 100644 --- a/packages/website/ts/pages/instant/config_generator_address_input.tsx +++ b/packages/website/ts/pages/instant/config_generator_address_input.tsx @@ -1,11 +1,13 @@ -import { colors } from '@0x/react-shared'; import { addressUtils } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; import { Container } from 'ts/components/ui/container'; -import { Input } from 'ts/components/ui/input'; -import { Text } from 'ts/components/ui/text'; + +import { Paragraph } from 'ts/components/text'; export interface ConfigGeneratorAddressInputProps { value?: string; @@ -16,6 +18,19 @@ export interface ConfigGeneratorAddressInputState { errMsg: string; } +export interface InputProps { + className?: string; + value?: string; + width?: string; + fontSize?: string; + fontColor?: string; + padding?: string; + placeholderColor?: string; + placeholder?: string; + backgroundColor?: string; + onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void; +} + export class ConfigGeneratorAddressInput extends React.Component< ConfigGeneratorAddressInputProps, ConfigGeneratorAddressInputState @@ -26,22 +41,13 @@ export class ConfigGeneratorAddressInput extends React.Component< public render(): React.ReactNode { const { errMsg } = this.state; const hasError = !_.isEmpty(errMsg); - const border = hasError ? '1px solid red' : undefined; return ( <Container height="80px"> - <Input - width="100%" - fontSize="16px" - padding="0.7em 1em" - value={this.props.value} - onChange={this._handleChange} - placeholder="0xe99...aa8da4" - border={border} - /> + <Input value={this.props.value} onChange={this._handleChange} placeholder="0xe99...aa8da4" /> <Container marginTop="5px" isHidden={!hasError} height="25px"> - <Text fontSize="14px" fontColor={colors.grey} fontStyle="italic"> + <Paragraph size="small" isNoMargin={true}> {errMsg} - </Text> + </Paragraph> </Container> </Container> ); @@ -57,3 +63,22 @@ export class ConfigGeneratorAddressInput extends React.Component< this.props.onChange(address, isValidAddress); }; } + +const PlainInput: React.StatelessComponent<InputProps> = ({ value, className, placeholder, onChange }) => ( + <input className={className} value={value} onChange={onChange} placeholder={placeholder} /> +); + +export const Input = styled(PlainInput)` + background-color: ${colors.white}; + color: ${colors.textDarkSecondary}; + font-size: 1rem; + width: 100%; + padding: 16px 20px 18px; + border-radius: 4px; + border: 1px solid transparent; + outline: none; + &::placeholder { + color: #333333; + opacity: 0.5; + } +`; diff --git a/packages/website/ts/pages/instant/configurator.tsx b/packages/website/ts/pages/instant/configurator.tsx index 2cb1a1c1c..a63e1752e 100644 --- a/packages/website/ts/pages/instant/configurator.tsx +++ b/packages/website/ts/pages/instant/configurator.tsx @@ -1,25 +1,22 @@ import * as _ from 'lodash'; import * as React from 'react'; +import styled from 'styled-components'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { ActionLink } from 'ts/pages/instant/action_link'; import { CodeDemo } from 'ts/pages/instant/code_demo'; import { ConfigGenerator } from 'ts/pages/instant/config_generator'; -import { colors } from 'ts/style/colors'; + +import { Link } from 'ts/components/link'; +import { Column, FlexWrap } from 'ts/components/newLayout'; +import { Heading } from 'ts/components/text'; import { WebsitePaths } from 'ts/types'; import { ZeroExInstantBaseConfig } from '../../../../instant/src/types'; -export interface ConfiguratorProps { - hash: string; -} - export interface ConfiguratorState { instantConfig: ZeroExInstantBaseConfig; } -export class Configurator extends React.Component<ConfiguratorProps> { +export class Configurator extends React.Component { public state: ConfiguratorState = { instantConfig: { orderSource: 'https://api.radarrelay.com/0x/v2/', @@ -31,36 +28,24 @@ export class Configurator extends React.Component<ConfiguratorProps> { }, }; public render(): React.ReactNode { - const { hash } = this.props; const codeToDisplay = this._generateCodeDemoCode(); return ( - <Container - className="flex justify-center py4 px3" - id={hash} - backgroundColor={colors.instantTertiaryBackground} - > - <Container className="mx3"> - <Container className="mb3"> - <Text fontSize="20px" lineHeight="28px" fontColor={colors.white} fontWeight={500}> - 0x Instant Configurator - </Text> - </Container> + <FlexWrap isFlex={true}> + <Column width="442px" padding="0 70px 0 0"> <ConfigGenerator value={this.state.instantConfig} onConfigChange={this._handleConfigChange} /> - </Container> - <Container className="mx3" height="550px"> - <Container className="mb3 flex justify-between"> - <Text fontSize="20px" lineHeight="28px" fontColor={colors.white} fontWeight={500}> + </Column> + <Column width="100%"> + <HeadingWrapper> + <Heading size="small" marginBottom="15px"> Code Snippet - </Text> - <ActionLink - displayText="Explore the Docs" - linkSrc={`${WebsitePaths.Wiki}#Get-Started-With-Instant`} - color={colors.grey} - /> - </Container> + </Heading> + <Link href={`${WebsitePaths.Wiki}#Get-Started-With-Instant`} isBlock={true} target="_blank"> + Explore the Docs + </Link> + </HeadingWrapper> <CodeDemo key={codeToDisplay}>{codeToDisplay}</CodeDemo> - </Container> - </Container> + </Column> + </FlexWrap> ); } private readonly _handleConfigChange = (config: ZeroExInstantBaseConfig) => { @@ -74,7 +59,7 @@ export class Configurator extends React.Component<ConfiguratorProps> { <html> <head> <meta charset="utf-8" /> - <script src="https://instant.0xproject.com/instant.js"></script> + <script src="https://instant.0x.org/instant.js"></script> </head> <body> <script> @@ -93,10 +78,10 @@ export class Configurator extends React.Component<ConfiguratorProps> { )}` : '' } - }, 'body'); - </script> - </body> -</html>`; + }, 'body'); + </script> + </body> + </html>`; }; private readonly _renderAvailableAssetDatasString = (availableAssetDatas: string[]): string => { const stringAvailableAssetDatas = availableAssetDatas.map(assetData => `'${assetData}'`); @@ -108,3 +93,12 @@ export class Configurator extends React.Component<ConfiguratorProps> { )}\n ]`; }; } + +const HeadingWrapper = styled.div` + display: flex; + justify-content: space-between; + + a { + transform: translateY(-8px); + } +`; diff --git a/packages/website/ts/pages/instant/features.tsx b/packages/website/ts/pages/instant/features.tsx deleted file mode 100644 index ed98ceb53..000000000 --- a/packages/website/ts/pages/instant/features.tsx +++ /dev/null @@ -1,115 +0,0 @@ -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 { ActionLink, ActionLinkProps } from 'ts/pages/instant/action_link'; -import { colors } from 'ts/style/colors'; -import { ScreenWidths, WebsitePaths } from 'ts/types'; - -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: `${WebsitePaths.Wiki}#Get-Started-With-Instant`, - }; - 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: `${WebsitePaths.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: `${WebsitePaths.Docs}/asset-buyer`, - }, - ]} - screenWidth={props.screenWidth} - /> - </Container> - ); -}; - -interface FeatureItemProps { - imgSrc: string; - title: string; - description: string; - linkInfos: ActionLinkProps[]; - 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 => ( - <Container key={linkInfo.displayText} marginRight="32px"> - <ActionLink {...linkInfo} /> - </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/fee_percentage_slider.tsx b/packages/website/ts/pages/instant/fee_percentage_slider.tsx index d76cee58f..c4d9f908f 100644 --- a/packages/website/ts/pages/instant/fee_percentage_slider.tsx +++ b/packages/website/ts/pages/instant/fee_percentage_slider.tsx @@ -1,64 +1,36 @@ import Slider from 'rc-slider'; -import 'rc-slider/assets/index.css'; import * as React from 'react'; +import styled from 'styled-components'; +import 'ts/pages/instant/rc-slider.css'; -import { Text } from 'ts/components/ui/text'; import { colors } from 'ts/style/colors'; -import { injectGlobal } from 'ts/style/theme'; const SliderWithTooltip = (Slider as any).createSliderWithTooltip(Slider); // tslint:disable-next-line:no-unused-expression -injectGlobal` - .rc-slider-tooltip-inner { - box-shadow: none !important; - background-color: ${colors.white} !important; - border-radius: 4px !important; - padding: 3px 12px !important; - height: auto !important; - position: relative; - top: 7px; - &: after { - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-width: 6px; - bottom: 100%; - left: 100%; - border-bottom-color: ${colors.white}; - margin-left: -60%; - } - } - .rc-slider-disabled { - background-color: inherit !important; - } -`; export interface FeePercentageSliderProps { value: number; - isDisabled: boolean; + isDisabled?: boolean; onChange: (value: number) => void; } export class FeePercentageSlider extends React.Component<FeePercentageSliderProps> { public render(): React.ReactNode { return ( - <SliderWithTooltip - disabled={this.props.isDisabled} + <StyledSlider min={0} max={0.05} step={0.0025} value={this.props.value} + disabled={this.props.isDisabled} onChange={this.props.onChange} tipFormatter={this._feePercentageSliderFormatter} - tipProps={{ placement: 'bottom' }} + tipProps={{ placement: 'bottom', overlayStyle: { backgroundColor: '#fff', borderRadius: '4px' } }} trackStyle={{ - backgroundColor: '#b4b4b4', + backgroundColor: colors.brandLight, }} railStyle={{ - backgroundColor: '#696969', + backgroundColor: 'rgba(255, 255, 255, 0.2)', }} handleStyle={{ border: 'none', @@ -72,6 +44,37 @@ export class FeePercentageSlider extends React.Component<FeePercentageSliderProp ); } private readonly _feePercentageSliderFormatter = (value: number): React.ReactNode => { - return <Text fontColor={colors.black} fontSize="14px" fontWeight={700}>{`${(value * 100).toFixed(2)}%`}</Text>; + return <Text>{`${(value * 100).toFixed(2)}%`}</Text>; }; } + +const StyledSlider = styled(SliderWithTooltip)` + .rc-slider-tooltip__inner { + box-shadow: none !important; + background-color: ${colors.white} !important; + border-radius: 4px !important; + padding: 3px 12px !important; + height: auto !important; + position: relative; + top: 7px; + &:after { + border: solid transparent; + content: ' '; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + border-width: 6px; + bottom: 100%; + left: 100%; + border-bottom-color: ${colors.white}; + margin-left: -60%; + } + } +`; + +const Text = styled.span` + color: #000000; + font-size: 12px; + line-height: 18px; +`; diff --git a/packages/website/ts/pages/instant/instant.tsx b/packages/website/ts/pages/instant/instant.tsx deleted file mode 100644 index d72585bfa..000000000 --- a/packages/website/ts/pages/instant/instant.tsx +++ /dev/null @@ -1,87 +0,0 @@ -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, WebsitePaths } 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(`${WebsitePaths.Wiki}#Get-Started-With-Instant`); - } 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 deleted file mode 100644 index da3f09faa..000000000 --- a/packages/website/ts/pages/instant/introducing_0x_instant.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from 'react'; - -import { Button } from 'ts/components/ui/button'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { colors } from 'ts/style/colors'; -import { ScreenWidths } from 'ts/types'; - -export interface Introducing0xInstantProps { - screenWidth: ScreenWidths; - onCTAClick: () => void; -} - -export const Introducing0xInstant = (props: Introducing0xInstantProps) => { - const isSmallScreen = props.screenWidth === ScreenWidths.Sm; - const zero = ( - <Text fontColor={colors.white} fontSize="42px" fontWeight="600" fontFamily="Roboto Mono" Tag="span"> - 0 - </Text> - ); - const title = isSmallScreen ? ( - <div> - Introducing<br /> - {zero}x Instant - </div> - ) : ( - <div>Introducing {zero}x Instant</div> - ); - return ( - <div className="clearfix center lg-pt4 md-pt4" style={{ backgroundColor: colors.instantPrimaryBackground }}> - <div className="mx-auto inline-block align-middle py4" style={{ lineHeight: '44px', textAlign: 'center' }}> - <Container className="sm-center sm-pt3"> - <Text fontColor={colors.white} fontSize="42px" lineHeight="52px" fontWeight="600"> - {title} - </Text> - </Container> - <Container className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 sm-center" maxWidth="600px"> - <Text fontColor={colors.grey500} fontSize="20px" lineHeight="32px" fontFamily="Roboto Mono"> - A free and flexible way to offer simple crypto - <br /> purchasing in any app or website. - </Text> - </Container> - <div className="py3"> - <Button - type="button" - backgroundColor={colors.mediumBlue} - fontColor={colors.white} - fontSize="18px" - onClick={props.onCTAClick} - > - Get Started - </Button> - </div> - </div> - </div> - ); -}; diff --git a/packages/website/ts/pages/instant/need_more.tsx b/packages/website/ts/pages/instant/need_more.tsx deleted file mode 100644 index 70aea7363..000000000 --- a/packages/website/ts/pages/instant/need_more.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import * as React from 'react'; - -import { Button } from 'ts/components/ui/button'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { colors } from 'ts/style/colors'; -import { ScreenWidths, WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { utils } from 'ts/utils/utils'; - -export interface NeedMoreProps { - screenWidth: ScreenWidths; -} -export const NeedMore = (props: NeedMoreProps) => { - const isSmallScreen = props.screenWidth === ScreenWidths.Sm; - const backgroundColor = isSmallScreen ? colors.instantTertiaryBackground : colors.instantSecondaryBackground; - const className = isSmallScreen ? 'flex flex-column items-center' : 'flex'; - const marginRight = isSmallScreen ? undefined : '200px'; - return ( - <Container className="flex flex-column items-center py4 px3" backgroundColor={backgroundColor}> - <Container className={className}> - <Container className="sm-center" marginRight={marginRight}> - <Text fontColor={colors.white} fontSize="32px" lineHeight="45px"> - Need more flexibility? - </Text> - <Text fontColor={colors.grey500} fontSize="18px" lineHeight="27px"> - View our full documentation or reach out if you have any questions. - </Text> - </Container> - <Container className="py3 flex"> - <Container marginRight="20px"> - <Button - type="button" - backgroundColor={colors.white} - fontColor={backgroundColor} - fontSize="18px" - onClick={onGetInTouchClick} - > - Get in Touch - </Button> - </Container> - <Button - type="button" - backgroundColor={colors.mediumBlue} - fontColor={colors.white} - fontSize="18px" - onClick={onDocsClick} - > - Explore the Docs - </Button> - </Container> - </Container> - </Container> - ); -}; - -const onGetInTouchClick = () => { - utils.openUrl(constants.URL_ZEROEX_CHAT); -}; -const onDocsClick = () => { - utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`); -}; diff --git a/packages/website/ts/pages/instant/rc-slider.css b/packages/website/ts/pages/instant/rc-slider.css new file mode 100644 index 000000000..63038324e --- /dev/null +++ b/packages/website/ts/pages/instant/rc-slider.css @@ -0,0 +1,295 @@ +.rc-slider { + position: relative; + height: 14px; + padding: 5px 0; + width: 100%; + border-radius: 6px; + -ms-touch-action: none; + touch-action: none; + box-sizing: border-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.rc-slider * { + box-sizing: border-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.rc-slider-rail { + position: absolute; + width: 100%; + background-color: #e9e9e9; + height: 4px; + border-radius: 6px; +} + +.rc-slider-track { + position: absolute; + left: 0; + height: 4px; + border-radius: 6px; + background-color: #abe2fb; +} + +.rc-slider-handle { + position: absolute; + margin-left: -7px; + margin-top: -5px; + width: 14px; + height: 14px; + cursor: pointer; + cursor: -webkit-grab; + cursor: grab; + border-radius: 50%; + border: solid 2px #96dbfa; + background-color: #fff; + -ms-touch-action: pan-x; + touch-action: pan-x; +} + +.rc-slider-handle:focus { + border-color: #57c5f7; + box-shadow: 0 0 0 5px #96dbfa; + outline: none; +} + +.rc-slider-handle-click-focused:focus { + border-color: #96dbfa; + box-shadow: unset; +} + +.rc-slider-handle:hover { + border-color: #57c5f7; +} + +.rc-slider-handle:active { + border-color: #57c5f7; + box-shadow: 0 0 5px #57c5f7; + cursor: -webkit-grabbing; + cursor: grabbing; +} + +.rc-slider-mark { + position: absolute; + top: 18px; + left: 0; + width: 100%; + font-size: 12px; +} + +.rc-slider-mark-text { + position: absolute; + display: inline-block; + vertical-align: middle; + text-align: center; + cursor: pointer; + color: #999; +} + +.rc-slider-mark-text-active { + color: #666; +} + +.rc-slider-step { + position: absolute; + width: 100%; + height: 4px; + background: transparent; +} + +.rc-slider-dot { + position: absolute; + bottom: -2px; + margin-left: -4px; + width: 8px; + height: 8px; + border: 2px solid #e9e9e9; + background-color: #fff; + cursor: pointer; + border-radius: 50%; + vertical-align: middle; +} + +.rc-slider-dot-active { + border-color: #96dbfa; +} + +.rc-slider-disabled { + opacity: 0.2; +} + +.rc-slider-disabled .rc-slider-track { + background-color: #ccc; +} + +.rc-slider-disabled .rc-slider-handle, +.rc-slider-disabled .rc-slider-dot { + border-color: #ccc; + box-shadow: none; + background-color: #fff; + cursor: not-allowed; +} + +.rc-slider-disabled .rc-slider-mark-text, +.rc-slider-disabled .rc-slider-dot { + cursor: not-allowed !important; +} + +.rc-slider-vertical { + width: 14px; + height: 100%; + padding: 0 5px; +} + +.rc-slider-vertical .rc-slider-rail { + height: 100%; + width: 4px; +} + +.rc-slider-vertical .rc-slider-track { + left: 5px; + bottom: 0; + width: 4px; +} + +.rc-slider-vertical .rc-slider-handle { + margin-left: -5px; + margin-bottom: -7px; + -ms-touch-action: pan-y; + touch-action: pan-y; +} + +.rc-slider-vertical .rc-slider-mark { + top: 0; + left: 18px; + height: 100%; +} + +.rc-slider-vertical .rc-slider-step { + height: 100%; + width: 4px; +} + +.rc-slider-vertical .rc-slider-dot { + left: 2px; + margin-bottom: -4px; +} + +.rc-slider-vertical .rc-slider-dot:first-child { + margin-bottom: -4px; +} + +.rc-slider-vertical .rc-slider-dot:last-child { + margin-bottom: -4px; +} + +.rc-slider-tooltip-zoom-down-enter, +.rc-slider-tooltip-zoom-down-appear { + animation-duration: .3s; + animation-fill-mode: both; + display: block !important; + animation-play-state: paused; +} + +.rc-slider-tooltip-zoom-down-leave { + animation-duration: .3s; + animation-fill-mode: both; + display: block !important; + animation-play-state: paused; +} + +.rc-slider-tooltip-zoom-down-enter.rc-slider-tooltip-zoom-down-enter-active, +.rc-slider-tooltip-zoom-down-appear.rc-slider-tooltip-zoom-down-appear-active { + animation-name: rcSliderTooltipZoomDownIn; + animation-play-state: running; +} + +.rc-slider-tooltip-zoom-down-leave.rc-slider-tooltip-zoom-down-leave-active { + animation-name: rcSliderTooltipZoomDownOut; + animation-play-state: running; +} + +.rc-slider-tooltip-zoom-down-enter, +.rc-slider-tooltip-zoom-down-appear { + transform: scale(0, 0); + animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); +} + +.rc-slider-tooltip-zoom-down-leave { + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); +} + +@keyframes rcSliderTooltipZoomDownIn { + 0% { + opacity: 0; + transform-origin: 50% 100%; + transform: scale(0, 0); + } + + 100% { + transform-origin: 50% 100%; + transform: scale(1, 1); + } +} + +@keyframes rcSliderTooltipZoomDownOut { + 0% { + transform-origin: 50% 100%; + transform: scale(1, 1); + } + + 100% { + opacity: 0; + transform-origin: 50% 100%; + transform: scale(0, 0); + } +} + +.rc-slider-tooltip { + position: absolute; + left: -9999px; + top: -9999px; + visibility: visible; + box-sizing: border-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.rc-slider-tooltip * { + box-sizing: border-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.rc-slider-tooltip-hidden { + display: none; +} + +.rc-slider-tooltip-placement-top { + padding: 4px 0 8px 0; +} + +.rc-slider-tooltip-inner { + padding: 4px 6px 4px; + min-width: 24px; + height: 24px; + font-size: 12px; + line-height: 1; + color: #000; + text-align: center; + text-decoration: none; +} + +.rc-slider-tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.rc-slider-tooltip-placement-top .rc-slider-tooltip-arrow { + bottom: 4px; + left: 50%; + margin-left: -4px; + border-width: 4px 4px 0; + border-top-color: #6c6c6c; +} diff --git a/packages/website/ts/pages/instant/screenshots.tsx b/packages/website/ts/pages/instant/screenshots.tsx deleted file mode 100644 index 7dcf17fd1..000000000 --- a/packages/website/ts/pages/instant/screenshots.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Container } from 'ts/components/ui/container'; -import { colors } from 'ts/style/colors'; -import { ScreenWidths } from 'ts/types'; - -export interface ScreenshotsProps { - screenWidth: ScreenWidths; -} - -export const Screenshots = (props: ScreenshotsProps) => { - const isSmallScreen = props.screenWidth === ScreenWidths.Sm; - const images = isSmallScreen - ? [ - 'images/instant/rep_screenshot.png', - 'images/instant/dai_screenshot.png', - 'images/instant/gods_screenshot.png', - ] - : [ - 'images/instant/nmr_screenshot.png', - 'images/instant/kitty_screenshot.png', - 'images/instant/rep_screenshot.png', - 'images/instant/dai_screenshot.png', - 'images/instant/gods_screenshot.png', - 'images/instant/gnt_screenshot.png', - ]; - return ( - <Container backgroundColor={colors.instantPrimaryBackground} className="py3 flex justify-center"> - {_.map(images, image => { - return <img className="px1 flex-none" width="300px" height="420px" src={image} key={image} />; - })} - </Container> - ); -}; diff --git a/packages/website/ts/pages/instant/select.tsx b/packages/website/ts/pages/instant/select.tsx new file mode 100644 index 000000000..d4146cfb0 --- /dev/null +++ b/packages/website/ts/pages/instant/select.tsx @@ -0,0 +1,74 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +export interface SelectItemConfig { + label: string; + value?: string; + onClick?: () => void; +} + +interface SelectProps { + value?: string; + id: string; + items: SelectItemConfig[]; + emptyText?: string; + onChange?: (ev: React.ChangeEvent<HTMLSelectElement>) => void; + shouldIncludeEmpty: boolean; +} + +export const Select: React.FunctionComponent<SelectProps> = ({ + value, + id, + items, + shouldIncludeEmpty, + emptyText, + onChange, +}) => { + return ( + <Container> + <StyledSelect id={id} onChange={onChange}> + {shouldIncludeEmpty && <option value="">{emptyText}</option>} + {items.map((item, index) => ( + <option + key={`${id}-item-${index}`} + value={item.value} + selected={item.value === value} + onClick={item.onClick} + > + {item.label} + </option> + ))} + </StyledSelect> + <Caret width="12" height="7" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M11 1L6 6 1 1" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> + </Caret> + </Container> + ); +}; + +Select.defaultProps = { + emptyText: 'Select...', + shouldIncludeEmpty: true, +}; + +const Container = styled.div` + background-color: #fff; + border-radius: 4px; + display: flex; + width: 100%; + position: relative; +`; + +const StyledSelect = styled.select` + appearance: none; + border: 0; + font-size: 1rem; + width: 100%; + padding: 20px 20px 20px 20px; +`; + +const Caret = styled.svg` + position: absolute; + right: 20px; + top: calc(50% - 4px); +`; |