diff options
author | fragosti <francesco.agosti93@gmail.com> | 2018-11-30 07:57:35 +0800 |
---|---|---|
committer | fragosti <francesco.agosti93@gmail.com> | 2018-11-30 07:57:35 +0800 |
commit | f80768cae0c2fdb71237bbdddecc67aec1c1f67f (patch) | |
tree | d3c310e026c37889e1c0f7c4d709107e16a858fc /packages | |
parent | 0af07bcf49f62aeeed4aa5ae7bf0e4d5835836e9 (diff) | |
download | dexon-sol-tools-f80768cae0c2fdb71237bbdddecc67aec1c1f67f.tar dexon-sol-tools-f80768cae0c2fdb71237bbdddecc67aec1c1f67f.tar.gz dexon-sol-tools-f80768cae0c2fdb71237bbdddecc67aec1c1f67f.tar.bz2 dexon-sol-tools-f80768cae0c2fdb71237bbdddecc67aec1c1f67f.tar.lz dexon-sol-tools-f80768cae0c2fdb71237bbdddecc67aec1c1f67f.tar.xz dexon-sol-tools-f80768cae0c2fdb71237bbdddecc67aec1c1f67f.tar.zst dexon-sol-tools-f80768cae0c2fdb71237bbdddecc67aec1c1f67f.zip |
feat: add Select component and use for configurator
Diffstat (limited to 'packages')
-rw-r--r-- | packages/website/ts/components/ui/container.tsx | 33 | ||||
-rw-r--r-- | packages/website/ts/components/ui/select.tsx | 168 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/action_link.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/code_demo.tsx | 3 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/config_generator.tsx | 38 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/configurator.tsx | 70 | ||||
-rw-r--r-- | packages/website/ts/pages/instant/features.tsx | 2 |
7 files changed, 285 insertions, 31 deletions
diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx index 7eab2a50f..cd0ed9986 100644 --- a/packages/website/ts/components/ui/container.tsx +++ b/packages/website/ts/components/ui/container.tsx @@ -1,6 +1,9 @@ import { TextAlignProperty } from 'csstype'; +import { darken } from 'polished'; import * as React from 'react'; +import { styled } from 'ts/style/theme'; + type StringOrNum = string | number; export type ContainerTag = 'div' | 'span'; @@ -17,10 +20,13 @@ export interface ContainerProps { paddingLeft?: StringOrNum; backgroundColor?: string; background?: string; + border?: string; + borderTop?: string; borderRadius?: StringOrNum; borderBottomLeftRadius?: StringOrNum; borderBottomRightRadius?: StringOrNum; borderBottom?: StringOrNum; + borderColor?: string; maxWidth?: StringOrNum; maxHeight?: StringOrNum; width?: StringOrNum; @@ -42,10 +48,23 @@ export interface ContainerProps { id?: string; onClick?: (event: React.MouseEvent<HTMLElement>) => void; overflowX?: 'scroll' | 'hidden' | 'auto' | 'visible'; + shouldDarkenOnHover?: boolean; + shouldAddBoxShadowOnHover?: boolean; } -export const Container: React.StatelessComponent<ContainerProps> = props => { - const { children, className, Tag, isHidden, id, onClick, ...style } = props; +export const PlainContainer: React.StatelessComponent<ContainerProps> = props => { + const { + children, + className, + Tag, + isHidden, + id, + onClick, + shouldDarkenOnHover, + shouldAddBoxShadowOnHover, + // tslint:disable-next-line:trailing-comma + ...style + } = props; const visibility = isHidden ? 'hidden' : undefined; return ( <Tag id={id} style={{ ...style, visibility }} className={className} onClick={onClick}> @@ -54,6 +73,16 @@ export const Container: React.StatelessComponent<ContainerProps> = props => { ); }; +export const Container = styled(PlainContainer)` + &:hover { + ${props => + props.shouldDarkenOnHover + ? `background-color: ${props.backgroundColor ? darken(0.05, props.backgroundColor) : 'none'} !important` + : ''}; + ${props => (props.shouldAddBoxShadowOnHover ? 'box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)' : '')}; + } +`; + Container.defaultProps = { Tag: 'div', }; diff --git a/packages/website/ts/components/ui/select.tsx b/packages/website/ts/components/ui/select.tsx new file mode 100644 index 000000000..abf202c67 --- /dev/null +++ b/packages/website/ts/components/ui/select.tsx @@ -0,0 +1,168 @@ +import { colors } from '@0x/react-shared'; +import * as _ from 'lodash'; +import * as React from 'react'; + +import { zIndex } from 'ts/style/z_index'; + +import { Container } from './container'; +import { Overlay } from './overlay'; +import { Text } from './text'; + +export interface SelectItemConfig { + text: string; + onClick?: () => void; +} + +export interface SelectProps { + value: string; + label?: string; + items: SelectItemConfig[]; + onOpen?: () => void; + border?: string; + fontSize?: string; + iconSize?: number; + textColor?: string; + labelColor?: string; + backgroundColor?: string; +} + +export interface SelectState { + isOpen: boolean; +} + +export class Select extends React.Component<SelectProps, SelectState> { + public static defaultProps = { + items: [] as SelectItemConfig[], + textColor: colors.black, + backgroundColor: colors.white, + fontSize: '16px', + iconSize: 25, + }; + public state: SelectState = { + isOpen: false, + }; + public render(): React.ReactNode { + const { value, label, items, border, textColor, labelColor, backgroundColor, fontSize, iconSize } = this.props; + const { isOpen } = this.state; + const hasItems = !_.isEmpty(items); + const borderRadius = isOpen ? '4px 4px 0px 0px' : '4px'; + return ( + <React.Fragment> + {isOpen && ( + <Overlay + style={{ + zIndex: zIndex.overlay, + backgroundColor: 'rgba(255, 255, 255, 0)', + }} + onClick={this._closeDropdown} + /> + )} + <Container position="relative"> + <Container + cursor={hasItems ? 'pointer' : undefined} + onClick={this._handleDropdownClick} + borderRadius={borderRadius} + border={border} + backgroundColor={backgroundColor} + padding="0.8em" + width="100%" + > + <Container className="flex justify-between"> + <Text fontSize={fontSize} fontColor={textColor}> + {value} + </Text> + <Container> + {label && ( + <Text fontSize={fontSize} fontColor={labelColor}> + {label} + </Text> + )} + {hasItems && ( + <Container marginLeft="5px" display="inline-block" position="relative" bottom="2px"> + <i + className="zmdi zmdi-chevron-down" + style={{ fontSize: iconSize, color: colors.darkGrey }} + /> + </Container> + )} + </Container> + </Container> + </Container> + {isOpen && ( + <Container + width="100%" + position="absolute" + onClick={this._closeDropdown} + zIndex={zIndex.aboveOverlay} + > + {_.map(items, (item, index) => ( + <SelectItem + key={item.text} + {...item} + isLast={index === items.length - 1} + backgroundColor={backgroundColor} + textColor={textColor} + border={border} + /> + ))} + </Container> + )} + </Container> + </React.Fragment> + ); + } + private readonly _handleDropdownClick = (): void => { + if (_.isEmpty(this.props.items)) { + return; + } + const isOpen = !this.state.isOpen; + this.setState({ + isOpen, + }); + + if (isOpen && this.props.onOpen) { + this.props.onOpen(); + } + }; + private readonly _closeDropdown = (): void => { + this.setState({ + isOpen: false, + }); + }; +} + +export interface SelectItemProps extends SelectItemConfig { + text: string; + onClick?: () => void; + isLast: boolean; + backgroundColor?: string; + border?: string; + textColor?: string; + fontSize?: string; +} + +export const SelectItem: React.StatelessComponent<SelectItemProps> = ({ + text, + onClick, + isLast, + border, + backgroundColor, + textColor, + fontSize, +}) => ( + <Container + onClick={onClick} + cursor="pointer" + backgroundColor={backgroundColor} + padding="0.8em" + borderTop="0" + border={border} + shouldDarkenOnHover={true} + borderRadius={isLast ? '0px 0px 4px 4px' : undefined} + width="100%" + > + <Text fontSize={fontSize} fontColor={textColor}> + {text} + </Text> + </Container> +); diff --git a/packages/website/ts/pages/instant/action_link.tsx b/packages/website/ts/pages/instant/action_link.tsx index 8a0bf24ff..5612dc25b 100644 --- a/packages/website/ts/pages/instant/action_link.tsx +++ b/packages/website/ts/pages/instant/action_link.tsx @@ -41,7 +41,7 @@ export class ActionLink extends React.Component<ActionLinkProps> { ); } - private _handleClick = (event: React.MouseEvent<HTMLElement>) => { + private readonly _handleClick = (event: React.MouseEvent<HTMLElement>) => { if (!_.isUndefined(this.props.onClick)) { this.props.onClick(); } else if (!_.isUndefined(this.props.linkSrc)) { diff --git a/packages/website/ts/pages/instant/code_demo.tsx b/packages/website/ts/pages/instant/code_demo.tsx index 4f44a6160..e9ecad40d 100644 --- a/packages/website/ts/pages/instant/code_demo.tsx +++ b/packages/website/ts/pages/instant/code_demo.tsx @@ -1,11 +1,8 @@ import * as React from 'react'; import SyntaxHighlighter from 'react-syntax-highlighter'; -import { atelierCaveDark } from 'react-syntax-highlighter/styles/hljs'; import { colors } from 'ts/style/colors'; import { styled } from 'ts/style/theme'; -import { Container } from 'ts/components/ui/container'; - const CustomPre = styled.pre` margin: 0px; line-height: 24px; diff --git a/packages/website/ts/pages/instant/config_generator.tsx b/packages/website/ts/pages/instant/config_generator.tsx new file mode 100644 index 000000000..d63975e31 --- /dev/null +++ b/packages/website/ts/pages/instant/config_generator.tsx @@ -0,0 +1,38 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { Container } from 'ts/components/ui/container'; +import { Select, SelectItemConfig } from 'ts/components/ui/select'; + +import { ZeroExInstantBaseConfig } from '../../../../instant/src/types'; + +export interface ConfigGeneratorProps { + value: ZeroExInstantBaseConfig; + onConfigChange: (config: ZeroExInstantBaseConfig) => void; +} + +const SRA_ENDPOINTS = ['https://api.radarrelay.com/0x/v2/', 'https://api.openrelay.xyz/v2/']; + +export class ConfigGenerator extends React.Component<ConfigGeneratorProps> { + public render(): React.ReactNode { + const { value } = this.props; + return ( + <Container> + <Select value={value.orderSource as string} items={this._generateItems()} /> + </Container> + ); + } + private readonly _generateItems = (): SelectItemConfig[] => { + return _.map(SRA_ENDPOINTS, endpoint => ({ + text: endpoint, + onClick: this._handleSRASelection.bind(this, endpoint), + })); + }; + private readonly _handleSRASelection = (sraEndpoint: string) => { + const newConfig = { + ...this.props.value, + orderSource: sraEndpoint, + }; + this.props.onConfigChange(newConfig); + }; +} diff --git a/packages/website/ts/pages/instant/configurator.tsx b/packages/website/ts/pages/instant/configurator.tsx index 29a3e2b1e..cf9985675 100644 --- a/packages/website/ts/pages/instant/configurator.tsx +++ b/packages/website/ts/pages/instant/configurator.tsx @@ -4,34 +4,56 @@ 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 { ZeroExInstantBaseConfig } from '../../../../instant/src/types'; + export interface ConfiguratorProps { hash: string; } -export const Configurator = (props: ConfiguratorProps) => ( - <Container - className="flex justify-center py4 px3" - id={props.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> - <Container height="400px" width="300px" backgroundColor="white" /> - </Container> - <Container className="mx3"> - <Container className="mb3 flex justify-between"> - <Text fontSize="20px" lineHeight="28px" fontColor={colors.white} fontWeight={500}> - Code Snippet - </Text> - <ActionLink displayText="Explore the Docs" linkSrc="/docs/instant" color={colors.grey} /> +export interface ConfiguratorState { + instantConfig: ZeroExInstantBaseConfig; +} + +export class Configurator extends React.Component<ConfiguratorProps> { + public state = { + instantConfig: { + orderSource: 'https://api.radarrelay.com/0x/v2/', + }, + }; + public render(): React.ReactNode { + const { hash } = this.props; + 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> + <ConfigGenerator value={this.state.instantConfig} onConfigChange={this._handleConfigChange} /> + </Container> + <Container className="mx3"> + <Container className="mb3 flex justify-between"> + <Text fontSize="20px" lineHeight="28px" fontColor={colors.white} fontWeight={500}> + Code Snippet + </Text> + <ActionLink displayText="Explore the Docs" linkSrc="/docs/instant" color={colors.grey} /> + </Container> + <CodeDemo /> + </Container> </Container> - <CodeDemo /> - </Container> - </Container> -); + ); + } + private readonly _handleConfigChange = (config: ZeroExInstantBaseConfig) => { + this.setState({ + instantConfig: config, + }); + }; +} diff --git a/packages/website/ts/pages/instant/features.tsx b/packages/website/ts/pages/instant/features.tsx index 6c6835311..1e187c9da 100644 --- a/packages/website/ts/pages/instant/features.tsx +++ b/packages/website/ts/pages/instant/features.tsx @@ -2,9 +2,9 @@ import * as _ from 'lodash'; import * as React from 'react'; import { Container } from 'ts/components/ui/container'; -import { ActionLink, ActionLinkProps } from 'ts/pages/instant/action_link'; 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 } from 'ts/types'; import { utils } from 'ts/utils/utils'; |