Merge pull request #1369 from 0xProject/feature/website/instant-configurator
[website][instant] Instant configurator
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
import { ObjectMap } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { Provider } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import { Provider as ReduxProvider } from 'react-redux';
|
||||
@@ -11,7 +9,7 @@ import { asyncData } from '../redux/async_data';
|
||||
import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer';
|
||||
import { store, Store } from '../redux/store';
|
||||
import { fonts } from '../style/fonts';
|
||||
import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource, QuoteFetchOrigin } from '../types';
|
||||
import { AccountState, Network, QuoteFetchOrigin, ZeroExInstantBaseConfig } from '../types';
|
||||
import { analytics, disableAnalytics } from '../util/analytics';
|
||||
import { assetUtils } from '../util/asset';
|
||||
import { errorFlasher } from '../util/error_flasher';
|
||||
@@ -21,24 +19,7 @@ import { Heartbeater } from '../util/heartbeater';
|
||||
import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory';
|
||||
import { providerStateFactory } from '../util/provider_state_factory';
|
||||
|
||||
export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps &
|
||||
Partial<ZeroExInstantProviderOptionalProps>;
|
||||
|
||||
export interface ZeroExInstantProviderRequiredProps {
|
||||
orderSource: OrderSource;
|
||||
}
|
||||
|
||||
export interface ZeroExInstantProviderOptionalProps {
|
||||
provider: Provider;
|
||||
walletDisplayName: string;
|
||||
availableAssetDatas: string[];
|
||||
defaultAssetBuyAmount: number;
|
||||
defaultSelectedAssetData: string;
|
||||
additionalAssetMetaDataMap: ObjectMap<AssetMetaData>;
|
||||
networkId: Network;
|
||||
affiliateInfo: AffiliateInfo;
|
||||
shouldDisableAnalyticsTracking: boolean;
|
||||
}
|
||||
export type ZeroExInstantProviderProps = ZeroExInstantBaseConfig;
|
||||
|
||||
export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
|
||||
private readonly _store: Store;
|
||||
|
||||
@@ -177,3 +177,21 @@ export enum ProviderType {
|
||||
Cipher = 'CIPHER',
|
||||
Fallback = 'FALLBACK',
|
||||
}
|
||||
|
||||
export interface ZeroExInstantRequiredBaseConfig {
|
||||
orderSource: OrderSource;
|
||||
}
|
||||
|
||||
export interface ZeroExInstantOptionalBaseConfig {
|
||||
provider: Provider;
|
||||
walletDisplayName: string;
|
||||
availableAssetDatas: string[];
|
||||
defaultAssetBuyAmount: number;
|
||||
defaultSelectedAssetData: string;
|
||||
additionalAssetMetaDataMap: ObjectMap<AssetMetaData>;
|
||||
networkId: Network;
|
||||
affiliateInfo: AffiliateInfo;
|
||||
shouldDisableAnalyticsTracking: boolean;
|
||||
}
|
||||
|
||||
export type ZeroExInstantBaseConfig = ZeroExInstantRequiredBaseConfig & Partial<ZeroExInstantOptionalBaseConfig>;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
"author": "Fabio Berger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@0x/asset-buyer": "^3.0.2",
|
||||
"@0x/contract-addresses": "^2.0.0",
|
||||
"@0x/contract-wrappers": "^4.1.1",
|
||||
"@0x/json-schemas": "^2.1.2",
|
||||
"@0x/order-utils": "^3.0.4",
|
||||
@@ -46,6 +48,7 @@
|
||||
"numeral": "^2.0.6",
|
||||
"polished": "^1.9.2",
|
||||
"query-string": "^6.0.0",
|
||||
"rc-slider": "^8.6.3",
|
||||
"react": "^16.4.2",
|
||||
"react-copy-to-clipboard": "^5.0.0",
|
||||
"react-document-title": "^2.0.3",
|
||||
@@ -54,6 +57,7 @@
|
||||
"react-popper": "^1.0.0-beta.6",
|
||||
"react-redux": "^5.0.3",
|
||||
"react-scroll": "0xproject/react-scroll#pr-330-and-replace-state",
|
||||
"react-syntax-highlighter": "^10.1.1",
|
||||
"react-tooltip": "^3.2.7",
|
||||
"react-typist": "^2.0.4",
|
||||
"redux": "^3.6.0",
|
||||
@@ -77,12 +81,14 @@
|
||||
"@types/node": "*",
|
||||
"@types/numeral": "^0.0.22",
|
||||
"@types/query-string": "^5.1.0",
|
||||
"@types/rc-slider": "^8.6.0",
|
||||
"@types/react": "^16.4.2",
|
||||
"@types/react-copy-to-clipboard": "^4.2.0",
|
||||
"@types/react-dom": "^16.0.7",
|
||||
"@types/react-helmet": "^5.0.6",
|
||||
"@types/react-redux": "^4.4.37",
|
||||
"@types/react-scroll": "1.5.3",
|
||||
"@types/react-syntax-highlighter": "^0.0.8",
|
||||
"@types/react-tap-event-plugin": "0.0.30",
|
||||
"@types/redux": "^3.6.0",
|
||||
"@types/web3-provider-engine": "^14.0.0",
|
||||
|
||||
@@ -1,95 +1,132 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="An Open Protocol For Decentralized Exchange On The Ethereum Blockchain" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="0x" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="An Open Protocol For Decentralized Exchange On The Ethereum Blockchain"
|
||||
/>
|
||||
<meta property="og:image" content="/images/og_image.png" />
|
||||
<title>0x: The Protocol for Trading Tokens</title>
|
||||
<link rel="icon" type="image/png" href="/images/favicon/favicon-2-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="/images/favicon/favicon-2-16x16.png" sizes="16x16" />
|
||||
<link rel="stylesheet" href="/css/material-design-iconic-font.min.css" />
|
||||
<link rel="stylesheet" href="/css/roboto.css" />
|
||||
<link rel="stylesheet" href="/css/roboto_mono.css" />
|
||||
<link rel="stylesheet" href="/css/basscss_responsive_custom.css" />
|
||||
<link rel="stylesheet" href="/css/basscss_responsive_padding.css" />
|
||||
<link rel="stylesheet" href="/css/basscss_responsive_margin.css" />
|
||||
<link rel="stylesheet" href="/css/basscss_responsive_type_scale.css" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="An Open Protocol For Decentralized Exchange On The Ethereum Blockchain" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="0x" />
|
||||
<meta property="og:description" content="An Open Protocol For Decentralized Exchange On The Ethereum Blockchain" />
|
||||
<meta property="og:image" content="/images/og_image.png" />
|
||||
<title>0x: The Protocol for Trading Tokens</title>
|
||||
<link rel="icon" type="image/png" href="/images/favicon/favicon-2-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="/images/favicon/favicon-2-16x16.png" sizes="16x16" />
|
||||
<link rel="stylesheet" href="/css/github-gist.css">
|
||||
<link rel="stylesheet" href="/css/material-design-iconic-font.min.css">
|
||||
<link rel="stylesheet" href="/css/roboto.css">
|
||||
<link rel="stylesheet" href="/css/roboto_mono.css">
|
||||
<link rel="stylesheet" href="/css/basscss_responsive_custom.css">
|
||||
<link rel="stylesheet" href="/css/basscss_responsive_padding.css">
|
||||
<link rel="stylesheet" href="/css/basscss_responsive_margin.css">
|
||||
<link rel="stylesheet" href="/css/basscss_responsive_type_scale.css">
|
||||
</head>
|
||||
<body style="margin: 0px; min-width: 355px;">
|
||||
<!-- Heap SDK -->
|
||||
<script type="text/javascript">
|
||||
(window.heap = window.heap || []),
|
||||
(heap.load = function(e, t) {
|
||||
(window.heap.appid = e), (window.heap.config = t = t || {});
|
||||
var r = t.forceSSL || 'https:' === document.location.protocol,
|
||||
a = document.createElement('script');
|
||||
(a.type = 'text/javascript'),
|
||||
(a.async = !0),
|
||||
(a.src = (r ? 'https:' : 'http:') + '//cdn.heapanalytics.com/js/heap-' + e + '.js');
|
||||
var n = document.getElementsByTagName('script')[0];
|
||||
n.parentNode.insertBefore(a, n);
|
||||
for (
|
||||
var o = function(e) {
|
||||
return function() {
|
||||
heap.push([e].concat(Array.prototype.slice.call(arguments, 0)));
|
||||
};
|
||||
},
|
||||
p = [
|
||||
'addEventProperties',
|
||||
'addUserProperties',
|
||||
'clearEventProperties',
|
||||
'identify',
|
||||
'resetIdentity',
|
||||
'removeEventProperty',
|
||||
'setEventProperties',
|
||||
'track',
|
||||
'unsetEventProperty',
|
||||
],
|
||||
c = 0;
|
||||
c < p.length;
|
||||
c++
|
||||
)
|
||||
heap[p[c]] = o(p[c]);
|
||||
});
|
||||
heap.load('410099666');
|
||||
</script>
|
||||
<!-- End Heap SDK -->
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-98720122-1"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
|
||||
<body style="margin: 0px; min-width: 355px;">
|
||||
<!-- Heap SDK -->
|
||||
<script type="text/javascript">
|
||||
window.heap = window.heap || [], heap.load = function (e, t) { window.heap.appid = e, window.heap.config = t = t || {}; var r = t.forceSSL || "https:" === document.location.protocol, a = document.createElement("script"); a.type = "text/javascript", a.async = !0, a.src = (r ? "https:" : "http:") + "//cdn.heapanalytics.com/js/heap-" + e + ".js"; var n = document.getElementsByTagName("script")[0]; n.parentNode.insertBefore(a, n); for (var o = function (e) { return function () { heap.push([e].concat(Array.prototype.slice.call(arguments, 0))) } }, p = ["addEventProperties", "addUserProperties", "clearEventProperties", "identify", "resetIdentity", "removeEventProperty", "setEventProperties", "track", "unsetEventProperty"], c = 0; c < p.length; c++)heap[p[c]] = o(p[c]) };
|
||||
heap.load("410099666");
|
||||
</script>
|
||||
<!-- End Heap SDK -->
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-98720122-1"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'UA-98720122-1');
|
||||
</script>
|
||||
<!-- End Google Analytics -->
|
||||
<!-- Facebook SDK -->
|
||||
<div id="fb-root"></div>
|
||||
<script>
|
||||
(function (d, s, id) {
|
||||
var js,
|
||||
fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) return;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8&appId=1687545238205192';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
})(document, 'script', 'facebook-jssdk');
|
||||
</script>
|
||||
<div id="app"></div>
|
||||
<!-- End Facebook SDK -->
|
||||
<!-- Twitter SDK -->
|
||||
<script>
|
||||
window.twttr = (function (d, s, id) {
|
||||
var js,
|
||||
fjs = d.getElementsByTagName(s)[0],
|
||||
t = window.twttr || {};
|
||||
if (d.getElementById(id)) return t;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = 'https://platform.twitter.com/widgets.js';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
|
||||
t._e = [];
|
||||
t.ready = function (f) {
|
||||
t._e.push(f);
|
||||
};
|
||||
return t;
|
||||
})(document, 'script', 'twitter-wjs');
|
||||
</script>
|
||||
<!-- End Twitter SDK -->
|
||||
<!-- Hotjar Tracking Code for https://0xproject.com/ -->
|
||||
<script>
|
||||
(function (h, o, t, j, a, r) {
|
||||
h.hj = h.hj || function () { (h.hj.q = h.hj.q || []).push(arguments) };
|
||||
h._hjSettings = { hjid: 935597, hjsv: 6 };
|
||||
a = o.getElementsByTagName('head')[0];
|
||||
r = o.createElement('script'); r.async = 1;
|
||||
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
|
||||
a.appendChild(r);
|
||||
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
|
||||
</script>
|
||||
<!-- End Hotjar Tracking Code -->
|
||||
<!-- Main -->
|
||||
<script type="text/javascript" crossorigin="anonymous" src="/bundle.js" charset="utf-8"></script>
|
||||
</body>
|
||||
gtag('config', 'UA-98720122-1');
|
||||
</script>
|
||||
<!-- End Google Analytics -->
|
||||
<!-- Facebook SDK -->
|
||||
<div id="fb-root"></div>
|
||||
<script>
|
||||
(function(d, s, id) {
|
||||
var js,
|
||||
fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) return;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8&appId=1687545238205192';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
})(document, 'script', 'facebook-jssdk');
|
||||
</script>
|
||||
<div id="app"></div>
|
||||
<!-- End Facebook SDK -->
|
||||
<!-- Twitter SDK -->
|
||||
<script>
|
||||
window.twttr = (function(d, s, id) {
|
||||
var js,
|
||||
fjs = d.getElementsByTagName(s)[0],
|
||||
t = window.twttr || {};
|
||||
if (d.getElementById(id)) return t;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = 'https://platform.twitter.com/widgets.js';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
|
||||
t._e = [];
|
||||
t.ready = function(f) {
|
||||
t._e.push(f);
|
||||
};
|
||||
return t;
|
||||
})(document, 'script', 'twitter-wjs');
|
||||
</script>
|
||||
<!-- End Twitter SDK -->
|
||||
<!-- Hotjar Tracking Code for https://0xproject.com/ -->
|
||||
<script>
|
||||
(function(h, o, t, j, a, r) {
|
||||
h.hj =
|
||||
h.hj ||
|
||||
function() {
|
||||
(h.hj.q = h.hj.q || []).push(arguments);
|
||||
};
|
||||
h._hjSettings = { hjid: 935597, hjsv: 6 };
|
||||
a = o.getElementsByTagName('head')[0];
|
||||
r = o.createElement('script');
|
||||
r.async = 1;
|
||||
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
|
||||
a.appendChild(r);
|
||||
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
|
||||
</script>
|
||||
<!-- End Hotjar Tracking Code -->
|
||||
<!-- Main -->
|
||||
<script type="text/javascript" crossorigin="anonymous" src="/bundle.js" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
31
packages/website/ts/components/ui/check_mark.tsx
Normal file
31
packages/website/ts/components/ui/check_mark.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { colors } from '@0x/react-shared';
|
||||
|
||||
export interface CheckMarkProps {
|
||||
color?: string;
|
||||
isChecked?: boolean;
|
||||
}
|
||||
|
||||
export const CheckMark: React.StatelessComponent<CheckMarkProps> = ({ color, isChecked }) => (
|
||||
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle
|
||||
cx="8.5"
|
||||
cy="8.5"
|
||||
r="8.5"
|
||||
fill={isChecked ? color : 'white'}
|
||||
stroke={isChecked ? undefined : '#CCCCCC'}
|
||||
/>
|
||||
<path
|
||||
d="M2.5 4.5L1.79289 5.20711L2.5 5.91421L3.20711 5.20711L2.5 4.5ZM-0.707107 2.70711L1.79289 5.20711L3.20711 3.79289L0.707107 1.29289L-0.707107 2.70711ZM3.20711 5.20711L7.70711 0.707107L6.29289 -0.707107L1.79289 3.79289L3.20711 5.20711Z"
|
||||
transform="translate(5 6.5)"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
CheckMark.displayName = 'Check';
|
||||
|
||||
CheckMark.defaultProps = {
|
||||
color: colors.mediumBlue,
|
||||
};
|
||||
@@ -1,11 +1,15 @@
|
||||
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';
|
||||
|
||||
export interface ContainerProps {
|
||||
margin?: string;
|
||||
marginTop?: StringOrNum;
|
||||
marginBottom?: StringOrNum;
|
||||
marginRight?: StringOrNum;
|
||||
@@ -17,10 +21,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;
|
||||
@@ -37,15 +44,32 @@ export interface ContainerProps {
|
||||
right?: string;
|
||||
bottom?: string;
|
||||
zIndex?: number;
|
||||
float?: 'right' | 'left';
|
||||
Tag?: ContainerTag;
|
||||
cursor?: string;
|
||||
id?: string;
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
overflowX?: 'scroll' | 'hidden' | 'auto' | 'visible';
|
||||
overflowY?: 'scroll' | 'hidden' | 'auto' | 'visible';
|
||||
shouldDarkenOnHover?: boolean;
|
||||
hasBoxShadow?: 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,
|
||||
hasBoxShadow,
|
||||
// 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 +78,20 @@ export const Container: React.StatelessComponent<ContainerProps> = props => {
|
||||
);
|
||||
};
|
||||
|
||||
const BOX_SHADOW = '0px 3px 10px rgba(0, 0, 0, 0.3)';
|
||||
|
||||
export const Container = styled(PlainContainer)`
|
||||
box-sizing: border-box;
|
||||
${props => (props.hasBoxShadow ? `box-shadow: ${BOX_SHADOW}` : '')};
|
||||
&:hover {
|
||||
${props =>
|
||||
props.shouldDarkenOnHover
|
||||
? `background-color: ${props.backgroundColor ? darken(0.05, props.backgroundColor) : 'none'} !important`
|
||||
: ''};
|
||||
${props => (props.shouldAddBoxShadowOnHover ? `box-shadow: ${BOX_SHADOW}` : '')};
|
||||
}
|
||||
`;
|
||||
|
||||
Container.defaultProps = {
|
||||
Tag: 'div',
|
||||
};
|
||||
|
||||
@@ -8,6 +8,8 @@ export interface InputProps {
|
||||
width?: string;
|
||||
fontSize?: string;
|
||||
fontColor?: string;
|
||||
border?: string;
|
||||
padding?: string;
|
||||
placeholderColor?: string;
|
||||
placeholder?: string;
|
||||
backgroundColor?: string;
|
||||
@@ -21,11 +23,13 @@ const PlainInput: React.StatelessComponent<InputProps> = ({ value, className, pl
|
||||
export const Input = styled(PlainInput)`
|
||||
font-size: ${props => props.fontSize};
|
||||
width: ${props => props.width};
|
||||
padding: 0.8em 1.2em;
|
||||
padding: ${props => props.padding};
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Roboto Mono';
|
||||
color: ${props => props.fontColor};
|
||||
border: none;
|
||||
border: ${props => props.border};
|
||||
outline: none;
|
||||
background-color: ${props => props.backgroundColor};
|
||||
&::placeholder {
|
||||
color: ${props => props.placeholderColor};
|
||||
@@ -38,6 +42,8 @@ Input.defaultProps = {
|
||||
fontColor: colors.darkestGrey,
|
||||
placeholderColor: colors.darkGrey,
|
||||
fontSize: '12px',
|
||||
border: 'none',
|
||||
padding: '0.8em 1.2em',
|
||||
};
|
||||
|
||||
Input.displayName = 'Input';
|
||||
|
||||
66
packages/website/ts/components/ui/multi_select.tsx
Normal file
66
packages/website/ts/components/ui/multi_select.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { colors } from '@0x/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Container } from './container';
|
||||
|
||||
export interface MultiSelectItemConfig {
|
||||
value: string;
|
||||
renderItemContent: (isSelected: boolean) => React.ReactNode;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export interface MultiSelectProps {
|
||||
selectedValues?: string[];
|
||||
items: MultiSelectItemConfig[];
|
||||
backgroundColor?: string;
|
||||
height?: string;
|
||||
}
|
||||
|
||||
export class MultiSelect extends React.Component<MultiSelectProps> {
|
||||
public static defaultProps = {
|
||||
backgroundColor: colors.white,
|
||||
};
|
||||
public render(): React.ReactNode {
|
||||
const { items, backgroundColor, selectedValues, height } = this.props;
|
||||
return (
|
||||
<Container
|
||||
backgroundColor={backgroundColor}
|
||||
borderRadius="4px"
|
||||
width="100%"
|
||||
height={height}
|
||||
overflowY="scroll"
|
||||
>
|
||||
{_.map(items, item => (
|
||||
<MultiSelectItem
|
||||
key={item.value}
|
||||
renderItemContent={item.renderItemContent}
|
||||
backgroundColor={backgroundColor}
|
||||
onClick={item.onClick}
|
||||
isSelected={_.isUndefined(selectedValues) || _.includes(selectedValues, item.value)}
|
||||
/>
|
||||
))}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export interface MultiSelectItemProps {
|
||||
renderItemContent: (isSelected: boolean) => React.ReactNode;
|
||||
isSelected?: boolean;
|
||||
onClick?: () => void;
|
||||
backgroundColor?: string;
|
||||
}
|
||||
|
||||
export const MultiSelectItem: React.StatelessComponent<MultiSelectItemProps> = ({
|
||||
renderItemContent,
|
||||
isSelected,
|
||||
onClick,
|
||||
backgroundColor,
|
||||
}) => (
|
||||
<Container cursor="pointer" shouldDarkenOnHover={true} onClick={onClick} backgroundColor={backgroundColor}>
|
||||
<Container borderBottom={`1px solid ${colors.lightestGrey}`} margin="0px 15px" padding="10px 0px">
|
||||
{renderItemContent(isSelected)}
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
170
packages/website/ts/components/ui/select.tsx
Normal file
170
packages/website/ts/components/ui/select.tsx
Normal file
@@ -0,0 +1,170 @@
|
||||
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}
|
||||
hasBoxShadow={isOpen}
|
||||
border={border}
|
||||
backgroundColor={backgroundColor}
|
||||
padding="0.5em 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">
|
||||
<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}
|
||||
hasBoxShadow={true}
|
||||
>
|
||||
{_.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>
|
||||
);
|
||||
@@ -2,6 +2,7 @@ import { colors, constants as sharedConstants, utils as sharedUtils } from '@0x/
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import DocumentTitle from 'react-document-title';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { DocsLogo } from 'ts/components/documentation/docs_logo';
|
||||
import { DocsTopBar } from 'ts/components/documentation/docs_top_bar';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
@@ -146,6 +147,9 @@ export class DevelopersPage extends React.Component<DevelopersPageProps, Develop
|
||||
} 50%, ${colors.white} 100%)`}
|
||||
>
|
||||
<DocumentTitle title="0x Docs" />
|
||||
<Helmet>
|
||||
<link rel="stylesheet" href="/css/github-gist.css" />
|
||||
</Helmet>
|
||||
<Container className="flex mx-auto" height="100vh">
|
||||
<Container
|
||||
className="sm-hide xs-hide relative"
|
||||
|
||||
46
packages/website/ts/pages/instant/action_link.tsx
Normal file
46
packages/website/ts/pages/instant/action_link.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
177
packages/website/ts/pages/instant/code_demo.tsx
Normal file
177
packages/website/ts/pages/instant/code_demo.tsx
Normal file
@@ -0,0 +1,177 @@
|
||||
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: 600px;
|
||||
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: #2a2a2a !important;
|
||||
color: #999;
|
||||
min-height: 98%;
|
||||
text-align: center;
|
||||
padding-right: 5px !important;
|
||||
padding-left: 5px;
|
||||
margin-right: 15px;
|
||||
line-height: 25px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
code:last-of-type {
|
||||
position: relative;
|
||||
top: 10px;
|
||||
}
|
||||
`;
|
||||
|
||||
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: '#aa573c',
|
||||
},
|
||||
'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: colors.instantSecondaryBackground,
|
||||
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 });
|
||||
};
|
||||
}
|
||||
306
packages/website/ts/pages/instant/config_generator.tsx
Normal file
306
packages/website/ts/pages/instant/config_generator.tsx
Normal file
@@ -0,0 +1,306 @@
|
||||
import { StandardRelayerAPIOrderProvider } from '@0x/asset-buyer';
|
||||
import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { ObjectMap } from '@0x/types';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
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 { FeePercentageSlider } from 'ts/pages/instant/fee_percentage_slider';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { WebsitePaths } from 'ts/types';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
|
||||
import { assetMetaDataMap } from '../../../../instant/src/data/asset_meta_data_map';
|
||||
import { ERC20AssetMetaData, ZeroExInstantBaseConfig } from '../../../../instant/src/types';
|
||||
|
||||
export interface ConfigGeneratorProps {
|
||||
value: ZeroExInstantBaseConfig;
|
||||
onConfigChange: (config: ZeroExInstantBaseConfig) => void;
|
||||
}
|
||||
|
||||
export interface ConfigGeneratorState {
|
||||
isLoadingAvailableTokens: boolean;
|
||||
// Address to token info
|
||||
availableTokens?: ObjectMap<ERC20AssetMetaData>;
|
||||
}
|
||||
|
||||
const SRA_ENDPOINTS = ['https://api.radarrelay.com/0x/v2/', 'https://sra.bamboorelay.com/0x/v2/'];
|
||||
|
||||
export class ConfigGenerator extends React.Component<ConfigGeneratorProps, ConfigGeneratorState> {
|
||||
public state: ConfigGeneratorState = {
|
||||
isLoadingAvailableTokens: true,
|
||||
};
|
||||
public componentDidMount(): void {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this._setAvailableAssetsFromOrderProvider();
|
||||
}
|
||||
public componentDidUpdate(prevProps: ConfigGeneratorProps): void {
|
||||
if (prevProps.value.orderSource !== this.props.value.orderSource) {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this._setAvailableAssetsFromOrderProvider();
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
availableAssetDatas: undefined,
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
}
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
const { value } = this.props;
|
||||
if (!_.isString(value.orderSource)) {
|
||||
throw new Error('ConfigGenerator component only supports string values as an orderSource.');
|
||||
}
|
||||
return (
|
||||
<Container minWidth="350px">
|
||||
<ConfigGeneratorSection title="Standard relayer API endpoint">
|
||||
<Select value={value.orderSource} items={this._generateItems()} />
|
||||
</ConfigGeneratorSection>
|
||||
<ConfigGeneratorSection {...this._getTokenSelectorProps()}>
|
||||
{this._renderTokenMultiSelectOrSpinner()}
|
||||
</ConfigGeneratorSection>
|
||||
<ConfigGeneratorSection title="Transaction fee ETH address" marginBottom="10px" isOptional={true}>
|
||||
<ConfigGeneratorAddressInput
|
||||
value={value.affiliateInfo ? value.affiliateInfo.feeRecipient : ''}
|
||||
onChange={this._handleAffiliateAddressChange}
|
||||
/>
|
||||
</ConfigGeneratorSection>
|
||||
<ConfigGeneratorSection
|
||||
title="Fee percentage"
|
||||
actionText="Learn more"
|
||||
onActionTextClick={this._handleAffiliatePercentageLearnMoreClick}
|
||||
>
|
||||
<FeePercentageSlider
|
||||
value={value.affiliateInfo.feePercentage}
|
||||
onChange={this._handleAffiliatePercentageChange}
|
||||
/>
|
||||
</ConfigGeneratorSection>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private readonly _getTokenSelectorProps = (): ConfigGeneratorSectionProps => {
|
||||
if (_.isEmpty(this.state.availableTokens)) {
|
||||
return {
|
||||
title: 'What tokens can users buy?',
|
||||
};
|
||||
}
|
||||
if (_.isUndefined(this.props.value.availableAssetDatas)) {
|
||||
return {
|
||||
title: 'What tokens can users buy?',
|
||||
actionText: 'Unselect All',
|
||||
onActionTextClick: this._handleUnselectAllClick,
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: 'What tokens can users buy?',
|
||||
actionText: 'Select All',
|
||||
onActionTextClick: this._handleSelectAllClick,
|
||||
};
|
||||
};
|
||||
private readonly _generateItems = (): SelectItemConfig[] => {
|
||||
return _.map(SRA_ENDPOINTS, endpoint => ({
|
||||
text: 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) => {
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
orderSource: sraEndpoint,
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleAffiliateAddressChange = (address: string, isValid: boolean) => {
|
||||
const oldConfig: ZeroExInstantBaseConfig = this.props.value;
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...oldConfig,
|
||||
affiliateInfo: {
|
||||
feeRecipient: address,
|
||||
feePercentage: oldConfig.affiliateInfo.feePercentage,
|
||||
},
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleAffiliatePercentageChange = (value: number) => {
|
||||
const oldConfig: ZeroExInstantBaseConfig = this.props.value;
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...oldConfig,
|
||||
affiliateInfo: {
|
||||
feeRecipient: oldConfig.affiliateInfo.feeRecipient,
|
||||
feePercentage: value,
|
||||
},
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleSelectAllClick = () => {
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
availableAssetDatas: undefined,
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleUnselectAllClick = () => {
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
availableAssetDatas: [],
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleTokenClick = (assetData: string) => {
|
||||
const { value } = this.props;
|
||||
let newAvailableAssetDatas: string[] = [];
|
||||
const allKnownAssetDatas = _.keys(this.state.availableTokens);
|
||||
const availableAssetDatas = value.availableAssetDatas;
|
||||
if (_.isUndefined(availableAssetDatas)) {
|
||||
// It being undefined means it's all tokens.
|
||||
newAvailableAssetDatas = _.pull(allKnownAssetDatas, assetData);
|
||||
} else if (!_.includes(availableAssetDatas, assetData)) {
|
||||
// Add it
|
||||
newAvailableAssetDatas = [...availableAssetDatas, assetData];
|
||||
if (newAvailableAssetDatas.length === allKnownAssetDatas.length) {
|
||||
// If all tokens are manually selected, just show none.
|
||||
newAvailableAssetDatas = undefined;
|
||||
}
|
||||
} else {
|
||||
// Remove it
|
||||
newAvailableAssetDatas = _.pull(availableAssetDatas, assetData);
|
||||
}
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
availableAssetDatas: newAvailableAssetDatas,
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _setAvailableAssetsFromOrderProvider = async (): Promise<void> => {
|
||||
const { value } = this.props;
|
||||
if (!_.isUndefined(value.orderSource) && _.isString(value.orderSource)) {
|
||||
this.setState({ isLoadingAvailableTokens: true });
|
||||
const networkId = constants.NETWORK_ID_MAINNET;
|
||||
const sraOrderProvider = new StandardRelayerAPIOrderProvider(value.orderSource, networkId);
|
||||
const etherTokenAddress = getContractAddressesForNetworkOrThrow(networkId).etherToken;
|
||||
const etherTokenAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddress);
|
||||
const assetDatas = await sraOrderProvider.getAvailableMakerAssetDatasAsync(etherTokenAssetData);
|
||||
const availableTokens = _.reduce(
|
||||
assetDatas,
|
||||
(acc, assetData) => {
|
||||
const metaDataIfExists = assetMetaDataMap[assetData] as ERC20AssetMetaData;
|
||||
if (metaDataIfExists) {
|
||||
acc[assetData] = metaDataIfExists;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as ObjectMap<ERC20AssetMetaData>,
|
||||
);
|
||||
this.setState({ availableTokens, isLoadingAvailableTokens: false });
|
||||
}
|
||||
};
|
||||
private readonly _renderTokenMultiSelectOrSpinner = (): React.ReactNode => {
|
||||
const { value } = this.props;
|
||||
const { availableTokens, isLoadingAvailableTokens } = this.state;
|
||||
const multiSelectHeight = '200px';
|
||||
if (isLoadingAvailableTokens) {
|
||||
return (
|
||||
<Container
|
||||
className="flex flex-column items-center justify-center"
|
||||
height={multiSelectHeight}
|
||||
backgroundColor={colors.white}
|
||||
borderRadius="4px"
|
||||
width="100%"
|
||||
>
|
||||
<Container position="relative" left="12px" marginBottom="20px">
|
||||
<Spinner />
|
||||
</Container>
|
||||
<Text fontSize="16px">Loading...</Text>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
const availableAssetDatas = _.keys(availableTokens);
|
||||
if (availableAssetDatas.length === 0) {
|
||||
return (
|
||||
<Container
|
||||
className="flex flex-column items-center justify-center"
|
||||
height={multiSelectHeight}
|
||||
backgroundColor={colors.white}
|
||||
borderRadius="4px"
|
||||
width="100%"
|
||||
>
|
||||
<Text fontSize="16px">No tokens available. Try another endpoint?</Text>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
const items = _.map(_.keys(availableTokens), assetData => {
|
||||
const metaData = availableTokens[assetData];
|
||||
return {
|
||||
value: assetData,
|
||||
renderItemContent: (isSelected: boolean) => (
|
||||
<Container className="flex items-center">
|
||||
<Container marginRight="10px">
|
||||
<CheckMark isChecked={isSelected} />
|
||||
</Container>
|
||||
<Text
|
||||
fontSize="16px"
|
||||
fontColor={isSelected ? colors.mediumBlue : colors.darkerGrey}
|
||||
fontWeight={300}
|
||||
>
|
||||
<b>{metaData.symbol.toUpperCase()}</b> — {metaData.name}
|
||||
</Text>
|
||||
</Container>
|
||||
),
|
||||
onClick: this._handleTokenClick.bind(this, assetData),
|
||||
};
|
||||
});
|
||||
return <MultiSelect items={items} selectedValues={value.availableAssetDatas} height={multiSelectHeight} />;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ConfigGeneratorSectionProps {
|
||||
title: string;
|
||||
actionText?: string;
|
||||
onActionTextClick?: () => void;
|
||||
isOptional?: boolean;
|
||||
marginBottom?: string;
|
||||
}
|
||||
|
||||
export const ConfigGeneratorSection: React.StatelessComponent<ConfigGeneratorSectionProps> = ({
|
||||
title,
|
||||
actionText,
|
||||
onActionTextClick,
|
||||
isOptional,
|
||||
marginBottom,
|
||||
children,
|
||||
}) => (
|
||||
<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>
|
||||
)}
|
||||
</Container>
|
||||
{children}
|
||||
</Container>
|
||||
);
|
||||
|
||||
ConfigGeneratorSection.defaultProps = {
|
||||
marginBottom: '30px',
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import { colors } from '@0x/react-shared';
|
||||
import { addressUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Input } from 'ts/components/ui/input';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
|
||||
export interface ConfigGeneratorAddressInputProps {
|
||||
value?: string;
|
||||
onChange?: (address: string, isValid: boolean) => void;
|
||||
}
|
||||
|
||||
export interface ConfigGeneratorAddressInputState {
|
||||
errMsg: string;
|
||||
}
|
||||
|
||||
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
|
||||
width="100%"
|
||||
fontSize="16px"
|
||||
padding="0.7em 1em"
|
||||
value={this.props.value}
|
||||
onChange={this._handleChange}
|
||||
placeholder="0xe99...aa8da4"
|
||||
border={border}
|
||||
/>
|
||||
<Container marginTop="5px" isHidden={!hasError} height="25px">
|
||||
<Text fontSize="14px" fontColor={colors.grey} fontStyle="italic">
|
||||
{errMsg}
|
||||
</Text>
|
||||
</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);
|
||||
};
|
||||
}
|
||||
@@ -1,12 +1,110 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
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 { WebsitePaths } from 'ts/types';
|
||||
|
||||
import { ZeroExInstantBaseConfig } from '../../../../instant/src/types';
|
||||
|
||||
export interface ConfiguratorProps {
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export const Configurator = (props: ConfiguratorProps) => (
|
||||
<Container id={props.hash} height="400px" backgroundColor={colors.instantTertiaryBackground} />
|
||||
);
|
||||
export interface ConfiguratorState {
|
||||
instantConfig: ZeroExInstantBaseConfig;
|
||||
}
|
||||
|
||||
export class Configurator extends React.Component<ConfiguratorProps> {
|
||||
public state: ConfiguratorState = {
|
||||
instantConfig: {
|
||||
orderSource: 'https://api.radarrelay.com/0x/v2/',
|
||||
availableAssetDatas: undefined,
|
||||
affiliateInfo: {
|
||||
feeRecipient: '',
|
||||
feePercentage: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
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>
|
||||
<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}>
|
||||
Code Snippet
|
||||
</Text>
|
||||
<ActionLink
|
||||
displayText="Explore the Docs"
|
||||
linkSrc={`${WebsitePaths.Wiki}#Get-Started-With-Instant`}
|
||||
color={colors.grey}
|
||||
/>
|
||||
</Container>
|
||||
<CodeDemo key={codeToDisplay}>{codeToDisplay}</CodeDemo>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private readonly _handleConfigChange = (config: ZeroExInstantBaseConfig) => {
|
||||
this.setState({
|
||||
instantConfig: config,
|
||||
});
|
||||
};
|
||||
private readonly _generateCodeDemoCode = (): string => {
|
||||
const { instantConfig } = this.state;
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="https://instant.0xproject.com/instant.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
zeroExInstant.render({
|
||||
orderSource: '${instantConfig.orderSource}',${
|
||||
!_.isUndefined(instantConfig.affiliateInfo) && instantConfig.affiliateInfo.feeRecipient
|
||||
? `\n affiliateInfo: {
|
||||
feeRecipient: '${instantConfig.affiliateInfo.feeRecipient.toLowerCase()}',
|
||||
feePercentage: ${instantConfig.affiliateInfo.feePercentage}
|
||||
}`
|
||||
: ''
|
||||
}${
|
||||
!_.isUndefined(instantConfig.availableAssetDatas)
|
||||
? `\n availableAssetDatas: ${this._renderAvailableAssetDatasString(
|
||||
instantConfig.availableAssetDatas,
|
||||
)}`
|
||||
: ''
|
||||
}
|
||||
}, 'body');
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
};
|
||||
private readonly _renderAvailableAssetDatasString = (availableAssetDatas: string[]): string => {
|
||||
const stringAvailableAssetDatas = availableAssetDatas.map(assetData => `'${assetData}'`);
|
||||
if (availableAssetDatas.length < 2) {
|
||||
return `[${stringAvailableAssetDatas.join(', ')}]`;
|
||||
}
|
||||
return `[\n ${stringAvailableAssetDatas.join(
|
||||
', \n ',
|
||||
)}\n ]`;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ 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 } from 'ts/types';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
import { ScreenWidths, WebsitePaths } from 'ts/types';
|
||||
|
||||
export interface FeatureProps {
|
||||
screenWidth: ScreenWidths;
|
||||
@@ -21,7 +21,7 @@ export const Features = (props: FeatureProps) => {
|
||||
};
|
||||
const exploreTheDocsLinkInfo = {
|
||||
displayText: 'Explore the docs',
|
||||
linkSrc: `${utils.getCurrentBaseUrl()}/wiki#Get-Started`,
|
||||
linkSrc: `${WebsitePaths.Wiki}#Get-Started-With-Instant`,
|
||||
};
|
||||
const tokenLinkInfos = isSmallScreen ? [getStartedLinkInfo] : [getStartedLinkInfo, exploreTheDocsLinkInfo];
|
||||
return (
|
||||
@@ -40,7 +40,7 @@ export const Features = (props: FeatureProps) => {
|
||||
linkInfos={[
|
||||
{
|
||||
displayText: 'Learn about affiliate fees',
|
||||
linkSrc: `${utils.getCurrentBaseUrl()}/wiki#Learn-About-Affiliate-Fees`,
|
||||
linkSrc: `${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`,
|
||||
},
|
||||
]}
|
||||
screenWidth={props.screenWidth}
|
||||
@@ -52,7 +52,7 @@ export const Features = (props: FeatureProps) => {
|
||||
linkInfos={[
|
||||
{
|
||||
displayText: 'Explore AssetBuyer',
|
||||
linkSrc: `${utils.getCurrentBaseUrl()}/docs/asset-buyer`,
|
||||
linkSrc: `${WebsitePaths.Docs}/asset-buyer`,
|
||||
},
|
||||
]}
|
||||
screenWidth={props.screenWidth}
|
||||
@@ -61,17 +61,11 @@ export const Features = (props: FeatureProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface LinkInfo {
|
||||
displayText: string;
|
||||
linkSrc?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
interface FeatureItemProps {
|
||||
imgSrc: string;
|
||||
title: string;
|
||||
description: string;
|
||||
linkInfos: LinkInfo[];
|
||||
linkInfos: ActionLinkProps[];
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
@@ -95,36 +89,11 @@ const FeatureItem = (props: FeatureItemProps) => {
|
||||
</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>
|
||||
);
|
||||
})}
|
||||
{_.map(linkInfos, linkInfo => (
|
||||
<Container key={linkInfo.displayText} marginRight="32px">
|
||||
<ActionLink {...linkInfo} />
|
||||
</Container>
|
||||
))}
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
|
||||
72
packages/website/ts/pages/instant/fee_percentage_slider.tsx
Normal file
72
packages/website/ts/pages/instant/fee_percentage_slider.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import Slider from 'rc-slider';
|
||||
import 'rc-slider/assets/index.css';
|
||||
import * as React from 'react';
|
||||
|
||||
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%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export interface FeePercentageSliderProps {
|
||||
value: number;
|
||||
onChange: (value: number) => void;
|
||||
}
|
||||
|
||||
export class FeePercentageSlider extends React.Component<FeePercentageSliderProps> {
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<SliderWithTooltip
|
||||
min={0}
|
||||
max={0.05}
|
||||
step={0.0025}
|
||||
value={this.props.value}
|
||||
onChange={this.props.onChange}
|
||||
tipFormatter={this._feePercentageSliderFormatter}
|
||||
tipProps={{ placement: 'bottom' }}
|
||||
trackStyle={{
|
||||
backgroundColor: '#b4b4b4',
|
||||
}}
|
||||
railStyle={{
|
||||
backgroundColor: '#696969',
|
||||
}}
|
||||
handleStyle={{
|
||||
border: 'none',
|
||||
boxShadow: 'none',
|
||||
}}
|
||||
activeDotStyle={{
|
||||
boxShadow: 'none',
|
||||
border: 'none',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
private readonly _feePercentageSliderFormatter = (value: number): React.ReactNode => {
|
||||
return <Text fontColor={colors.black} fontSize="14px" fontWeight={700}>{`${(value * 100).toFixed(2)}%`}</Text>;
|
||||
};
|
||||
}
|
||||
@@ -14,7 +14,7 @@ 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 { ScreenWidths, WebsitePaths } from 'ts/types';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
@@ -67,7 +67,7 @@ export class Instant extends React.Component<InstantProps, InstantState> {
|
||||
}
|
||||
private readonly _onGetStartedClick = () => {
|
||||
if (this._isSmallScreen()) {
|
||||
utils.openUrl(`${utils.getCurrentBaseUrl()}/wiki#Get-Started`);
|
||||
utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`);
|
||||
} else {
|
||||
this._scrollToConfigurator();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ 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 { ScreenWidths, WebsitePaths } from 'ts/types';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
@@ -58,5 +58,5 @@ const onGetInTouchClick = () => {
|
||||
utils.openUrl(constants.URL_ZEROEX_CHAT);
|
||||
};
|
||||
const onDocsClick = () => {
|
||||
utils.openUrl(`${utils.getCurrentBaseUrl()}/wiki#Get-Started`);
|
||||
utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`);
|
||||
};
|
||||
|
||||
@@ -36,8 +36,8 @@ interface Project {
|
||||
}
|
||||
|
||||
const THROTTLE_TIMEOUT = 100;
|
||||
const WHATS_NEW_TITLE = 'Introducing the 0x Launch Kit';
|
||||
const WHATS_NEW_URL = 'https://blog.0xproject.com/introducing-the-0x-launch-kit-4acdc3453585';
|
||||
const WHATS_NEW_TITLE = 'Introducing 0x Instant';
|
||||
const WHATS_NEW_URL = WebsitePaths.Instant;
|
||||
const TITLE_STYLE: React.CSSProperties = {
|
||||
fontFamily: 'Roboto Mono',
|
||||
color: colors.grey,
|
||||
|
||||
209
yarn.lock
209
yarn.lock
@@ -1533,6 +1533,19 @@
|
||||
version "0.25.38"
|
||||
resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.25.38.tgz#6c945fcc91a5fa470cc3c5a4cd4a62d7f8d03576"
|
||||
|
||||
"@types/rc-slider@^8.6.0":
|
||||
version "8.6.0"
|
||||
resolved "https://registry.npmjs.org/@types/rc-slider/-/rc-slider-8.6.0.tgz#7f061a920b067825c8455cf481c57b0927889c72"
|
||||
dependencies:
|
||||
"@types/rc-tooltip" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/rc-tooltip@*":
|
||||
version "3.7.0"
|
||||
resolved "https://registry.npmjs.org/@types/rc-tooltip/-/rc-tooltip-3.7.0.tgz#6dc9898dc426495baea1b786e5dbde8980bf9737"
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-addons-linked-state-mixin@*":
|
||||
version "0.14.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-addons-linked-state-mixin/-/react-addons-linked-state-mixin-0.14.19.tgz#7ef00a5618a089da4a99e1f58c9aa4c1781d46d5"
|
||||
@@ -1607,6 +1620,12 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-syntax-highlighter@^0.0.8":
|
||||
version "0.0.8"
|
||||
resolved "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-0.0.8.tgz#ed44e2ead992c513327bcf2ede5eda7daa981421"
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-tap-event-plugin@0.0.30":
|
||||
version "0.0.30"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-tap-event-plugin/-/react-tap-event-plugin-0.0.30.tgz#123f35080412f489b6770c5a65c159ff96654cb5"
|
||||
@@ -1975,6 +1994,12 @@ acorn@^6.0.2:
|
||||
version "6.0.4"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754"
|
||||
|
||||
add-dom-event-listener@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310"
|
||||
dependencies:
|
||||
object-assign "4.x"
|
||||
|
||||
aes-js@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d"
|
||||
@@ -2937,7 +2962,7 @@ babel-register@^6.26.0:
|
||||
mkdirp "^0.5.1"
|
||||
source-map-support "^0.4.15"
|
||||
|
||||
babel-runtime@6.x.x, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
||||
babel-runtime@6.x, babel-runtime@6.x.x, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
dependencies:
|
||||
@@ -4183,6 +4208,12 @@ combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5, combined-
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
comma-separated-tokens@^1.0.0:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.5.tgz#b13793131d9ea2d2431cf5b507ddec258f0ce0db"
|
||||
dependencies:
|
||||
trim "0.0.1"
|
||||
|
||||
commander@2.11.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
|
||||
@@ -4228,10 +4259,20 @@ compare-versions@^3.0.1:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.1.0.tgz#43310256a5c555aaed4193c04d8f154cf9c6efd5"
|
||||
|
||||
component-classes@^1.2.5:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691"
|
||||
dependencies:
|
||||
component-indexof "0.0.3"
|
||||
|
||||
component-emitter@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
|
||||
|
||||
component-indexof@0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24"
|
||||
|
||||
compressible@~2.0.13:
|
||||
version "2.0.13"
|
||||
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9"
|
||||
@@ -4678,6 +4719,13 @@ crypto-random-string@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
|
||||
|
||||
css-animation@^1.3.2:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.npmjs.org/css-animation/-/css-animation-1.5.0.tgz#c96b9097a5ef74a7be8480b45cc44e4ec6ca2bf5"
|
||||
dependencies:
|
||||
babel-runtime "6.x"
|
||||
component-classes "^1.2.5"
|
||||
|
||||
css-color-keywords@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
|
||||
@@ -5320,6 +5368,10 @@ doctrine@^2.1.0:
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
dom-align@^1.7.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.npmjs.org/dom-align/-/dom-align-1.8.0.tgz#c0e89b5b674c6e836cd248c52c2992135f093654"
|
||||
|
||||
dom-helpers@^3.2.0, dom-helpers@^3.2.1, dom-helpers@^3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
|
||||
@@ -6474,6 +6526,12 @@ fastparse@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
|
||||
|
||||
fault@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/fault/-/fault-1.0.2.tgz#c3d0fec202f172a3a4d414042ad2bb5e2a3ffbaa"
|
||||
dependencies:
|
||||
format "^0.2.2"
|
||||
|
||||
faye-websocket@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
|
||||
@@ -6776,6 +6834,10 @@ format-util@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/format-util/-/format-util-1.0.3.tgz#032dca4a116262a12c43f4c3ec8566416c5b2d95"
|
||||
|
||||
format@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.npmjs.org/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
|
||||
|
||||
forwarded@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||
@@ -6938,7 +7000,7 @@ ganache-core@0xProject/ganache-core#monorepo-dep:
|
||||
ethereumjs-tx "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default"
|
||||
ethereumjs-util "^5.2.0"
|
||||
ethereumjs-vm "2.3.5"
|
||||
ethereumjs-wallet "0.6.0"
|
||||
ethereumjs-wallet "~0.6.0"
|
||||
fake-merkle-patricia-tree "~1.0.1"
|
||||
heap "~0.2.6"
|
||||
js-scrypt "^0.2.0"
|
||||
@@ -7627,6 +7689,19 @@ hash.js@1.1.3, hash.js@^1.0.0, hash.js@^1.0.3:
|
||||
inherits "^2.0.3"
|
||||
minimalistic-assert "^1.0.0"
|
||||
|
||||
hast-util-parse-selector@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.1.tgz#4ddbae1ae12c124e3eb91b581d2556441766f0ab"
|
||||
|
||||
hastscript@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/hastscript/-/hastscript-5.0.0.tgz#fee10382c1bc4ba3f1be311521d368c047d2c43a"
|
||||
dependencies:
|
||||
comma-separated-tokens "^1.0.0"
|
||||
hast-util-parse-selector "^2.2.0"
|
||||
property-information "^5.0.1"
|
||||
space-separated-tokens "^1.0.0"
|
||||
|
||||
hawk@3.1.3, hawk@~3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
|
||||
@@ -7667,7 +7742,7 @@ heap@~0.2.6:
|
||||
version "0.2.6"
|
||||
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac"
|
||||
|
||||
highlight.js@^9.0.0, highlight.js@^9.11.0, highlight.js@^9.6.0:
|
||||
highlight.js@^9.0.0, highlight.js@^9.11.0, highlight.js@^9.6.0, highlight.js@~9.12.0:
|
||||
version "9.12.0"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
|
||||
|
||||
@@ -9835,7 +9910,7 @@ lodash.isequal@^4.0.0, lodash.isequal@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
|
||||
lodash.keys@^3.0.0:
|
||||
lodash.keys@^3.0.0, lodash.keys@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
|
||||
dependencies:
|
||||
@@ -10028,6 +10103,13 @@ lowercase-keys@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
|
||||
|
||||
lowlight@~1.9.1:
|
||||
version "1.9.2"
|
||||
resolved "https://registry.npmjs.org/lowlight/-/lowlight-1.9.2.tgz#0b9127e3cec2c3021b7795dd81005c709a42fdd1"
|
||||
dependencies:
|
||||
fault "^1.0.2"
|
||||
highlight.js "~9.12.0"
|
||||
|
||||
lru-cache@2:
|
||||
version "2.7.3"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
|
||||
@@ -11152,14 +11234,14 @@ oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
|
||||
object-assign@4.x, object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
object-assign@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
|
||||
|
||||
object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
object-copy@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
|
||||
@@ -11608,6 +11690,17 @@ parse-entities@^1.1.0:
|
||||
is-decimal "^1.0.0"
|
||||
is-hexadecimal "^1.0.0"
|
||||
|
||||
parse-entities@^1.1.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.0.tgz#9deac087661b2e36814153cb78d7e54a4c5fd6f4"
|
||||
dependencies:
|
||||
character-entities "^1.0.0"
|
||||
character-entities-legacy "^1.0.0"
|
||||
character-reference-invalid "^1.0.0"
|
||||
is-alphanumerical "^1.0.0"
|
||||
is-decimal "^1.0.0"
|
||||
is-hexadecimal "^1.0.0"
|
||||
|
||||
parse-filepath@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
|
||||
@@ -12261,7 +12354,7 @@ pretty-hrtime@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||
|
||||
prismjs@^1.15.0:
|
||||
prismjs@^1.15.0, prismjs@^1.8.4, prismjs@~1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.15.0.tgz#8801d332e472091ba8def94976c8877ad60398d9"
|
||||
optionalDependencies:
|
||||
@@ -12346,7 +12439,7 @@ promzard@^0.3.0:
|
||||
dependencies:
|
||||
read "1"
|
||||
|
||||
prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.6.2:
|
||||
prop-types@15.x, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.6.2:
|
||||
version "15.6.2"
|
||||
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||
dependencies:
|
||||
@@ -12361,6 +12454,12 @@ prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8,
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
property-information@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/property-information/-/property-information-5.0.1.tgz#c3b09f4f5750b1634c0b24205adbf78f18bdf94f"
|
||||
dependencies:
|
||||
xtend "^4.0.1"
|
||||
|
||||
proto-list@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "http://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
|
||||
@@ -12644,6 +12743,66 @@ raw-loader@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
|
||||
|
||||
rc-align@^2.4.0:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.npmjs.org/rc-align/-/rc-align-2.4.3.tgz#b9b3c2a6d68adae71a8e1d041cd5e3b2a655f99a"
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
dom-align "^1.7.0"
|
||||
prop-types "^15.5.8"
|
||||
rc-util "^4.0.4"
|
||||
|
||||
rc-animate@2.x:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.npmjs.org/rc-animate/-/rc-animate-2.6.0.tgz#ca8440d042781af7a1329d84f97ea94794c5ec15"
|
||||
dependencies:
|
||||
babel-runtime "6.x"
|
||||
classnames "^2.2.6"
|
||||
css-animation "^1.3.2"
|
||||
prop-types "15.x"
|
||||
raf "^3.4.0"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
rc-slider@^8.6.3:
|
||||
version "8.6.3"
|
||||
resolved "https://registry.npmjs.org/rc-slider/-/rc-slider-8.6.3.tgz#1ca0e0bd2863252741de75e7bf8c9f2cfcffccb7"
|
||||
dependencies:
|
||||
babel-runtime "6.x"
|
||||
classnames "^2.2.5"
|
||||
prop-types "^15.5.4"
|
||||
rc-tooltip "^3.7.0"
|
||||
rc-util "^4.0.4"
|
||||
shallowequal "^1.0.1"
|
||||
warning "^3.0.0"
|
||||
|
||||
rc-tooltip@^3.7.0:
|
||||
version "3.7.3"
|
||||
resolved "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-3.7.3.tgz#280aec6afcaa44e8dff0480fbaff9e87fc00aecc"
|
||||
dependencies:
|
||||
babel-runtime "6.x"
|
||||
prop-types "^15.5.8"
|
||||
rc-trigger "^2.2.2"
|
||||
|
||||
rc-trigger@^2.2.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.6.2.tgz#a9c09ba5fad63af3b2ec46349c7db6cb46657001"
|
||||
dependencies:
|
||||
babel-runtime "6.x"
|
||||
classnames "^2.2.6"
|
||||
prop-types "15.x"
|
||||
rc-align "^2.4.0"
|
||||
rc-animate "2.x"
|
||||
rc-util "^4.4.0"
|
||||
|
||||
rc-util@^4.0.4, rc-util@^4.4.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.npmjs.org/rc-util/-/rc-util-4.6.0.tgz#ba33721783192ec4f3afb259e182b04e55deb7f6"
|
||||
dependencies:
|
||||
add-dom-event-listener "^1.1.0"
|
||||
babel-runtime "6.x"
|
||||
prop-types "^15.5.10"
|
||||
shallowequal "^0.2.2"
|
||||
|
||||
rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.6.tgz#eb18989c6d4f4f162c399f79ddd29f3835568092"
|
||||
@@ -12828,6 +12987,16 @@ react-side-effect@^1.0.2, react-side-effect@^1.1.0:
|
||||
exenv "^1.2.1"
|
||||
shallowequal "^1.0.1"
|
||||
|
||||
react-syntax-highlighter@^10.1.1:
|
||||
version "10.1.1"
|
||||
resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-10.1.1.tgz#1bf7ad4f2f16d2978b04594407b670671b4d3316"
|
||||
dependencies:
|
||||
babel-runtime "^6.18.0"
|
||||
highlight.js "~9.12.0"
|
||||
lowlight "~1.9.1"
|
||||
prismjs "^1.8.4"
|
||||
refractor "^2.4.1"
|
||||
|
||||
react-tabs@^2.0.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.npmjs.org/react-tabs/-/react-tabs-2.2.2.tgz#2f2935da379889484751d1df47c1b639e5ee835d"
|
||||
@@ -13157,6 +13326,14 @@ reflect-metadata@^0.1.12:
|
||||
version "0.1.12"
|
||||
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2"
|
||||
|
||||
refractor@^2.4.1:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.npmjs.org/refractor/-/refractor-2.6.2.tgz#8e0877ab8864165275aafeea5d9c8eebe871552f"
|
||||
dependencies:
|
||||
hastscript "^5.0.0"
|
||||
parse-entities "^1.1.2"
|
||||
prismjs "~1.15.0"
|
||||
|
||||
regenerate@^1.2.1:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f"
|
||||
@@ -14010,6 +14187,12 @@ sha3@^1.1.0:
|
||||
dependencies:
|
||||
nan "2.10.0"
|
||||
|
||||
shallowequal@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e"
|
||||
dependencies:
|
||||
lodash.keys "^3.1.2"
|
||||
|
||||
shallowequal@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.0.2.tgz#1561dbdefb8c01408100319085764da3fcf83f8f"
|
||||
@@ -14383,6 +14566,12 @@ source-map@~0.2.0:
|
||||
dependencies:
|
||||
amdefine ">=0.0.4"
|
||||
|
||||
space-separated-tokens@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.2.tgz#e95ab9d19ae841e200808cd96bc7bd0adbbb3412"
|
||||
dependencies:
|
||||
trim "0.0.1"
|
||||
|
||||
sparkles@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3"
|
||||
|
||||
Reference in New Issue
Block a user