aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFred Carlsen <fred@sjelfull.no>2018-12-14 00:38:18 +0800
committerFred Carlsen <fred@sjelfull.no>2018-12-14 00:38:32 +0800
commit1c413e632b3a71453a523d68507e0f464f0f61bc (patch)
treeee1945846765ad6d4e012b9e5661d5f5d26d68bd
parent803086da5769c7cad2b4bbb80496ea58b353e5b8 (diff)
downloaddexon-sol-tools-1c413e632b3a71453a523d68507e0f464f0f61bc.tar
dexon-sol-tools-1c413e632b3a71453a523d68507e0f464f0f61bc.tar.gz
dexon-sol-tools-1c413e632b3a71453a523d68507e0f464f0f61bc.tar.bz2
dexon-sol-tools-1c413e632b3a71453a523d68507e0f464f0f61bc.tar.lz
dexon-sol-tools-1c413e632b3a71453a523d68507e0f464f0f61bc.tar.xz
dexon-sol-tools-1c413e632b3a71453a523d68507e0f464f0f61bc.tar.zst
dexon-sol-tools-1c413e632b3a71453a523d68507e0f464f0f61bc.zip
Styled configurator
-rw-r--r--packages/website/ts/@next/components/text.tsx8
-rw-r--r--packages/website/ts/@next/pages/instant/code_demo.tsx179
-rw-r--r--packages/website/ts/@next/pages/instant/config_generator.tsx74
-rw-r--r--packages/website/ts/@next/pages/instant/config_generator_address_input.tsx90
-rw-r--r--packages/website/ts/@next/pages/instant/configurator.tsx12
-rw-r--r--packages/website/ts/@next/pages/instant/select.tsx66
6 files changed, 398 insertions, 31 deletions
diff --git a/packages/website/ts/@next/components/text.tsx b/packages/website/ts/@next/components/text.tsx
index 54d4764f3..c29277c16 100644
--- a/packages/website/ts/@next/components/text.tsx
+++ b/packages/website/ts/@next/components/text.tsx
@@ -10,7 +10,9 @@ interface BaseTextInterface extends PaddingInterface {
interface HeadingProps extends BaseTextInterface {
asElement?: 'h1'| 'h2'| 'h3'| 'h4';
maxWidth?: string;
+ fontWeight?: string;
isCentered?: boolean;
+ isFlex?: boolean;
isNoMargin?: boolean;
isMuted?: boolean | number;
marginBottom?: string;
@@ -26,6 +28,9 @@ interface ParagraphProps extends BaseTextInterface {
const StyledHeading = styled.h1<HeadingProps>`
max-width: ${props => props.maxWidth};
color: ${props => props.color || props.theme.textColor};
+ display: ${props => props.isFlex && `inline-flex`};
+ align-items: center;
+ justify-content: ${props => props.isFlex && `space-between`};
font-size: ${props => isNaN(props.size) ? `var(--${props.size || 'default'}Heading)` : `${props.size}px`};
line-height: ${props => `var(--${props.size || 'default'}HeadingHeight)`};
text-align: ${props => props.isCentered && 'center'};
@@ -34,7 +39,8 @@ const StyledHeading = styled.h1<HeadingProps>`
margin-right: ${props => props.isCentered && 'auto'};
margin-bottom: ${props => !props.isNoMargin && (props.marginBottom || '30px')};
opacity: ${props => typeof props.isMuted === 'boolean' ? 0.75 : props.isMuted};
- font-weight: ${props => ['h4'].includes(props.asElement) ? 400 : 300};
+ font-weight: ${props => props.fontWeight ? props.fontWeight : (['h4'].includes(props.asElement) ? 400 : 300)};
+ width: ${props => props.isFlex && `100%`};
`;
export const Heading: React.StatelessComponent<HeadingProps> = props => {
diff --git a/packages/website/ts/@next/pages/instant/code_demo.tsx b/packages/website/ts/@next/pages/instant/code_demo.tsx
new file mode 100644
index 000000000..fe11175d5
--- /dev/null
+++ b/packages/website/ts/@next/pages/instant/code_demo.tsx
@@ -0,0 +1,179 @@
+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 { 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';
+
+const CustomPre = styled.pre`
+ margin: 0px;
+ line-height: 24px;
+ overflow: scroll;
+ width: 100%;
+ height: 100%;
+ max-height: 800px;
+ border-radius: 4px;
+ code {
+ background-color: inherit !important;
+ border-radius: 0px;
+ font-family: 'Roboto Mono', sans-serif;
+ border: none;
+ }
+ code:first-of-type {
+ background-color: #060D0D !important;
+ color: #999;
+ min-height: 100%;
+ text-align: center;
+ margin-right: 15px;
+ line-height: 25px;
+ padding: 10px 7px !important;
+ }
+ code:last-of-type {
+ position: relative;
+ top: 10px;
+ top: 0;
+ padding-top: 11px;
+ display: inline-block;
+ line-height: 25px;
+ }
+`;
+
+const customStyle = {
+ 'hljs-comment': {
+ color: '#7e7887',
+ },
+ 'hljs-quote': {
+ color: '#7e7887',
+ },
+ 'hljs-variable': {
+ color: '#be4678',
+ },
+ 'hljs-template-variable': {
+ color: '#be4678',
+ },
+ 'hljs-attribute': {
+ color: '#be4678',
+ },
+ 'hljs-regexp': {
+ color: '#be4678',
+ },
+ 'hljs-link': {
+ color: '#be4678',
+ },
+ 'hljs-tag': {
+ color: '#61f5ff',
+ },
+ 'hljs-name': {
+ color: '#61f5ff',
+ },
+ 'hljs-selector-id': {
+ color: '#be4678',
+ },
+ 'hljs-selector-class': {
+ color: '#be4678',
+ },
+ 'hljs-number': {
+ color: '#c994ff',
+ },
+ 'hljs-meta': {
+ color: '#61f5ff',
+ },
+ 'hljs-built_in': {
+ color: '#aa573c',
+ },
+ 'hljs-builtin-name': {
+ color: '#aa573c',
+ },
+ 'hljs-literal': {
+ color: '#aa573c',
+ },
+ 'hljs-type': {
+ color: '#aa573c',
+ },
+ 'hljs-params': {
+ color: '#aa573c',
+ },
+ 'hljs-string': {
+ color: '#bcff88',
+ },
+ 'hljs-symbol': {
+ color: '#2a9292',
+ },
+ 'hljs-bullet': {
+ color: '#2a9292',
+ },
+ 'hljs-title': {
+ color: '#576ddb',
+ },
+ 'hljs-section': {
+ color: '#576ddb',
+ },
+ 'hljs-keyword': {
+ color: '#955ae7',
+ },
+ 'hljs-selector-tag': {
+ color: '#955ae7',
+ },
+ 'hljs-deletion': {
+ color: '#19171c',
+ display: 'inline-block',
+ width: '100%',
+ backgroundColor: '#be4678',
+ },
+ 'hljs-addition': {
+ color: '#19171c',
+ display: 'inline-block',
+ width: '100%',
+ backgroundColor: '#2a9292',
+ },
+ hljs: {
+ display: 'block',
+ overflowX: 'hidden',
+ background: '#1B2625',
+ color: 'white',
+ fontSize: '12px',
+ },
+ 'hljs-emphasis': {
+ fontStyle: 'italic',
+ },
+ 'hljs-strong': {
+ fontWeight: 'bold',
+ },
+};
+
+export interface CodeDemoProps {
+ children: string;
+}
+
+export interface CodeDemoState {
+ didCopyCode: boolean;
+}
+
+export class CodeDemo extends React.Component<CodeDemoProps, CodeDemoState> {
+ public state: CodeDemoState = {
+ didCopyCode: false,
+ };
+ public render(): React.ReactNode {
+ const copyButtonText = this.state.didCopyCode ? 'Copied!' : 'Copy';
+ return (
+ <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>
+ </CopyToClipboard>
+ </Container>
+ <SyntaxHighlighter language="html" style={customStyle} showLineNumbers={true} PreTag={CustomPre}>
+ {this.props.children}
+ </SyntaxHighlighter>
+ </Container>
+ );
+ }
+ private readonly _handleCopyClick = () => {
+ this.setState({ didCopyCode: true });
+ };
+}
diff --git a/packages/website/ts/@next/pages/instant/config_generator.tsx b/packages/website/ts/@next/pages/instant/config_generator.tsx
index 00e491431..119311d94 100644
--- a/packages/website/ts/@next/pages/instant/config_generator.tsx
+++ b/packages/website/ts/@next/pages/instant/config_generator.tsx
@@ -4,14 +4,14 @@ 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';
+import { ConfigGeneratorAddressInput } from 'ts/@next/pages/instant/config_generator_address_input';
import { FeePercentageSlider } from 'ts/pages/instant/fee_percentage_slider';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
@@ -19,6 +19,7 @@ import { constants } from 'ts/utils/constants';
// New components
import { Heading, Paragraph } from 'ts/@next/components/text';
+import { Select, SelectItemConfig } from 'ts/@next/pages/instant/select';
import { assetMetaDataMap } from '../../../../../instant/src/data/asset_meta_data_map';
import { ERC20AssetMetaData, ZeroExInstantBaseConfig } from '../../../../../instant/src/types';
@@ -62,8 +63,8 @@ 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 id="" value={value.orderSource} items={this._generateItems()} />
</ConfigGeneratorSection>
<ConfigGeneratorSection {...this._getTokenSelectorProps()}>
{this._renderTokenMultiSelectOrSpinner()}
@@ -113,7 +114,8 @@ 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),
}));
};
@@ -252,15 +254,9 @@ 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),
@@ -288,27 +284,57 @@ export const ConfigGeneratorSection: React.StatelessComponent<ConfigGeneratorSec
}) => (
<Container marginBottom={marginBottom}>
<Container marginBottom="10px" className="flex justify-between items-center">
- <Container>
- <Heading size="small" isNoMargin={true}>
- {title}
- </Heading>
+ <Heading size="small" marginBottom="0" isFlex={true}>
+ <span>{title}</span>
{isOptional && (
- <Text fontColor={colors.grey} fontSize="16px" lineHeight="18px" display="inline">
- {' '}
- (optional)
- </Text>
+ <OptionalText>
+ {' '}
+ Optional
+ </OptionalText>
)}
- </Container>
+ </Heading>
{actionText && (
- <Text fontSize="12px" fontColor={colors.grey} onClick={onActionTextClick}>
+ <OptionalAction onClick={onActionTextClick}>
{actionText}
- </Text>
+ </OptionalAction>
)}
</Container>
{children}
</Container>
);
+const Mark = ({ checked }) => (
+ <StyledMark checked={checked}>
+ {checked && ''}
+ </StyledMark>
+);
+
+const StyledMark = styled.div`
+ border: 1px solid #ccc;
+ border-radius: 50%;
+ width: 16px;
+ height: 16px;
+ border-color: ${props => props.checked && colors.brandLight};
+ background-color: ${props => props.checked && colors.brandLight};
+`;
+
ConfigGeneratorSection.defaultProps = {
marginBottom: '30px',
};
+
+const OptionalText = styled.span`
+ display: inline;
+ font-size: 14px;
+ color: #999999;
+ flex-shrink: 0;
+`;
+
+const CheckboxText = styled.span`
+ font-size: 14px;
+ line-height: 18px;
+ color: ${props => props.isSelected ? colors.brandDark : '#666666'}
+`;
+
+const OptionalAction = styled(OptionalText)`
+ cursor: pointer;
+`; \ No newline at end of file
diff --git a/packages/website/ts/@next/pages/instant/config_generator_address_input.tsx b/packages/website/ts/@next/pages/instant/config_generator_address_input.tsx
new file mode 100644
index 000000000..01453d445
--- /dev/null
+++ b/packages/website/ts/@next/pages/instant/config_generator_address_input.tsx
@@ -0,0 +1,90 @@
+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 { Text } from 'ts/components/ui/text';
+import { Paragraph } from 'ts/@next/components/text';
+
+export interface ConfigGeneratorAddressInputProps {
+ value?: string;
+ onChange?: (address: string, isValid: boolean) => void;
+}
+
+export interface ConfigGeneratorAddressInputState {
+ errMsg: string;
+}
+
+export interface InputProps {
+ className?: string;
+ value?: string;
+ width?: string;
+ fontSize?: string;
+ fontColor?: string;
+ border?: string;
+ padding?: string;
+ placeholderColor?: string;
+ placeholder?: string;
+ backgroundColor?: string;
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
+}
+
+export class ConfigGeneratorAddressInput extends React.Component<
+ ConfigGeneratorAddressInputProps,
+ ConfigGeneratorAddressInputState
+> {
+ public state = {
+ errMsg: '',
+ };
+ public render(): React.ReactNode {
+ const { errMsg } = this.state;
+ const hasError = !_.isEmpty(errMsg);
+ const border = hasError ? '1px solid red' : undefined;
+ return (
+ <Container height="80px">
+ <Input
+ value={this.props.value}
+ onChange={this._handleChange}
+ placeholder="0xe99...aa8da4"
+ />
+ <Container marginTop="5px" isHidden={!hasError} height="25px">
+ <Paragraph size="small" isNoMargin={true}>
+ {errMsg}
+ </Paragraph>
+ </Container>
+ </Container>
+ );
+ }
+
+ private readonly _handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
+ const address = event.target.value;
+ const isValidAddress = addressUtils.isAddress(address.toLowerCase()) || address === '';
+ const errMsg = isValidAddress ? '' : 'Please enter a valid Ethereum address';
+ this.setState({
+ errMsg,
+ });
+ 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;
+ }
+`; \ No newline at end of file
diff --git a/packages/website/ts/@next/pages/instant/configurator.tsx b/packages/website/ts/@next/pages/instant/configurator.tsx
index 354a7c205..cdba53ca9 100644
--- a/packages/website/ts/@next/pages/instant/configurator.tsx
+++ b/packages/website/ts/@next/pages/instant/configurator.tsx
@@ -4,8 +4,8 @@ import styled from 'styled-components';
import { colors } from 'ts/style/colors';
+import { CodeDemo } from 'ts/@next/pages/instant/code_demo';
import { ConfigGenerator } from 'ts/@next/pages/instant/config_generator';
-import { CodeDemo } from 'ts/pages/instant/code_demo';
import { Column, FlexWrap, Section } from 'ts/@next/components/newLayout';
import { Heading, Paragraph } from 'ts/@next/components/text';
import { WebsitePaths } from 'ts/types';
@@ -44,7 +44,7 @@ export class Configurator extends React.Component<ConfiguratorProps> {
</Column>
<Column width="560px">
<HeadingWrapper>
- <Heading size="small">Code Snippet</Heading>
+ <Heading size="small" marginBottom="15px">Code Snippet</Heading>
<Link
href={`${WebsitePaths.Wiki}#Get-Started-With-Instant`}
isBlock={true}
@@ -87,10 +87,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}'`);
diff --git a/packages/website/ts/@next/pages/instant/select.tsx b/packages/website/ts/@next/pages/instant/select.tsx
new file mode 100644
index 000000000..7c601da1c
--- /dev/null
+++ b/packages/website/ts/@next/pages/instant/select.tsx
@@ -0,0 +1,66 @@
+import * as React from 'react';
+import styled from 'styled-components';
+
+import { colors } from 'ts/style/colors';
+
+import {Column, Section, Wrap, WrapCentered} from 'ts/@next/components/layout';
+import {Heading, Paragraph} from 'ts/@next/components/text';
+
+export interface SelectItemConfig {
+ label: string;
+ value?: string;
+ onClick?: () => void;
+}
+
+interface SelectProps {
+ value?: string;
+ id: string;
+ items: SelectItemConfig[];
+ emptyText?: string;
+}
+
+export const Select: React.FunctionComponent<SelectProps> = ({ value, id, items, emptyText }) => {
+ return (
+ <Container>
+ <StyledSelect id={id}>
+ <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...',
+};
+
+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 SelectAllButton = styled.button`
+ appearance: none;
+ border: 0;
+ font-size: 0.777777778rem;
+ display: block;
+ opacity: 0.75;
+`;
+
+const Caret = styled.svg`
+ position: absolute;
+ right: 20px;
+ top: calc(50% - 4px);
+`;