diff options
author | Hsuan Lee <boczeratul@gmail.com> | 2019-03-06 17:46:50 +0800 |
---|---|---|
committer | Hsuan Lee <boczeratul@gmail.com> | 2019-03-06 17:46:50 +0800 |
commit | 35703539d0f2b4ddb3b11d0de8c9634af59ab71f (patch) | |
tree | ae3731221dbbb3a6fa40060a8d916cfd3f738289 /packages/website/ts | |
parent | 92a1fde5b1ecd81b07cdb5bf0c9c1cd3544799db (diff) | |
download | dexon-0x-contracts-stable.tar.gz dexon-0x-contracts-stable.tar.zst dexon-0x-contracts-stable.zip |
Deploy @dexon-foundation/0x.jsstable
Diffstat (limited to 'packages/website/ts')
291 files changed, 0 insertions, 28372 deletions
diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts deleted file mode 100644 index ea5a59340..000000000 --- a/packages/website/ts/blockchain.ts +++ /dev/null @@ -1,953 +0,0 @@ -import { - BlockRange, - ContractWrappers, - DecodedLogEvent, - ExchangeCancelEventArgs, - ExchangeEventArgs, - ExchangeEvents, - ExchangeFillEventArgs, - IndexedFilterValues, -} from '@0x/contract-wrappers'; -import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils'; -import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared'; -import { - ledgerEthereumBrowserClientFactoryAsync, - LedgerSubprovider, - MetamaskSubprovider, - RedundantSubprovider, - RPCSubprovider, - SignerSubprovider, - Web3ProviderEngine, -} from '@0x/subproviders'; -import { SignedOrder, Token as ZeroExToken } from '@0x/types'; -import { BigNumber, intervalUtils, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { BlockParam, LogWithDecodedArgs, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; -import * as moment from 'moment'; -import * as React from 'react'; -import contract from 'truffle-contract'; -import { BlockchainWatcher } from 'ts/blockchain_watcher'; -import { AssetSendCompleted } from 'ts/components/flash_messages/asset_send_completed'; -import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted'; -import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; -import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { - BlockchainCallErrs, - BlockchainErrs, - ContractInstance, - Fill, - InjectedProvider, - InjectedProviderObservable, - InjectedProviderUpdate, - Providers, - ProviderType, - Side, - SideToAssetToken, - Token, - TokenByAddress, -} from 'ts/types'; -import { backendClient } from 'ts/utils/backend_client'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { fakeTokenRegistry } from 'ts/utils/fake_token_registry'; -import { tokenAddressOverrides } from 'ts/utils/token_address_overrides'; -import { utils } from 'ts/utils/utils'; -import FilterSubprovider from 'web3-provider-engine/subproviders/filters'; - -import MintableArtifacts from '../contracts/Mintable.json'; - -const BLOCK_NUMBER_BACK_TRACK = 50; -const GWEI_IN_WEI = 1000000000; - -const providerToName: { [provider: string]: string } = { - [Providers.Metamask]: constants.PROVIDER_NAME_METAMASK, - [Providers.Parity]: constants.PROVIDER_NAME_PARITY_SIGNER, - [Providers.Mist]: constants.PROVIDER_NAME_MIST, - [Providers.CoinbaseWallet]: constants.PROVIDER_NAME_COINBASE_WALLET, - [Providers.Cipher]: constants.PROVIDER_NAME_CIPHER, -}; - -export class Blockchain { - public networkId: number; - public nodeVersion: string; - private _contractWrappers: ContractWrappers; - private readonly _dispatcher: Dispatcher; - private _web3Wrapper?: Web3Wrapper; - private _blockchainWatcher?: BlockchainWatcher; - private _injectedProviderObservable?: InjectedProviderObservable; - private readonly _injectedProviderUpdateHandler: (update: InjectedProviderUpdate) => Promise<void>; - private _userAddressIfExists: string; - private _ledgerSubprovider: LedgerSubprovider; - private _defaultGasPrice: BigNumber; - private _watchGasPriceIntervalId: NodeJS.Timer; - private _injectedProviderIfExists?: InjectedProvider; - private static _getNameGivenProvider(provider: Provider): string { - const providerType = utils.getProviderType(provider); - const providerNameIfExists = providerToName[providerType]; - if (_.isUndefined(providerNameIfExists)) { - return constants.PROVIDER_NAME_GENERIC; - } - return providerNameIfExists; - } - private static async _getProviderAsync( - injectedProviderIfExists?: InjectedProvider, - networkIdIfExists?: number, - shouldUserLedgerProvider: boolean = false, - ): Promise<[Provider, LedgerSubprovider | undefined]> { - const doesInjectedProviderExist = !_.isUndefined(injectedProviderIfExists); - const isNetworkIdAvailable = !_.isUndefined(networkIdIfExists); - const publicNodeUrlsIfExistsForNetworkId = configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists]; - const isPublicNodeAvailableForNetworkId = !_.isUndefined(publicNodeUrlsIfExistsForNetworkId); - - if (shouldUserLedgerProvider && isNetworkIdAvailable) { - const isU2FSupported = await utils.isU2FSupportedAsync(); - if (!isU2FSupported) { - throw new Error('Cannot update providerType to LEDGER without U2F support'); - } - const provider = new Web3ProviderEngine(); - const ledgerWalletConfigs = { - networkId: networkIdIfExists, - ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync, - }; - const ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs); - provider.addProvider(ledgerSubprovider); - provider.addProvider(new FilterSubprovider()); - const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists], publicNodeUrl => { - return new RPCSubprovider(publicNodeUrl); - }); - provider.addProvider(new RedundantSubprovider(rpcSubproviders)); - provider.start(); - return [provider, ledgerSubprovider]; - } else if (doesInjectedProviderExist && isPublicNodeAvailableForNetworkId) { - // We catch all requests involving a users account and send it to the injectedWeb3 - // instance. All other requests go to the public hosted node. - const provider = new Web3ProviderEngine(); - const providerName = this._getNameGivenProvider(injectedProviderIfExists); - // Wrap Metamask in a compatability wrapper MetamaskSubprovider (to handle inconsistencies) - const signerSubprovider = - providerName === constants.PROVIDER_NAME_METAMASK - ? new MetamaskSubprovider(injectedProviderIfExists) - : new SignerSubprovider(injectedProviderIfExists); - provider.addProvider(signerSubprovider); - provider.addProvider(new FilterSubprovider()); - const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => { - return new RPCSubprovider(publicNodeUrl); - }); - provider.addProvider(new RedundantSubprovider(rpcSubproviders)); - provider.start(); - return [provider, undefined]; - } else if (doesInjectedProviderExist) { - // Since no public node for this network, all requests go to injectedWeb3 instance - return [injectedProviderIfExists, undefined]; - } else { - // If no injectedWeb3 instance, all requests fallback to our public hosted mainnet/testnet node - // We do this so that users can still browse the 0x Portal DApp even if they do not have web3 - // injected into their browser. - const provider = new Web3ProviderEngine(); - provider.addProvider(new FilterSubprovider()); - const networkId = constants.NETWORK_ID_MAINNET; - const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], publicNodeUrl => { - return new RPCSubprovider(publicNodeUrl); - }); - provider.addProvider(new RedundantSubprovider(rpcSubproviders)); - provider.start(); - return [provider, undefined]; - } - } - constructor(dispatcher: Dispatcher) { - this._dispatcher = dispatcher; - const defaultGasPrice = GWEI_IN_WEI * 40; - this._defaultGasPrice = new BigNumber(defaultGasPrice); - // We need a unique reference to this function so we can use it to unsubcribe. - this._injectedProviderUpdateHandler = this._handleInjectedProviderUpdateAsync.bind(this); - // tslint:disable-next-line:no-floating-promises - this._onPageLoadInitFireAndForgetAsync(); - } - public async networkIdUpdatedFireAndForgetAsync(newNetworkId: number): Promise<void> { - const isConnected = !_.isUndefined(newNetworkId); - if (!isConnected) { - this.networkId = newNetworkId; - this._dispatcher.encounteredBlockchainError(BlockchainErrs.DisconnectedFromEthereumNode); - this._dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - } else if (this.networkId !== newNetworkId) { - this.networkId = newNetworkId; - this._dispatcher.encounteredBlockchainError(BlockchainErrs.NoError); - await this.fetchTokenInformationAsync(); - await this._rehydrateStoreWithContractEventsAsync(); - } - } - public async userAddressUpdatedFireAndForgetAsync(newUserAddress: string): Promise<void> { - if (this._userAddressIfExists !== newUserAddress) { - this._userAddressIfExists = newUserAddress; - await this.fetchTokenInformationAsync(); - await this._rehydrateStoreWithContractEventsAsync(); - } - } - public async nodeVersionUpdatedFireAndForgetAsync(nodeVersion: string): Promise<void> { - if (this.nodeVersion !== nodeVersion) { - this.nodeVersion = nodeVersion; - } - } - public async isAddressInTokenRegistryAsync(tokenAddress: string): Promise<boolean> { - const tokens = fakeTokenRegistry[this.networkId]; - const tokenIfExists = _.find(tokens, { address: tokenAddress }); - - // HACK: Override token addresses on testnets - const tokenSymbolToAddressOverrides = tokenAddressOverrides[this.networkId]; - let isTokenAddressInOverrides = false; - if (!_.isUndefined(tokenSymbolToAddressOverrides)) { - isTokenAddressInOverrides = _.values(tokenSymbolToAddressOverrides).includes(tokenAddress); - } - return !_.isUndefined(tokenIfExists) || isTokenAddressInOverrides; - } - public getLedgerDerivationPathIfExists(): string { - if (_.isUndefined(this._ledgerSubprovider)) { - return undefined; - } - const path = this._ledgerSubprovider.getPath(); - return path; - } - public updateLedgerDerivationPathIfExists(path: string): void { - if (_.isUndefined(this._ledgerSubprovider)) { - return; // noop - } - this._ledgerSubprovider.setPath(path); - } - public async updateProviderToLedgerAsync(networkId: number): Promise<void> { - const shouldPollUserAddress = false; - const shouldUserLedgerProvider = true; - await this._resetOrInitializeAsync(networkId, shouldPollUserAddress, shouldUserLedgerProvider); - } - public async updateProviderToInjectedAsync(): Promise<void> { - const shouldPollUserAddress = true; - const shouldUserLedgerProvider = false; - this._dispatcher.updateBlockchainIsLoaded(false); - // We don't want to be out of sync with the network the injected provider declares. - const networkId = await this._getInjectedProviderNetworkIdIfExistsAsync(); - await this._resetOrInitializeAsync(networkId, shouldPollUserAddress, shouldUserLedgerProvider); - } - public async setProxyAllowanceAsync(token: Token, amountInBaseUnits: BigNumber): Promise<void> { - utils.assert(this.isValidAddress(token.address), BlockchainCallErrs.TokenAddressIsInvalid); - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - utils.assert(!_.isUndefined(this._contractWrappers), 'Contract Wrappers must be instantiated.'); - - this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.erc20Token.setProxyAllowanceAsync( - token.address, - this._userAddressIfExists, - amountInBaseUnits, - { - gasPrice: this._defaultGasPrice, - }, - ); - await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - } - public async sendAsync(toAddress: string, amountInBaseUnits: BigNumber): Promise<void> { - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - const transaction = { - from: this._userAddressIfExists, - to: toAddress, - value: amountInBaseUnits, - gasPrice: this._defaultGasPrice, - }; - this._showFlashMessageIfLedger(); - const txHash = await this._web3Wrapper.sendTransactionAsync(transaction); - await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - const etherScanLinkIfExists = sharedUtils.getEtherScanLinkIfExists( - txHash, - this.networkId, - EtherscanLinkSuffixes.Tx, - ); - this._dispatcher.showFlashMessage( - React.createElement(AssetSendCompleted, { - etherScanLinkIfExists, - toAddress, - amountInBaseUnits, - decimals: constants.DECIMAL_PLACES_ETH, - symbol: constants.ETHER_SYMBOL, - }), - ); - } - public async transferAsync(token: Token, toAddress: string, amountInBaseUnits: BigNumber): Promise<void> { - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.erc20Token.transferAsync( - token.address, - this._userAddressIfExists, - toAddress, - amountInBaseUnits, - { - gasPrice: this._defaultGasPrice, - }, - ); - await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - const etherScanLinkIfExists = sharedUtils.getEtherScanLinkIfExists( - txHash, - this.networkId, - EtherscanLinkSuffixes.Tx, - ); - this._dispatcher.showFlashMessage( - React.createElement(AssetSendCompleted, { - etherScanLinkIfExists, - toAddress, - amountInBaseUnits, - decimals: token.decimals, - symbol: token.symbol, - }), - ); - } - public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber): Promise<BigNumber> { - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.exchange.fillOrderAsync( - signedOrder, - fillTakerTokenAmount, - this._userAddressIfExists, - { - gasPrice: this._defaultGasPrice, - }, - ); - const receipt = await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - const logs: Array<LogWithDecodedArgs<ExchangeEventArgs>> = receipt.logs as any; - const logFill = _.find(logs, { event: ExchangeEvents.Fill }); - const args = (logFill.args as any) as ExchangeFillEventArgs; - const takerAssetFilledAmount = args.takerAssetFilledAmount; - return takerAssetFilledAmount; - } - public async cancelOrderAsync(signedOrder: SignedOrder): Promise<string> { - this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.exchange.cancelOrderAsync(signedOrder, { - gasPrice: this._defaultGasPrice, - }); - const receipt = await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - const logs: Array<LogWithDecodedArgs<ExchangeEventArgs>> = receipt.logs as any; - const logCancel = _.find(logs, { event: ExchangeEvents.Cancel }); - const args = (logCancel.args as any) as ExchangeCancelEventArgs; - const cancelledOrderHash = args.orderHash; - return cancelledOrderHash; - } - public async getUnavailableTakerAmountAsync(orderHash: string): Promise<BigNumber> { - utils.assert(orderHashUtils.isValidOrderHash(orderHash), 'Must be valid orderHash'); - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - const unavailableTakerAmount = await this._contractWrappers.exchange.getFilledTakerAssetAmountAsync(orderHash); - return unavailableTakerAmount; - } - public getExchangeContractAddressIfExists(): string | undefined { - return this._contractWrappers.exchange.address; - } - public async validateFillOrderThrowIfInvalidAsync( - signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, - takerAddress: string, - ): Promise<void> { - await this._contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, - fillTakerTokenAmount, - takerAddress, - ); - } - public isValidAddress(address: string): boolean { - const lowercaseAddress = address.toLowerCase(); - return Web3Wrapper.isAddress(lowercaseAddress); - } - public async isValidSignatureAsync(data: string, signature: string, signerAddress: string): Promise<boolean> { - const result = await signatureUtils.isValidSignatureAsync( - this._contractWrappers.getProvider(), - data, - signature, - signerAddress, - ); - return result; - } - public async pollTokenBalanceAsync(token: Token): Promise<BigNumber> { - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - const [currBalance] = await this.getTokenBalanceAndAllowanceAsync(this._userAddressIfExists, token.address); - - const newTokenBalancePromise = new Promise((resolve: (balance: BigNumber) => void, reject) => { - const tokenPollInterval = intervalUtils.setAsyncExcludingInterval( - async () => { - const [balance] = await this.getTokenBalanceAndAllowanceAsync( - this._userAddressIfExists, - token.address, - ); - if (!balance.eq(currBalance)) { - intervalUtils.clearAsyncExcludingInterval(tokenPollInterval); - resolve(balance); - } - }, - 5000, - (err: Error) => { - logUtils.log(`Polling tokenBalance failed: ${err}`); - intervalUtils.clearAsyncExcludingInterval(tokenPollInterval); - reject(err); - }, - ); - }); - - return newTokenBalancePromise; - } - public async signOrderHashAsync(orderHash: string): Promise<string> { - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - const makerAddress = this._userAddressIfExists; - // If makerAddress is undefined, this means they have a web3 instance injected into their browser - // but no account addresses associated with it. - if (_.isUndefined(makerAddress)) { - throw new Error('Tried to send a sign request but user has no associated addresses'); - } - this._showFlashMessageIfLedger(); - const provider = this._contractWrappers.getProvider(); - const ecSignatureString = await signatureUtils.ecSignHashAsync(provider, orderHash, makerAddress); - this._dispatcher.updateSignature(ecSignatureString); - return ecSignatureString; - } - public async mintTestTokensAsync(token: Token): Promise<void> { - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - const mintableContract = await this._instantiateContractIfExistsAsync(MintableArtifacts, token.address); - this._showFlashMessageIfLedger(); - await mintableContract.mint(constants.MINT_AMOUNT, { - from: this._userAddressIfExists, - gasPrice: this._defaultGasPrice, - }); - } - public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> { - const balanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(owner); - return balanceInWei; - } - public async convertEthToWrappedEthTokensAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> { - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.etherToken.depositAsync( - etherTokenAddress, - amount, - this._userAddressIfExists, - { - gasPrice: this._defaultGasPrice, - }, - ); - await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - } - public async convertWrappedEthTokensToEthAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> { - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.etherToken.withdrawAsync( - etherTokenAddress, - amount, - this._userAddressIfExists, - { - gasPrice: this._defaultGasPrice, - }, - ); - await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - } - public async doesContractExistAtAddressAsync(address: string): Promise<boolean> { - const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(address); - return doesContractExist; - } - public async getCurrentUserTokenBalanceAndAllowanceAsync(tokenAddress: string): Promise<BigNumber[]> { - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - const tokenBalanceAndAllowance = await this.getTokenBalanceAndAllowanceAsync( - this._userAddressIfExists, - tokenAddress, - ); - return tokenBalanceAndAllowance; - } - public async getTokenBalanceAndAllowanceAsync( - ownerAddressIfExists: string, - tokenAddress: string, - ): Promise<[BigNumber, BigNumber]> { - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - - if (_.isUndefined(ownerAddressIfExists)) { - const zero = new BigNumber(0); - return [zero, zero]; - } - let balance = new BigNumber(0); - let allowance = new BigNumber(0); - if (this._doesUserAddressExist()) { - [balance, allowance] = await Promise.all([ - this._contractWrappers.erc20Token.getBalanceAsync(tokenAddress, ownerAddressIfExists), - this._contractWrappers.erc20Token.getProxyAllowanceAsync(tokenAddress, ownerAddressIfExists), - ]); - } - return [balance, allowance]; - } - public async getUserAccountsAsync(): Promise<string[]> { - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - const provider = this._contractWrappers.getProvider(); - const web3Wrapper = new Web3Wrapper(provider); - const userAccountsIfExists = await web3Wrapper.getAvailableAddressesAsync(); - return userAccountsIfExists; - } - // HACK: When a user is using a Ledger, we simply dispatch the selected userAddress, which - // by-passes the web3Wrapper logic for updating the prevUserAddress. We therefore need to - // manually update it. This should only be called by the LedgerConfigDialog. - public updateWeb3WrapperPrevUserAddress(newUserAddress: string): void { - this._blockchainWatcher.updatePrevUserAddress(newUserAddress); - } - public destroy(): void { - this._blockchainWatcher.destroy(); - if (this._injectedProviderObservable) { - this._injectedProviderObservable.unsubscribe(this._injectedProviderUpdateHandler); - } - this._stopWatchingExchangeLogFillEvents(); - this._stopWatchingGasPrice(); - } - public async fetchTokenInformationAsync(): Promise<void> { - utils.assert( - !_.isUndefined(this.networkId), - 'Cannot call fetchTokenInformationAsync if disconnected from Ethereum node', - ); - - this._dispatcher.updateBlockchainIsLoaded(false); - - const tokenRegistryTokensByAddress = await this._getTokenRegistryTokensByAddressAsync(); - - const trackedTokensByAddress = _.isUndefined(this._userAddressIfExists) - ? {} - : trackedTokenStorage.getTrackedTokensByAddress(this._userAddressIfExists, this.networkId); - const tokenRegistryTokens = _.values(tokenRegistryTokensByAddress); - const tokenRegistryTokenSymbols = _.map(tokenRegistryTokens, t => t.symbol); - const defaultTrackedTokensInRegistry = _.intersection( - tokenRegistryTokenSymbols, - configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, - ); - const currentTimestamp = moment().unix(); - if (defaultTrackedTokensInRegistry.length !== configs.DEFAULT_TRACKED_TOKEN_SYMBOLS.length) { - this._dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - this._dispatcher.encounteredBlockchainError(BlockchainErrs.DefaultTokensNotInTokenRegistry); - const err = new Error( - `Default tracked tokens (${JSON.stringify( - configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, - )}) not found in tokenRegistry: ${JSON.stringify(tokenRegistryTokens)}`, - ); - errorReporter.report(err); - return; - } - if (_.isEmpty(trackedTokensByAddress)) { - _.each(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, symbol => { - const token = _.find(tokenRegistryTokens, t => t.symbol === symbol); - token.trackedTimestamp = currentTimestamp; - trackedTokensByAddress[token.address] = token; - }); - if (!_.isUndefined(this._userAddressIfExists)) { - _.each(trackedTokensByAddress, (token: Token) => { - trackedTokenStorage.addTrackedTokenToUser(this._userAddressIfExists, this.networkId, token); - }); - } - } else { - // Properly set all tokenRegistry tokens `trackedTimestamp` if they are in the existing trackedTokens array - _.each(trackedTokensByAddress, (trackedToken: Token, address: string) => { - if (!_.isUndefined(tokenRegistryTokensByAddress[address])) { - tokenRegistryTokensByAddress[address].trackedTimestamp = trackedToken.trackedTimestamp; - } - }); - } - const allTokensByAddress = { - ...tokenRegistryTokensByAddress, - ...trackedTokensByAddress, - }; - const allTokens = _.values(allTokensByAddress); - const mostPopularTradingPairTokens: Token[] = [ - _.find(allTokens, { symbol: configs.DEFAULT_TRACKED_TOKEN_SYMBOLS[0] }), - _.find(allTokens, { symbol: configs.DEFAULT_TRACKED_TOKEN_SYMBOLS[1] }), - ]; - const sideToAssetToken: SideToAssetToken = { - [Side.Deposit]: { - address: mostPopularTradingPairTokens[0].address, - }, - [Side.Receive]: { - address: mostPopularTradingPairTokens[1].address, - }, - }; - this._dispatcher.batchDispatch(allTokensByAddress, this.networkId, this._userAddressIfExists, sideToAssetToken); - - this._dispatcher.updateBlockchainIsLoaded(true); - } - private async _getInjectedProviderIfExistsAsync(): Promise<InjectedProvider | undefined> { - if (!_.isUndefined(this._injectedProviderIfExists)) { - return this._injectedProviderIfExists; - } - let injectedProviderIfExists = (window as any).ethereum; - if (!_.isUndefined(injectedProviderIfExists)) { - if (!_.isUndefined(injectedProviderIfExists.enable)) { - try { - await injectedProviderIfExists.enable(); - } catch (err) { - errorReporter.report(err); - } - } - } else { - const injectedWeb3IfExists = (window as any).web3; - if (!_.isUndefined(injectedWeb3IfExists) && !_.isUndefined(injectedWeb3IfExists.currentProvider)) { - injectedProviderIfExists = injectedWeb3IfExists.currentProvider; - } else { - return undefined; - } - } - this._injectedProviderIfExists = injectedProviderIfExists; - return injectedProviderIfExists; - } - private async _getInjectedProviderNetworkIdIfExistsAsync(): Promise<number | undefined> { - // If the user has an injectedWeb3 instance that is disconnected from a backing - // Ethereum node, this call will throw. We need to handle this case gracefully - const injectedProviderIfExists = await this._getInjectedProviderIfExistsAsync(); - let networkIdIfExists: number; - if (!_.isUndefined(injectedProviderIfExists)) { - try { - const injectedWeb3Wrapper = new Web3Wrapper(injectedProviderIfExists); - networkIdIfExists = await injectedWeb3Wrapper.getNetworkIdAsync(); - } catch (err) { - // Ignore error and proceed with networkId undefined - } - } - return networkIdIfExists; - } - private async _showEtherScanLinkAndAwaitTransactionMinedAsync( - txHash: string, - ): Promise<TransactionReceiptWithDecodedLogs> { - const etherScanLinkIfExists = sharedUtils.getEtherScanLinkIfExists( - txHash, - this.networkId, - EtherscanLinkSuffixes.Tx, - ); - this._dispatcher.showFlashMessage( - React.createElement(TransactionSubmitted, { - etherScanLinkIfExists, - }), - ); - const provider = this._contractWrappers.getProvider(); - const web3Wrapper = new Web3Wrapper(provider); - const exchangeAbi = this._contractWrappers.exchange.abi; - web3Wrapper.abiDecoder.addABI(exchangeAbi); - const receipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); - return receipt; - } - private _doesUserAddressExist(): boolean { - return !_.isUndefined(this._userAddressIfExists); - } - private async _handleInjectedProviderUpdateAsync(update: InjectedProviderUpdate): Promise<void> { - if (update.networkVersion === 'loading' || !_.isUndefined(this._ledgerSubprovider)) { - return; - } - const updatedNetworkId = _.parseInt(update.networkVersion); - if (this.networkId === updatedNetworkId) { - return; - } - const shouldPollUserAddress = true; - const shouldUserLedgerProvider = false; - await this._resetOrInitializeAsync(updatedNetworkId, shouldPollUserAddress, shouldUserLedgerProvider); - } - private async _rehydrateStoreWithContractEventsAsync(): Promise<void> { - // Ensure we are only ever listening to one set of events - this._stopWatchingExchangeLogFillEvents(); - - if (!this._doesUserAddressExist()) { - return; // short-circuit - } - - if (!_.isUndefined(this._contractWrappers)) { - // Since we do not have an index on the `taker` address and want to show - // transactions where an account is either the `maker` or `taker`, we loop - // through all fill events, and filter/cache them client-side. - const filterIndexObj = {}; - await this._startListeningForExchangeLogFillEventsAsync(filterIndexObj); - } - } - private async _startListeningForExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues): Promise<void> { - utils.assert(!_.isUndefined(this._contractWrappers), 'ContractWrappers must be instantiated.'); - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - // Fetch historical logs - await this._fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues); - - // Start a subscription for new logs - this._contractWrappers.exchange.subscribe( - ExchangeEvents.Fill, - indexFilterValues, - async (err: Error, decodedLogEvent: DecodedLogEvent<ExchangeFillEventArgs>) => { - if (err) { - // Note: it's not entirely clear from the documentation which - // errors will be thrown by `watch`. For now, let's log the error - // to rollbar and stop watching when one occurs - errorReporter.report(err); // fire and forget - return; - } else { - const decodedLog = decodedLogEvent.log; - if (!this._doesLogEventInvolveUser(decodedLog)) { - return; // We aren't interested in the fill event - } - this._updateLatestFillsBlockIfNeeded(decodedLog.blockNumber); - const fill = await this._convertDecodedLogToFillAsync(decodedLog); - if (decodedLogEvent.isRemoved) { - tradeHistoryStorage.removeFillFromUser(this._userAddressIfExists, this.networkId, fill); - } else { - tradeHistoryStorage.addFillToUser(this._userAddressIfExists, this.networkId, fill); - } - } - }, - ); - } - private async _fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues): Promise<void> { - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this._userAddressIfExists, this.networkId); - const blockRange: BlockRange = { - fromBlock, - toBlock: 'latest' as BlockParam, - }; - const decodedLogs = await this._contractWrappers.exchange.getLogsAsync<ExchangeFillEventArgs>( - ExchangeEvents.Fill, - blockRange, - indexFilterValues, - ); - for (const decodedLog of decodedLogs) { - if (!this._doesLogEventInvolveUser(decodedLog)) { - continue; // We aren't interested in the fill event - } - this._updateLatestFillsBlockIfNeeded(decodedLog.blockNumber); - const fill = await this._convertDecodedLogToFillAsync(decodedLog); - tradeHistoryStorage.addFillToUser(this._userAddressIfExists, this.networkId, fill); - } - } - private async _convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<ExchangeFillEventArgs>): Promise<Fill> { - const args = decodedLog.args; - const blockTimestamp = await this._web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash); - const makerToken = assetDataUtils.decodeERC20AssetData(args.makerAssetData).tokenAddress; - const takerToken = assetDataUtils.decodeERC20AssetData(args.takerAssetData).tokenAddress; - const fill = { - filledTakerTokenAmount: args.takerAssetFilledAmount, - filledMakerTokenAmount: args.makerAssetFilledAmount, - logIndex: decodedLog.logIndex, - maker: args.makerAddress, - orderHash: args.orderHash, - taker: args.takerAddress, - makerToken, - takerToken, - paidMakerFee: args.makerFeePaid, - paidTakerFee: args.takerFeePaid, - transactionHash: decodedLog.transactionHash, - blockTimestamp, - }; - return fill; - } - private _doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<ExchangeFillEventArgs>): boolean { - const args = decodedLog.args; - const isUserMakerOrTaker = args.maker === this._userAddressIfExists || args.taker === this._userAddressIfExists; - return isUserMakerOrTaker; - } - private _updateLatestFillsBlockIfNeeded(blockNumber: number): void { - utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - - const isBlockPending = _.isNull(blockNumber); - if (!isBlockPending) { - // Hack: I've observed the behavior where a client won't register certain fill events - // and lowering the cache blockNumber fixes the issue. As a quick fix for now, simply - // set the cached blockNumber 50 below the one returned. This way, upon refreshing, a user - // would still attempt to re-fetch events from the previous 50 blocks, but won't need to - // re-fetch all events in all blocks. - // TODO: Debug if this is a race condition, and apply a more precise fix - const blockNumberToSet = - blockNumber - BLOCK_NUMBER_BACK_TRACK < 0 ? 0 : blockNumber - BLOCK_NUMBER_BACK_TRACK; - tradeHistoryStorage.setFillsLatestBlock(this._userAddressIfExists, this.networkId, blockNumberToSet); - } - } - private _stopWatchingExchangeLogFillEvents(): void { - this._contractWrappers.exchange.unsubscribeAll(); - } - private async _getTokenRegistryTokensByAddressAsync(): Promise<TokenByAddress> { - let tokenRegistryTokens; - if (this.networkId === constants.NETWORK_ID_MAINNET) { - tokenRegistryTokens = await backendClient.getTokenInfosAsync(); - } else { - tokenRegistryTokens = fakeTokenRegistry[this.networkId]; - const tokenSymbolToAddressOverrides = tokenAddressOverrides[this.networkId]; - if (!_.isUndefined(tokenAddressOverrides)) { - // HACK: Override token addresses on testnets - tokenRegistryTokens = _.map(tokenRegistryTokens, (token: ZeroExToken) => { - const overrideIfExists = tokenSymbolToAddressOverrides[token.symbol]; - if (!_.isUndefined(overrideIfExists)) { - return { - ...token, - address: overrideIfExists, - }; - } - return token; - }); - } - } - const tokenByAddress: TokenByAddress = {}; - _.each(tokenRegistryTokens, (t: ZeroExToken) => { - // HACK: For now we have a hard-coded list of iconUrls for the dummyTokens - // TODO: Refactor this out and pull the iconUrl directly from the TokenRegistry - const iconUrl = utils.getTokenIconUrl(t.symbol); - const token: Token = { - iconUrl, - address: t.address, - name: t.name, - symbol: t.symbol, - decimals: t.decimals, - trackedTimestamp: undefined, - isRegistered: true, - }; - tokenByAddress[token.address] = token; - }); - return tokenByAddress; - } - private async _onPageLoadInitFireAndForgetAsync(): Promise<void> { - await utils.onPageLoadPromise; // wait for page to load - const networkIdIfExists = await this._getInjectedProviderNetworkIdIfExistsAsync(); - this.networkId = !_.isUndefined(networkIdIfExists) ? networkIdIfExists : constants.NETWORK_ID_MAINNET; - const injectedProviderIfExists = await this._getInjectedProviderIfExistsAsync(); - if (!_.isUndefined(injectedProviderIfExists)) { - const injectedProviderObservable = injectedProviderIfExists.publicConfigStore; - if (!_.isUndefined(injectedProviderObservable) && _.isUndefined(this._injectedProviderObservable)) { - this._injectedProviderObservable = injectedProviderObservable; - this._injectedProviderObservable.subscribe(this._injectedProviderUpdateHandler); - } - } - this._updateProviderName(injectedProviderIfExists); - const shouldPollUserAddress = true; - const shouldUseLedgerProvider = false; - this._startWatchingGasPrice(); - await this._resetOrInitializeAsync(this.networkId, shouldPollUserAddress, shouldUseLedgerProvider); - } - private _startWatchingGasPrice(): void { - if (!_.isUndefined(this._watchGasPriceIntervalId)) { - return; // we are already watching - } - const oneMinuteInMs = 60000; - // tslint:disable-next-line:no-floating-promises - this._updateDefaultGasPriceAsync(); - this._watchGasPriceIntervalId = intervalUtils.setAsyncExcludingInterval( - this._updateDefaultGasPriceAsync.bind(this), - oneMinuteInMs, - (err: Error) => { - logUtils.log(`Watching gas price failed: ${err.stack}`); - this._stopWatchingGasPrice(); - }, - ); - } - private _stopWatchingGasPrice(): void { - if (!_.isUndefined(this._watchGasPriceIntervalId)) { - intervalUtils.clearAsyncExcludingInterval(this._watchGasPriceIntervalId); - } - } - private async _resetOrInitializeAsync( - networkId: number, - shouldPollUserAddress: boolean = false, - shouldUserLedgerProvider: boolean = false, - ): Promise<void> { - if (!shouldUserLedgerProvider) { - this._dispatcher.updateBlockchainIsLoaded(false); - } - this._dispatcher.updateUserWeiBalance(undefined); - this.networkId = networkId; - const injectedProviderIfExists = await this._getInjectedProviderIfExistsAsync(); - const [provider, ledgerSubproviderIfExists] = await Blockchain._getProviderAsync( - injectedProviderIfExists, - networkId, - shouldUserLedgerProvider, - ); - this._web3Wrapper = new Web3Wrapper(provider); - this.networkId = await this._web3Wrapper.getNetworkIdAsync(); - if (!_.isUndefined(this._contractWrappers)) { - this._contractWrappers.unsubscribeAll(); - } - const contractWrappersConfig = { - networkId, - }; - this._contractWrappers = new ContractWrappers(provider, contractWrappersConfig); - if (!_.isUndefined(this._blockchainWatcher)) { - this._blockchainWatcher.destroy(); - } - this._blockchainWatcher = new BlockchainWatcher(this._dispatcher, this._web3Wrapper, shouldPollUserAddress); - if (shouldUserLedgerProvider && !_.isUndefined(ledgerSubproviderIfExists)) { - delete this._userAddressIfExists; - this._ledgerSubprovider = ledgerSubproviderIfExists; - this._dispatcher.updateUserAddress(undefined); - this._dispatcher.updateProviderType(ProviderType.Ledger); - } else { - delete this._ledgerSubprovider; - const userAddresses = await this._web3Wrapper.getAvailableAddressesAsync(); - this._userAddressIfExists = userAddresses[0]; - this._dispatcher.updateUserAddress(this._userAddressIfExists); - if (!_.isUndefined(injectedProviderIfExists)) { - this._dispatcher.updateProviderType(ProviderType.Injected); - } - await this.fetchTokenInformationAsync(); - } - await this._blockchainWatcher.startEmittingUserBalanceStateAsync(); - this._dispatcher.updateNetworkId(networkId); - await this._rehydrateStoreWithContractEventsAsync(); - } - private _updateProviderName(injectedProviderIfExists?: InjectedProvider): void { - const doesInjectedProviderExist = !_.isUndefined(injectedProviderIfExists); - const providerName = doesInjectedProviderExist - ? Blockchain._getNameGivenProvider(injectedProviderIfExists) - : constants.PROVIDER_NAME_PUBLIC; - this._dispatcher.updateInjectedProviderName(providerName); - } - private async _instantiateContractIfExistsAsync(artifact: any, address?: string): Promise<ContractInstance> { - const c = await contract(artifact); - const providerObj = this._web3Wrapper.getProvider(); - c.setProvider(providerObj); - - const artifactNetworkConfigs = artifact.networks[this.networkId]; - let contractAddress; - if (!_.isUndefined(address)) { - contractAddress = address; - } else if (!_.isUndefined(artifactNetworkConfigs)) { - contractAddress = artifactNetworkConfigs.address; - } - - if (!_.isUndefined(contractAddress)) { - const doesContractExist = await this.doesContractExistAtAddressAsync(contractAddress); - if (!doesContractExist) { - logUtils.log(`Contract does not exist: ${artifact.contract_name} at ${contractAddress}`); - throw new Error(BlockchainCallErrs.ContractDoesNotExist); - } - } - - try { - const contractInstance = _.isUndefined(address) ? await c.deployed() : await c.at(address); - return contractInstance; - } catch (err) { - const errMsg = `${err}`; - logUtils.log(`Notice: Error encountered: ${err} ${err.stack}`); - if (_.includes(errMsg, 'not been deployed to detected network')) { - throw new Error(BlockchainCallErrs.ContractDoesNotExist); - } else { - errorReporter.report(err); - throw new Error(BlockchainCallErrs.UnhandledError); - } - } - } - private _showFlashMessageIfLedger(): void { - if (!_.isUndefined(this._ledgerSubprovider)) { - this._dispatcher.showFlashMessage('Confirm the transaction on your Ledger Nano S'); - } - } - private async _updateDefaultGasPriceAsync(): Promise<void> { - try { - const gasInfo = await backendClient.getGasInfoAsync(); - const gasPriceInGwei = new BigNumber(gasInfo.fast / 10); - const gasPriceInWei = gasPriceInGwei.multipliedBy(1000000000); - this._defaultGasPrice = gasPriceInWei; - } catch (err) { - return; - } - } -} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/blockchain_watcher.ts b/packages/website/ts/blockchain_watcher.ts deleted file mode 100644 index 835932dcd..000000000 --- a/packages/website/ts/blockchain_watcher.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { BigNumber, intervalUtils, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import { Dispatcher } from 'ts/redux/dispatcher'; - -export class BlockchainWatcher { - private readonly _dispatcher: Dispatcher; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _shouldPollUserAddress: boolean; - private _watchBalanceIntervalId: NodeJS.Timer; - private _prevUserEtherBalanceInWei?: BigNumber; - private _prevUserAddressIfExists: string; - private _prevNodeVersionIfExists: string; - constructor(dispatcher: Dispatcher, web3Wrapper: Web3Wrapper, shouldPollUserAddress: boolean) { - this._dispatcher = dispatcher; - this._shouldPollUserAddress = shouldPollUserAddress; - this._web3Wrapper = web3Wrapper; - } - public destroy(): void { - this._stopEmittingUserBalanceState(); - // HACK: stop() is only available on providerEngine instances - const provider = this._web3Wrapper.getProvider(); - if (!_.isUndefined((provider as any).stop)) { - (provider as any).stop(); - } - } - // This should only be called from the LedgerConfigDialog - public updatePrevUserAddress(userAddress: string): void { - this._prevUserAddressIfExists = userAddress; - } - public async startEmittingUserBalanceStateAsync(): Promise<void> { - if (!_.isUndefined(this._watchBalanceIntervalId)) { - return; // we are already emitting the state - } - this._prevUserEtherBalanceInWei = undefined; - await this._updateBalanceAsync(); - this._watchBalanceIntervalId = intervalUtils.setAsyncExcludingInterval( - this._updateBalanceAsync.bind(this), - 5000, - (err: Error) => { - logUtils.log(`Watching network and balances failed: ${err.stack}`); - this._stopEmittingUserBalanceState(); - }, - ); - } - private async _updateBalanceAsync(): Promise<void> { - const currentNodeVersion = await this._web3Wrapper.getNodeVersionAsync(); - if (this._prevNodeVersionIfExists !== currentNodeVersion) { - this._prevNodeVersionIfExists = currentNodeVersion; - this._dispatcher.updateNodeVersion(currentNodeVersion); - } - - if (this._shouldPollUserAddress) { - const addresses = await this._web3Wrapper.getAvailableAddressesAsync(); - const userAddressIfExists = addresses[0]; - // Update makerAddress on network change - if (this._prevUserAddressIfExists !== userAddressIfExists) { - this._prevUserAddressIfExists = userAddressIfExists; - this._dispatcher.updateUserAddress(userAddressIfExists); - } - - // Check for user ether balance changes - if (!_.isUndefined(userAddressIfExists)) { - await this._updateUserWeiBalanceAsync(userAddressIfExists); - } - } else { - // This logic is primarily for the Ledger, since we don't regularly poll for the address - // we simply update the balance for the last fetched address. - if (!_.isUndefined(this._prevUserAddressIfExists)) { - await this._updateUserWeiBalanceAsync(this._prevUserAddressIfExists); - } - } - } - private async _updateUserWeiBalanceAsync(userAddress: string): Promise<void> { - const balanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(userAddress); - if (_.isUndefined(this._prevUserEtherBalanceInWei) || !balanceInWei.eq(this._prevUserEtherBalanceInWei)) { - this._prevUserEtherBalanceInWei = balanceInWei; - this._dispatcher.updateUserWeiBalance(balanceInWei); - } - } - private _stopEmittingUserBalanceState(): void { - if (!_.isUndefined(this._watchBalanceIntervalId)) { - intervalUtils.clearAsyncExcludingInterval(this._watchBalanceIntervalId); - } - } -} diff --git a/packages/website/ts/components/aboutPageLayout.tsx b/packages/website/ts/components/aboutPageLayout.tsx deleted file mode 100644 index 51c1a661e..000000000 --- a/packages/website/ts/components/aboutPageLayout.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import styled from 'styled-components'; - -import { Button } from 'ts/components/button'; -import { ChapterLink } from 'ts/components/chapter_link'; -import { Column, Section } from 'ts/components/newLayout'; -import { SiteWrap } from 'ts/components/siteWrap'; -import { Heading, Paragraph } from 'ts/components/text'; - -import { addFadeInAnimation } from 'ts/constants/animations'; -import { WebsitePaths } from 'ts/types'; - -interface Props { - title: string; - description: React.ReactNode | string; - linkLabel?: string; - href?: string; - to?: string; - children?: React.ReactNode; -} - -export const AboutPageLayout = (props: Props) => ( - <SiteWrap theme="light"> - <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> - <Column> - <ChapterLink to={WebsitePaths.AboutMission}>Mission</ChapterLink> - <ChapterLink to={WebsitePaths.AboutTeam}>Team</ChapterLink> - <ChapterLink to={WebsitePaths.AboutPress}>Press</ChapterLink> - <ChapterLink to={WebsitePaths.AboutJobs}>Jobs</ChapterLink> - </Column> - - <Column width="70%" maxWidth="800px"> - <Column width="100%" maxWidth="680px"> - <AnimatedHeading size="medium">{props.title}</AnimatedHeading> - - <AnimatedParagraph size="medium" marginBottom="60px" isMuted={0.65}> - {props.description} - </AnimatedParagraph> - - {props.linkLabel && (props.href || props.to) && ( - <AnimatedLink - to={props.to} - href={props.href} - target={!_.isUndefined(props.href) ? '_blank' : undefined} - isWithArrow={true} - isAccentColor={true} - > - {props.linkLabel} - </AnimatedLink> - )} - </Column> - </Column> - </Section> - - {props.children} - </SiteWrap> -); - -const AnimatedHeading = styled(Heading)` - ${addFadeInAnimation('0.5s')}; -`; - -const AnimatedParagraph = styled(Paragraph)` - ${addFadeInAnimation('0.5s', '0.15s')}; -`; - -const AnimatedLink = styled(Button)` - ${addFadeInAnimation('0.6s', '0.3s')}; -`; diff --git a/packages/website/ts/components/animatedChatIcon.tsx b/packages/website/ts/components/animatedChatIcon.tsx deleted file mode 100644 index 770536259..000000000 --- a/packages/website/ts/components/animatedChatIcon.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import * as React from 'react'; -import styled, { keyframes } from 'styled-components'; - -export const AnimatedChatIcon = () => ( - <svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> - <mask id="mask30" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="150" height="150"> - <circle cx="75" cy="75" r="73" fill="#00AE99" stroke="#00AE99" stroke-width="3" /> - </mask> - - <g mask="url(#mask30)"> - <circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3" /> - - <Rays> - <path vector-effect="non-scaling-stroke" d="M76 37H137.5" stroke="#00AE99" stroke-width="3" /> - <path - vector-effect="non-scaling-stroke" - d="M37 73.5L37 12M113 137.5L113 75" - stroke="#00AE99" - stroke-width="3" - /> - <path vector-effect="non-scaling-stroke" d="M13 113H71.5" stroke="#00AE99" stroke-width="3" /> - <path - vector-effect="non-scaling-stroke" - d="M49.087 47.5264L92.574 4.03932" - stroke="#00AE99" - stroke-width="3" - /> - <path - vector-effect="non-scaling-stroke" - d="M47.3192 100.913L3.8321 57.4259M146.314 92.4277L102.12 48.2335" - stroke="#00AE99" - stroke-width="3" - /> - <path - vector-effect="non-scaling-stroke" - d="M58.2793 145.814L101.766 102.327" - stroke="#00AE99" - stroke-width="3" - /> - </Rays> - - <Bubble> - <path - vector-effect="non-scaling-stroke" - d="M113 75C113 85.3064 108.897 94.6546 102.235 101.5C98.4048 105.436 71 132.5 71 132.5V112.792C51.8933 110.793 37 94.6359 37 75C37 54.0132 54.0132 37 75 37C95.9868 37 113 54.0132 113 75Z" - stroke="#00AE99" - strokeWidth="3" - /> - </Bubble> - - <Dot delay={0} vector-effect="non-scaling-stroke" cx="75" cy="75" r="4" stroke="#00AE99" strokeWidth="3" /> - <Dot - delay={4.4} - vector-effect="non-scaling-stroke" - cx="91" - cy="75" - r="4" - stroke="#00AE99" - strokeWidth="3" - /> - <Dot - delay={-4.6} - vector-effect="non-scaling-stroke" - cx="59" - cy="75" - r="4" - stroke="#00AE99" - strokeWidth="3" - /> - </g> - </svg> -); - -const scale = keyframes` - 0% { transform: scale(1.2) } - 15% { transform: scale(1) } - 85% { transform: scale(1) } - 100% { transform: scale(1.2) } -`; - -const fadeInOut = keyframes` - 0%, 30%, 50%, 100% { - transform: initial; - } - - 40% { - transform: translateY(-5px); - } -`; - -const Bubble = styled.g` - animation: ${scale} 4s infinite cubic-bezier(0.175, 0.885, 0.32, 1.275); - transform-origin: 50% 50%; -`; - -const Rays = styled.g` - animation: ${scale} 4s infinite cubic-bezier(0.175, 0.885, 0.32, 1.275); - transform-origin: 50% 50%; -`; - -const Dot = styled.circle<{ delay: number }>` - animation: ${fadeInOut} 4s ${props => `${props.delay}s`} infinite; -`; diff --git a/packages/website/ts/components/animatedCompassIcon.tsx b/packages/website/ts/components/animatedCompassIcon.tsx deleted file mode 100644 index 5388f95ca..000000000 --- a/packages/website/ts/components/animatedCompassIcon.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import * as React from 'react'; -import styled, { keyframes } from 'styled-components'; - -export const AnimatedCompassIcon = () => ( - <svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> - <g> - <circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3" /> - <circle cx="75" cy="75" r="58" stroke="#00AE99" stroke-width="3" /> - <Needle - d="M62.9792 62.9792L36.6447 113.355L87.0208 87.0208M62.9792 62.9792L113.355 36.6447L87.0208 87.0208M62.9792 62.9792L87.0208 87.0208" - stroke="#00AE99" - strokeWidth="3" - /> - - <Dial> - <path d="M75 2V17M75 133V148" stroke="#00AE99" stroke-width="3" /> - <path d="M2 75L17 75M133 75L148 75" stroke="#00AE99" stroke-width="3" /> - <path d="M11.7801 38.5L24.7705 46M125.229 104L138.22 111.5" stroke="#00AE99" stroke-width="3" /> - <path d="M38.5001 11.7801L46.0001 24.7705M104 125.229L111.5 138.22" stroke="#00AE99" stroke-width="3" /> - <path d="M111.5 11.7801L104 24.7705M46 125.229L38.5 138.22" stroke="#00AE99" stroke-width="3" /> - <path d="M138.22 38.5L125.229 46M24.7705 104L11.7801 111.5" stroke="#00AE99" stroke-width="3" /> - </Dial> - </g> - </svg> -); - -const point = keyframes` - 0% { transform: rotate(0deg) } - 20% { transform: rotate(10deg) } - 30% { transform: rotate(30deg) } - 60% { transform: rotate(-20deg) } - 80% { transform: rotate(-20deg) } - 100% { transform: rotate(0deg) } -`; - -const rotate = keyframes` - 0% { transform: rotate(0deg) } - 20% { transform: rotate(-10deg) } - 30% { transform: rotate(-30deg) } - 60% { transform: rotate(20deg) } - 80% { transform: rotate(20deg) } - 100% { transform: rotate(0deg) } -`; - -const Needle = styled.path` - animation: ${point} 5s infinite; - transform-origin: 50% 50%; -`; - -const Dial = styled.g` - animation: ${rotate} 5s infinite; - transform-origin: 50% 50%; -`; diff --git a/packages/website/ts/components/banner.tsx b/packages/website/ts/components/banner.tsx deleted file mode 100644 index ce3fd499a..000000000 --- a/packages/website/ts/components/banner.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -import { colors } from 'ts/style/colors'; - -import { Button } from 'ts/components/button'; -import { ThemeInterface } from 'ts/components/siteWrap'; -import { Paragraph } from 'ts/components/text'; - -import { Column, Section } from 'ts/components/newLayout'; - -interface Props { - heading?: string; - subline?: string; - mainCta?: CTAButton; - secondaryCta?: CTAButton; - theme?: ThemeInterface; -} - -interface CTAButton { - text: string; - href?: string; - onClick?: () => void; - shouldOpenInNewTab?: boolean; -} - -interface BorderProps { - isBottom?: boolean; -} - -export const Banner: React.StatelessComponent<Props> = (props: Props) => { - const { heading, subline, mainCta, secondaryCta } = props; - return ( - <CustomSection bgColor={colors.brandDark} isFlex={true} flexBreakpoint="900px" paddingMobile="120px 0"> - <Border /> - <Border isBottom={true} /> - - <Column> - <CustomHeading>{heading}</CustomHeading> - - {subline && ( - <Paragraph color={colors.white} isMuted={0.5} isNoMargin={true}> - {subline} - </Paragraph> - )} - </Column> - <Column> - <ButtonWrap> - {mainCta && ( - <Button - color={colors.white} - isTransparent={false} - href={mainCta.href} - target={mainCta.shouldOpenInNewTab ? '_blank' : ''} - > - {mainCta.text} - </Button> - )} - - {secondaryCta && ( - <Button - color={colors.white} - href={secondaryCta.href} - onClick={secondaryCta.onClick} - isTransparent={true} - > - {secondaryCta.text} - </Button> - )} - </ButtonWrap> - </Column> - </CustomSection> - ); -}; - -const CustomSection = styled(Section)` - color: ${colors.white}; - margin-top: 30px; - - @media (max-width: 900px) { - text-align: center; - - p { - margin-bottom: 30px; - } - - div:last-child { - margin-bottom: 0; - } - } -`; - -const CustomHeading = styled.h2` - font-size: 34px; - font-weight: 400; - margin-bottom: 10px @media (max-width: 768px) { - font-size: 30px; - } -`; - -const ButtonWrap = styled.div` - display: inline-block; - - @media (min-width: 768px) { - * + * { - margin-left: 15px; - } - } - - @media (max-width: 768px) { - a, - button { - display: block; - width: 220px; - } - - * + * { - margin-top: 15px; - } - } -`; - -// Note let's refactor this -// is it absolutely necessary to have a stateless component -// to pass props down into the styled icon? -const Border = styled.div<BorderProps>` - position: absolute; - background-image: ${props => - props.isBottom ? 'url(/images/banner/bottomofcta.png);' : 'url(/images/banner/topofcta.png);'}; - background-position: ${props => (props.isBottom ? 'left top' : 'left bottom')}; - left: 0; - width: calc(100% + 214px); - height: 40px; - top: ${props => !props.isBottom && 0}; - bottom: ${props => props.isBottom && 0}; - transform: translate(-112px); - - @media (max-width: 768px) { - width: calc(100% + 82px); - height: 40px; - transform: translate(-41px); - background-size: auto 80px; - } -`; diff --git a/packages/website/ts/components/blockIconLink.tsx b/packages/website/ts/components/blockIconLink.tsx deleted file mode 100644 index ff7712595..000000000 --- a/packages/website/ts/components/blockIconLink.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { History, Location } from 'history'; -import * as React from 'react'; -import { match, withRouter } from 'react-router-dom'; -import styled from 'styled-components'; - -import { Button } from 'ts/components/button'; -import { Icon } from 'ts/components/icon'; - -interface BaseComponentProps { - icon?: string; - iconComponent?: React.ReactNode; - title: string; - linkLabel: string; - linkUrl?: string; - linkAction?: () => void; - history: History; - location: Location; - match: match<any>; -} - -class BaseComponent extends React.PureComponent<BaseComponentProps> { - public onClick = (): void => { - const { linkAction, linkUrl } = this.props; - - if (linkAction) { - linkAction(); - } else { - this.props.history.push(linkUrl); - } - }; - - public render(): React.ReactNode { - const { icon, iconComponent, linkUrl, linkAction, title, linkLabel } = this.props; - - return ( - <Wrap onClick={this.onClick}> - <div> - <Icon name={icon} component={iconComponent} size="large" margin={[0, 0, 'default', 0]} /> - - <Title>{title}</Title> - - <Button isWithArrow={true} isTransparent={true} href={linkUrl} onClick={linkAction}> - {linkLabel} - </Button> - </div> - </Wrap> - ); - } -} - -export const BlockIconLink = withRouter<BaseComponentProps>(BaseComponent); - -const Wrap = styled.div` - width: calc(50% - 15px); - height: 400px; - padding: 40px; - display: flex; - justify-content: center; - align-items: center; - text-align: center; - transition: background-color 0.25s; - background-color: ${props => props.theme.lightBgColor}; - cursor: pointer; - - a, - button { - pointer-events: none; - } - - @media (max-width: 900px) { - width: 100%; - margin-top: 30px; - } - - &:hover { - background-color: #002d28; - } -`; - -const Title = styled.h2` - font-size: 20px; - margin-bottom: 30px; - color: ${props => props.theme.linkColor}; -`; diff --git a/packages/website/ts/components/button.tsx b/packages/website/ts/components/button.tsx deleted file mode 100644 index 31a74e599..000000000 --- a/packages/website/ts/components/button.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import * as React from 'react'; -import { Link as ReactRouterLink } from 'react-router-dom'; -import styled from 'styled-components'; - -import { ThemeInterface } from 'ts/components/siteWrap'; - -import { colors } from 'ts/style/colors'; - -interface ButtonInterface { - bgColor?: string; - borderColor?: string; - color?: string; - children?: React.ReactNode | string; - isTransparent?: boolean; - isNoBorder?: boolean; - isNoPadding?: boolean; - isWithArrow?: boolean; - isAccentColor?: boolean; - hasIcon?: boolean | string; - isInline?: boolean; - href?: string; - type?: string; - target?: string; - to?: string; - onClick?: () => any; - theme?: ThemeInterface; - shouldUseAnchorTag?: boolean; -} - -export const Button: React.StatelessComponent<ButtonInterface> = (props: ButtonInterface) => { - const { children, href, isWithArrow, to, shouldUseAnchorTag, target } = props; - let linkElem; - - if (href || shouldUseAnchorTag) { - linkElem = 'a'; - } - if (to) { - linkElem = ReactRouterLink; - } - - const Component = linkElem ? ButtonBase.withComponent<any>(linkElem) : ButtonBase; - const targetProp = href && target ? { target } : {}; - - return ( - <Component {...props} {...targetProp}> - {children} - - {isWithArrow && ( - <svg width="16" height="15" fill="none" xmlns="http://www.w3.org/2000/svg"> - <path d="M4.484.246l.024 1.411 8.146.053L.817 13.547l.996.996L13.65 2.706l.052 8.146 1.412.024L15.045.315 4.484.246z" /> - </svg> - )} - </Component> - ); -}; - -Button.defaultProps = { - borderColor: 'rgba(255, 255, 255, .4)', -}; - -const ButtonBase = styled.button<ButtonInterface>` - appearance: none; - border: 1px solid transparent; - display: inline-block; - background-color: ${props => props.bgColor || colors.brandLight}; - background-color: ${props => (props.isTransparent || props.isWithArrow) && 'transparent'}; - border-color: ${props => props.isTransparent && !props.isWithArrow && props.borderColor}; - color: ${props => (props.isAccentColor ? props.theme.linkColor : props.color || props.theme.textColor)}; - padding: ${props => !props.isNoPadding && !props.isWithArrow && '18px 30px'}; - white-space: ${props => props.isWithArrow && 'nowrap'}; - text-align: center; - font-size: ${props => (props.isWithArrow ? '20px' : '18px')}; - text-decoration: none; - cursor: pointer; - outline: none; - transition: background-color 0.35s, border-color 0.35s; - - // @todo Refactor to use theme props - ${props => - props.bgColor === 'dark' && - ` - background-color: ${colors.brandDark}; - color: ${colors.white}; - `} - - svg { - margin-left: 9px; - transition: transform 0.5s; - transform: translate3d(-2px, 2px, 0); - } - - path { - fill: ${props => (props.isAccentColor ? props.theme.linkColor : props.color || props.theme.textColor)}; - } - - &:hover { - background-color: ${props => !props.isTransparent && !props.isWithArrow && '#04BEA8'}; - border-color: ${props => props.isTransparent && !props.isNoBorder && !props.isWithArrow && '#00AE99'}; - - svg { - transform: translate3d(2px, -2px, 0); - } - } -`; diff --git a/packages/website/ts/components/chapter_link.tsx b/packages/website/ts/components/chapter_link.tsx deleted file mode 100644 index fd974cec1..000000000 --- a/packages/website/ts/components/chapter_link.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { NavLink as ReactRouterLink } from 'react-router-dom'; -import styled from 'styled-components'; - -export const ChapterLink = styled(ReactRouterLink).attrs({ - activeStyle: { opacity: 1 }, -})` - font-size: 1.222222222rem; - display: block; - opacity: 0.5; - margin-bottom: 1.666666667rem; - - &:hover { - opacity: 1; - } -`; diff --git a/packages/website/ts/components/definition.tsx b/packages/website/ts/components/definition.tsx deleted file mode 100644 index bd7a40425..000000000 --- a/packages/website/ts/components/definition.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -import { Button } from 'ts/components/button'; -import { Icon } from 'ts/components/icon'; -import { Heading, Paragraph } from 'ts/components/text'; - -export interface Action { - label: string; - url?: string; - onClick?: () => void; - shouldUseAnchorTag?: boolean; -} - -interface Props { - isInline?: boolean; - isInlineIcon?: boolean; - isCentered?: boolean; - isWithMargin?: boolean; - icon: string; - iconSize?: 'medium' | 'large' | number; - fontSize?: 'default' | 'medium' | number; - title: string; - titleSize?: 'small' | 'default' | number; - description: React.ReactNode | string; - actions?: Action[]; -} - -export const Definition = (props: Props) => ( - <Wrap {...props}> - <Icon name={props.icon} size={props.iconSize || 'medium'} margin={[0, 0, 'default', 0]} /> - - <TextWrap {...props}> - <Heading - asElement="h2" - fontWeight="400" - marginBottom={props.titleSize === 'small' ? '7px' : '15px'} - size={props.titleSize || 'default'} - > - {props.title} - </Heading> - - {typeof props.description === 'string' ? ( - <Paragraph isMuted={true} size={props.fontSize || 'default'}> - {props.description} - </Paragraph> - ) : ( - <>{props.description}</> - )} - - {props.actions && ( - <LinkWrap> - {props.actions.map((item, index) => ( - <Button - key={`dlink-${index}`} - href={item.url} - onClick={item.onClick} - isWithArrow={true} - isAccentColor={true} - shouldUseAnchorTag={item.shouldUseAnchorTag} - target="_blank" - > - {item.label} - </Button> - ))} - </LinkWrap> - )} - </TextWrap> - </Wrap> -); - -const Wrap = styled.div<Props>` - max-width: ${props => props.isInline && '354px'}; - - & + & { - margin-top: ${props => props.isInlineIcon && '120px'}; - margin-top: ${props => props.isWithMargin && '60px'}; - } - - @media (min-width: 768px) { - width: ${props => (props.isInline ? 'calc(33.3333% - 30px)' : '100%')}; - display: ${props => props.isInlineIcon && 'flex'}; - justify-content: ${props => props.isInlineIcon && 'space-between'}; - align-items: ${props => props.isInlineIcon && 'center'}; - text-align: ${props => (props.isInlineIcon || !props.isCentered) && 'left'}; - } - - @media (max-width: 768px) { - margin: 0 auto; - - & + & { - margin-top: ${props => props.isInline && '60px'}; - } - } -`; - -const TextWrap = styled.div<Props>` - width: 100%; - max-width: 560px; - - ul { - padding-top: 10px; - padding-left: 1rem; - } - - li { - color: ${props => props.theme.paragraphColor}; - font-size: ${props => `var(--${props.fontSize || 'default'}Paragraph)`}; - font-weight: 300; - list-style: disc; - opacity: 0.75; - line-height: 1.444444444; - margin-bottom: 1rem; - } - - @media (min-width: 768px) { - margin-left: ${props => props.isInlineIcon && '60px'}; - } -`; - -const LinkWrap = styled.div` - margin-top: 60px; - - @media (min-width: 768px) { - display: inline-flex; - - a + a { - margin-left: 60px; - } - } - - @media (max-width: 768px) { - max-width: 250px; - - a + a { - margin-top: 15px; - } - } -`; diff --git a/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx b/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx deleted file mode 100644 index 1c47903db..000000000 --- a/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { colors, Networks } from '@0x/react-shared'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { BlockchainErrs } from 'ts/types'; -import { constants } from 'ts/utils/constants'; - -interface BlockchainErrDialogProps { - blockchain: Blockchain; - blockchainErr: BlockchainErrs; - isOpen: boolean; - userAddress: string; - toggleDialogFn: (isOpen: boolean) => void; - networkId: number; -} - -export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProps, undefined> { - public render(): React.ReactNode { - const dialogActions = [ - <FlatButton - key="blockchainErrOk" - label="Ok" - primary={true} - onClick={this.props.toggleDialogFn.bind(this.props.toggleDialogFn, false)} - />, - ]; - - const hasWalletAddress = this.props.userAddress !== ''; - return ( - <Dialog - title={this._getTitle(hasWalletAddress)} - titleStyle={{ fontWeight: 100 }} - actions={dialogActions} - open={this.props.isOpen} - contentStyle={{ width: 400 }} - onRequestClose={this.props.toggleDialogFn.bind(this.props.toggleDialogFn, false)} - autoScrollBodyContent={true} - > - <div className="pt2" style={{ color: colors.grey700 }}> - {this._renderExplanation(hasWalletAddress)} - </div> - </Dialog> - ); - } - private _getTitle(hasWalletAddress: boolean): string { - if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) { - return '0x smart contracts not found'; - } else if (!hasWalletAddress) { - return 'Enable wallet communication'; - } else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) { - return 'Disconnected from Ethereum network'; - } else if (this.props.blockchainErr === BlockchainErrs.DefaultTokensNotInTokenRegistry) { - return 'Default TokenRegistry tokens missing'; - } else { - return 'Unexpected error'; - } - } - private _renderExplanation(hasWalletAddress: boolean): React.ReactNode { - if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) { - return this._renderContractsNotDeployedExplanation(); - } else if (!hasWalletAddress) { - return this._renderNoWalletFoundExplanation(); - } else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) { - return this._renderDisconnectedFromNode(); - } else if (this.props.blockchainErr === BlockchainErrs.DefaultTokensNotInTokenRegistry) { - return this._renderDefaultTokenNotInTokenRegistry(); - } else { - return this._renderUnexpectedErrorExplanation(); - } - } - private _renderDisconnectedFromNode(): React.ReactNode { - return ( - <div> - You were disconnected from the backing Ethereum node. If using{' '} - <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank"> - Metamask - </a>{' '} - or{' '} - <a href={constants.URL_MIST_DOWNLOAD} target="_blank"> - Mist - </a>{' '} - try refreshing the page. If using a locally hosted Ethereum node, make sure it's still running. - </div> - ); - } - private _renderDefaultTokenNotInTokenRegistry(): React.ReactNode { - return ( - <div> - The TokenRegistry deployed on your network does not contain the needed default tokens for 0x Portal to - operate. Please try one of the supported networks (Mainnet, Kovan, Ropsten, Rinkeby). If on a local - Testnet, make sure the TokenRegistry contract is deployed and loaded with some default tokens (i.e WETH - & ZRX). - </div> - ); - } - private _renderUnexpectedErrorExplanation(): React.ReactNode { - return <div>We encountered an unexpected error. Please try refreshing the page.</div>; - } - private _renderNoWalletFoundExplanation(): React.ReactNode { - return ( - <div> - <div> - We were unable to access an Ethereum wallet you control. In order to interact with the 0x portal - dApp, we need a way to interact with one of your Ethereum wallets. There are two easy ways you can - enable us to do that: - </div> - <h4>1. Metamask chrome extension</h4> - <div> - You can install the{' '} - <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank"> - Metamask - </a>{' '} - Chrome extension Ethereum wallet. Once installed and set up, refresh this page. - <div className="pt1"> - <span className="bold">Note:</span> If you already have Metamask installed, make sure it is - unlocked. - </div> - </div> - <h4>Parity Signer</h4> - <div> - The{' '} - <a href={constants.URL_PARITY_CHROME_STORE} target="_blank"> - Parity Signer Chrome extension - </a>{' '} - lets you connect to a locally running Parity node. Make sure you have started your local Parity node - with `parity ui` or `parity --chain kovan ui` in order to connect to mainnet or Kovan respectively. - </div> - <div className="pt2"> - <span className="bold">Note:</span> If you have done one of the above steps and are still seeing - this message, we might still be unable to retrieve an Ethereum address by calling - `web3.eth.accounts`. Make sure you have created at least one Ethereum address. - </div> - </div> - ); - } - private _renderContractsNotDeployedExplanation(): React.ReactNode { - return ( - <div> - <div> - The 0x smart contracts are not deployed on the Ethereum network you are currently connected to - (network Id: {this.props.networkId}). In order to use the 0x portal dApp, please connect to the{' '} - {Networks.Kovan} testnet (network Id: {constants.NETWORK_ID_KOVAN}) or ${constants.MAINNET_NAME}{' '} - (network Id: ${constants.NETWORK_ID_MAINNET}). - </div> - <h4>Metamask</h4> - <div> - If you are using{' '} - <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank"> - Metamask - </a> - , you can switch networks in the top left corner of the extension popover. - </div> - <h4>Parity Signer</h4> - <div> - If using the{' '} - <a href={constants.URL_PARITY_CHROME_STORE} target="_blank"> - Parity Signer Chrome extension - </a> - , make sure to start your local Parity node with `parity ui` or `parity --chain Kovan ui` in order - to connect to mainnet \ or Kovan respectively. - </div> - </div> - ); - } -} diff --git a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx deleted file mode 100644 index 5ca272b1a..000000000 --- a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; -import { EthAmountInput } from 'ts/containers/inputs/eth_amount_input'; -import { Side, Token } from 'ts/types'; - -interface EthWethConversionDialogProps { - blockchain: Blockchain; - userAddress: string; - networkId: number; - direction: Side; - onComplete: (direction: Side, value: BigNumber) => void; - onCancelled: () => void; - isOpen: boolean; - token: Token; - etherBalanceInWei?: BigNumber; - lastForceTokenStateRefetch: number; -} - -interface EthWethConversionDialogState { - value?: BigNumber; - shouldShowIncompleteErrs: boolean; - hasErrors: boolean; - isEthTokenBalanceLoaded: boolean; - ethTokenBalance: BigNumber; -} - -export class EthWethConversionDialog extends React.Component< - EthWethConversionDialogProps, - EthWethConversionDialogState -> { - private _isUnmounted: boolean; - constructor(props: EthWethConversionDialogProps) { - super(props); - this._isUnmounted = false; - this.state = { - shouldShowIncompleteErrs: false, - hasErrors: false, - isEthTokenBalanceLoaded: false, - ethTokenBalance: new BigNumber(0), - }; - } - public componentWillMount(): void { - // tslint:disable-next-line:no-floating-promises - this._fetchEthTokenBalanceAsync(); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - } - public render(): React.ReactNode { - const convertDialogActions = [ - <FlatButton key="cancel" label="Cancel" onClick={this._onCancel.bind(this)} />, - <FlatButton key="convert" label="Convert" primary={true} onClick={this._onConvertClick.bind(this)} />, - ]; - const title = this.props.direction === Side.Deposit ? 'Wrap ETH' : 'Unwrap WETH'; - return !_.isUndefined(this.props.etherBalanceInWei) ? ( - <Dialog - title={title} - titleStyle={{ fontWeight: 100 }} - actions={convertDialogActions} - contentStyle={{ width: 448 }} - open={this.props.isOpen} - > - {this._renderConversionDialogBody()} - </Dialog> - ) : null; - } - private _renderConversionDialogBody(): React.ReactNode { - const explanation = - this.props.direction === Side.Deposit - ? 'Convert your Ether into a tokenized, tradable form.' - : "Convert your Wrapped Ether back into it's native form."; - const isWrappedVersion = this.props.direction === Side.Receive; - return ( - <div> - <div className="pb2">{explanation}</div> - <div className="mx-auto" style={{ maxWidth: 312 }}> - <div className="flex"> - {this._renderCurrency(isWrappedVersion)} - <div style={{ paddingTop: 68 }}> - <i style={{ fontSize: 28, color: colors.darkBlue }} className="zmdi zmdi-arrow-right" /> - </div> - {this._renderCurrency(!isWrappedVersion)} - </div> - <div className="pt2 mx-auto" style={{ width: 245 }}> - {this.props.direction === Side.Receive ? ( - <TokenAmountInput - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - blockchain={this.props.blockchain} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - token={this.props.token} - shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} - shouldCheckBalance={true} - shouldCheckAllowance={false} - onChange={this._onValueChange.bind(this)} - amount={this.state.value} - /> - ) : ( - <EthAmountInput - amount={this.state.value} - onChange={this._onValueChange.bind(this)} - shouldCheckBalance={true} - shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} - /> - )} - <div className="pt1" style={{ fontSize: 12 }}> - <div className="left">1 ETH = 1 WETH</div> - {this.props.direction === Side.Receive && this.state.isEthTokenBalanceLoaded && ( - <div - className="right" - onClick={this._onMaxClick.bind(this)} - style={{ - color: colors.darkBlue, - textDecoration: 'underline', - cursor: 'pointer', - }} - > - Max - </div> - )} - </div> - </div> - </div> - </div> - ); - } - private _renderCurrency(isWrappedVersion: boolean): React.ReactNode { - const name = isWrappedVersion ? 'Wrapped Ether' : 'Ether'; - const iconUrl = isWrappedVersion ? '/images/token_icons/ether_erc20.png' : '/images/ether.png'; - const symbol = isWrappedVersion ? 'WETH' : 'ETH'; - return ( - <div className="mx-auto pt2"> - <div className="center" style={{ color: colors.darkBlue }}> - {name} - </div> - <div className="center py2"> - <img src={iconUrl} style={{ width: 60 }} /> - </div> - <div className="center" style={{ fontSize: 12 }}> - ({symbol}) - </div> - </div> - ); - } - private _onMaxClick(): void { - this.setState({ - value: this.state.ethTokenBalance, - }); - } - private _onValueChange(isValid: boolean, amount?: BigNumber): void { - this.setState({ - value: amount, - hasErrors: !isValid, - }); - } - private _onConvertClick(): void { - if (this.state.hasErrors) { - this.setState({ - shouldShowIncompleteErrs: true, - }); - } else { - const value = this.state.value; - this.setState({ - value: undefined, - }); - this.props.onComplete(this.props.direction, value); - } - } - private _onCancel(): void { - this.setState({ - value: undefined, - }); - this.props.onCancelled(); - } - private async _fetchEthTokenBalanceAsync(): Promise<void> { - const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; - const [balance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - this.props.token.address, - ); - if (!this._isUnmounted) { - this.setState({ - isEthTokenBalanceLoaded: true, - ethTokenBalance: balance, - }); - } - } -} diff --git a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx deleted file mode 100644 index 527353aa0..000000000 --- a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx +++ /dev/null @@ -1,307 +0,0 @@ -import { colors, constants as sharedConstants } from '@0x/react-shared'; -import { BigNumber, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; -import TextField from 'material-ui/TextField'; -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; -import { Blockchain } from 'ts/blockchain'; -import { NetworkDropDown } from 'ts/components/dropdowns/network_drop_down'; -import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { ProviderType } from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { utils } from 'ts/utils/utils'; - -const VALID_ETHEREUM_DERIVATION_PATH_PREFIX = `44'/60'`; - -enum LedgerSteps { - Connect, - SelectAddress, -} - -interface LedgerConfigDialogProps { - isOpen: boolean; - toggleDialogFn: (isOpen: boolean) => void; - dispatcher: Dispatcher; - blockchain: Blockchain; - networkId?: number; - providerType: ProviderType; -} - -interface LedgerConfigDialogState { - connectionErrMsg: string; - stepIndex: LedgerSteps; - userAddresses: string[]; - addressBalances: BigNumber[]; - derivationPath: string; - derivationErrMsg: string; - preferredNetworkId: number; -} - -export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, LedgerConfigDialogState> { - public static defaultProps = { - networkId: 1, - }; - constructor(props: LedgerConfigDialogProps) { - super(props); - const derivationPathIfExists = props.blockchain.getLedgerDerivationPathIfExists(); - this.state = { - connectionErrMsg: '', - stepIndex: LedgerSteps.Connect, - userAddresses: [], - addressBalances: [], - derivationPath: _.isUndefined(derivationPathIfExists) - ? configs.DEFAULT_DERIVATION_PATH - : derivationPathIfExists, - derivationErrMsg: '', - preferredNetworkId: props.networkId, - }; - } - public render(): React.ReactNode { - const dialogActions = [ - <FlatButton key="ledgerConnectCancel" label="Cancel" onClick={this._onClose.bind(this)} />, - ]; - const dialogTitle = - this.state.stepIndex === LedgerSteps.Connect ? 'Connect to your Ledger' : 'Select desired address'; - return ( - <Dialog - title={dialogTitle} - titleStyle={{ fontWeight: 100 }} - actions={dialogActions} - open={this.props.isOpen} - onRequestClose={this._onClose.bind(this)} - autoScrollBodyContent={true} - bodyStyle={{ paddingBottom: 0 }} - > - <div style={{ color: colors.grey700, paddingTop: 1 }}> - {this.state.stepIndex === LedgerSteps.Connect && this._renderConnectStep()} - {this.state.stepIndex === LedgerSteps.SelectAddress && this._renderSelectAddressStep()} - </div> - </Dialog> - ); - } - private _renderConnectStep(): React.ReactNode { - const networkIds = _.values(sharedConstants.NETWORK_ID_BY_NAME); - return ( - <div> - <div className="h4 pt3">Follow these instructions before proceeding:</div> - <ol className="mb0"> - <li className="pb1">Connect your Ledger Nano S & Open the Ethereum application</li> - <li className="pb1">Verify that "Browser Support" AND "Contract Data" are enabled in Settings</li> - <li className="pb1"> - If no Browser Support is found in settings, verify that you have{' '} - <a href="https://www.ledgerwallet.com/apps/manager" target="_blank"> - Firmware >1.2 - </a> - </li> - <li>Choose your desired network:</li> - </ol> - <div className="pb2"> - <NetworkDropDown - updateSelectedNetwork={this._onSelectedNetworkUpdated.bind(this)} - selectedNetworkId={this.state.preferredNetworkId} - avialableNetworkIds={networkIds} - /> - </div> - <div className="center pb3"> - <LifeCycleRaisedButton - isPrimary={true} - labelReady="Connect to Ledger" - labelLoading="Connecting..." - labelComplete="Connected!" - onClickAsyncFn={this._onConnectLedgerClickAsync.bind(this, true)} - /> - {!_.isEmpty(this.state.connectionErrMsg) && ( - <div className="pt2 left-align" style={{ color: colors.red200 }}> - {this.state.connectionErrMsg} - </div> - )} - </div> - </div> - ); - } - private _renderSelectAddressStep(): React.ReactNode { - return ( - <div> - <div> - <Table bodyStyle={{ height: 300 }} onRowSelection={this._onAddressSelected.bind(this)}> - <TableHeader displaySelectAll={false}> - <TableRow> - <TableHeaderColumn colSpan={2}>Address</TableHeaderColumn> - <TableHeaderColumn>Balance</TableHeaderColumn> - </TableRow> - </TableHeader> - <TableBody>{this._renderAddressTableRows()}</TableBody> - </Table> - </div> - <div className="flex pt2" style={{ height: 100 }}> - <div className="overflow-hidden" style={{ width: 180 }}> - <TextField - floatingLabelFixed={true} - floatingLabelStyle={{ color: colors.grey }} - floatingLabelText="Update path derivation (advanced)" - value={this.state.derivationPath} - errorText={this.state.derivationErrMsg} - onChange={this._onDerivationPathChanged.bind(this)} - /> - </div> - <div className="pl2" style={{ paddingTop: 28 }}> - <LifeCycleRaisedButton - labelReady="Update" - labelLoading="Updating..." - labelComplete="Updated!" - onClickAsyncFn={this._onFetchAddressesForDerivationPathAsync.bind(this)} - /> - </div> - </div> - </div> - ); - } - private _renderAddressTableRows(): React.ReactNode { - const rows = _.map(this.state.userAddresses, (userAddress: string, i: number) => { - const balanceInWei = this.state.addressBalances[i]; - const addressTooltipId = `address-${userAddress}`; - const balanceTooltipId = `balance-${userAddress}`; - const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId]; - // We specifically prefix kovan ETH. - // TODO: We should probably add prefixes for all networks - const isKovanNetwork = networkName === 'Kovan'; - const balanceInEth = Web3Wrapper.toUnitAmount(balanceInWei, constants.DECIMAL_PLACES_ETH); - const balanceString = `${balanceInEth.toString()} ${isKovanNetwork ? 'Kovan ' : ''}ETH`; - return ( - <TableRow key={userAddress} style={{ height: 40 }}> - <TableRowColumn colSpan={2}> - <div data-tip={true} data-for={addressTooltipId}> - {userAddress} - </div> - <ReactTooltip id={addressTooltipId}>{userAddress}</ReactTooltip> - </TableRowColumn> - <TableRowColumn> - <div data-tip={true} data-for={balanceTooltipId}> - {balanceString} - </div> - <ReactTooltip id={balanceTooltipId}>{balanceString}</ReactTooltip> - </TableRowColumn> - </TableRow> - ); - }); - return rows; - } - private _onClose(): void { - this.setState({ - connectionErrMsg: '', - stepIndex: LedgerSteps.Connect, - }); - const isOpen = false; - this.props.toggleDialogFn(isOpen); - } - private _onAddressSelected(selectedRowIndexes: number[]): void { - const selectedRowIndex = selectedRowIndexes[0]; - const selectedAddress = this.state.userAddresses[selectedRowIndex]; - const selectAddressBalance = this.state.addressBalances[selectedRowIndex]; - this.props.dispatcher.updateUserAddress(selectedAddress); - this.props.blockchain.updateWeb3WrapperPrevUserAddress(selectedAddress); - // tslint:disable-next-line:no-floating-promises - this.props.blockchain.fetchTokenInformationAsync(); - this.props.dispatcher.updateUserWeiBalance(selectAddressBalance); - this.setState({ - stepIndex: LedgerSteps.Connect, - }); - const isOpen = false; - this.props.toggleDialogFn(isOpen); - } - private async _onFetchAddressesForDerivationPathAsync(): Promise<boolean> { - const currentlySetPath = this.props.blockchain.getLedgerDerivationPathIfExists(); - let didSucceed; - if (currentlySetPath === this.state.derivationPath) { - didSucceed = true; - return didSucceed; - } - this.props.blockchain.updateLedgerDerivationPathIfExists(this.state.derivationPath); - didSucceed = await this._fetchAddressesAndBalancesAsync(); - if (!didSucceed) { - this.setState({ - derivationErrMsg: 'Failed to connect to Ledger.', - }); - } - return didSucceed; - } - private async _fetchAddressesAndBalancesAsync(): Promise<boolean> { - let userAddresses: string[]; - const addressBalances: BigNumber[] = []; - try { - userAddresses = await this._getUserAddressesAsync(); - for (const address of userAddresses) { - const balanceInWei = await this.props.blockchain.getBalanceInWeiAsync(address); - addressBalances.push(balanceInWei); - } - } catch (err) { - logUtils.log(`Ledger error: ${JSON.stringify(err)}`); - this.setState({ - connectionErrMsg: 'Failed to connect. Follow the instructions and try again.', - }); - return false; - } - this.setState({ - userAddresses, - addressBalances, - }); - return true; - } - private _onDerivationPathChanged(_event: any, derivationPath: string): void { - let derivationErrMsg = ''; - if (!_.startsWith(derivationPath, VALID_ETHEREUM_DERIVATION_PATH_PREFIX)) { - derivationErrMsg = 'Must be valid Ethereum path.'; - } - - this.setState({ - derivationPath, - derivationErrMsg, - }); - } - private async _onConnectLedgerClickAsync(): Promise<boolean> { - const isU2FSupported = await utils.isU2FSupportedAsync(); - if (!isU2FSupported) { - logUtils.log(`U2F not supported in this browser`); - this.setState({ - connectionErrMsg: 'U2F not supported by this browser. Try using Chrome.', - }); - return false; - } - - if ( - this.props.providerType !== ProviderType.Ledger || - (this.props.providerType === ProviderType.Ledger && this.props.networkId !== this.state.preferredNetworkId) - ) { - await this.props.blockchain.updateProviderToLedgerAsync(this.state.preferredNetworkId); - } - - const didSucceed = await this._fetchAddressesAndBalancesAsync(); - if (didSucceed) { - this.setState({ - stepIndex: LedgerSteps.SelectAddress, - connectionErrMsg: '', - }); - } - return didSucceed; - } - private async _getUserAddressesAsync(): Promise<string[]> { - let userAddresses: string[]; - userAddresses = await this.props.blockchain.getUserAccountsAsync(); - - if (_.isEmpty(userAddresses)) { - throw new Error('No addresses retrieved.'); - } - return userAddresses; - } - private _onSelectedNetworkUpdated(_event: any, _index: number, networkId: number): void { - this.setState({ - preferredNetworkId: networkId, - }); - } -} diff --git a/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx b/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx deleted file mode 100644 index 326df2a8c..000000000 --- a/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { colors } from '@0x/react-shared'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import * as React from 'react'; - -interface PortalDisclaimerDialogProps { - isOpen: boolean; - onToggleDialog: () => void; -} - -export const PortalDisclaimerDialog = (props: PortalDisclaimerDialogProps) => { - return ( - <Dialog - title="0x Portal Disclaimer" - titleStyle={{ fontWeight: 100 }} - actions={[<FlatButton key="portalAgree" label="I Agree" onClick={props.onToggleDialog} />]} - open={props.isOpen} - onRequestClose={props.onToggleDialog} - autoScrollBodyContent={true} - modal={true} - > - <div className="pt2" style={{ color: colors.grey700 }}> - <div> - 0x Portal is a free software-based tool intended to help users to buy and sell ERC20-compatible - blockchain tokens through the 0x protocol on a purely peer-to-peer basis. 0x portal is not a - regulated marketplace, exchange or intermediary of any kind, and therefore, you should only use 0x - portal to exchange tokens that are not securities, commodity interests, or any other form of - regulated instrument. 0x has not attempted to screen or otherwise limit the tokens that you may - enter in 0x Portal. By clicking “I Agree” below, you understand that you are solely responsible for - using 0x Portal and buying and selling tokens using 0x Portal in compliance with all applicable laws - and regulations. - </div> - </div> - </Dialog> - ); -}; diff --git a/packages/website/ts/components/dialogs/send_dialog.tsx b/packages/website/ts/components/dialogs/send_dialog.tsx deleted file mode 100644 index 5f6927cef..000000000 --- a/packages/website/ts/components/dialogs/send_dialog.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { AddressInput } from 'ts/components/inputs/address_input'; -import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; -import { EthAmountInput } from 'ts/containers/inputs/eth_amount_input'; -import { Token } from 'ts/types'; - -interface SendDialogProps { - blockchain: Blockchain; - userAddress: string; - networkId: number; - onComplete: (recipient: string, value: BigNumber) => void; - onCancelled: () => void; - isOpen: boolean; - asset: Token | 'ETH'; - lastForceTokenStateRefetch: number; -} - -interface SendDialogState { - value?: BigNumber; - recipient: string; - shouldShowIncompleteErrs: boolean; - isAmountValid: boolean; -} - -export class SendDialog extends React.Component<SendDialogProps, SendDialogState> { - constructor(props: SendDialogProps) { - super(props); - this.state = { - recipient: '', - shouldShowIncompleteErrs: false, - isAmountValid: false, - }; - } - public render(): React.ReactNode { - const transferDialogActions = [ - <FlatButton key="cancelTransfer" label="Cancel" onClick={this._onCancel.bind(this)} />, - <FlatButton - key="sendTransfer" - disabled={this._hasErrors()} - label="Send" - primary={true} - onClick={this._onSendClick.bind(this)} - />, - ]; - return ( - <Dialog - title="I want to send" - titleStyle={{ fontWeight: 100 }} - actions={transferDialogActions} - open={this.props.isOpen} - > - {this._renderSendDialogBody()} - </Dialog> - ); - } - private _renderSendDialogBody(): React.ReactNode { - const input = - this.props.asset === 'ETH' ? ( - <EthAmountInput - label="Amount to send" - shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} - shouldCheckBalance={true} - shouldShowErrs={true} - onChange={this._onValueChange.bind(this)} - amount={this.state.value} - /> - ) : ( - <TokenAmountInput - blockchain={this.props.blockchain} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - label="Amount to send" - token={this.props.asset} - shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} - shouldCheckBalance={true} - shouldCheckAllowance={false} - onChange={this._onValueChange.bind(this)} - amount={this.state.value} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - /> - ); - return ( - <div className="mx-auto" style={{ maxWidth: 300 }}> - <div style={{ height: 80 }}> - <AddressInput - initialAddress={this.state.recipient} - updateAddress={this._onRecipientChange.bind(this)} - isRequired={true} - label="Recipient address'" - hintText="Address" - /> - </div> - {input} - </div> - ); - } - private _onRecipientChange(recipient?: string): void { - this.setState({ - shouldShowIncompleteErrs: false, - recipient, - }); - } - private _onValueChange(isValid: boolean, amount?: BigNumber): void { - this.setState({ - isAmountValid: isValid, - value: amount, - }); - } - private _onSendClick(): void { - if (this._hasErrors()) { - this.setState({ - shouldShowIncompleteErrs: true, - }); - } else { - const value = this.state.value; - this.setState({ - recipient: undefined, - value: undefined, - }); - this.props.onComplete(this.state.recipient, value); - } - } - private _onCancel(): void { - this.setState({ - value: undefined, - }); - this.props.onCancelled(); - } - private _hasErrors(): boolean { - return _.isUndefined(this.state.recipient) || _.isUndefined(this.state.value) || !this.state.isAmountValid; - } -} diff --git a/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx b/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx deleted file mode 100644 index c8d5af6b6..000000000 --- a/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import * as moment from 'moment'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { TrackTokenConfirmation } from 'ts/components/track_token_confirmation'; -import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { Token, TokenByAddress } from 'ts/types'; - -interface TrackTokenConfirmationDialogProps { - tokens: Token[]; - tokenByAddress: TokenByAddress; - isOpen: boolean; - onToggleDialog: (didConfirmTokenTracking: boolean) => void; - dispatcher: Dispatcher; - networkId: number; - blockchain: Blockchain; - userAddress: string; -} - -interface TrackTokenConfirmationDialogState { - isAddingTokenToTracked: boolean; -} - -export class TrackTokenConfirmationDialog extends React.Component< - TrackTokenConfirmationDialogProps, - TrackTokenConfirmationDialogState -> { - constructor(props: TrackTokenConfirmationDialogProps) { - super(props); - this.state = { - isAddingTokenToTracked: false, - }; - } - public render(): React.ReactNode { - const tokens = this.props.tokens; - return ( - <Dialog - title="Tracking confirmation" - titleStyle={{ fontWeight: 100 }} - actions={[ - <FlatButton - key="trackNo" - label="No" - onClick={this._onTrackConfirmationRespondedAsync.bind(this, false)} - />, - <FlatButton - key="trackYes" - label="Yes" - onClick={this._onTrackConfirmationRespondedAsync.bind(this, true)} - />, - ]} - open={this.props.isOpen} - onRequestClose={this.props.onToggleDialog.bind(this, false)} - autoScrollBodyContent={true} - > - <div className="pt2"> - <TrackTokenConfirmation - tokens={tokens} - networkId={this.props.networkId} - tokenByAddress={this.props.tokenByAddress} - isAddingTokenToTracked={this.state.isAddingTokenToTracked} - /> - </div> - </Dialog> - ); - } - private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean): Promise<void> { - if (!didUserAcceptTracking) { - this.props.onToggleDialog(didUserAcceptTracking); - return; - } - this.setState({ - isAddingTokenToTracked: true, - }); - const currentTimestamp = moment().unix(); - for (const token of this.props.tokens) { - const newTokenEntry = { - ...token, - trackedTimestamp: currentTimestamp, - }; - - trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newTokenEntry); - this.props.dispatcher.updateTokenByAddress([newTokenEntry]); - } - - this.setState({ - isAddingTokenToTracked: false, - }); - this.props.onToggleDialog(didUserAcceptTracking); - } -} diff --git a/packages/website/ts/components/documentation/docs_logo.tsx b/packages/website/ts/components/documentation/docs_logo.tsx deleted file mode 100644 index ac331db79..000000000 --- a/packages/website/ts/components/documentation/docs_logo.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Link } from '@0x/react-shared'; -import * as React from 'react'; -import { styled } from 'ts/style/theme'; -import { WebsitePaths } from 'ts/types'; - -import { Container } from '../ui/container'; - -export interface DocsLogoProps { - containerStyle?: React.CSSProperties; -} - -const Image = styled.img` - &:hover { - opacity: 0.7; - } -`; - -export const DocsLogo: React.StatelessComponent<DocsLogoProps> = props => { - return ( - <Container className="flex"> - <Container> - <Link to={WebsitePaths.Home}> - <Image src="/images/developers/logo/0x.svg" height={34} /> - </Link> - </Container> - <Container paddingTop="6px" paddingLeft="7px"> - <Link to={WebsitePaths.Docs}> - <Image src="/images/developers/logo/docs.svg" height={20} /> - </Link> - </Container> - </Container> - ); -}; - -DocsLogo.defaultProps = { - containerStyle: {}, -}; diff --git a/packages/website/ts/components/documentation/docs_top_bar.tsx b/packages/website/ts/components/documentation/docs_top_bar.tsx deleted file mode 100644 index c4291b78f..000000000 --- a/packages/website/ts/components/documentation/docs_top_bar.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { ALink, colors, Link } from '@0x/react-shared'; -import * as _ from 'lodash'; -import Drawer from 'material-ui/Drawer'; -import * as React from 'react'; -import { DocsLogo } from 'ts/components/documentation/docs_logo'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { Deco, Key, ScreenWidths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -export interface DocsTopBarProps { - location: Location; - screenWidth: ScreenWidths; - translate: Translate; - sidebar?: React.ReactNode; -} - -interface DocsTopBarState { - isDrawerOpen: boolean; -} - -export class DocsTopBar extends React.Component<DocsTopBarProps, DocsTopBarState> { - constructor(props: DocsTopBarProps) { - super(props); - this.state = { - isDrawerOpen: false, - }; - } - public componentWillReceiveProps(nextProps: DocsTopBarProps): void { - if (nextProps.location.pathname !== this.props.location.pathname) { - this.setState({ - isDrawerOpen: false, - }); - } - } - public render(): React.ReactNode { - return ( - <Container height={80}> - <Container - className="flex items-center lg-pt3 md-pt3 sm-pt1 lg-justify-end md-justify-end sm-justify-start" - width="100%" - > - <Container className="sm-hide xs-hide"> - <Container className="flex items-center justify-between right" width="250px"> - {this._renderMenuItems(constants.DEVELOPER_TOPBAR_LINKS)} - </Container> - </Container> - <Container className="lg-hide md-hide"> - <Container paddingTop="6px"> - <DocsLogo /> - </Container> - </Container> - <Container className="md-hide lg-hide absolute" right="18px" top="12px"> - <i - className="zmdi zmdi-menu" - style={{ - color: colors.grey700, - fontSize: 30, - cursor: 'pointer', - }} - onClick={this._onMenuButtonClick.bind(this)} - /> - </Container> - </Container> - <Container width={'100%'} height={'1px'} backgroundColor={colors.grey300} marginTop={'16px'} /> - {this.props.screenWidth === ScreenWidths.Sm && this._renderDrawer()} - </Container> - ); - } - private _renderMenuItems(menuItemLinks: ALink[]): React.ReactNode { - const menuItems = _.map(menuItemLinks, menuItemInfo => { - return ( - <Link - key={`menu-item-${menuItemInfo.title}`} - to={menuItemInfo.to} - shouldOpenInNewTab={menuItemInfo.shouldOpenInNewTab} - > - <Container className="flex items-center" paddingLeft="4px"> - <Text fontSize="16px" fontColor={colors.lightLinkBlue} fontWeight="bold"> - {this.props.translate.get(menuItemInfo.title as Key, Deco.Cap)} - </Text> - </Container> - </Link> - ); - }); - return menuItems; - } - private _renderDrawer(): React.ReactNode { - return ( - <Drawer - open={this.state.isDrawerOpen} - docked={false} - openSecondary={true} - onRequestChange={this._onMenuButtonClick.bind(this)} - > - <Container className="clearfix pl1 pt2" onClick={this._onMenuButtonClick.bind(this)}> - {this.props.sidebar} - </Container> - </Drawer> - ); - } - private _onMenuButtonClick(): void { - this.setState({ - isDrawerOpen: !this.state.isDrawerOpen, - }); - } -} diff --git a/packages/website/ts/components/documentation/overview_content.tsx b/packages/website/ts/components/documentation/overview_content.tsx deleted file mode 100644 index caabaf874..000000000 --- a/packages/website/ts/components/documentation/overview_content.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { colors, Link, MarkdownLinkBlock, utils as sharedUtils } from '@0x/react-shared'; -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; -import * as React from 'react'; -import * as ReactMarkdown from 'react-markdown'; -import { Element as ScrollElement } from 'react-scroll'; -import { TutorialButton } from 'ts/components/documentation/tutorial_button'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { Deco, Key, Package, TutorialInfo } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; - -export interface OverviewContentProps { - translate: Translate; - tutorials: TutorialInfo[]; - categoryToPackages: ObjectMap<Package[]>; -} - -export interface OverviewContentState {} - -export class OverviewContent extends React.Component<OverviewContentProps, OverviewContentState> { - public render(): React.ReactNode { - return ( - <Container> - {this._renderSectionTitle(this.props.translate.get(Key.StartBuildOn0x, Deco.Cap))} - <Container paddingTop="12px"> - {this._renderSectionDescription(this.props.translate.get(Key.StartBuildOn0xDescription, Deco.Cap))} - <Container marginTop="36px"> - {_.map(this.props.tutorials, tutorialInfo => ( - <ScrollElement - name={sharedUtils.getIdFromName( - this.props.translate.get(tutorialInfo.link.title as Key, Deco.Cap), - )} - key={`tutorial-${tutorialInfo.link.title}`} - > - <TutorialButton translate={this.props.translate} tutorialInfo={tutorialInfo} /> - </ScrollElement> - ))} - </Container> - </Container> - <Container marginTop="32px" paddingBottom="100px"> - {this._renderSectionTitle(this.props.translate.get(Key.LibrariesAndTools, Deco.CapWords))} - <Container paddingTop="12px"> - {this._renderSectionDescription( - this.props.translate.get(Key.LibrariesAndToolsDescription, Deco.Cap), - )} - <Container marginTop="36px"> - {_.map(this.props.categoryToPackages, (pkgs, category) => - this._renderPackageCategory(category, pkgs), - )} - </Container> - </Container> - </Container> - </Container> - ); - } - private _renderPackageCategory(category: string, pkgs: Package[]): React.ReactNode { - return ( - <Container key={`category-${category}`}> - <Text fontSize="18px">{category}</Text> - <Container>{_.map(pkgs, pkg => this._renderPackage(pkg))}</Container> - </Container> - ); - } - private _renderPackage(pkg: Package): React.ReactNode { - const id = sharedUtils.getIdFromName(pkg.link.title); - return ( - <ScrollElement name={id} key={`package-${pkg.link.title}`}> - <Container className="pb2"> - <Container width="100%" height="1px" backgroundColor={colors.grey300} marginTop="11px" /> - <Container className="clearfix mt2 pt1"> - <Container className="md-col lg-col md-col-4 lg-col-4"> - <Link - to={pkg.link.to} - fontColor={colors.lightLinkBlue} - shouldOpenInNewTab={!!pkg.link.shouldOpenInNewTab} - > - <Text Tag="div" fontColor={colors.lightLinkBlue} fontWeight="bold"> - {pkg.link.title} - </Text> - </Link> - </Container> - <Container className="md-col lg-col md-col-6 lg-col-6 sm-py2"> - <Text fontColor={colors.grey700}> - <ReactMarkdown - source={pkg.description} - renderers={{ - link: MarkdownLinkBlock, - paragraph: 'span', - }} - /> - </Text> - </Container> - <Container className="md-col lg-col md-col-2 lg-col-2 sm-pb2 relative"> - <Container position="absolute" right="0px"> - <Link - to={pkg.link.to} - fontColor={colors.lightLinkBlue} - shouldOpenInNewTab={!!pkg.link.shouldOpenInNewTab} - > - <Container className="flex"> - <Container>{this.props.translate.get(Key.More, Deco.Cap)}</Container> - <Container paddingTop="1px" paddingLeft="6px"> - <i - className="zmdi zmdi-chevron-right bold" - style={{ fontSize: 18, color: colors.lightLinkBlue }} - /> - </Container> - </Container> - </Link> - </Container> - </Container> - </Container> - </Container> - </ScrollElement> - ); - } - private _renderSectionTitle(text: string): React.ReactNode { - return ( - <Container paddingTop="30px"> - <Text fontColor={colors.projectsGrey} fontSize="30px" fontWeight="bold"> - {text} - </Text> - </Container> - ); - } - private _renderSectionDescription(text: string): React.ReactNode { - return ( - <Text fontColor={colors.linkSectionGrey} fontSize="16px" fontFamily="Roboto Mono"> - {text} - </Text> - ); - } -} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/documentation/sidebar_header.tsx b/packages/website/ts/components/documentation/sidebar_header.tsx deleted file mode 100644 index d158ab926..000000000 --- a/packages/website/ts/components/documentation/sidebar_header.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { VersionDropDown } from 'ts/components/documentation/version_drop_down'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { ScreenWidths } from 'ts/types'; - -export interface SidebarHeaderProps { - screenWidth: ScreenWidths; - title: string; - docsVersion?: string; - availableDocVersions?: string[]; - onVersionSelected?: () => void; -} - -export const SidebarHeader: React.StatelessComponent<SidebarHeaderProps> = ({ - screenWidth, - title, - docsVersion, - availableDocVersions, - onVersionSelected, -}) => { - return ( - <Container> - <Container className="flex justify-bottom"> - <Container className="col col-8 pl1"> - <Text - fontColor={colors.lightLinkBlue} - fontSize={screenWidth === ScreenWidths.Sm ? '20px' : '22px'} - fontWeight="bold" - lineHeight="26px" - > - {title} - </Text> - </Container> - {!_.isUndefined(docsVersion) && - !_.isUndefined(availableDocVersions) && - !_.isUndefined(onVersionSelected) && ( - <div className="col col-4 pl1" style={{ alignSelf: 'flex-end', paddingBottom: 4 }}> - <Container className="right"> - <VersionDropDown - selectedVersion={docsVersion} - versions={availableDocVersions} - onVersionSelected={onVersionSelected} - /> - </Container> - </div> - )} - </Container> - <Container - width={'100%'} - height={'1px'} - backgroundColor={colors.grey300} - marginTop="20px" - marginBottom="27px" - /> - </Container> - ); -}; diff --git a/packages/website/ts/components/documentation/tutorial_button.tsx b/packages/website/ts/components/documentation/tutorial_button.tsx deleted file mode 100644 index b747ef598..000000000 --- a/packages/website/ts/components/documentation/tutorial_button.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { colors, Link } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { Deco, Key, TutorialInfo } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; - -import { styled } from 'ts/style/theme'; - -export interface TutorialButtonProps { - className?: string; - translate: Translate; - tutorialInfo: TutorialInfo; -} - -const PlainTutorialButton: React.StatelessComponent<TutorialButtonProps> = ({ translate, tutorialInfo, className }) => ( - <Container className={className}> - <Link to={tutorialInfo.link.to} shouldOpenInNewTab={tutorialInfo.link.shouldOpenInNewTab}> - <div className="flex relative"> - <div className="col col-1 flex items-center sm-pr3"> - <img src={tutorialInfo.iconUrl} height={40} /> - </div> - <div className="lg-pl2 md-pl2 sm-pl3 col col-10"> - <Text Tag="div" fontSize="18" fontColor={colors.lightLinkBlue} fontWeight="bold"> - {translate.get(tutorialInfo.link.title as Key, Deco.Cap)} - </Text> - <Text Tag="div" fontColor={colors.grey750} fontSize="16"> - {translate.get(tutorialInfo.description as Key, Deco.Cap)} - </Text> - </div> - <div className="col col-1 flex items-center justify-end"> - <div className="right"> - <i - className="zmdi zmdi-chevron-right bold" - style={{ fontSize: 26, color: colors.lightLinkBlue }} - /> - </div> - </div> - </div> - </Link> - </Container> -); - -export const TutorialButton = styled(PlainTutorialButton)` - border-radius: 4px; - border: 1px solid ${colors.grey325}; - background-color: ${colors.white}; - &:hover { - border: 1px solid ${colors.lightLinkBlue}; - background-color: ${colors.lightestBlue}; - } - padding: 20px; - margin-bottom: 15px; -`; - -TutorialButton.defaultProps = {}; - -TutorialButton.displayName = 'TutorialButton'; diff --git a/packages/website/ts/components/documentation/version_drop_down.tsx b/packages/website/ts/components/documentation/version_drop_down.tsx deleted file mode 100644 index 5e77530fd..000000000 --- a/packages/website/ts/components/documentation/version_drop_down.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { Button } from 'ts/components/ui/button'; -import { Container } from 'ts/components/ui/container'; -import { DropDown, DropdownMouseEvent } from 'ts/components/ui/drop_down'; -import { Text } from 'ts/components/ui/text'; -import { styled } from 'ts/style/theme'; - -interface ActiveNodeProps { - className?: string; - selectedVersion: string; -} - -const PlainActiveNode: React.StatelessComponent<ActiveNodeProps> = ({ className, selectedVersion }) => ( - <Container className={className}> - <Container className="flex justify-center"> - <Text fontColor={colors.grey700} fontSize="12px"> - v {selectedVersion} - </Text> - <Container paddingLeft="6px"> - <i className="zmdi zmdi-chevron-down" style={{ fontSize: 17, color: 'rgba(153, 153, 153, 0.8)' }} /> - </Container> - </Container> - </Container> -); - -const ActiveNode = styled(PlainActiveNode)` - cursor: pointer; - border: 1px solid ${colors.beigeWhite}; - border-radius: 4px; - padding: 4px 6px 4px 8px; -`; - -interface VersionDropDownProps { - selectedVersion: string; - versions: string[]; - onVersionSelected: (semver: string) => void; -} - -interface VersionDropDownState {} - -export class VersionDropDown extends React.Component<VersionDropDownProps, VersionDropDownState> { - public render(): React.ReactNode { - const activeNode = <ActiveNode selectedVersion={this.props.selectedVersion} />; - return ( - <DropDown - activateEvent={DropdownMouseEvent.Click} - activeNode={activeNode} - popoverContent={this._renderDropdownMenu()} - anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }} - targetOrigin={{ horizontal: 'middle', vertical: 'top' }} - popoverStyle={{ borderRadius: 4 }} - /> - ); - } - private _renderDropdownMenu(): React.ReactNode { - const items = _.map(this.props.versions, version => { - const isSelected = version === this.props.selectedVersion; - return ( - <Container key={`dropdown-items-${version}`}> - <Button - borderRadius="0px" - padding="0.8em 0em" - width="100%" - isDisabled={isSelected} - onClick={this._onClick.bind(this, version)} - > - v {version} - </Button> - </Container> - ); - }); - const dropdownMenu = <Container width="88px">{items}</Container>; - return dropdownMenu; - } - private _onClick(selectedVersion: string): void { - this.props.onVersionSelected(selectedVersion); - } -} diff --git a/packages/website/ts/components/dropdowns/developers_drop_down.tsx b/packages/website/ts/components/dropdowns/developers_drop_down.tsx deleted file mode 100644 index 079132f2b..000000000 --- a/packages/website/ts/components/dropdowns/developers_drop_down.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { ALink, colors, Link } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { Container } from 'ts/components/ui/container'; -import { DropDown } from 'ts/components/ui/drop_down'; -import { Text } from 'ts/components/ui/text'; -import { Deco, Key, WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -const gettingStartedKeyToLinkInfo1: ALink[] = [ - { - title: Key.BuildARelayer, - to: `${WebsitePaths.Wiki}#Build-A-Relayer`, - }, - { - title: Key.OrderBasics, - to: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`, - }, -]; -const gettingStartedKeyToLinkInfo2: ALink[] = [ - { - title: Key.DevelopOnEthereum, - to: `${WebsitePaths.Wiki}#Ethereum-Development`, - }, - { - title: Key.UseNetworkedLiquidity, - to: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`, - }, -]; -const popularDocsToLinkInfos: ALink[] = [ - { - title: Key.ZeroExJs, - to: WebsitePaths.ZeroExJs, - }, - { - title: Key.Connect, - to: WebsitePaths.Connect, - }, - { - title: Key.SmartContract, - to: WebsitePaths.SmartContracts, - }, -]; -const usefulLinksToLinkInfo: ALink[] = [ - { - title: Key.Wiki, - to: WebsitePaths.Wiki, - }, - { - title: Key.Github, - to: constants.URL_GITHUB_ORG, - shouldOpenInNewTab: true, - }, - { - title: Key.ProtocolSpecification, - to: constants.URL_PROTOCOL_SPECIFICATION, - shouldOpenInNewTab: true, - }, -]; - -interface DevelopersDropDownProps { - location: Location; - translate: Translate; - menuItemStyles: React.CSSProperties; - menuIconStyle: React.CSSProperties; -} - -interface DevelopersDropDownState {} - -export class DevelopersDropDown extends React.Component<DevelopersDropDownProps, DevelopersDropDownState> { - public render(): React.ReactNode { - const activeNode = ( - <Container className="flex relative" paddingRight="10"> - <Text fontColor={this.props.menuIconStyle.color}> - {this.props.translate.get(Key.Developers, Deco.Cap)} - </Text> - </Container> - ); - return ( - <DropDown - activeNode={activeNode} - popoverContent={this._renderDropdownMenu()} - anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }} - targetOrigin={{ horizontal: 'left', vertical: 'top' }} - style={this.props.menuItemStyles} - popoverStyle={{ borderRadius: 4, width: 397, height: 373, marginTop: 0 }} - /> - ); - } - private _renderDropdownMenu(): React.ReactNode { - const sectionPadding = '26px'; - const dropdownMenu = ( - <Container> - <Container className="flex" padding={sectionPadding}> - <Container paddingRight="45px"> - {this._renderLinkSection(gettingStartedKeyToLinkInfo1, 'Getting started')} - </Container> - <Container>{this._renderLinkSection(gettingStartedKeyToLinkInfo2)}</Container> - </Container> - <Container width="100%" height="1px" backgroundColor={colors.grey300} /> - <Container className="flex" padding={sectionPadding}> - <Container paddingRight="62px"> - <Container>{this._renderLinkSection(popularDocsToLinkInfos, 'Popular docs')}</Container> - </Container> - <Container> - <Container>{this._renderLinkSection(usefulLinksToLinkInfo, 'Useful links')}</Container> - </Container> - </Container> - <Link to={WebsitePaths.Docs} fontColor={colors.lightBlueA700}> - <Container - padding="0.9rem" - backgroundColor={colors.lightBgGrey} - borderBottomLeftRadius={4} - borderBottomRightRadius={4} - > - <Text fontColor={colors.lightBlueA700} fontWeight="bold" fontSize="14px" textAlign="center"> - {this.props.translate.get(Key.ViewAllDocumentation, Deco.Upper)} - </Text> - </Container> - </Link> - </Container> - ); - return dropdownMenu; - } - private _renderLinkSection(links: ALink[], title: string = ''): React.ReactNode { - const numLinks = links.length; - let i = 0; - const renderLinks = _.map(links, (link: ALink) => { - const isWikiLink = _.startsWith(link.to, WebsitePaths.Wiki) && _.includes(link.to, '#'); - const isOnWiki = this.props.location.pathname === WebsitePaths.Wiki; - let to = link.to; - if (isWikiLink && isOnWiki) { - to = `${link.to.split('#')[1]}`; - } - i++; - const isLast = i === numLinks; - const linkText = this.props.translate.get(link.title as Key, Deco.Cap); - return ( - <Container className={`pr1 pt1 ${!isLast && 'pb1'}`} key={`dev-dropdown-link-${link.title}`}> - <Link to={to} shouldOpenInNewTab={!!link.shouldOpenInNewTab}> - <Text fontFamily="Roboto, Roboto Mono" fontColor={colors.lightBlueA700}> - {linkText} - </Text> - </Link> - </Container> - ); - }); - return ( - <Container> - <Container height="33px"> - {!_.isEmpty(title) && ( - <Text letterSpacing={1} fontColor={colors.linkSectionGrey} fontSize="14px" fontWeight={600}> - {title.toUpperCase()} - </Text> - )} - </Container> - {renderLinks} - </Container> - ); - } -} diff --git a/packages/website/ts/components/dropdowns/dropdown_developers.tsx b/packages/website/ts/components/dropdowns/dropdown_developers.tsx deleted file mode 100644 index 590d2ead9..000000000 --- a/packages/website/ts/components/dropdowns/dropdown_developers.tsx +++ /dev/null @@ -1,184 +0,0 @@ -import { Link } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import styled, { withTheme } from 'styled-components'; - -import { Button } from 'ts/components/button'; -import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout'; -import { ThemeValuesInterface } from 'ts/components/siteWrap'; -import { Heading } from 'ts/components/text'; -import { WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; - -interface Props { - theme: ThemeValuesInterface; -} - -interface LinkConfig { - label: string; - url: string; - shouldOpenInNewTab?: boolean; -} - -const introData: LinkConfig[] = [ - { - label: 'Build a relayer', - url: `${WebsitePaths.Wiki}#Build-A-Relayer`, - }, - { - label: 'Develop on Ethereum', - url: `${WebsitePaths.Wiki}#Ethereum-Development`, - }, - { - label: 'Make & take orders', - url: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`, - }, - { - label: 'Use networked liquidity', - url: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`, - }, - { - label: 'Market making', - url: `${WebsitePaths.MarketMaker}`, - }, -]; - -const docsData: LinkConfig[] = [ - { - label: '0x.js', - url: WebsitePaths.ZeroExJs, - }, - { - label: '0x Connect', - url: WebsitePaths.Connect, - }, - { - label: 'Smart Contract', - url: WebsitePaths.SmartContracts, - }, -]; - -const linksData: LinkConfig[] = [ - { - label: 'Wiki', - url: WebsitePaths.Wiki, - }, - { - label: 'Github', - url: constants.URL_GITHUB_ORG, - shouldOpenInNewTab: true, - }, - { - label: 'Protocol specification', - url: constants.URL_PROTOCOL_SPECIFICATION, - shouldOpenInNewTab: true, - }, -]; - -export const DropdownDevelopers: React.FunctionComponent<Props> = withTheme((props: Props) => ( - <> - <DropdownWrap> - <div> - <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}> - Getting Started - </Heading> - - <StyledGrid isCentered={false} isWrapped={true}> - {_.map(introData, (item, index) => ( - <li> - <Link key={`introLink-${index}`} to={item.url}> - {item.label} - </Link> - </li> - ))} - </StyledGrid> - </div> - - <StyledWrap> - <Column width="calc(100% - 15px)"> - <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}> - Popular Docs - </Heading> - - <ul> - {_.map(docsData, (item, index) => ( - <li key={`docsLink-${index}`}> - <Link to={item.url} shouldOpenInNewTab={item.shouldOpenInNewTab}> - {item.label} - </Link> - </li> - ))} - </ul> - </Column> - - <Column width="calc(100% - 15px)"> - <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}> - Useful Links - </Heading> - - <ul> - {_.map(linksData, (item, index) => ( - <li key={`usefulLink-${index}`}> - <Link to={item.url} shouldOpenInNewTab={item.shouldOpenInNewTab}> - {item.label} - </Link> - </li> - ))} - </ul> - </Column> - </StyledWrap> - - <StyledLink - to={WebsitePaths.Docs} - bgColor={props.theme.dropdownButtonBg} - isAccentColor={true} - isNoBorder={true} - > - View All Documentation - </StyledLink> - </DropdownWrap> - </> -)); - -const DropdownWrap = styled.div` - padding: 15px 30px 75px 30px; - - a { - color: inherit; - } - - li { - margin: 8px 0; - } -`; - -const StyledGrid = styled(WrapGrid.withComponent('ul'))` - li { - width: 50%; - flex-shrink: 0; - } -`; - -const StyledWrap = styled(FlexWrap)` - padding-top: 20px; - margin-top: 30px; - position: relative; - - &:before { - content: ''; - width: 100%; - height: 1px; - background-color: ${props => props.theme.dropdownColor}; - opacity: 0.15; - position: absolute; - top: 0; - left: 0; - } -`; - -const StyledLink = styled(Button)` - width: 100%; - position: absolute; - bottom: 0; - left: 0; -`; diff --git a/packages/website/ts/components/dropdowns/dropdown_products.tsx b/packages/website/ts/components/dropdowns/dropdown_products.tsx deleted file mode 100644 index 93fd1a4fe..000000000 --- a/packages/website/ts/components/dropdowns/dropdown_products.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; -import { Heading, Paragraph } from 'ts/components/text'; -import { WebsitePaths } from 'ts/types'; - -const navData = [ - { - title: '0x Instant', - description: 'Simple crypto purchasing', - url: WebsitePaths.Instant, - }, - { - title: '0x Launch Kit', - description: 'Build on the 0x protocol', - url: WebsitePaths.LaunchKit, - }, -]; - -export const DropdownProducts: React.FunctionComponent<{}> = () => ( - <List> - {_.map(navData, (item, index) => ( - <li key={`productLink-${index}`}> - <Link to={item.url}> - <Heading asElement="h3" color="inherit" isNoMargin={true} size="small"> - {item.title} - </Heading> - - {item.description && ( - <Paragraph color="inherit" isNoMargin={true} size="small" isMuted={0.5}> - {item.description} - </Paragraph> - )} - </Link> - </li> - ))} - </List> -); - -const List = styled.ul` - a { - padding: 15px 30px; - display: block; - color: inherit; - } -`; diff --git a/packages/website/ts/components/dropdowns/network_drop_down.tsx b/packages/website/ts/components/dropdowns/network_drop_down.tsx deleted file mode 100644 index df2d72edc..000000000 --- a/packages/website/ts/components/dropdowns/network_drop_down.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { constants as sharedConstants } from '@0x/react-shared'; -import * as _ from 'lodash'; -import DropDownMenu from 'material-ui/DropDownMenu'; -import MenuItem from 'material-ui/MenuItem'; -import * as React from 'react'; - -interface NetworkDropDownProps { - updateSelectedNetwork: (e: any, index: number, value: number) => void; - selectedNetworkId: number; - avialableNetworkIds: number[]; -} - -interface NetworkDropDownState {} - -export class NetworkDropDown extends React.Component<NetworkDropDownProps, NetworkDropDownState> { - public render(): React.ReactNode { - return ( - <div className="mx-auto" style={{ width: 120 }}> - <DropDownMenu value={this.props.selectedNetworkId} onChange={this.props.updateSelectedNetwork}> - {this._renderDropDownItems()} - </DropDownMenu> - </div> - ); - } - private _renderDropDownItems(): React.ReactNode { - const items = _.map(this.props.avialableNetworkIds, networkId => { - const networkName = sharedConstants.NETWORK_NAME_BY_ID[networkId]; - const primaryText = ( - <div className="flex"> - <div className="pr1" style={{ width: 14, paddingTop: 2 }}> - <img src={`/images/network_icons/${networkName.toLowerCase()}.png`} style={{ width: 14 }} /> - </div> - <div>{networkName}</div> - </div> - ); - return <MenuItem key={networkId} value={networkId} primaryText={primaryText} />; - }); - return items; - } -} diff --git a/packages/website/ts/components/eth_weth_conversion_button.tsx b/packages/website/ts/components/eth_weth_conversion_button.tsx deleted file mode 100644 index 536ba924b..000000000 --- a/packages/website/ts/components/eth_weth_conversion_button.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { BigNumber, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import RaisedButton from 'material-ui/RaisedButton'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { EthWethConversionDialog } from 'ts/components/dialogs/eth_weth_conversion_dialog'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { BlockchainCallErrs, Side, Token } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { utils } from 'ts/utils/utils'; - -interface EthWethConversionButtonProps { - userAddress: string; - networkId: number; - direction: Side; - ethToken: Token; - dispatcher: Dispatcher; - blockchain: Blockchain; - userEtherBalanceInWei: BigNumber; - isOutdatedWrappedEther: boolean; - onConversionSuccessful?: () => void; - isDisabled?: boolean; - lastForceTokenStateRefetch: number; - refetchEthTokenStateAsync: () => Promise<void>; -} - -interface EthWethConversionButtonState { - isEthConversionDialogVisible: boolean; - isEthConversionHappening: boolean; -} - -export class EthWethConversionButton extends React.Component< - EthWethConversionButtonProps, - EthWethConversionButtonState -> { - public static defaultProps: Partial<EthWethConversionButtonProps> = { - isDisabled: false, - onConversionSuccessful: _.noop.bind(_), - }; - public constructor(props: EthWethConversionButtonProps) { - super(props); - this.state = { - isEthConversionDialogVisible: false, - isEthConversionHappening: false, - }; - } - public render(): React.ReactNode { - const labelStyle = this.state.isEthConversionHappening ? { fontSize: 10 } : {}; - let callToActionLabel; - let inProgressLabel; - if (this.props.direction === Side.Deposit) { - callToActionLabel = 'Wrap'; - inProgressLabel = 'Wrapping...'; - } else { - callToActionLabel = 'Unwrap'; - inProgressLabel = 'Unwrapping...'; - } - return ( - <div> - <RaisedButton - style={{ width: '100%' }} - labelStyle={labelStyle} - disabled={this.props.isDisabled || this.state.isEthConversionHappening} - label={this.state.isEthConversionHappening ? inProgressLabel : callToActionLabel} - onClick={this._toggleConversionDialog.bind(this)} - /> - <EthWethConversionDialog - blockchain={this.props.blockchain} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - direction={this.props.direction} - isOpen={this.state.isEthConversionDialogVisible} - onComplete={this._onConversionAmountSelectedAsync.bind(this)} - onCancelled={this._toggleConversionDialog.bind(this)} - etherBalanceInWei={this.props.userEtherBalanceInWei} - token={this.props.ethToken} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - /> - </div> - ); - } - private _toggleConversionDialog(): void { - this.setState({ - isEthConversionDialogVisible: !this.state.isEthConversionDialogVisible, - }); - } - private async _onConversionAmountSelectedAsync(direction: Side, value: BigNumber): Promise<void> { - this.setState({ - isEthConversionHappening: true, - }); - this._toggleConversionDialog(); - const token = this.props.ethToken; - try { - if (direction === Side.Deposit) { - await this.props.blockchain.convertEthToWrappedEthTokensAsync(token.address, value); - const ethAmount = Web3Wrapper.toUnitAmount(value, constants.DECIMAL_PLACES_ETH); - this.props.dispatcher.showFlashMessage(`Successfully wrapped ${ethAmount.toString()} ETH to WETH`); - } else { - await this.props.blockchain.convertWrappedEthTokensToEthAsync(token.address, value); - const tokenAmount = Web3Wrapper.toUnitAmount(value, token.decimals); - this.props.dispatcher.showFlashMessage(`Successfully unwrapped ${tokenAmount.toString()} WETH to ETH`); - } - if (!this.props.isOutdatedWrappedEther) { - await this.props.refetchEthTokenStateAsync(); - } - this.props.onConversionSuccessful(); - } catch (err) { - const errMsg = `${err}`; - if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - } else if (!utils.didUserDenyWeb3Request(errMsg)) { - logUtils.log(`Unexpected error encountered: ${err}`); - logUtils.log(err.stack); - const errorMsg = - direction === Side.Deposit - ? 'Failed to wrap your ETH. Please try again.' - : 'Failed to unwrap your WETH. Please try again.'; - this.props.dispatcher.showFlashMessage(errorMsg); - errorReporter.report(err); - } - } - this.setState({ - isEthConversionHappening: false, - }); - } -} diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx deleted file mode 100644 index dc597b18f..000000000 --- a/packages/website/ts/components/eth_wrappers.tsx +++ /dev/null @@ -1,448 +0,0 @@ -import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import Divider from 'material-ui/Divider'; -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; -import * as moment from 'moment'; -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; -import { Blockchain } from 'ts/blockchain'; -import { EthWethConversionButton } from 'ts/components/eth_weth_conversion_button'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { - OutdatedWrappedEtherByNetworkId, - Side, - Token, - TokenByAddress, - TokenState, - TokenStateByAddress, -} from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { utils } from 'ts/utils/utils'; - -const DATE_FORMAT = 'D/M/YY'; -const ICON_DIMENSION = 40; -const ETHER_ICON_PATH = '/images/ether.png'; -const OUTDATED_WETH_ICON_PATH = '/images/wrapped_eth_gray.png'; - -interface EthWrappersProps { - networkId: number; - blockchain: Blockchain; - dispatcher: Dispatcher; - tokenByAddress: TokenByAddress; - userAddress: string; - userEtherBalanceInWei?: BigNumber; - lastForceTokenStateRefetch: number; - isFullWidth?: boolean; -} - -interface EthWrappersState { - ethTokenState: TokenState; - outdatedWETHStateByAddress: TokenStateByAddress; -} - -export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> { - public static defaultProps: Partial<EthWrappersProps> = { - isFullWidth: false, - }; - private _isUnmounted: boolean; - constructor(props: EthWrappersProps) { - super(props); - this._isUnmounted = false; - const outdatedWETHAddresses = this._getOutdatedWETHAddresses(); - const outdatedWETHStateByAddress: TokenStateByAddress = {}; - _.each(outdatedWETHAddresses, outdatedWETHAddress => { - outdatedWETHStateByAddress[outdatedWETHAddress] = { - balance: new BigNumber(0), - allowance: new BigNumber(0), - isLoaded: false, - }; - }); - this.state = { - outdatedWETHStateByAddress, - ethTokenState: { - balance: new BigNumber(0), - allowance: new BigNumber(0), - isLoaded: false, - }, - }; - } - public componentWillReceiveProps(nextProps: EthWrappersProps): void { - if ( - nextProps.userAddress !== this.props.userAddress || - nextProps.networkId !== this.props.networkId || - nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch - ) { - // tslint:disable-next-line:no-floating-promises - this._fetchWETHStateAsync(); - } - } - public componentDidMount(): void { - window.scrollTo(0, 0); - // tslint:disable-next-line:no-floating-promises - this._fetchWETHStateAsync(); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - } - public render(): React.ReactNode { - const etherToken = this._getEthToken(); - const wethBalance = Web3Wrapper.toUnitAmount(this.state.ethTokenState.balance, constants.DECIMAL_PLACES_ETH); - const isBidirectional = true; - const etherscanUrl = sharedUtils.getEtherScanLinkIfExists( - etherToken.address, - this.props.networkId, - EtherscanLinkSuffixes.Address, - ); - const tokenLabel = this._renderToken( - 'Wrapped Ether', - etherToken.address, - utils.getTokenIconUrl(etherToken.symbol), - ); - const userEtherBalanceInEth = !_.isUndefined(this.props.userEtherBalanceInWei) - ? Web3Wrapper.toUnitAmount(this.props.userEtherBalanceInWei, constants.DECIMAL_PLACES_ETH) - : undefined; - const rootClassName = this.props.isFullWidth ? 'clearfix' : 'clearfix lg-px4 md-px4 sm-px2'; - return ( - <div className={rootClassName} style={{ minHeight: 600 }}> - <div className="relative"> - <h3>ETH Wrapper</h3> - <div className="absolute" style={{ top: 0, right: 0 }}> - <a target="_blank" href={constants.URL_WETH_IO} style={{ color: colors.grey }}> - <div className="flex"> - <div>About Wrapped ETH</div> - <div className="pl1"> - <i className="zmdi zmdi-open-in-new" /> - </div> - </div> - </a> - </div> - </div> - <Divider /> - <div> - <div className="py2">Wrap ETH into an ERC20-compliant Ether token. 1 ETH = 1 WETH.</div> - <div> - <Table selectable={false} style={{ backgroundColor: 'transparent' }}> - <TableHeader displaySelectAll={false} adjustForCheckbox={false}> - <TableRow> - <TableHeaderColumn>ETH Token</TableHeaderColumn> - <TableHeaderColumn>Balance</TableHeaderColumn> - <TableHeaderColumn className="center"> - {this._renderActionColumnTitle(isBidirectional)} - </TableHeaderColumn> - </TableRow> - </TableHeader> - <TableBody displayRowCheckbox={false}> - <TableRow key="ETH"> - <TableRowColumn className="py1"> - <div className="flex"> - <img - style={{ - width: ICON_DIMENSION, - height: ICON_DIMENSION, - }} - src={ETHER_ICON_PATH} - /> - <div className="ml2 sm-hide xs-hide" style={{ marginTop: 12 }}> - ETH - </div> - </div> - </TableRowColumn> - <TableRowColumn> - {!_.isUndefined(userEtherBalanceInEth) ? ( - `${userEtherBalanceInEth.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} ETH` - ) : ( - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - )} - </TableRowColumn> - <TableRowColumn> - <EthWethConversionButton - refetchEthTokenStateAsync={this._refetchEthTokenStateAsync.bind(this)} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - isOutdatedWrappedEther={false} - direction={Side.Deposit} - ethToken={etherToken} - dispatcher={this.props.dispatcher} - blockchain={this.props.blockchain} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - isDisabled={_.isUndefined(userEtherBalanceInEth)} - /> - </TableRowColumn> - </TableRow> - <TableRow key="WETH"> - <TableRowColumn className="py1"> - {this._renderTokenLink(tokenLabel, etherscanUrl)} - </TableRowColumn> - <TableRowColumn> - {this.state.ethTokenState.isLoaded ? ( - `${wethBalance.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} WETH` - ) : ( - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - )} - </TableRowColumn> - <TableRowColumn> - <EthWethConversionButton - refetchEthTokenStateAsync={this._refetchEthTokenStateAsync.bind(this)} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - isOutdatedWrappedEther={false} - direction={Side.Receive} - isDisabled={!this.state.ethTokenState.isLoaded} - ethToken={etherToken} - dispatcher={this.props.dispatcher} - blockchain={this.props.blockchain} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - /> - </TableRowColumn> - </TableRow> - </TableBody> - </Table> - </div> - </div> - <div> - <h4>Outdated WETH</h4> - <Divider /> - <div className="pt2" style={{ lineHeight: 1.5 }}> - The{' '} - <a href={constants.URL_CANONICAL_WETH_POST} target="_blank"> - canonical WETH - </a>{' '} - contract is updated when necessary. Unwrap outdated WETH in order to
retrieve your ETH and move - it to the updated WETH token. - </div> - <div> - <Table selectable={false} style={{ backgroundColor: 'transparent' }}> - <TableHeader displaySelectAll={false} adjustForCheckbox={false}> - <TableRow> - <TableHeaderColumn>WETH Version</TableHeaderColumn> - <TableHeaderColumn>Balance</TableHeaderColumn> - <TableHeaderColumn className="center"> - {this._renderActionColumnTitle(!isBidirectional)} - </TableHeaderColumn> - </TableRow> - </TableHeader> - <TableBody displayRowCheckbox={false}>{this._renderOutdatedWeths(etherToken)}</TableBody> - </Table> - </div> - </div> - </div> - ); - } - private _renderActionColumnTitle(isBidirectional: boolean): React.ReactNode { - let iconClass = 'zmdi-long-arrow-right'; - let leftSymbol = 'WETH'; - let rightSymbol = 'ETH'; - if (isBidirectional) { - iconClass = 'zmdi-swap'; - leftSymbol = 'ETH'; - rightSymbol = 'WETH'; - } - return ( - <div className="flex mx-auto" style={{ width: 85 }}> - <div style={{ paddingTop: 3 }}>{leftSymbol}</div> - <div className="px1"> - <i style={{ fontSize: 18 }} className={`zmdi ${iconClass}`} /> - </div> - <div style={{ paddingTop: 3 }}>{rightSymbol}</div> - </div> - ); - } - private _renderOutdatedWeths(etherToken: Token): React.ReactNode { - const rows = _.map( - configs.OUTDATED_WRAPPED_ETHERS, - (outdatedWETHByNetworkId: OutdatedWrappedEtherByNetworkId) => { - const outdatedWETHIfExists = outdatedWETHByNetworkId[this.props.networkId]; - if (_.isUndefined(outdatedWETHIfExists)) { - return null; // noop - } - const timestampMsRange = outdatedWETHIfExists.timestampMsRange; - let dateRange: string; - if (!_.isUndefined(timestampMsRange)) { - const startMoment = moment(timestampMsRange.startTimestampMs); - const endMoment = moment(timestampMsRange.endTimestampMs); - dateRange = `${startMoment.format(DATE_FORMAT)}-${endMoment.format(DATE_FORMAT)}`; - } else { - dateRange = '-'; - } - const outdatedEtherToken = { - ...etherToken, - address: outdatedWETHIfExists.address, - }; - const outdatedEtherTokenState = this.state.outdatedWETHStateByAddress[outdatedWETHIfExists.address]; - const isStateLoaded = outdatedEtherTokenState.isLoaded; - const balanceInEthIfExists = isStateLoaded - ? Web3Wrapper.toUnitAmount(outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH).toFixed( - configs.AMOUNT_DISPLAY_PRECSION, - ) - : undefined; - const onConversionSuccessful = this._onOutdatedConversionSuccessfulAsync.bind( - this, - outdatedWETHIfExists.address, - ); - const etherscanUrl = sharedUtils.getEtherScanLinkIfExists( - outdatedWETHIfExists.address, - this.props.networkId, - EtherscanLinkSuffixes.Address, - ); - const tokenLabel = this._renderToken(dateRange, outdatedEtherToken.address, OUTDATED_WETH_ICON_PATH); - return ( - <TableRow key={`weth-${outdatedWETHIfExists.address}`}> - <TableRowColumn className="py1"> - {this._renderTokenLink(tokenLabel, etherscanUrl)} - </TableRowColumn> - <TableRowColumn> - {isStateLoaded ? ( - `${balanceInEthIfExists} WETH` - ) : ( - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - )} - </TableRowColumn> - <TableRowColumn> - <EthWethConversionButton - refetchEthTokenStateAsync={this._refetchEthTokenStateAsync.bind(this)} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - isDisabled={!isStateLoaded} - isOutdatedWrappedEther={true} - direction={Side.Receive} - ethToken={outdatedEtherToken} - dispatcher={this.props.dispatcher} - blockchain={this.props.blockchain} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - onConversionSuccessful={onConversionSuccessful} - /> - </TableRowColumn> - </TableRow> - ); - }, - ); - return rows; - } - private _renderTokenLink(tokenLabel: React.ReactNode, etherscanUrl: string): React.ReactNode { - return ( - <span> - {_.isUndefined(etherscanUrl) ? ( - tokenLabel - ) : ( - <a href={etherscanUrl} target="_blank" style={{ textDecoration: 'none' }}> - {tokenLabel} - </a> - )} - </span> - ); - } - private _renderToken(name: string, address: string, imgPath: string): React.ReactNode { - const tooltipId = `tooltip-${address}`; - return ( - <div className="flex"> - <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={imgPath} /> - <div className="ml2 sm-hide xs-hide" style={{ marginTop: 12 }}> - <span data-tip={true} data-for={tooltipId}> - {name} - </span> - <ReactTooltip id={tooltipId}>{address}</ReactTooltip> - </div> - </div> - ); - } - private async _onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string): Promise<void> { - const currentOutdatedWETHState = this.state.outdatedWETHStateByAddress[outdatedWETHAddress]; - this.setState({ - outdatedWETHStateByAddress: { - ...this.state.outdatedWETHStateByAddress, - [outdatedWETHAddress]: { - balance: currentOutdatedWETHState.balance, - allowance: currentOutdatedWETHState.allowance, - isLoaded: false, - }, - }, - }); - const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; - const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - outdatedWETHAddress, - ); - this.setState({ - outdatedWETHStateByAddress: { - ...this.state.outdatedWETHStateByAddress, - [outdatedWETHAddress]: { - balance, - allowance, - isLoaded: true, - }, - }, - }); - } - private async _fetchWETHStateAsync(): Promise<void> { - const tokens = _.values(this.props.tokenByAddress); - const wethToken = _.find(tokens, token => token.symbol === 'WETH'); - const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; - const [wethBalance, wethAllowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - wethToken.address, - ); - - const outdatedWETHAddresses = this._getOutdatedWETHAddresses(); - const outdatedWETHStateByAddress: TokenStateByAddress = {}; - for (const address of outdatedWETHAddresses) { - const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - address, - ); - outdatedWETHStateByAddress[address] = { - balance, - allowance, - isLoaded: true, - }; - } - if (!this._isUnmounted) { - this.setState({ - outdatedWETHStateByAddress, - ethTokenState: { - balance: wethBalance, - allowance: wethAllowance, - isLoaded: true, - }, - }); - } - } - private _getOutdatedWETHAddresses(): string[] { - const outdatedWETHAddresses = _.compact( - _.map(configs.OUTDATED_WRAPPED_ETHERS, outdatedWrappedEtherByNetwork => { - const outdatedWrappedEtherIfExists = outdatedWrappedEtherByNetwork[this.props.networkId]; - if (_.isUndefined(outdatedWrappedEtherIfExists)) { - return undefined; - } - const address = outdatedWrappedEtherIfExists.address; - return address; - }), - ); - return outdatedWETHAddresses; - } - private _getEthToken(): Token { - const tokens = _.values(this.props.tokenByAddress); - const etherToken = _.find(tokens, { symbol: 'WETH' }); - return etherToken; - } - private async _refetchEthTokenStateAsync(): Promise<void> { - const etherToken = this._getEthToken(); - const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; - const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - etherToken.address, - ); - this.setState({ - ethTokenState: { - balance, - allowance, - isLoaded: true, - }, - }); - } -} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/fill_order.tsx b/packages/website/ts/components/fill_order.tsx deleted file mode 100644 index 95a3671c4..000000000 --- a/packages/website/ts/components/fill_order.tsx +++ /dev/null @@ -1,661 +0,0 @@ -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { colors, Link } from '@0x/react-shared'; -import { BigNumber, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as accounting from 'accounting'; -import * as _ from 'lodash'; -import { Card, CardHeader, CardText } from 'material-ui/Card'; -import Divider from 'material-ui/Divider'; -import RaisedButton from 'material-ui/RaisedButton'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { TrackTokenConfirmationDialog } from 'ts/components/dialogs/track_token_confirmation_dialog'; -import { FillOrderJSON } from 'ts/components/fill_order_json'; -import { FillWarningDialog } from 'ts/components/fill_warning_dialog'; -import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; -import { Alert } from 'ts/components/ui/alert'; -import { EthereumAddress } from 'ts/components/ui/ethereum_address'; -import { Identicon } from 'ts/components/ui/identicon'; -import { VisualOrder } from 'ts/components/visual_order'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { portalOrderSchema } from 'ts/schemas/portal_order_schema'; -import { validator } from 'ts/schemas/validator'; -import { AlertTypes, BlockchainErrs, PortalOrder, Token, TokenByAddress, WebsitePaths } from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { orderParser } from 'ts/utils/order_parser'; -import { utils } from 'ts/utils/utils'; - -interface FillOrderProps { - blockchain: Blockchain; - blockchainErr: BlockchainErrs; - orderFillAmount: BigNumber; - isOrderInUrl: boolean; - networkId: number; - userAddress: string; - tokenByAddress: TokenByAddress; - initialOrder: PortalOrder; - dispatcher: Dispatcher; - lastForceTokenStateRefetch: number; - isFullWidth?: boolean; - shouldHideHeader?: boolean; -} - -interface FillOrderState { - didOrderValidationRun: boolean; - areAllInvolvedTokensTracked: boolean; - globalErrMsg: string; - orderJSON: string; - orderJSONErrMsg: string; - parsedOrder: PortalOrder; - didFillOrderSucceed: boolean; - didCancelOrderSucceed: boolean; - unavailableTakerAmount: BigNumber; - isMakerTokenAddressInRegistry: boolean; - isTakerTokenAddressInRegistry: boolean; - isFillWarningDialogOpen: boolean; - isFilling: boolean; - isCancelling: boolean; - isConfirmingTokenTracking: boolean; - tokensToTrack: Token[]; -} - -export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { - public static defaultProps: Partial<FillOrderProps> = { - isFullWidth: false, - shouldHideHeader: false, - }; - private _isUnmounted: boolean; - constructor(props: FillOrderProps) { - super(props); - this._isUnmounted = false; - this.state = { - globalErrMsg: '', - didOrderValidationRun: false, - areAllInvolvedTokensTracked: false, - didFillOrderSucceed: false, - didCancelOrderSucceed: false, - orderJSON: _.isUndefined(this.props.initialOrder) ? '' : JSON.stringify(this.props.initialOrder), - orderJSONErrMsg: '', - parsedOrder: this.props.initialOrder, - unavailableTakerAmount: new BigNumber(0), - isMakerTokenAddressInRegistry: false, - isTakerTokenAddressInRegistry: false, - isFillWarningDialogOpen: false, - isFilling: false, - isCancelling: false, - isConfirmingTokenTracking: false, - tokensToTrack: [], - }; - } - public componentWillMount(): void { - if (!_.isEmpty(this.state.orderJSON)) { - // tslint:disable-next-line:no-floating-promises - this._validateFillOrderFireAndForgetAsync(this.state.orderJSON); - } - } - public componentDidMount(): void { - window.scrollTo(0, 0); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - } - public render(): React.ReactNode { - const rootClassName = this.props.isFullWidth ? 'clearfix' : 'lg-px4 md-px4 sm-px2'; - return ( - <div className={rootClassName} style={{ minHeight: 600 }}> - {!this.props.shouldHideHeader && ( - <div> - <h3>Fill an order</h3> - <Divider /> - </div> - )} - <div> - {!this.props.isOrderInUrl && ( - <div> - <div className="pt2 pb2">Paste an order JSON snippet below to begin</div> - <div className="pb2">Order JSON</div> - <FillOrderJSON - blockchain={this.props.blockchain} - tokenByAddress={this.props.tokenByAddress} - orderJSON={this.state.orderJSON} - onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)} - /> - {this._renderOrderJsonNotices()} - </div> - )} - <div> - {!_.isUndefined(this.state.parsedOrder) && - this.state.didOrderValidationRun && - this.state.areAllInvolvedTokensTracked && - this._renderVisualOrder()} - </div> - {this.props.isOrderInUrl && ( - <div className="pt2"> - <Card - style={{ - boxShadow: 'none', - backgroundColor: 'none', - border: '1px solid #eceaea', - }} - > - <CardHeader title="Order JSON" actAsExpander={true} showExpandableButton={true} /> - <CardText expandable={true}> - <FillOrderJSON - blockchain={this.props.blockchain} - tokenByAddress={this.props.tokenByAddress} - orderJSON={this.state.orderJSON} - onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)} - /> - </CardText> - </Card> - {this._renderOrderJsonNotices()} - </div> - )} - </div> - <FillWarningDialog - isOpen={this.state.isFillWarningDialogOpen} - onToggleDialog={this._onFillWarningClosed.bind(this)} - /> - <TrackTokenConfirmationDialog - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this.props.blockchain} - tokenByAddress={this.props.tokenByAddress} - dispatcher={this.props.dispatcher} - tokens={this.state.tokensToTrack} - isOpen={this.state.isConfirmingTokenTracking} - onToggleDialog={this._onToggleTrackConfirmDialog.bind(this)} - /> - </div> - ); - } - private _renderOrderJsonNotices(): React.ReactNode { - return ( - <div> - {!_.isUndefined(this.props.initialOrder) && !this.state.didOrderValidationRun && ( - <div className="pt2"> - <span className="pr1"> - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - </span> - <span>Validating order...</span> - </div> - )} - {!_.isEmpty(this.state.orderJSONErrMsg) && ( - <Alert type={AlertTypes.Error} message={this.state.orderJSONErrMsg} /> - )} - </div> - ); - } - private _renderVisualOrder(): React.ReactNode { - const takerTokenAddress = assetDataUtils.decodeERC20AssetData(this.state.parsedOrder.signedOrder.takerAssetData) - .tokenAddress; - const takerToken = this.props.tokenByAddress[takerTokenAddress]; - const orderTakerAmount = this.state.parsedOrder.signedOrder.takerAssetAmount; - const orderMakerAmount = this.state.parsedOrder.signedOrder.makerAssetAmount; - const takerAssetToken = { - amount: orderTakerAmount.minus(this.state.unavailableTakerAmount), - symbol: takerToken.symbol, - }; - const fillToken = this.props.tokenByAddress[takerTokenAddress]; - const makerTokenAddress = assetDataUtils.decodeERC20AssetData(this.state.parsedOrder.signedOrder.makerAssetData) - .tokenAddress; - const makerToken = this.props.tokenByAddress[makerTokenAddress]; - const makerAssetToken = { - amount: orderMakerAmount - .times(takerAssetToken.amount) - .div(orderTakerAmount) - .integerValue(BigNumber.ROUND_FLOOR), - symbol: makerToken.symbol, - }; - const fillAssetToken = { - amount: this.props.orderFillAmount, - symbol: takerToken.symbol, - }; - const parsedOrderExpiration = this.state.parsedOrder.signedOrder.expirationTimeSeconds; - - let orderReceiveAmount = 0; - if (!_.isUndefined(this.props.orderFillAmount)) { - const orderReceiveAmountBigNumber = orderMakerAmount - .times(this.props.orderFillAmount) - .dividedBy(orderTakerAmount) - .integerValue(BigNumber.ROUND_FLOOR); - orderReceiveAmount = this._formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals); - } - const isUserMaker = - !_.isUndefined(this.state.parsedOrder) && - this.state.parsedOrder.signedOrder.makerAddress === this.props.userAddress; - const expiryDate = utils.convertToReadableDateTimeFromUnixTimestamp(parsedOrderExpiration); - return ( - <div className="pt3 pb1"> - <div className="clearfix pb2" style={{ width: '100%' }}> - <div className="inline left">Order details</div> - <div className="inline right" style={{ minWidth: 208 }}> - <div className="col col-4 pl2" style={{ color: colors.grey }}> - Maker: - </div> - <div className="col col-2 pr1"> - <Identicon address={this.state.parsedOrder.signedOrder.makerAddress} diameter={23} /> - </div> - <div className="col col-6"> - <EthereumAddress - address={this.state.parsedOrder.signedOrder.makerAddress} - networkId={this.props.networkId} - /> - </div> - </div> - </div> - <div className="lg-px4 md-px4 sm-px0"> - <div className="lg-px4 md-px4 sm-px1 pt1"> - <VisualOrder - makerAssetToken={makerAssetToken} - takerAssetToken={takerAssetToken} - tokenByAddress={this.props.tokenByAddress} - makerToken={makerToken} - takerToken={takerToken} - networkId={this.props.networkId} - isMakerTokenAddressInRegistry={this.state.isMakerTokenAddressInRegistry} - isTakerTokenAddressInRegistry={this.state.isTakerTokenAddressInRegistry} - /> - <div className="center pt3 pb2">Expires: {expiryDate} UTC</div> - </div> - </div> - {!isUserMaker && ( - <div className="clearfix mx-auto relative" style={{ width: 235, height: 108 }}> - <TokenAmountInput - blockchain={this.props.blockchain} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - label="Fill amount" - onChange={this._onFillAmountChange.bind(this)} - shouldShowIncompleteErrs={false} - token={fillToken} - amount={fillAssetToken.amount} - shouldCheckBalance={true} - shouldCheckAllowance={true} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - /> - <div - className="absolute sm-hide xs-hide" - style={{ - color: colors.grey400, - right: -247, - top: 39, - width: 242, - }} - > - = {accounting.formatNumber(orderReceiveAmount, 6)} {makerToken.symbol} - </div> - </div> - )} - <div> - {isUserMaker ? ( - <div> - <RaisedButton - style={{ width: '100%' }} - disabled={this.state.isCancelling} - label={this.state.isCancelling ? 'Cancelling order...' : 'Cancel order'} - onClick={this._onCancelOrderClickFireAndForgetAsync.bind(this)} - /> - {this.state.didCancelOrderSucceed && ( - <Alert type={AlertTypes.Success} message={this._renderCancelSuccessMsg()} /> - )} - </div> - ) : ( - <div> - <RaisedButton - style={{ width: '100%' }} - disabled={this.state.isFilling} - label={this.state.isFilling ? 'Filling order...' : 'Fill order'} - onClick={this._onFillOrderClick.bind(this)} - /> - {!_.isEmpty(this.state.globalErrMsg) && ( - <Alert type={AlertTypes.Error} message={this.state.globalErrMsg} /> - )} - {this.state.didFillOrderSucceed && ( - <Alert type={AlertTypes.Success} message={this._renderFillSuccessMsg()} /> - )} - </div> - )} - </div> - </div> - ); - } - private _renderFillSuccessMsg(): React.ReactNode { - return ( - <div> - Order successfully filled. See the trade details in your{' '} - <Link to={`${WebsitePaths.Portal}/trades`} fontColor={colors.white}> - trade history - </Link> - </div> - ); - } - private _renderCancelSuccessMsg(): React.ReactNode { - return <div>Order successfully cancelled.</div>; - } - private _onFillOrderClick(): void { - if (!this.state.isMakerTokenAddressInRegistry || !this.state.isTakerTokenAddressInRegistry) { - this.setState({ - isFillWarningDialogOpen: true, - }); - } else { - // tslint:disable-next-line:no-floating-promises - this._onFillOrderClickFireAndForgetAsync(); - } - } - private _onFillWarningClosed(didUserCancel: boolean): void { - this.setState({ - isFillWarningDialogOpen: false, - }); - if (!didUserCancel) { - // tslint:disable-next-line:no-floating-promises - this._onFillOrderClickFireAndForgetAsync(); - } - } - private _onFillAmountChange(_isValid: boolean, amount?: BigNumber): void { - this.props.dispatcher.updateOrderFillAmount(amount); - } - private _onFillOrderJSONChanged(event: any): void { - const orderJSON = event.target.value; - this.setState({ - didOrderValidationRun: _.isEmpty(orderJSON) && _.isEmpty(this.state.orderJSONErrMsg), - didFillOrderSucceed: false, - }); - // tslint:disable-next-line:no-floating-promises - this._validateFillOrderFireAndForgetAsync(orderJSON); - } - private async _checkForUntrackedTokensAndAskToAddAsync(): Promise<void> { - if (!_.isEmpty(this.state.orderJSONErrMsg)) { - return; - } - const makerTokenAddress = assetDataUtils.decodeERC20AssetData(this.state.parsedOrder.signedOrder.makerAssetData) - .tokenAddress; - const takerTokenAddress = assetDataUtils.decodeERC20AssetData(this.state.parsedOrder.signedOrder.takerAssetData) - .tokenAddress; - const makerTokenIfExists = this.props.tokenByAddress[makerTokenAddress]; - const takerTokenIfExists = this.props.tokenByAddress[takerTokenAddress]; - const tokensToTrack: Token[] = []; - const isUnseenMakerToken = _.isUndefined(makerTokenIfExists); - const isMakerTokenTracked = !_.isUndefined(makerTokenIfExists) && utils.isTokenTracked(makerTokenIfExists); - if (isUnseenMakerToken) { - tokensToTrack.push({ - ...this.state.parsedOrder.metadata.makerToken, - address: makerTokenAddress, - iconUrl: undefined, - trackedTimestamp: undefined, - isRegistered: false, - }); - } else if (!isMakerTokenTracked) { - tokensToTrack.push(makerTokenIfExists); - } - const isUnseenTakerToken = _.isUndefined(takerTokenIfExists); - const isTakerTokenTracked = !_.isUndefined(takerTokenIfExists) && utils.isTokenTracked(takerTokenIfExists); - if (isUnseenTakerToken) { - tokensToTrack.push({ - ...this.state.parsedOrder.metadata.takerToken, - address: takerTokenAddress, - iconUrl: undefined, - trackedTimestamp: undefined, - isRegistered: false, - }); - } else if (!isTakerTokenTracked) { - tokensToTrack.push(takerTokenIfExists); - } - if (!_.isEmpty(tokensToTrack)) { - this.setState({ - isConfirmingTokenTracking: true, - tokensToTrack, - }); - } else { - this.setState({ - areAllInvolvedTokensTracked: true, - }); - } - } - private async _validateFillOrderFireAndForgetAsync(orderJSON: string): Promise<void> { - let orderJSONErrMsg = ''; - let parsedOrder: PortalOrder; - let orderHash: string; - try { - const order = orderParser.parseJsonString(orderJSON); - const validationResult = validator.validate(order, portalOrderSchema); - if (validationResult.errors.length > 0) { - orderJSONErrMsg = 'Submitted order JSON is not a valid order'; - logUtils.log(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`); - return; - } - parsedOrder = order; - const signedOrder = parsedOrder.signedOrder; - orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const exchangeContractAddr = this.props.blockchain.getExchangeContractAddressIfExists(); - const signature = signedOrder.signature; - const isSignatureValid = await this.props.blockchain.isValidSignatureAsync( - orderHash, - signature, - signedOrder.makerAddress, - ); - if (exchangeContractAddr !== signedOrder.exchangeAddress) { - orderJSONErrMsg = 'This order was made on another network or using a deprecated Exchange contract'; - parsedOrder = undefined; - } else if (!isSignatureValid) { - orderJSONErrMsg = 'Order signature is invalid'; - parsedOrder = undefined; - } else { - // Update user supplied order cache so that if they navigate away from fill view - // e.g to set a token allowance, when they come back, the fill order persists - this.props.dispatcher.updateUserSuppliedOrderCache(parsedOrder); - } - } catch (err) { - logUtils.log(`Validate order err: ${err}`); - if (!_.isEmpty(orderJSON)) { - orderJSONErrMsg = 'Submitted order JSON is not valid JSON'; - } - if (!this._isUnmounted) { - this.setState({ - didOrderValidationRun: true, - orderJSON, - orderJSONErrMsg, - parsedOrder, - }); - } - return; - } - - let unavailableTakerAmount = new BigNumber(0); - if (!_.isEmpty(orderJSONErrMsg)) { - // Clear cache entry if user updates orderJSON to invalid entry - this.props.dispatcher.updateUserSuppliedOrderCache(undefined); - } else { - unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash); - const makerTokenAddress = assetDataUtils.decodeERC20AssetData(parsedOrder.signedOrder.makerAssetData) - .tokenAddress; - const takerTokenAddress = assetDataUtils.decodeERC20AssetData(parsedOrder.signedOrder.takerAssetData) - .tokenAddress; - const isMakerTokenAddressInRegistry = await this.props.blockchain.isAddressInTokenRegistryAsync( - makerTokenAddress, - ); - const isTakerTokenAddressInRegistry = await this.props.blockchain.isAddressInTokenRegistryAsync( - takerTokenAddress, - ); - this.setState({ - isMakerTokenAddressInRegistry, - isTakerTokenAddressInRegistry, - }); - } - - this.setState({ - didOrderValidationRun: true, - orderJSON, - orderJSONErrMsg, - parsedOrder, - unavailableTakerAmount, - }); - - await this._checkForUntrackedTokensAndAskToAddAsync(); - } - private _trackOrderEvent(eventName: string): void { - const parsedOrder = this.state.parsedOrder; - analytics.trackOrderEvent(eventName, parsedOrder); - } - private async _onFillOrderClickFireAndForgetAsync(): Promise<void> { - if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return; - } - - this.setState({ - isFilling: true, - didFillOrderSucceed: false, - }); - - const parsedOrder = this.state.parsedOrder; - const takerFillAmount = this.props.orderFillAmount; - - if (_.isUndefined(this.props.userAddress)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - this.setState({ - isFilling: false, - }); - return; - } - let globalErrMsg = ''; - - if (_.isUndefined(takerFillAmount)) { - globalErrMsg = 'You must specify a fill amount'; - } - - const signedOrder = parsedOrder.signedOrder; - if (_.isEmpty(globalErrMsg)) { - try { - await this.props.blockchain.validateFillOrderThrowIfInvalidAsync( - signedOrder, - takerFillAmount, - this.props.userAddress, - ); - } catch (err) { - globalErrMsg = utils.zeroExErrToHumanReadableErrMsg(err.message, parsedOrder.signedOrder.takerAddress); - } - } - if (!_.isEmpty(globalErrMsg)) { - this.setState({ - isFilling: false, - globalErrMsg, - }); - return; - } - try { - const orderFilledAmount: BigNumber = await this.props.blockchain.fillOrderAsync( - signedOrder, - this.props.orderFillAmount, - ); - this._trackOrderEvent('Fill Order Success'); - // After fill completes, let's force fetch the token balances - this.props.dispatcher.forceTokenStateRefetch(); - this.setState({ - isFilling: false, - didFillOrderSucceed: true, - globalErrMsg: '', - unavailableTakerAmount: this.state.unavailableTakerAmount.plus(orderFilledAmount), - }); - return; - } catch (err) { - this.setState({ - isFilling: false, - }); - this._trackOrderEvent('Fill Order Failure'); - const errMsg = `${err}`; - if (utils.didUserDenyWeb3Request(errMsg)) { - return; - } - globalErrMsg = 'Failed to fill order, please refresh and try again'; - logUtils.log(`${err}`); - this.setState({ - globalErrMsg, - }); - errorReporter.report(err); - return; - } - } - private async _onCancelOrderClickFireAndForgetAsync(): Promise<void> { - if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return; - } - - this.setState({ - isCancelling: true, - didCancelOrderSucceed: false, - }); - - const parsedOrder = this.state.parsedOrder; - const takerAddress = this.props.userAddress; - - if (_.isUndefined(takerAddress)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - this.setState({ - isFilling: false, - }); - return; - } - let globalErrMsg = ''; - const signedOrder = parsedOrder.signedOrder; - const takerTokenAmount = signedOrder.takerAssetAmount; - if (!_.isEmpty(globalErrMsg)) { - this.setState({ - isCancelling: false, - globalErrMsg, - }); - return; - } - try { - await this.props.blockchain.cancelOrderAsync(signedOrder); - this.setState({ - isCancelling: false, - didCancelOrderSucceed: true, - globalErrMsg: '', - unavailableTakerAmount: takerTokenAmount, - }); - this._trackOrderEvent('Cancel Order Success'); - return; - } catch (err) { - this.setState({ - isCancelling: false, - }); - const errMsg = `${err}`; - if (utils.didUserDenyWeb3Request(errMsg)) { - return; - } - this._trackOrderEvent('Cancel Order Failure'); - globalErrMsg = 'Failed to cancel order, please refresh and try again'; - logUtils.log(`${err}`); - this.setState({ - globalErrMsg, - }); - errorReporter.report(err); - return; - } - } - private _formatCurrencyAmount(amount: BigNumber, decimals: number): number { - const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals); - const roundedUnitAmount = Math.round(unitAmount.toNumber() * 100000) / 100000; - return roundedUnitAmount; - } - private _onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean): void { - if (!didConfirmTokenTracking) { - this.setState({ - orderJSON: '', - orderJSONErrMsg: '', - parsedOrder: undefined, - }); - } else { - this.setState({ - areAllInvolvedTokensTracked: true, - }); - } - this.setState({ - isConfirmingTokenTracking: !this.state.isConfirmingTokenTracking, - tokensToTrack: [], - }); - } -} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/fill_order_json.tsx b/packages/website/ts/components/fill_order_json.tsx deleted file mode 100644 index 41413eac2..000000000 --- a/packages/website/ts/components/fill_order_json.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import Paper from 'material-ui/Paper'; -import TextField from 'material-ui/TextField'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { Side, TokenByAddress } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { utils } from 'ts/utils/utils'; - -interface FillOrderJSONProps { - blockchain: Blockchain; - tokenByAddress: TokenByAddress; - orderJSON: string; - onFillOrderJSONChanged: (event: any) => void; -} - -interface FillOrderJSONState {} - -export class FillOrderJSON extends React.Component<FillOrderJSONProps, FillOrderJSONState> { - public render(): React.ReactNode { - const tokenAddresses = _.keys(this.props.tokenByAddress); - const exchangeContract = this.props.blockchain.getExchangeContractAddressIfExists(); - const hintSideToAssetToken = { - [Side.Deposit]: { - amount: new BigNumber(35), - address: tokenAddresses[0], - }, - [Side.Receive]: { - amount: new BigNumber(89), - address: tokenAddresses[1], - }, - }; - const hintOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec(); - const hintECSignature = '0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33'; - const hintSalt = generatePseudoRandomSalt(); - const feeRecipient = constants.NULL_ADDRESS; - const hintOrder = utils.generateOrder( - exchangeContract, - hintSideToAssetToken, - hintOrderExpiryTimestamp, - '', - '', - constants.MAKER_FEE, - constants.TAKER_FEE, - feeRecipient, - hintECSignature, - this.props.tokenByAddress, - hintSalt, - ); - const hintOrderJSON = `${JSON.stringify(hintOrder, null, '\t').substring(0, 500)}...`; - return ( - <div> - <Paper className="p1 overflow-hidden" style={{ height: 164 }}> - <TextField - id="orderJSON" - hintStyle={{ bottom: 0, top: 0 }} - fullWidth={true} - value={this.props.orderJSON} - onChange={this.props.onFillOrderJSONChanged.bind(this)} - hintText={hintOrderJSON} - multiLine={true} - rows={6} - rowsMax={6} - underlineStyle={{ display: 'none' }} - textareaStyle={{ marginTop: 0 }} - /> - </Paper> - </div> - ); - } -} diff --git a/packages/website/ts/components/fill_warning_dialog.tsx b/packages/website/ts/components/fill_warning_dialog.tsx deleted file mode 100644 index 5be09e6c2..000000000 --- a/packages/website/ts/components/fill_warning_dialog.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { colors } from '@0x/react-shared'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import * as React from 'react'; - -interface FillWarningDialogProps { - isOpen: boolean; - onToggleDialog: (didUserCancel: boolean) => void; -} - -export const FillWarningDialog = (props: FillWarningDialogProps) => { - const didCancel = true; - return ( - <Dialog - title="Warning" - titleStyle={{ fontWeight: 100, color: colors.red500 }} - actions={[ - <FlatButton - key="fillWarningCancel" - label="Cancel" - onClick={() => props.onToggleDialog(didCancel)} // tslint:disable-line:jsx-no-lambda - />, - <FlatButton - key="fillWarningContinue" - label="Fill Order" - onClick={() => props.onToggleDialog(!didCancel)} // tslint:disable-line:jsx-no-lambda - />, - ]} - open={props.isOpen} - onRequestClose={() => props.onToggleDialog(didCancel)} // tslint:disable-line:jsx-no-lambda - autoScrollBodyContent={true} - modal={true} - > - <div className="pt2" style={{ color: colors.grey700 }}> - <div> - At least one of the tokens in this order was not found in the token registry smart contract and may - be counterfeit. It is your responsibility to verify the token addresses on Etherscan ( - <a href="https://0x.org/wiki#Verifying-Custom-Tokens" target="_blank"> - See this how-to guide - </a> - ) before filling an order. <b>This action may result in the loss of funds</b>. - </div> - </div> - </Dialog> - ); -}; diff --git a/packages/website/ts/components/flash_messages/asset_send_completed.tsx b/packages/website/ts/components/flash_messages/asset_send_completed.tsx deleted file mode 100644 index b895126dc..000000000 --- a/packages/website/ts/components/flash_messages/asset_send_completed.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { utils } from 'ts/utils/utils'; - -interface AssetSendCompletedProps { - etherScanLinkIfExists?: string; - toAddress: string; - amountInBaseUnits: BigNumber; - decimals: number; - symbol: string; -} - -interface AssetSendCompletedState {} - -export class AssetSendCompleted extends React.Component<AssetSendCompletedProps, AssetSendCompletedState> { - public render(): React.ReactNode { - const etherScanLink = !_.isUndefined(this.props.etherScanLinkIfExists) && ( - <a style={{ color: colors.white }} href={`${this.props.etherScanLinkIfExists}`} target="_blank"> - Verify on Etherscan - </a> - ); - const amountInUnits = Web3Wrapper.toUnitAmount(this.props.amountInBaseUnits, this.props.decimals); - const truncatedAddress = utils.getAddressBeginAndEnd(this.props.toAddress); - return ( - <div> - {`Sent ${amountInUnits} ${this.props.symbol} to ${truncatedAddress}: `} - {etherScanLink} - </div> - ); - } -} diff --git a/packages/website/ts/components/flash_messages/transaction_submitted.tsx b/packages/website/ts/components/flash_messages/transaction_submitted.tsx deleted file mode 100644 index b1d909baa..000000000 --- a/packages/website/ts/components/flash_messages/transaction_submitted.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; - -interface TransactionSubmittedProps { - etherScanLinkIfExists?: string; -} - -interface TransactionSubmittedState {} - -export class TransactionSubmitted extends React.Component<TransactionSubmittedProps, TransactionSubmittedState> { - public render(): React.ReactNode { - if (_.isUndefined(this.props.etherScanLinkIfExists)) { - return <div>Transaction submitted to the network</div>; - } else { - return ( - <div> - Transaction submitted to the network:{' '} - <a style={{ color: colors.white }} href={`${this.props.etherScanLinkIfExists}`} target="_blank"> - Verify on Etherscan - </a> - </div> - ); - } - } -} diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx deleted file mode 100644 index 3765a32ca..000000000 --- a/packages/website/ts/components/footer.tsx +++ /dev/null @@ -1,168 +0,0 @@ -import { Link as SmartLink } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import MediaQuery from 'react-responsive'; -import styled from 'styled-components'; - -import { Logo } from 'ts/components/logo'; -import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout'; -import { NewsletterForm } from 'ts/components/newsletter_form'; -import { WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; - -interface LinkInterface { - text: string; - url: string; - shouldOpenInNewTab?: boolean; -} - -interface LinkRows { - heading: string; - isOnMobile?: boolean; - links: LinkInterface[]; -} - -interface LinkListProps { - links: LinkInterface[]; -} - -const linkRows: LinkRows[] = [ - { - heading: 'Products', - isOnMobile: true, - links: [ - { url: WebsitePaths.Instant, text: '0x Instant' }, - { url: WebsitePaths.LaunchKit, text: '0x Launch Kit' }, - ], - }, - { - heading: 'Developers', - links: [ - { url: WebsitePaths.Docs, text: 'Documentation' }, - { url: constants.URL_GITHUB_ORG, text: 'GitHub', shouldOpenInNewTab: true }, - { url: constants.URL_PROTOCOL_SPECIFICATION, text: 'Protocol Spec', shouldOpenInNewTab: true }, - ], - }, - { - heading: 'About', - isOnMobile: true, - links: [ - { url: WebsitePaths.AboutMission, text: 'Mission' }, - { url: WebsitePaths.AboutTeam, text: 'Team' }, - { url: WebsitePaths.AboutJobs, text: 'Jobs' }, - { url: WebsitePaths.AboutPress, text: 'Press' }, - { url: WebsitePaths.Ecosystem, text: 'Grant Program' }, - ], - }, - { - heading: 'Community', - isOnMobile: true, - links: [ - { url: constants.URL_TWITTER, text: 'Twitter', shouldOpenInNewTab: true }, - { url: constants.URL_ZEROEX_CHAT, text: 'Discord Chat', shouldOpenInNewTab: true }, - { url: constants.URL_FACEBOOK, text: 'Facebook', shouldOpenInNewTab: true }, - { url: constants.URL_REDDIT, text: 'Reddit', shouldOpenInNewTab: true }, - ], - }, -]; - -export const Footer: React.StatelessComponent = () => ( - <FooterWrap> - <FlexWrap> - <FooterColumn width="35%"> - <Logo /> - <NewsletterForm /> - </FooterColumn> - - <FooterColumn width="55%"> - <WrapGrid isCentered={false} isWrapped={true}> - {_.map(linkRows, (row: LinkRows, index) => ( - <MediaQuery minWidth={row.isOnMobile ? 0 : 768} key={`fc-${index}`}> - <FooterSectionWrap> - <RowHeading>{row.heading}</RowHeading> - - <LinkList links={row.links} /> - </FooterSectionWrap> - </MediaQuery> - ))} - </WrapGrid> - </FooterColumn> - </FlexWrap> - </FooterWrap> -); - -const LinkList = (props: LinkListProps) => ( - <List> - {_.map(props.links, (link, index) => ( - <li key={`fl-${index}`}> - <Link to={link.url} shouldOpenInNewTab={link.shouldOpenInNewTab}> - {link.text} - </Link> - </li> - ))} - </List> -); - -const FooterWrap = styled.footer` - padding: 40px 30px 30px 30px; - margin-top: 30px; - background-color: ${props => props.theme.footerBg}; - color: ${props => props.theme.footerColor}; - - path { - fill: ${props => props.theme.footerColor}; - } - - @media (min-width: 768px) { - height: 350px; - } -`; - -const FooterColumn = styled(Column)` - @media (min-width: 768px) { - width: ${props => props.width}; - } - - @media (max-width: 768px) { - text-align: left; - } -`; - -const FooterSectionWrap = styled(FooterColumn)` - @media (max-width: 768px) { - width: 50%; - - & + & { - margin-top: 0; - margin-bottom: 30px; - } - } -`; - -const RowHeading = styled.h3` - color: inherit; - font-weight: 700; - font-size: 16px; - margin-bottom: 1.25em; - opacity: 0.75; -`; - -const List = styled.ul` - li + li { - margin-top: 8px; - } -`; - -const Link = styled(SmartLink)` - color: inherit; - opacity: 0.5; - display: block; - font-size: 16px; - line-height: 20px; - transition: opacity 0.25s; - text-decoration: none; - - &:hover { - opacity: 0.8; - } -`; diff --git a/packages/website/ts/components/generate_order/asset_picker.tsx b/packages/website/ts/components/generate_order/asset_picker.tsx deleted file mode 100644 index d3f11f962..000000000 --- a/packages/website/ts/components/generate_order/asset_picker.tsx +++ /dev/null @@ -1,284 +0,0 @@ -import * as _ from 'lodash'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import * as moment from 'moment'; -import * as React from 'react'; -import firstBy from 'thenby'; - -import { Blockchain } from 'ts/blockchain'; -import { NewTokenForm } from 'ts/components/generate_order/new_token_form'; -import { TrackTokenConfirmation } from 'ts/components/track_token_confirmation'; -import { TokenIcon } from 'ts/components/ui/token_icon'; -import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { DialogConfigs, Token, TokenByAddress, TokenVisibility } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { utils } from 'ts/utils/utils'; - -const TOKEN_ICON_DIMENSION = 100; -const TILE_DIMENSION = 146; -enum AssetViews { - AssetPicker = 'ASSET_PICKER', - NewTokenForm = 'NEW_TOKEN_FORM', - ConfirmTrackToken = 'CONFIRM_TRACK_TOKEN', -} - -interface AssetPickerProps { - userAddress: string; - blockchain: Blockchain; - dispatcher: Dispatcher; - networkId: number; - isOpen: boolean; - currentTokenAddress: string; - onTokenChosen: (tokenAddress: string) => void; - tokenByAddress: TokenByAddress; - tokenVisibility?: TokenVisibility; -} - -interface AssetPickerState { - assetView: AssetViews; - hoveredAddress: string | undefined; - chosenTrackTokenAddress: string; - isAddingTokenToTracked: boolean; -} - -export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerState> { - public static defaultProps: Partial<AssetPickerProps> = { - tokenVisibility: TokenVisibility.All, - }; - private readonly _dialogConfigsByAssetView: { [assetView: string]: DialogConfigs }; - constructor(props: AssetPickerProps) { - super(props); - this.state = { - assetView: AssetViews.AssetPicker, - hoveredAddress: undefined, - chosenTrackTokenAddress: undefined, - isAddingTokenToTracked: false, - }; - this._dialogConfigsByAssetView = { - [AssetViews.AssetPicker]: { - title: 'Select token', - isModal: false, - actions: [], - }, - [AssetViews.NewTokenForm]: { - title: 'Add an ERC20 token', - isModal: false, - actions: [], - }, - [AssetViews.ConfirmTrackToken]: { - title: 'Tracking confirmation', - isModal: true, - actions: [ - <FlatButton - key="noTracking" - label="No" - onClick={this._onTrackConfirmationRespondedAsync.bind(this, false)} - />, - <FlatButton - key="yesTrack" - label="Yes" - onClick={this._onTrackConfirmationRespondedAsync.bind(this, true)} - />, - ], - }, - }; - } - public render(): React.ReactNode { - const dialogConfigs: DialogConfigs = this._dialogConfigsByAssetView[this.state.assetView]; - return ( - <Dialog - title={dialogConfigs.title} - modal={dialogConfigs.isModal} - open={this.props.isOpen} - actions={dialogConfigs.actions} - autoScrollBodyContent={true} - onRequestClose={this._onCloseDialog.bind(this)} - > - {this.state.assetView === AssetViews.AssetPicker && this._renderAssetPicker()} - {this.state.assetView === AssetViews.NewTokenForm && ( - <NewTokenForm - blockchain={this.props.blockchain} - onNewTokenSubmitted={this._onNewTokenSubmitted.bind(this)} - tokenByAddress={this.props.tokenByAddress} - /> - )} - {this.state.assetView === AssetViews.ConfirmTrackToken && this._renderConfirmTrackToken()} - </Dialog> - ); - } - private _renderConfirmTrackToken(): React.ReactNode { - const token = this.props.tokenByAddress[this.state.chosenTrackTokenAddress]; - return ( - <TrackTokenConfirmation - tokens={[token]} - tokenByAddress={this.props.tokenByAddress} - networkId={this.props.networkId} - isAddingTokenToTracked={this.state.isAddingTokenToTracked} - /> - ); - } - private _renderAssetPicker(): React.ReactNode { - return ( - <div - className="flex flex-wrap" - style={{ - maxWidth: 1000, - maxHeight: 600, - marginBottom: 10, - }} - > - {this._renderGridTiles()} - </div> - ); - } - private _renderGridTiles(): React.ReactNode { - let isHovered; - let tileStyles; - const allTokens = _.values(this.props.tokenByAddress); - // filter tokens based on visibility specified in props, do not show ZRX or ETHER as tracked or untracked - const filteredTokens = - this.props.tokenVisibility === TokenVisibility.All - ? allTokens - : _.filter(allTokens, token => { - return ( - token.symbol !== constants.ZRX_TOKEN_SYMBOL && - token.symbol !== constants.ETHER_TOKEN_SYMBOL && - ((this.props.tokenVisibility === TokenVisibility.Tracked && utils.isTokenTracked(token)) || - (this.props.tokenVisibility === TokenVisibility.Untracked && - !utils.isTokenTracked(token))) - ); - }); - // if we are showing tracked tokens, sort by date added, otherwise sort by symbol - const sortKey = this.props.tokenVisibility === TokenVisibility.Tracked ? 'trackedTimestamp' : 'symbol'; - const sortedTokens = filteredTokens.sort(firstBy(sortKey)); - if (_.isEmpty(sortedTokens)) { - return <div className="mx-auto p4 h2">No tokens to remove.</div>; - } - const gridTiles = _.map(sortedTokens, token => { - const address = token.address; - isHovered = this.state.hoveredAddress === address; - tileStyles = { - cursor: 'pointer', - opacity: isHovered ? 0.6 : 1, - }; - return ( - <div - key={address} - style={{ - width: TILE_DIMENSION, - height: TILE_DIMENSION, - ...tileStyles, - }} - className="p2 flex sm-col-6 md-col-3 lg-col-3 flex-column items-center mx-auto" - onClick={this._onChooseToken.bind(this, address)} - onMouseEnter={this._onToggleHover.bind(this, address, true)} - onMouseLeave={this._onToggleHover.bind(this, address, false)} - > - <div className="p1"> - <TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} /> - </div> - <div className="center">{token.symbol}</div> - </div> - ); - }); - const otherTokenKey = 'otherToken'; - isHovered = this.state.hoveredAddress === otherTokenKey; - tileStyles = { - cursor: 'pointer', - opacity: isHovered ? 0.6 : 1, - }; - if (this.props.tokenVisibility !== TokenVisibility.Tracked) { - gridTiles.push( - <div - key={otherTokenKey} - style={{ - width: TILE_DIMENSION, - height: TILE_DIMENSION, - ...tileStyles, - }} - className="p2 flex sm-col-6 md-col-3 lg-col-3 flex-column items-center mx-auto" - onClick={this._onCustomAssetChosen.bind(this)} - onMouseEnter={this._onToggleHover.bind(this, otherTokenKey, true)} - onMouseLeave={this._onToggleHover.bind(this, otherTokenKey, false)} - > - <div className="p1 center"> - <i - style={{ fontSize: 105, paddingLeft: 1, paddingRight: 1 }} - className="zmdi zmdi-plus-circle" - /> - </div> - <div className="center">Other ERC20 Token</div> - </div>, - ); - } - return gridTiles; - } - private _onToggleHover(address: string, isHovered: boolean): void { - const hoveredAddress = isHovered ? address : undefined; - this.setState({ - hoveredAddress, - }); - } - private _onCloseDialog(): void { - this.setState({ - assetView: AssetViews.AssetPicker, - }); - this.props.onTokenChosen(this.props.currentTokenAddress); - } - private _onChooseToken(tokenAddress: string): void { - const token = this.props.tokenByAddress[tokenAddress]; - if (utils.isTokenTracked(token)) { - this.props.onTokenChosen(tokenAddress); - } else { - this.setState({ - assetView: AssetViews.ConfirmTrackToken, - chosenTrackTokenAddress: tokenAddress, - }); - } - } - private _onCustomAssetChosen(): void { - this.setState({ - assetView: AssetViews.NewTokenForm, - }); - } - private _onNewTokenSubmitted(newToken: Token): void { - trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newToken); - this.props.dispatcher.addTokenToTokenByAddress(newToken); - this.setState({ - assetView: AssetViews.AssetPicker, - }); - this.props.onTokenChosen(newToken.address); - } - private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean): Promise<void> { - const resetState: AssetPickerState = { - ...this.state, - isAddingTokenToTracked: false, - assetView: AssetViews.AssetPicker, - chosenTrackTokenAddress: undefined, - }; - if (!didUserAcceptTracking) { - this.setState(resetState); - this._onCloseDialog(); - return; - } - this.setState({ - isAddingTokenToTracked: true, - }); - const tokenAddress = this.state.chosenTrackTokenAddress; - const token = this.props.tokenByAddress[tokenAddress]; - if (_.isUndefined(tokenAddress)) { - this.setState(resetState); - return; - } - const newTokenEntry = { - ...token, - trackedTimestamp: moment().unix(), - }; - trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newTokenEntry); - - this.props.dispatcher.updateTokenByAddress([newTokenEntry]); - this.setState(resetState); - this.props.onTokenChosen(tokenAddress); - } -} diff --git a/packages/website/ts/components/generate_order/generate_order_form.tsx b/packages/website/ts/components/generate_order/generate_order_form.tsx deleted file mode 100644 index 0f70aa18f..000000000 --- a/packages/website/ts/components/generate_order/generate_order_form.tsx +++ /dev/null @@ -1,385 +0,0 @@ -import { assetDataUtils, generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils'; -import { colors } from '@0x/react-shared'; -import { Order as ZeroExOrder } from '@0x/types'; -import { BigNumber, logUtils } from '@0x/utils'; -import * as _ from 'lodash'; -import Dialog from 'material-ui/Dialog'; -import Divider from 'material-ui/Divider'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { ExpirationInput } from 'ts/components/inputs/expiration_input'; -import { HashInput } from 'ts/components/inputs/hash_input'; -import { IdenticonAddressInput } from 'ts/components/inputs/identicon_address_input'; -import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; -import { TokenInput } from 'ts/components/inputs/token_input'; -import { OrderJSON } from 'ts/components/order_json'; -import { Alert } from 'ts/components/ui/alert'; -import { HelpTooltip } from 'ts/components/ui/help_tooltip'; -import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; -import { SwapIcon } from 'ts/components/ui/swap_icon'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { portalOrderSchema } from 'ts/schemas/portal_order_schema'; -import { validator } from 'ts/schemas/validator'; -import { - AlertTypes, - BlockchainErrs, - HashData, - PortalOrder, - Side, - SideToAssetToken, - Token, - TokenByAddress, -} from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; -import { constants } from 'ts/utils/constants'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { utils } from 'ts/utils/utils'; - -enum SigningState { - Unsigned, - Signing, - Signed, -} - -interface GenerateOrderFormProps { - blockchain: Blockchain; - blockchainErr: BlockchainErrs; - blockchainIsLoaded: boolean; - dispatcher: Dispatcher; - hashData: HashData; - orderExpiryTimestamp: BigNumber; - networkId: number; - userAddress: string; - orderSignature: string; - orderTakerAddress: string; - orderSalt: BigNumber; - sideToAssetToken: SideToAssetToken; - tokenByAddress: TokenByAddress; - lastForceTokenStateRefetch: number; - isFullWidth?: boolean; - shouldHideHeader?: boolean; -} - -interface GenerateOrderFormState { - globalErrMsg: string; - shouldShowIncompleteErrs: boolean; - signingState: SigningState; -} - -export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> { - public static defaultProps: Partial<GenerateOrderFormProps> = { - isFullWidth: false, - shouldHideHeader: false, - }; - constructor(props: GenerateOrderFormProps) { - super(props); - this.state = { - globalErrMsg: '', - shouldShowIncompleteErrs: false, - signingState: SigningState.Unsigned, - }; - } - public componentDidMount(): void { - window.scrollTo(0, 0); - } - public render(): React.ReactNode { - const dispatcher = this.props.dispatcher; - const depositTokenAddress = this.props.sideToAssetToken[Side.Deposit].address; - const depositToken = this.props.tokenByAddress[depositTokenAddress]; - const receiveTokenAddress = this.props.sideToAssetToken[Side.Receive].address; - const receiveToken = this.props.tokenByAddress[receiveTokenAddress]; - const takerExplanation = - 'If a taker is specified, only they are<br> \ - allowed to fill this order. If no taker is<br> \ - specified, anyone is able to fill it.'; - const exchangeContractIfExists = this.props.blockchain.getExchangeContractAddressIfExists(); - const initialTakerAddress = - this.props.orderTakerAddress === constants.NULL_ADDRESS ? '' : this.props.orderTakerAddress; - const rootClassName = this.props.isFullWidth ? 'clearfix mb2' : 'clearfix mb2 lg-px4 md-px4 sm-px2'; - return ( - <div className={rootClassName}> - {!this.props.shouldHideHeader && ( - <div> - <h3>Generate an order</h3> - <Divider /> - </div> - )} - <div className="mx-auto" style={{ maxWidth: 580 }}> - <div className="pt3"> - <div className="mx-auto clearfix"> - <div className="lg-col md-col lg-col-5 md-col-5 sm-col sm-col-5 sm-pb2"> - <TokenInput - userAddress={this.props.userAddress} - blockchain={this.props.blockchain} - blockchainErr={this.props.blockchainErr} - dispatcher={this.props.dispatcher} - label="Selling" - side={Side.Deposit} - networkId={this.props.networkId} - assetToken={this.props.sideToAssetToken[Side.Deposit]} - updateChosenAssetToken={dispatcher.updateChosenAssetToken.bind(dispatcher)} - tokenByAddress={this.props.tokenByAddress} - /> - <TokenAmountInput - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - blockchain={this.props.blockchain} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - label="Sell amount" - token={depositToken} - amount={this.props.sideToAssetToken[Side.Deposit].amount} - onChange={this._onTokenAmountChange.bind(this, depositToken, Side.Deposit)} - shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} - shouldCheckBalance={true} - shouldCheckAllowance={true} - /> - </div> - <div className="lg-col md-col lg-col-2 md-col-2 sm-col sm-col-2 xs-hide"> - <div className="p1"> - <SwapIcon swapTokensFn={dispatcher.swapAssetTokenSymbols.bind(dispatcher)} /> - </div> - </div> - <div className="lg-col md-col lg-col-5 md-col-5 sm-col sm-col-5 sm-pb2"> - <TokenInput - userAddress={this.props.userAddress} - blockchain={this.props.blockchain} - blockchainErr={this.props.blockchainErr} - dispatcher={this.props.dispatcher} - label="Buying" - side={Side.Receive} - networkId={this.props.networkId} - assetToken={this.props.sideToAssetToken[Side.Receive]} - updateChosenAssetToken={dispatcher.updateChosenAssetToken.bind(dispatcher)} - tokenByAddress={this.props.tokenByAddress} - /> - <TokenAmountInput - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - blockchain={this.props.blockchain} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - label="Receive amount" - token={receiveToken} - amount={this.props.sideToAssetToken[Side.Receive].amount} - onChange={this._onTokenAmountChange.bind(this, receiveToken, Side.Receive)} - shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} - shouldCheckBalance={false} - shouldCheckAllowance={false} - /> - </div> - </div> - </div> - <div className="pt1 sm-pb2 lg-px4 md-px4"> - <div className="lg-px3 md-px3"> - <div style={{ fontSize: 12, color: colors.grey }}>Expiration</div> - <ExpirationInput - orderExpiryTimestamp={this.props.orderExpiryTimestamp} - updateOrderExpiry={dispatcher.updateOrderExpiry.bind(dispatcher)} - /> - </div> - </div> - <div className="pt1 flex mx-auto"> - <IdenticonAddressInput - label="Taker" - initialAddress={initialTakerAddress} - updateOrderAddress={this._updateOrderAddress.bind(this)} - /> - <div className="pt3"> - <div className="pl1"> - <HelpTooltip explanation={takerExplanation} /> - </div> - </div> - </div> - <div> - <HashInput - blockchain={this.props.blockchain} - blockchainIsLoaded={this.props.blockchainIsLoaded} - hashData={this.props.hashData} - label="Order Hash" - /> - </div> - <div className="pt2"> - <div className="center"> - <LifeCycleRaisedButton - labelReady="Sign hash" - labelLoading="Signing..." - labelComplete="Hash signed!" - onClickAsyncFn={this._onSignClickedAsync.bind(this)} - /> - </div> - {this.state.globalErrMsg !== '' && ( - <Alert type={AlertTypes.Error} message={this.state.globalErrMsg} /> - )} - </div> - </div> - <Dialog - title="Order JSON" - titleStyle={{ fontWeight: 100 }} - modal={false} - open={this.state.signingState === SigningState.Signed} - onRequestClose={this._onCloseOrderJSONDialog.bind(this)} - > - <OrderJSON - exchangeContractIfExists={exchangeContractIfExists} - orderExpiryTimestamp={this.props.orderExpiryTimestamp} - orderSignature={this.props.orderSignature} - orderTakerAddress={this.props.orderTakerAddress} - orderMakerAddress={this.props.userAddress} - orderSalt={this.props.orderSalt} - orderMakerFee={this.props.hashData.makerFee} - orderTakerFee={this.props.hashData.takerFee} - orderFeeRecipient={this.props.hashData.feeRecipientAddress} - sideToAssetToken={this.props.sideToAssetToken} - tokenByAddress={this.props.tokenByAddress} - /> - </Dialog> - </div> - ); - } - private _onTokenAmountChange(token: Token, side: Side, _isValid: boolean, amount?: BigNumber): void { - this.props.dispatcher.updateChosenAssetToken(side, { - address: token.address, - amount, - }); - } - private _onCloseOrderJSONDialog(): void { - // Upon closing the order JSON dialog, we update the orderSalt stored in the Redux store - // with a new value so that if a user signs the identical order again, the newly signed - // orderHash will not collide with the previously generated orderHash. - this.props.dispatcher.updateOrderSalt(generatePseudoRandomSalt()); - this.setState({ - signingState: SigningState.Unsigned, - }); - } - private async _onSignClickedAsync(): Promise<boolean> { - if (this.props.blockchainErr !== BlockchainErrs.NoError) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return false; - } - - // Check if all required inputs were supplied - const debitToken = this.props.sideToAssetToken[Side.Deposit]; - const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; - const [debitBalance, debitAllowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - debitToken.address, - ); - const receiveToken = this.props.sideToAssetToken[Side.Receive]; - const receiveAmount = receiveToken.amount; - if ( - !_.isUndefined(debitToken.amount) && - !_.isUndefined(receiveAmount) && - debitToken.amount.gt(0) && - receiveAmount.gt(0) && - this.props.userAddress !== '' && - debitBalance.gte(debitToken.amount) && - debitAllowance.gte(debitToken.amount) - ) { - const signedOrder = await this._signTransactionAsync(); - const doesSignedOrderExist = !_.isUndefined(signedOrder); - if (doesSignedOrderExist) { - analytics.trackOrderEvent('Sign Order Success', signedOrder); - this.setState({ - globalErrMsg: '', - shouldShowIncompleteErrs: false, - }); - } - return doesSignedOrderExist; - } else { - let globalErrMsg = 'You must fix the above errors in order to generate a valid order'; - if (this.props.userAddress === '') { - globalErrMsg = 'You must enable wallet communication'; - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - } - analytics.track('Sign Order Failure', { - makerTokenAmount: debitToken.amount.toString(), - makerToken: this.props.tokenByAddress[debitToken.address].symbol, - takerTokenAmount: receiveToken.amount.toString(), - takerToken: this.props.tokenByAddress[receiveToken.address].symbol, - }); - this.setState({ - globalErrMsg, - shouldShowIncompleteErrs: true, - }); - return false; - } - } - private async _signTransactionAsync(): Promise<PortalOrder | undefined> { - this.setState({ - signingState: SigningState.Signing, - }); - const exchangeAddress = this.props.blockchain.getExchangeContractAddressIfExists(); - if (_.isUndefined(exchangeAddress)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - this.setState({ - signingState: SigningState.Unsigned, - }); - return undefined; - } - const hashData = this.props.hashData; - - const makerAssetData = assetDataUtils.encodeERC20AssetData(hashData.depositTokenContractAddr); - const takerAssetData = assetDataUtils.encodeERC20AssetData(hashData.receiveTokenContractAddr); - const zeroExOrder: ZeroExOrder = { - senderAddress: constants.NULL_ADDRESS, - exchangeAddress, - expirationTimeSeconds: hashData.orderExpiryTimestamp, - feeRecipientAddress: hashData.feeRecipientAddress, - makerAddress: hashData.orderMakerAddress, - makerFee: hashData.makerFee, - makerAssetData, - makerAssetAmount: hashData.depositAmount, - salt: hashData.orderSalt, - takerAddress: hashData.orderTakerAddress, - takerFee: hashData.takerFee, - takerAssetData, - takerAssetAmount: hashData.receiveAmount, - }; - const orderHash = orderHashUtils.getOrderHashHex(zeroExOrder); - - let globalErrMsg = ''; - let order; - try { - const signature = await this.props.blockchain.signOrderHashAsync(orderHash); - order = utils.generateOrder( - exchangeAddress, - this.props.sideToAssetToken, - hashData.orderExpiryTimestamp, - this.props.orderTakerAddress, - this.props.userAddress, - hashData.makerFee, - hashData.takerFee, - hashData.feeRecipientAddress, - signature, - this.props.tokenByAddress, - hashData.orderSalt, - ); - const validationResult = validator.validate(order, portalOrderSchema); - if (validationResult.errors.length > 0) { - globalErrMsg = 'Order signing failed. Please refresh and try again'; - logUtils.log(`Unexpected error occured: Order validation failed: - ${validationResult.errors}`); - } - } catch (err) { - const errMsg = `${err}`; - if (utils.didUserDenyWeb3Request(errMsg)) { - globalErrMsg = 'User denied sign request'; - } else { - globalErrMsg = 'An unexpected error occured. Please try refreshing the page'; - logUtils.log(`Unexpected error occured: ${err}`); - logUtils.log(err.stack); - errorReporter.report(err); - } - } - this.setState({ - signingState: globalErrMsg === '' ? SigningState.Signed : SigningState.Unsigned, - globalErrMsg, - }); - return order; - } - private _updateOrderAddress(address?: string): void { - if (!_.isUndefined(address)) { - const normalizedAddress = _.isEmpty(address) ? constants.NULL_ADDRESS : address; - this.props.dispatcher.updateOrderTakerAddress(normalizedAddress); - } - } -} diff --git a/packages/website/ts/components/generate_order/new_token_form.tsx b/packages/website/ts/components/generate_order/new_token_form.tsx deleted file mode 100644 index ce684d177..000000000 --- a/packages/website/ts/components/generate_order/new_token_form.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as _ from 'lodash'; -import TextField from 'material-ui/TextField'; -import * as moment from 'moment'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { AddressInput } from 'ts/components/inputs/address_input'; -import { Alert } from 'ts/components/ui/alert'; -import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; -import { RequiredLabel } from 'ts/components/ui/required_label'; -import { AlertTypes, Token, TokenByAddress } from 'ts/types'; - -interface NewTokenFormProps { - blockchain: Blockchain; - tokenByAddress: TokenByAddress; - onNewTokenSubmitted: (token: Token) => void; -} - -interface NewTokenFormState { - globalErrMsg: string; - name: string; - nameErrText: string; - symbol: string; - symbolErrText: string; - address: string; - shouldShowAddressIncompleteErr: boolean; - decimals: string; - decimalsErrText: string; -} - -export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFormState> { - constructor(props: NewTokenFormProps) { - super(props); - this.state = { - address: '', - globalErrMsg: '', - name: '', - nameErrText: '', - shouldShowAddressIncompleteErr: false, - symbol: '', - symbolErrText: '', - decimals: '18', - decimalsErrText: '', - }; - } - public render(): React.ReactNode { - return ( - <div className="mx-auto pb2" style={{ width: 256 }}> - <div> - <TextField - floatingLabelFixed={true} - floatingLabelStyle={{ color: colors.grey }} - floatingLabelText={<RequiredLabel label="Name" />} - value={this.state.name} - errorText={this.state.nameErrText} - onChange={this._onTokenNameChanged.bind(this)} - /> - </div> - <div> - <TextField - floatingLabelFixed={true} - floatingLabelStyle={{ color: colors.grey }} - floatingLabelText={<RequiredLabel label="Symbol" />} - value={this.state.symbol} - errorText={this.state.symbolErrText} - onChange={this._onTokenSymbolChanged.bind(this)} - /> - </div> - <div> - <AddressInput - isRequired={true} - label="Contract address" - initialAddress="" - shouldShowIncompleteErrs={this.state.shouldShowAddressIncompleteErr} - updateAddress={this._onTokenAddressChanged.bind(this)} - /> - </div> - <div> - <TextField - floatingLabelFixed={true} - floatingLabelStyle={{ color: colors.grey }} - floatingLabelText={<RequiredLabel label="Decimals" />} - value={this.state.decimals} - errorText={this.state.decimalsErrText} - onChange={this._onTokenDecimalsChanged.bind(this)} - /> - </div> - <div className="pt2 mx-auto" style={{ width: 120 }}> - <LifeCycleRaisedButton - labelReady="Add" - labelLoading="Adding..." - labelComplete="Added!" - onClickAsyncFn={this._onAddNewTokenClickAsync.bind(this)} - /> - </div> - {this.state.globalErrMsg !== '' && <Alert type={AlertTypes.Error} message={this.state.globalErrMsg} />} - </div> - ); - } - private async _onAddNewTokenClickAsync(): Promise<void> { - // Trigger validation of name and symbol - this._onTokenNameChanged(undefined, this.state.name); - this._onTokenSymbolChanged(undefined, this.state.symbol); - this._onTokenDecimalsChanged(undefined, this.state.decimals); - - const isAddressIncomplete = this.state.address === ''; - let doesContractExist = false; - if (!isAddressIncomplete) { - doesContractExist = await this.props.blockchain.doesContractExistAtAddressAsync(this.state.address); - } - - let hasBalanceAllowanceErr = false; - if (doesContractExist) { - try { - await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync(this.state.address); - } catch (err) { - hasBalanceAllowanceErr = true; - } - } - - let globalErrMsg = ''; - if ( - this.state.nameErrText !== '' || - this.state.symbolErrText !== '' || - this.state.decimalsErrText !== '' || - isAddressIncomplete - ) { - globalErrMsg = 'Please fix the above issues'; - } else if (!doesContractExist) { - globalErrMsg = 'No contract found at supplied address'; - } else if (hasBalanceAllowanceErr) { - globalErrMsg = 'Unsuccessful call to `balanceOf` and/or `allowance` on supplied contract address'; - } else if (!isAddressIncomplete && !_.isUndefined(this.props.tokenByAddress[this.state.address])) { - globalErrMsg = 'A token already exists with this address'; - } - - if (globalErrMsg !== '') { - this.setState({ - globalErrMsg, - shouldShowAddressIncompleteErr: isAddressIncomplete, - }); - return; - } - - const newToken: Token = { - address: this.state.address, - decimals: _.parseInt(this.state.decimals), - iconUrl: undefined, - name: this.state.name, - symbol: this.state.symbol.toUpperCase(), - trackedTimestamp: moment().unix(), - isRegistered: false, - }; - this.props.onNewTokenSubmitted(newToken); - } - private _onTokenNameChanged(_event: any, name: string): void { - let nameErrText = ''; - const maxLength = 30; - const tokens = _.values(this.props.tokenByAddress); - const tokenWithNameIfExists = _.find(tokens, { name }); - const doesTokenWithNameExists = !_.isUndefined(tokenWithNameIfExists); - if (name === '') { - nameErrText = 'Name is required'; - } else if (!this._isValidName(name)) { - nameErrText = 'Name should only contain letters, digits and spaces'; - } else if (name.length > maxLength) { - nameErrText = `Max length is ${maxLength}`; - } else if (doesTokenWithNameExists) { - nameErrText = 'Token with this name already exists'; - } - - this.setState({ - name, - nameErrText, - }); - } - private _onTokenSymbolChanged(_event: any, symbol: string): void { - let symbolErrText = ''; - const maxLength = 5; - const tokens = _.values(this.props.tokenByAddress); - const doesTokenWithSymbolExists = !_.isUndefined(_.find(tokens, { symbol })); - if (symbol === '') { - symbolErrText = 'Symbol is required'; - } else if (!this._isAlphanumeric(symbol)) { - symbolErrText = 'Can only include alphanumeric characters'; - } else if (symbol.length > maxLength) { - symbolErrText = `Max length is ${maxLength}`; - } else if (doesTokenWithSymbolExists) { - symbolErrText = 'Token with symbol already exists'; - } - - this.setState({ - symbol, - symbolErrText, - }); - } - private _onTokenDecimalsChanged(_event: any, decimals: string): void { - let decimalsErrText = ''; - const maxLength = 2; - if (decimals === '') { - decimalsErrText = 'Decimals is required'; - } else if (!this._isInteger(decimals)) { - decimalsErrText = 'Must be an integer'; - } else if (decimals.length > maxLength) { - decimalsErrText = `Max length is ${maxLength}`; - } - - this.setState({ - decimals, - decimalsErrText, - }); - } - private _onTokenAddressChanged(address?: string): void { - if (!_.isUndefined(address)) { - this.setState({ - address, - }); - } - } - private _isValidName(input: string): boolean { - return /^[a-z0-9 ]+$/i.test(input); - } - private _isInteger(input: string): boolean { - return /^[0-9]+$/i.test(input); - } - private _isAlphanumeric(input: string): boolean { - return /^[a-zA-Z0-9]+$/i.test(input); - } -} diff --git a/packages/website/ts/components/hamburger.tsx b/packages/website/ts/components/hamburger.tsx deleted file mode 100644 index 34d4ccc46..000000000 --- a/packages/website/ts/components/hamburger.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -interface Props { - isOpen: boolean; - onClick?: () => void; -} - -export const Hamburger: React.FunctionComponent<Props> = (props: Props) => { - return ( - <StyledHamburger isOpen={props.isOpen} onClick={props.onClick}> - <span /> - <span /> - <span /> - </StyledHamburger> - ); -}; - -const StyledHamburger = styled.button<Props>` - background: none; - border: 0; - width: 22px; - height: 16px; - position: relative; - z-index: 25; - padding: 0; - outline: none; - user-select: none; - - @media (min-width: 800px) { - display: none; - } - - span { - display: block; - background-color: ${props => props.theme.textColor}; - width: 100%; - height: 2px; - margin-bottom: 5px; - transform-origin: 4px 0px; - transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1), - background-color 0.5s cubic-bezier(0.77, 0.2, 0.05, 1), opacity 0.55s ease; - - &:first-child { - //transform-origin: 0% 0%; - } - - &:last-child { - //transform-origin: 0% 100%; - } - - ${props => - props.isOpen && - ` - opacity: 1; - transform: rotate(45deg) translate(0, 1px); - - &:nth-child(2) { - opacity: 0; - transform: rotate(0deg) scale(0.2, 0.2); - } - - &:last-child { - transform: rotate(-45deg) translate(1px, -4px); - } - `} - } -`; diff --git a/packages/website/ts/components/header.tsx b/packages/website/ts/components/header.tsx deleted file mode 100644 index 088f41048..000000000 --- a/packages/website/ts/components/header.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import { Link } from '@0x/react-shared'; -import _ from 'lodash'; -import * as React from 'react'; -import MediaQuery from 'react-responsive'; -import styled, { css, withTheme } from 'styled-components'; - -import Headroom from 'react-headroom'; - -import { Button } from 'ts/components/button'; -import { DropdownDevelopers } from 'ts/components/dropdowns/dropdown_developers'; -import { DropdownProducts } from 'ts/components/dropdowns/dropdown_products'; -import { Hamburger } from 'ts/components/hamburger'; -import { Logo } from 'ts/components/logo'; -import { MobileNav } from 'ts/components/mobileNav'; -import { FlexWrap } from 'ts/components/newLayout'; -import { ThemeValuesInterface } from 'ts/components/siteWrap'; -import { WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; - -interface HeaderProps { - location?: Location; - isNavToggled?: boolean; - toggleMobileNav?: () => void; - theme: ThemeValuesInterface; -} - -interface NavItemProps { - url?: string; - id?: string; - text?: string; - dropdownWidth?: number; - dropdownComponent?: React.FunctionComponent<any>; - shouldOpenInNewTab?: boolean; -} - -interface DropdownWrapInterface { - width?: number; -} - -const navItems: NavItemProps[] = [ - { - id: 'why', - url: WebsitePaths.Why, - text: 'Why 0x', - }, - { - id: 'products', - text: 'Products', - dropdownComponent: DropdownProducts, - dropdownWidth: 280, - }, - { - id: 'developers', - text: 'Developers', - dropdownComponent: DropdownDevelopers, - dropdownWidth: 480, - }, - { - id: 'about', - url: WebsitePaths.AboutMission, - text: 'About', - }, - { - id: 'blog', - url: constants.URL_BLOG, - shouldOpenInNewTab: true, - text: 'Blog', - }, -]; - -class HeaderBase extends React.Component<HeaderProps> { - public onUnpin = () => { - if (this.props.isNavToggled) { - this.props.toggleMobileNav(); - } - }; - - public render(): React.ReactNode { - const { isNavToggled, toggleMobileNav, theme } = this.props; - - return ( - <Headroom onUnpin={this.onUnpin} downTolerance={4} upTolerance={10}> - <StyledHeader isNavToggled={isNavToggled}> - <HeaderWrap> - <Link to={WebsitePaths.Home}> - <Logo /> - </Link> - - <NavLinks> - {_.map(navItems, (link, index) => ( - <NavItem key={`navlink-${index}`} link={link} /> - ))} - </NavLinks> - - <MediaQuery minWidth={990}> - <TradeButton bgColor={theme.headerButtonBg} color="#ffffff" href="/portal"> - Trade on 0x - </TradeButton> - </MediaQuery> - - <Hamburger isOpen={isNavToggled} onClick={toggleMobileNav} /> - <MobileNav isToggled={isNavToggled} toggleMobileNav={toggleMobileNav} /> - </HeaderWrap> - </StyledHeader> - </Headroom> - ); - } -} - -export const Header = withTheme(HeaderBase); - -const NavItem = (props: { link: NavItemProps; key: string }) => { - const { link } = props; - const Subnav = link.dropdownComponent; - const linkElement = _.isUndefined(link.url) ? ( - <StyledAnchor href="#">{link.text}</StyledAnchor> - ) : ( - <StyledNavLink to={link.url} shouldOpenInNewTab={link.shouldOpenInNewTab}> - {link.text} - </StyledNavLink> - ); - return ( - <LinkWrap> - {linkElement} - - {link.dropdownComponent && ( - <DropdownWrap width={link.dropdownWidth}> - <Subnav /> - </DropdownWrap> - )} - </LinkWrap> - ); -}; - -const StyledHeader = styled.header<HeaderProps>` - padding: 30px; - background-color: ${props => props.theme.bgColor}; -`; - -const LinkWrap = styled.li` - position: relative; - - a { - display: block; - } - - @media (min-width: 800px) { - &:hover > div { - display: block; - visibility: visible; - opacity: 1; - transform: translate3d(0, 0, 0); - transition: opacity 0.35s, transform 0.35s, visibility 0s; - } - } -`; - -const linkStyles = css` - color: ${props => props.theme.textColor}; - opacity: 0.5; - transition: opacity 0.35s; - padding: 15px 0; - margin: 0 30px; - - &:hover { - opacity: 1; - } -`; - -const StyledNavLink = styled(Link).attrs({ - activeStyle: { opacity: 1 }, -})` - ${linkStyles}; -`; - -const StyledAnchor = styled.a` - ${linkStyles}; - cursor: default; -`; - -const HeaderWrap = styled(FlexWrap)` - justify-content: space-between; - align-items: center; - - @media (max-width: 800px) { - padding-top: 0; - display: flex; - padding-bottom: 0; - } -`; - -const NavLinks = styled.ul` - display: flex; - align-items: center; - justify-content: space-between; - - @media (max-width: 800px) { - display: none; - } -`; - -const DropdownWrap = styled.div<DropdownWrapInterface>` - width: ${props => props.width || 280}px; - padding: 15px 0; - border: 1px solid transparent; - border-color: ${props => props.theme.dropdownBorderColor}; - background-color: ${props => props.theme.dropdownBg}; - color: ${props => props.theme.dropdownColor}; - position: absolute; - top: 100%; - left: calc(50% - ${props => (props.width || 280) / 2}px); - visibility: hidden; - opacity: 0; - transform: translate3d(0, -10px, 0); - transition: opacity 0.35s, transform 0.35s, visibility 0s 0.35s; - z-index: 20; - - &:after, - &:before { - bottom: 100%; - left: 50%; - border: solid transparent; - content: ' '; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - } - &:after { - border-color: rgba(255, 255, 255, 0); - border-bottom-color: ${props => props.theme.dropdownBg}; - border-width: 10px; - margin-left: -10px; - } - &:before { - border-color: rgba(255, 0, 0, 0); - border-bottom-color: ${props => props.theme.dropdownBorderColor}; - border-width: 11px; - margin-left: -11px; - } - - @media (max-width: 768px) { - display: none; - } -`; - -const TradeButton = styled(Button)` - padding: 14px 22px !important; -`; diff --git a/packages/website/ts/components/hero.tsx b/packages/website/ts/components/hero.tsx deleted file mode 100644 index c326e0292..000000000 --- a/packages/website/ts/components/hero.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -import { addFadeInAnimation } from 'ts/constants/animations'; - -interface Props { - title: string; - maxWidth?: string; - maxWidthHeading?: string; - isLargeTitle?: boolean; - isFullWidth?: boolean; - isCenteredMobile?: boolean; - description: string; - figure?: React.ReactNode; - actions?: React.ReactNode; -} - -const Section = styled.section` - padding: 120px 0; - - @media (max-width: 768px) { - padding: 60px 0; - } -`; - -interface WrapProps { - isCentered?: boolean; - isFullWidth?: boolean; - isCenteredMobile?: boolean; -} -const Wrap = styled.div<WrapProps>` - width: calc(100% - 60px); - margin: 0 auto; - - @media (min-width: 768px) { - max-width: ${props => (!props.isFullWidth ? '895px' : '1136px')}; - flex-direction: row-reverse; - display: flex; - align-items: center; - text-align: ${props => props.isCentered && 'center'}; - justify-content: ${props => (props.isCentered ? 'center' : 'space-between')}; - } - - @media (max-width: 768px) { - text-align: ${props => (props.isCenteredMobile ? `center` : 'left')}; - } -`; - -interface TitleProps { - isLarge?: any; - maxWidth?: string; -} -const Title = styled.h1<TitleProps>` - font-size: ${props => (props.isLarge ? '80px' : '50px')}; - font-weight: 300; - line-height: 1.1; - margin-left: auto; - margin-right: auto; - margin-bottom: 30px; - max-width: ${props => props.maxWidth}; - ${addFadeInAnimation('0.5s')} - - @media (max-width: 1024px) { - font-size: 60px; - } - - @media (max-width: 768px) { - font-size: 46px; - } -`; - -const Description = styled.p` - font-size: 22px; - line-height: 31px; - font-weight: 300; - padding: 0; - margin-bottom: 50px; - color: ${props => props.theme.introTextColor}; - ${addFadeInAnimation('0.5s', '0.15s')} @media (max-width: 1024px) { - margin-bottom: 30px; - } -`; - -const Content = styled.div<{ width: string }>` - width: 100%; - - @media (min-width: 768px) { - max-width: ${props => props.width}; - } -`; - -const ButtonWrap = styled.div` - display: inline-flex; - align-items: center; - - * + * { - margin-left: 12px; - } - - > *:nth-child(1) { - ${addFadeInAnimation('0.6s', '0.3s')}; - } - > *:nth-child(2) { - ${addFadeInAnimation('0.6s', '0.4s')}; - } - - @media (max-width: 500px) { - flex-direction: column; - justify-content: center; - - * { - padding-left: 20px; - padding-right: 20px; - } - - * + * { - margin-left: 0; - margin-top: 12px; - } - } -`; - -export const Hero: React.StatelessComponent<Props> = (props: Props) => ( - <Section> - <Wrap isCentered={!props.figure} isFullWidth={props.isFullWidth} isCenteredMobile={props.isCenteredMobile}> - {props.figure && <Content width="400px">{props.figure}</Content>} - - <Content width={props.maxWidth ? props.maxWidth : props.figure ? '546px' : '678px'}> - <Title isLarge={props.isLargeTitle} maxWidth={props.maxWidthHeading}> - {props.title} - </Title> - - <Description>{props.description}</Description> - - {props.actions && <ButtonWrap>{props.actions}</ButtonWrap>} - </Content> - </Wrap> - </Section> -); - -Hero.defaultProps = { - isCenteredMobile: true, -}; diff --git a/packages/website/ts/components/heroAnimation.tsx b/packages/website/ts/components/heroAnimation.tsx deleted file mode 100644 index 42956fb6a..000000000 --- a/packages/website/ts/components/heroAnimation.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import * as React from 'react'; -import styled, { keyframes } from 'styled-components'; - -export const HeroAnimation = () => ( - <Image width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg"> - <mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="404" height="404"> - <circle cx="202" cy="202" r="200" fill="#00AE99" stroke="#00AE99" stroke-width="3" /> - </mask> - <g mask="url(#mask0)"> - <circle cx="202" cy="202" r="200" stroke="#00AE99" strokeWidth="3" /> - <TopCircle - vector-effect="non-scaling-stroke" - cx="201.667" - cy="68.6667" - r="66.6667" - stroke="#00AE99" - strokeWidth="3" - /> - <LeftCircle - vector-effect="non-scaling-stroke" - cx="68.6667" - cy="202.667" - r="66.6667" - stroke="#00AE99" - strokeWidth="3" - /> - <Logo - vector-effect="non-scaling-stroke" - d="M168.17 260.29L167.271 259.089L165.46 260.444L167.413 261.585L168.17 260.29ZM197.32 269.2L197.219 270.696L197.226 270.697L197.32 269.2ZM237.414 258.856L238.22 260.12L238.225 260.117L237.414 258.856ZM252.653 245.439L253.801 246.405L254.55 245.515L253.874 244.568L252.653 245.439ZM241.096 229.872L242.285 228.958L242.281 228.952L242.276 228.946L241.096 229.872ZM237.72 225.571L238.901 224.645L237.582 222.965L236.449 224.775L237.72 225.571ZM219.719 241.445L218.672 242.519L219.418 243.246L220.36 242.801L219.719 241.445ZM208.264 230.282L209.311 229.207L208.392 228.312L207.365 229.081L208.264 230.282ZM143.827 169.549L145.02 168.64L143.647 166.838L142.524 168.806L143.827 169.549ZM135.133 198.43L133.637 198.329L133.636 198.337L135.133 198.43ZM145.464 238.577L144.201 239.388L145.464 238.577ZM158.862 253.837L157.895 254.984L158.786 255.736L159.735 255.057L158.862 253.837ZM174.409 242.264L175.324 243.453L175.33 243.448L175.336 243.443L174.409 242.264ZM178.705 238.885L179.632 240.064L181.287 238.761L179.516 237.623L178.705 238.885ZM162.851 220.757L161.78 219.707L161.049 220.452L161.495 221.397L162.851 220.757ZM174.102 209.286L175.173 210.337L176.082 209.41L175.295 208.377L174.102 209.286ZM235.163 145.072L236.036 146.292L237.92 144.945L235.92 143.777L235.163 145.072ZM206.014 136.162L205.91 137.658L205.913 137.658L206.014 136.162ZM165.817 146.506L166.629 147.767L166.632 147.765L165.817 146.506ZM150.578 159.922L149.43 158.956L148.681 159.846L149.357 160.793L150.578 159.922ZM162.135 175.489L160.946 176.403L160.951 176.409L160.955 176.415L162.135 175.489ZM165.511 179.791L164.331 180.717L165.634 182.378L166.773 180.6L165.511 179.791ZM183.614 163.916L184.655 162.836L183.913 162.122L182.98 162.557L183.614 163.916ZM194.354 174.26L193.313 175.341L194.212 176.206L195.226 175.48L194.354 174.26ZM259.608 235.505L258.411 236.409L259.789 238.233L260.914 236.243L259.608 235.505ZM268.2 206.931L269.696 207.033L269.697 207.024L268.2 206.931ZM257.87 166.784L259.135 165.979L259.132 165.974L257.87 166.784ZM244.471 151.524L245.439 150.378L244.547 149.625L243.598 150.304L244.471 151.524ZM228.924 163.097L228.009 161.909L228.003 161.913L227.997 161.918L228.924 163.097ZM224.629 166.477L223.701 165.298L222.034 166.609L223.826 167.744L224.629 166.477ZM240.584 184.604L239.228 185.244L239.235 185.259L239.242 185.274L240.584 184.604ZM240.687 184.809L241.767 185.849L242.502 185.086L242.029 184.139L240.687 184.809ZM229.845 196.075L228.764 195.035L227.877 195.957L228.648 196.979L229.845 196.075ZM167.413 261.585C176.201 266.718 186.346 269.964 197.219 270.696L197.421 267.703C187.019 267.002 177.321 263.898 168.926 258.994L167.413 261.585ZM197.226 270.697C212.283 271.639 226.405 267.659 238.22 260.12L236.607 257.591C225.307 264.8 211.813 268.604 197.413 267.703L197.226 270.697ZM238.225 260.117C244.08 256.348 249.307 251.742 253.801 246.405L251.506 244.473C247.204 249.583 242.203 253.989 236.602 257.594L238.225 260.117ZM253.874 244.568C250.283 239.533 246.385 234.295 242.285 228.958L239.906 230.786C243.989 236.1 247.864 241.309 251.432 246.31L253.874 244.568ZM242.276 228.946C241.713 228.229 241.151 227.512 240.588 226.795C240.026 226.078 239.463 225.362 238.901 224.645L236.54 226.497C237.103 227.213 237.665 227.93 238.228 228.647C238.791 229.364 239.353 230.081 239.916 230.798L242.276 228.946ZM236.449 224.775C232.311 231.384 226.193 236.725 219.078 240.089L220.36 242.801C227.974 239.201 234.538 233.481 238.992 226.367L236.449 224.775ZM220.766 240.371L209.311 229.207L207.217 231.356L218.672 242.519L220.766 240.371ZM207.365 229.081L167.271 259.089L169.069 261.49L209.163 231.483L207.365 229.081ZM142.524 168.806C137.505 177.601 134.368 187.549 133.637 198.329L136.63 198.532C137.33 188.214 140.33 178.703 145.13 170.293L142.524 168.806ZM133.636 198.337C132.696 213.409 136.668 227.654 144.201 239.388L146.726 237.767C139.531 226.56 135.73 212.947 136.63 198.524L133.636 198.337ZM144.201 239.388C147.965 245.25 152.565 250.484 157.895 254.984L159.83 252.691C154.727 248.383 150.327 243.376 146.726 237.767L144.201 239.388ZM159.735 255.057C164.764 251.461 169.994 247.558 175.324 243.453L173.494 241.076C168.187 245.164 162.985 249.045 157.99 252.617L159.735 255.057ZM175.336 243.443C176.768 242.317 178.2 241.19 179.632 240.064L177.777 237.706C176.345 238.832 174.913 239.959 173.481 241.086L175.336 243.443ZM179.516 237.623C172.904 233.374 167.568 227.241 164.208 220.117L161.495 221.397C165.09 229.021 170.8 235.588 177.894 240.147L179.516 237.623ZM163.922 221.807L175.173 210.337L173.031 208.236L161.78 219.707L163.922 221.807ZM175.295 208.377L145.02 168.64L142.634 170.458L172.909 210.196L175.295 208.377ZM235.92 143.777C227.132 138.643 216.987 135.398 206.114 134.665L205.913 137.658C216.315 138.359 226.012 141.463 234.407 146.367L235.92 143.777ZM206.118 134.665C191.055 133.618 176.824 137.599 165.003 145.246L166.632 147.765C177.926 140.459 191.515 136.657 205.91 137.658L206.118 134.665ZM165.006 145.244C159.151 149.013 153.924 153.619 149.43 158.956L151.725 160.888C156.027 155.779 161.028 151.372 166.629 147.767L165.006 145.244ZM149.357 160.793C152.948 165.828 156.846 171.066 160.946 176.403L163.325 174.575C159.242 169.261 155.367 164.052 151.799 159.051L149.357 160.793ZM160.955 176.415C161.518 177.132 162.08 177.849 162.643 178.566C163.205 179.283 163.768 180 164.331 180.717L166.691 178.865C166.128 178.148 165.566 177.431 165.003 176.714C164.441 175.997 163.878 175.28 163.315 174.563L160.955 176.415ZM166.773 180.6C171.021 173.973 177.044 168.635 184.248 165.276L182.98 162.557C175.251 166.161 168.796 171.885 164.248 178.981L166.773 180.6ZM182.574 164.997L193.313 175.341L195.394 173.18L184.655 162.836L182.574 164.997ZM195.226 175.48L236.036 146.292L234.291 143.852L193.481 173.04L195.226 175.48ZM260.914 236.243C265.827 227.556 268.964 217.713 269.696 207.033L266.703 206.828C266.003 217.042 263.004 226.453 258.303 234.767L260.914 236.243ZM269.697 207.024C270.638 191.949 266.663 177.81 259.135 165.979L256.604 167.589C263.804 178.904 267.603 192.417 266.703 206.837L269.697 207.024ZM259.132 165.974C255.368 160.111 250.769 154.878 245.439 150.378L243.503 152.67C248.606 156.978 253.007 161.986 256.607 167.594L259.132 165.974ZM243.598 150.304C238.57 153.901 233.339 157.803 228.009 161.909L229.84 164.285C235.147 160.197 240.349 156.316 245.344 152.744L243.598 150.304ZM227.997 161.918C227.281 162.481 226.565 163.045 225.849 163.608C225.133 164.171 224.417 164.734 223.701 165.298L225.556 167.656C226.272 167.092 226.988 166.529 227.704 165.966C228.42 165.402 229.136 164.839 229.852 164.276L227.997 161.918ZM223.826 167.744C230.535 171.992 235.869 178.121 239.228 185.244L241.941 183.964C238.345 176.339 232.632 169.769 225.431 165.209L223.826 167.744ZM239.242 185.274L239.345 185.479L242.029 184.139L241.926 183.934L239.242 185.274ZM239.606 183.769L228.764 195.035L230.926 197.115L241.767 185.849L239.606 183.769ZM228.648 196.979L258.411 236.409L260.806 234.601L231.042 195.171L228.648 196.979Z" - fill="#00AE99" - /> - <Rectangle - vector-effect="non-scaling-stroke" - d="M269 135V268.333H442V135H269Z" - stroke="#00AE99" - strokeWidth="3" - /> - <Square - vector-effect="non-scaling-stroke" - d="M339.64 269.64L270 339.281L343.913 413.194L413.554 343.554L339.64 269.64Z" - stroke="#00AE99" - strokeWidth="3" - /> - <Oblong - vector-effect="non-scaling-stroke" - d="M202.5 269C202.5 269 269 269 269 335.5C269 402 202.5 402 202.5 402H-6.5C-6.5 402 -77 402 -77 335.5C-77 269 -6.5 269 -6.5 269H202.5Z" - stroke="#00AE99" - strokeWidth="3" - /> - </g> - </Image> -); - -const moveUp = keyframes` - 0% { transform: translate3d(0, 0, 0) } - 45% { transform: translate3d(0, 0, 0) } - 55% { transform: translate3d(0, -7%, 0) } - 85% { transform: translate3d(0, -7%, 0) } - 100% { transform: translate3d(0, 0, 0) } -`; - -const moveLeft = keyframes` - 0% { transform: translate3d(0, 0, 0) } - 45% { transform: translate3d(0, 0, 0) } - 55% { transform: translate3d(-7%, 0, 0) } - 85% { transform: translate3d(-7%, 0, 0) } - 100% { transform: translate3d(0, 0, 0) } -`; - -const moveDiag = keyframes` - 0% { transform: translate3d(0, 0, 0) } - 45% { transform: translate3d(0, 0, 0) } - 55% { transform: translate3d(5%, 5%, 0) } - 85% { transform: translate3d(5%, 5%, 0) } - 100% { transform: translate3d(0, 0, 0) } -`; - -const moveRight = keyframes` - 0% { transform: translate3d(0, 0, 0) } - 45% { transform: translate3d(0, 0, 0) } - 55% { transform: translate3d(7%, 0, 0) } - 85% { transform: translate3d(7%, 0, 0) } - 100% { transform: translate3d(0, 0, 0) } -`; - -const spin = keyframes` - 0% { transform: rotate(0deg) } - 65% { transform: rotate(0deg) } - 85% { transform: rotate(90deg) } - 100% { transform: rotate(90deg) } -`; - -const moveIn = keyframes` - 0% { opacity: 0; transform: scale(1.7) rotate(-30deg) } - 100% { opacity: 1; transform: scale(1) rotate(0deg) } -`; - -const Image = styled.svg` - opacity: 0; - transform: scale(1.5) rotate(-30deg); - animation: ${moveIn} 2s forwards; -`; - -const TopCircle = styled.circle` - animation: ${moveUp} 4s -2.85s infinite; -`; -const LeftCircle = styled.circle` - animation: ${moveLeft} 4s -2.85s infinite; -`; -const Oblong = styled.path` - animation: ${moveLeft} 4s -2.85s infinite; -`; -const Square = styled.path` - animation: ${moveDiag} 4s -2.85s infinite; -`; -const Rectangle = styled.path` - animation: ${moveRight} 4s -2.85s infinite; -`; - -const Logo = styled.path` - animation: ${spin} 4s -2.8s infinite; - transform-origin: 202px 202.7px; -`; diff --git a/packages/website/ts/components/heroImage.tsx b/packages/website/ts/components/heroImage.tsx deleted file mode 100644 index af7c055ac..000000000 --- a/packages/website/ts/components/heroImage.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -interface Props { - image: React.ReactNode; -} - -export const LandingAnimation = (props: Props) => <Wrap>{props.image}</Wrap>; - -const Wrap = styled.figure` - display: inline-block; - - svg { - width: 100%; - height: auto; - } - - @media (min-width: 768px) { - width: 100%; - max-width: 400px; - } - - @media (max-width: 768px) { - width: 180px; - margin-bottom: 40px; - } -`; diff --git a/packages/website/ts/components/icon.tsx b/packages/website/ts/components/icon.tsx deleted file mode 100644 index 60e4d04ee..000000000 --- a/packages/website/ts/components/icon.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import * as React from 'react'; -import Loadable from 'react-loadable'; -import styled from 'styled-components'; - -import { Paragraph } from 'ts/components/text'; -import { getCSSPadding, PaddingInterface } from 'ts/constants/utilities'; - -interface IconProps extends PaddingInterface { - name?: string; - component?: React.ReactNode; - size?: 'small' | 'medium' | 'large' | 'hero' | number; -} - -export const Icon: React.FunctionComponent<IconProps> = (props: IconProps) => { - if (props.name && !props.component) { - const IconSVG = Loadable({ - loader: async () => import(/* webpackChunkName: "icon" */ `ts/icons/illustrations/${props.name}.svg`), - loading: () => <Paragraph>Loading</Paragraph>, - }); - - return ( - <StyledIcon {...props}> - <IconSVG /> - </StyledIcon> - ); - } - - if (props.component) { - return <StyledIcon {...props}>{props.component}</StyledIcon>; - } - - return null; -}; - -export const InlineIconWrap = styled.div<PaddingInterface>` - margin: ${props => getCSSPadding(props.margin)}; - display: flex; - align-items: center; - justify-content: center; - - > figure { - margin: 0 5px; - } -`; - -const _getSize = (size: string | number = 'small'): string => { - if (typeof size === 'string') { - return `var(--${size}Icon)`; - } - - return `${size}px`; -}; - -const StyledIcon = styled.figure<IconProps>` - width: ${props => _getSize(props.size)}; - height: ${props => _getSize(props.size)}; - margin: ${props => getCSSPadding(props.margin)}; - display: inline-block; - flex-shrink: 0; - - svg { - width: 100%; - height: 100%; - object-fit: cover; - } -`; diff --git a/packages/website/ts/components/image.tsx b/packages/website/ts/components/image.tsx deleted file mode 100644 index 0137cfc97..000000000 --- a/packages/website/ts/components/image.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -interface Props { - alt?: string; - src?: any; - srcset?: any; - isCentered?: boolean; -} - -const ImageClass: React.FunctionComponent<Props> = (props: Props) => { - return <img {...props} />; -}; - -export const Image = styled(ImageClass)<Props>` - margin: ${props => props.isCentered && `0 auto`}; -`; diff --git a/packages/website/ts/components/inputs/address_input.tsx b/packages/website/ts/components/inputs/address_input.tsx deleted file mode 100644 index 1a71f8081..000000000 --- a/packages/website/ts/components/inputs/address_input.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { addressUtils } from '@0x/utils'; -import * as _ from 'lodash'; -import TextField from 'material-ui/TextField'; -import * as React from 'react'; -import { RequiredLabel } from 'ts/components/ui/required_label'; - -interface AddressInputProps { - disabled?: boolean; - initialAddress: string; - isRequired?: boolean; - hintText?: string; - shouldHideLabel?: boolean; - label?: string; - shouldShowIncompleteErrs?: boolean; - updateAddress: (address?: string) => void; -} - -interface AddressInputState { - address: string; - errMsg: string; -} - -export class AddressInput extends React.Component<AddressInputProps, AddressInputState> { - constructor(props: AddressInputProps) { - super(props); - this.state = { - address: this.props.initialAddress, - errMsg: '', - }; - } - public componentWillReceiveProps(nextProps: AddressInputProps): void { - if (nextProps.shouldShowIncompleteErrs && this.props.isRequired && this.state.address === '') { - this.setState({ - errMsg: 'Address is required', - }); - } - } - public render(): React.ReactNode { - const label = this.props.isRequired ? <RequiredLabel label={this.props.label} /> : this.props.label; - const labelDisplay = this.props.shouldHideLabel ? 'hidden' : 'block'; - const hintText = this.props.hintText ? this.props.hintText : ''; - return ( - <div className="overflow-hidden"> - <TextField - id={`address-field-${this.props.label}`} - disabled={_.isUndefined(this.props.disabled) ? false : this.props.disabled} - fullWidth={true} - hintText={hintText} - floatingLabelFixed={true} - floatingLabelStyle={{ color: colors.grey, display: labelDisplay }} - floatingLabelText={label} - errorText={this.state.errMsg} - value={this.state.address} - onChange={this._onOrderTakerAddressUpdated.bind(this)} - /> - </div> - ); - } - private _onOrderTakerAddressUpdated(e: any): void { - const address = e.target.value.toLowerCase(); - const isValidAddress = addressUtils.isAddress(address) || address === ''; - const errMsg = isValidAddress ? '' : 'Invalid ethereum address'; - this.setState({ - address, - errMsg, - }); - const addressIfValid = isValidAddress ? address : undefined; - this.props.updateAddress(addressIfValid); - } -} diff --git a/packages/website/ts/components/inputs/allowance_state_toggle.tsx b/packages/website/ts/components/inputs/allowance_state_toggle.tsx deleted file mode 100644 index 3a78d32f3..000000000 --- a/packages/website/ts/components/inputs/allowance_state_toggle.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { BigNumber, logUtils } from '@0x/utils'; -import * as _ from 'lodash'; -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; -import { Blockchain } from 'ts/blockchain'; -import { AllowanceState, AllowanceStateView } from 'ts/components/ui/allowance_state_view'; -import { Container } from 'ts/components/ui/container'; -import { PointerDirection } from 'ts/components/ui/pointer'; -import { Text } from 'ts/components/ui/text'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { BalanceErrs, Token, TokenState } from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { utils } from 'ts/utils/utils'; - -export interface AllowanceStateToggleProps { - networkId: number; - blockchain: Blockchain; - dispatcher: Dispatcher; - token: Token; - tokenState: TokenState; - userAddress: string; - onErrorOccurred?: (errType: BalanceErrs) => void; - refetchTokenStateAsync: () => Promise<void>; - tooltipDirection?: PointerDirection; -} - -export interface AllowanceStateToggleState { - allowanceState: AllowanceState; - prevTokenState: TokenState; - loadingMessage?: string; -} - -const DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS = new BigNumber(2).pow(256).minus(1); - -export class AllowanceStateToggle extends React.Component<AllowanceStateToggleProps, AllowanceStateToggleState> { - public static defaultProps = { - onErrorOccurred: _.noop.bind(_), - tooltipDirection: PointerDirection.Right, - }; - private static _getAllowanceState(tokenState: TokenState): AllowanceState { - if (!tokenState.isLoaded) { - return AllowanceState.Loading; - } - if (tokenState.allowance.gt(0)) { - return AllowanceState.Unlocked; - } - return AllowanceState.Locked; - } - constructor(props: AllowanceStateToggleProps) { - super(props); - const tokenState = props.tokenState; - this.state = { - allowanceState: AllowanceStateToggle._getAllowanceState(tokenState), - prevTokenState: tokenState, - }; - } - - public render(): React.ReactNode { - const tooltipId = `tooltip-id-${this.props.token.symbol}`; - return ( - <Container cursor="pointer"> - <ReactTooltip id={tooltipId} effect="solid" offset={{ top: 3 }}> - {this._getTooltipContent()} - </ReactTooltip> - <div - data-tip={true} - data-for={tooltipId} - data-place={this.props.tooltipDirection} - onClick={this._onToggleAllowanceAsync.bind(this)} - > - <AllowanceStateView allowanceState={this.state.allowanceState} /> - </div> - </Container> - ); - } - public componentWillReceiveProps(nextProps: AllowanceStateToggleProps): void { - const nextTokenState = nextProps.tokenState; - const prevTokenState = this.state.prevTokenState; - if ( - !nextTokenState.allowance.eq(prevTokenState.allowance) || - nextTokenState.isLoaded !== prevTokenState.isLoaded - ) { - const tokenState = nextProps.tokenState; - this.setState({ - prevTokenState: tokenState, - allowanceState: AllowanceStateToggle._getAllowanceState(nextTokenState), - }); - } - } - private _getTooltipContent(): React.ReactNode { - const symbol = this.props.token.symbol; - switch (this.state.allowanceState) { - case AllowanceState.Loading: - return ( - <Text noWrap={true} fontColor={colors.white}> - {this.state.loadingMessage || 'Loading...'} - </Text> - ); - case AllowanceState.Locked: - return ( - <Text noWrap={true} fontColor={colors.white}> - Click to enable <b>{symbol}</b> for trading - </Text> - ); - case AllowanceState.Unlocked: - return ( - <Text noWrap={true} fontColor={colors.white}> - <b>{symbol}</b> is available for trading - </Text> - ); - default: - return null; - } - } - private async _onToggleAllowanceAsync(): Promise<void> { - // Close all tooltips - ReactTooltip.hide(); - if (this.props.userAddress === '') { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return; - } - - let newAllowanceAmountInBaseUnits = new BigNumber(0); - if (!this._isAllowanceSet()) { - newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS; - } - const isUnlockingToken = newAllowanceAmountInBaseUnits.gt(0); - this.setState({ - allowanceState: AllowanceState.Loading, - loadingMessage: `${isUnlockingToken ? 'Unlocking' : 'Locking'} ${this.props.token.symbol}`, - }); - const logData = { - tokenSymbol: this.props.token.symbol, - newAllowance: newAllowanceAmountInBaseUnits.toNumber(), - }; - try { - await this.props.blockchain.setProxyAllowanceAsync(this.props.token, newAllowanceAmountInBaseUnits); - analytics.track('Set Allowances Success', logData); - await this.props.refetchTokenStateAsync(); - } catch (err) { - analytics.track('Set Allowance Failure', logData); - this.setState({ - allowanceState: AllowanceStateToggle._getAllowanceState(this.state.prevTokenState), - }); - const errMsg = `${err}`; - if (utils.didUserDenyWeb3Request(errMsg)) { - return; - } - logUtils.log(`Unexpected error encountered: ${err}`); - logUtils.log(err.stack); - this.props.onErrorOccurred(BalanceErrs.AllowanceSettingFailed); - errorReporter.report(err); - } - } - private _isAllowanceSet(): boolean { - return !this.props.tokenState.allowance.eq(0); - } -} diff --git a/packages/website/ts/components/inputs/balance_bounded_input.tsx b/packages/website/ts/components/inputs/balance_bounded_input.tsx deleted file mode 100644 index 83f263842..000000000 --- a/packages/website/ts/components/inputs/balance_bounded_input.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import TextField from 'material-ui/TextField'; -import * as React from 'react'; -import { RequiredLabel } from 'ts/components/ui/required_label'; -import { ValidatedBigNumberCallback } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -interface BalanceBoundedInputProps { - label?: string; - balance: BigNumber; - amount?: BigNumber; - hintText?: string; - onChange: ValidatedBigNumberCallback; - onErrorMsgChange?: (errorMsg: React.ReactNode) => void; - shouldShowIncompleteErrs?: boolean; - shouldCheckBalance: boolean; - validate?: (amount: BigNumber) => React.ReactNode; - isDisabled?: boolean; - shouldShowErrs?: boolean; - shouldShowUnderline?: boolean; - inputStyle?: React.CSSProperties; - inputHintStyle?: React.CSSProperties; -} - -interface BalanceBoundedInputState { - errMsg: React.ReactNode; - amountString: string; -} - -export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProps, BalanceBoundedInputState> { - public static defaultProps: Partial<BalanceBoundedInputProps> = { - shouldShowIncompleteErrs: false, - isDisabled: false, - shouldShowErrs: true, - hintText: 'amount', - onErrorMsgChange: _.noop.bind(_), - shouldShowUnderline: true, - }; - constructor(props: BalanceBoundedInputProps) { - super(props); - const amountString = this.props.amount ? this.props.amount.toString() : ''; - this.state = { - errMsg: this._validate(amountString, props.balance), - amountString, - }; - } - public componentWillReceiveProps(nextProps: BalanceBoundedInputProps): void { - if (nextProps === this.props) { - return; - } - const isCurrentAmountNumeric = utils.isNumeric(this.state.amountString); - if (!_.isUndefined(nextProps.amount)) { - let shouldResetState = false; - if (!isCurrentAmountNumeric) { - shouldResetState = true; - } else { - const currentAmount = new BigNumber(this.state.amountString); - if (!currentAmount.eq(nextProps.amount) || !nextProps.balance.eq(this.props.balance)) { - shouldResetState = true; - } - } - if (shouldResetState) { - const amountString = nextProps.amount.toString(); - this._setAmountState(amountString, nextProps.balance); - } - } else if (isCurrentAmountNumeric) { - const amountString = ''; - this._setAmountState(amountString, nextProps.balance); - } - } - public render(): React.ReactNode { - let errorText; - if (this.props.shouldShowErrs) { - errorText = - this.props.shouldShowIncompleteErrs && this.state.amountString === '' - ? 'This field is required' - : this.state.errMsg; - } - let label: React.ReactNode | string = ''; - if (!_.isUndefined(this.props.label)) { - label = <RequiredLabel label={this.props.label} />; - } - return ( - <TextField - fullWidth={true} - floatingLabelText={label} - floatingLabelFixed={true} - floatingLabelStyle={{ color: colors.grey, width: 206 }} - errorText={errorText} - value={this.state.amountString} - hintText={<span style={{ textTransform: 'capitalize' }}>{this.props.hintText}</span>} - onChange={this._onValueChange.bind(this)} - underlineStyle={{ width: 'calc(100% + 50px)' }} - inputStyle={this.props.inputStyle} - hintStyle={this.props.inputHintStyle} - underlineShow={this.props.shouldShowUnderline} - disabled={this.props.isDisabled} - /> - ); - } - private _onValueChange(_event: any, amountString: string): void { - this._setAmountState(amountString, this.props.balance, () => { - const isValid = _.isUndefined(this._validate(amountString, this.props.balance)); - const isPositiveNumber = utils.isNumeric(amountString) && !_.includes(amountString, '-'); - if (isPositiveNumber) { - this.props.onChange(isValid, new BigNumber(amountString)); - } else { - this.props.onChange(isValid); - } - }); - } - private _validate(amountString: string, balance: BigNumber): React.ReactNode { - if (!utils.isNumeric(amountString)) { - return amountString !== '' ? 'Must be a number' : ''; - } - const amount = new BigNumber(amountString); - if (amount.eq(0)) { - return 'Cannot be zero'; - } - if (this.props.shouldCheckBalance && amount.gt(balance)) { - return <span>Insufficient balance.</span>; - } - const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount); - return errMsg; - } - private _setAmountState(amount: string, balance: BigNumber, callback: () => void = _.noop.bind(_)): void { - const errorMsg = this._validate(amount, balance); - this.props.onErrorMsgChange(errorMsg); - this.setState( - { - amountString: amount, - errMsg: errorMsg, - }, - callback, - ); - } -} diff --git a/packages/website/ts/components/inputs/eth_amount_input.tsx b/packages/website/ts/components/inputs/eth_amount_input.tsx deleted file mode 100644 index 6799e54bf..000000000 --- a/packages/website/ts/components/inputs/eth_amount_input.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input'; -import { ValidatedBigNumberCallback } from 'ts/types'; -import { constants } from 'ts/utils/constants'; - -interface EthAmountInputProps { - label?: string; - balance: BigNumber; - amount?: BigNumber; - hintText?: string; - onChange: ValidatedBigNumberCallback; - onErrorMsgChange?: (errorMsg: React.ReactNode) => void; - shouldShowIncompleteErrs: boolean; - shouldCheckBalance: boolean; - shouldShowErrs?: boolean; - shouldShowUnderline?: boolean; - style?: React.CSSProperties; - labelStyle?: React.CSSProperties; - inputHintStyle?: React.CSSProperties; -} - -interface EthAmountInputState {} - -export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmountInputState> { - public static defaultProps: Partial<EthAmountInputProps> = { - shouldShowErrs: true, - shouldShowUnderline: true, - }; - public render(): React.ReactNode { - const amount = this.props.amount - ? Web3Wrapper.toUnitAmount(this.props.amount, constants.DECIMAL_PLACES_ETH) - : undefined; - return ( - <div className="flex" style={this.props.style}> - <BalanceBoundedInput - label={this.props.label} - balance={this.props.balance} - amount={amount} - onChange={this._onChange.bind(this)} - onErrorMsgChange={this.props.onErrorMsgChange} - shouldCheckBalance={this.props.shouldCheckBalance} - shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs} - hintText={this.props.hintText} - shouldShowErrs={this.props.shouldShowErrs} - shouldShowUnderline={this.props.shouldShowUnderline} - inputStyle={this.props.style} - inputHintStyle={this.props.inputHintStyle} - /> - <div style={this._getLabelStyle()}>ETH</div> - </div> - ); - } - private _onChange(isValid: boolean, amount?: BigNumber): void { - const baseUnitAmountIfExists = _.isUndefined(amount) - ? undefined - : Web3Wrapper.toBaseUnitAmount(amount, constants.DECIMAL_PLACES_ETH); - this.props.onChange(isValid, baseUnitAmountIfExists); - } - private _getLabelStyle(): React.CSSProperties { - return this.props.labelStyle || { paddingTop: _.isUndefined(this.props.label) ? 15 : 40 }; - } -} diff --git a/packages/website/ts/components/inputs/expiration_input.tsx b/packages/website/ts/components/inputs/expiration_input.tsx deleted file mode 100644 index 3e43c1c07..000000000 --- a/packages/website/ts/components/inputs/expiration_input.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import DatePicker from 'material-ui/DatePicker'; -import TimePicker from 'material-ui/TimePicker'; -import * as moment from 'moment'; -import * as React from 'react'; -import { utils } from 'ts/utils/utils'; - -interface ExpirationInputProps { - orderExpiryTimestamp: BigNumber; - updateOrderExpiry: (unixTimestampSec: BigNumber) => void; -} - -interface ExpirationInputState { - dateMoment: moment.Moment; - timeMoment: moment.Moment; -} - -export class ExpirationInput extends React.Component<ExpirationInputProps, ExpirationInputState> { - private readonly _earliestPickableMoment: moment.Moment; - constructor(props: ExpirationInputProps) { - super(props); - // Set the earliest pickable date to today at 00:00, so users can only pick the current or later dates - this._earliestPickableMoment = moment().startOf('day'); - const expirationMoment = utils.convertToMomentFromUnixTimestamp(props.orderExpiryTimestamp); - const initialOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec(); - const didUserSetExpiry = !initialOrderExpiryTimestamp.eq(props.orderExpiryTimestamp); - this.state = { - dateMoment: didUserSetExpiry ? expirationMoment : undefined, - timeMoment: didUserSetExpiry ? expirationMoment : undefined, - }; - } - public render(): React.ReactNode { - const date = this.state.dateMoment ? this.state.dateMoment.toDate() : undefined; - const time = this.state.timeMoment ? this.state.timeMoment.toDate() : undefined; - return ( - <div className="clearfix"> - <div className="col col-6 overflow-hidden pr3 flex relative"> - <DatePicker - className="overflow-hidden" - hintText="Date" - mode="landscape" - autoOk={true} - value={date} - onChange={this._onDateChanged.bind(this)} - shouldDisableDate={this._shouldDisableDate.bind(this)} - /> - <div className="absolute" style={{ fontSize: 20, right: 40, top: 13, pointerEvents: 'none' }}> - <i className="zmdi zmdi-calendar" /> - </div> - </div> - <div className="col col-5 overflow-hidden flex relative"> - <TimePicker - className="overflow-hidden" - hintText="Time" - autoOk={true} - value={time} - onChange={this._onTimeChanged.bind(this)} - /> - <div className="absolute" style={{ fontSize: 20, right: 9, top: 13, pointerEvents: 'none' }}> - <i className="zmdi zmdi-time" /> - </div> - </div> - <div onClick={this._clearDates.bind(this)} className="col col-1 pt2" style={{ textAlign: 'right' }}> - <i style={{ fontSize: 16, cursor: 'pointer' }} className="zmdi zmdi-close" /> - </div> - </div> - ); - } - private _shouldDisableDate(date: Date): boolean { - return moment(date) - .startOf('day') - .isBefore(this._earliestPickableMoment); - } - private _clearDates(): void { - this.setState({ - dateMoment: undefined, - timeMoment: undefined, - }); - const defaultDateTime = utils.initialOrderExpiryUnixTimestampSec(); - this.props.updateOrderExpiry(defaultDateTime); - } - private _onDateChanged(_event: any, date: Date): void { - const dateMoment = moment(date); - this.setState({ - dateMoment, - }); - const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, this.state.timeMoment); - this.props.updateOrderExpiry(timestamp); - } - private _onTimeChanged(_event: any, time: Date): void { - const timeMoment = moment(time); - this.setState({ - timeMoment, - }); - const dateMoment = _.isUndefined(this.state.dateMoment) ? moment() : this.state.dateMoment; - const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, timeMoment); - this.props.updateOrderExpiry(timestamp); - } -} diff --git a/packages/website/ts/components/inputs/hash_input.tsx b/packages/website/ts/components/inputs/hash_input.tsx deleted file mode 100644 index 7688ffe21..000000000 --- a/packages/website/ts/components/inputs/hash_input.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { Styles } from '@0x/react-shared'; -import { Order } from '@0x/types'; -import * as _ from 'lodash'; -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; - -import { Blockchain } from 'ts/blockchain'; -import { FakeTextField } from 'ts/components/ui/fake_text_field'; -import { HashData } from 'ts/types'; -import { constants } from 'ts/utils/constants'; - -const styles: Styles = { - textField: { - overflow: 'hidden', - paddingTop: 8, - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - }, -}; - -interface HashInputProps { - blockchain: Blockchain; - blockchainIsLoaded: boolean; - hashData: HashData; - label: string; -} - -interface HashInputState {} - -export class HashInput extends React.Component<HashInputProps, HashInputState> { - public render(): React.ReactNode { - const msgHashHex = this.props.blockchainIsLoaded ? this._generateMessageHashHex() : ''; - return ( - <div> - <FakeTextField label={this.props.label}> - <div style={styles.textField} data-tip={true} data-for="hashTooltip"> - {msgHashHex} - </div> - </FakeTextField> - <ReactTooltip id="hashTooltip">{msgHashHex}</ReactTooltip> - </div> - ); - } - private _generateMessageHashHex(): string { - const exchangeAddress = this.props.blockchain.getExchangeContractAddressIfExists(); - const hashData = this.props.hashData; - const makerAssetData = assetDataUtils.encodeERC20AssetData(hashData.depositTokenContractAddr); - const takerAssetData = assetDataUtils.encodeERC20AssetData(hashData.receiveTokenContractAddr); - const order: Order = { - senderAddress: constants.NULL_ADDRESS, - exchangeAddress, - expirationTimeSeconds: hashData.orderExpiryTimestamp, - feeRecipientAddress: hashData.feeRecipientAddress, - makerAddress: _.isEmpty(hashData.orderMakerAddress) ? constants.NULL_ADDRESS : hashData.orderMakerAddress, - makerFee: hashData.makerFee, - makerAssetData, - makerAssetAmount: hashData.depositAmount, - salt: hashData.orderSalt, - takerAddress: hashData.orderTakerAddress, - takerFee: hashData.takerFee, - takerAssetData, - takerAssetAmount: hashData.receiveAmount, - }; - const orderHash = orderHashUtils.getOrderHashHex(order); - return orderHash; - } -} diff --git a/packages/website/ts/components/inputs/identicon_address_input.tsx b/packages/website/ts/components/inputs/identicon_address_input.tsx deleted file mode 100644 index 6ba7584a7..000000000 --- a/packages/website/ts/components/inputs/identicon_address_input.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as React from 'react'; -import { AddressInput } from 'ts/components/inputs/address_input'; -import { Identicon } from 'ts/components/ui/identicon'; -import { InputLabel } from 'ts/components/ui/input_label'; -import { RequiredLabel } from 'ts/components/ui/required_label'; - -interface IdenticonAddressInputProps { - initialAddress: string; - isRequired?: boolean; - label: string; - updateOrderAddress: (address?: string) => void; -} - -interface IdenticonAddressInputState { - address: string; -} - -export class IdenticonAddressInput extends React.Component<IdenticonAddressInputProps, IdenticonAddressInputState> { - constructor(props: IdenticonAddressInputProps) { - super(props); - this.state = { - address: props.initialAddress, - }; - } - public render(): React.ReactNode { - const label = this.props.isRequired ? <RequiredLabel label={this.props.label} /> : this.props.label; - return ( - <div className="relative" style={{ width: '100%' }}> - <InputLabel text={label} /> - <div className="flex"> - <div className="col col-1 pb1 pr1" style={{ paddingTop: 13 }}> - <Identicon address={this.state.address} diameter={26} /> - </div> - <div className="col col-11 pb1 pl1" style={{ height: 65 }}> - <AddressInput - hintText="e.g 0x75bE4F78AA3699B3A348c84bDB2a96c3Db..." - shouldHideLabel={true} - initialAddress={this.props.initialAddress} - updateAddress={this._updateAddress.bind(this)} - /> - </div> - </div> - </div> - ); - } - private _updateAddress(address?: string): void { - this.setState({ - address, - }); - this.props.updateOrderAddress(address); - } -} diff --git a/packages/website/ts/components/inputs/token_amount_input.tsx b/packages/website/ts/components/inputs/token_amount_input.tsx deleted file mode 100644 index fded3a9dd..000000000 --- a/packages/website/ts/components/inputs/token_amount_input.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { colors, Link } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input'; -import { Token, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; - -interface TokenAmountInputProps { - userAddress: string; - networkId: number; - blockchain: Blockchain; - token: Token; - label?: string; - amount?: BigNumber; - hintText?: string; - shouldShowIncompleteErrs: boolean; - shouldCheckBalance: boolean; - shouldCheckAllowance: boolean; - onChange: ValidatedBigNumberCallback; - onErrorMsgChange?: (errorMsg: React.ReactNode) => void; - lastForceTokenStateRefetch: number; - shouldShowErrs?: boolean; - shouldShowUnderline?: boolean; - style?: React.CSSProperties; - labelStyle?: React.CSSProperties; - inputHintStyle?: React.CSSProperties; -} - -interface TokenAmountInputState { - balance: BigNumber; - allowance: BigNumber; - isBalanceAndAllowanceLoaded: boolean; -} - -const HEIGHT_WITH_LABEL = 84; -const HEIGHT_WITHOUT_LABEL = 62; - -export class TokenAmountInput extends React.Component<TokenAmountInputProps, TokenAmountInputState> { - public static defaultProps: Partial<TokenAmountInputProps> = { - shouldShowErrs: true, - shouldShowUnderline: true, - }; - private _isUnmounted: boolean; - constructor(props: TokenAmountInputProps) { - super(props); - this._isUnmounted = false; - const defaultAmount = new BigNumber(0); - this.state = { - balance: defaultAmount, - allowance: defaultAmount, - isBalanceAndAllowanceLoaded: false, - }; - } - public componentWillMount(): void { - // tslint:disable-next-line:no-floating-promises - this._fetchBalanceAndAllowanceAsync(this.props.token.address, this.props.userAddress); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - } - public componentWillReceiveProps(nextProps: TokenAmountInputProps): void { - if ( - nextProps.userAddress !== this.props.userAddress || - nextProps.networkId !== this.props.networkId || - nextProps.token.address !== this.props.token.address || - nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch - ) { - // tslint:disable-next-line:no-floating-promises - this._fetchBalanceAndAllowanceAsync(nextProps.token.address, nextProps.userAddress); - } - } - public render(): React.ReactNode { - const amount = this.props.amount - ? Web3Wrapper.toUnitAmount(this.props.amount, this.props.token.decimals) - : undefined; - return ( - <div className="flex overflow-hidden" style={this._getStyle()}> - <BalanceBoundedInput - label={this.props.label} - amount={amount} - balance={Web3Wrapper.toUnitAmount(this.state.balance, this.props.token.decimals)} - onChange={this._onChange.bind(this)} - onErrorMsgChange={this.props.onErrorMsgChange} - validate={this._validate.bind(this)} - shouldCheckBalance={this.props.shouldCheckBalance} - shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs} - isDisabled={!this.state.isBalanceAndAllowanceLoaded} - hintText={this.props.hintText} - shouldShowErrs={this.props.shouldShowErrs} - shouldShowUnderline={this.props.shouldShowUnderline} - inputStyle={this.props.style} - inputHintStyle={this.props.inputHintStyle} - /> - <div style={this._getLabelStyle()}>{this.props.token.symbol}</div> - </div> - ); - } - private _onChange(isValid: boolean, amount?: BigNumber): void { - let baseUnitAmount; - if (!_.isUndefined(amount)) { - baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amount, this.props.token.decimals); - } - this.props.onChange(isValid, baseUnitAmount); - } - private _validate(amount: BigNumber): React.ReactNode { - if (this.props.shouldCheckAllowance && amount.gt(this.state.allowance)) { - return ( - <span> - Insufficient allowance.{' '} - <Link - to={`${WebsitePaths.Portal}/account`} - textDecoration="underline" - fontColor={colors.darkestGrey} - > - Set allowance - </Link> - </span> - ); - } else { - return undefined; - } - } - private async _fetchBalanceAndAllowanceAsync(tokenAddress: string, userAddress: string): Promise<void> { - this.setState({ - isBalanceAndAllowanceLoaded: false, - }); - const userAddressIfExists = _.isEmpty(userAddress) ? undefined : userAddress; - const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - tokenAddress, - ); - if (!this._isUnmounted) { - this.setState({ - balance, - allowance, - isBalanceAndAllowanceLoaded: true, - }); - } - } - private _getStyle(): React.CSSProperties { - const hasLabel = !_.isUndefined(this.props.label); - return !_.isUndefined(this.props.style) - ? this.props.style - : { height: hasLabel ? HEIGHT_WITH_LABEL : HEIGHT_WITHOUT_LABEL }; - } - private _getLabelStyle(): React.CSSProperties { - const hasLabel = !_.isUndefined(this.props.label); - return this.props.labelStyle || { paddingTop: hasLabel ? 39 : 14 }; - } -} diff --git a/packages/website/ts/components/inputs/token_input.tsx b/packages/website/ts/components/inputs/token_input.tsx deleted file mode 100644 index c3c2d8b37..000000000 --- a/packages/website/ts/components/inputs/token_input.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { colors } from '@0x/react-shared'; -import Paper from 'material-ui/Paper'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { AssetPicker } from 'ts/components/generate_order/asset_picker'; -import { InputLabel } from 'ts/components/ui/input_label'; -import { TokenIcon } from 'ts/components/ui/token_icon'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { AssetToken, BlockchainErrs, Side, Token, TokenByAddress } from 'ts/types'; - -const TOKEN_ICON_DIMENSION = 80; - -interface TokenInputProps { - blockchain: Blockchain; - blockchainErr: BlockchainErrs; - dispatcher: Dispatcher; - label: string; - side: Side; - networkId: number; - assetToken: AssetToken; - updateChosenAssetToken: (side: Side, token: AssetToken) => void; - tokenByAddress: TokenByAddress; - userAddress: string; -} - -interface TokenInputState { - isHoveringIcon: boolean; - isPickerOpen: boolean; - trackCandidateTokenIfExists?: Token; -} - -export class TokenInput extends React.Component<TokenInputProps, TokenInputState> { - constructor(props: TokenInputProps) { - super(props); - this.state = { - isHoveringIcon: false, - isPickerOpen: false, - }; - } - public render(): React.ReactNode { - const token = this.props.tokenByAddress[this.props.assetToken.address]; - const iconStyles = { - cursor: 'pointer', - opacity: this.state.isHoveringIcon ? 0.5 : 1, - }; - return ( - <div className="relative"> - <div className="pb1"> - <InputLabel text={this.props.label} /> - </div> - <Paper - zDepth={1} - style={{ cursor: 'pointer' }} - onMouseEnter={this._onToggleHover.bind(this, true)} - onMouseLeave={this._onToggleHover.bind(this, false)} - onClick={this._onAssetClicked.bind(this)} - > - <div className="mx-auto pt2" style={{ width: TOKEN_ICON_DIMENSION, ...iconStyles }}> - <TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} /> - </div> - <div className="py1 center" style={{ color: colors.grey }}> - {token.name} - </div> - </Paper> - <AssetPicker - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this.props.blockchain} - dispatcher={this.props.dispatcher} - isOpen={this.state.isPickerOpen} - currentTokenAddress={this.props.assetToken.address} - onTokenChosen={this._onTokenChosen.bind(this)} - tokenByAddress={this.props.tokenByAddress} - /> - </div> - ); - } - private _onTokenChosen(tokenAddress: string): void { - const assetToken: AssetToken = { - address: tokenAddress, - amount: this.props.assetToken.amount, - }; - this.props.updateChosenAssetToken(this.props.side, assetToken); - this.setState({ - isPickerOpen: false, - }); - } - private _onToggleHover(isHoveringIcon: boolean): void { - this.setState({ - isHoveringIcon, - }); - } - private _onAssetClicked(): void { - if (this.props.blockchainErr !== BlockchainErrs.NoError) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return; - } - - this.setState({ - isPickerOpen: true, - }); - } -} diff --git a/packages/website/ts/components/link.tsx b/packages/website/ts/components/link.tsx deleted file mode 100644 index a66985acc..000000000 --- a/packages/website/ts/components/link.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { Link as SmartLink } from '@0x/react-shared'; -import * as React from 'react'; -import styled from 'styled-components'; - -interface LinkInterface { - color?: string; - children?: React.ReactNode | string; - isNoArrow?: boolean; - hasIcon?: boolean | string; - isBlock?: boolean; - isCentered?: boolean; - href?: string; - theme?: { - textColor: string; - }; - shouldOpenInNewTab?: boolean; - target?: string; -} - -export const Link = (props: LinkInterface) => { - const { children, isNoArrow, href } = props; - - return ( - <StyledLink to={href} {...props}> - {children} - {!isNoArrow && ( - <svg width="25" height="25" fill="none" xmlns="http://www.w3.org/2000/svg"> - <path - d="M8.484 5.246l.023 1.411 8.147.053L4.817 18.547l.996.996L17.65 7.706l.052 8.146 1.411.024-.068-10.561-10.561-.069z" - fill="currentColor" - /> - </svg> - )} - </StyledLink> - ); -}; - -// Added this, & + & doesnt really work since we switch with element types... -export const LinkWrap = styled.div` - a + a, - a + button, - button + a { - margin-left: 20px; - } -`; - -const StyledLink = styled(SmartLink)<LinkInterface>` - display: ${props => !props.isBlock && 'inline-flex'}; - color: ${props => props.color || props.theme.linkColor}; - text-align: center; - font-size: 18px; - text-decoration: none; - align-items: center; - - @media (max-width: 768px) { - } - - svg { - margin-left: 3px; - } -`; diff --git a/packages/website/ts/components/logo.tsx b/packages/website/ts/components/logo.tsx deleted file mode 100644 index f89be0711..000000000 --- a/packages/website/ts/components/logo.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -import { ThemeInterface } from 'ts/components/siteWrap'; -import LogoIcon from 'ts/icons/logo-with-type.svg'; - -interface LogoInterface { - theme?: ThemeInterface; -} - -// Note let's refactor this -// is it absolutely necessary to have a stateless component -// to pass props down into the styled icon? -const StyledLogo = styled.div` - text-align: left; - position: relative; - z-index: 25; - - @media (max-width: 800px) { - svg { - width: 60px; - } - } -`; - -const Icon = styled(LogoIcon)<LogoInterface>` - flex-shrink: 0; - - path { - fill: ${props => props.theme.textColor}; - } -`; - -export const Logo: React.StatelessComponent<LogoInterface> = (props: LogoInterface) => ( - <StyledLogo> - <Icon {...props} /> - </StyledLogo> -); diff --git a/packages/website/ts/components/meta_tags.tsx b/packages/website/ts/components/meta_tags.tsx deleted file mode 100644 index f6c43d23f..000000000 --- a/packages/website/ts/components/meta_tags.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import * as React from 'react'; -import { Helmet } from 'react-helmet'; - -export interface MetaTagsProps { - title: string; - description: string; - imgSrc?: string; -} - -export const MetaTags: React.StatelessComponent<MetaTagsProps> = ({ title, description, imgSrc }) => ( - <Helmet> - <title>{title}</title> - <meta name="description" content={description} /> - <meta property="og:title" content={title} /> - <meta property="og:description" content={description} /> - <meta property="og:type" content="website" /> - <meta property="og:image" content={imgSrc} /> - <meta name="twitter:site" content="@0xproject" /> - <meta name="twitter:image" content={imgSrc} /> - </Helmet> -); - -MetaTags.defaultProps = { - imgSrc: '/images/og_image.png', -}; diff --git a/packages/website/ts/components/mobileNav.tsx b/packages/website/ts/components/mobileNav.tsx deleted file mode 100644 index 1aa826755..000000000 --- a/packages/website/ts/components/mobileNav.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import * as React from 'react'; -import MediaQuery from 'react-responsive'; -import styled from 'styled-components'; - -import { Link } from 'react-router-dom'; - -import { WrapGrid, WrapProps } from 'ts/components/newLayout'; -import { WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; - -interface Props { - isToggled: boolean; - toggleMobileNav: () => void; -} - -export class MobileNav extends React.PureComponent<Props> { - public render(): React.ReactNode { - const { isToggled, toggleMobileNav } = this.props; - - return ( - <MediaQuery maxWidth={800}> - <Wrap isToggled={isToggled}> - <Section> - <h4>Products</h4> - - <ul> - <li> - <Link to={WebsitePaths.Instant}>0x Instant</Link> - </li> - <li> - <Link to={WebsitePaths.LaunchKit}>0x Launch Kit</Link> - </li> - </ul> - </Section> - - <Section isDark={true}> - <Grid as="ul" isFullWidth={true} isWrapped={true}> - <li> - <Link to={WebsitePaths.Why}>Why 0x</Link> - </li> - <li> - <Link to={WebsitePaths.AboutMission}>About</Link> - </li> - <li> - <a href={constants.URL_BLOG} target="_blank"> - Blog - </a> - </li> - </Grid> - </Section> - - {isToggled && <Overlay onClick={toggleMobileNav} />} - </Wrap> - </MediaQuery> - ); - } -} - -const Wrap = styled.nav<{ isToggled: boolean }>` - width: 100%; - height: 357px; - background-color: ${props => props.theme.mobileNavBgUpper}; - color: ${props => props.theme.mobileNavColor}; - transition: ${props => (props.isToggled ? 'visibility 0s, transform 0.5s' : 'visibility 0s 0.5s, transform 0.5s')}; - transform: translate3d(0, ${props => (props.isToggled ? 0 : '-100%')}, 0); - visibility: ${props => !props.isToggled && 'hidden'}; - position: fixed; - display: flex; - flex-direction: column; - justify-content: flex-end; - z-index: 20; - top: 0; - left: 0; - font-size: 20px; - - a { - padding: 15px 0; - display: block; - color: inherit; - } - - h4 { - font-size: 14px; - opacity: 0.5; - } -`; - -const Overlay = styled.div` - position: absolute; - width: 100vw; - height: 100vh; - top: 100%; - background: transparent; - cursor: pointer; -`; - -interface SectionProps { - isDark?: boolean; -} -const Section = styled.div<SectionProps>` - width: 100%; - padding: 15px 30px; - background-color: ${props => (props.isDark ? props.theme.mobileNavBgLower : 'transparent')}; -`; - -const Grid = styled(WrapGrid)<WrapProps>` - justify-content: flex-start; - - li { - width: 50%; - flex-shrink: 0; - } -`; diff --git a/packages/website/ts/components/modals/input.tsx b/packages/website/ts/components/modals/input.tsx deleted file mode 100644 index c72e53aa0..000000000 --- a/packages/website/ts/components/modals/input.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -export enum InputWidth { - Half, - Full, -} - -interface InputProps { - name: string; - width?: InputWidth; - label: string; - type?: string; - errors?: ErrorProps; - isErrors?: boolean; - required?: boolean; -} - -interface ErrorProps { - [key: string]: string; -} - -export const Input = React.forwardRef((props: InputProps, ref?: React.Ref<HTMLInputElement>) => { - const { name, label, type, errors } = props; - const id = `input-${name}`; - const componentType = type === 'textarea' ? 'textarea' : 'input'; - const isErrors = errors.hasOwnProperty(name) && errors[name] !== null; - const errorMessage = isErrors ? errors[name] : null; - - return ( - <InputWrapper {...props}> - <Label htmlFor={id}>{label}</Label> - <StyledInput as={componentType} ref={ref} id={id} isErrors={isErrors} {...props} /> - {isErrors && <Error>{errorMessage}</Error>} - </InputWrapper> - ); -}); - -Input.defaultProps = { - width: InputWidth.Full, - errors: {}, -}; - -const StyledInput = styled.input` - appearance: none; - background-color: #fff; - border: 1px solid #d5d5d5; - color: #000; - font-size: 1.294117647rem; - padding: 16px 15px 14px; - outline: none; - width: 100%; - min-height: ${props => props.type === 'textarea' && `120px`}; - - background-color: ${(props: InputProps) => props.isErrors && `#FDEDED`}; - border-color: ${(props: InputProps) => props.isErrors && `#FD0000`}; - - &::placeholder { - color: #c3c3c3; - } -`; - -const InputWrapper = styled.div<InputProps>` - position: relative; - flex-grow: ${props => props.width === InputWidth.Full && 1}; - width: ${props => props.width === InputWidth.Half && `calc(50% - 15px)`}; - - @media (max-width: 768px) { - width: 100%; - margin-bottom: 30px; - } -`; - -const Label = styled.label` - color: #000; - font-size: 1.111111111rem; - line-height: 1.4em; - margin-bottom: 10px; - display: inline-block; -`; - -const Error = styled.span` - color: #fd0000; - font-size: 0.833333333rem; - line-height: 1em; - display: inline-block; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - transform: translateY(24px); -`; diff --git a/packages/website/ts/components/modals/modal_contact.tsx b/packages/website/ts/components/modals/modal_contact.tsx deleted file mode 100644 index 62c1062a3..000000000 --- a/packages/website/ts/components/modals/modal_contact.tsx +++ /dev/null @@ -1,390 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import styled from 'styled-components'; - -import { colors } from 'ts/style/colors'; - -import { DialogContent, DialogOverlay } from '@reach/dialog'; -import '@reach/dialog/styles.css'; - -import { Button } from 'ts/components/button'; -import { Icon } from 'ts/components/icon'; -import { Input, InputWidth } from 'ts/components/modals/input'; -import { Heading, Paragraph } from 'ts/components/text'; -import { GlobalStyle } from 'ts/constants/globalStyle'; -import { utils } from 'ts/utils/utils'; - -export enum ModalContactType { - General = 'GENERAL', - MarketMaker = 'MARKET_MAKER', -} - -interface Props { - theme?: GlobalStyle; - isOpen?: boolean; - onDismiss?: () => void; - modalContactType: ModalContactType; -} - -interface FormProps { - isSuccessful?: boolean; - isSubmitting?: boolean; -} - -interface ErrorResponseProps { - param: string; - location: string; - msg: string; -} - -interface ErrorResponse { - errors: ErrorResponseProps[]; -} - -interface ErrorProps { - [key: string]: string; -} - -export class ModalContact extends React.Component<Props> { - public static defaultProps = { - modalContactType: ModalContactType.General, - }; - public state = { - isSubmitting: false, - isSuccessful: false, - errors: {}, - }; - // shared fields - public nameRef: React.RefObject<HTMLInputElement> = React.createRef(); - public emailRef: React.RefObject<HTMLInputElement> = React.createRef(); - public companyProjectRef: React.RefObject<HTMLInputElement> = React.createRef(); - public commentsRef: React.RefObject<HTMLInputElement> = React.createRef(); - // general lead fields - public linkRef: React.RefObject<HTMLInputElement> = React.createRef(); - // market maker lead fields - public countryRef: React.RefObject<HTMLInputElement> = React.createRef(); - public fundSizeRef: React.RefObject<HTMLInputElement> = React.createRef(); - public constructor(props: Props) { - super(props); - } - public render(): React.ReactNode { - const { isOpen, onDismiss } = this.props; - const { isSuccessful, errors } = this.state; - return ( - <> - <DialogOverlay - style={{ background: 'rgba(0, 0, 0, 0.75)', zIndex: 30 }} - isOpen={isOpen} - onDismiss={onDismiss} - > - <StyledDialogContent> - <Form onSubmit={this._onSubmitAsync.bind(this)} isSuccessful={isSuccessful}> - <Heading color={colors.textDarkPrimary} size={34} asElement="h2"> - Contact the 0x Core Team - </Heading> - {this._renderFormContent(errors)} - <ButtonRow> - <Button - color="#5C5C5C" - isNoBorder={true} - isTransparent={true} - type="button" - onClick={this.props.onDismiss} - > - Back - </Button> - <Button>Submit</Button> - </ButtonRow> - </Form> - <Confirmation isSuccessful={isSuccessful}> - <Icon name="rocketship" size="large" margin={[0, 0, 'default', 0]} /> - <Heading color={colors.textDarkPrimary} size={34} asElement="h2"> - Thanks for contacting us. - </Heading> - <Paragraph isMuted={true} color={colors.textDarkPrimary}> - We'll get back to you soon. If you need quick support in the meantime, reach out to the - 0x team on Discord. - </Paragraph> - <Button onClick={this.props.onDismiss}>Done</Button> - </Confirmation> - </StyledDialogContent> - </DialogOverlay> - </> - ); - } - public _renderFormContent(errors: ErrorProps): React.ReactNode { - switch (this.props.modalContactType) { - case ModalContactType.MarketMaker: - return this._renderMarketMakerFormContent(errors); - case ModalContactType.General: - default: - return this._renderGeneralFormContent(errors); - } - } - private _renderMarketMakerFormContent(errors: ErrorProps): React.ReactNode { - return ( - <> - <Paragraph isMuted={true} color={colors.textDarkPrimary}> - If you’re considering market making on 0x, we’re happy to answer your questions. Fill out the form - so we can connect you with the right person to help you get started. - </Paragraph> - <InputRow> - <Input - name="name" - label="Your name" - type="text" - width={InputWidth.Half} - ref={this.nameRef} - required={true} - errors={errors} - /> - <Input - name="email" - label="Your email" - type="email" - ref={this.emailRef} - required={true} - errors={errors} - width={InputWidth.Half} - /> - </InputRow> - <InputRow> - <Input - name="country" - label="Country of Location" - type="text" - ref={this.countryRef} - required={true} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="fundSize" - label="Fund Size" - type="text" - ref={this.fundSizeRef} - required={true} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="companyOrProject" - label="Name of your project / company" - type="text" - ref={this.companyProjectRef} - required={false} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="comments" - label="What is prompting you to reach out?" - type="textarea" - ref={this.commentsRef} - required={false} - errors={errors} - /> - </InputRow> - </> - ); - } - private _renderGeneralFormContent(errors: ErrorProps): React.ReactNode { - return ( - <> - <Paragraph isMuted={true} color={colors.textDarkPrimary}> - If you're considering building on 0x, we're happy to answer your questions. Fill out the form so we - can connect you with the right person to help you get started. - </Paragraph> - <InputRow> - <Input - name="name" - label="Your name" - type="text" - width={InputWidth.Half} - ref={this.nameRef} - required={true} - errors={errors} - /> - <Input - name="email" - label="Your email" - type="email" - ref={this.emailRef} - required={true} - errors={errors} - width={InputWidth.Half} - /> - </InputRow> - <InputRow> - <Input - name="companyOrProject" - label="Name of your project / company" - type="text" - ref={this.companyProjectRef} - required={true} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="link" - label="Do you have any documentation or a website?" - type="text" - ref={this.linkRef} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="comments" - label="Anything else?" - type="textarea" - ref={this.commentsRef} - errors={errors} - /> - </InputRow> - </> - ); - } - private async _onSubmitAsync(e: Event): Promise<void> { - e.preventDefault(); - - let jsonBody; - if (this.props.modalContactType === ModalContactType.MarketMaker) { - jsonBody = { - name: this.nameRef.current.value, - email: this.emailRef.current.value, - country: this.countryRef.current.value, - fundSize: this.fundSizeRef.current.value, - projectOrCompany: this.companyProjectRef.current.value, - comments: this.commentsRef.current.value, - }; - } else { - jsonBody = { - name: this.nameRef.current.value, - email: this.emailRef.current.value, - projectOrCompany: this.companyProjectRef.current.value, - link: this.linkRef.current.value, - comments: this.commentsRef.current.value, - }; - } - - this.setState({ ...this.state, errors: [], isSubmitting: true }); - - const endpoint = - this.props.modalContactType === ModalContactType.MarketMaker ? '/market_maker_leads' : '/leads'; - - try { - // Disabling no-unbound method b/c no reason for _.isEmpty to be bound - // tslint:disable:no-unbound-method - const response = await fetch(`${utils.getBackendBaseUrl()}${endpoint}`, { - method: 'post', - mode: 'cors', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json; charset=utf-8', - }, - body: JSON.stringify(_.omitBy(jsonBody, _.isEmpty)), - }); - - if (!response.ok) { - const errorResponse: ErrorResponse = await response.json(); - const errors = this._parseErrors(errorResponse.errors); - this.setState({ ...this.state, isSubmitting: false, errors }); - - throw new Error('Request failed'); - } - - this.setState({ ...this.state, isSuccessful: true }); - } catch (e) { - // Empty block - } - } - private _parseErrors(errors: ErrorResponseProps[]): ErrorProps { - const initialValue: {} = {}; - return _.reduce( - errors, - (hash: ErrorProps, error: ErrorResponseProps) => { - const { param, msg } = error; - const key = param; - hash[key] = msg; - - return hash; - }, - initialValue, - ); - } -} - -// Handle errors: {"errors":[{"location":"body","param":"name","msg":"Invalid value"},{"location":"body","param":"email","msg":"Invalid value"}]} - -const InputRow = styled.div` - width: 100%; - flex: 0 0 auto; - - @media (min-width: 768px) { - display: flex; - justify-content: space-between; - margin-bottom: 30px; - } -`; - -const ButtonRow = styled(InputRow)` - @media (max-width: 768px) { - display: flex; - flex-direction: column; - - button:nth-child(1) { - order: 2; - } - - button:nth-child(2) { - order: 1; - margin-bottom: 10px; - } - } -`; - -const StyledDialogContent = styled(DialogContent)` - position: relative; - max-width: 800px; - background-color: #f6f6f6 !important; - padding: 60px 60px !important; - - @media (max-width: 768px) { - width: calc(100vw - 40px) !important; - margin: 40px auto !important; - padding: 30px 30px !important; - } -`; - -const Form = styled.form<FormProps>` - position: relative; - transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out; - - opacity: ${props => props.isSuccessful && `0`}; - visibility: ${props => props.isSuccessful && `hidden`}; -`; - -const Confirmation = styled.div<FormProps>` - position: absolute; - top: 50%; - text-align: center; - width: 100%; - left: 0; - transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out; - transition-delay: 0.4s; - padding: 60px 60px; - transform: translateY(-50%); - opacity: ${props => (props.isSuccessful ? `1` : `0`)}; - visibility: ${props => (props.isSuccessful ? 'visible' : `hidden`)}; - - p { - max-width: 492px; - margin-left: auto; - margin-right: auto; - } -`; diff --git a/packages/website/ts/components/nested_sidebar_menu.tsx b/packages/website/ts/components/nested_sidebar_menu.tsx deleted file mode 100644 index 56df880f3..000000000 --- a/packages/website/ts/components/nested_sidebar_menu.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { ALink, colors, Link, utils as sharedUtils } from '@0x/react-shared'; -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { Button } from 'ts/components/ui/button'; -import { Text } from 'ts/components/ui/text'; -import { ScreenWidths } from 'ts/types'; - -export interface NestedSidebarMenuProps { - sectionNameToLinks: ObjectMap<ALink[]>; - sidebarHeader?: React.ReactNode; - shouldReformatMenuItemNames?: boolean; - screenWidth: ScreenWidths; -} - -export const NestedSidebarMenu = (props: NestedSidebarMenuProps) => { - const navigation = _.map(props.sectionNameToLinks, (links: ALink[], sectionName: string) => { - const finalSectionName = sharedUtils.convertCamelCaseToSpaces(sectionName); - const menuItems = _.map(links, (link, i) => { - const menuItemTitle = props.shouldReformatMenuItemNames - ? _.capitalize(sharedUtils.convertDashesToSpaces(link.title)) - : link.title; - const finalLink = { - ...link, - title: menuItemTitle, - }; - return <MenuItem key={`menu-item-${menuItemTitle}`} link={finalLink} screenWidth={props.screenWidth} />; - }); - // tslint:disable-next-line:no-unused-variable - return ( - <div key={`section-${sectionName}`} className="py1" style={{ color: colors.greyTheme }}> - <Text fontSize="14px" letterSpacing="0.5" className="py1 pl1"> - {finalSectionName.toUpperCase()} - </Text> - {menuItems} - </div> - ); - }); - return ( - <div> - {props.sidebarHeader} - <div>{navigation}</div> - </div> - ); -}; - -export interface MenuItemProps { - link: ALink; - screenWidth: ScreenWidths; -} - -export interface MenuItemState { - isActive: boolean; -} - -export class MenuItem extends React.Component<MenuItemProps, MenuItemState> { - constructor(props: MenuItemProps) { - super(props); - const isActive = window.location.hash.slice(1) === props.link.to; - this.state = { - isActive, - }; - } - public render(): React.ReactNode { - const isActive = this.state.isActive; - return ( - <Link - to={this.props.link.to} - shouldOpenInNewTab={this.props.link.shouldOpenInNewTab} - onActivityChanged={this._onActivityChanged.bind(this)} - > - <Button - borderRadius="4px" - padding="0.4em 0.375em" - width="100%" - backgroundColor={ - isActive - ? colors.lightLinkBlue - : this.props.screenWidth === ScreenWidths.Sm - ? 'white' - : colors.grey100 - } - fontSize="14px" - textAlign="left" - > - <Text - fontWeight={isActive ? 'bold' : 'normal'} - fontColor={isActive ? colors.white : colors.grey800} - > - {this.props.link.title} - </Text> - </Button> - </Link> - ); - } - private _onActivityChanged(isActive: boolean): void { - this.setState({ - isActive, - }); - } -} diff --git a/packages/website/ts/components/newLayout.tsx b/packages/website/ts/components/newLayout.tsx deleted file mode 100644 index 07691a02a..000000000 --- a/packages/website/ts/components/newLayout.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -export interface WrapProps { - bgColor?: string; - id?: string; - offsetTop?: string; - maxWidth?: string; - wrapWidth?: string; - isFullWidth?: boolean; - isTextCentered?: boolean; - isCentered?: boolean; - isWrapped?: boolean; -} - -export interface WrapGridProps { - isWrapped?: boolean; - isCentered?: boolean; -} - -export interface WrapStickyProps { - offsetTop?: string; -} - -export interface SectionProps extends WrapProps { - isPadded?: boolean; - isFullWidth?: boolean; - isFlex?: boolean; - padding?: string; - paddingMobile?: string; - flexBreakpoint?: string; - maxWidth?: string; - bgColor?: 'dark' | 'light' | string; - children: any; -} - -export interface FlexProps { - padding?: string; - isFlex?: boolean; - flexBreakpoint?: string; -} - -export interface ColumnProps { - padding?: string; - width?: string; - maxWidth?: string; -} - -export const Section: React.FunctionComponent<SectionProps> = (props: SectionProps) => { - return ( - <SectionBase {...props}> - <Wrap {...props}>{props.children}</Wrap> - </SectionBase> - ); -}; - -export const Column = styled.div<ColumnProps>` - width: ${props => props.width}; - max-width: ${props => props.maxWidth}; - padding: ${props => props.padding}; - - @media (max-width: 768px) { - width: 100%; - - & + & { - margin-top: 60px; - } - } -`; - -export const FlexWrap = styled.div<FlexProps>` - max-width: 1500px; - margin: 0 auto; - padding: ${props => props.padding}; - - @media (min-width: ${props => props.flexBreakpoint || '768px'}) { - display: ${props => props.isFlex && 'flex'}; - justify-content: ${props => props.isFlex && 'space-between'}; - } -`; - -export const WrapSticky = styled.div<WrapProps>` - position: sticky; - top: ${props => props.offsetTop || '60px'}; -`; - -const SectionBase = styled.section<SectionProps>` - width: ${props => !props.isFullWidth && 'calc(100% - 60px)'}; - max-width: 1500px; - margin: 0 auto; - padding: ${props => props.isPadded && '120px 0'}; - background-color: ${props => props.theme[`${props.bgColor}BgColor`] || props.bgColor}; - position: relative; - overflow: ${props => !props.isFullWidth && 'hidden'}; - - @media (max-width: 768px) { - padding: ${props => props.isPadded && (props.paddingMobile || '40px 0')}; - } -`; - -const Wrap = styled(FlexWrap)<WrapProps>` - width: ${props => props.wrapWidth || 'calc(100% - 60px)'}; - width: ${props => props.bgColor && 'calc(100% - 60px)'}; - max-width: ${props => !props.isFullWidth && (props.maxWidth || '895px')}; - text-align: ${props => props.isTextCentered && 'center'}; - margin: 0 auto; -`; - -export const WrapGrid = styled(Wrap)<WrapProps>` - display: flex; - flex-wrap: ${props => props.isWrapped && `wrap`}; - justify-content: ${props => (props.isCentered ? `center` : 'space-between')}; - - @media (max-width: 768px) { - width: 100%; - } -`; - -Section.defaultProps = { - isPadded: true, -}; - -FlexWrap.defaultProps = { - isFlex: true, -}; - -WrapGrid.defaultProps = { - isCentered: true, - isFullWidth: true, -}; - -Wrap.defaultProps = { - isFlex: false, -}; diff --git a/packages/website/ts/components/newsletter_form.tsx b/packages/website/ts/components/newsletter_form.tsx deleted file mode 100644 index e5fd95646..000000000 --- a/packages/website/ts/components/newsletter_form.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import * as React from 'react'; -import styled, { withTheme } from 'styled-components'; - -import { ThemeValuesInterface } from 'ts/components/siteWrap'; -import { colors } from 'ts/style/colors'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { utils } from 'ts/utils/utils'; - -interface FormProps { - theme: ThemeValuesInterface; -} - -interface InputProps { - isSubmitted: boolean; - name: string; - type: string; - label: string; - textColor: string; - required?: boolean; -} - -interface ArrowProps { - isSubmitted: boolean; -} - -const Input = React.forwardRef((props: InputProps, ref: React.Ref<HTMLInputElement>) => { - const { name, label, type } = props; - const id = `input-${name}`; - - return ( - <InnerInputWrapper {...props}> - <label className="visuallyHidden" htmlFor={id}> - {label} - </label> - <StyledInput ref={ref} id={id} placeholder={label} type={type || 'text'} {...props} /> - </InnerInputWrapper> - ); -}); - -class Form extends React.Component<FormProps> { - public emailInput = React.createRef<HTMLInputElement>(); - public state = { - isSubmitted: false, - }; - public render(): React.ReactNode { - const { isSubmitted } = this.state; - const { theme } = this.props; - - return ( - <StyledForm onSubmit={this._onSubmitAsync.bind(this)}> - <InputWrapper> - <Input - isSubmitted={isSubmitted} - name="email" - type="email" - label="Email Address" - ref={this.emailInput} - required={true} - textColor={theme.textColor} - /> - - <SubmitButton> - <Arrow - isSubmitted={isSubmitted} - width="22" - height="17" - fill="none" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M13.066 0l-1.068 1.147 6.232 6.557H0v1.592h18.23l-6.232 6.557L13.066 17l8.08-8.5-8.08-8.5z" - fill="#CBCBCB" - /> - </Arrow> - </SubmitButton> - <SuccessText isSubmitted={isSubmitted}>🎉 Thank you for signing up!</SuccessText> - </InputWrapper> - <Text>Subscribe to our newsletter for updates in the 0x ecosystem</Text> - </StyledForm> - ); - } - - private async _onSubmitAsync(e: React.FormEvent<HTMLFormElement>): Promise<void> { - e.preventDefault(); - - const email = this.emailInput.current.value; - const referrer = 'https://0x.org/'; - - this.setState({ isSubmitted: true }); - - if (email === 'triggererror@0xproject.org') { - throw new Error('Manually triggered error'); - } - - try { - await fetch(`${utils.getBackendBaseUrl()}/newsletter_subscriber/substack`, { - method: 'post', - mode: 'cors', - headers: { - 'content-type': 'application/json; charset=utf-8', - }, - body: JSON.stringify({ email, referrer }), - }); - } catch (e) { - errorReporter.report(e); - } - } -} - -export const NewsletterForm = withTheme(Form); - -const StyledForm = styled.form` - appearance: none; - border: 0; - color: ${colors.white}; - padding: 13px 0 14px; - margin-top: 27px; -`; - -const StyledInput = styled.input<InputProps>` - appearance: none; - background-color: transparent; - border: 0; - border-bottom: 1px solid #393939; - color: ${props => props.textColor || '#fff'}; - font-size: 1.294117647rem; - padding: 15px 0; - outline: none; - width: 100%; - - &::placeholder { - color: #b1b1b1; // #9D9D9D on light theme - } -`; - -const InputWrapper = styled.div` - position: relative; -`; - -const InnerInputWrapper = styled.div<ArrowProps>` - opacity: ${props => props.isSubmitted && 0}; - visibility: ${props => props.isSubmitted && 'hidden'}; - transition: opacity 0.25s ease-in-out, visibility 0.25s ease-in-out; - transition-delay: 0.3s; -`; - -const SubmitButton = styled.button` - width: 44px; - height: 44px; - background-color: transparent; - border: 0; - position: absolute; - right: 0; - top: calc(50% - 22px); - overflow: hidden; - outline: 0; - - &:focus-within { - //background-color: #eee; - } -`; - -const Text = styled.p` - color: #656565; - font-size: 0.833333333rem; - font-weight: 300; - line-height: 1.2em; - margin-top: 15px; -`; - -const SuccessText = styled.p<ArrowProps>` - color: #b1b1b1; - font-size: 1rem; - font-weight: 300; - line-height: 1.2em; - padding-top: 25px; - position: absolute; - left: 0; - top: 0; - text-align: left; - right: 50px; - opacity: ${props => (props.isSubmitted ? 1 : 0)}; - visibility: ${props => (props.isSubmitted ? 'visible' : 'hidden')}; - transition: opacity 0.25s ease-in-out, visibility 0.25s ease-in-out; - transition-delay: 0.55s; -`; - -const Arrow = styled.svg<ArrowProps>` - transform: ${props => props.isSubmitted && `translateX(44px)`}; - transition: transform 0.25s ease-in-out; -`; diff --git a/packages/website/ts/components/old_footer.tsx b/packages/website/ts/components/old_footer.tsx deleted file mode 100644 index 6366bf4ea..000000000 --- a/packages/website/ts/components/old_footer.tsx +++ /dev/null @@ -1,228 +0,0 @@ -import { ALink, colors, Link } from '@0x/react-shared'; -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; -import DropDownMenu from 'material-ui/DropDownMenu'; -import MenuItem from 'material-ui/MenuItem'; -import * as React from 'react'; - -import { Dispatcher } from 'ts/redux/dispatcher'; -import { Deco, Key, Language, WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -const ICON_DIMENSION = 16; - -const languageToMenuTitle = { - [Language.English]: 'English', - [Language.Russian]: 'Русский', - [Language.Spanish]: 'Español', - [Language.Korean]: '한국어', - [Language.Chinese]: '中文', -}; - -export interface FooterProps { - translate: Translate; - dispatcher: Dispatcher; - backgroundColor?: string; -} - -interface FooterState { - selectedLanguage: Language; -} - -export class Footer extends React.Component<FooterProps, FooterState> { - public static defaultProps = { - backgroundColor: colors.darkerGrey, - }; - constructor(props: FooterProps) { - super(props); - this.state = { - selectedLanguage: props.translate.getLanguage(), - }; - } - public render(): React.ReactNode { - const sectionNameToLinks: ObjectMap<ALink[]> = { - [Key.Documentation]: [ - { - title: 'Developer Home', - to: WebsitePaths.Docs, - }, - { - title: '0x.js', - to: WebsitePaths.ZeroExJs, - }, - { - title: this.props.translate.get(Key.SmartContracts, Deco.Cap), - to: WebsitePaths.SmartContracts, - }, - { - title: this.props.translate.get(Key.Connect, Deco.Cap), - to: WebsitePaths.Connect, - }, - { - title: this.props.translate.get(Key.Whitepaper, Deco.Cap), - to: WebsitePaths.Whitepaper, - shouldOpenInNewTab: true, - }, - { - title: this.props.translate.get(Key.Wiki, Deco.Cap), - to: WebsitePaths.Wiki, - }, - ], - [Key.Community]: [ - { - title: this.props.translate.get(Key.Discord, Deco.Cap), - to: constants.URL_ZEROEX_CHAT, - shouldOpenInNewTab: true, - }, - { - title: this.props.translate.get(Key.Blog, Deco.Cap), - to: constants.URL_BLOG, - shouldOpenInNewTab: true, - }, - { - title: 'Twitter', - to: constants.URL_TWITTER, - shouldOpenInNewTab: true, - }, - { - title: 'Reddit', - to: constants.URL_REDDIT, - shouldOpenInNewTab: true, - }, - { - title: this.props.translate.get(Key.Forum, Deco.Cap), - to: constants.URL_DISCOURSE_FORUM, - shouldOpenInNewTab: true, - }, - ], - [Key.Organization]: [ - { - title: this.props.translate.get(Key.About, Deco.Cap), - to: WebsitePaths.About, - }, - { - title: this.props.translate.get(Key.Careers, Deco.Cap), - to: WebsitePaths.Careers, - }, - { - title: this.props.translate.get(Key.Contact, Deco.Cap), - to: 'mailto:team@0x.org', - shouldOpenInNewTab: true, - }, - ], - }; - const languageMenuItems = _.map(languageToMenuTitle, (menuTitle: string, language: Language) => { - return <MenuItem key={menuTitle} value={language} primaryText={menuTitle} />; - }); - return ( - <div className="relative pb4 pt2" style={{ backgroundColor: this.props.backgroundColor }}> - <div className="mx-auto max-width-4 md-px2 lg-px0 py4 clearfix" style={{ color: colors.white }}> - <div className="col lg-col-4 md-col-4 col-12 left"> - <div className="sm-mx-auto" style={{ width: 148 }}> - <div> - <img src="/images/protocol_logo_white.png" height="30" /> - </div> - <div - style={{ - fontSize: 11, - color: colors.grey, - paddingLeft: 37, - paddingTop: 2, - }} - > - © ZeroEx, Intl. - </div> - <div className="pt4 center"> - <DropDownMenu - labelStyle={{ color: colors.white }} - value={this.state.selectedLanguage} - onChange={this._updateLanguage.bind(this)} - > - {languageMenuItems} - </DropDownMenu> - </div> - </div> - </div> - <div className="col lg-col-8 md-col-8 col-12 lg-pl4 md-pl4"> - <div className="col lg-col-4 md-col-4 col-12"> - <div className="lg-right md-right sm-center"> - {this._renderHeader(Key.Documentation)} - {_.map(sectionNameToLinks[Key.Documentation], this._renderMenuItem.bind(this))} - </div> - </div> - <div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2"> - <div className="lg-right md-right sm-center"> - {this._renderHeader(Key.Community)} - {_.map(sectionNameToLinks[Key.Community], this._renderMenuItem.bind(this))} - </div> - </div> - <div className="col lg-col-4 md-col-4 col-12"> - <div className="lg-right md-right sm-center"> - {this._renderHeader(Key.Organization)} - {_.map(sectionNameToLinks[Key.Organization], this._renderMenuItem.bind(this))} - </div> - </div> - </div> - </div> - </div> - ); - } - private _renderIcon(fileName: string): React.ReactNode { - return ( - <div style={{ height: ICON_DIMENSION, width: ICON_DIMENSION }}> - <img src={`/images/social/${fileName}`} style={{ width: ICON_DIMENSION }} /> - </div> - ); - } - private _renderMenuItem(link: ALink): React.ReactNode { - const titleToIcon: { [title: string]: string } = { - [this.props.translate.get(Key.Discord, Deco.Cap)]: 'discord.png', - [this.props.translate.get(Key.Blog, Deco.Cap)]: 'medium.png', - Twitter: 'twitter.png', - Reddit: 'reddit.png', - [this.props.translate.get(Key.Forum, Deco.Cap)]: 'discourse.png', - }; - const iconIfExists = titleToIcon[link.title]; - return ( - <div key={link.title} className="sm-center" style={{ fontSize: 13, paddingTop: 25 }}> - <Link - to={link.to} - shouldOpenInNewTab={link.shouldOpenInNewTab} - fontColor={colors.white} - className="text-decoration-none" - > - <div> - {!_.isUndefined(iconIfExists) ? ( - <div className="inline-block"> - <div className="pr1 table-cell">{this._renderIcon(iconIfExists)}</div> - <div className="table-cell">{link.title}</div> - </div> - ) : ( - link.title - )} - </div> - </Link> - </div> - ); - } - private _renderHeader(key: Key): React.ReactNode { - const headerStyle = { - color: colors.grey400, - letterSpacing: 2, - fontFamily: 'Roboto Mono', - fontSize: 13, - }; - return ( - <div className="lg-pb2 md-pb2 sm-pt4" style={headerStyle}> - {this.props.translate.get(key, Deco.Upper)} - </div> - ); - } - private _updateLanguage(_event: any, _index: number, value: Language): void { - this.setState({ - selectedLanguage: value, - }); - this.props.dispatcher.updateSelectedLanguage(value); - } -} diff --git a/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx b/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx deleted file mode 100644 index 1d21e5a85..000000000 --- a/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as React from 'react'; -import { Balance } from 'ts/components/ui/balance'; -import { Container } from 'ts/components/ui/container'; -import { Image } from 'ts/components/ui/image'; -import { Text } from 'ts/components/ui/text'; -import { constants } from 'ts/utils/constants'; - -export interface AddEthOnboardingStepProps { - userEthBalanceInWei: BigNumber; -} - -export const AddEthOnboardingStep: React.StatelessComponent<AddEthOnboardingStepProps> = props => - props.userEthBalanceInWei.gt(0) ? ( - <div className="flex items-center flex-column"> - <Text> - Great! Looks like you already have{' '} - <Balance - amount={props.userEthBalanceInWei} - decimals={constants.DECIMAL_PLACES_ETH} - symbol={constants.ETHER_SYMBOL} - />{' '} - in your wallet. - </Text> - <Container marginTop="15px" marginBottom="15px"> - <Image src="/images/ether_alt.svg" height="50px" width="50px" /> - </Container> - </div> - ) : ( - <div className="flex items-center flex-column"> - <Text> Before you begin you will need to send some ETH to your wallet.</Text> - <Container marginTop="15px" marginBottom="15px"> - <Image src="/images/ether_alt.svg" height="50px" width="50px" /> - </Container> - <Text className="xs-hide"> - Click on the <Image src="/images/metamask_icon.png" height="20px" width="20px" /> MetaMask extension in - your browser and click either <b>BUY</b> or <b>DEPOSIT</b>. - </Text> - </div> - ); diff --git a/packages/website/ts/components/onboarding/congrats_onboarding_step.tsx b/packages/website/ts/components/onboarding/congrats_onboarding_step.tsx deleted file mode 100644 index 8100fd2c0..000000000 --- a/packages/website/ts/components/onboarding/congrats_onboarding_step.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import * as React from 'react'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; - -export interface CongratsOnboardingStepProps {} - -export const CongratsOnboardingStep: React.StatelessComponent<CongratsOnboardingStepProps> = () => ( - <div className="flex items-center flex-column"> - <Text>Your wallet is now set up for trading. Use it on any relayer in the 0x ecosystem.</Text> - <Container marginTop="25px" marginBottom="15px" className="flex justify-center"> - <img src="/images/zrx_ecosystem.svg" height="150px" /> - </Container> - <Text>No need to log in. Each relayer automatically detects and connects to your wallet.</Text> - </div> -); diff --git a/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx deleted file mode 100644 index 173ba9a97..000000000 --- a/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { colors } from '@0x/react-shared'; -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 { utils } from 'ts/utils/utils'; - -export interface InstallWalletOnboardingStepProps {} - -export const InstallWalletOnboardingStep: React.StatelessComponent<InstallWalletOnboardingStepProps> = () => { - const [downloadLink, isOnMobile] = utils.getBestWalletDownloadLinkAndIsMobile(); - const followupText = isOnMobile - ? `Please revisit this site in your mobile dApp browser to continue!` - : `Please refresh the page once you've done this to continue!`; - const downloadText = isOnMobile ? 'Get Coinbase Wallet' : 'Get the MetaMask extension'; - return ( - <div className="flex items-center flex-column"> - <Text>First, you need to connect to a wallet. This will be used across all 0x relayers and dApps.</Text> - <Container className="flex items-center" marginTop="15px" marginBottom="15px"> - <Image - height="50px" - width="50px" - borderRadius="22%" - src={isOnMobile ? '/images/coinbase_wallet_logo.png' : '/images/metamask_icon.png'} - /> - <Container marginLeft="10px"> - <a href={downloadLink} target="_blank"> - <Text - fontWeight={700} - fontSize="18px" - fontColor={colors.mediumBlue} - textDecorationLine="underline" - > - {downloadText} - </Text> - </a> - </Container> - </Container> - <Text>{followupText}</Text> - </div> - ); -}; diff --git a/packages/website/ts/components/onboarding/intro_onboarding_step.tsx b/packages/website/ts/components/onboarding/intro_onboarding_step.tsx deleted file mode 100644 index f9ced7315..000000000 --- a/packages/website/ts/components/onboarding/intro_onboarding_step.tsx +++ /dev/null @@ -1,30 +0,0 @@ -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'; - -export interface IntroOnboardingStepProps {} - -export const IntroOnboardingStep: React.StatelessComponent<IntroOnboardingStepProps> = () => ( - <div className="flex items-center flex-column"> - <Text> - In order to start trading on any 0x relayer in the 0x ecosystem, you need to complete three simple steps. - </Text> - <Container width="100%" marginTop="25px" marginBottom="15px" className="flex justify-around"> - <div className="flex flex-column items-center"> - <Image src="/images/ether.png" height="50px" width="50px" /> - <Text> Add ETH </Text> - </div> - <div className="flex flex-column items-center"> - <Image src="/images/eth_token.svg" height="50px" width="50x" /> - <Text> Wrap ETH </Text> - </div> - <div className="flex flex-column items-center"> - <Container marginBottom="9px"> - <Image src="/images/lock_icon.svg" height="35px" width="35x" /> - </Container> - <Text> Unlock tokens </Text> - </div> - </Container> - </div> -); diff --git a/packages/website/ts/components/onboarding/onboarding_card.tsx b/packages/website/ts/components/onboarding/onboarding_card.tsx deleted file mode 100644 index 384bf7154..000000000 --- a/packages/website/ts/components/onboarding/onboarding_card.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; - -import * as _ from 'lodash'; -import { Button } from 'ts/components/ui/button'; -import { Container } from 'ts/components/ui/container'; -import { IconButton } from 'ts/components/ui/icon_button'; -import { Island } from 'ts/components/ui/island'; -import { Text, Title } from 'ts/components/ui/text'; - -export type ContinueButtonDisplay = 'enabled' | 'disabled'; - -export interface OnboardingCardProps { - title?: string; - shouldCenterTitle?: boolean; - content: React.ReactNode; - isLastStep: boolean; - onClose: () => void; - onClickNext: () => void; - onClickBack: () => void; - onContinueButtonClick?: () => void; - continueButtonDisplay?: ContinueButtonDisplay; - shouldHideBackButton?: boolean; - shouldHideNextButton?: boolean; - continueButtonText?: string; - borderRadius?: string; - // Used for super-custom content. - shouldRemoveExtraSpacing?: boolean; -} - -export const OnboardingCard: React.StatelessComponent<OnboardingCardProps> = ({ - title, - shouldCenterTitle, - content, - continueButtonDisplay, - continueButtonText, - onContinueButtonClick, - onClickNext, - onClickBack, - onClose, - shouldHideBackButton, - shouldHideNextButton, - borderRadius, - shouldRemoveExtraSpacing, -}) => { - const padding = shouldRemoveExtraSpacing - ? {} - : { - paddingRight: '30px', - paddingLeft: '30px', - paddingTop: '15px', - paddingBottom: '15px', - }; - const closeIconPositioning = shouldRemoveExtraSpacing - ? { right: '15px', bottom: '3px' } - : { bottom: '20px', left: '15px' }; - return ( - <Island borderRadius={borderRadius}> - <Container {...padding}> - <div className="flex flex-column"> - <Container className="flex justify-between"> - <Container width="100%"> - <Title center={shouldCenterTitle}>{title}</Title> - </Container> - <Container position="relative" {...closeIconPositioning}> - <IconButton color={colors.grey} iconName="zmdi-close" onClick={onClose}> - Close - </IconButton> - </Container> - </Container> - <Container marginBottom={shouldRemoveExtraSpacing ? undefined : '15px'}> - <Text>{content}</Text> - </Container> - {continueButtonDisplay && ( - <Button - isDisabled={continueButtonDisplay === 'disabled'} - onClick={!_.isUndefined(onContinueButtonClick) ? onContinueButtonClick : onClickNext} - fontColor={colors.white} - fontSize="15px" - backgroundColor={colors.mediumBlue} - > - {continueButtonText} - </Button> - )} - {!(shouldHideBackButton && shouldHideNextButton) && ( - <Container className="clearfix" marginTop="15px"> - <div className="left"> - {!shouldHideBackButton && ( - <Text fontColor={colors.grey} onClick={onClickBack}> - Back - </Text> - )} - </div> - <div className="right"> - {!shouldHideNextButton && ( - <Text fontColor={colors.grey} onClick={onClickNext}> - Skip - </Text> - )} - </div> - </Container> - )} - </div> - </Container> - </Island> - ); -}; - -OnboardingCard.defaultProps = { - continueButtonText: 'Continue', - shouldCenterTitle: false, - shouldRemoveExtraSpacing: false, -}; - -OnboardingCard.displayName = 'OnboardingCard'; diff --git a/packages/website/ts/components/onboarding/onboarding_flow.tsx b/packages/website/ts/components/onboarding/onboarding_flow.tsx deleted file mode 100644 index ec1b5bc42..000000000 --- a/packages/website/ts/components/onboarding/onboarding_flow.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import * as React from 'react'; -import { Placement, Popper, PopperChildrenProps } from 'react-popper'; - -import { OnboardingCard } from 'ts/components/onboarding/onboarding_card'; -import { - ContinueButtonDisplay, - OnboardingTooltip, - TooltipPointerDisplay, -} from 'ts/components/onboarding/onboarding_tooltip'; -import { Container } from 'ts/components/ui/container'; -import { EaseUpFromBottomAnimation } from 'ts/components/ui/ease_up_from_bottom_animation'; -import { Overlay } from 'ts/components/ui/overlay'; -import { zIndex } from 'ts/style/z_index'; - -export interface FixedPositionSettings { - type: 'fixed'; - top?: string; - bottom?: string; - left?: string; - right?: string; - tooltipPointerDisplay?: TooltipPointerDisplay; -} - -export interface TargetPositionSettings { - type: 'target'; - target: string; - placement: Placement; -} - -export interface Step { - // Provide either a CSS selector, or fixed position settings. Only applies to desktop. - position: TargetPositionSettings | FixedPositionSettings; - title?: string; - shouldCenterTitle?: boolean; - content: React.ReactNode; - shouldHideBackButton?: boolean; - shouldHideNextButton?: boolean; - continueButtonDisplay?: ContinueButtonDisplay; - continueButtonText?: string; - onContinueButtonClick?: () => void; - // Only used for very custom steps. - shouldRemoveExtraSpacing?: boolean; -} - -export interface OnboardingFlowProps { - steps: Step[]; - stepIndex: number; - isRunning: boolean; - onClose: () => void; - updateOnboardingStep: (stepIndex: number) => void; - disableOverlay?: boolean; - isMobile: boolean; - disableCloseOnClickOutside?: boolean; -} - -export class OnboardingFlow extends React.Component<OnboardingFlowProps> { - public static defaultProps = { - disableOverlay: false, - isMobile: false, - disableCloseOnClickOutside: false, - }; - public render(): React.ReactNode { - if (!this.props.isRunning) { - return null; - } - let onboardingElement = null; - const currentStep = this._getCurrentStep(); - if (this.props.isMobile) { - onboardingElement = <EaseUpFromBottomAnimation>{this._renderOnboardingCard()}</EaseUpFromBottomAnimation>; - } else if (currentStep.position.type === 'target') { - const { placement, target } = currentStep.position; - onboardingElement = ( - <Popper referenceElement={document.querySelector(target)} placement={placement} positionFixed={true}> - {this._renderPopperChildren.bind(this)} - </Popper> - ); - } else if (currentStep.position.type === 'fixed') { - const { top, right, bottom, left, tooltipPointerDisplay } = currentStep.position; - onboardingElement = ( - <Container - position="fixed" - zIndex={zIndex.aboveOverlay} - top={top} - right={right} - bottom={bottom} - left={left} - > - {this._renderToolTip(tooltipPointerDisplay)} - </Container> - ); - } - if (this.props.disableOverlay) { - return onboardingElement; - } - return ( - <div> - <Overlay onClick={this.props.disableCloseOnClickOutside ? undefined : this.props.onClose} /> - {onboardingElement} - </div> - ); - } - private _renderPopperChildren(props: PopperChildrenProps): React.ReactNode { - const customStyles = { zIndex: zIndex.aboveOverlay }; - // On re-render, we want to re-center the popper. - props.scheduleUpdate(); - return ( - <div ref={props.ref} style={{ ...props.style, ...customStyles }} data-placement={props.placement}> - {this._renderToolTip()} - </div> - ); - } - private _renderToolTip(tooltipPointerDisplay?: TooltipPointerDisplay): React.ReactNode { - const { steps, stepIndex } = this.props; - const step = steps[stepIndex]; - const isLastStep = steps.length - 1 === stepIndex; - return ( - <Container marginLeft="30px" width="400px"> - <OnboardingTooltip - title={step.title} - shouldCenterTitle={step.shouldCenterTitle} - content={step.content} - isLastStep={isLastStep} - shouldHideBackButton={step.shouldHideBackButton} - shouldHideNextButton={step.shouldHideNextButton} - onClose={this.props.onClose} - onClickNext={this._goToNextStep.bind(this)} - onClickBack={this._goToPrevStep.bind(this)} - continueButtonDisplay={step.continueButtonDisplay} - continueButtonText={step.continueButtonText} - onContinueButtonClick={step.onContinueButtonClick} - pointerDisplay={tooltipPointerDisplay} - shouldRemoveExtraSpacing={step.shouldRemoveExtraSpacing} - /> - </Container> - ); - } - - private _renderOnboardingCard(): React.ReactNode { - const { steps, stepIndex } = this.props; - const step = steps[stepIndex]; - const isLastStep = steps.length - 1 === stepIndex; - return ( - <Container position="relative" zIndex={1}> - <OnboardingCard - title={step.title} - shouldCenterTitle={step.shouldCenterTitle} - content={step.content} - isLastStep={isLastStep} - shouldHideBackButton={step.shouldHideBackButton} - shouldHideNextButton={step.shouldHideNextButton} - onClose={this.props.onClose} - onClickNext={this._goToNextStep.bind(this)} - onClickBack={this._goToPrevStep.bind(this)} - continueButtonDisplay={step.continueButtonDisplay} - continueButtonText={step.continueButtonText} - onContinueButtonClick={step.onContinueButtonClick} - borderRadius="10px 10px 0px 0px" - shouldRemoveExtraSpacing={step.shouldRemoveExtraSpacing} - /> - </Container> - ); - } - private _getCurrentStep(): Step { - return this.props.steps[this.props.stepIndex]; - } - private _goToNextStep(): void { - const nextStep = this.props.stepIndex + 1; - if (nextStep < this.props.steps.length) { - this.props.updateOnboardingStep(nextStep); - } else { - this.props.onClose(); - } - } - private _goToPrevStep(): void { - const nextStep = this.props.stepIndex - 1; - if (nextStep >= 0) { - this.props.updateOnboardingStep(nextStep); - } else { - this.props.onClose(); - } - } -} diff --git a/packages/website/ts/components/onboarding/onboarding_tooltip.tsx b/packages/website/ts/components/onboarding/onboarding_tooltip.tsx deleted file mode 100644 index ff5f0bab6..000000000 --- a/packages/website/ts/components/onboarding/onboarding_tooltip.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from 'react'; - -import { OnboardingCard, OnboardingCardProps } from 'ts/components/onboarding/onboarding_card'; -import { Pointer, PointerDirection } from 'ts/components/ui/pointer'; - -export type ContinueButtonDisplay = 'enabled' | 'disabled'; -export type TooltipPointerDisplay = PointerDirection | 'none'; - -export interface OnboardingTooltipProps extends OnboardingCardProps { - className?: string; - pointerDisplay?: TooltipPointerDisplay; -} - -export const OnboardingTooltip: React.StatelessComponent<OnboardingTooltipProps> = props => { - const { pointerDisplay, className, ...cardProps } = props; - const card = <OnboardingCard {...cardProps} />; - if (pointerDisplay === 'none') { - return card; - } - return ( - <Pointer className={className} direction={pointerDisplay}> - <OnboardingCard {...cardProps} /> - </Pointer> - ); -}; -OnboardingTooltip.defaultProps = { - pointerDisplay: PointerDirection.Left, -}; - -OnboardingTooltip.displayName = 'OnboardingTooltip'; diff --git a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx deleted file mode 100644 index 6adcec0b1..000000000 --- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx +++ /dev/null @@ -1,281 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import { RouteComponentProps, withRouter } from 'react-router'; - -import { BigNumber } from '@0x/utils'; -import { Blockchain } from 'ts/blockchain'; -import { AddEthOnboardingStep } from 'ts/components/onboarding/add_eth_onboarding_step'; -import { CongratsOnboardingStep } from 'ts/components/onboarding/congrats_onboarding_step'; -import { InstallWalletOnboardingStep } from 'ts/components/onboarding/install_wallet_onboarding_step'; -import { IntroOnboardingStep } from 'ts/components/onboarding/intro_onboarding_step'; -import { - FixedPositionSettings, - OnboardingFlow, - Step, - TargetPositionSettings, -} from 'ts/components/onboarding/onboarding_flow'; -import { SetAllowancesOnboardingStep } from 'ts/components/onboarding/set_allowances_onboarding_step'; -import { UnlockWalletOnboardingStep } from 'ts/components/onboarding/unlock_wallet_onboarding_step'; -import { - WrapEthOnboardingStep1, - WrapEthOnboardingStep2, - WrapEthOnboardingStep3, -} from 'ts/components/onboarding/wrap_eth_onboarding_step'; -import { AllowanceStateToggle } from 'ts/containers/inputs/allowance_state_toggle'; -import { BrowserType, ProviderType, ScreenWidths, Token, TokenByAddress, TokenStateByAddress } from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; -import { utils } from 'ts/utils/utils'; - -export interface PortalOnboardingFlowProps extends RouteComponentProps<any> { - networkId: number; - blockchain: Blockchain; - stepIndex: number; - isRunning: boolean; - userAddress: string; - hasBeenClosed: boolean; - providerType: ProviderType; - injectedProviderName: string; - blockchainIsLoaded: boolean; - userEtherBalanceInWei?: BigNumber; - tokenByAddress: TokenByAddress; - trackedTokenStateByAddress: TokenStateByAddress; - updateIsRunning: (isRunning: boolean) => void; - updateOnboardingStep: (stepIndex: number) => void; - refetchTokenStateAsync: (tokenAddress: string) => Promise<void>; - screenWidth: ScreenWidths; -} - -class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProps> { - private _unlisten: () => void; - public componentDidMount(): void { - this._adjustStepIfShould(); - // If there is a route change, just close onboarding. - this._unlisten = this.props.history.listen(() => this.props.updateIsRunning(false)); - } - public componentWillUnmount(): void { - this._unlisten(); - } - public componentDidUpdate(prevProps: PortalOnboardingFlowProps): void { - // Any one of steps 0-3 could be the starting step, and we only want to reset the scroll on the starting step. - if (this.props.isRunning && utils.isMobileWidth(this.props.screenWidth) && this.props.stepIndex < 3) { - // On mobile, make sure the wallet is completely visible. - document.querySelector('.wallet').scrollIntoView(); - } - this._adjustStepIfShould(); - if (!prevProps.blockchainIsLoaded && this.props.blockchainIsLoaded) { - this._autoStartOnboardingIfShould(); - } - } - public render(): React.ReactNode { - const browserType = utils.getBrowserType(); - return ( - <OnboardingFlow - steps={this._getSteps()} - stepIndex={this.props.stepIndex} - isRunning={this.props.isRunning} - onClose={this._closeOnboarding.bind(this)} - updateOnboardingStep={this._updateOnboardingStep.bind(this)} - disableOverlay={this.props.screenWidth === ScreenWidths.Sm} - isMobile={this.props.screenWidth === ScreenWidths.Sm} - // This is necessary to ensure onboarding stays open once the user unlocks metamask and clicks away - disableCloseOnClickOutside={browserType === BrowserType.Firefox || browserType === BrowserType.Opera} - /> - ); - } - private _getSteps(): Step[] { - const nextToWalletPosition: TargetPositionSettings = { - type: 'target', - target: '.wallet', - placement: 'right', - }; - const underMetamaskExtension: FixedPositionSettings = { - type: 'fixed', - top: '10px', - right: '10px', - tooltipPointerDisplay: 'none', - }; - const steps: Step[] = [ - { - position: nextToWalletPosition, - title: '0x Ecosystem Setup', - content: <InstallWalletOnboardingStep />, - shouldHideBackButton: true, - shouldHideNextButton: true, - }, - { - position: underMetamaskExtension, - title: 'Please Unlock Metamask...', - content: <UnlockWalletOnboardingStep />, - shouldHideBackButton: true, - shouldHideNextButton: true, - shouldCenterTitle: true, - shouldRemoveExtraSpacing: true, - }, - { - position: nextToWalletPosition, - title: '0x Ecosystem Account Setup', - content: <IntroOnboardingStep />, - shouldHideBackButton: true, - continueButtonDisplay: 'enabled', - }, - { - position: nextToWalletPosition, - title: 'Step 1: Add ETH', - content: ( - <AddEthOnboardingStep userEthBalanceInWei={this.props.userEtherBalanceInWei || new BigNumber(0)} /> - ), - continueButtonDisplay: this._userHasVisibleEth() ? 'enabled' : 'disabled', - }, - { - position: nextToWalletPosition, - title: 'Step 2: Wrap ETH', - content: <WrapEthOnboardingStep1 />, - continueButtonDisplay: 'enabled', - }, - { - position: nextToWalletPosition, - title: 'Step 2: Wrap ETH', - content: <WrapEthOnboardingStep2 />, - continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled', - }, - { - position: nextToWalletPosition, - title: 'Step 2: Wrap ETH', - content: <WrapEthOnboardingStep3 wethAmount={this._getWethBalance()} />, - continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled', - }, - { - position: nextToWalletPosition, - title: 'Step 3: Unlock Tokens', - content: ( - <SetAllowancesOnboardingStep - zrxAllowanceToggle={this._renderZrxAllowanceStateToggle()} - ethAllowanceToggle={this._renderEthAllowanceStateToggle()} - doesUserHaveAllowancesForWethAndZrx={this._doesUserHaveAllowancesForWethAndZrx()} - /> - ), - continueButtonDisplay: this._doesUserHaveAllowancesForWethAndZrx() ? 'enabled' : 'disabled', - }, - { - position: nextToWalletPosition, - title: '🎉 The Ecosystem Awaits', - content: <CongratsOnboardingStep />, - continueButtonDisplay: 'enabled', - shouldHideNextButton: true, - continueButtonText: 'Enter the 0x Ecosystem', - onContinueButtonClick: this._handleFinalStepContinueClick.bind(this), - }, - ]; - return steps; - } - private _isAddressAvailable(): boolean { - return !_.isEmpty(this.props.userAddress); - } - private _userHasVisibleEth(): boolean { - return this.props.userEtherBalanceInWei > new BigNumber(0); - } - private _getWethBalance(): BigNumber { - const ethToken = utils.getEthToken(this.props.tokenByAddress); - if (!ethToken) { - return new BigNumber(0); - } - const ethTokenState = this.props.trackedTokenStateByAddress[ethToken.address]; - return ethTokenState.balance; - } - private _userHasVisibleWeth(): boolean { - return this._getWethBalance() > new BigNumber(0); - } - private _doesUserHaveAllowancesForWethAndZrx(): boolean { - const ethToken = utils.getEthToken(this.props.tokenByAddress); - const zrxToken = utils.getZrxToken(this.props.tokenByAddress); - if (ethToken && zrxToken) { - const ethTokenState = this.props.trackedTokenStateByAddress[ethToken.address]; - const zrxTokenState = this.props.trackedTokenStateByAddress[zrxToken.address]; - if (ethTokenState && zrxTokenState) { - return ethTokenState.allowance.gt(0) && zrxTokenState.allowance.gt(0); - } - } - return false; - } - private _adjustStepIfShould(): void { - const stepIndex = this.props.stepIndex; - if (this._isAddressAvailable()) { - if (stepIndex < 2) { - this.props.updateOnboardingStep(2); - } - return; - } - const isExternallyInjected = utils.isExternallyInjected( - this.props.providerType, - this.props.injectedProviderName, - ); - if (isExternallyInjected) { - if (stepIndex !== 1) { - this.props.updateOnboardingStep(1); - } - return; - } - if (stepIndex !== 0) { - this.props.updateOnboardingStep(0); - } - } - private _autoStartOnboardingIfShould(): void { - if ( - (this.props.stepIndex === 0 && !this.props.isRunning && this.props.blockchainIsLoaded) || - (!this.props.isRunning && !this.props.hasBeenClosed && this.props.blockchainIsLoaded) - ) { - analytics.track('Onboarding Started', { - reason: 'automatic', - stepIndex: this.props.stepIndex, - }); - this.props.updateIsRunning(true); - } - } - private _updateOnboardingStep(stepIndex: number): void { - this.props.updateOnboardingStep(stepIndex); - analytics.track('Update Onboarding Step', { - stepIndex, - }); - } - private _closeOnboarding(): void { - this.props.updateIsRunning(false); - analytics.track('Onboarding Closed', { - stepIndex: this.props.stepIndex, - }); - } - private _renderZrxAllowanceStateToggle(): React.ReactNode { - const zrxToken = utils.getZrxToken(this.props.tokenByAddress); - return this._renderAllowanceStateToggle(zrxToken); - } - private _renderEthAllowanceStateToggle(): React.ReactNode { - const ethToken = utils.getEthToken(this.props.tokenByAddress); - return this._renderAllowanceStateToggle(ethToken); - } - private _renderAllowanceStateToggle(token: Token): React.ReactNode { - if (!token) { - return null; - } - const tokenStateIfExists = this.props.trackedTokenStateByAddress[token.address]; - if (_.isUndefined(tokenStateIfExists)) { - return null; - } - return ( - <AllowanceStateToggle - token={token} - tokenState={tokenStateIfExists} - blockchain={this.props.blockchain} - // tslint:disable-next-line:jsx-no-lambda - refetchTokenStateAsync={async () => this.props.refetchTokenStateAsync(token.address)} - /> - ); - } - private _handleFinalStepContinueClick(): void { - if (utils.isMobileWidth(this.props.screenWidth)) { - window.scrollTo(0, 0); - this.props.history.push('/portal'); - } - this._closeOnboarding(); - } -} - -export const PortalOnboardingFlow = withRouter(PlainPortalOnboardingFlow); diff --git a/packages/website/ts/components/onboarding/set_allowances_onboarding_step.tsx b/packages/website/ts/components/onboarding/set_allowances_onboarding_step.tsx deleted file mode 100644 index 5ddfe38d7..000000000 --- a/packages/website/ts/components/onboarding/set_allowances_onboarding_step.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from 'react'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; - -export interface SetAllowancesOnboardingStepProps { - zrxAllowanceToggle: React.ReactNode; - ethAllowanceToggle: React.ReactNode; - doesUserHaveAllowancesForWethAndZrx: boolean; -} - -export const SetAllowancesOnboardingStep: React.StatelessComponent<SetAllowancesOnboardingStepProps> = ({ - ethAllowanceToggle, - zrxAllowanceToggle, - doesUserHaveAllowancesForWethAndZrx, -}) => ( - <div className="flex items-center flex-column"> - <Text>Unlock your tokens for trading. You only need to do this once for each token.</Text> - <Container width="100%" marginTop="25px" marginBottom="15px" className="flex justify-around"> - <div className="flex flex-column items-center"> - <Text fontWeight={700}> Enable WETH </Text> - <Container marginTop="10px">{ethAllowanceToggle}</Container> - </div> - <div className="flex flex-column items-center"> - <Text fontWeight={700}> Enable ZRX </Text> - <Container marginTop="10px">{zrxAllowanceToggle}</Container> - </div> - </Container> - {doesUserHaveAllowancesForWethAndZrx && <Text>Perfect! Both your ZRX and WETH tokens are unlocked.</Text>} - </div> -); diff --git a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx deleted file mode 100644 index 358141520..000000000 --- a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import * as React from 'react'; -import { Image } from 'ts/components/ui/image'; - -export interface UnlockWalletOnboardingStepProps {} - -export const UnlockWalletOnboardingStep: React.StatelessComponent<UnlockWalletOnboardingStepProps> = () => ( - <Image src="/images/unlock-mm.png" /> -); diff --git a/packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx b/packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx deleted file mode 100644 index 37eef867b..000000000 --- a/packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import * as React from 'react'; -import { Balance } from 'ts/components/ui/balance'; -import { Container } from 'ts/components/ui/container'; -import { IconButton } from 'ts/components/ui/icon_button'; -import { Text } from 'ts/components/ui/text'; -import { constants } from 'ts/utils/constants'; - -export interface WrapEthOnboardingStep1Props {} - -export const WrapEthOnboardingStep1: React.StatelessComponent<WrapEthOnboardingStep1Props> = () => ( - <div className="flex items-center flex-column"> - <Text> - You need to convert some of your ETH into tradeable <b>Wrapped ETH (WETH)</b>. - </Text> - <Container width="100%" marginTop="25px" marginBottom="15px" className="flex justify-center"> - <div className="flex flex-column items-center"> - <Text fontWeight={700}> 1 ETH </Text> - <img src="/images/eth_dollar.svg" height="75px" width="75x" /> - </div> - <Container marginRight="25px" marginLeft="25px" position="relative" top="20px"> - <Text fontSize="36px">=</Text> - </Container> - <div className="flex flex-column items-center"> - <Text fontWeight={700}> 1 WETH </Text> - <img src="/images/eth_token_erc20.svg" height="75px" width="75px" /> - </div> - </Container> - <Text> - Think of it like the coin version of a paper note. It has the same value, but some machines only take coins. - </Text> - </div> -); - -export interface WrapEthOnboardingStep2Props {} - -export const WrapEthOnboardingStep2: React.StatelessComponent<WrapEthOnboardingStep2Props> = () => ( - <div className="flex items-center flex-column"> - <Text>Wrapping your ETH is a reversable transaction, so don't worry about losing your ETH.</Text> - <Text> - Click - <Container display="inline-block" marginLeft="10px" marginRight="10px"> - <IconButton - iconName="zmdi-long-arrow-down" - color={colors.mediumBlue} - labelText="wrap" - display="inline-flex" - /> - </Container> - to wrap your ETH. - </Text> - </div> -); - -export interface WrapEthOnboardingStep3Props { - wethAmount: BigNumber; -} - -export const WrapEthOnboardingStep3: React.StatelessComponent<WrapEthOnboardingStep3Props> = ({ wethAmount }) => ( - <div className="flex items-center flex-column"> - <Text> - You have{' '} - <Balance - amount={wethAmount} - decimals={constants.DECIMAL_PLACES_ETH} - symbol={constants.ETHER_TOKEN_SYMBOL} - />{' '} - in your wallet. - {wethAmount.gt(0) && ' Great!'} - </Text> - <Container width="100%" marginTop="25px" marginBottom="15px" className="flex justify-center"> - <div className="flex flex-column items-center"> - <Text fontWeight={700}> 1 ETH </Text> - <img src="/images/eth_dollar.svg" height="75px" width="75x" /> - </div> - <Container marginRight="25px" marginLeft="25px" position="relative" top="20px"> - <Text fontSize="25px"> - <i className="zmdi zmdi-long-arrow-right" /> - </Text> - </Container> - <div className="flex flex-column items-center"> - <Text fontWeight={700}> 1 WETH </Text> - <img src="/images/eth_token_erc20.svg" height="75px" width="75px" /> - </div> - </Container> - </div> -); diff --git a/packages/website/ts/components/order_json.tsx b/packages/website/ts/components/order_json.tsx deleted file mode 100644 index f33681835..000000000 --- a/packages/website/ts/components/order_json.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import { BigNumber, fetchAsync, logUtils } from '@0x/utils'; -import * as _ from 'lodash'; -import Paper from 'material-ui/Paper'; -import TextField from 'material-ui/TextField'; -import * as React from 'react'; -import { CopyIcon } from 'ts/components/ui/copy_icon'; -import { SideToAssetToken, TokenByAddress, WebsitePaths } from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { utils } from 'ts/utils/utils'; - -interface OrderJSONProps { - exchangeContractIfExists: string; - orderExpiryTimestamp: BigNumber; - orderSignature: string; - orderTakerAddress: string; - orderMakerAddress: string; - orderSalt: BigNumber; - orderMakerFee: BigNumber; - orderTakerFee: BigNumber; - orderFeeRecipient: string; - sideToAssetToken: SideToAssetToken; - tokenByAddress: TokenByAddress; -} - -interface OrderJSONState { - shareLink: string; -} - -export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> { - constructor(props: OrderJSONProps) { - super(props); - this.state = { - shareLink: '', - }; - // tslint:disable-next-line:no-floating-promises - this._setShareLinkAsync(); - } - public render(): React.ReactNode { - const order = utils.generateOrder( - this.props.exchangeContractIfExists, - this.props.sideToAssetToken, - this.props.orderExpiryTimestamp, - this.props.orderTakerAddress, - this.props.orderMakerAddress, - this.props.orderMakerFee, - this.props.orderTakerFee, - this.props.orderFeeRecipient, - this.props.orderSignature, - this.props.tokenByAddress, - this.props.orderSalt, - ); - const orderJSON = JSON.stringify(order); - return ( - <div> - <div className="pb2"> - You have successfully generated and cryptographically signed an order! The following JSON contains - the order parameters and cryptographic signature that your counterparty will need to execute a trade - with you. - </div> - <div className="pb2 flex"> - <div className="inline-block pl1" style={{ top: 1 }}> - <CopyIcon data={orderJSON} callToAction="Copy" /> - </div> - </div> - <Paper className="center overflow-hidden"> - <TextField - id="orderJSON" - style={{ width: 710 }} - value={JSON.stringify(order, null, '\t')} - multiLine={true} - rows={2} - rowsMax={8} - underlineStyle={{ display: 'none' }} - /> - </Paper> - <div className="pt3 pb2 center"> - <div>Share your signed order!</div> - <div> - <div className="mx-auto overflow-hidden" style={{ width: 152 }}> - <TextField id={`${this.state.shareLink}-bitly`} value={this.state.shareLink} /> - </div> - </div> - <div className="mx-auto pt1 flex" style={{ width: 91 }}> - <div> - <i - style={{ cursor: 'pointer', fontSize: 29 }} - onClick={this._shareViaFacebook.bind(this)} - className="zmdi zmdi-facebook-box" - /> - </div> - <div className="pl1" style={{ position: 'relative', width: 28 }}> - <i - style={{ - cursor: 'pointer', - fontSize: 32, - position: 'absolute', - top: -2, - left: 8, - }} - onClick={this._shareViaEmailAsync.bind(this)} - className="zmdi zmdi-email" - /> - </div> - <div className="pl1"> - <i - style={{ cursor: 'pointer', fontSize: 29 }} - onClick={this._shareViaTwitterAsync.bind(this)} - className="zmdi zmdi-twitter-box" - /> - </div> - </div> - </div> - </div> - ); - } - private _shareViaTwitterAsync(): void { - const tweetText = encodeURIComponent(`Fill my order using the 0x protocol: ${this.state.shareLink}`); - window.open(`https://twitter.com/intent/tweet?text=${tweetText}`, 'Share your order', 'width=500,height=400'); - } - private _shareViaFacebook(): void { - (window as any).FB.ui( - { - display: 'popup', - href: this.state.shareLink, - method: 'share', - }, - _.noop.bind(_), - ); - } - private _shareViaEmailAsync(): void { - const encodedSubject = encodeURIComponent("Let's trade using the 0x protocol"); - const encodedBody = encodeURIComponent(`I generated an order with the 0x protocol. -You can see and fill it here: ${this.state.shareLink}`); - const mailToLink = `mailto:mail@example.org?subject=${encodedSubject}&body=${encodedBody}`; - window.open(mailToLink, '_blank'); - } - private async _setShareLinkAsync(): Promise<void> { - const shareLink = await this._generateShareLinkAsync(); - this.setState({ - shareLink, - }); - } - private async _generateShareLinkAsync(): Promise<string> { - const longUrl = encodeURIComponent(this._getOrderUrl()); - const bitlyRequestUrl = `${constants.URL_BITLY_API}/v3/shorten?access_token=${ - configs.BITLY_ACCESS_TOKEN - }&longUrl=${longUrl}`; - const response = await fetchAsync(bitlyRequestUrl); - const responseBody = await response.text(); - const bodyObj = JSON.parse(responseBody); - if (response.status !== 200 || bodyObj.status_code !== 200) { - // TODO: Show error message in UI - logUtils.log(`Unexpected status code: ${response.status} -> ${responseBody}`); - errorReporter.report(new Error(`Bitly returned non-200: ${JSON.stringify(response)}`)); - return ''; - } - return bodyObj.data.url; - } - private _getOrderUrl(): string { - const order = utils.generateOrder( - this.props.exchangeContractIfExists, - this.props.sideToAssetToken, - this.props.orderExpiryTimestamp, - this.props.orderTakerAddress, - this.props.orderMakerAddress, - this.props.orderMakerFee, - this.props.orderTakerFee, - this.props.orderFeeRecipient, - this.props.orderSignature, - this.props.tokenByAddress, - this.props.orderSalt, - ); - const orderJSONString = JSON.stringify(order); - const orderUrl = `${configs.BASE_URL}${WebsitePaths.Portal}/fill?order=${orderJSONString}`; - return orderUrl; - } -} diff --git a/packages/website/ts/components/portal/back_button.tsx b/packages/website/ts/components/portal/back_button.tsx deleted file mode 100644 index 9b4451196..000000000 --- a/packages/website/ts/components/portal/back_button.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Link, Styles } from '@0x/react-shared'; -import * as React from 'react'; -import { Island } from 'ts/components/ui/island'; -import { colors } from 'ts/style/colors'; - -export interface BackButtonProps { - to: string; - labelText: string; -} - -const BACK_BUTTON_HEIGHT = 28; - -const styles: Styles = { - backButton: { - height: BACK_BUTTON_HEIGHT, - paddingTop: 10, - borderRadius: BACK_BUTTON_HEIGHT, - }, - backButtonIcon: { - color: colors.mediumBlue, - fontSize: 20, - }, -}; - -export const BackButton = (props: BackButtonProps) => { - return ( - <div style={{ height: 65, paddingTop: 25 }}> - <Link to={props.to}> - <Island className="flex right" style={styles.backButton}> - <div style={{ marginLeft: 12 }}> - <i style={styles.backButtonIcon} className={`zmdi zmdi-arrow-left`} /> - </div> - <div style={{ marginLeft: 12, marginRight: 12 }}> - <div style={{ fontSize: 16, color: colors.mediumBlue }}>{props.labelText}</div> - </div> - </Island> - </Link> - </div> - ); -}; diff --git a/packages/website/ts/components/portal/drawer_menu.tsx b/packages/website/ts/components/portal/drawer_menu.tsx deleted file mode 100644 index 7280a6102..000000000 --- a/packages/website/ts/components/portal/drawer_menu.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { Styles } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Blockchain } from 'ts/blockchain'; -import { defaultMenuItemEntries, Menu } from 'ts/components/portal/menu'; -import { Identicon } from 'ts/components/ui/identicon'; -import { Text } from 'ts/components/ui/text'; -import { colors } from 'ts/style/colors'; -import { ProviderType, WebsitePaths } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -const IDENTICON_DIAMETER = 45; -const BORDER_RADIUS = '50%'; - -const styles: Styles = { - root: { - backgroundColor: colors.drawerMenuBackground, - width: '100%', - height: '100%', - }, - identicon: { - borderWidth: 3, - borderStyle: 'solid', - borderColor: colors.white, - borderRadius: BORDER_RADIUS, - MozBorderRadius: BORDER_RADIUS, - WebkitBorderRadius: BORDER_RADIUS, - }, -}; - -export interface DrawerMenuProps { - selectedPath?: string; - userAddress?: string; - injectedProviderName: string; - providerType: ProviderType; - blockchain?: Blockchain; - blockchainIsLoaded: boolean; -} -export const DrawerMenu = (props: DrawerMenuProps) => { - const relayerItemEntry = { - to: WebsitePaths.Portal, - labelText: 'Relayer ecosystem', - iconName: 'zmdi-portable-wifi', - }; - const menuItemEntries = _.concat(relayerItemEntry, defaultMenuItemEntries); - const accountState = utils.getAccountState( - props.blockchainIsLoaded && !_.isUndefined(props.blockchain), - props.providerType, - props.injectedProviderName, - props.userAddress, - ); - const displayMessage = utils.getReadableAccountState(accountState, props.userAddress); - return ( - <div style={styles.root}> - <Header userAddress={props.userAddress} displayMessage={displayMessage} /> - <Menu selectedPath={props.selectedPath} menuItemEntries={menuItemEntries} /> - </div> - ); -}; - -interface HeaderProps { - userAddress?: string; - displayMessage: string; -} -const Header = (props: HeaderProps) => { - return ( - <div className="flex flex-center py4"> - <div className="flex flex-column mx-auto items-center"> - <Identicon address={props.userAddress} diameter={IDENTICON_DIAMETER} style={styles.identicon} /> - <Text className="pt2" fontColor={colors.white}> - {props.displayMessage} - </Text> - </div> - </div> - ); -}; diff --git a/packages/website/ts/components/portal/loading.tsx b/packages/website/ts/components/portal/loading.tsx deleted file mode 100644 index d804dd1b8..000000000 --- a/packages/website/ts/components/portal/loading.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import CircularProgress from 'material-ui/CircularProgress'; -import * as React from 'react'; - -const CIRCULAR_PROGRESS_SIZE = 40; -const CIRCULAR_PROGRESS_THICKNESS = 5; - -export interface LoadingProps { - isLoading: boolean; - content: React.ReactNode; -} -export const Loading = (props: LoadingProps) => { - if (props.isLoading) { - return ( - <div className="center"> - <CircularProgress size={CIRCULAR_PROGRESS_SIZE} thickness={CIRCULAR_PROGRESS_THICKNESS} /> - </div> - ); - } else { - return <div>{props.content}</div>; - } -}; diff --git a/packages/website/ts/components/portal/menu.tsx b/packages/website/ts/components/portal/menu.tsx deleted file mode 100644 index d59101686..000000000 --- a/packages/website/ts/components/portal/menu.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { Styles } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { CustomMenuItem } from 'ts/components/ui/custom_menu_item'; -import { colors } from 'ts/style/colors'; -import { WebsitePaths } from 'ts/types'; - -export interface MenuTheme { - paddingLeft: number; - textColor: string; - iconColor: string; - selectedIconColor: string; - selectedBackgroundColor: string; -} - -export interface MenuItemEntry { - to: string; - labelText: string; - iconName: string; -} - -export interface MenuProps { - selectedPath?: string; - theme?: MenuTheme; - menuItemEntries?: MenuItemEntry[]; -} - -export const defaultMenuItemEntries: MenuItemEntry[] = [ - { - to: `${WebsitePaths.Portal}/account`, - labelText: 'Account overview', - iconName: 'zmdi-balance-wallet', - }, - { - to: `${WebsitePaths.Portal}/trades`, - labelText: 'Trade history', - iconName: 'zmdi-format-list-bulleted', - }, - { - to: `${WebsitePaths.Portal}/weth`, - labelText: 'Wrapped ETH', - iconName: 'zmdi-circle-o', - }, - { - to: `${WebsitePaths.Portal}/generate`, - labelText: 'Generate order', - iconName: 'zmdi-arrow-right-top', - }, - { - to: `${WebsitePaths.Portal}/fill`, - labelText: 'Fill order', - iconName: 'zmdi-arrow-left-bottom', - }, -]; - -const DEFAULT_MENU_THEME: MenuTheme = { - paddingLeft: 30, - textColor: colors.white, - iconColor: colors.white, - selectedIconColor: colors.white, - selectedBackgroundColor: colors.menuItemDefaultSelectedBackground, -}; - -export const Menu: React.StatelessComponent<MenuProps> = (props: MenuProps) => { - return ( - <div> - {_.map(props.menuItemEntries, entry => { - const isSelected = entry.to === props.selectedPath; - return ( - <CustomMenuItem key={entry.to} to={entry.to}> - <MenuItemLabel - title={entry.labelText} - iconName={entry.iconName} - selected={isSelected} - theme={props.theme} - /> - </CustomMenuItem> - ); - })} - </div> - ); -}; -Menu.defaultProps = { - theme: DEFAULT_MENU_THEME, - menuItemEntries: defaultMenuItemEntries, -}; - -interface MenuItemLabelProps { - title: string; - iconName: string; - selected: boolean; - theme: MenuTheme; -} -const MenuItemLabel: React.StatelessComponent<MenuItemLabelProps> = (props: MenuItemLabelProps) => { - const styles: Styles = { - root: { - backgroundColor: props.selected ? props.theme.selectedBackgroundColor : undefined, - paddingLeft: props.theme.paddingLeft, - }, - icon: { - color: props.selected ? props.theme.selectedIconColor : props.theme.iconColor, - fontSize: 20, - }, - text: { - color: props.theme.textColor, - fontWeight: props.selected ? 'bold' : 'normal', - fontSize: 16, - }, - }; - return ( - <div className="flex py2" style={styles.root}> - <div className="pr1"> - <i style={styles.icon} className={`zmdi ${props.iconName}`} /> - </div> - <div className="pl1" style={styles.text}> - {props.title} - </div> - </div> - ); -}; diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx deleted file mode 100644 index 6ebbf8d1f..000000000 --- a/packages/website/ts/components/portal/portal.tsx +++ /dev/null @@ -1,749 +0,0 @@ -import { colors, Link } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import * as React from 'react'; -import * as DocumentTitle from 'react-document-title'; -import { Route, RouteComponentProps, Switch } from 'react-router-dom'; - -import { Blockchain } from 'ts/blockchain'; -import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; -import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; -import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; -import { EthWrappers } from 'ts/components/eth_wrappers'; -import { FillOrder } from 'ts/components/fill_order'; -import { AssetPicker } from 'ts/components/generate_order/asset_picker'; -import { MetaTags } from 'ts/components/meta_tags'; -import { BackButton } from 'ts/components/portal/back_button'; -import { Loading } from 'ts/components/portal/loading'; -import { Menu, MenuTheme } from 'ts/components/portal/menu'; -import { Section } from 'ts/components/portal/section'; -import { TextHeader } from 'ts/components/portal/text_header'; -import { RelayerIndex, RelayerIndexCellStyle } from 'ts/components/relayer_index/relayer_index'; -import { TokenBalances } from 'ts/components/token_balances'; -import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar'; -import { TradeHistory } from 'ts/components/trade_history/trade_history'; -import { Container } from 'ts/components/ui/container'; -import { FlashMessage } from 'ts/components/ui/flash_message'; -import { Image } from 'ts/components/ui/image'; -import { PointerDirection } from 'ts/components/ui/pointer'; -import { Text } from 'ts/components/ui/text'; -import { Wallet } from 'ts/components/wallet/wallet'; -import { GenerateOrderForm } from 'ts/containers/generate_order_form'; -import { PortalOnboardingFlow } from 'ts/containers/portal_onboarding_flow'; -import { localStorage } from 'ts/local_storage/local_storage'; -import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; -import { FullscreenMessage } from 'ts/pages/fullscreen_message'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { zIndex } from 'ts/style/z_index'; -import { - BlockchainErrs, - HashData, - ItemByAddress, - PortalOrder, - ProviderType, - ScreenWidths, - Token, - TokenByAddress, - TokenStateByAddress, - TokenVisibility, - WebsitePaths, -} from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; -import { backendClient } from 'ts/utils/backend_client'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { orderParser } from 'ts/utils/order_parser'; -import { Translate } from 'ts/utils/translate'; -import { utils } from 'ts/utils/utils'; - -export interface PortalProps { - blockchainErr: BlockchainErrs; - blockchainIsLoaded: boolean; - dispatcher: Dispatcher; - hashData: HashData; - injectedProviderName: string; - networkId: number; - nodeVersion: string; - orderFillAmount: BigNumber; - providerType: ProviderType; - screenWidth: ScreenWidths; - tokenByAddress: TokenByAddress; - userEtherBalanceInWei?: BigNumber; - userAddress: string; - shouldBlockchainErrDialogBeOpen: boolean; - userSuppliedOrderCache: PortalOrder; - location: Location; - flashMessage?: string | React.ReactNode; - lastForceTokenStateRefetch: number; - translate: Translate; - isPortalOnboardingShowing: boolean; - portalOnboardingStep: number; -} - -interface PortalState { - prevNetworkId: number; - prevNodeVersion: string; - prevUserAddress: string; - prevPathname: string; - isDisclaimerDialogOpen: boolean; - isLedgerDialogOpen: boolean; - tokenManagementState: TokenManagementState; - trackedTokenStateByAddress: TokenStateByAddress; -} - -interface AccountManagementItem { - pathName: string; - headerText?: string; - render: () => React.ReactNode; -} - -enum TokenManagementState { - Add = 'Add', - Remove = 'Remove', - None = 'None', -} - -const THROTTLE_TIMEOUT = 100; -const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded); -const LEFT_COLUMN_WIDTH = 346; -const MENU_PADDING_LEFT = 185; -const LARGE_LAYOUT_MAX_WIDTH = 1200; -const SIDE_PADDING = 20; -const DOCUMENT_TITLE = '0x Portal'; -const DOCUMENT_DESCRIPTION = 'Learn about and trade on 0x Relayers'; - -export class Portal extends React.Component<PortalProps, PortalState> { - private _blockchain: Blockchain; - private readonly _sharedOrderIfExists: PortalOrder; - private readonly _throttledScreenWidthUpdate: () => void; - constructor(props: PortalProps) { - super(props); - this._sharedOrderIfExists = orderParser.parseQueryString(window.location.search); - this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); - const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); - const hasAcceptedDisclaimer = - !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer); - const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress( - this._getCurrentTrackedTokens(), - ); - this.state = { - prevNetworkId: this.props.networkId, - prevNodeVersion: this.props.nodeVersion, - prevUserAddress: this.props.userAddress, - prevPathname: this.props.location.pathname, - isDisclaimerDialogOpen: !hasAcceptedDisclaimer, - tokenManagementState: TokenManagementState.None, - isLedgerDialogOpen: false, - trackedTokenStateByAddress: initialTrackedTokenStateByAddress, - }; - } - public componentDidMount(): void { - window.addEventListener('resize', this._throttledScreenWidthUpdate); - window.scrollTo(0, 0); - } - public componentWillMount(): void { - this._blockchain = new Blockchain(this.props.dispatcher); - } - public componentWillUnmount(): void { - this._blockchain.destroy(); - window.removeEventListener('resize', this._throttledScreenWidthUpdate); - // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered - // the initialization process always occurs from the same base state. This helps avoid - // initialization inconsistencies (i.e While the portal was unrendered, the user might have - // become disconnected from their backing Ethereum node, changed user accounts, etc...) - this.props.dispatcher.resetState(); - } - public componentDidUpdate(prevProps: PortalProps): void { - if (!prevProps.blockchainIsLoaded && this.props.blockchainIsLoaded) { - // tslint:disable-next-line:no-floating-promises - this._fetchBalancesAndAllowancesAsync(this._getCurrentTrackedTokensAddresses()); - } - } - public componentWillReceiveProps(nextProps: PortalProps): void { - if (nextProps.networkId !== this.state.prevNetworkId) { - // tslint:disable-next-line:no-floating-promises - this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); - this.setState({ - prevNetworkId: nextProps.networkId, - }); - } - if (nextProps.userAddress !== this.state.prevUserAddress) { - const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress; - // tslint:disable-next-line:no-floating-promises - this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress); - this.setState({ - prevUserAddress: nextProps.userAddress, - }); - } - if (nextProps.nodeVersion !== this.state.prevNodeVersion) { - // tslint:disable-next-line:no-floating-promises - this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); - } - if (nextProps.location.pathname !== this.state.prevPathname) { - this.setState({ - prevPathname: nextProps.location.pathname, - }); - } - - // If the address changed, but the network did not, we can just refetch the currently tracked tokens. - if ( - (nextProps.userAddress !== this.props.userAddress && nextProps.networkId === this.props.networkId) || - nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch - ) { - // tslint:disable-next-line:no-floating-promises - this._fetchBalancesAndAllowancesAsync(this._getCurrentTrackedTokensAddresses()); - } - - const nextTrackedTokens = utils.getTrackedTokens(nextProps.tokenByAddress); - const trackedTokens = this._getCurrentTrackedTokens(); - - if (!_.isEqual(nextTrackedTokens, trackedTokens)) { - const newTokens = _.difference(nextTrackedTokens, trackedTokens); - const newTokenAddresses = _.map(newTokens, token => token.address); - // Add placeholder entry for this token to the state, since fetching the - // balance/allowance is asynchronous - const trackedTokenStateByAddress = { ...this.state.trackedTokenStateByAddress }; - for (const tokenAddress of newTokenAddresses) { - trackedTokenStateByAddress[tokenAddress] = { - balance: new BigNumber(0), - allowance: new BigNumber(0), - isLoaded: false, - }; - } - this.setState( - { - trackedTokenStateByAddress, - }, - () => { - // Fetch the actual balance/allowance. - // tslint:disable-next-line:no-floating-promises - this._fetchBalancesAndAllowancesAsync(newTokenAddresses); - }, - ); - } - } - public render(): React.ReactNode { - const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( - this.props.dispatcher, - ); - const isAssetPickerDialogOpen = this.state.tokenManagementState !== TokenManagementState.None; - const tokenVisibility = - this.state.tokenManagementState === TokenManagementState.Add - ? TokenVisibility.Untracked - : TokenVisibility.Tracked; - return ( - <Container> - <MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} /> - <DocumentTitle title={DOCUMENT_TITLE} /> - <TopBar - userAddress={this.props.userAddress} - networkId={this.props.networkId} - injectedProviderName={this.props.injectedProviderName} - onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} - dispatcher={this.props.dispatcher} - providerType={this.props.providerType} - blockchainIsLoaded={this.props.blockchainIsLoaded} - location={this.props.location} - blockchain={this._blockchain} - translate={this.props.translate} - displayType={TopBarDisplayType.Expanded} - style={{ - backgroundColor: colors.lightestGrey, - position: 'fixed', - zIndex: zIndex.topBar, - }} - maxWidth={LARGE_LAYOUT_MAX_WIDTH} - /> - <Container marginTop={TOP_BAR_HEIGHT} minHeight="100vh" backgroundColor={colors.lightestGrey}> - <Switch> - <Route path={`${WebsitePaths.Portal}/:route`} render={this._renderOtherRoutes.bind(this)} /> - <Route - exact={true} - path={`${WebsitePaths.Portal}/`} - render={this._renderMainRoute.bind(this)} - /> - </Switch> - <BlockchainErrDialog - blockchain={this._blockchain} - blockchainErr={this.props.blockchainErr} - isOpen={this.props.shouldBlockchainErrDialogBeOpen} - userAddress={this.props.userAddress} - toggleDialogFn={updateShouldBlockchainErrDialogBeOpen} - networkId={this.props.networkId} - /> - <FlashMessage dispatcher={this.props.dispatcher} flashMessage={this.props.flashMessage} /> - - <LedgerConfigDialog - providerType={this.props.providerType} - networkId={this.props.networkId} - blockchain={this._blockchain} - dispatcher={this.props.dispatcher} - toggleDialogFn={this._onToggleLedgerDialog.bind(this)} - isOpen={this.state.isLedgerDialogOpen} - /> - - <AssetPicker - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this._blockchain} - dispatcher={this.props.dispatcher} - isOpen={isAssetPickerDialogOpen} - currentTokenAddress={''} - onTokenChosen={this._onTokenChosen.bind(this)} - tokenByAddress={this.props.tokenByAddress} - tokenVisibility={tokenVisibility} - /> - </Container> - </Container> - ); - } - private _renderMainRoute(): React.ReactNode { - if (this._isSmallScreen()) { - return <SmallLayout content={this._renderRelayerIndexSection()} />; - } else { - return <LargeLayout left={this._renderWalletSection()} right={this._renderRelayerIndexSection()} />; - } - } - private _renderOtherRoutes(routeComponentProps: RouteComponentProps<any>): React.ReactNode { - if (this._isSmallScreen()) { - return <SmallLayout content={this._renderAccountManagement()} />; - } else { - return <LargeLayout left={this._renderMenu(routeComponentProps)} right={this._renderAccountManagement()} />; - } - } - private _renderMenu(routeComponentProps: RouteComponentProps<any>): React.ReactNode { - const menuTheme: MenuTheme = { - paddingLeft: MENU_PADDING_LEFT, - textColor: colors.darkerGrey, - iconColor: colors.darkerGrey, - selectedIconColor: colors.yellow800, - selectedBackgroundColor: 'transparent', - }; - return ( - <Section - header={<BackButton to={WebsitePaths.Portal} labelText="Back to Relayers" />} - body={<Menu selectedPath={routeComponentProps.location.pathname} theme={menuTheme} />} - /> - ); - } - private _renderWallet(): React.ReactNode { - const isMobile = utils.isMobileWidth(this.props.screenWidth); - // We need room to scroll down for mobile onboarding - const marginBottom = isMobile ? '250px' : '15px'; - return ( - <div> - <Container className="flex flex-column items-center"> - {isMobile && ( - <Container marginTop="20px" marginBottom="20px"> - {this._renderStartOnboarding()} - </Container> - )} - <Container marginBottom={marginBottom} width="100%"> - <Wallet - style={ - !isMobile && this.props.isPortalOnboardingShowing - ? { zIndex: zIndex.aboveOverlay, position: 'relative' } - : undefined - } - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this._blockchain} - blockchainIsLoaded={this.props.blockchainIsLoaded} - blockchainErr={this.props.blockchainErr} - dispatcher={this.props.dispatcher} - tokenByAddress={this.props.tokenByAddress} - trackedTokens={this._getCurrentTrackedTokens()} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - injectedProviderName={this.props.injectedProviderName} - providerType={this.props.providerType} - screenWidth={this.props.screenWidth} - location={this.props.location} - trackedTokenStateByAddress={this.state.trackedTokenStateByAddress} - onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} - onAddToken={this._onAddToken.bind(this)} - onRemoveToken={this._onRemoveToken.bind(this)} - refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)} - toggleTooltipDirection={ - this.props.isPortalOnboardingShowing ? PointerDirection.Left : PointerDirection.Right - } - /> - </Container> - {!isMobile && <Container marginTop="8px">{this._renderStartOnboarding()}</Container>} - </Container> - <PortalOnboardingFlow - blockchain={this._blockchain} - trackedTokenStateByAddress={this.state.trackedTokenStateByAddress} - refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)} - /> - </div> - ); - } - private _renderStartOnboarding(): React.ReactNode { - const isMobile = utils.isMobileWidth(this.props.screenWidth); - const shouldStartOnboarding = !isMobile || this.props.location.pathname === `${WebsitePaths.Portal}/account`; - const startOnboarding = ( - <Container className="flex items-center center"> - <Text fontColor={colors.mediumBlue} fontSize="16px" onClick={this._startOnboarding.bind(this)}> - Set up your account to start trading - </Text> - <Container marginLeft="8px" paddingTop="3px"> - <Image src="/images/setup_account_icon.svg" height="20px" width="20x" /> - </Container> - </Container> - ); - return !shouldStartOnboarding ? ( - <Link to={`${WebsitePaths.Portal}/account`}>{startOnboarding}</Link> - ) : ( - startOnboarding - ); - } - private _startOnboarding(): void { - analytics.track('Onboarding Started', { - reason: 'manual', - stepIndex: this.props.portalOnboardingStep, - }); - this.props.dispatcher.updatePortalOnboardingShowing(true); - } - private _renderWalletSection(): React.ReactNode { - return <Section header={<TextHeader labelText="Your Account" />} body={this._renderWallet()} />; - } - private _renderAccountManagement(): React.ReactNode { - const accountManagementItems: AccountManagementItem[] = [ - { - pathName: `${WebsitePaths.Portal}/weth`, - headerText: 'Wrapped ETH', - render: this._renderEthWrapper.bind(this), - }, - { - pathName: `${WebsitePaths.Portal}/account`, - headerText: this._isSmallScreen() ? undefined : 'Your Account', - render: this._isSmallScreen() ? this._renderWallet.bind(this) : this._renderTokenBalances.bind(this), - }, - { - pathName: `${WebsitePaths.Portal}/trades`, - headerText: 'Trade History', - render: this._renderTradeHistory.bind(this), - }, - { - pathName: `${WebsitePaths.Portal}/generate`, - headerText: 'Generate Order', - render: this._renderGenerateOrderForm.bind(this), - }, - { - pathName: `${WebsitePaths.Portal}/fill`, - headerText: 'Fill Order', - render: this._renderFillOrder.bind(this), - }, - ]; - return ( - <div> - <Switch> - {_.map(accountManagementItems, item => { - return ( - <Route - key={item.pathName} - path={item.pathName} - render={this._renderAccountManagementItem.bind(this, item)} - /> - ); - })} - } - <Route render={this._renderNotFoundMessage.bind(this)} /> - </Switch> - <PortalDisclaimerDialog - isOpen={this.state.isDisclaimerDialogOpen} - onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)} - /> - </div> - ); - } - private _renderAccountManagementItem(item: AccountManagementItem): React.ReactNode { - return ( - <Section - header={!_.isUndefined(item.headerText) && <TextHeader labelText={item.headerText} />} - body={<Loading isLoading={!this.props.blockchainIsLoaded} content={item.render()} />} - /> - ); - } - private _renderEthWrapper(): React.ReactNode { - return ( - <EthWrappers - networkId={this.props.networkId} - blockchain={this._blockchain} - dispatcher={this.props.dispatcher} - tokenByAddress={this.props.tokenByAddress} - userAddress={this.props.userAddress} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - isFullWidth={true} - /> - ); - } - private _renderTradeHistory(): React.ReactNode { - return ( - <TradeHistory - tokenByAddress={this.props.tokenByAddress} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - isFullWidth={true} - shouldHideHeader={true} - isScrollable={false} - /> - ); - } - private _renderGenerateOrderForm(): React.ReactNode { - return ( - <GenerateOrderForm - blockchain={this._blockchain} - hashData={this.props.hashData} - dispatcher={this.props.dispatcher} - isFullWidth={true} - shouldHideHeader={true} - /> - ); - } - private _renderFillOrder(): React.ReactNode { - const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache) - ? this.props.userSuppliedOrderCache - : this._sharedOrderIfExists; - return ( - <FillOrder - blockchain={this._blockchain} - blockchainErr={this.props.blockchainErr} - initialOrder={initialFillOrder} - isOrderInUrl={!_.isUndefined(this._sharedOrderIfExists)} - orderFillAmount={this.props.orderFillAmount} - networkId={this.props.networkId} - userAddress={this.props.userAddress} - tokenByAddress={this.props.tokenByAddress} - dispatcher={this.props.dispatcher} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - isFullWidth={true} - shouldHideHeader={true} - /> - ); - } - private _renderTokenBalances(): React.ReactNode { - return ( - <TokenBalances - blockchain={this._blockchain} - blockchainErr={this.props.blockchainErr} - blockchainIsLoaded={this.props.blockchainIsLoaded} - dispatcher={this.props.dispatcher} - screenWidth={this.props.screenWidth} - tokenByAddress={this.props.tokenByAddress} - trackedTokens={this._getCurrentTrackedTokens()} - userAddress={this.props.userAddress} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - networkId={this.props.networkId} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - isFullWidth={true} - /> - ); - } - private _renderRelayerIndexSection(): React.ReactNode { - const isMobile = utils.isMobileWidth(this.props.screenWidth); - // TODO(bmillman): revert RelayerIndex cellStyle to Expanded once data pipeline is tracking v2 volume - return ( - <Section - header={!isMobile && <TextHeader labelText="0x Relayers" />} - body={ - <Container className="flex flex-column"> - {isMobile && ( - <Container marginTop="20px" marginBottom="20px"> - {this._renderStartOnboarding()} - </Container> - )} - <RelayerIndex - networkId={this.props.networkId} - screenWidth={this.props.screenWidth} - cellStyle={RelayerIndexCellStyle.Minimized} - /> - </Container> - } - /> - ); - } - private _renderNotFoundMessage(): React.ReactNode { - return ( - <FullscreenMessage - headerText="404 Not Found" - bodyText="Hm... looks like we couldn't find what you are looking for." - /> - ); - } - private _onTokenChosen(tokenAddress: string): void { - if (_.isEmpty(tokenAddress)) { - this.setState({ - tokenManagementState: TokenManagementState.None, - }); - return; - } - const token = this.props.tokenByAddress[tokenAddress]; - const isDefaultTrackedToken = _.includes(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, token.symbol); - if (this.state.tokenManagementState === TokenManagementState.Remove && !isDefaultTrackedToken) { - if (token.isRegistered) { - // Remove the token from tracked tokens - const newToken: Token = { - ...token, - trackedTimestamp: undefined, - }; - this.props.dispatcher.updateTokenByAddress([newToken]); - } else { - this.props.dispatcher.removeTokenToTokenByAddress(token); - } - trackedTokenStorage.removeTrackedToken(this.props.userAddress, this.props.networkId, tokenAddress); - } else if (isDefaultTrackedToken) { - this.props.dispatcher.showFlashMessage(`Cannot remove ${token.name} because it's a default token`); - } - this.setState({ - tokenManagementState: TokenManagementState.None, - }); - } - private _onToggleLedgerDialog(): void { - this.setState({ - isLedgerDialogOpen: !this.state.isLedgerDialogOpen, - }); - } - private _onAddToken(): void { - this.setState({ - tokenManagementState: TokenManagementState.Add, - }); - } - private _onRemoveToken(): void { - this.setState({ - tokenManagementState: TokenManagementState.Remove, - }); - } - private _onPortalDisclaimerAccepted(): void { - localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); - this.setState({ - isDisclaimerDialogOpen: false, - }); - } - private _updateScreenWidth(): void { - const newScreenWidth = utils.getScreenWidth(); - this.props.dispatcher.updateScreenWidth(newScreenWidth); - } - private _isSmallScreen(): boolean { - const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; - return isSmallScreen; - } - private _getCurrentTrackedTokens(): Token[] { - return utils.getTrackedTokens(this.props.tokenByAddress); - } - private _getCurrentTrackedTokensAddresses(): string[] { - return _.map(this._getCurrentTrackedTokens(), token => token.address); - } - private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]): TokenStateByAddress { - const trackedTokenStateByAddress: TokenStateByAddress = {}; - _.each(trackedTokens, token => { - trackedTokenStateByAddress[token.address] = { - balance: new BigNumber(0), - allowance: new BigNumber(0), - isLoaded: false, - }; - }); - return trackedTokenStateByAddress; - } - - private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]): Promise<void> { - if (_.isEmpty(tokenAddresses)) { - return; - } - const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress; - const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; - const balancesAndAllowances = await Promise.all( - tokenAddresses.map(async tokenAddress => { - return this._blockchain.getTokenBalanceAndAllowanceAsync(userAddressIfExists, tokenAddress); - }), - ); - const priceByAddress = await this._getPriceByAddressAsync(tokenAddresses); - for (let i = 0; i < tokenAddresses.length; i++) { - // Order is preserved in Promise.all - const [balance, allowance] = balancesAndAllowances[i]; - const tokenAddress = tokenAddresses[i]; - trackedTokenStateByAddress[tokenAddress] = { - balance, - allowance, - isLoaded: true, - price: priceByAddress[tokenAddress], - }; - } - this.setState({ - trackedTokenStateByAddress, - }); - } - - private async _getPriceByAddressAsync(tokenAddresses: string[]): Promise<ItemByAddress<BigNumber>> { - if (_.isEmpty(tokenAddresses)) { - return {}; - } - // for each input token address, search for the corresponding symbol in this.props.tokenByAddress, if it exists - // create a mapping from existing symbols -> address - const tokenAddressBySymbol: { [symbol: string]: string } = {}; - _.each(tokenAddresses, address => { - const tokenIfExists = _.get(this.props.tokenByAddress, address); - if (!_.isUndefined(tokenIfExists)) { - const symbol = tokenIfExists.symbol; - tokenAddressBySymbol[symbol] = address; - } - }); - const tokenSymbols = _.keys(tokenAddressBySymbol); - try { - const priceBySymbol = await backendClient.getPriceInfoAsync(tokenSymbols); - const priceByAddress = _.mapKeys(priceBySymbol, (_value, symbol) => _.get(tokenAddressBySymbol, symbol)); - const result = _.mapValues(priceByAddress, price => { - const priceBigNumber = new BigNumber(price); - return priceBigNumber; - }); - return result; - } catch (err) { - return {}; - } - } - - private async _refetchTokenStateAsync(tokenAddress: string): Promise<void> { - await this._fetchBalancesAndAllowancesAsync([tokenAddress]); - } -} - -interface LargeLayoutProps { - left: React.ReactNode; - right: React.ReactNode; -} -const LargeLayout = (props: LargeLayoutProps) => { - return ( - <Container - className="mx-auto flex flex-center" - maxWidth={LARGE_LAYOUT_MAX_WIDTH} - paddingLeft={SIDE_PADDING} - paddingRight={SIDE_PADDING} - > - <div className="flex-last"> - <Container width={LEFT_COLUMN_WIDTH} position="fixed" zIndex={zIndex.aboveTopBar}> - {props.left} - </Container> - </div> - <Container className="flex-auto" marginLeft={LEFT_COLUMN_WIDTH}> - <Container className="flex-auto" marginLeft={SIDE_PADDING}> - {props.right} - </Container> - </Container> - </Container> - ); -}; - -interface SmallLayoutProps { - content: React.ReactNode; -} -const SmallLayout = (props: SmallLayoutProps) => { - return ( - <div className="flex flex-center"> - <Container className="flex-auto" paddingLeft={SIDE_PADDING} paddingRight={SIDE_PADDING}> - {props.content} - </Container> - </div> - ); -}; // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/portal/section.tsx b/packages/website/ts/components/portal/section.tsx deleted file mode 100644 index b6c9fd098..000000000 --- a/packages/website/ts/components/portal/section.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from 'react'; - -export interface SectionProps { - header: React.ReactNode; - body: React.ReactNode; -} -export const Section = (props: SectionProps) => { - return ( - <div className="flex flex-column"> - {props.header} - {props.body} - </div> - ); -}; diff --git a/packages/website/ts/components/portal/text_header.tsx b/packages/website/ts/components/portal/text_header.tsx deleted file mode 100644 index b6045b832..000000000 --- a/packages/website/ts/components/portal/text_header.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; - -import { Text } from 'ts/components/ui/text'; - -export interface TextHeaderProps { - labelText: string; -} - -export const TextHeader = (props: TextHeaderProps) => { - return ( - <Text className="pt3 pb2" fontWeight="bold" fontSize="16px" fontColor={colors.darkestGrey}> - {props.labelText} - </Text> - ); -}; diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx deleted file mode 100644 index 7f1b4ebb4..000000000 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { Styles } from '@0x/react-shared'; -import * as _ from 'lodash'; -import { GridTile as PlainGridTile } from 'material-ui/GridList'; -import * as React from 'react'; -import { analytics } from 'ts/utils/analytics'; - -import { TopTokens } from 'ts/components/relayer_index/relayer_top_tokens'; -import { Container } from 'ts/components/ui/container'; -import { Image } from 'ts/components/ui/image'; -import { Island } from 'ts/components/ui/island'; -import { colors } from 'ts/style/colors'; -import { media } from 'ts/style/media'; -import { styled } from 'ts/style/theme'; -import { WebsiteBackendRelayerInfo } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -export enum RelayerGridTileStyle { - Expanded = 0, - Minimized, -} - -export interface RelayerGridTileProps { - relayerInfo: WebsiteBackendRelayerInfo; - networkId: number; - style: RelayerGridTileStyle; -} - -const styles: Styles = { - root: { - boxSizing: 'border-box', - // All material UI components have position: relative - // which creates a new stacking context and makes z-index stuff impossible. So reset. - position: 'static', - }, - innerDiv: { - height: '100%', - boxSizing: 'border-box', - }, - expandedHeader: { - height: '50%', - width: '100%', - }, - minimizedHeader: { - height: '100%', - width: '100%', - }, - body: { - height: '50%', - width: '100%', - boxSizing: 'border-box', - padding: 12, - }, - weeklyTradeVolumeLabel: { - fontSize: 14, - color: colors.mediumBlue, - }, - subLabel: { - fontSize: 12, - color: colors.lightGrey, - }, - relayerNameLabel: { - fontSize: 16, - fontWeight: 'bold', - color: colors.black, - }, -}; - -const FALLBACK_IMG_SRC = '/images/relayer_fallback.png'; -const FALLBACK_PRIMARY_COLOR = colors.grey300; -const NO_CONTENT_MESSAGE = '--'; -const RELAYER_ICON_HEIGHT = '110px'; - -export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (props: RelayerGridTileProps) => { - const link = props.relayerInfo.appUrl || props.relayerInfo.url; - const topTokens = props.relayerInfo.topTokens; - const weeklyTxnVolume = props.relayerInfo.weeklyTxnVolume; - const onClick = () => { - analytics.track('Relayer Click', { - name: props.relayerInfo.name, - }); - utils.openUrl(link); - }; - const headerImageUrl = props.relayerInfo.logoImgUrl; - const headerBackgroundColor = - !_.isUndefined(headerImageUrl) && !_.isUndefined(props.relayerInfo.primaryColor) - ? props.relayerInfo.primaryColor - : FALLBACK_PRIMARY_COLOR; - const isExpanded = props.style === RelayerGridTileStyle.Expanded; - const headerStyle = isExpanded ? styles.expandedHeader : styles.minimizedHeader; - return ( - <Island style={styles.root} Component={GridTile}> - <div style={styles.innerDiv} onClick={onClick}> - <div className="flex items-center" style={{ ...headerStyle, backgroundColor: headerBackgroundColor }}> - <Image - className="mx-auto" - src={props.relayerInfo.logoImgUrl} - fallbackSrc={FALLBACK_IMG_SRC} - height={RELAYER_ICON_HEIGHT} - /> - </div> - {isExpanded && ( - <div style={styles.body}> - <div className="pb1" style={styles.relayerNameLabel}> - {props.relayerInfo.name} - </div> - <Section titleText="Weekly Trade Volume"> - {!_.isUndefined(weeklyTxnVolume) && ( - <div style={styles.weeklyTradeVolumeLabel}>{props.relayerInfo.weeklyTxnVolume}</div> - )} - </Section> - <Container marginTop="10px"> - <Section titleText="Top Tokens"> - {!_.isEmpty(topTokens) && <TopTokens tokens={topTokens} networkId={props.networkId} />} - </Section> - </Container> - </div> - )} - </div> - </Island> - ); -}; - -const GridTile = styled(PlainGridTile)` - cursor: pointer; - &:hover { - transition: transform 0.2s ease; - transform: translate(0px, -3px); - } - ${media.small` - transform: none !important; - transition: none !important; - `}; -`; - -interface SectionProps { - titleText: string; - children?: React.ReactNode; -} -const Section = (props: SectionProps) => { - return ( - <div> - <div style={styles.subLabel}>{props.titleText}</div> - <Container marginTop="6px">{props.children || <NoContent />}</Container> - </div> - ); -}; - -const NoContent = () => <div style={styles.subLabel}>{NO_CONTENT_MESSAGE}</div>; diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx deleted file mode 100644 index e88c20d7e..000000000 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import * as _ from 'lodash'; -import CircularProgress from 'material-ui/CircularProgress'; -import { GridList } from 'material-ui/GridList'; -import * as React from 'react'; - -import { RelayerGridTile, RelayerGridTileStyle } from 'ts/components/relayer_index/relayer_grid_tile'; -import { Retry } from 'ts/components/ui/retry'; -import { ScreenWidths, WebsiteBackendRelayerInfo } from 'ts/types'; -import { backendClient } from 'ts/utils/backend_client'; - -export enum RelayerIndexCellStyle { - Expanded = 0, - Minimized, -} - -export interface RelayerIndexProps { - networkId: number; - screenWidth: ScreenWidths; - cellStyle: RelayerIndexCellStyle; -} - -interface RelayerIndexState { - relayerInfos?: WebsiteBackendRelayerInfo[]; - error?: Error; -} - -const CELL_HEIGHT_EXPANDED = 290; -const CELL_HEIGHT_MINIMIZED = 225; -const NUMBER_OF_COLUMNS_LARGE = 3; -const NUMBER_OF_COLUMNS_MEDIUM = 2; -const NUMBER_OF_COLUMNS_SMALL = 2; -const GRID_PADDING = 20; - -export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerIndexState> { - private _isUnmounted: boolean; - constructor(props: RelayerIndexProps) { - super(props); - this._isUnmounted = false; - this.state = { - relayerInfos: undefined, - error: undefined, - }; - } - public componentWillMount(): void { - // tslint:disable-next-line:no-floating-promises - this._fetchRelayerInfosAsync(); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - } - public render(): React.ReactNode { - const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos); - if (!isReadyToRender) { - return ( - // TODO: consolidate this loading component with the one in portal and OpenPositions - // TODO: possibly refactor into a generic loading container with spinner and retry UI - <div className="center"> - {_.isUndefined(this.state.error) ? ( - <CircularProgress size={40} thickness={5} /> - ) : ( - <Retry onRetry={this._fetchRelayerInfosAsync.bind(this)} /> - )} - </div> - ); - } else { - const numberOfRelayers = this.state.relayerInfos.length; - const numberOfColumns = Math.min( - numberOfRelayers, - this._numberOfColumnsForScreenWidth(this.props.screenWidth), - ); - const isExpanded = this.props.cellStyle === RelayerIndexCellStyle.Expanded; - const cellHeight = isExpanded ? CELL_HEIGHT_EXPANDED : CELL_HEIGHT_MINIMIZED; - const gridTileStyle = isExpanded ? RelayerGridTileStyle.Expanded : RelayerGridTileStyle.Minimized; - return ( - <GridList - cellHeight={cellHeight} - cols={numberOfColumns} - padding={GRID_PADDING} - style={{ marginTop: -10, marginBottom: 0 }} - > - {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => ( - <RelayerGridTile - key={index} - relayerInfo={relayerInfo} - networkId={this.props.networkId} - style={gridTileStyle} - /> - ))} - </GridList> - ); - } - } - private async _fetchRelayerInfosAsync(): Promise<void> { - try { - if (!this._isUnmounted) { - this.setState({ - relayerInfos: undefined, - error: undefined, - }); - } - const relayerInfos = await backendClient.getRelayerInfosAsync(); - if (!this._isUnmounted) { - this.setState({ - relayerInfos, - }); - } - } catch (error) { - if (!this._isUnmounted) { - this.setState({ - error, - }); - } - } - } - private _numberOfColumnsForScreenWidth(screenWidth: ScreenWidths): number { - switch (screenWidth) { - case ScreenWidths.Md: - return NUMBER_OF_COLUMNS_MEDIUM; - case ScreenWidths.Sm: - return NUMBER_OF_COLUMNS_SMALL; - case ScreenWidths.Lg: - default: - return NUMBER_OF_COLUMNS_LARGE; - } - } -} diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx deleted file mode 100644 index 558d99855..000000000 --- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { WebsiteBackendTokenInfo } from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; -import { utils } from 'ts/utils/utils'; - -export interface TopTokensProps { - tokens: WebsiteBackendTokenInfo[]; - networkId: number; -} - -export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTokensProps) => { - return ( - <div className="flex"> - {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo) => { - return ( - <Container key={tokenInfo.address} marginRight="16px"> - <TokenLink tokenInfo={tokenInfo} networkId={props.networkId} /> - </Container> - ); - })} - </div> - ); -}; - -interface TokenLinkProps { - tokenInfo: WebsiteBackendTokenInfo; - networkId: number; -} -interface TokenLinkState {} - -class TokenLink extends React.Component<TokenLinkProps, TokenLinkState> { - constructor(props: TokenLinkProps) { - super(props); - this.state = { - isHovering: false, - }; - } - public render(): React.ReactNode { - const onClick = (event: React.MouseEvent<HTMLElement>) => { - event.stopPropagation(); - analytics.track('Token Click', { - tokenSymbol: this.props.tokenInfo.symbol, - }); - const tokenLink = this._tokenLinkFromToken(this.props.tokenInfo, this.props.networkId); - utils.openUrl(tokenLink); - }; - return ( - <Text fontSize="14px" fontColor={colors.mediumBlue} onClick={onClick}> - {this.props.tokenInfo.symbol} - </Text> - ); - } - private _tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number): string { - return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address); - } -} diff --git a/packages/website/ts/components/sections/landing/about.tsx b/packages/website/ts/components/sections/landing/about.tsx deleted file mode 100644 index 9c369d83a..000000000 --- a/packages/website/ts/components/sections/landing/about.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -import { Button } from 'ts/components/button'; -import { Icon, InlineIconWrap } from 'ts/components/icon'; -import { Column, FlexWrap, Section } from 'ts/components/newLayout'; -import { Paragraph } from 'ts/components/text'; -import { WebsitePaths } from 'ts/types'; - -interface FigureProps { - value: string; - description: string; -} - -export const SectionLandingAbout = () => ( - <Section bgColor="dark" isTextCentered={true}> - <InlineIconWrap> - <Icon name="descriptionCoin" size="small" /> - <Icon name="descriptionCopy" size="small" /> - <Icon name="descriptionFlask" size="small" /> - <Icon name="descriptionBolt" size="small" /> - </InlineIconWrap> - - <Paragraph size="large" isCentered={true} isMuted={1} padding={['large', 0, 'default', 0]}> - Anyone in the world can use 0x to service a wide variety of markets ranging from gaming items to financial - instruments to assets that could have never existed before. - </Paragraph> - - <DeveloperLink href={`${WebsitePaths.Why}#cases`} isWithArrow={true} isAccentColor={true}> - Discover how developers use 0x - </DeveloperLink> - - <hr - style={{ - width: '100%', - maxWidth: '340px', - borderColor: '#3C4746', - margin: '60px auto', - }} - /> - - <FlexWrap as="dl"> - <Figure value="353K" description="Total Transactions" /> - - <Figure value="$447M" description="Total Volume" /> - - <Figure value="30+" description="Total Projects" /> - </FlexWrap> - </Section> -); - -const Figure = (props: FigureProps) => ( - <Column padding="0 30px"> - <FigureValue>{props.value}</FigureValue> - <FigureDescription>{props.description}</FigureDescription> - </Column> -); - -const DeveloperLink = styled(Button)` - @media (max-width: 500px) { - && { - white-space: pre-wrap; - line-height: 1.3; - } - } -`; - -const FigureValue = styled.dt` - font-size: 50px; - font-weight: 300; - margin-bottom: 15px; - - @media (max-width: 768px) { - font-size: 40px; - } -`; - -const FigureDescription = styled.dd` - font-size: 18px; - color: #999999; -`; diff --git a/packages/website/ts/components/sections/landing/clients.tsx b/packages/website/ts/components/sections/landing/clients.tsx deleted file mode 100644 index 4d83a1d2f..000000000 --- a/packages/website/ts/components/sections/landing/clients.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import styled from 'styled-components'; -import { Heading } from 'ts/components/text'; - -import { Section, WrapGrid } from 'ts/components/newLayout'; - -interface ProjectLogo { - name: string; - imageUrl?: string; - persistOnMobile?: boolean; -} - -interface StyledProjectInterface { - isOnMobile?: boolean; -} - -const projects: ProjectLogo[] = [ - { - name: 'Radar Relay', - imageUrl: 'images/clients/radar-relay.svg', - persistOnMobile: true, - }, - { - name: 'Paradex', - imageUrl: 'images/clients/paradex.svg', - persistOnMobile: true, - }, - { - name: 'Star Bit Ex', - imageUrl: 'images/clients/starbitex.svg', - }, - { - name: 'LedgerDex', - imageUrl: 'images/clients/ledgerdex.svg', - }, - { - name: 'OpenRelay', - imageUrl: 'images/clients/openrelay.svg', - persistOnMobile: true, - }, - { - name: 'Bamboo Relay', - imageUrl: 'images/clients/bamboo.svg', - persistOnMobile: true, - }, - { - name: 'dEX', - imageUrl: 'images/clients/ercdex.svg', - persistOnMobile: true, - }, - { - name: 'emoon', - imageUrl: 'images/clients/emoon.svg', - persistOnMobile: true, - }, - { - name: 'Gods Unchained', - imageUrl: 'images/clients/godsUnchained.svg', - }, - { - name: 'Instex', - imageUrl: 'images/clients/instex.svg', - }, - { - name: 'Lake Trade', - imageUrl: 'images/clients/laketrade.svg', - }, - { - name: 'Veil', - imageUrl: 'images/clients/veil.svg', - }, -]; - -export const SectionLandingClients = () => ( - <Section isTextCentered={true}> - <Heading size="small">Join the growing number of projects developing on 0x</Heading> - - <WrapGrid isWrapped={true}> - {_.map(projects, (item: ProjectLogo, index) => ( - <StyledProject key={`client-${index}`} isOnMobile={item.persistOnMobile}> - <img src={item.imageUrl} alt={item.name} /> - </StyledProject> - ))} - </WrapGrid> - </Section> -); - -const StyledProject = styled.div<StyledProjectInterface>` - flex-shrink: 0; - - img { - object-fit: contain; - width: 100%; - height: 100%; - } - - @media (min-width: 768px) { - width: auto; - height: 50px; - margin: 30px; - } - - @media (max-width: 768px) { - width: auto; - height: 42px; - margin: 15px; - display: ${props => !props.isOnMobile && 'none'}; - } -`; diff --git a/packages/website/ts/components/sections/landing/cta.tsx b/packages/website/ts/components/sections/landing/cta.tsx deleted file mode 100644 index ec5a58a58..000000000 --- a/packages/website/ts/components/sections/landing/cta.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; - -import { BlockIconLink } from 'ts/components/blockIconLink'; -import { Section } from 'ts/components/newLayout'; - -import { AnimatedChatIcon } from 'ts/components/animatedChatIcon'; -import { AnimatedCompassIcon } from 'ts/components/animatedCompassIcon'; -import { WebsitePaths } from 'ts/types'; - -interface Props { - onContactClick?: () => void; -} - -export const SectionLandingCta = (props: Props) => ( - <Section isPadded={false} isFlex={true} maxWidth="auto" wrapWidth="100%" flexBreakpoint="900px"> - <BlockIconLink - iconComponent={<AnimatedCompassIcon />} - title="Ready to build on 0x?" - linkLabel="Get Started" - linkUrl={WebsitePaths.Docs} - /> - <BlockIconLink - iconComponent={<AnimatedChatIcon />} - title="Want help from the 0x team?" - linkLabel="Get in Touch" - linkAction={props.onContactClick} - /> - </Section> -); diff --git a/packages/website/ts/components/sections/landing/hero.tsx b/packages/website/ts/components/sections/landing/hero.tsx deleted file mode 100644 index 489757286..000000000 --- a/packages/website/ts/components/sections/landing/hero.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from 'react'; - -import { Button } from 'ts/components/button'; -import { Hero } from 'ts/components/hero'; -import { LandingAnimation } from 'ts/components/heroImage'; - -import { HeroAnimation } from 'ts/components/heroAnimation'; -import { WebsitePaths } from 'ts/types'; - -export const SectionLandingHero = () => ( - <Hero - title="Powering Decentralized Exchange" - isLargeTitle={true} - isFullWidth={true} - description="0x is an open protocol that enables the peer-to-peer exchange of assets on the Ethereum blockchain." - figure={<LandingAnimation image={<HeroAnimation />} />} - actions={<HeroActions />} - /> -); - -const HeroActions = () => ( - <> - <Button href="https://0x.org/docs" isInline={true}> - Get Started - </Button> - - <Button to={WebsitePaths.Why} isTransparent={true} isInline={true}> - Learn More - </Button> - </> -); diff --git a/packages/website/ts/components/send_button.tsx b/packages/website/ts/components/send_button.tsx deleted file mode 100644 index 27438e5d5..000000000 --- a/packages/website/ts/components/send_button.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { BigNumber, logUtils } from '@0x/utils'; -import * as _ from 'lodash'; -import RaisedButton from 'material-ui/RaisedButton'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { SendDialog } from 'ts/components/dialogs/send_dialog'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { BlockchainCallErrs, Token } from 'ts/types'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { utils } from 'ts/utils/utils'; - -interface SendButtonProps { - userAddress: string; - networkId: number; - asset: Token | 'ETH'; - dispatcher: Dispatcher; - blockchain: Blockchain; - onError: () => void; - lastForceTokenStateRefetch: number; - refetchTokenStateAsync: (tokenAddress: string) => Promise<void>; -} - -interface SendButtonState { - isSendDialogVisible: boolean; - isSending: boolean; -} - -export class SendButton extends React.Component<SendButtonProps, SendButtonState> { - public constructor(props: SendButtonProps) { - super(props); - this.state = { - isSendDialogVisible: false, - isSending: false, - }; - } - public render(): React.ReactNode { - const labelStyle = this.state.isSending ? { fontSize: 10 } : {}; - return ( - <div> - <RaisedButton - style={{ width: '100%' }} - labelStyle={labelStyle} - disabled={this.state.isSending} - label={this.state.isSending ? 'Sending...' : 'Send'} - onClick={this._toggleSendDialog.bind(this)} - /> - <SendDialog - blockchain={this.props.blockchain} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - isOpen={this.state.isSendDialogVisible} - onComplete={this._onSendAmountSelectedAsync.bind(this)} - onCancelled={this._toggleSendDialog.bind(this)} - asset={this.props.asset} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - /> - </div> - ); - } - private _toggleSendDialog(): void { - this.setState({ - isSendDialogVisible: !this.state.isSendDialogVisible, - }); - } - private async _onSendAmountSelectedAsync(recipient: string, value: BigNumber): Promise<void> { - this.setState({ - isSending: true, - }); - this._toggleSendDialog(); - try { - if (this.props.asset === 'ETH') { - await this.props.blockchain.sendAsync(recipient, value); - } else { - const token = this.props.asset; - await this.props.blockchain.transferAsync(token, recipient, value); - await this.props.refetchTokenStateAsync(token.address); - } - } catch (err) { - const errMsg = `${err}`; - if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return; - } else if (!utils.didUserDenyWeb3Request(errMsg)) { - logUtils.log(`Unexpected error encountered: ${err}`); - logUtils.log(err.stack); - this.props.onError(); - errorReporter.report(err); - } - } - this.setState({ - isSending: false, - }); - } -} diff --git a/packages/website/ts/components/siteWrap.tsx b/packages/website/ts/components/siteWrap.tsx deleted file mode 100644 index 1f0902105..000000000 --- a/packages/website/ts/components/siteWrap.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import * as React from 'react'; -import styled, { ThemeProvider } from 'styled-components'; - -import { colors } from 'ts/style/colors'; - -import { Footer } from 'ts/components/footer'; -import { Header } from 'ts/components/header'; -import { GlobalStyles } from 'ts/constants/globalStyle'; - -interface Props { - theme?: 'dark' | 'light' | 'gray'; - children: any; -} - -interface State { - isMobileNavOpen: boolean; -} - -interface MainProps { - isNavToggled: boolean; -} - -export interface ThemeValuesInterface { - bgColor: string; - darkBgColor?: string; - lightBgColor: string; - introTextColor: string; - textColor: string; - paragraphColor: string; - linkColor: string; - mobileNavBgUpper: string; - mobileNavBgLower: string; - mobileNavColor: string; - dropdownBg: string; - dropdownButtonBg: string; - dropdownBorderColor?: string; - dropdownColor: string; - headerButtonBg: string; - footerBg: string; - footerColor: string; -} - -export interface ThemeInterface { - [key: string]: ThemeValuesInterface; -} - -const GLOBAL_THEMES: ThemeInterface = { - dark: { - bgColor: '#000000', - darkBgColor: '#111A19', - lightBgColor: '#003831', - introTextColor: 'rgba(255, 255, 255, 0.75)', - textColor: '#FFFFFF', - paragraphColor: '#FFFFFF', - linkColor: colors.brandLight, - mobileNavBgUpper: '#003831', - mobileNavBgLower: '#022924', - mobileNavColor: '#FFFFFF', - dropdownBg: '#111A19', - dropdownButtonBg: '#003831', - dropdownColor: '#FFFFFF', - headerButtonBg: '#00AE99', - footerBg: '#181818', - footerColor: '#FFFFFF', - }, - light: { - bgColor: '#FFFFFF', - lightBgColor: '#F3F6F4', - darkBgColor: '#003831', - introTextColor: 'rgba(92, 92, 92, 0.87)', - textColor: '#000000', - paragraphColor: '#474747', - linkColor: colors.brandDark, - mobileNavBgUpper: '#FFFFFF', - mobileNavBgLower: '#F3F6F4', - mobileNavColor: '#000000', - dropdownBg: '#FBFBFB', - dropdownButtonBg: '#F3F6F4', - dropdownColor: '#003831', - dropdownBorderColor: '#E4E4E4', - headerButtonBg: '#003831', - footerBg: '#F2F2F2', - footerColor: '#000000', - }, - gray: { - bgColor: '#e0e0e0', - lightBgColor: '#003831', - introTextColor: 'rgba(92, 92, 92, 0.87)', - textColor: '#000000', - paragraphColor: '#777777', - linkColor: colors.brandDark, - mobileNavBgUpper: '#FFFFFF', - mobileNavBgLower: '#F3F6F4', - mobileNavColor: '#000000', - dropdownBg: '#FFFFFF', - dropdownButtonBg: '#F3F6F4', - dropdownColor: '#003831', - headerButtonBg: '#003831', - footerBg: '#181818', - footerColor: '#FFFFFF', - }, -}; - -export class SiteWrap extends React.Component<Props, State> { - public state = { - isMobileNavOpen: false, - }; - - public componentDidMount(): void { - document.documentElement.style.overflowY = 'auto'; - window.scrollTo(0, 0); - } - - public toggleMobileNav = () => { - this.setState({ - isMobileNavOpen: !this.state.isMobileNavOpen, - }); - }; - - public render(): React.ReactNode { - const { children, theme = 'dark' } = this.props; - const { isMobileNavOpen } = this.state; - const currentTheme = GLOBAL_THEMES[theme]; - - return ( - <> - <ThemeProvider theme={currentTheme}> - <> - <GlobalStyles /> - - <Header isNavToggled={isMobileNavOpen} toggleMobileNav={this.toggleMobileNav} /> - - <Main isNavToggled={isMobileNavOpen}>{children}</Main> - - <Footer /> - </> - </ThemeProvider> - </> - ); - } -} - -const Main = styled.main<MainProps>` - transition: transform 0.5s, opacity 0.5s; - opacity: ${props => props.isNavToggled && '0.5'}; -`; diff --git a/packages/website/ts/components/slider/slider.tsx b/packages/website/ts/components/slider/slider.tsx deleted file mode 100644 index f0a29f894..000000000 --- a/packages/website/ts/components/slider/slider.tsx +++ /dev/null @@ -1,177 +0,0 @@ -import * as React from 'react'; -import Flickity from 'react-flickity-component'; -import styled from 'styled-components'; - -import { colors } from 'ts/style/colors'; - -import { Icon } from 'ts/components/icon'; -import { Heading, Paragraph } from 'ts/components/text'; - -interface SliderProps {} - -interface SlideProps { - icon: string; - heading: string; - text: string; - href?: string; -} - -const flickityOptions = { - initialIndex: 0, - cellAlign: 'left', - arrowShape: - 'M0 50.766L42.467 93.58l5.791-5.839-32.346-32.61H100V46.84H15.48L50.2 11.838 44.409 6 5.794 44.93l-.003-.003z', - prevNextButtons: true, -}; - -export const Slide: React.StatelessComponent<SlideProps> = (props: SlideProps) => { - const { heading, text, icon } = props; - - return ( - <StyledSlide> - <SlideHead> - <Icon name={icon} size="large" /> - </SlideHead> - <SlideContent> - <Heading asElement="h4" size="small" marginBottom="15px"> - {heading} - </Heading> - <Paragraph isMuted={true}>{text}</Paragraph> - </SlideContent> - </StyledSlide> - ); -}; - -export const Slider: React.StatelessComponent<SliderProps> = props => { - return ( - <StyledSlider> - <Flickity - className={'carousel'} // default '' - elementType={'div'} // default 'div' - options={flickityOptions} // takes flickity options {} - disableImagesLoaded={false} // default false - > - {props.children} - </Flickity> - </StyledSlider> - ); -}; - -const StyledSlider = styled.div` - //overflow: hidden; - width: 100%; - height: 520px; - - @media (max-width: 500px) { - height: 450px; - } - - .carousel { - display: block; - user-select: none; - touch-action: pan-y; - -webkit-tap-highlight-color: transparent; - outline: none; - - @media (max-width: 500px) { - overflow: hidden; - margin-left: -20px; - width: calc(100vw - 20px); - } - } - - .flickity-viewport { - outline: none; - } - - .flickity-button { - cursor: pointer; - position: absolute; - width: 74px; - height: 74px; - background-color: #000; - display: flex; - outline: 0; - top: calc(50% - 37px); - border: 0; - padding: 0; - transition: background-color 0.4s ease-in-out, visibility 0.4s ease-in-out, opacity 0.4s ease-in-out; - - &:disabled { - opacity: 0; - visibility: hidden; - } - - &:hover { - background-color: hsla(0, 0%, 10%, 1); - } - - &.previous { - left: 0; - } - - &.next { - right: 0; - } - - svg { - margin: auto; - width: 28px; - height: auto; - } - - path { - fill: #fff; - } - } -`; - -const StyledSlide = styled.div` - background-color: ${colors.backgroundDark}; - width: 560px; - height: 520px; - flex: 0 0 auto; - opacity: 0.3; - transition: opacity 0.4s ease-in-out; - - & + & { - margin-left: 30px; - } - - @media (max-width: 1200px) { - width: 100%; - } - - @media (max-width: 500px) { - width: calc(100vw - 10px - 30px); - height: 450px; - - & + & { - margin-left: 10px; - } - } - - &.is-selected { - opacity: 1; - } -`; - -const SlideHead = styled.div` - background-color: ${colors.brandDark}; - height: 300px; - display: flex; - justify-content: center; - align-items: center; - - @media (max-width: 500px) { - height: 240px; - } -`; - -const SlideContent = styled.div` - padding: 30px; - - @media (max-width: 500px) { - padding: 20px; - } -`; diff --git a/packages/website/ts/components/text.tsx b/packages/website/ts/components/text.tsx deleted file mode 100644 index a47e61ef3..000000000 --- a/packages/website/ts/components/text.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; -import { getCSSPadding, PaddingInterface } from 'ts/constants/utilities'; - -interface BaseTextInterface extends PaddingInterface { - size?: 'default' | 'medium' | 'large' | 'small' | number; - isCentered?: boolean; - textAlign?: string; -} - -interface HeadingProps extends BaseTextInterface { - asElement?: 'h1' | 'h2' | 'h3' | 'h4'; - maxWidth?: string; - fontWeight?: string; - isCentered?: boolean; - isFlex?: boolean; - isNoMargin?: boolean; - isMuted?: boolean | number; - marginBottom?: string; - color?: string; -} - -interface ParagraphProps extends BaseTextInterface { - isNoMargin?: boolean; - marginBottom?: string; // maybe we should remove isNoMargin - isMuted?: boolean | number; - fontWeight?: string | number; -} - -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 => - typeof props.size === 'string' ? `var(--${props.size || 'default'}Heading)` : `${props.size}px`}; - line-height: ${props => `var(--${props.size || 'default'}HeadingHeight)`}; - text-align: ${props => props.isCentered && 'center'}; - padding: ${props => props.padding && getCSSPadding(props.padding)}; - margin-left: ${props => props.isCentered && 'auto'}; - 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 => (props.fontWeight ? props.fontWeight : ['h4'].includes(props.asElement) ? 400 : 300)}; - width: ${props => props.isFlex && `100%`}; -`; - -export const Heading: React.StatelessComponent<HeadingProps> = props => { - const { asElement = 'h1', children } = props; - const Component = StyledHeading.withComponent(asElement); - - return <Component {...props}>{children}</Component>; -}; - -Heading.defaultProps = { - size: 'default', -}; - -// No need to declare it twice as Styled then rewrap as a stateless comp -// Note: this would be useful to be implemented the same way was "Heading" -// and be more generic. e.g. <Text /> with a props asElement so we can use it -// for literally anything = -export const Paragraph = styled.p<ParagraphProps>` - font-size: ${props => `var(--${props.size || 'default'}Paragraph)`}; - font-weight: ${props => props.fontWeight || 300}; - margin-bottom: ${props => !props.isNoMargin && (props.marginBottom || '30px')}; - padding: ${props => props.padding && getCSSPadding(props.padding)}; - color: ${props => props.color || props.theme.paragraphColor}; - opacity: ${props => (typeof props.isMuted === 'boolean' ? 0.75 : props.isMuted)}; - text-align: ${props => (props.textAlign ? props.textAlign : props.isCentered && 'center')}; - line-height: 1.4; -`; - -Paragraph.defaultProps = { - isMuted: true, -}; diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx deleted file mode 100644 index e8f2a6461..000000000 --- a/packages/website/ts/components/token_balances.tsx +++ /dev/null @@ -1,658 +0,0 @@ -import { - constants as sharedConstants, - EtherscanLinkSuffixes, - Networks, - Styles, - utils as sharedUtils, -} from '@0x/react-shared'; -import { BigNumber, errorUtils, fetchAsync, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import Dialog from 'material-ui/Dialog'; -import Divider from 'material-ui/Divider'; -import FlatButton from 'material-ui/FlatButton'; -import FloatingActionButton from 'material-ui/FloatingActionButton'; -import ContentAdd from 'material-ui/svg-icons/content/add'; -import ContentRemove from 'material-ui/svg-icons/content/remove'; -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; -import firstBy from 'thenby'; -import { Blockchain } from 'ts/blockchain'; -import { AssetPicker } from 'ts/components/generate_order/asset_picker'; -import { SendButton } from 'ts/components/send_button'; -import { HelpTooltip } from 'ts/components/ui/help_tooltip'; -import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; -import { TokenIcon } from 'ts/components/ui/token_icon'; -import { AllowanceStateToggle } from 'ts/containers/inputs/allowance_state_toggle'; -import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { - BalanceErrs, - BlockchainCallErrs, - BlockchainErrs, - ScreenWidths, - Token, - TokenByAddress, - TokenStateByAddress, - TokenVisibility, -} from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { utils } from 'ts/utils/utils'; - -const ETHER_ICON_PATH = '/images/ether.png'; -const ETHER_TOKEN_SYMBOL = 'WETH'; -const ZRX_TOKEN_SYMBOL = 'ZRX'; - -const ICON_DIMENSION = 40; -const ARTIFICIAL_FAUCET_REQUEST_DELAY = 1000; -const TOKEN_TABLE_ROW_HEIGHT = 60; -const MAX_TOKEN_TABLE_HEIGHT = 420; -const TOKEN_COL_SPAN_LG = 2; -const TOKEN_COL_SPAN_SM = 1; - -const styles: Styles = { - bgColor: { - backgroundColor: 'transparent', - }, -}; - -interface TokenBalancesProps { - blockchain: Blockchain; - blockchainErr: BlockchainErrs; - blockchainIsLoaded: boolean; - dispatcher: Dispatcher; - screenWidth: ScreenWidths; - tokenByAddress: TokenByAddress; - trackedTokens: Token[]; - userAddress: string; - userEtherBalanceInWei: BigNumber; - networkId: number; - lastForceTokenStateRefetch: number; - isFullWidth?: boolean; -} - -interface TokenBalancesState { - errorType: BalanceErrs; - trackedTokenStateByAddress: TokenStateByAddress; - isBalanceSpinnerVisible: boolean; - isZRXSpinnerVisible: boolean; - isTokenPickerOpen: boolean; - isAddingToken: boolean; -} - -export class TokenBalances extends React.Component<TokenBalancesProps, TokenBalancesState> { - public static defaultProps: Partial<TokenBalancesProps> = { - userEtherBalanceInWei: new BigNumber(0), - isFullWidth: false, - }; - private _isUnmounted: boolean; - public constructor(props: TokenBalancesProps) { - super(props); - this._isUnmounted = false; - const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(props.trackedTokens); - this.state = { - errorType: undefined, - isBalanceSpinnerVisible: false, - isZRXSpinnerVisible: false, - isTokenPickerOpen: false, - isAddingToken: false, - trackedTokenStateByAddress: initialTrackedTokenStateByAddress, - }; - } - public componentWillMount(): void { - const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress); - // tslint:disable-next-line:no-floating-promises - this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - } - public componentWillReceiveProps(nextProps: TokenBalancesProps): void { - if (nextProps.userEtherBalanceInWei !== this.props.userEtherBalanceInWei) { - if (this.state.isBalanceSpinnerVisible) { - const receivedAmountInWei = nextProps.userEtherBalanceInWei.minus(this.props.userEtherBalanceInWei); - const receivedAmountInEth = Web3Wrapper.toUnitAmount(receivedAmountInWei, constants.DECIMAL_PLACES_ETH); - const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId]; - this.props.dispatcher.showFlashMessage( - `Received ${receivedAmountInEth.toString(10)} ${networkName} Ether`, - ); - } - this.setState({ - isBalanceSpinnerVisible: false, - }); - } - - if ( - nextProps.userAddress !== this.props.userAddress || - nextProps.networkId !== this.props.networkId || - nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch - ) { - const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress); - // tslint:disable-next-line:no-floating-promises - this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses); - } - - if (!_.isEqual(nextProps.trackedTokens, this.props.trackedTokens)) { - const newTokens = _.difference(nextProps.trackedTokens, this.props.trackedTokens); - const newTokenAddresses = _.map(newTokens, token => token.address); - // Add placeholder entry for this token to the state, since fetching the - // balance/allowance is asynchronous - const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress; - for (const tokenAddress of newTokenAddresses) { - trackedTokenStateByAddress[tokenAddress] = { - balance: new BigNumber(0), - allowance: new BigNumber(0), - isLoaded: false, - }; - } - this.setState({ - trackedTokenStateByAddress, - }); - // Fetch the actual balance/allowance. - // tslint:disable-next-line:no-floating-promises - this._fetchBalancesAndAllowancesAsync(newTokenAddresses); - } - } - public componentDidMount(): void { - window.scrollTo(0, 0); - } - public render(): React.ReactNode { - const errorDialogActions = [ - <FlatButton - key="errorOkBtn" - label="Ok" - primary={true} - onClick={this._onErrorDialogToggle.bind(this, false)} - />, - ]; - const isTestNetwork = utils.isTestNetwork(this.props.networkId); - const stubColumnStyle = { - display: isTestNetwork ? 'none' : 'table-cell', - }; - const allTokenRowHeight = _.size(this.props.tokenByAddress) * TOKEN_TABLE_ROW_HEIGHT; - const tokenTableHeight = - allTokenRowHeight < MAX_TOKEN_TABLE_HEIGHT ? allTokenRowHeight : MAX_TOKEN_TABLE_HEIGHT; - const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; - const tokenColSpan = isSmallScreen ? TOKEN_COL_SPAN_SM : TOKEN_COL_SPAN_LG; - const allowanceExplanation = - '0x smart contracts require access to your<br> \ - token balances in order to execute trades.<br> \ - Toggling sets an allowance for the<br> \ - smart contract so you can start trading that token.'; - const userEtherBalanceInEth = Web3Wrapper.toUnitAmount( - this.props.userEtherBalanceInWei, - constants.DECIMAL_PLACES_ETH, - ); - const rootClassName = this.props.isFullWidth ? 'pb2' : 'lg-px4 md-px4 sm-px1 pb2'; - return ( - <div className={rootClassName}> - <h3>{isTestNetwork ? 'Test ether' : 'Ether'}</h3> - <Divider /> - <div className="pt2 pb2"> - {isTestNetwork - ? 'In order to try out the 0x Portal Dapp, request some test ether to pay for \ - gas costs. It might take a bit of time for the test ether to show up.' - : 'Ether must be converted to Ether Tokens in order to be tradable via 0x. \ - You can convert between Ether and Ether Tokens from the "Wrap ETH" tab.'} - </div> - <Table selectable={false} style={styles.bgColor}> - <TableHeader displaySelectAll={false} adjustForCheckbox={false}> - <TableRow> - <TableHeaderColumn>Currency</TableHeaderColumn> - <TableHeaderColumn>Balance</TableHeaderColumn> - <TableRowColumn className="sm-hide xs-hide" style={stubColumnStyle} /> - {isTestNetwork && <TableHeaderColumn style={{ paddingLeft: 3 }}>Action</TableHeaderColumn>} - <TableHeaderColumn>Send</TableHeaderColumn> - </TableRow> - </TableHeader> - <TableBody displayRowCheckbox={false}> - <TableRow key="ETH"> - <TableRowColumn className="py1"> - <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} /> - </TableRowColumn> - <TableRowColumn> - {userEtherBalanceInEth.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} ETH - {this.state.isBalanceSpinnerVisible && ( - <span className="pl1"> - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - </span> - )} - </TableRowColumn> - <TableRowColumn className="sm-hide xs-hide" style={stubColumnStyle} /> - {isTestNetwork && ( - <TableRowColumn style={{ paddingLeft: 3 }}> - <LifeCycleRaisedButton - labelReady="Request" - labelLoading="Sending..." - labelComplete="Sent!" - onClickAsyncFn={this._faucetRequestAsync.bind(this, true)} - /> - </TableRowColumn> - )} - <TableRowColumn> - <SendButton - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this.props.blockchain} - dispatcher={this.props.dispatcher} - asset="ETH" - onError={this._onSendFailed.bind(this)} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - // This is not necessary for ETH. - // tslint:disable:jsx-no-lambda - refetchTokenStateAsync={() => undefined} - /> - </TableRowColumn> - </TableRow> - </TableBody> - </Table> - <div className="clearfix" style={{ paddingBottom: 1 }}> - <div className="col col-10"> - <h3 className="pt2">{isTestNetwork ? 'Test tokens' : 'Tokens'}</h3> - </div> - <div className="col col-1 pt3 align-right"> - <FloatingActionButton mini={true} zDepth={0} onClick={this._onAddTokenClicked.bind(this)}> - <ContentAdd /> - </FloatingActionButton> - </div> - <div className="col col-1 pt3 align-right"> - <FloatingActionButton mini={true} zDepth={0} onClick={this._onRemoveTokenClicked.bind(this)}> - <ContentRemove /> - </FloatingActionButton> - </div> - </div> - <Divider /> - <div className="pt2 pb2"> - {isTestNetwork - ? "Mint some test tokens you'd like to use to generate or fill an order using 0x." - : "Set trading permissions for a token you'd like to start trading."} - </div> - <Table selectable={false} bodyStyle={{ height: tokenTableHeight }} style={styles.bgColor}> - <TableHeader displaySelectAll={false} adjustForCheckbox={false}> - <TableRow> - <TableHeaderColumn colSpan={tokenColSpan}>Token</TableHeaderColumn> - <TableHeaderColumn style={{ paddingLeft: 3 }}>Balance</TableHeaderColumn> - <TableHeaderColumn> - <div className="inline-block">Allowance</div> - <HelpTooltip style={{ paddingLeft: 4 }} explanation={allowanceExplanation} /> - </TableHeaderColumn> - {isTestNetwork && <TableHeaderColumn>Action</TableHeaderColumn>} - {this.props.screenWidth !== ScreenWidths.Sm && <TableHeaderColumn>Send</TableHeaderColumn>} - </TableRow> - </TableHeader> - <TableBody displayRowCheckbox={false}>{this._renderTokenTableRows()}</TableBody> - </Table> - <Dialog - title="Oh oh" - titleStyle={{ fontWeight: 100 }} - actions={errorDialogActions} - open={!_.isUndefined(this.state.errorType)} - onRequestClose={this._onErrorDialogToggle.bind(this, false)} - > - {this._renderErrorDialogBody()} - </Dialog> - <AssetPicker - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this.props.blockchain} - dispatcher={this.props.dispatcher} - isOpen={this.state.isTokenPickerOpen} - currentTokenAddress={''} - onTokenChosen={this._onAssetTokenPicked.bind(this)} - tokenByAddress={this.props.tokenByAddress} - tokenVisibility={this.state.isAddingToken ? TokenVisibility.Untracked : TokenVisibility.Tracked} - /> - </div> - ); - } - private _renderTokenTableRows(): React.ReactNode { - if (!this.props.blockchainIsLoaded || this.props.blockchainErr !== BlockchainErrs.NoError) { - return ''; - } - const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; - const tokenColSpan = isSmallScreen ? TOKEN_COL_SPAN_SM : TOKEN_COL_SPAN_LG; - const actionPaddingX = isSmallScreen ? 2 : 24; - const trackedTokens = this.props.trackedTokens; - const trackedTokensStartingWithEtherToken = trackedTokens.sort( - firstBy((t: Token) => t.symbol !== ETHER_TOKEN_SYMBOL) - .thenBy((t: Token) => t.symbol !== ZRX_TOKEN_SYMBOL) - .thenBy('trackedTimestamp'), - ); - const tableRows = _.map( - trackedTokensStartingWithEtherToken, - this._renderTokenRow.bind(this, tokenColSpan, actionPaddingX), - ); - return tableRows; - } - private _renderTokenRow(tokenColSpan: number, actionPaddingX: number, token: Token): React.ReactNode { - const tokenState = this.state.trackedTokenStateByAddress[token.address]; - const tokenLink = sharedUtils.getEtherScanLinkIfExists( - token.address, - this.props.networkId, - EtherscanLinkSuffixes.Address, - ); - const isMintable = - (_.includes(configs.SYMBOLS_OF_MINTABLE_KOVAN_TOKENS, token.symbol) && - this.props.networkId === sharedConstants.NETWORK_ID_BY_NAME[Networks.Kovan]) || - (_.includes(configs.SYMBOLS_OF_MINTABLE_ROPSTEN_TOKENS, token.symbol) && - this.props.networkId === sharedConstants.NETWORK_ID_BY_NAME[Networks.Ropsten]); - return ( - <TableRow key={token.address} style={{ height: TOKEN_TABLE_ROW_HEIGHT }}> - <TableRowColumn colSpan={tokenColSpan}> - {_.isUndefined(tokenLink) ? ( - this._renderTokenName(token) - ) : ( - <a href={tokenLink} target="_blank" style={{ textDecoration: 'none' }}> - {this._renderTokenName(token)} - </a> - )} - </TableRowColumn> - <TableRowColumn style={{ paddingRight: 3, paddingLeft: 3 }}> - {tokenState.isLoaded ? ( - <span> - {this._renderAmount(tokenState.balance, token.decimals)} {token.symbol} - {this.state.isZRXSpinnerVisible && token.symbol === ZRX_TOKEN_SYMBOL && ( - <span className="pl1"> - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - </span> - )} - </span> - ) : ( - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - )} - </TableRowColumn> - <TableRowColumn> - <div className="flex justify-center"> - <AllowanceStateToggle - blockchain={this.props.blockchain} - token={token} - tokenState={tokenState} - onErrorOccurred={this._onErrorOccurred.bind(this)} - refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this, token.address)} - /> - </div> - </TableRowColumn> - {utils.isTestNetwork(this.props.networkId) && ( - <TableRowColumn style={{ paddingLeft: actionPaddingX, paddingRight: actionPaddingX }}> - {isMintable && ( - <LifeCycleRaisedButton - labelReady="Mint" - labelLoading={<span style={{ fontSize: 12 }}>Minting...</span>} - labelComplete="Minted!" - onClickAsyncFn={this._onMintTestTokensAsync.bind(this, token)} - /> - )} - </TableRowColumn> - )} - {this.props.screenWidth !== ScreenWidths.Sm && ( - <TableRowColumn - style={{ - paddingLeft: actionPaddingX, - paddingRight: actionPaddingX, - }} - > - <SendButton - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this.props.blockchain} - dispatcher={this.props.dispatcher} - asset={token} - onError={this._onSendFailed.bind(this)} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this, token.address)} - /> - </TableRowColumn> - )} - </TableRow> - ); - } - private _onAssetTokenPicked(tokenAddress: string): void { - if (_.isEmpty(tokenAddress)) { - this.setState({ - isTokenPickerOpen: false, - }); - return; - } - const token = this.props.tokenByAddress[tokenAddress]; - const isDefaultTrackedToken = _.includes(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, token.symbol); - if (!this.state.isAddingToken && !isDefaultTrackedToken) { - if (token.isRegistered) { - // Remove the token from tracked tokens - const newToken: Token = { - ...token, - trackedTimestamp: undefined, - }; - this.props.dispatcher.updateTokenByAddress([newToken]); - } else { - this.props.dispatcher.removeTokenToTokenByAddress(token); - } - trackedTokenStorage.removeTrackedToken(this.props.userAddress, this.props.networkId, tokenAddress); - } else if (isDefaultTrackedToken) { - this.props.dispatcher.showFlashMessage(`Cannot remove ${token.name} because it's a default token`); - } - this.setState({ - isTokenPickerOpen: false, - }); - } - private _onSendFailed(): void { - this.setState({ - errorType: BalanceErrs.SendFailed, - }); - } - private _renderAmount(amount: BigNumber, decimals: number): React.ReactNode { - const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals); - return unitAmount.toNumber().toFixed(configs.AMOUNT_DISPLAY_PRECSION); - } - private _renderTokenName(token: Token): React.ReactNode { - const tooltipId = `tooltip-${token.address}`; - return ( - <div className="flex"> - <TokenIcon token={token} diameter={ICON_DIMENSION} /> - <div data-tip={true} data-for={tooltipId} className="mt2 ml2 sm-hide xs-hide"> - {token.name} - </div> - <ReactTooltip id={tooltipId}>{token.address}</ReactTooltip> - </div> - ); - } - private _renderErrorDialogBody(): React.ReactNode { - switch (this.state.errorType) { - case BalanceErrs.IncorrectNetworkForFaucet: - return ( - <div> - Our faucet can only send test Ether to addresses on testnets. Please make sure you are connected - to a testnet and try requesting again. - </div> - ); - - case BalanceErrs.FaucetRequestFailed: - return ( - <div> - An unexpected error occurred while trying to request test Ether from our faucet. Please refresh - the page and try again. - </div> - ); - - case BalanceErrs.FaucetQueueIsFull: - return <div>Our test Ether faucet queue is full. Please try requesting test Ether again later.</div>; - - case BalanceErrs.MintingFailed: - return <div>Minting your test tokens failed unexpectedly. Please refresh the page and try again.</div>; - - case BalanceErrs.AllowanceSettingFailed: - return ( - <div> - An unexpected error occurred while trying to set your test token allowance. Please refresh the - page and try again. - </div> - ); - - case undefined: - return null; // No error to show - - default: - throw errorUtils.spawnSwitchErr('errorType', this.state.errorType); - } - } - private _onErrorOccurred(errorType: BalanceErrs): void { - this.setState({ - errorType, - }); - } - private async _onMintTestTokensAsync(token: Token): Promise<boolean> { - try { - await this.props.blockchain.mintTestTokensAsync(token); - await this._refetchTokenStateAsync(token.address); - const amount = Web3Wrapper.toUnitAmount(constants.MINT_AMOUNT, token.decimals); - this.props.dispatcher.showFlashMessage(`Successfully minted ${amount.toString(10)} ${token.symbol}`); - return true; - } catch (err) { - const errMsg = `${err}`; - if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return false; - } - if (utils.didUserDenyWeb3Request(errMsg)) { - return false; - } - logUtils.log(`Unexpected error encountered: ${err}`); - logUtils.log(err.stack); - this.setState({ - errorType: BalanceErrs.MintingFailed, - }); - errorReporter.report(err); - return false; - } - } - private async _faucetRequestAsync(isEtherRequest: boolean): Promise<boolean> { - if (this.props.userAddress === '') { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return false; - } - - // If on another network other then the testnet our faucet serves test ether - // from, we must show user an error message - if (!utils.isTestNetwork(this.props.blockchain.networkId)) { - this.setState({ - errorType: BalanceErrs.IncorrectNetworkForFaucet, - }); - return false; - } - - await utils.sleepAsync(ARTIFICIAL_FAUCET_REQUEST_DELAY); - - const segment = isEtherRequest ? 'ether' : 'zrx'; - const response = await fetchAsync( - `${constants.URL_TESTNET_FAUCET}/${segment}/${this.props.userAddress}?networkId=${this.props.networkId}`, - ); - const responseBody = await response.text(); - if (response.status !== constants.SUCCESS_STATUS) { - logUtils.log(`Unexpected status code: ${response.status} -> ${responseBody}`); - const errorType = - response.status === constants.UNAVAILABLE_STATUS - ? BalanceErrs.FaucetQueueIsFull - : BalanceErrs.FaucetRequestFailed; - this.setState({ - errorType, - }); - errorReporter.report(new Error(`Faucet returned non-200: ${JSON.stringify(response)}`)); - return false; - } - - if (isEtherRequest) { - this.setState({ - isBalanceSpinnerVisible: true, - }); - } else { - this.setState({ - isZRXSpinnerVisible: true, - }); - // tslint:disable-next-line:no-floating-promises - this._startPollingZrxBalanceAsync(); - } - return true; - } - private _onErrorDialogToggle(_isOpen: boolean): void { - this.setState({ - errorType: undefined, - }); - } - private _onAddTokenClicked(): void { - this.setState({ - isTokenPickerOpen: true, - isAddingToken: true, - }); - } - private _onRemoveTokenClicked(): void { - this.setState({ - isTokenPickerOpen: true, - isAddingToken: false, - }); - } - private async _startPollingZrxBalanceAsync(): Promise<void> { - const tokens = _.values(this.props.tokenByAddress); - const zrxToken = _.find(tokens, t => t.symbol === ZRX_TOKEN_SYMBOL); - - // tslint:disable-next-line:no-floating-promises - const balance = await this.props.blockchain.pollTokenBalanceAsync(zrxToken); - const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress; - trackedTokenStateByAddress[zrxToken.address] = { - ...trackedTokenStateByAddress[zrxToken.address], - balance, - }; - this.setState({ - isZRXSpinnerVisible: false, - }); - } - private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]): Promise<void> { - const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress; - const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; - for (const tokenAddress of tokenAddresses) { - const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - tokenAddress, - ); - trackedTokenStateByAddress[tokenAddress] = { - balance, - allowance, - isLoaded: true, - }; - } - if (!this._isUnmounted) { - this.setState({ - trackedTokenStateByAddress, - }); - } - } - private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]): TokenStateByAddress { - const trackedTokenStateByAddress: TokenStateByAddress = {}; - _.each(trackedTokens, token => { - trackedTokenStateByAddress[token.address] = { - balance: new BigNumber(0), - allowance: new BigNumber(0), - isLoaded: false, - }; - }); - return trackedTokenStateByAddress; - } - private async _refetchTokenStateAsync(tokenAddress: string): Promise<void> { - const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; - const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( - userAddressIfExists, - tokenAddress, - ); - this.setState({ - trackedTokenStateByAddress: { - ...this.state.trackedTokenStateByAddress, - [tokenAddress]: { - balance, - allowance, - isLoaded: true, - }, - }, - }); - } -} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx deleted file mode 100644 index c88c29b8e..000000000 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import { Styles } from '@0x/react-shared'; -import * as _ from 'lodash'; -import CircularProgress from 'material-ui/CircularProgress'; -import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; -import * as React from 'react'; - -import { Blockchain } from 'ts/blockchain'; -import { AccountConnection } from 'ts/components/ui/account_connection'; -import { Container } from 'ts/components/ui/container'; -import { DropDown } from 'ts/components/ui/drop_down'; -import { Identicon } from 'ts/components/ui/identicon'; -import { Image } from 'ts/components/ui/image'; -import { Island } from 'ts/components/ui/island'; -import { - CopyAddressSimpleMenuItem, - DifferentWalletSimpleMenuItem, - GoToAccountManagementSimpleMenuItem, - SimpleMenu, -} from 'ts/components/ui/simple_menu'; -import { Text } from 'ts/components/ui/text'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { colors } from 'ts/style/colors'; -import { AccountState, ProviderType } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -const ROOT_HEIGHT = 24; - -export interface ProviderDisplayProps { - dispatcher: Dispatcher; - userAddress: string; - networkId: number; - injectedProviderName: string; - providerType: ProviderType; - onToggleLedgerDialog: () => void; - blockchain?: Blockchain; - blockchainIsLoaded: boolean; -} - -interface ProviderDisplayState {} - -const styles: Styles = { - root: { - height: ROOT_HEIGHT, - borderRadius: ROOT_HEIGHT, - }, -}; - -export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> { - public render(): React.ReactNode { - const activeNode = ( - <Island className="flex items-center py1 px2" style={styles.root}> - {this._renderIcon()} - <Container marginLeft="12px" marginRight="12px"> - {this._renderDisplayMessage()} - </Container> - {this._renderInjectedProvider()} - </Island> - ); - return ( - <div style={{ width: 'fit-content', height: 48, float: 'right' }}> - <DropDown - activeNode={activeNode} - popoverContent={this._renderPopoverContent()} - anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }} - targetOrigin={{ horizontal: 'middle', vertical: 'top' }} - zDepth={1} - /> - </div> - ); - } - private _renderPopoverContent(): React.ReactNode { - const accountState = this._getAccountState(); - switch (accountState) { - case AccountState.Ready: - return ( - <SimpleMenu> - <CopyAddressSimpleMenuItem userAddress={this.props.userAddress} /> - <DifferentWalletSimpleMenuItem onClick={this.props.onToggleLedgerDialog} /> - <GoToAccountManagementSimpleMenuItem /> - </SimpleMenu> - ); - case AccountState.Disconnected: - case AccountState.Locked: - case AccountState.Loading: - default: - return null; - } - } - private _renderIcon(): React.ReactNode { - const accountState = this._getAccountState(); - switch (accountState) { - case AccountState.Ready: - return <Identicon address={this.props.userAddress} diameter={ROOT_HEIGHT} />; - case AccountState.Loading: - return <CircularProgress size={ROOT_HEIGHT} thickness={2} />; - case AccountState.Locked: - return <Image src="/images/lock_icon.svg" height="20px" width="20px" />; - case AccountState.Disconnected: - return <ActionAccountBalanceWallet color={colors.mediumBlue} />; - default: - return null; - } - } - private _renderDisplayMessage(): React.ReactNode { - const accountState = this._getAccountState(); - const displayMessage = utils.getReadableAccountState(accountState, this.props.userAddress); - const fontColor = this._getDisplayMessageFontColor(); - return ( - <Text fontSize="16px" fontColor={fontColor} fontWeight={500}> - {displayMessage} - </Text> - ); - } - private _getDisplayMessageFontColor(): string { - const accountState = this._getAccountState(); - switch (accountState) { - case AccountState.Loading: - return colors.darkGrey; - case AccountState.Ready: - case AccountState.Locked: - case AccountState.Disconnected: - default: - return colors.black; - } - } - private _renderInjectedProvider(): React.ReactNode { - const accountState = this._getAccountState(); - switch (accountState) { - case AccountState.Ready: - case AccountState.Locked: - return ( - <AccountConnection - accountState={accountState} - injectedProviderName={this.props.injectedProviderName} - /> - ); - case AccountState.Disconnected: - case AccountState.Loading: - default: - return null; - } - } - private _isBlockchainReady(): boolean { - return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain); - } - private _getAccountState(): AccountState { - return utils.getAccountState( - this._isBlockchainReady(), - this.props.providerType, - this.props.injectedProviderName, - this.props.userAddress, - ); - } -} diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx deleted file mode 100644 index d5967cd1d..000000000 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ /dev/null @@ -1,279 +0,0 @@ -import { DocsInfo } from '@0x/react-docs'; -import { ALink, colors, Link, Styles } from '@0x/react-shared'; -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; -import Drawer from 'material-ui/Drawer'; -import MenuItem from 'material-ui/MenuItem'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { DevelopersDropDown } from 'ts/components/dropdowns/developers_drop_down'; -import { DrawerMenu } from 'ts/components/portal/drawer_menu'; -import { ProviderDisplay } from 'ts/components/top_bar/provider_display'; -import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item'; -import { Container } from 'ts/components/ui/container'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { Deco, Key, ProviderType, WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -export enum TopBarDisplayType { - Default, - Expanded, -} - -export interface TopBarProps { - userAddress?: string; - networkId?: number; - injectedProviderName?: string; - providerType?: ProviderType; - onToggleLedgerDialog?: () => void; - blockchain?: Blockchain; - dispatcher?: Dispatcher; - blockchainIsLoaded: boolean; - location: Location; - translate: Translate; - docsVersion?: string; - availableDocVersions?: string[]; - sectionNameToLinks?: ObjectMap<ALink[]>; - displayType?: TopBarDisplayType; - docsInfo?: DocsInfo; - style?: React.CSSProperties; - isNightVersion?: boolean; - onVersionSelected?: (semver: string) => void; - sidebarHeader?: React.ReactNode; - maxWidth?: number; - paddingLeft?: number; - paddingRight?: number; -} - -interface TopBarState { - isDrawerOpen: boolean; -} - -const styles: Styles = { - topBar: { - backgroundColor: colors.white, - width: '100%', - position: 'relative', - top: 0, - paddingBottom: 1, - zIndex: 1, - }, - bottomBar: { - boxShadow: 'rgba(0, 0, 0, 0.187647) 0px 1px 3px', - }, - menuItem: { - fontSize: 14, - color: colors.darkestGrey, - paddingTop: 6, - paddingBottom: 6, - cursor: 'pointer', - fontWeight: 400, - }, -}; - -const DEFAULT_HEIGHT = 68; -const EXPANDED_HEIGHT = 75; - -export class TopBar extends React.Component<TopBarProps, TopBarState> { - public static defaultProps: Partial<TopBarProps> = { - displayType: TopBarDisplayType.Default, - style: {}, - isNightVersion: false, - paddingLeft: 20, - paddingRight: 20, - }; - public static heightForDisplayType(displayType: TopBarDisplayType): number { - const result = displayType === TopBarDisplayType.Expanded ? EXPANDED_HEIGHT : DEFAULT_HEIGHT; - return result + 1; - } - constructor(props: TopBarProps) { - super(props); - this.state = { - isDrawerOpen: false, - }; - } - public componentWillReceiveProps(nextProps: TopBarProps): void { - if (nextProps.location.pathname !== this.props.location.pathname) { - this.setState({ - isDrawerOpen: false, - }); - } - } - public render(): React.ReactNode { - const isNightVersion = this.props.isNightVersion; - const isExpandedDisplayType = this.props.displayType === TopBarDisplayType.Expanded; - const parentClassNames = !isExpandedDisplayType - ? 'flex mx-auto items-center max-width-4' - : 'flex mx-auto items-center'; - const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT; - const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {}; - const fullWidthClasses = isExpandedDisplayType ? 'pr4' : ''; - const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png'; - const menuClasses = `col col-${ - isExpandedDisplayType ? '4' : '6' - } ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`; - const menuIconStyle = { - fontSize: 25, - color: isNightVersion ? 'white' : 'black', - cursor: 'pointer', - }; - return ( - <div - style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style, ...{ height } }} - className="pb1 flex items-center" - > - <Container - className={parentClassNames} - width="100%" - maxWidth={this.props.maxWidth} - paddingLeft={this.props.paddingLeft} - paddingRight={this.props.paddingRight} - > - <Link to={WebsitePaths.Home}> - <img src={logoUrl} height="30" /> - </Link> - <div className="flex-auto" /> - {!this._isViewingPortal() && ( - <div className={menuClasses}> - <div className="flex items-center justify-between"> - <DevelopersDropDown - location={this.props.location} - menuItemStyles={{ ...styles.menuItem, paddingBottom: 12, paddingTop: 12 }} - translate={this.props.translate} - menuIconStyle={menuIconStyle} - /> - <TopBarMenuItem - title={this.props.translate.get(Key.Blog, Deco.Cap)} - path={constants.URL_BLOG} - style={styles.menuItem} - isNightVersion={isNightVersion} - shouldOpenInNewTab={true} - /> - <TopBarMenuItem - title={this.props.translate.get(Key.About, Deco.Cap)} - path={WebsitePaths.About} - style={styles.menuItem} - isNightVersion={isNightVersion} - /> - <TopBarMenuItem - title={this.props.translate.get(Key.Careers, Deco.Cap)} - path={WebsitePaths.Careers} - style={styles.menuItem} - isNightVersion={isNightVersion} - /> - <TopBarMenuItem - title={this.props.translate.get(Key.TradeCallToAction, Deco.Cap)} - path={WebsitePaths.Portal} - isPrimary={true} - style={styles.menuItem} - className={`${isExpandedDisplayType && 'md-hide'}`} - isNightVersion={isNightVersion} - /> - </div> - </div> - )} - {this._isViewingPortal() && ( - <div className="sm-hide xs-hide"> - <ProviderDisplay - dispatcher={this.props.dispatcher} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - injectedProviderName={this.props.injectedProviderName} - providerType={this.props.providerType} - onToggleLedgerDialog={this.props.onToggleLedgerDialog} - blockchain={this.props.blockchain} - blockchainIsLoaded={this.props.blockchainIsLoaded} - /> - </div> - )} - <div className={'md-hide lg-hide'}> - <div style={menuIconStyle}> - <i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} /> - </div> - </div> - </Container> - {this._isViewingPortal() ? this._renderPortalDrawer() : this._renderDrawer()} - </div> - ); - } - private _renderPortalDrawer(): React.ReactNode { - return ( - <Drawer - open={this.state.isDrawerOpen} - docked={false} - openSecondary={true} - onRequestChange={this._onMenuButtonClick.bind(this)} - > - <DrawerMenu - selectedPath={this.props.location.pathname} - userAddress={this.props.userAddress} - injectedProviderName={this.props.injectedProviderName} - providerType={this.props.providerType} - blockchainIsLoaded={this.props.blockchainIsLoaded} - blockchain={this.props.blockchain} - /> - </Drawer> - ); - } - private _renderDrawer(): React.ReactNode { - return ( - <Drawer - open={this.state.isDrawerOpen} - docked={false} - openSecondary={true} - onRequestChange={this._onMenuButtonClick.bind(this)} - > - <div className="clearfix"> - <div className="pl1 py1 mt3" style={{ backgroundColor: colors.lightGrey }}> - {this.props.translate.get(Key.Website, Deco.Cap)} - </div> - <Link to={WebsitePaths.Home}> - <MenuItem className="py2">{this.props.translate.get(Key.Home, Deco.Cap)}</MenuItem> - </Link> - <Link to={WebsitePaths.Docs}> - <MenuItem className="py2">{this.props.translate.get(Key.Docs, Deco.Cap)}</MenuItem> - </Link> - {!this._isViewingPortal() && ( - <Link to={WebsitePaths.Portal}> - <MenuItem className="py2"> - {this.props.translate.get(Key.PortalDApp, Deco.CapWords)} - </MenuItem> - </Link> - )} - <Link to={WebsitePaths.Whitepaper} shouldOpenInNewTab={true}> - <MenuItem className="py2">{this.props.translate.get(Key.Whitepaper, Deco.Cap)}</MenuItem> - </Link> - <Link to={WebsitePaths.About}> - <MenuItem className="py2">{this.props.translate.get(Key.About, Deco.Cap)}</MenuItem> - </Link> - <Link to={WebsitePaths.Careers}> - <MenuItem className="py2">{this.props.translate.get(Key.Careers, Deco.Cap)}</MenuItem> - </Link> - <Link to={constants.URL_BLOG} shouldOpenInNewTab={true}> - <MenuItem className="py2">{this.props.translate.get(Key.Blog, Deco.Cap)}</MenuItem> - </Link> - <Link to={WebsitePaths.FAQ}> - <MenuItem className="py2" onClick={this._onMenuButtonClick.bind(this)}> - {this.props.translate.get(Key.Faq, Deco.Cap)} - </MenuItem> - </Link> - </div> - </Drawer> - ); - } - private _onMenuButtonClick(): void { - this.setState({ - isDrawerOpen: !this.state.isDrawerOpen, - }); - } - private _isViewingPortal(): boolean { - return _.includes(this.props.location.pathname, WebsitePaths.Portal); - } - private _isViewingFAQ(): boolean { - return _.includes(this.props.location.pathname, WebsitePaths.FAQ); - } - private _shouldDisplayBottomBar(): boolean { - return this._isViewingFAQ() || this._isViewingPortal(); - } -} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx deleted file mode 100644 index 9f15cffbb..000000000 --- a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { colors, Link } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; - -import { CallToAction } from 'ts/components/ui/button'; - -const DEFAULT_STYLE = { - color: colors.darkestGrey, -}; - -interface TopBarMenuItemProps { - title: string; - path?: string; - isPrimary?: boolean; - shouldOpenInNewTab?: boolean; - style?: React.CSSProperties; - className?: string; - isNightVersion?: boolean; -} - -interface TopBarMenuItemState {} - -export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarMenuItemState> { - public static defaultProps: Partial<TopBarMenuItemProps> = { - isPrimary: false, - style: DEFAULT_STYLE, - className: '', - shouldOpenInNewTab: false, - isNightVersion: false, - }; - public render(): React.ReactNode { - const menuItemColor = this.props.isNightVersion ? 'white' : this.props.style.color; - const linkColor = _.isUndefined(menuItemColor) ? colors.darkestGrey : menuItemColor; - const itemContent = this.props.isPrimary ? ( - <CallToAction padding="0.8em 1.5em">{this.props.title}</CallToAction> - ) : ( - this.props.title - ); - return ( - <div className={`center ${this.props.className}`} style={{ ...this.props.style, color: menuItemColor }}> - <Link to={this.props.path} shouldOpenInNewTab={this.props.shouldOpenInNewTab} fontColor={linkColor}> - {itemContent} - </Link> - </div> - ); - } -} diff --git a/packages/website/ts/components/track_token_confirmation.tsx b/packages/website/ts/components/track_token_confirmation.tsx deleted file mode 100644 index e701686b0..000000000 --- a/packages/website/ts/components/track_token_confirmation.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { Party } from 'ts/components/ui/party'; -import { Token, TokenByAddress } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -interface TrackTokenConfirmationProps { - tokens: Token[]; - tokenByAddress: TokenByAddress; - networkId: number; - isAddingTokenToTracked: boolean; -} - -interface TrackTokenConfirmationState {} - -export class TrackTokenConfirmation extends React.Component<TrackTokenConfirmationProps, TrackTokenConfirmationState> { - public render(): React.ReactNode { - const isMultipleTokens = this.props.tokens.length > 1; - const allTokens = _.values(this.props.tokenByAddress); - return ( - <div style={{ color: colors.grey700 }}> - {this.props.isAddingTokenToTracked ? ( - <div className="py4 my4 center"> - <span className="pr1"> - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - </span> - <span>Adding token{isMultipleTokens && 's'}...</span> - </div> - ) : ( - <div> - <div>You do not currently track the following token{isMultipleTokens && 's'}:</div> - <div className="py2 clearfix mx-auto center" style={{ width: 355 }}> - {_.map(this.props.tokens, (token: Token) => ( - <div - key={`token-profile-${token.name}`} - className={`col col-${isMultipleTokens ? '6' : '12'} px2`} - > - <Party - label={token.name} - address={token.address} - networkId={this.props.networkId} - alternativeImage={token.iconUrl} - isInTokenRegistry={token.isRegistered} - hasUniqueNameAndSymbol={utils.hasUniqueNameAndSymbol(allTokens, token)} - /> - </div> - ))} - </div> - <div> - Tracking a token adds it to the balances section of 0x Portal and allows you to - generate/fill orders involving the token - {isMultipleTokens && 's'}. Would you like to start tracking{' '} - {isMultipleTokens ? 'these' : 'this'} token? - </div> - </div> - )} - </div> - ); - } -} diff --git a/packages/website/ts/components/trade_history/trade_history.tsx b/packages/website/ts/components/trade_history/trade_history.tsx deleted file mode 100644 index 84c0f70a8..000000000 --- a/packages/website/ts/components/trade_history/trade_history.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import * as _ from 'lodash'; -import Divider from 'material-ui/Divider'; -import Paper from 'material-ui/Paper'; -import * as React from 'react'; -import { TradeHistoryItem } from 'ts/components/trade_history/trade_history_item'; -import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage'; -import { Fill, TokenByAddress } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -const FILL_POLLING_INTERVAL = 1000; - -interface TradeHistoryProps { - tokenByAddress: TokenByAddress; - userAddress: string; - networkId: number; - isFullWidth?: boolean; - shouldHideHeader?: boolean; - isScrollable?: boolean; -} - -interface TradeHistoryState { - sortedFills: Fill[]; -} - -export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistoryState> { - public static defaultProps: Partial<TradeHistoryProps> = { - isFullWidth: false, - shouldHideHeader: false, - isScrollable: true, - }; - private _fillPollingIntervalId: number; - public constructor(props: TradeHistoryProps) { - super(props); - const sortedFills = this._getSortedFills(); - this.state = { - sortedFills, - }; - } - public componentWillMount(): void { - this._startPollingForFills(); - } - public componentWillUnmount(): void { - this._stopPollingForFills(); - } - public componentDidMount(): void { - window.scrollTo(0, 0); - } - public render(): React.ReactNode { - const rootClassName = !this.props.isFullWidth ? 'lg-px4 md-px4 sm-px2' : undefined; - return ( - <div className={rootClassName}> - {!this.props.shouldHideHeader && ( - <div> - <h3>Trade history</h3> - <Divider /> - </div> - )} - {this.props.isScrollable ? ( - <div className="pt2" style={{ height: 608, overflow: 'scroll' }}> - {this._renderTrades()} - </div> - ) : ( - this._renderTrades() - )} - </div> - ); - } - private _renderTrades(): React.ReactNode { - const numNonCustomFills = this._numFillsWithoutCustomERC20Tokens(); - if (numNonCustomFills === 0) { - return this._renderEmptyNotice(); - } - - return _.map(this.state.sortedFills, (fill, index) => { - return ( - <TradeHistoryItem - key={`${fill.orderHash}-${fill.filledTakerTokenAmount}-${index}`} - fill={fill} - tokenByAddress={this.props.tokenByAddress} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - /> - ); - }); - } - private _renderEmptyNotice(): React.ReactNode { - return ( - <Paper className="mt1 p2 mx-auto center" style={{ width: '80%' }}> - No filled orders yet. - </Paper> - ); - } - private _numFillsWithoutCustomERC20Tokens(): number { - let numNonCustomFills = 0; - const tokens = _.values(this.props.tokenByAddress); - _.each(this.state.sortedFills, fill => { - const takerToken = _.find(tokens, token => { - return token.address === fill.takerToken; - }); - const makerToken = _.find(tokens, token => { - return token.address === fill.makerToken; - }); - // For now we don't show history items for orders using custom ERC20 - // tokens the client does not know how to display. - // TODO: Try to retrieve the name/symbol of an unknown token in order to display it - // Be sure to remove similar logic in trade_history_item.tsx - if (!_.isUndefined(takerToken) && !_.isUndefined(makerToken)) { - numNonCustomFills += 1; - } - }); - return numNonCustomFills; - } - private _startPollingForFills(): void { - this._fillPollingIntervalId = window.setInterval(() => { - const sortedFills = this._getSortedFills(); - if (!utils.deepEqual(sortedFills, this.state.sortedFills)) { - this.setState({ - sortedFills, - }); - } - }, FILL_POLLING_INTERVAL); - } - private _stopPollingForFills(): void { - clearInterval(this._fillPollingIntervalId); - } - private _getSortedFills(): Fill[] { - const fillsByHash = tradeHistoryStorage.getUserFillsByHash(this.props.userAddress, this.props.networkId); - const fills = _.values(fillsByHash); - const sortedFills = _.sortBy(fills, [(fill: Fill) => fill.blockTimestamp * -1]); - return sortedFills; - } -} diff --git a/packages/website/ts/components/trade_history/trade_history_item.tsx b/packages/website/ts/components/trade_history/trade_history_item.tsx deleted file mode 100644 index 667027dce..000000000 --- a/packages/website/ts/components/trade_history/trade_history_item.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import { colors, EtherscanLinkSuffixes } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import Paper from 'material-ui/Paper'; -import * as moment from 'moment'; -import * as React from 'react'; -import * as ReactTooltip from 'react-tooltip'; -import { EtherScanIcon } from 'ts/components/ui/etherscan_icon'; -import { Party } from 'ts/components/ui/party'; -import { Fill, Token, TokenByAddress } from 'ts/types'; -import { configs } from 'ts/utils/configs'; - -const IDENTICON_DIAMETER = 40; - -interface TradeHistoryItemProps { - fill: Fill; - tokenByAddress: TokenByAddress; - userAddress: string; - networkId: number; -} - -interface TradeHistoryItemState {} - -export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, TradeHistoryItemState> { - public render(): React.ReactNode { - const fill = this.props.fill; - const tokens = _.values(this.props.tokenByAddress); - const takerToken = _.find(tokens, token => { - return token.address === fill.takerToken; - }); - const makerToken = _.find(tokens, token => { - return token.address === fill.makerToken; - }); - // For now we don't show history items for orders using custom ERC20 - // tokens the client does not know how to display. - // TODO: Try to retrieve the name/symbol of an unknown token in order to display it - // Be sure to remove similar logic in trade_history.tsx - if (_.isUndefined(takerToken) || _.isUndefined(makerToken)) { - return null; - } - - const amountColStyle: React.CSSProperties = { - fontWeight: 100, - display: 'inline-block', - }; - const amountColClassNames = - 'col col-12 lg-col-4 md-col-4 lg-py2 md-py2 sm-py1 lg-pr2 md-pr2 \ - lg-right-align md-right-align sm-center'; - - return ( - <Paper className="py1" style={{ margin: '3px 3px 15px 3px' }}> - <div className="clearfix"> - <div className="col col-12 lg-col-1 md-col-1 pt2 lg-pl3 md-pl3">{this._renderDate()}</div> - <div - className="col col-12 lg-col-6 md-col-6 lg-pl3 md-pl3" - style={{ fontSize: 12, fontWeight: 100 }} - > - <div className="flex sm-mx-auto xs-mx-auto" style={{ paddingTop: 4, width: 224 }}> - <Party - label="Maker" - address={fill.maker} - identiconDiameter={IDENTICON_DIAMETER} - networkId={this.props.networkId} - /> - <i style={{ fontSize: 30 }} className="zmdi zmdi-swap py3" /> - <Party - label="Taker" - address={fill.taker} - identiconDiameter={IDENTICON_DIAMETER} - networkId={this.props.networkId} - /> - </div> - </div> - <div className={amountColClassNames} style={amountColStyle}> - {this._renderAmounts(makerToken, takerToken)} - </div> - <div className="col col-12 lg-col-1 md-col-1 lg-pr3 md-pr3 lg-py3 md-py3 sm-pb1 sm-center"> - <div className="pt1 lg-right md-right sm-mx-auto" style={{ width: 13 }}> - <EtherScanIcon - addressOrTxHash={fill.transactionHash} - networkId={this.props.networkId} - etherscanLinkSuffixes={EtherscanLinkSuffixes.Tx} - /> - </div> - </div> - </div> - </Paper> - ); - } - private _renderAmounts(makerToken: Token, takerToken: Token): React.ReactNode { - const fill = this.props.fill; - const filledTakerTokenAmountInUnits = Web3Wrapper.toUnitAmount( - fill.filledTakerTokenAmount, - takerToken.decimals, - ); - const filledMakerTokenAmountInUnits = Web3Wrapper.toUnitAmount( - fill.filledMakerTokenAmount, - takerToken.decimals, - ); - let exchangeRate = filledTakerTokenAmountInUnits.div(filledMakerTokenAmountInUnits); - const fillMakerTokenAmount = Web3Wrapper.toBaseUnitAmount(filledMakerTokenAmountInUnits, makerToken.decimals); - - let receiveAmount; - let receiveToken; - let givenAmount; - let givenToken; - if (this.props.userAddress === fill.maker && this.props.userAddress === fill.taker) { - receiveAmount = new BigNumber(0); - givenAmount = new BigNumber(0); - receiveToken = makerToken; - givenToken = takerToken; - } else if (this.props.userAddress === fill.maker) { - receiveAmount = fill.filledTakerTokenAmount; - givenAmount = fillMakerTokenAmount; - receiveToken = takerToken; - givenToken = makerToken; - exchangeRate = new BigNumber(1).div(exchangeRate); - } else if (this.props.userAddress === fill.taker) { - receiveAmount = fillMakerTokenAmount; - givenAmount = fill.filledTakerTokenAmount; - receiveToken = makerToken; - givenToken = takerToken; - } else { - // This condition should never be hit - throw new Error("Found Fill that wasn't performed by this user"); - } - - return ( - <div> - <div style={{ color: colors.green400, fontSize: 16 }}> - <span>+ </span> - {this._renderAmount(receiveAmount, receiveToken.symbol, receiveToken.decimals)} - </div> - <div className="pb1 inline-block" style={{ color: colors.red200, fontSize: 16 }}> - <span>- </span> - {this._renderAmount(givenAmount, givenToken.symbol, givenToken.decimals)} - </div> - <div style={{ color: colors.grey400, fontSize: 14 }}> - {exchangeRate.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} {givenToken.symbol}/{receiveToken.symbol} - </div> - </div> - ); - } - private _renderDate(): React.ReactNode { - const blockMoment = moment.unix(this.props.fill.blockTimestamp); - if (!blockMoment.isValid()) { - return null; - } - - const dayOfMonth = blockMoment.format('D'); - const monthAbreviation = blockMoment.format('MMM'); - const formattedBlockDate = blockMoment.format('H:mmA - MMMM D, YYYY'); - const dateTooltipId = `${this.props.fill.transactionHash}-date`; - - return ( - <div data-tip={true} data-for={dateTooltipId}> - <div className="center pt1" style={{ fontSize: 13 }}> - {monthAbreviation} - </div> - <div className="center" style={{ fontSize: 24, fontWeight: 100 }}> - {dayOfMonth} - </div> - <ReactTooltip id={dateTooltipId}>{formattedBlockDate}</ReactTooltip> - </div> - ); - } - private _renderAmount(amount: BigNumber, symbol: string, decimals: number): React.ReactNode { - const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals); - return ( - <span> - {unitAmount.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} {symbol} - </span> - ); - } -} diff --git a/packages/website/ts/components/ui/account_connection.tsx b/packages/website/ts/components/ui/account_connection.tsx deleted file mode 100644 index 6d0b90922..000000000 --- a/packages/website/ts/components/ui/account_connection.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import * as React from 'react'; - -import { Circle } from 'ts/components/ui/circle'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { colors } from 'ts/style/colors'; -import { AccountState } from 'ts/types'; - -export interface AccountConnectionProps { - accountState: AccountState; - injectedProviderName: string; -} - -export const AccountConnection: React.StatelessComponent<AccountConnectionProps> = ({ - accountState, - injectedProviderName, -}) => { - return ( - <Container className="flex items-center"> - <Circle diameter={6} fillColor={getInjectedProviderColor(accountState)} /> - <Container marginLeft="6px"> - <Text fontSize="12px" lineHeight="14px" fontColor={colors.darkGrey}> - {injectedProviderName} - </Text> - </Container> - </Container> - ); -}; - -const getInjectedProviderColor = (accountState: AccountState) => { - switch (accountState) { - case AccountState.Ready: - return colors.limeGreen; - case AccountState.Locked: - case AccountState.Loading: - case AccountState.Disconnected: - default: - return colors.red; - } -}; diff --git a/packages/website/ts/components/ui/alert.tsx b/packages/website/ts/components/ui/alert.tsx deleted file mode 100644 index c7a5b9030..000000000 --- a/packages/website/ts/components/ui/alert.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; -import { AlertTypes } from 'ts/types'; - -interface AlertProps { - type: AlertTypes; - message: string | React.ReactNode; -} - -export const Alert = (props: AlertProps) => { - const isAlert = props.type === AlertTypes.Error; - const errMsgStyles = { - background: isAlert ? colors.red200 : colors.lightestGreen, - color: colors.white, - marginTop: 10, - padding: 4, - paddingLeft: 8, - }; - - return ( - <div className="rounded center" style={errMsgStyles}> - {props.message} - </div> - ); -}; diff --git a/packages/website/ts/components/ui/allowance_state_view.tsx b/packages/website/ts/components/ui/allowance_state_view.tsx deleted file mode 100644 index fc754421a..000000000 --- a/packages/website/ts/components/ui/allowance_state_view.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; -import { Container } from 'ts/components/ui/container'; -import { Spinner } from 'ts/components/ui/spinner'; - -export enum AllowanceState { - Locked, - Unlocked, - Loading, -} - -export interface AllowanceStateViewProps { - allowanceState: AllowanceState; -} - -export const AllowanceStateView: React.StatelessComponent<AllowanceStateViewProps> = ({ allowanceState }) => { - switch (allowanceState) { - case AllowanceState.Locked: - return renderLock(); - case AllowanceState.Unlocked: - return renderCheck(); - case AllowanceState.Loading: - return ( - <Container position="relative" top="3px" left="5px"> - <Spinner size={18} strokeSize={2} /> - </Container> - ); - default: - return null; - } -}; - -const renderCheck = (color: string = colors.lightGreen) => ( - <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={color} /> - <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> -); - -const renderLock = () => ( - <svg width="12" height="15" viewBox="0 0 12 15" fill="none" xmlns="http://www.w3.org/2000/svg"> - <path - d="M6 0C3.51604 0 1.48688 2.0495 1.48688 4.55837V5.86581C0.664723 5.86581 -3.33647e-08 6.53719 -3.33647e-08 7.36759V13.3217C-3.33647e-08 14.1521 0.664723 14.8235 1.48688 14.8235H10.5131C11.3353 14.8235 12 14.1521 12 13.3217V7.36759C12 6.53719 11.3353 5.86581 10.5131 5.86581V4.55837C10.5131 2.0495 8.48396 0 6 0ZM8.93878 5.86581H3.06122V4.55837C3.06122 2.9329 4.37318 1.59013 6 1.59013C7.62682 1.59013 8.93878 2.9329 8.93878 4.55837V5.86581Z" - fill="black" - /> - </svg> -); diff --git a/packages/website/ts/components/ui/balance.tsx b/packages/website/ts/components/ui/balance.tsx deleted file mode 100644 index a1a8ff89b..000000000 --- a/packages/website/ts/components/ui/balance.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as React from 'react'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { utils } from 'ts/utils/utils'; - -export interface BalanceProps { - amount: BigNumber; - decimals: number; - symbol: string; -} - -export const Balance: React.StatelessComponent<BalanceProps> = ({ amount, decimals, symbol }) => { - const formattedAmout = utils.getFormattedAmount(amount, decimals); - return ( - <span> - <Text Tag="span" fontSize="16px" fontWeight="700" lineHeight="1em"> - {formattedAmout} - </Text> - <Container marginLeft="0.3em" Tag="span"> - <Text Tag="span" fontSize="12px" fontWeight="700" lineHeight="1em"> - {symbol} - </Text> - </Container> - </span> - ); -}; diff --git a/packages/website/ts/components/ui/button.tsx b/packages/website/ts/components/ui/button.tsx deleted file mode 100644 index 92f927843..000000000 --- a/packages/website/ts/components/ui/button.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { darken, saturate } from 'polished'; -import * as React from 'react'; -import { styled } from 'ts/style/theme'; - -export interface ButtonProps { - className?: string; - fontSize?: string; - fontColor?: string; - fontFamily?: string; - backgroundColor?: string; - borderColor?: string; - borderRadius?: string; - width?: string; - padding?: string; - type?: string; - isDisabled?: boolean; - onClick?: (event: React.MouseEvent<HTMLElement>) => void; - textAlign?: string; -} - -const PlainButton: React.StatelessComponent<ButtonProps> = ({ children, isDisabled, onClick, type, className }) => ( - <button type={type} className={className} onClick={isDisabled ? undefined : onClick} disabled={isDisabled}> - {children} - </button> -); - -export const Button = styled(PlainButton)` - cursor: ${props => (props.isDisabled ? 'default' : 'pointer')}; - font-size: ${props => props.fontSize}; - color: ${props => props.fontColor}; - transition: background-color, opacity 0.5s ease; - padding: ${props => props.padding}; - border-radius: ${props => props.borderRadius}; - font-weight: 500; - outline: none; - font-family: ${props => props.fontFamily}; - width: ${props => props.width}; - text-align: ${props => props.textAlign}; - background-color: ${props => props.backgroundColor}; - border: ${props => (props.borderColor ? `1px solid ${props.borderColor}` : 'none')}; - &:hover { - background-color: ${props => (!props.isDisabled ? darken(0.1, props.backgroundColor) : '')} !important; - } - &:active { - background-color: ${props => (!props.isDisabled ? darken(0.2, props.backgroundColor) : '')}; - } - &:disabled { - opacity: 0.5; - } - &:focus { - background-color: ${props => saturate(0.2, props.backgroundColor)}; - } -`; - -Button.defaultProps = { - fontSize: '12px', - borderRadius: '6px', - backgroundColor: colors.white, - width: 'auto', - fontFamily: 'Roboto', - isDisabled: false, - padding: '0.8em 2.2em', - textAlign: 'center', -}; - -Button.displayName = 'Button'; - -type CallToActionType = 'light' | 'dark'; - -export interface CallToActionProps { - type?: CallToActionType; - fontSize?: string; - width?: string; - padding?: string; -} - -export const CallToAction: React.StatelessComponent<CallToActionProps> = ({ - children, - type, - fontSize, - padding, - width, -}) => { - const isLight = type === 'light'; - const backgroundColor = isLight ? colors.white : colors.mediumBlue; - const fontColor = isLight ? colors.heroGrey : colors.white; - return ( - <Button - fontSize={fontSize} - padding={padding} - backgroundColor={backgroundColor} - fontColor={fontColor} - width={width} - > - {children} - </Button> - ); -}; - -CallToAction.defaultProps = { - type: 'dark', - fontSize: '14px', - padding: '0.9em 1.6em', -}; diff --git a/packages/website/ts/components/ui/check_mark.tsx b/packages/website/ts/components/ui/check_mark.tsx deleted file mode 100644 index 86e427c8b..000000000 --- a/packages/website/ts/components/ui/check_mark.tsx +++ /dev/null @@ -1,31 +0,0 @@ -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, -}; diff --git a/packages/website/ts/components/ui/circle.tsx b/packages/website/ts/components/ui/circle.tsx deleted file mode 100644 index 75103d066..000000000 --- a/packages/website/ts/components/ui/circle.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from 'react'; - -export interface CircleProps { - className?: string; - diameter: number; - fillColor: string; -} - -export const Circle: React.StatelessComponent<CircleProps> = ({ className, diameter, fillColor }) => { - const radius = diameter / 2; - return ( - <svg className={className} height={diameter} width={diameter}> - <circle cx={radius} cy={radius} r={radius} fill={fillColor} /> - </svg> - ); -}; diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx deleted file mode 100644 index 778f59f27..000000000 --- a/packages/website/ts/components/ui/container.tsx +++ /dev/null @@ -1,100 +0,0 @@ -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; - marginLeft?: StringOrNum; - padding?: StringOrNum; - paddingTop?: StringOrNum; - paddingBottom?: StringOrNum; - paddingRight?: StringOrNum; - paddingLeft?: StringOrNum; - backgroundColor?: string; - background?: string; - border?: string; - borderTop?: string; - borderRadius?: StringOrNum; - borderBottomLeftRadius?: StringOrNum; - borderBottomRightRadius?: StringOrNum; - borderBottom?: StringOrNum; - borderColor?: string; - children?: React.ReactNode; - maxWidth?: StringOrNum; - maxHeight?: StringOrNum; - width?: StringOrNum; - height?: StringOrNum; - minWidth?: StringOrNum; - minHeight?: StringOrNum; - textAlign?: TextAlignProperty; - isHidden?: boolean; - className?: string; - position?: 'absolute' | 'fixed' | 'relative' | 'unset'; - display?: 'inline-block' | 'block' | 'inline-flex' | 'inline'; - top?: string; - left?: string; - 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 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}> - {children} - </Tag> - ); -}; - -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', -}; - -Container.displayName = 'Container'; diff --git a/packages/website/ts/components/ui/copy_icon.tsx b/packages/website/ts/components/ui/copy_icon.tsx deleted file mode 100644 index 403cd4607..000000000 --- a/packages/website/ts/components/ui/copy_icon.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; -import * as CopyToClipboard from 'react-copy-to-clipboard'; -import * as ReactDOM from 'react-dom'; -import ReactTooltip from 'react-tooltip'; - -interface CopyIconProps { - data: string; - callToAction?: string; -} - -interface CopyIconState { - isHovering: boolean; -} - -export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> { - private _copyTooltipTimeoutId: number; - private _copyable: HTMLInputElement; - constructor(props: CopyIconProps) { - super(props); - this.state = { - isHovering: false, - }; - } - public componentDidUpdate(): void { - // Remove tooltip if hover away - if (!this.state.isHovering && this._copyTooltipTimeoutId) { - clearInterval(this._copyTooltipTimeoutId); - this._hideTooltip(); - } - } - public render(): React.ReactNode { - return ( - <div className="inline-block"> - <CopyToClipboard text={this.props.data} onCopy={this._onCopy.bind(this)}> - <div - className="inline flex" - style={{ cursor: 'pointer', color: colors.amber600 }} - ref={this._setRefToProperty.bind(this)} - data-tip={true} - data-for="copy" - data-event="click" - data-iscapture={true} // This let's the click event continue to propogate - onMouseOver={this._setHoverState.bind(this, true)} - onMouseOut={this._setHoverState.bind(this, false)} - > - <div> - <i style={{ fontSize: 15 }} className="zmdi zmdi-copy" /> - </div> - {this.props.callToAction && <div className="pl1">{this.props.callToAction}</div>} - </div> - </CopyToClipboard> - <ReactTooltip id="copy">Copied!</ReactTooltip> - </div> - ); - } - private _setRefToProperty(el: HTMLInputElement): void { - this._copyable = el; - } - private _setHoverState(isHovering: boolean): void { - this.setState({ - isHovering, - }); - } - private _onCopy(): void { - if (this._copyTooltipTimeoutId) { - clearInterval(this._copyTooltipTimeoutId); - } - - const tooltipLifespanMs = 1000; - this._copyTooltipTimeoutId = window.setTimeout(() => { - this._hideTooltip(); - }, tooltipLifespanMs); - } - private _hideTooltip(): void { - ReactTooltip.hide(ReactDOM.findDOMNode(this._copyable)); - } -} diff --git a/packages/website/ts/components/ui/custom_menu_item.tsx b/packages/website/ts/components/ui/custom_menu_item.tsx deleted file mode 100644 index 87ce32126..000000000 --- a/packages/website/ts/components/ui/custom_menu_item.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Link } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; - -interface CustomMenuItemProps { - to: string; - onClick?: () => void; - className?: string; -} - -interface CustomMenuItemState { - isHovering: boolean; -} - -export class CustomMenuItem extends React.Component<CustomMenuItemProps, CustomMenuItemState> { - public static defaultProps: Partial<CustomMenuItemProps> = { - onClick: _.noop.bind(_), - className: '', - }; - public constructor(props: CustomMenuItemProps) { - super(props); - this.state = { - isHovering: false, - }; - } - public render(): React.ReactNode { - const menuItemStyles = { - cursor: 'pointer', - opacity: this.state.isHovering ? 0.5 : 1, - }; - return ( - <Link to={this.props.to}> - <div - onClick={this.props.onClick.bind(this)} - className={`mx-auto ${this.props.className}`} - style={menuItemStyles} - onMouseEnter={this._onToggleHover.bind(this, true)} - onMouseLeave={this._onToggleHover.bind(this, false)} - > - {this.props.children} - </div> - </Link> - ); - } - private _onToggleHover(isHovering: boolean): void { - this.setState({ - isHovering, - }); - } -} diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx deleted file mode 100644 index 4138b3fe5..000000000 --- a/packages/website/ts/components/ui/drop_down.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import * as _ from 'lodash'; -import Popover from 'material-ui/Popover'; -import * as React from 'react'; -import { MaterialUIPosition } from 'ts/types'; - -const CHECK_CLOSE_POPOVER_INTERVAL_MS = 300; -const DEFAULT_STYLE = { - fontSize: 14, -}; - -export enum DropdownMouseEvent { - Hover = 'hover', - Click = 'click', -} - -export interface DropDownProps { - activeNode: React.ReactNode; - popoverContent: React.ReactNode; - anchorOrigin: MaterialUIPosition; - targetOrigin: MaterialUIPosition; - style?: React.CSSProperties; - zDepth?: number; - activateEvent?: DropdownMouseEvent; - closeEvent?: DropdownMouseEvent; - popoverStyle?: React.CSSProperties; -} - -interface DropDownState { - isDropDownOpen: boolean; - anchorEl?: HTMLInputElement; -} - -export class DropDown extends React.Component<DropDownProps, DropDownState> { - public static defaultProps: Partial<DropDownProps> = { - style: DEFAULT_STYLE, - zDepth: 1, - activateEvent: DropdownMouseEvent.Hover, - closeEvent: DropdownMouseEvent.Hover, - popoverStyle: {}, - }; - private _isHovering: boolean; - private _popoverCloseCheckIntervalId: number; - constructor(props: DropDownProps) { - super(props); - this.state = { - isDropDownOpen: false, - }; - } - public componentDidMount(): void { - this._popoverCloseCheckIntervalId = window.setInterval(() => { - this._checkIfShouldClosePopover(); - }, CHECK_CLOSE_POPOVER_INTERVAL_MS); - } - public componentWillUnmount(): void { - window.clearInterval(this._popoverCloseCheckIntervalId); - } - public componentWillReceiveProps(_nextProps: DropDownProps): void { - // HACK: If the popoverContent is updated to a different dimension and the users - // mouse is no longer above it, the dropdown can enter an inconsistent state where - // it believes the user is still hovering over it. In order to remedy this, we - // call hoverOff whenever the dropdown receives updated props. This is a hack - // because it will effectively close the dropdown on any prop update, barring - // dropdowns from having dynamic content. - this._onHoverOff(); - } - public render(): React.ReactNode { - return ( - <div - style={{ ...this.props.style, width: 'fit-content', height: '100%' }} - onMouseEnter={this._onHover.bind(this)} - onMouseLeave={this._onHoverOff.bind(this)} - > - <div onClick={this._onActiveNodeClick.bind(this)}>{this.props.activeNode}</div> - <Popover - open={this.state.isDropDownOpen} - anchorEl={this.state.anchorEl} - anchorOrigin={this.props.anchorOrigin} - targetOrigin={this.props.targetOrigin} - onRequestClose={ - this.props.closeEvent === DropdownMouseEvent.Click - ? this._closePopover.bind(this) - : _.noop.bind(_) - } - useLayerForClickAway={this.props.closeEvent === DropdownMouseEvent.Click} - animated={false} - zDepth={this.props.zDepth} - style={this.props.popoverStyle} - > - <div - onMouseEnter={this._onHover.bind(this)} - onMouseLeave={this._onHoverOff.bind(this)} - onClick={this._closePopover.bind(this)} - > - {this.props.popoverContent} - </div> - </Popover> - </div> - ); - } - private _onActiveNodeClick(event: React.FormEvent<HTMLInputElement>): void { - if (this.props.activateEvent === DropdownMouseEvent.Click) { - this.setState({ - isDropDownOpen: !this.state.isDropDownOpen, - anchorEl: event.currentTarget, - }); - } - } - private _onHover(event: React.FormEvent<HTMLInputElement>): void { - this._isHovering = true; - if (this.props.activateEvent === DropdownMouseEvent.Hover) { - this._checkIfShouldOpenPopover(event); - } - } - private _onHoverOff(): void { - this._isHovering = false; - } - private _checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>): void { - if (this.state.isDropDownOpen) { - return; // noop - } - this.setState({ - isDropDownOpen: true, - anchorEl: event.currentTarget, - }); - } - private _checkIfShouldClosePopover(): void { - if (!this.state.isDropDownOpen) { - return; // noop - } - if (this.props.closeEvent === DropdownMouseEvent.Hover && !this._isHovering) { - this._closePopover(); - } - } - private _closePopover(): void { - this.setState({ - isDropDownOpen: false, - }); - } -} diff --git a/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx b/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx deleted file mode 100644 index ba141c01e..000000000 --- a/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { css, keyframes, styled } from 'ts/style/theme'; - -const appearFromBottomFrames = keyframes` - from { - position: fixed; - bottom: -500px; - left: 0px; - right: 0px; - } - - to { - position: fixed; - bottom: 0px; - left: 0px; - right: 0px; - } -`; - -const stylesForAnimation = css` - position: fixed; -`; -const animations = css` - animation: ${appearFromBottomFrames} 1s ease 0s 1 forwards; -`; - -export const EaseUpFromBottomAnimation = styled.div` - ${props => animations}; - ${props => stylesForAnimation}; -`; - -EaseUpFromBottomAnimation.displayName = 'EaseUpFromBottomAnimation'; diff --git a/packages/website/ts/components/ui/ethereum_address.tsx b/packages/website/ts/components/ui/ethereum_address.tsx deleted file mode 100644 index 12f8636eb..000000000 --- a/packages/website/ts/components/ui/ethereum_address.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { EtherscanLinkSuffixes } from '@0x/react-shared'; -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; -import { EtherScanIcon } from 'ts/components/ui/etherscan_icon'; -import { utils } from 'ts/utils/utils'; - -interface EthereumAddressProps { - address: string; - networkId: number; -} - -export const EthereumAddress = (props: EthereumAddressProps) => { - const tooltipId = `${props.address}-ethereum-address`; - const truncatedAddress = utils.getAddressBeginAndEnd(props.address); - return ( - <div> - <div className="inline" style={{ fontSize: 13 }} data-tip={true} data-for={tooltipId}> - {truncatedAddress} - </div> - <div className="pl1 inline"> - <EtherScanIcon - addressOrTxHash={props.address} - networkId={props.networkId} - etherscanLinkSuffixes={EtherscanLinkSuffixes.Address} - /> - </div> - <ReactTooltip id={tooltipId}>{props.address}</ReactTooltip> - </div> - ); -}; diff --git a/packages/website/ts/components/ui/etherscan_icon.tsx b/packages/website/ts/components/ui/etherscan_icon.tsx deleted file mode 100644 index a7fba8a33..000000000 --- a/packages/website/ts/components/ui/etherscan_icon.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; - -interface EtherScanIconProps { - addressOrTxHash: string; - etherscanLinkSuffixes: EtherscanLinkSuffixes; - networkId: number; -} - -export const EtherScanIcon = (props: EtherScanIconProps) => { - const etherscanLinkIfExists = sharedUtils.getEtherScanLinkIfExists( - props.addressOrTxHash, - props.networkId, - props.etherscanLinkSuffixes, - ); - const transactionTooltipId = `${props.addressOrTxHash}-etherscan-icon-tooltip`; - return ( - <div className="inline"> - {!_.isUndefined(etherscanLinkIfExists) ? ( - <a href={etherscanLinkIfExists} target="_blank"> - {renderIcon()} - </a> - ) : ( - <div className="inline" data-tip={true} data-for={transactionTooltipId}> - {renderIcon()} - <ReactTooltip id={transactionTooltipId}> - Your network (id: {props.networkId}) is not supported by Etherscan - </ReactTooltip> - </div> - )} - </div> - ); -}; - -function renderIcon(): React.ReactNode { - return <i style={{ color: colors.amber600 }} className="zmdi zmdi-open-in-new" />; -} diff --git a/packages/website/ts/components/ui/fake_text_field.tsx b/packages/website/ts/components/ui/fake_text_field.tsx deleted file mode 100644 index 7c3a482a4..000000000 --- a/packages/website/ts/components/ui/fake_text_field.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Styles } from '@0x/react-shared'; -import * as React from 'react'; -import { InputLabel } from 'ts/components/ui/input_label'; - -const styles: Styles = { - hr: { - borderBottom: '1px solid rgb(224, 224, 224)', - borderLeft: 'none rgb(224, 224, 224)', - borderRight: 'none rgb(224, 224, 224)', - borderTop: 'none rgb(224, 224, 224)', - bottom: 6, - boxSizing: 'content-box', - margin: 0, - position: 'absolute', - width: '100%', - }, -}; - -interface FakeTextFieldProps { - label?: React.ReactNode | string; - children?: any; -} - -export const FakeTextField = (props: FakeTextFieldProps) => { - return ( - <div className="relative"> - {props.label !== '' && <InputLabel text={props.label} />} - <div className="pb2" style={{ height: 23 }}> - {props.children} - </div> - <hr style={styles.hr} /> - </div> - ); -}; diff --git a/packages/website/ts/components/ui/flash_message.tsx b/packages/website/ts/components/ui/flash_message.tsx deleted file mode 100644 index 2b866676d..000000000 --- a/packages/website/ts/components/ui/flash_message.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import * as _ from 'lodash'; -import Snackbar from 'material-ui/Snackbar'; -import * as React from 'react'; -import { Dispatcher } from 'ts/redux/dispatcher'; - -const SHOW_DURATION_MS = 4000; - -interface FlashMessageProps { - dispatcher: Dispatcher; - flashMessage?: string | React.ReactNode; - showDurationMs?: number; - bodyStyle?: React.CSSProperties; -} - -interface FlashMessageState {} - -export class FlashMessage extends React.Component<FlashMessageProps, FlashMessageState> { - public static defaultProps: Partial<FlashMessageProps> = { - showDurationMs: SHOW_DURATION_MS, - bodyStyle: {}, - }; - public render(): React.ReactNode { - if (!_.isUndefined(this.props.flashMessage)) { - return ( - <Snackbar - open={true} - message={this.props.flashMessage} - autoHideDuration={this.props.showDurationMs} - onRequestClose={this._onClose.bind(this)} - bodyStyle={this.props.bodyStyle} - /> - ); - } else { - return null; - } - } - private _onClose(): void { - this.props.dispatcher.hideFlashMessage(); - } -} diff --git a/packages/website/ts/components/ui/help_tooltip.tsx b/packages/website/ts/components/ui/help_tooltip.tsx deleted file mode 100644 index 831d888f5..000000000 --- a/packages/website/ts/components/ui/help_tooltip.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; - -interface HelpTooltipProps { - style?: React.CSSProperties; - explanation: React.ReactNode; -} - -export const HelpTooltip = (props: HelpTooltipProps) => { - return ( - <div - style={{ ...props.style }} - className="inline-block" - data-tip={props.explanation} - data-for="helpTooltip" - data-multiline={true} - > - <i style={{ fontSize: 16 }} className="zmdi zmdi-help" /> - <ReactTooltip id="helpTooltip" /> - </div> - ); -}; diff --git a/packages/website/ts/components/ui/icon_button.tsx b/packages/website/ts/components/ui/icon_button.tsx deleted file mode 100644 index 9f469ec69..000000000 --- a/packages/website/ts/components/ui/icon_button.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { colors, Styles } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; - -export interface IconButtonProps { - iconName: string; - labelText?: string; - onClick?: () => void; - color?: string; - display?: string; -} -interface IconButtonState { - isHovering: boolean; -} -export class IconButton extends React.Component<IconButtonProps, IconButtonState> { - public static defaultProps: Partial<IconButtonProps> = { - labelText: '', - color: colors.mediumBlue, - }; - public constructor(props: IconButtonProps) { - super(props); - this.state = { - isHovering: false, - }; - } - public render(): React.ReactNode { - const styles: Styles = { - root: { - cursor: this.props.onClick ? 'pointer' : 'undefined', - opacity: this.state.isHovering && this.props.onClick ? 0.5 : 1, - display: this.props.display, - }, - icon: { - color: this.props.color, - fontSize: 20, - }, - label: { - color: this.props.color, - fontSize: 10, - }, - }; - return ( - <div - className="flex items-center py2" - onClick={this.props.onClick} - onMouseEnter={this._onToggleHover.bind(this, true)} - onMouseLeave={this._onToggleHover.bind(this, false)} - style={styles.root} - > - <i style={styles.icon} className={`zmdi ${this.props.iconName}`} /> - {!_.isEmpty(this.props.labelText) && ( - <div className="pl1" style={styles.label}> - {this.props.labelText} - </div> - )} - </div> - ); - } - private _onToggleHover(isHovering: boolean): void { - this.setState({ - isHovering, - }); - } -} diff --git a/packages/website/ts/components/ui/identicon.tsx b/packages/website/ts/components/ui/identicon.tsx deleted file mode 100644 index 9eca04a5d..000000000 --- a/packages/website/ts/components/ui/identicon.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import blockies from 'blockies'; -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Circle } from 'ts/components/ui/circle'; -import { Image } from 'ts/components/ui/image'; -import { colors } from 'ts/style/colors'; - -interface IdenticonProps { - address: string; - diameter: number; - style?: React.CSSProperties; -} - -interface IdenticonState {} - -export class Identicon extends React.Component<IdenticonProps, IdenticonState> { - public static defaultProps: Partial<IdenticonProps> = { - style: {}, - }; - public render(): React.ReactNode { - const address = this.props.address; - const diameter = this.props.diameter; - return ( - <div - className="circle relative transitionFix" - style={{ - width: diameter, - height: diameter, - overflow: 'hidden', - ...this.props.style, - }} - > - {!_.isEmpty(address) ? ( - <Image - src={blockies({ - seed: address.toLowerCase(), - }).toDataURL()} - height={diameter} - width={diameter} - /> - ) : ( - <Circle diameter={diameter} fillColor={colors.grey200} /> - )} - </div> - ); - } -} diff --git a/packages/website/ts/components/ui/image.tsx b/packages/website/ts/components/ui/image.tsx deleted file mode 100644 index d698ddaa0..000000000 --- a/packages/website/ts/components/ui/image.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -export interface ImageProps { - className?: string; - src?: string; - fallbackSrc?: string; - borderRadius?: string; - width?: string | number; - height?: string | number; - maxWidth?: string | number; - maxHeight?: string | number; - additionalStyle?: React.CSSProperties; -} -interface ImageState { - imageLoadFailed: boolean; -} -export class Image extends React.Component<ImageProps, ImageState> { - constructor(props: ImageProps) { - super(props); - this.state = { - imageLoadFailed: false, - }; - } - public render(): React.ReactNode { - const src = - this.state.imageLoadFailed || _.isUndefined(this.props.src) ? this.props.fallbackSrc : this.props.src; - return ( - <img - className={this.props.className} - onError={this._onError.bind(this)} - src={src} - style={{ - ...this.props.additionalStyle, - borderRadius: this.props.borderRadius, - maxWidth: this.props.maxWidth, - maxHeight: this.props.maxHeight, - }} - height={this.props.height} - width={this.props.width} - /> - ); - } - private _onError(): void { - this.setState({ - imageLoadFailed: true, - }); - } -} diff --git a/packages/website/ts/components/ui/input_label.tsx b/packages/website/ts/components/ui/input_label.tsx deleted file mode 100644 index e7afb5a17..000000000 --- a/packages/website/ts/components/ui/input_label.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { colors, Styles } from '@0x/react-shared'; -import * as React from 'react'; - -export interface InputLabelProps { - text: string | Element | React.ReactNode; -} - -const styles: Styles = { - label: { - color: colors.grey, - fontSize: 12, - pointerEvents: 'none', - textAlign: 'left', - transform: 'scale(0.75) translate(0px, -28px)', - transformOrigin: 'left top 0px', - transition: 'all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms', - userSelect: 'none', - width: 240, - zIndex: 1, - } as React.CSSProperties, -}; - -export const InputLabel = (props: InputLabelProps) => { - return <label style={styles.label}>{props.text}</label>; -}; diff --git a/packages/website/ts/components/ui/island.tsx b/packages/website/ts/components/ui/island.tsx deleted file mode 100644 index c8abfb7e0..000000000 --- a/packages/website/ts/components/ui/island.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; -import { colors } from 'ts/style/colors'; -import { styled } from 'ts/style/theme'; - -export interface IslandProps { - style?: React.CSSProperties; - className?: string; - Component?: string | React.ComponentClass<any> | React.StatelessComponent<any>; - borderRadius?: string; -} - -const PlainIsland: React.StatelessComponent<IslandProps> = ({ Component, style, className, children }) => ( - <Component style={style} className={className} children={children} /> -); - -export const Island = styled(PlainIsland)` - background-color: ${colors.white}; - border-radius: ${props => props.borderRadius}; - box-shadow: 0px 4px 6px ${colors.walletBoxShadow}; - overflow: hidden; -`; - -Island.defaultProps = { - Component: 'div', - borderRadius: '10px', - style: {}, -}; - -Island.displayName = 'Island'; diff --git a/packages/website/ts/components/ui/lifecycle_raised_button.tsx b/packages/website/ts/components/ui/lifecycle_raised_button.tsx deleted file mode 100644 index f004dd47f..000000000 --- a/packages/website/ts/components/ui/lifecycle_raised_button.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { errorUtils } from '@0x/utils'; -import RaisedButton from 'material-ui/RaisedButton'; -import * as React from 'react'; - -const COMPLETE_STATE_SHOW_LENGTH_MS = 2000; - -enum ButtonState { - Ready, - Loading, - Complete, -} - -interface LifeCycleRaisedButtonProps { - isHidden?: boolean; - isDisabled?: boolean; - isPrimary?: boolean; - labelReady: React.ReactNode | string; - labelLoading: React.ReactNode | string; - labelComplete: React.ReactNode | string; - onClickAsyncFn: () => Promise<boolean>; - backgroundColor?: string; - labelColor?: string; -} - -interface LifeCycleRaisedButtonState { - buttonState: ButtonState; -} - -export class LifeCycleRaisedButton extends React.Component<LifeCycleRaisedButtonProps, LifeCycleRaisedButtonState> { - public static defaultProps: Partial<LifeCycleRaisedButtonProps> = { - isDisabled: false, - backgroundColor: colors.white, - labelColor: colors.darkGrey, - }; - private _buttonTimeoutId: number; - private _didUnmount: boolean; - constructor(props: LifeCycleRaisedButtonProps) { - super(props); - this.state = { - buttonState: ButtonState.Ready, - }; - } - public componentWillUnmount(): void { - clearTimeout(this._buttonTimeoutId); - this._didUnmount = true; - } - public render(): React.ReactNode { - if (this.props.isHidden) { - return <span />; - } - - let label; - switch (this.state.buttonState) { - case ButtonState.Ready: - label = this.props.labelReady; - break; - case ButtonState.Loading: - label = this.props.labelLoading; - break; - case ButtonState.Complete: - label = this.props.labelComplete; - break; - default: - throw errorUtils.spawnSwitchErr('ButtonState', this.state.buttonState); - } - return ( - <RaisedButton - primary={this.props.isPrimary} - label={label} - style={{ width: '100%' }} - backgroundColor={this.props.backgroundColor} - labelColor={this.props.labelColor} - onClick={this.onClickAsync.bind(this)} - disabled={this.props.isDisabled || this.state.buttonState !== ButtonState.Ready} - /> - ); - } - public async onClickAsync(): Promise<void> { - this.setState({ - buttonState: ButtonState.Loading, - }); - const didSucceed = await this.props.onClickAsyncFn(); - if (this._didUnmount) { - return; // noop since unmount called before async callback returned. - } - if (didSucceed) { - this.setState({ - buttonState: ButtonState.Complete, - }); - this._buttonTimeoutId = window.setTimeout(() => { - this.setState({ - buttonState: ButtonState.Ready, - }); - }, COMPLETE_STATE_SHOW_LENGTH_MS); - } else { - this.setState({ - buttonState: ButtonState.Ready, - }); - } - } -} diff --git a/packages/website/ts/components/ui/multi_select.tsx b/packages/website/ts/components/ui/multi_select.tsx deleted file mode 100644 index 2cf44cae1..000000000 --- a/packages/website/ts/components/ui/multi_select.tsx +++ /dev/null @@ -1,66 +0,0 @@ -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> -); diff --git a/packages/website/ts/components/ui/overlay.tsx b/packages/website/ts/components/ui/overlay.tsx deleted file mode 100644 index fc7507475..000000000 --- a/packages/website/ts/components/ui/overlay.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -import { zIndex } from 'ts/style/z_index'; - -export interface OverlayProps { - style?: React.CSSProperties; - onClick?: () => void; -} - -const style: React.CSSProperties = { - position: 'fixed', - top: 0, - right: 0, - bottom: 0, - left: 0, - zIndex: zIndex.overlay, - backgroundColor: 'rgba(0, 0, 0, 0.6)', -}; - -export const Overlay: React.StatelessComponent<OverlayProps> = props => ( - <div style={{ ...style, ...props.style }} onClick={props.onClick}> - {props.children} - </div> -); - -Overlay.defaultProps = { - style: {}, - onClick: _.noop.bind(_), -}; - -Overlay.displayName = 'Overlay'; diff --git a/packages/website/ts/components/ui/party.tsx b/packages/website/ts/components/ui/party.tsx deleted file mode 100644 index a14b94d8a..000000000 --- a/packages/website/ts/components/ui/party.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import ReactTooltip from 'react-tooltip'; -import { EthereumAddress } from 'ts/components/ui/ethereum_address'; -import { Identicon } from 'ts/components/ui/identicon'; - -const IMAGE_DIMENSION = 100; -const IDENTICON_DIAMETER = 95; - -interface PartyProps { - label: string; - address: string; - networkId: number; - alternativeImage?: string; - identiconDiameter?: number; - identiconStyle?: React.CSSProperties; - isInTokenRegistry?: boolean; - hasUniqueNameAndSymbol?: boolean; -} - -interface PartyState {} - -export class Party extends React.Component<PartyProps, PartyState> { - public static defaultProps: Partial<PartyProps> = { - identiconStyle: {}, - identiconDiameter: IDENTICON_DIAMETER, - }; - public render(): React.ReactNode { - const label = this.props.label; - const address = this.props.address; - const identiconDiameter = this.props.identiconDiameter; - const emptyIdenticonStyles = { - width: identiconDiameter, - height: identiconDiameter, - backgroundColor: 'lightgray', - marginTop: 13, - marginBottom: 10, - }; - const tokenImageStyle = { - width: IMAGE_DIMENSION, - height: IMAGE_DIMENSION, - }; - const etherscanLinkIfExists = sharedUtils.getEtherScanLinkIfExists( - this.props.address, - this.props.networkId, - EtherscanLinkSuffixes.Address, - ); - const isRegistered = this.props.isInTokenRegistry; - const registeredTooltipId = `${this.props.address}-${isRegistered}-registeredTooltip`; - const uniqueNameAndSymbolTooltipId = `${this.props.address}-${isRegistered}-uniqueTooltip`; - return ( - <div style={{ overflow: 'hidden' }}> - <div className="pb1 center">{label}</div> - {_.isEmpty(address) ? ( - <div className="circle mx-auto" style={emptyIdenticonStyles} /> - ) : ( - <a href={etherscanLinkIfExists} target="_blank"> - {isRegistered && !_.isUndefined(this.props.alternativeImage) ? ( - <img style={tokenImageStyle} src={this.props.alternativeImage} /> - ) : ( - <div className="mx-auto" style={{ height: identiconDiameter, width: identiconDiameter }}> - <Identicon - address={this.props.address} - diameter={identiconDiameter} - style={this.props.identiconStyle} - /> - </div> - )} - </a> - )} - <div className="mx-auto center pt1"> - <div style={{ height: 25 }}> - <EthereumAddress address={address} networkId={this.props.networkId} /> - </div> - {!_.isUndefined(this.props.isInTokenRegistry) && ( - <div> - <div - data-tip={true} - data-for={registeredTooltipId} - className="mx-auto" - style={{ fontSize: 13, width: 127 }} - > - <span - style={{ - color: isRegistered ? colors.brightGreen : colors.red500, - }} - > - <i - className={`zmdi ${isRegistered ? 'zmdi-check-circle' : 'zmdi-alert-triangle'}`} - /> - </span>{' '} - <span>{isRegistered ? 'Registered' : 'Unregistered'} token</span> - <ReactTooltip id={registeredTooltipId}> - {isRegistered ? ( - <div> - This token address was found in the token registry - <br /> - smart contract and is therefore believed to be a<br /> - legitimate token. - </div> - ) : ( - <div> - This token is not included in the token registry - <br /> - smart contract. We cannot guarantee the legitimacy - <br /> - of this token. Make sure to verify its address on Etherscan. - </div> - )} - </ReactTooltip> - </div> - </div> - )} - {!_.isUndefined(this.props.hasUniqueNameAndSymbol) && !this.props.hasUniqueNameAndSymbol && ( - <div> - <div - data-tip={true} - data-for={uniqueNameAndSymbolTooltipId} - className="mx-auto" - style={{ fontSize: 13, width: 127 }} - > - <span style={{ color: colors.red500 }}> - <i className="zmdi zmdi-alert-octagon" /> - </span>{' '} - <span>Suspicious token</span> - <ReactTooltip id={uniqueNameAndSymbolTooltipId}> - This token shares it's name, symbol or both with - <br /> - a token in the 0x Token Registry but it has a different - <br /> - smart contract address. This is most likely a scam token! - </ReactTooltip> - </div> - </div> - )} - </div> - </div> - ); - } -} diff --git a/packages/website/ts/components/ui/pointer.tsx b/packages/website/ts/components/ui/pointer.tsx deleted file mode 100644 index c97b1e700..000000000 --- a/packages/website/ts/components/ui/pointer.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; -import { styled } from 'ts/style/theme'; - -export enum PointerDirection { - Top = 'top', - Right = 'right', - Bottom = 'bottom', - Left = 'left', -} - -export interface PointerProps { - className?: string; - color?: string; - size?: number; - direction: PointerDirection; -} - -const PlainPointer: React.StatelessComponent<PointerProps> = props => <div {...props} />; - -const positionToCss = (props: PointerProps) => { - const position = { - top: `bottom: 100%; left: 50%;`, - right: `left: 100%; top: 50%;`, - bottom: `top: 100%; left: 50%;`, - left: `right: 100%; top: 50%;`, - }[props.direction]; - - const borderColorSide = { - top: 'border-bottom-color', - right: 'border-left-color', - bottom: 'border-top-color', - left: 'border-right-color', - }[props.direction]; - const border = `${borderColorSide}: ${props.color};`; - const marginSide = { - top: 'margin-left', - right: 'margin-top', - bottom: 'margin-left', - left: 'margin-top', - }[props.direction]; - const margin = `${marginSide}: -${props.size}px`; - return { - position, - border, - margin, - }; -}; - -export const Pointer = styled(PlainPointer)` - position: relative; - &:after { - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-width: ${props => `${props.size}px`}; - ${props => positionToCss(props).position} - ${props => positionToCss(props).border} - ${props => positionToCss(props).margin} - } -`; - -Pointer.defaultProps = { - color: colors.white, - size: 16, -}; - -Pointer.displayName = 'Pointer'; diff --git a/packages/website/ts/components/ui/required_label.tsx b/packages/website/ts/components/ui/required_label.tsx deleted file mode 100644 index 5080462fa..000000000 --- a/packages/website/ts/components/ui/required_label.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; - -export interface RequiredLabelProps { - label: string | React.ReactNode; -} - -export const RequiredLabel = (props: RequiredLabelProps) => { - return ( - <span> - {props.label} - <span style={{ color: colors.red600 }}>*</span> - </span> - ); -}; diff --git a/packages/website/ts/components/ui/retry.tsx b/packages/website/ts/components/ui/retry.tsx deleted file mode 100644 index 543b7df4b..000000000 --- a/packages/website/ts/components/ui/retry.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import * as React from 'react'; - -import { Button } from 'ts/components/ui/button'; -import { colors } from 'ts/style/colors'; - -const BUTTON_TEXT = 'reload'; - -export interface RetryProps { - onRetry: () => void; -} -export const Retry = (props: RetryProps) => ( - <div className="clearfix center" style={{ color: colors.black }}> - <div className="mx-auto inline-block align-middle" style={{ lineHeight: '44px', textAlign: 'center' }}> - <div className="h2" style={{ fontFamily: 'Roboto Mono' }}> - Something went wrong. - </div> - <div className="py3"> - <Button - type="button" - backgroundColor={colors.black} - width="290px" - fontColor={colors.white} - fontSize="18px" - fontFamily="Roboto Mono" - onClick={props.onRetry} - > - {BUTTON_TEXT} - </Button> - </div> - </div> - </div> -); diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx deleted file mode 100644 index 45ee752e3..000000000 --- a/packages/website/ts/components/ui/simple_menu.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { Link } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import * as CopyToClipboard from 'react-copy-to-clipboard'; - -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { colors } from 'ts/style/colors'; -import { WebsitePaths } from 'ts/types'; - -export interface SimpleMenuProps { - minWidth?: number | string; -} - -export const SimpleMenu: React.StatelessComponent<SimpleMenuProps> = ({ children, minWidth }) => { - return ( - <Container - marginLeft="16px" - marginRight="16px" - marginBottom="16px" - minWidth={minWidth} - className="flex flex-column" - > - {children} - </Container> - ); -}; - -SimpleMenu.defaultProps = { - minWidth: '220px', -}; - -export interface SimpleMenuItemProps { - displayText: string; - onClick?: () => void; -} -export const SimpleMenuItem: React.StatelessComponent<SimpleMenuItemProps> = ({ displayText, onClick }) => { - // Falling back to _.noop for onclick retains the hovering effect - return ( - <Container marginTop="16px" className="flex flex-column"> - <Text - fontSize="14px" - fontColor={colors.darkGrey} - onClick={onClick || _.noop.bind(_)} - hoverColor={colors.mediumBlue} - > - {displayText} - </Text> - </Container> - ); -}; - -export interface CopyAddressSimpleMenuItemProps { - userAddress: string; - onClick?: () => void; -} -export const CopyAddressSimpleMenuItem: React.StatelessComponent<CopyAddressSimpleMenuItemProps> = ({ - userAddress, - onClick, -}) => { - return ( - <CopyToClipboard text={userAddress}> - <SimpleMenuItem displayText="Copy Address to Clipboard" onClick={onClick} /> - </CopyToClipboard> - ); -}; - -export interface GoToAccountManagementSimpleMenuItemProps { - onClick?: () => void; -} -export const GoToAccountManagementSimpleMenuItem: React.StatelessComponent< - GoToAccountManagementSimpleMenuItemProps -> = ({ onClick }) => { - return ( - <Link to={`${WebsitePaths.Portal}/account`}> - <SimpleMenuItem displayText="Manage Account..." onClick={onClick} /> - </Link> - ); -}; - -export interface DifferentWalletSimpleMenuItemProps { - onClick?: () => void; -} -export const DifferentWalletSimpleMenuItem: React.StatelessComponent<DifferentWalletSimpleMenuItemProps> = ({ - onClick, -}) => { - return <SimpleMenuItem displayText="Use Ledger Wallet..." onClick={onClick} />; -}; diff --git a/packages/website/ts/components/ui/spinner.tsx b/packages/website/ts/components/ui/spinner.tsx deleted file mode 100644 index dc73e74e3..000000000 --- a/packages/website/ts/components/ui/spinner.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; -import { styled } from 'ts/style/theme'; - -import { dash, rotate } from 'ts/style/keyframes'; - -interface SpinnerSvgProps { - color: string; - size: number; - viewBox?: string; -} - -const SpinnerSvg: React.StatelessComponent<SpinnerSvgProps> = props => <svg {...props} />; - -const StyledSpinner = styled(SpinnerSvg)` - animation: ${rotate} 3s linear infinite; - margin: ${props => `-${props.size / 2}px 0 0 -${props.size / 2}px`}; - margin-top: ${props => `-${props.size / 2}px`}; - margin-left: ${props => `-${props.size / 2}px`}; - margin-bottom: 0px; - margin-right: 0px; - size: ${props => `${props.size}px`}; - height: ${props => `${props.size}px`}; - - & .path { - stroke: ${props => props.color}; - stroke-linecap: round; - animation: ${dash} 2.5s ease-in-out infinite; - } -`; - -export interface SpinnerProps { - size?: number; - strokeSize?: number; - color?: string; -} - -export const Spinner: React.StatelessComponent<SpinnerProps> = ({ size, strokeSize, color }) => { - const c = size / 2; - const r = c - strokeSize; - return ( - <StyledSpinner color={color} size={size} viewBox={`0 0 ${size} ${size}`}> - <circle className="path" cx={c} cy={c} r={r} fill="none" strokeWidth={strokeSize} /> - </StyledSpinner> - ); -}; - -Spinner.defaultProps = { - size: 50, - color: colors.mediumBlue, - strokeSize: 4, -}; - -Spinner.displayName = 'Spinner'; diff --git a/packages/website/ts/components/ui/swap_icon.tsx b/packages/website/ts/components/ui/swap_icon.tsx deleted file mode 100644 index 406da8fe1..000000000 --- a/packages/website/ts/components/ui/swap_icon.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as React from 'react'; - -interface SwapIconProps { - swapTokensFn: () => void; -} - -interface SwapIconState { - isHovering: boolean; -} - -export class SwapIcon extends React.Component<SwapIconProps, SwapIconState> { - public constructor(props: SwapIconProps) { - super(props); - this.state = { - isHovering: false, - }; - } - public render(): React.ReactNode { - const swapStyles = { - color: this.state.isHovering ? colors.amber600 : colors.amber800, - fontSize: 50, - }; - return ( - <div - className="mx-auto pt4" - style={{ cursor: 'pointer', height: 50, width: 37.5 }} - onClick={this.props.swapTokensFn} - onMouseEnter={this._onToggleHover.bind(this, true)} - onMouseLeave={this._onToggleHover.bind(this, false)} - > - <i style={swapStyles} className="zmdi zmdi-swap" /> - </div> - ); - } - private _onToggleHover(isHovering: boolean): void { - this.setState({ - isHovering, - }); - } -} diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx deleted file mode 100644 index 046442ee5..000000000 --- a/packages/website/ts/components/ui/text.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { darken } from 'polished'; -import * as React from 'react'; -import { styled } from 'ts/style/theme'; - -export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i' | 'span'; - -export interface TextProps { - className?: string; - children?: any; - Tag?: TextTag; - fontSize?: string; - fontFamily?: string; - fontStyle?: string; - fontColor?: string; - lineHeight?: string; - minHeight?: string; - center?: boolean; - fontWeight?: number | string; - textDecorationLine?: string; - onClick?: (event: React.MouseEvent<HTMLElement>) => void; - hoverColor?: string; - letterSpacing?: string | number; - noWrap?: boolean; - textAlign?: string; - display?: string; -} - -const PlainText: React.StatelessComponent<TextProps> = ({ children, className, onClick, Tag }) => ( - <Tag className={className} onClick={onClick}> - {children} - </Tag> -); - -export const Text = styled(PlainText)` - font-family: ${props => props.fontFamily}; - font-style: ${props => props.fontStyle}; - font-weight: ${props => props.fontWeight}; - font-size: ${props => props.fontSize}; - text-align: ${props => props.textAlign}; - letter-spacing: ${props => props.letterSpacing}; - text-decoration-line: ${props => props.textDecorationLine}; - ${props => (props.lineHeight ? `line-height: ${props.lineHeight}` : '')}; - ${props => (props.center ? 'text-align: center' : '')}; - color: ${props => props.fontColor}; - ${props => (props.minHeight ? `min-height: ${props.minHeight}` : '')}; - ${props => (props.onClick ? 'cursor: pointer' : '')}; - transition: color 0.5s ease; - ${props => (props.noWrap ? 'white-space: nowrap' : '')}; - ${props => (props.display ? `display: ${props.display}` : '')}; - &:hover { - ${props => (props.onClick ? `color: ${props.hoverColor || darken(0.3, props.fontColor)}` : '')}; - } -`; - -Text.defaultProps = { - fontFamily: 'Roboto', - fontStyle: 'normal', - fontWeight: 400, - fontColor: colors.black, - fontSize: '15px', - lineHeight: '1.5em', - textDecorationLine: 'none', - Tag: 'div', - noWrap: false, -}; - -Text.displayName = 'Text'; - -export const Title: React.StatelessComponent<TextProps> = props => <Text {...props} />; - -Title.defaultProps = { - Tag: 'h2', - fontSize: '20px', - fontWeight: 600, - fontColor: colors.black, -}; - -Title.displayName = 'Title'; diff --git a/packages/website/ts/components/ui/token_icon.tsx b/packages/website/ts/components/ui/token_icon.tsx deleted file mode 100644 index 0875cc56b..000000000 --- a/packages/website/ts/components/ui/token_icon.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import { Identicon } from 'ts/components/ui/identicon'; -import { Token } from 'ts/types'; - -interface TokenIconProps { - token: Token; - diameter: number; - link?: string; -} - -interface TokenIconState {} - -export class TokenIcon extends React.Component<TokenIconProps, TokenIconState> { - public render(): React.ReactNode { - const token = this.props.token; - const diameter = this.props.diameter; - const icon = - token.isRegistered && !_.isUndefined(token.iconUrl) ? ( - <img style={{ width: diameter, height: diameter }} src={token.iconUrl} /> - ) : ( - <Identicon address={token.address} diameter={diameter} /> - ); - if (_.isEmpty(this.props.link)) { - return icon; - } else { - return ( - <a href={this.props.link} target="_blank" style={{ textDecoration: 'none' }}> - {icon} - </a> - ); - } - } -} diff --git a/packages/website/ts/components/visual_order.tsx b/packages/website/ts/components/visual_order.tsx deleted file mode 100644 index d723757d2..000000000 --- a/packages/website/ts/components/visual_order.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { Party } from 'ts/components/ui/party'; -import { AssetToken, Token, TokenByAddress } from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { utils } from 'ts/utils/utils'; - -interface VisualOrderProps { - makerAssetToken: AssetToken; - takerAssetToken: AssetToken; - makerToken: Token; - takerToken: Token; - networkId: number; - tokenByAddress: TokenByAddress; - isMakerTokenAddressInRegistry: boolean; - isTakerTokenAddressInRegistry: boolean; -} - -interface VisualOrderState {} - -export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderState> { - public render(): React.ReactNode { - const allTokens = _.values(this.props.tokenByAddress); - const makerImage = this.props.makerToken.iconUrl; - const takerImage = this.props.takerToken.iconUrl; - return ( - <div> - <div className="clearfix"> - <div className="col col-5 center"> - <Party - label="Send" - address={this.props.takerToken.address} - alternativeImage={takerImage} - networkId={this.props.networkId} - isInTokenRegistry={this.props.isTakerTokenAddressInRegistry} - hasUniqueNameAndSymbol={utils.hasUniqueNameAndSymbol(allTokens, this.props.takerToken)} - /> - </div> - <div className="col col-2 center pt1"> - <div className="pb1"> - {this._renderAmount(this.props.takerAssetToken, this.props.takerToken)} - </div> - <div className="lg-p2 md-p2 sm-p1"> - <img src="/images/trade_arrows.png" style={{ width: 47 }} /> - </div> - <div className="pt1"> - {this._renderAmount(this.props.makerAssetToken, this.props.makerToken)} - </div> - </div> - <div className="col col-5 center"> - <Party - label="Receive" - address={this.props.makerToken.address} - alternativeImage={makerImage} - networkId={this.props.networkId} - isInTokenRegistry={this.props.isMakerTokenAddressInRegistry} - hasUniqueNameAndSymbol={utils.hasUniqueNameAndSymbol(allTokens, this.props.makerToken)} - /> - </div> - </div> - </div> - ); - } - private _renderAmount(assetToken: AssetToken, token: Token): React.ReactNode { - const unitAmount = Web3Wrapper.toUnitAmount(assetToken.amount, token.decimals); - return ( - <div style={{ fontSize: 13 }}> - {unitAmount.toNumber().toFixed(configs.AMOUNT_DISPLAY_PRECSION)} {token.symbol} - </div> - ); - } -} diff --git a/packages/website/ts/components/wallet/body_overlay.tsx b/packages/website/ts/components/wallet/body_overlay.tsx deleted file mode 100644 index 3795f0eaa..000000000 --- a/packages/website/ts/components/wallet/body_overlay.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Blockchain } from 'ts/blockchain'; -import { Container } from 'ts/components/ui/container'; -import { Image } from 'ts/components/ui/image'; -import { Island } from 'ts/components/ui/island'; -import { Text } from 'ts/components/ui/text'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { colors } from 'ts/style/colors'; -import { styled } from 'ts/style/theme'; -import { AccountState, ProviderType } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -const METAMASK_IMG_SRC = '/images/metamask_icon.png'; -const COINBASE_WALLET_IMG_SRC = '/images/coinbase_wallet_logo.png'; - -export interface BodyOverlayProps { - dispatcher: Dispatcher; - userAddress: string; - injectedProviderName: string; - providerType: ProviderType; - onToggleLedgerDialog: () => void; - blockchain?: Blockchain; - blockchainIsLoaded: boolean; -} - -interface BodyOverlayState {} - -export class BodyOverlay extends React.Component<BodyOverlayProps, BodyOverlayState> { - public render(): React.ReactNode { - const accountState = this._getAccountState(); - switch (accountState) { - case AccountState.Locked: - return <LockedOverlay onUseDifferentWalletClicked={this.props.onToggleLedgerDialog} />; - case AccountState.Disconnected: - return <DisconnectedOverlay onUseDifferentWalletClicked={this.props.onToggleLedgerDialog} />; - case AccountState.Ready: - case AccountState.Loading: - default: - return null; - } - } - private _isBlockchainReady(): boolean { - return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain); - } - private _getAccountState(): AccountState { - return utils.getAccountState( - this._isBlockchainReady(), - this.props.providerType, - this.props.injectedProviderName, - this.props.userAddress, - ); - } -} - -interface LockedOverlayProps { - className?: string; - onUseDifferentWalletClicked?: () => void; -} -const PlainLockedOverlay: React.StatelessComponent<LockedOverlayProps> = ({ - className, - onUseDifferentWalletClicked, -}) => ( - <div className={className}> - <Container - className="flex flex-column items-center" - marginBottom="24px" - marginTop="24px" - marginLeft="48px" - marginRight="48px" - > - <Image src={METAMASK_IMG_SRC} height="70px" /> - <Container marginTop="12px"> - <Text fontColor={colors.metaMaskOrange} fontSize="16px" fontWeight="bold"> - Please Unlock MetaMask - </Text> - </Container> - <UseDifferentWallet fontColor={colors.darkGrey} onClick={onUseDifferentWalletClicked} /> - </Container> - </div> -); -const LockedOverlay = styled(PlainLockedOverlay)` - background: ${colors.metaMaskTransparentOrange}; - border: 1px solid ${colors.metaMaskOrange}; - border-radius: 10px; -`; - -interface DisconnectedOverlayProps { - onUseDifferentWalletClicked?: () => void; -} -const DisconnectedOverlay = (props: DisconnectedOverlayProps) => { - return ( - <div className="flex flex-column items-center"> - <GetWalletCallToAction /> - {!utils.isMobileOperatingSystem() && ( - <UseDifferentWallet fontColor={colors.mediumBlue} onClick={props.onUseDifferentWalletClicked} /> - )} - </div> - ); -}; - -interface UseDifferentWallet { - fontColor: string; - onClick?: () => void; -} -const UseDifferentWallet = (props: UseDifferentWallet) => { - return ( - <Container marginTop="12px"> - <Text fontColor={props.fontColor} fontSize="16px" textDecorationLine="underline" onClick={props.onClick}> - Use a different wallet - </Text> - </Container> - ); -}; - -const GetWalletCallToAction = () => { - const [downloadLink, isOnMobile] = utils.getBestWalletDownloadLinkAndIsMobile(); - const imageUrl = isOnMobile ? COINBASE_WALLET_IMG_SRC : METAMASK_IMG_SRC; - const text = isOnMobile ? 'Get Coinbase Wallet' : 'Get MetaMask Wallet'; - return ( - <a href={downloadLink} target="_blank" style={{ textDecoration: 'none' }}> - <Island - className="flex items-center py1 px2" - style={{ height: 28, borderRadius: 28, backgroundColor: colors.mediumBlue }} - > - <Image src={imageUrl} width="28px" borderRadius="22%" /> - <Container marginLeft="8px" marginRight="12px"> - <Text fontColor={colors.white} fontSize="16px" fontWeight={500}> - {text} - </Text> - </Container> - </Island> - </a> - ); -}; diff --git a/packages/website/ts/components/wallet/null_token_row.tsx b/packages/website/ts/components/wallet/null_token_row.tsx deleted file mode 100644 index a1ec9871a..000000000 --- a/packages/website/ts/components/wallet/null_token_row.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from 'react'; - -import { Circle } from 'ts/components/ui/circle'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { PlaceHolder } from 'ts/components/wallet/placeholder'; -import { StandardIconRow } from 'ts/components/wallet/standard_icon_row'; -import { colors } from 'ts/style/colors'; - -export interface NullTokenRowProps { - iconDimension: number; - fillColor: string; -} - -export const NullTokenRow: React.StatelessComponent<NullTokenRowProps> = ({ iconDimension, fillColor }) => { - const icon = <Circle diameter={iconDimension} fillColor={fillColor} />; - const main = ( - <div className="flex flex-column"> - <PlaceHolder hideChildren={true} fillColor={fillColor}> - <Text fontSize="16px" fontWeight="bold" lineHeight="1em"> - 0.00 XXX - </Text> - </PlaceHolder> - <Container marginTop="3px"> - <PlaceHolder hideChildren={true} fillColor={fillColor}> - <Text fontSize="14px" fontColor={colors.darkGrey} lineHeight="1em"> - $0.00 - </Text> - </PlaceHolder> - </Container> - </div> - ); - const accessory = ( - <Container marginRight="12px"> - <PlaceHolder hideChildren={true} fillColor={fillColor}> - <Container width="20px" height="14px" /> - </PlaceHolder> - </Container> - ); - return <StandardIconRow icon={icon} main={main} accessory={accessory} />; -}; diff --git a/packages/website/ts/components/wallet/placeholder.tsx b/packages/website/ts/components/wallet/placeholder.tsx deleted file mode 100644 index bf40d2ea8..000000000 --- a/packages/website/ts/components/wallet/placeholder.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import * as React from 'react'; - -import { styled } from 'ts/style/theme'; - -export interface PlaceHolderProps { - className?: string; - hideChildren: React.ReactNode; - fillColor: string; -} - -const PlainPlaceHolder: React.StatelessComponent<PlaceHolderProps> = ({ className, hideChildren, children }) => { - const childrenVisibility = hideChildren ? 'hidden' : 'visible'; - const childrenStyle: React.CSSProperties = { visibility: childrenVisibility }; - return ( - <div className={className}> - <div style={childrenStyle}>{children}</div> - </div> - ); -}; - -export const PlaceHolder = styled(PlainPlaceHolder)` - background-color: ${props => (props.hideChildren ? props.fillColor : 'transparent')}; - display: inline-block; - border-radius: 2px; -`; diff --git a/packages/website/ts/components/wallet/standard_icon_row.tsx b/packages/website/ts/components/wallet/standard_icon_row.tsx deleted file mode 100644 index 1a2ec021b..000000000 --- a/packages/website/ts/components/wallet/standard_icon_row.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; - -import { colors } from 'ts/style/colors'; -import { styled } from 'ts/style/theme'; - -export interface StandardIconRowProps { - className?: string; - icon: React.ReactNode; - main: React.ReactNode; - accessory?: React.ReactNode; - minHeight?: string; - borderBottomColor?: string; - borderBottomStyle?: string; - borderWidth?: string; - backgroundColor?: string; -} -const PlainStandardIconRow: React.StatelessComponent<StandardIconRowProps> = ({ className, icon, main, accessory }) => { - return ( - <div className={`flex items-center ${className}`}> - <div className="flex items-center px2">{icon}</div> - <div className="flex-none pr2">{main}</div> - <div className="flex-auto" /> - <div>{accessory}</div> - </div> - ); -}; - -export const StandardIconRow = styled(PlainStandardIconRow)` - min-height: ${props => props.minHeight}; - border-bottom-color: ${props => props.borderBottomColor}; - border-bottom-style: ${props => props.borderBottomStyle}; - border-width: ${props => props.borderWidth}; - background-color: ${props => props.backgroundColor}; -`; - -StandardIconRow.defaultProps = { - minHeight: '85px', - borderBottomColor: colors.walletBorder, - borderBottomStyle: 'solid', - borderWidth: '1px', - backgroundColor: colors.walletDefaultItemBackground, -}; - -StandardIconRow.displayName = 'StandardIconRow'; diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx deleted file mode 100644 index d9da0b9d5..000000000 --- a/packages/website/ts/components/wallet/wallet.tsx +++ /dev/null @@ -1,527 +0,0 @@ -import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared'; -import { BigNumber, errorUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; -import * as React from 'react'; -import firstBy from 'thenby'; - -import { Blockchain } from 'ts/blockchain'; -import { AccountConnection } from 'ts/components/ui/account_connection'; -import { Balance } from 'ts/components/ui/balance'; -import { Container } from 'ts/components/ui/container'; -import { DropDown, DropdownMouseEvent } from 'ts/components/ui/drop_down'; -import { IconButton } from 'ts/components/ui/icon_button'; -import { Identicon } from 'ts/components/ui/identicon'; -import { Island } from 'ts/components/ui/island'; -import { PointerDirection } from 'ts/components/ui/pointer'; -import { - CopyAddressSimpleMenuItem, - DifferentWalletSimpleMenuItem, - GoToAccountManagementSimpleMenuItem, - SimpleMenu, - SimpleMenuItem, -} from 'ts/components/ui/simple_menu'; -import { Text } from 'ts/components/ui/text'; -import { TokenIcon } from 'ts/components/ui/token_icon'; -import { BodyOverlay } from 'ts/components/wallet/body_overlay'; -import { NullTokenRow } from 'ts/components/wallet/null_token_row'; -import { PlaceHolder } from 'ts/components/wallet/placeholder'; -import { StandardIconRow } from 'ts/components/wallet/standard_icon_row'; -import { WrapEtherItem } from 'ts/components/wallet/wrap_ether_item'; -import { AllowanceStateToggle } from 'ts/containers/inputs/allowance_state_toggle'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { colors } from 'ts/style/colors'; -import { - AccountState, - BlockchainErrs, - ProviderType, - ScreenWidths, - Side, - Token, - TokenByAddress, - TokenState, - TokenStateByAddress, -} from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; -import { constants } from 'ts/utils/constants'; -import { utils } from 'ts/utils/utils'; - -export interface WalletProps { - userAddress: string; - networkId: number; - blockchain: Blockchain; - blockchainIsLoaded: boolean; - blockchainErr: BlockchainErrs; - dispatcher: Dispatcher; - tokenByAddress: TokenByAddress; - trackedTokens: Token[]; - userEtherBalanceInWei?: BigNumber; - lastForceTokenStateRefetch: number; - injectedProviderName: string; - providerType: ProviderType; - screenWidth: ScreenWidths; - location: Location; - trackedTokenStateByAddress: TokenStateByAddress; - onToggleLedgerDialog: () => void; - onAddToken: () => void; - onRemoveToken: () => void; - refetchTokenStateAsync: (tokenAddress: string) => Promise<void>; - style: React.CSSProperties; - toggleTooltipDirection?: PointerDirection; -} - -interface WalletState { - wrappedEtherDirection?: Side; - isHoveringSidebar: boolean; -} - -interface AllowanceStateToggleConfig { - token: Token; - tokenState: TokenState; -} - -interface AccessoryItemConfig { - wrappedEtherDirection?: Side; - allowanceStateToggleConfig?: AllowanceStateToggleConfig; -} - -const ETHER_ICON_PATH = '/images/ether.png'; -const ICON_DIMENSION = 28; -const BODY_ITEM_KEY = 'BODY'; -const HEADER_ITEM_KEY = 'HEADER'; -const ETHER_ITEM_KEY = 'ETHER'; -const WRAP_ROW_ALLOWANCE_TOGGLE_WIDTH = 67; -const ALLOWANCE_TOGGLE_WIDTH = 56; -const PLACEHOLDER_COLOR = colors.grey300; -const LOADING_ROWS_COUNT = 6; - -export class Wallet extends React.Component<WalletProps, WalletState> { - public static defaultProps = { - style: {}, - }; - constructor(props: WalletProps) { - super(props); - this.state = { - wrappedEtherDirection: undefined, - isHoveringSidebar: false, - }; - } - public componentDidUpdate(prevProps: WalletProps): void { - const currentTrackedTokens = this.props.trackedTokens; - const differentTrackedTokens = _.difference(currentTrackedTokens, prevProps.trackedTokens); - const firstDifferentTrackedToken = _.head(differentTrackedTokens); - // check if there is only one different token, and if that token is a member of the current tracked tokens - // this means that the token was added, not removed - if ( - !_.isUndefined(firstDifferentTrackedToken) && - _.size(differentTrackedTokens) === 1 && - _.includes(currentTrackedTokens, firstDifferentTrackedToken) - ) { - document.getElementById(firstDifferentTrackedToken.address).scrollIntoView(); - } - } - public render(): React.ReactNode { - return ( - <Island className="flex flex-column wallet" style={this.props.style}> - {this._isBlockchainReady() ? this._renderLoadedRows() : this._renderLoadingRows()} - </Island> - ); - } - private _renderLoadingRows(): React.ReactNode { - return _.concat(this._renderLoadingHeaderRows(), this._renderLoadingBodyRows()); - } - private _renderLoadingHeaderRows(): React.ReactElement<{}> { - return this._renderPlainHeaderRow('Loading...'); - } - private _renderLoadingBodyRows(): React.ReactElement<{}> { - const bodyStyle = this._getBodyStyle(); - const loadingRowsRange = _.range(LOADING_ROWS_COUNT); - return ( - <div key={BODY_ITEM_KEY} className="flex flex-column" style={bodyStyle}> - {_.map(loadingRowsRange, index => { - return <NullTokenRow key={index} iconDimension={ICON_DIMENSION} fillColor={PLACEHOLDER_COLOR} />; - })} - <Container - className="flex items-center" - position="absolute" - width="100%" - height="100%" - maxHeight={bodyStyle.maxHeight} - > - <div className="mx-auto"> - <BodyOverlay - dispatcher={this.props.dispatcher} - userAddress={this.props.userAddress} - injectedProviderName={this.props.injectedProviderName} - providerType={this.props.providerType} - onToggleLedgerDialog={this.props.onToggleLedgerDialog} - blockchain={this.props.blockchain} - blockchainIsLoaded={this.props.blockchainIsLoaded} - /> - </div> - </Container> - </div> - ); - } - private _renderLoadedRows(): React.ReactNode { - const isAddressAvailable = !_.isEmpty(this.props.userAddress); - return isAddressAvailable - ? _.concat(this._renderConnectedHeaderRows(), this._renderBody()) - : _.concat(this._renderDisconnectedHeaderRows(), this._renderLoadingBodyRows()); - } - private _renderDisconnectedHeaderRows(): React.ReactElement<{}> { - const isExternallyInjectedProvider = utils.isExternallyInjected( - this.props.providerType, - this.props.injectedProviderName, - ); - const text = isExternallyInjectedProvider ? 'Please unlock MetaMask...' : 'Please connect a wallet...'; - return this._renderPlainHeaderRow(text); - } - private _renderPlainHeaderRow(text: string): React.ReactElement<{}> { - return ( - <StandardIconRow - key={HEADER_ITEM_KEY} - icon={<ActionAccountBalanceWallet color={colors.grey} />} - main={ - <Text fontSize="16px" fontColor={colors.grey}> - {text} - </Text> - // https://github.com/palantir/tslint-react/issues/140 - // tslint:disable-next-line:jsx-curly-spacing - } - minHeight="60px" - backgroundColor={colors.white} - /> - ); - } - private _renderConnectedHeaderRows(): React.ReactElement<{}> { - const isMobile = this.props.screenWidth === ScreenWidths.Sm; - const userAddress = this.props.userAddress; - const accountState = this._getAccountState(); - const main = ( - <div className="flex flex-column"> - <Text fontSize="16px" lineHeight="19px" fontWeight={500}> - {utils.getAddressBeginAndEnd(userAddress)} - </Text> - <AccountConnection accountState={accountState} injectedProviderName={this.props.injectedProviderName} /> - </div> - ); - const onClick = _.noop.bind(_); - const accessory = ( - <DropDown - activeNode={ - // this container gives the menu button more of a hover target for the drop down - // it prevents accidentally closing the menu by moving off of the button - <Container paddingLeft="100px" paddingRight="15px"> - <Text - className="zmdi zmdi-more-horiz" - Tag="i" - fontSize="32px" - fontFamily="Material-Design-Iconic-Font" - fontColor={colors.darkGrey} - onClick={onClick} - hoverColor={colors.mediumBlue} - /> - </Container> - } - popoverContent={ - <SimpleMenu minWidth="150px"> - <CopyAddressSimpleMenuItem userAddress={this.props.userAddress} /> - {!isMobile && <DifferentWalletSimpleMenuItem onClick={this.props.onToggleLedgerDialog} />} - <SimpleMenuItem displayText="Add Tokens..." onClick={this.props.onAddToken} /> - <SimpleMenuItem displayText="Remove Tokens..." onClick={this.props.onRemoveToken} /> - {!isMobile && <GoToAccountManagementSimpleMenuItem />} - </SimpleMenu> - } - anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} - targetOrigin={{ horizontal: 'right', vertical: 'top' }} - zDepth={1} - activateEvent={DropdownMouseEvent.Click} - closeEvent={DropdownMouseEvent.Click} - /> - ); - return ( - <StandardIconRow - key={HEADER_ITEM_KEY} - icon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />} - main={main} - accessory={accessory} - minHeight="60px" - backgroundColor={colors.white} - /> - ); - } - private _renderBody(): React.ReactElement<{}> { - const bodyStyle = this._getBodyStyle(); - return ( - <div - style={bodyStyle} - key={BODY_ITEM_KEY} - onMouseEnter={this._onSidebarHover.bind(this)} - onMouseLeave={this._onSidebarHoverOff.bind(this)} - > - {this._renderEthRows()} - {this._renderTokenRows()} - </div> - ); - } - private _getBodyStyle(): React.CSSProperties { - return { - overflow: 'auto', - WebkitOverflowScrolling: 'touch', - position: 'relative', - overflowY: this.state.isHoveringSidebar ? 'scroll' : 'hidden', - marginRight: this.state.isHoveringSidebar ? 0 : 4, - minHeight: '250px', - maxHeight: !utils.isMobileWidth(this.props.screenWidth) ? 'calc(90vh - 300px)' : undefined, - }; - } - private _onSidebarHover(_event: React.FormEvent<HTMLInputElement>): void { - this.setState({ - isHoveringSidebar: true, - }); - } - private _onSidebarHoverOff(): void { - this.setState({ - isHoveringSidebar: false, - }); - } - private _renderEthRows(): React.ReactNode { - const icon = <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />; - const primaryText = this._renderAmount( - this.props.userEtherBalanceInWei || new BigNumber(0), - constants.DECIMAL_PLACES_ETH, - constants.ETHER_SYMBOL, - _.isUndefined(this.props.userEtherBalanceInWei), - ); - const etherToken = this._getEthToken(); - const etherTokenState = this.props.trackedTokenStateByAddress[etherToken.address]; - const etherPrice = etherTokenState.price; - const secondaryText = this._renderValue( - this.props.userEtherBalanceInWei || new BigNumber(0), - constants.DECIMAL_PLACES_ETH, - etherPrice, - _.isUndefined(this.props.userEtherBalanceInWei) || !etherTokenState.isLoaded, - ); - const accessoryItemConfig = { - wrappedEtherDirection: Side.Deposit, - }; - const key = ETHER_ITEM_KEY; - return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig); - } - private _renderTokenRows(): React.ReactNode { - const trackedTokens = this.props.trackedTokens; - const trackedTokensStartingWithEtherToken = trackedTokens.sort( - firstBy((t: Token) => t.symbol !== constants.ETHER_TOKEN_SYMBOL) - .thenBy((t: Token) => t.symbol !== constants.ZRX_TOKEN_SYMBOL) - .thenBy('trackedTimestamp'), - ); - return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this)); - } - private _renderTokenRow(token: Token): React.ReactNode { - const tokenState = this.props.trackedTokenStateByAddress[token.address]; - if (_.isUndefined(tokenState)) { - return null; - } - const tokenLink = sharedUtils.getEtherScanLinkIfExists( - token.address, - this.props.networkId, - EtherscanLinkSuffixes.Address, - ); - const icon = <TokenIcon token={token} diameter={ICON_DIMENSION} link={tokenLink} />; - const isWeth = token.symbol === constants.ETHER_TOKEN_SYMBOL; - const wrappedEtherDirection = isWeth ? Side.Receive : undefined; - const primaryText = this._renderAmount(tokenState.balance, token.decimals, token.symbol, !tokenState.isLoaded); - const secondaryText = this._renderValue( - tokenState.balance, - token.decimals, - tokenState.price, - !tokenState.isLoaded, - ); - const accessoryItemConfig: AccessoryItemConfig = { - wrappedEtherDirection, - allowanceStateToggleConfig: { - token, - tokenState, - }, - }; - const key = token.address; - return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig); - } - private _renderBalanceRow( - key: string, - icon: React.ReactNode, - primaryText: React.ReactNode, - secondaryText: React.ReactNode, - accessoryItemConfig: AccessoryItemConfig, - className?: string, - ): React.ReactNode { - const shouldShowWrapEtherItem = - !_.isUndefined(this.state.wrappedEtherDirection) && - this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection && - !_.isUndefined(this.props.userEtherBalanceInWei); - const etherToken = this._getEthToken(); - const wrapEtherItem = shouldShowWrapEtherItem ? ( - <WrapEtherItem - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this.props.blockchain} - dispatcher={this.props.dispatcher} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - direction={accessoryItemConfig.wrappedEtherDirection} - etherToken={etherToken} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - onConversionSuccessful={this._closeWrappedEtherActionRow.bind(this)} - // tslint:disable:jsx-no-lambda - refetchEthTokenStateAsync={async () => this.props.refetchTokenStateAsync(etherToken.address)} - /> - ) : null; - return ( - <div id={key} key={key} className={`flex flex-column ${className || ''}`}> - {this.state.wrappedEtherDirection === Side.Receive && wrapEtherItem} - <StandardIconRow - icon={icon} - main={ - <div className="flex flex-column"> - {primaryText} - <Container marginTop="3px">{secondaryText}</Container> - </div> - } - accessory={this._renderAccessoryItems(accessoryItemConfig)} - /> - {this.state.wrappedEtherDirection === Side.Deposit && wrapEtherItem} - </div> - ); - } - private _renderAccessoryItems(config: AccessoryItemConfig): React.ReactElement<{}> { - const shouldShowWrappedEtherAction = !_.isUndefined(config.wrappedEtherDirection); - const shouldShowToggle = !_.isUndefined(config.allowanceStateToggleConfig); - // if we don't have a toggle, we still want some space to the right of the "wrap" button so that it aligns with - // the "unwrap" button in the row below - const isWrapEtherRow = shouldShowWrappedEtherAction && config.wrappedEtherDirection === Side.Deposit; - const width = isWrapEtherRow ? WRAP_ROW_ALLOWANCE_TOGGLE_WIDTH : ALLOWANCE_TOGGLE_WIDTH; - const toggle = ( - <Container className="flex justify-center" width={width}> - {shouldShowToggle && this._renderAllowanceToggle(config.allowanceStateToggleConfig)} - </Container> - ); - return ( - <div className="flex items-center"> - <div className="flex-auto"> - {shouldShowWrappedEtherAction && this._renderWrappedEtherButton(config.wrappedEtherDirection)} - </div> - <div className="flex-last pl2">{toggle}</div> - </div> - ); - } - private _renderAllowanceToggle(config: AllowanceStateToggleConfig): React.ReactNode { - // TODO: Error handling - return ( - <AllowanceStateToggle - blockchain={this.props.blockchain} - token={config.token} - tokenState={config.tokenState} - tooltipDirection={this.props.toggleTooltipDirection} - refetchTokenStateAsync={async () => this.props.refetchTokenStateAsync(config.token.address)} - /> - ); - } - private _renderAmount( - amount: BigNumber, - decimals: number, - symbol: string, - isLoading: boolean = false, - ): React.ReactNode { - if (isLoading) { - return ( - <PlaceHolder hideChildren={isLoading} fillColor={PLACEHOLDER_COLOR}> - <Text fontSize="16px" fontWeight="bold" lineHeight="1em"> - 0.00 XXX - </Text> - </PlaceHolder> - ); - } else { - return <Balance amount={amount} decimals={decimals} symbol={symbol} />; - } - } - private _renderValue( - amount: BigNumber, - decimals: number, - price?: BigNumber, - isLoading: boolean = false, - ): React.ReactNode { - const result = !isLoading - ? _.isUndefined(price) - ? '--' - : utils.getUsdValueFormattedAmount(amount, decimals, price) - : '$0.00'; - return ( - <PlaceHolder hideChildren={isLoading} fillColor={PLACEHOLDER_COLOR}> - <Text fontSize="14px" fontColor={colors.darkGrey} lineHeight="1em"> - {result} - </Text> - </PlaceHolder> - ); - } - private _renderWrappedEtherButton(wrappedEtherDirection: Side): React.ReactNode { - const isWrappedEtherDirectionOpen = this.state.wrappedEtherDirection === wrappedEtherDirection; - let buttonLabel; - let buttonIconName; - if (isWrappedEtherDirectionOpen) { - buttonLabel = 'cancel'; - buttonIconName = 'zmdi-close'; - } else { - switch (wrappedEtherDirection) { - case Side.Deposit: - buttonLabel = 'wrap'; - buttonIconName = 'zmdi-long-arrow-down'; - break; - case Side.Receive: - buttonLabel = 'unwrap'; - buttonIconName = 'zmdi-long-arrow-up'; - break; - default: - throw errorUtils.spawnSwitchErr('wrappedEtherDirection', wrappedEtherDirection); - } - } - const onClick = isWrappedEtherDirectionOpen - ? this._closeWrappedEtherActionRow.bind(this, wrappedEtherDirection) - : this._openWrappedEtherActionRow.bind(this, wrappedEtherDirection); - return ( - <IconButton iconName={buttonIconName} labelText={buttonLabel} onClick={onClick} color={colors.mediumBlue} /> - ); - } - private _openWrappedEtherActionRow(wrappedEtherDirection: Side): void { - const action = - wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Opened' : 'Wallet - Unwrap WETH Opened'; - analytics.track(action); - this.setState({ - wrappedEtherDirection, - }); - } - private _closeWrappedEtherActionRow(wrappedEtherDirection: Side): void { - const action = - wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Closed' : 'Wallet - Unwrap WETH Closed'; - analytics.track(action); - this.setState({ - wrappedEtherDirection: undefined, - }); - } - private _getEthToken(): Token { - return utils.getEthToken(this.props.tokenByAddress); - } - private _isBlockchainReady(): boolean { - return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain); - } - private _getAccountState(): AccountState { - return utils.getAccountState( - this._isBlockchainReady(), - this.props.providerType, - this.props.injectedProviderName, - this.props.userAddress, - ); - } -} - -// tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/wallet/wrap_ether_item.tsx b/packages/website/ts/components/wallet/wrap_ether_item.tsx deleted file mode 100644 index 7de3afbf8..000000000 --- a/packages/website/ts/components/wallet/wrap_ether_item.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import { Styles } from '@0x/react-shared'; -import { BigNumber, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import FlatButton from 'material-ui/FlatButton'; -import * as React from 'react'; - -import { Blockchain } from 'ts/blockchain'; -import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; -import { Container } from 'ts/components/ui/container'; -import { EthAmountInput } from 'ts/containers/inputs/eth_amount_input'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { colors } from 'ts/style/colors'; -import { BlockchainCallErrs, Side, Token } from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; -import { constants } from 'ts/utils/constants'; -import { errorReporter } from 'ts/utils/error_reporter'; -import { utils } from 'ts/utils/utils'; - -export interface WrapEtherItemProps { - userAddress: string; - networkId: number; - blockchain: Blockchain; - dispatcher: Dispatcher; - userEtherBalanceInWei: BigNumber; - direction: Side; - etherToken: Token; - lastForceTokenStateRefetch: number; - onConversionSuccessful?: () => void; - refetchEthTokenStateAsync: () => Promise<void>; -} - -interface WrapEtherItemState { - currentInputAmount?: BigNumber; - isEthConversionHappening: boolean; - errorMsg: React.ReactNode; -} - -const styles: Styles = { - topLabel: { - color: colors.black, - fontSize: 11, - }, - inputContainer: { - backgroundColor: colors.white, - borderBottomRightRadius: 3, - borderBottomLeftRadius: 3, - borderTopRightRadius: 3, - borderTopLeftRadius: 3, - padding: 4, - }, - amountInput: { - height: 34, - }, - amountInputLabel: { - paddingTop: 10, - paddingRight: 10, - paddingLeft: 5, - color: colors.grey, - fontSize: 14, - }, - amountInputHint: { - bottom: 18, - }, - wrapEtherConfirmationButtonLabel: { - fontSize: 12, - color: colors.white, - }, - errorMsg: { - fontSize: 12, - marginTop: 4, - color: colors.red, - minHeight: 20, - }, - conversionSpinner: { - paddingTop: 26, - }, -}; - -export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEtherItemState> { - constructor(props: WrapEtherItemProps) { - super(props); - this.state = { - currentInputAmount: undefined, - isEthConversionHappening: false, - errorMsg: null, - }; - } - public render(): React.ReactNode { - const isWrappingEth = this.props.direction === Side.Deposit; - const topLabelText = isWrappingEth ? 'Convert ETH into WETH 1:1' : 'Convert WETH into ETH 1:1'; - return ( - <Container className="flex" backgroundColor={colors.walletFocusedItemBackground} paddingTop="25px"> - <div>{this._renderIsEthConversionHappeningSpinner()} </div> - <div className="flex flex-column"> - <div style={styles.topLabel}>{topLabelText}</div> - <div className="flex items-center"> - <div style={styles.inputContainer}> - {isWrappingEth ? ( - <EthAmountInput - amount={this.state.currentInputAmount} - hintText="0.00" - onChange={this._onValueChange.bind(this)} - shouldCheckBalance={true} - shouldShowIncompleteErrs={false} - shouldShowErrs={false} - shouldShowUnderline={false} - style={styles.amountInput} - labelStyle={styles.amountInputLabel} - inputHintStyle={styles.amountInputHint} - onErrorMsgChange={this._onErrorMsgChange.bind(this)} - /> - ) : ( - <TokenAmountInput - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - blockchain={this.props.blockchain} - userAddress={this.props.userAddress} - networkId={this.props.networkId} - token={this.props.etherToken} - shouldShowIncompleteErrs={false} - shouldCheckBalance={true} - shouldCheckAllowance={false} - onChange={this._onValueChange.bind(this)} - amount={this.state.currentInputAmount} - hintText="0.00" - shouldShowErrs={false} - shouldShowUnderline={false} - style={styles.amountInput} - labelStyle={styles.amountInputLabel} - inputHintStyle={styles.amountInputHint} - onErrorMsgChange={this._onErrorMsgChange.bind(this)} - /> - )} - </div> - <div>{this._renderWrapEtherConfirmationButton()}</div> - </div> - - {this._renderErrorMsg()} - </div> - </Container> - ); - } - private _onValueChange(_isValid: boolean, amount?: BigNumber): void { - this.setState({ - currentInputAmount: amount, - }); - } - private _onErrorMsgChange(errorMsg: React.ReactNode): void { - this.setState({ - errorMsg, - }); - } - private _renderIsEthConversionHappeningSpinner(): React.ReactElement<{}> { - const visibility = this.state.isEthConversionHappening ? 'visible' : 'hidden'; - const style: React.CSSProperties = { ...styles.conversionSpinner, visibility }; - return ( - <div className="pl3 pr2" style={style}> - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - </div> - ); - } - private _renderWrapEtherConfirmationButton(): React.ReactElement<{}> { - const isWrappingEth = this.props.direction === Side.Deposit; - const labelText = isWrappingEth ? 'wrap' : 'unwrap'; - return ( - <div className="pl1 pr3"> - <FlatButton - backgroundColor={colors.wrapEtherConfirmationButton} - label={labelText} - style={{ zIndex: 0 }} - labelStyle={styles.wrapEtherConfirmationButtonLabel} - onClick={this._wrapEtherConfirmationActionAsync.bind(this)} - disabled={this.state.isEthConversionHappening} - /> - </div> - ); - } - private _renderErrorMsg(): React.ReactNode { - return <div style={styles.errorMsg}>{this.state.errorMsg}</div>; - } - private async _wrapEtherConfirmationActionAsync(): Promise<void> { - this.setState({ - isEthConversionHappening: true, - }); - const etherToken = this.props.etherToken; - const amountToConvert = this.state.currentInputAmount; - const ethAmount = Web3Wrapper.toUnitAmount(amountToConvert, constants.DECIMAL_PLACES_ETH).toString(); - const tokenAmount = Web3Wrapper.toUnitAmount(amountToConvert, etherToken.decimals).toString(); - try { - if (this.props.direction === Side.Deposit) { - await this.props.blockchain.convertEthToWrappedEthTokensAsync(etherToken.address, amountToConvert); - this.props.dispatcher.showFlashMessage(`Successfully wrapped ${ethAmount} ETH to WETH`); - analytics.track('Wrap ETH Success', { - amount: ethAmount, - }); - } else { - await this.props.blockchain.convertWrappedEthTokensToEthAsync(etherToken.address, amountToConvert); - this.props.dispatcher.showFlashMessage(`Successfully unwrapped ${tokenAmount} WETH to ETH`); - analytics.track('Unwrap WETH Success', { - amount: tokenAmount, - }); - } - await this.props.refetchEthTokenStateAsync(); - this.props.onConversionSuccessful(); - } catch (err) { - const errMsg = `${err}`; - if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) { - this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - } else if (!utils.didUserDenyWeb3Request(errMsg)) { - logUtils.log(`Unexpected error encountered: ${err}`); - logUtils.log(err.stack); - if (this.props.direction === Side.Deposit) { - this.props.dispatcher.showFlashMessage('Failed to wrap your ETH. Please try again.'); - analytics.track('Wrap ETH Failure', { - amount: ethAmount, - }); - } else { - this.props.dispatcher.showFlashMessage('Failed to unwrap your WETH. Please try again.'); - analytics.track('Unwrap WETH Failed', { - amount: tokenAmount, - }); - } - errorReporter.report(err); - } - } - this.setState({ - isEthConversionHappening: false, - }); - } -} diff --git a/packages/website/ts/constants/.gitkeep b/packages/website/ts/constants/.gitkeep deleted file mode 100644 index e69de29bb..000000000 --- a/packages/website/ts/constants/.gitkeep +++ /dev/null diff --git a/packages/website/ts/constants/animations.tsx b/packages/website/ts/constants/animations.tsx deleted file mode 100644 index 6a58c4b40..000000000 --- a/packages/website/ts/constants/animations.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { css, keyframes } from 'styled-components'; - -export const fadeIn = keyframes` - 0% { - transform: translateY(10px); - opacity: 0; - } - 100% { - transform: translateY(0); - opacity: 1; - } -`; - -export const addFadeInAnimation = (duration: string = '0.5s', delay: string = '0s') => css` - opacity: 0; - transform: translateY(10px); - animation: ${fadeIn} ${duration} ${delay} forwards; -`; diff --git a/packages/website/ts/constants/cssReset.js b/packages/website/ts/constants/cssReset.js deleted file mode 100644 index 4c5105b50..000000000 --- a/packages/website/ts/constants/cssReset.js +++ /dev/null @@ -1,50 +0,0 @@ -export const cssReset = ` - *, - *:before, - *:after { - box-sizing: border-box; - } - html, body, div, span, applet, object, iframe, - h1, h2, h3, h4, h5, h6, p, blockquote, pre, - a, abbr, acronym, address, big, cite, code, - del, dfn, em, img, ins, kbd, q, s, samp, - small, strike, strong, sub, sup, tt, var, - b, u, i, center, - dl, dt, dd, ol, ul, li, - fieldset, form, label, legend, - table, caption, tbody, tfoot, thead, tr, th, td, - article, aside, canvas, details, embed, - figure, figcaption, footer, header, hgroup, - menu, nav, output, ruby, section, summary, - time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; - } - /* HTML5 display-role reset for older browsers */ - article, aside, details, figcaption, figure, - footer, header, hgroup, menu, nav, section { - display: block; - } - body { - line-height: 1; - } - ol, ul { - list-style: none; - } - blockquote, q { - quotes: none; - } - blockquote:before, blockquote:after, - q:before, q:after { - content: ''; - content: none; - } - table { - border-collapse: collapse; - border-spacing: 0; - } -`; diff --git a/packages/website/ts/constants/globalStyle.tsx b/packages/website/ts/constants/globalStyle.tsx deleted file mode 100644 index ef7ec9426..000000000 --- a/packages/website/ts/constants/globalStyle.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { createGlobalStyle, withTheme } from 'styled-components'; -import { cssReset } from 'ts/constants/cssReset'; - -export interface GlobalStyle { - theme: { - bgColor: string; - textColor: string; - linkColor: string; - dropdownButtonBg: string; - }; -} - -const GlobalStyles = withTheme( - createGlobalStyle<GlobalStyle>` - ${cssReset}; - - html { - font-size: 18px; - background-color: ${props => props.theme.bgColor}; - overflow-x: hidden; - } - - @media (min-width: 768px) { - :root { - --smallHeading: 20px; - --defaultHeading: 28px; - --mediumHeading: 50px; - --largeHeading: 80px; - --smallHeadingHeight: 1.4em; - --defaultHeadingHeight: 1.357142857em; - --mediumHeadingHeight: 1.16em; - --largeHeadingHeight: 1em; - --smallParagraph: 14px; - --defaultParagraph: 18px; - --mediumParagraph: 22px; - --largeParagraph: 28px; - --smallIcon: 75px; - --mediumIcon: 85px; - --largeIcon: 145px; - --heroIcon: 282px; - } - } - - @media (max-width: 1170px) { - :root { - --largeHeading: 60px; - } - } - - @media (max-width: 768px) { - :root { - --smallHeading: 18px; - --defaultHeading: 18px; - --mediumHeading: 40px; - --largeHeading: 46px; - --smallHeadingHeight: 1.4em; // TO DO - --defaultHeadingHeight: 1.357142857em; // TO DO - --mediumHeadingHeight: 1.16em; // TO DO - --largeHeadingHeight: 1.108695652em; // TO DO - --smallParagraph: 14px; // TO DO - --defaultParagraph: 16px; // TO DO - --mediumParagraph: 20px; // TO DO - --largeParagraph: 20px; // TO DO - --smallIcon: 55px; - --mediumIcon: 85px; - --largeIcon: 115px; - } - } - - body { - font-family: 'Formular', sans-serif !important; - -webkit-font-smoothing: antialiased; - color: ${props => props.theme.textColor}; - font-feature-settings: "zero"; - scroll-behavior: smooth; - } - - .visuallyHidden { - position: absolute !important; - clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ - clip: rect(1px, 1px, 1px, 1px); - padding:0 !important; - border:0 !important; - height: 1px !important; - width: 1px !important; - overflow: hidden; - } - - img, svg { - max-width: 100%; - object-fit: contain; - } - - a, button { - text-decoration: none; - font-family: inherit; - outline: none; - } - - svg + p, - img + p { - padding-top: 30px; - } -`, -); - -export { GlobalStyles }; diff --git a/packages/website/ts/constants/utilities.tsx b/packages/website/ts/constants/utilities.tsx deleted file mode 100644 index ee5c5b4ce..000000000 --- a/packages/website/ts/constants/utilities.tsx +++ /dev/null @@ -1,22 +0,0 @@ -export interface PaddingInterface { - padding?: number | Array<'large' | 'default' | 'small' | number>; - margin?: number | Array<'large' | 'default' | 'small' | number>; -} - -interface PaddingSizes { - [key: string]: string; -} - -export const PADDING_SIZES: PaddingSizes = { - default: '30px', - large: '60px', - small: '15px', -}; - -export const getCSSPadding = (value: number | Array<string | number> = 0): string => { - if (Array.isArray(value)) { - return value.map(val => PADDING_SIZES[val] || `${val}px`).join(' '); - } else { - return `${value}px`; - } -}; diff --git a/packages/website/ts/containers/asset_buyer_documentation.ts b/packages/website/ts/containers/asset_buyer_documentation.ts deleted file mode 100644 index a75c6d861..000000000 --- a/packages/website/ts/containers/asset_buyer_documentation.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown = require('md/docs/asset_buyer/introduction'); -const InstallationMarkdown = require('md/docs/asset_buyer/installation'); -const UsageMarkdown = require('md/docs/asset_buyer/usage'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', - usage: 'usage', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.AssetBuyer, - packageName: '@0x/asset-buyer', - type: SupportedDocJson.TypeDoc, - displayName: 'AssetBuyer', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/asset-buyer', - markdownMenu: { - introduction: [markdownSections.introduction], - install: [markdownSections.installation], - usage: [markdownSections.usage], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown, - [markdownSections.installation]: InstallationMarkdown, - [markdownSections.usage]: UsageMarkdown, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/connect_documentation.ts b/packages/website/ts/containers/connect_documentation.ts deleted file mode 100644 index 1cfc0702e..000000000 --- a/packages/website/ts/containers/connect_documentation.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/connect/1/introduction'); -const IntroMarkdown2 = require('md/docs/connect/2/introduction'); -const InstallationMarkdown1 = require('md/docs/connect/1/installation'); -const InstallationMarkdown3 = require('md/docs/connect/3/installation'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.Connect, - packageName: '@0x/connect', - type: SupportedDocJson.TypeDoc, - displayName: '0x Connect', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/connect', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - }, - '2.0.0-rc.1': { - [markdownSections.introduction]: IntroMarkdown2, - [markdownSections.installation]: InstallationMarkdown1, - }, - '3.0.2': { - [markdownSections.introduction]: IntroMarkdown2, - [markdownSections.installation]: InstallationMarkdown3, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/contract_wrappers_documentation.ts b/packages/website/ts/containers/contract_wrappers_documentation.ts deleted file mode 100644 index bbabce7a7..000000000 --- a/packages/website/ts/containers/contract_wrappers_documentation.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/contract_wrappers/1/introduction'); -const InstallMarkdownV1 = require('md/docs/contract_wrappers/1/installation'); -const InstallMarkdownV2 = require('md/docs/contract_wrappers/2/installation'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.ContractWrappers, - packageName: '@0x/contract-wrappers', - type: SupportedDocJson.TypeDoc, - displayName: 'Contract Wrappers', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/contract-wrappers', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallMarkdownV1, - }, - '3.0.0': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallMarkdownV2, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/docs_home.ts b/packages/website/ts/containers/docs_home.ts deleted file mode 100644 index 2a6dac0e2..000000000 --- a/packages/website/ts/containers/docs_home.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { DocsHome as DocsHomeComponent, DocsHomeProps } from 'ts/pages/documentation/docs_home'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { ScreenWidths } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; - -interface ConnectedState { - translate: Translate; - screenWidth: ScreenWidths; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, _ownProps: DocsHomeProps): ConnectedState => ({ - translate: state.translate, - screenWidth: state.screenWidth, -}); - -const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const DocsHome: React.ComponentClass<DocsHomeProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocsHomeComponent); diff --git a/packages/website/ts/containers/ethereum_types_documentation.ts b/packages/website/ts/containers/ethereum_types_documentation.ts deleted file mode 100644 index e6e4d4067..000000000 --- a/packages/website/ts/containers/ethereum_types_documentation.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { constants as docConstants, DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown = require('md/docs/ethereum_types/introduction'); -const InstallationMarkdown = require('md/docs/ethereum_types/installation'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', - types: docConstants.TYPES_SECTION_NAME, -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.EthereumTypes, - packageName: 'ethereum-types', - type: SupportedDocJson.TypeDoc, - displayName: 'Ethereum Types', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/ethereum-types', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown, - [markdownSections.installation]: InstallationMarkdown, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/faq.ts b/packages/website/ts/containers/faq.ts deleted file mode 100644 index da5b71bdd..000000000 --- a/packages/website/ts/containers/faq.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { FAQ as FAQComponent, FAQProps } from 'ts/pages/faq/faq'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { Translate } from 'ts/utils/translate'; - -interface ConnectedState { - translate: Translate; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, _ownProps: FAQProps): ConnectedState => ({ - translate: state.translate, -}); - -const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const FAQ: React.ComponentClass<FAQProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(FAQComponent); diff --git a/packages/website/ts/containers/generate_order_form.ts b/packages/website/ts/containers/generate_order_form.ts deleted file mode 100644 index 98b2831ce..000000000 --- a/packages/website/ts/containers/generate_order_form.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Blockchain } from 'ts/blockchain'; -import { GenerateOrderForm as GenerateOrderFormComponent } from 'ts/components/generate_order/generate_order_form'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { BlockchainErrs, HashData, SideToAssetToken, TokenByAddress } from 'ts/types'; - -interface GenerateOrderFormProps { - blockchain: Blockchain; - hashData: HashData; - dispatcher: Dispatcher; - isFullWidth?: boolean; - shouldHideHeader?: boolean; -} - -interface ConnectedState { - blockchainErr: BlockchainErrs; - blockchainIsLoaded: boolean; - orderExpiryTimestamp: BigNumber; - orderSignature: string; - userAddress: string; - orderTakerAddress: string; - orderSalt: BigNumber; - networkId: number; - sideToAssetToken: SideToAssetToken; - tokenByAddress: TokenByAddress; - lastForceTokenStateRefetch: number; -} - -const mapStateToProps = (state: State, _ownProps: GenerateOrderFormProps): ConnectedState => ({ - blockchainErr: state.blockchainErr, - blockchainIsLoaded: state.blockchainIsLoaded, - orderExpiryTimestamp: state.orderExpiryTimestamp, - orderSignature: state.orderSignature, - orderTakerAddress: state.orderTakerAddress, - orderSalt: state.orderSalt, - networkId: state.networkId, - sideToAssetToken: state.sideToAssetToken, - tokenByAddress: state.tokenByAddress, - userAddress: state.userAddress, - lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, -}); - -export const GenerateOrderForm: React.ComponentClass<GenerateOrderFormProps> = connect(mapStateToProps)( - GenerateOrderFormComponent, -); diff --git a/packages/website/ts/containers/inputs/allowance_state_toggle.ts b/packages/website/ts/containers/inputs/allowance_state_toggle.ts deleted file mode 100644 index 70712685e..000000000 --- a/packages/website/ts/containers/inputs/allowance_state_toggle.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { Blockchain } from 'ts/blockchain'; -import { PointerDirection } from 'ts/components/ui/pointer'; -import { State } from 'ts/redux/reducer'; -import { BalanceErrs, Token, TokenState } from 'ts/types'; - -import { AllowanceStateToggle as AllowanceStateToggleComponent } from 'ts/components/inputs/allowance_state_toggle'; -import { Dispatcher } from 'ts/redux/dispatcher'; - -interface AllowanceStateToggleProps { - blockchain: Blockchain; - onErrorOccurred?: (errType: BalanceErrs) => void; - token: Token; - tokenState: TokenState; - refetchTokenStateAsync: () => Promise<void>; - tooltipDirection?: PointerDirection; -} - -interface ConnectedState { - networkId: number; - userAddress: string; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, _ownProps: AllowanceStateToggleProps): ConnectedState => ({ - networkId: state.networkId, - userAddress: state.userAddress, -}); - -const mapDispatchTopProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const AllowanceStateToggle: React.ComponentClass<AllowanceStateToggleProps> = connect( - mapStateToProps, - mapDispatchTopProps, -)(AllowanceStateToggleComponent); diff --git a/packages/website/ts/containers/inputs/eth_amount_input.ts b/packages/website/ts/containers/inputs/eth_amount_input.ts deleted file mode 100644 index 45d3ddebd..000000000 --- a/packages/website/ts/containers/inputs/eth_amount_input.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { State } from 'ts/redux/reducer'; -import { ValidatedBigNumberCallback } from 'ts/types'; -import { constants } from 'ts/utils/constants'; - -import { EthAmountInput as EthAmountInputComponent } from 'ts/components/inputs/eth_amount_input'; - -interface EthAmountInputProps { - label?: string; - amount?: BigNumber; - hintText?: string; - onChange: ValidatedBigNumberCallback; - onErrorMsgChange?: (errorMsg: React.ReactNode) => void; - shouldShowIncompleteErrs: boolean; - shouldCheckBalance: boolean; - shouldShowErrs?: boolean; - shouldShowUnderline?: boolean; - style?: React.CSSProperties; - labelStyle?: React.CSSProperties; - inputHintStyle?: React.CSSProperties; -} - -interface ConnectedState { - balance: BigNumber; -} - -const mapStateToProps = (state: State, _ownProps: EthAmountInputProps): ConnectedState => ({ - balance: Web3Wrapper.toUnitAmount(state.userEtherBalanceInWei, constants.DECIMAL_PLACES_ETH), -}); - -export const EthAmountInput: React.ComponentClass<EthAmountInputProps> = connect(mapStateToProps)( - EthAmountInputComponent, -); diff --git a/packages/website/ts/containers/json_schemas_documentation.ts b/packages/website/ts/containers/json_schemas_documentation.ts deleted file mode 100644 index 1090265e7..000000000 --- a/packages/website/ts/containers/json_schemas_documentation.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/json_schemas/1/introduction'); -const IntroMarkdown3 = require('md/docs/json_schemas/3/introduction'); -const InstallationMarkdown1 = require('md/docs/json_schemas/1/installation'); -const InstallationMarkdown3 = require('md/docs/json_schemas/3/installation'); -const usageMarkdown1 = require('md/docs/json_schemas/1/usage'); -const usageMarkdown3 = require('md/docs/json_schemas/3/usage'); -const SchemasMarkdown1 = require('md/docs/json_schemas/1/schemas'); -const SchemasMarkdown2 = require('md/docs/json_schemas/2/schemas'); -const SchemasMarkdown3 = require('md/docs/json_schemas/3/schemas'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', - usage: 'usage', - schemas: 'schemas', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.JSONSchemas, - packageName: '@0x/json-schemas', - type: SupportedDocJson.TypeDoc, - displayName: 'JSON Schemas', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/json-schemas', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation, markdownSections.usage], - schemas: [markdownSections.schemas], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - [markdownSections.schemas]: SchemasMarkdown1, - [markdownSections.usage]: usageMarkdown1, - }, - '1.0.0': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - [markdownSections.schemas]: SchemasMarkdown2, - [markdownSections.usage]: usageMarkdown1, - }, - '2.0.0': { - [markdownSections.introduction]: IntroMarkdown3, - [markdownSections.installation]: InstallationMarkdown3, - [markdownSections.schemas]: SchemasMarkdown2, - [markdownSections.usage]: usageMarkdown3, - }, - '2.0.1': { - [markdownSections.introduction]: IntroMarkdown3, - [markdownSections.installation]: InstallationMarkdown3, - [markdownSections.schemas]: SchemasMarkdown3, - [markdownSections.usage]: usageMarkdown3, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/migrations_documentation.ts b/packages/website/ts/containers/migrations_documentation.ts deleted file mode 100644 index bae84dfea..000000000 --- a/packages/website/ts/containers/migrations_documentation.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { DocPackages, ScreenWidths } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/migrations/1/introduction'); -const InstallationMarkdown1 = require('md/docs/migrations/1/installation'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.Migrations, - packageName: '@0x/migrations', - type: SupportedDocJson.TypeDoc, - displayName: 'Migrations', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/migrations', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation], - }, - sectionNameToMarkdownByVersion: { - '2.0.4': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - }, - }, - markdownSections, -}; -const docsInfo = new DocsInfo(docsInfoConfig); - -interface ConnectedState { - docsVersion: string; - availableDocVersions: string[]; - docsInfo: DocsInfo; - translate: Translate; - screenWidth: ScreenWidths; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, _ownProps: DocPageProps): ConnectedState => ({ - docsVersion: state.docsVersion, - availableDocVersions: state.availableDocVersions, - translate: state.translate, - docsInfo, - screenWidth: state.screenWidth, -}); - -const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/not_found.ts b/packages/website/ts/containers/not_found.ts deleted file mode 100644 index 825c021ec..000000000 --- a/packages/website/ts/containers/not_found.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { NotFound as NotFoundComponent, NotFoundProps } from 'ts/pages/not_found'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { Translate } from 'ts/utils/translate'; - -interface ConnectedState { - translate: Translate; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, _ownProps: NotFoundProps): ConnectedState => ({ - translate: state.translate, -}); - -const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const NotFound: React.ComponentClass<NotFoundProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(NotFoundComponent); diff --git a/packages/website/ts/containers/order_utils_documentation.ts b/packages/website/ts/containers/order_utils_documentation.ts deleted file mode 100644 index 8d83357ca..000000000 --- a/packages/website/ts/containers/order_utils_documentation.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/order_utils/1/introduction'); -const InstallationMarkdown1 = require('md/docs/order_utils/1/installation'); -const IntroMarkdown2 = require('md/docs/order_utils/2/introduction'); -const InstallationMarkdown2 = require('md/docs/order_utils/2/installation'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.OrderUtils, - packageName: '@0x/order-utils', - type: SupportedDocJson.TypeDoc, - displayName: 'Order utils', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/order-utils', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - }, - '2.0.0': { - [markdownSections.introduction]: IntroMarkdown2, - [markdownSections.installation]: InstallationMarkdown2, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/order_watcher_documentation.ts b/packages/website/ts/containers/order_watcher_documentation.ts deleted file mode 100644 index 149ffdd2a..000000000 --- a/packages/website/ts/containers/order_watcher_documentation.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/order_watcher/1/introduction'); -const InstallationMarkdown1 = require('md/docs/order_watcher/1/installation'); -const IntroMarkdown2 = require('md/docs/order_watcher/2/introduction'); -const InstallationMarkdown2 = require('md/docs/order_watcher/2/installation'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.OrderWatcher, - packageName: '@0x/order-watcher', - type: SupportedDocJson.TypeDoc, - displayName: 'Order Watcher', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/order-watcher', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - }, - '2.2.0': { - [markdownSections.introduction]: IntroMarkdown2, - [markdownSections.installation]: InstallationMarkdown2, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts deleted file mode 100644 index db41a3ec3..000000000 --- a/packages/website/ts/containers/portal.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { Portal as PortalComponent, PortalProps as PortalComponentProps } from 'ts/components/portal/portal'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { BlockchainErrs, HashData, PortalOrder, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -interface ConnectedState { - blockchainErr: BlockchainErrs; - blockchainIsLoaded: boolean; - hashData: HashData; - injectedProviderName: string; - networkId: number; - nodeVersion: string; - orderFillAmount: BigNumber; - providerType: ProviderType; - tokenByAddress: TokenByAddress; - lastForceTokenStateRefetch: number; - userEtherBalanceInWei?: BigNumber; - screenWidth: ScreenWidths; - shouldBlockchainErrDialogBeOpen: boolean; - userAddress: string; - userSuppliedOrderCache: PortalOrder; - flashMessage?: string | React.ReactNode; - translate: Translate; - isPortalOnboardingShowing: boolean; - portalOnboardingStep: number; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, _ownProps: PortalComponentProps): ConnectedState => { - const receiveAssetToken = state.sideToAssetToken[Side.Receive]; - const depositAssetToken = state.sideToAssetToken[Side.Deposit]; - const receiveAddress = !_.isUndefined(receiveAssetToken.address) - ? receiveAssetToken.address - : constants.NULL_ADDRESS; - const depositAddress = !_.isUndefined(depositAssetToken.address) - ? depositAssetToken.address - : constants.NULL_ADDRESS; - const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0); - const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0); - const hashData = { - depositAmount, - depositTokenContractAddr: depositAddress, - feeRecipientAddress: constants.NULL_ADDRESS, - makerFee: constants.MAKER_FEE, - orderExpiryTimestamp: state.orderExpiryTimestamp, - orderMakerAddress: state.userAddress, - orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS, - receiveAmount, - receiveTokenContractAddr: receiveAddress, - takerFee: constants.TAKER_FEE, - orderSalt: state.orderSalt, - }; - return { - blockchainErr: state.blockchainErr, - blockchainIsLoaded: state.blockchainIsLoaded, - hashData, - injectedProviderName: state.injectedProviderName, - networkId: state.networkId, - nodeVersion: state.nodeVersion, - orderFillAmount: state.orderFillAmount, - providerType: state.providerType, - screenWidth: state.screenWidth, - shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen, - tokenByAddress: state.tokenByAddress, - lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, - userAddress: state.userAddress, - userEtherBalanceInWei: state.userEtherBalanceInWei, - userSuppliedOrderCache: state.userSuppliedOrderCache, - flashMessage: state.flashMessage, - translate: state.translate, - isPortalOnboardingShowing: state.isPortalOnboardingShowing, - portalOnboardingStep: state.portalOnboardingStep, - }; -}; - -const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const Portal: React.ComponentClass<PortalComponentProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(PortalComponent); diff --git a/packages/website/ts/containers/portal_onboarding_flow.ts b/packages/website/ts/containers/portal_onboarding_flow.ts deleted file mode 100644 index 66473733c..000000000 --- a/packages/website/ts/containers/portal_onboarding_flow.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { Blockchain } from 'ts/blockchain'; -import { ActionTypes, ProviderType, ScreenWidths, TokenByAddress, TokenStateByAddress } from 'ts/types'; - -import { PortalOnboardingFlow as PortalOnboardingFlowComponent } from 'ts/components/onboarding/portal_onboarding_flow'; -import { State } from 'ts/redux/reducer'; - -interface PortalOnboardingFlowProps { - trackedTokenStateByAddress: TokenStateByAddress; - blockchain: Blockchain; - refetchTokenStateAsync: (tokenAddress: string) => Promise<void>; -} - -interface ConnectedState { - networkId: number; - stepIndex: number; - isRunning: boolean; - userAddress: string; - hasBeenClosed: boolean; - providerType: ProviderType; - injectedProviderName: string; - blockchainIsLoaded: boolean; - userEtherBalanceInWei?: BigNumber; - tokenByAddress: TokenByAddress; - screenWidth: ScreenWidths; -} - -interface ConnectedDispatch { - updateIsRunning: (isRunning: boolean) => void; - updateOnboardingStep: (stepIndex: number) => void; -} - -const mapStateToProps = (state: State, _ownProps: PortalOnboardingFlowProps): ConnectedState => ({ - networkId: state.networkId, - stepIndex: state.portalOnboardingStep, - isRunning: state.isPortalOnboardingShowing, - userAddress: state.userAddress, - providerType: state.providerType, - injectedProviderName: state.injectedProviderName, - blockchainIsLoaded: state.blockchainIsLoaded, - userEtherBalanceInWei: state.userEtherBalanceInWei, - tokenByAddress: state.tokenByAddress, - hasBeenClosed: state.hasPortalOnboardingBeenClosed, - screenWidth: state.screenWidth, -}); - -const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - updateIsRunning: (isRunning: boolean): void => { - dispatch({ - type: ActionTypes.UpdatePortalOnboardingShowing, - data: isRunning, - }); - }, - updateOnboardingStep: (stepIndex: number): void => { - dispatch({ - type: ActionTypes.UpdatePortalOnboardingStep, - data: stepIndex, - }); - }, -}); - -export const PortalOnboardingFlow: React.ComponentClass<PortalOnboardingFlowProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(PortalOnboardingFlowComponent); diff --git a/packages/website/ts/containers/smart_contracts_documentation.ts b/packages/website/ts/containers/smart_contracts_documentation.ts deleted file mode 100644 index d94e285a7..000000000 --- a/packages/website/ts/containers/smart_contracts_documentation.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import { Networks } from '@0x/react-shared'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages, SmartContractDocSections as Sections } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/smart_contracts/1/introduction'); -const IntroMarkdown2 = require('md/docs/smart_contracts/2/introduction'); -/* tslint:enable:no-var-requires */ - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.SmartContracts, - packageName: 'contracts', - type: SupportedDocJson.SolDoc, - displayName: '0x Smart Contracts', - packageUrl: 'https://github.com/0xProject/contracts', - markdownMenu: { - introduction: [Sections.Introduction], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [Sections.Introduction]: IntroMarkdown1, - }, - '2.0.0': { - [Sections.Introduction]: IntroMarkdown2, - }, - }, - markdownSections: { - Introduction: Sections.Introduction, - }, - contractsByVersionByNetworkId: { - '1.0.0': { - [Networks.Mainnet]: { - Exchange_v1: '0x12459c951127e0c374ff9105dda097662a027093', - TokenTransferProxy_v1: '0x8da0d80f5007ef1e431dd2127178d224e32c2ef4', - TokenRegistry: '0x926a74c5c36adf004c87399e65f75628b0f98d2c', - }, - [Networks.Ropsten]: { - Exchange_v1: '0x479cc461fecd078f766ecc58533d6f69580cf3ac', - TokenTransferProxy_v1: '0x4e9aad8184de8833365fea970cd9149372fdf1e6', - TokenRegistry: '0x6b1a50f0bb5a7995444bd3877b22dc89c62843ed', - }, - [Networks.Kovan]: { - Exchange_v1: '0x90fe2af704b34e0224bf2299c838e04d4dcf1364', - TokenTransferProxy_v1: '0x087Eed4Bc1ee3DE49BeFbd66C662B434B15d49d4', - TokenRegistry: '0xf18e504561f4347bea557f3d4558f559dddbae7f', - }, - [Networks.Rinkeby]: { - Exchange_v1: '0x1d16ef40fac01cec8adac2ac49427b9384192c05', - TokenTransferProxy_v1: '0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d', - TokenRegistry: '0x4e9aad8184de8833365fea970cd9149372fdf1e6', - }, - }, - '2.0.0': { - [Networks.Mainnet]: { - AssetProxyOwner: '0x17992e4ffb22730138e4b62aaa6367fa9d3699a6', - ERC20Proxy: '0x2240dab907db71e64d3e0dba4800c83b5c502d4e', - ERC721Proxy: '0x208e41fb445f1bb1b6780d58356e81405f3e6127', - Exchange: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b', - Forwarder: '0x7afc2d5107af94c462a194d2c21b5bdd238709d6', - OrderValidator: '0x9463e518dea6810309563c81d5266c1b1d149138', - WETH9: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - ZRXToken: '0xe41d2489571d322189246dafa5ebde1f4699f498', - }, - [Networks.Ropsten]: { - AssetProxyOwner: '0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b', - ERC20Proxy: '0xb1408f4c245a23c31b98d2c626777d4c0d766caa', - ERC721Proxy: '0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4', - Exchange: '0x4530c0483a1633c7a1c97d2c53721caff2caaaaf', - Forwarder: '0x3983e204b12b3c02fb0638caf2cd406a62e0ead3', - OrderValidator: '0x90431a90516ab49af23a0530e04e8c7836e7122f', - WETH9: '0xc778417e063141139fce010982780140aa0cd5ab', - ZRXToken: '0xff67881f8d12f372d91baae9752eb3631ff0ed00', - }, - [Networks.Kovan]: { - AssetProxyOwner: '0x2c824d2882baa668e0d5202b1e7f2922278703f8', - ERC20Proxy: '0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e', - ERC721Proxy: '0x2a9127c745688a165106c11cd4d647d2220af821', - Exchange: '0x35dd2932454449b14cee11a94d3674a936d5d7b2', - Forwarder: '0xd85e2fa7e7e252b27b01bf0d65c946959d2f45b8', - OrderValidator: '0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d', - WETH9: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', - ZRXToken: '0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa', - }, - }, - }, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/sol_compiler_documentation.ts b/packages/website/ts/containers/sol_compiler_documentation.ts deleted file mode 100644 index 31117372b..000000000 --- a/packages/website/ts/containers/sol_compiler_documentation.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/sol-compiler/1/introduction'); -const InstallationMarkdown1 = require('md/docs/sol-compiler/1/installation'); -const InstallationMarkdown2 = require('md/docs/sol-compiler/2/installation'); -const UsageMarkdown1 = require('md/docs/sol-compiler/1/usage'); -const UsageMarkdown2 = require('md/docs/sol-compiler/2/usage'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', - usage: 'usage', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.SolCompiler, - packageName: '@0x/sol-compiler', - type: SupportedDocJson.TypeDoc, - displayName: 'Solidity Compiler', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/sol-compiler', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation, markdownSections.usage], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - [markdownSections.usage]: UsageMarkdown1, - }, - '1.1.8': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown2, - [markdownSections.usage]: UsageMarkdown2, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/sol_coverage_documentation.ts b/packages/website/ts/containers/sol_coverage_documentation.ts deleted file mode 100644 index a9073b720..000000000 --- a/packages/website/ts/containers/sol_coverage_documentation.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown = require('md/docs/sol_coverage/introduction'); -const InstallationMarkdown = require('md/docs/sol_coverage/installation'); -const UsageMarkdown = require('md/docs/sol_coverage/usage'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', - usage: 'usage', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.SolCoverage, - packageName: '@0x/sol-coverage', - type: SupportedDocJson.TypeDoc, - displayName: 'Sol-coverage', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/sol-coverage', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation, markdownSections.usage], - }, - sectionNameToMarkdownByVersion: { - '1.0.0': { - [markdownSections.introduction]: IntroMarkdown, - [markdownSections.installation]: InstallationMarkdown, - [markdownSections.usage]: UsageMarkdown, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/sol_profiler_documentation.ts b/packages/website/ts/containers/sol_profiler_documentation.ts deleted file mode 100644 index 2f3936cae..000000000 --- a/packages/website/ts/containers/sol_profiler_documentation.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown = require('md/docs/sol_profiler/introduction'); -const InstallationMarkdown = require('md/docs/sol_profiler/installation'); -const UsageMarkdown = require('md/docs/sol_profiler/usage'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', - usage: 'usage', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.SolProfiler, - packageName: '@0x/sol-profiler', - type: SupportedDocJson.TypeDoc, - displayName: 'Sol-profiler', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/sol-profiler', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation, markdownSections.usage], - }, - sectionNameToMarkdownByVersion: { - '1.0.0': { - [markdownSections.introduction]: IntroMarkdown, - [markdownSections.installation]: InstallationMarkdown, - [markdownSections.usage]: UsageMarkdown, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/sol_trace_documentation.ts b/packages/website/ts/containers/sol_trace_documentation.ts deleted file mode 100644 index 9c2552438..000000000 --- a/packages/website/ts/containers/sol_trace_documentation.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown = require('md/docs/sol_trace/introduction'); -const InstallationMarkdown = require('md/docs/sol_trace/installation'); -const UsageMarkdown = require('md/docs/sol_trace/usage'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', - usage: 'usage', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.SolTrace, - packageName: '@0x/sol-trace', - type: SupportedDocJson.TypeDoc, - displayName: 'Sol-trace', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/sol-trace', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation, markdownSections.usage], - }, - sectionNameToMarkdownByVersion: { - '1.0.0': { - [markdownSections.introduction]: IntroMarkdown, - [markdownSections.installation]: InstallationMarkdown, - [markdownSections.usage]: UsageMarkdown, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/subproviders_documentation.ts b/packages/website/ts/containers/subproviders_documentation.ts deleted file mode 100644 index 2ac0360ab..000000000 --- a/packages/website/ts/containers/subproviders_documentation.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/subproviders/1/introduction'); -const InstallationMarkdown1 = require('md/docs/subproviders/1/installation'); -const InstallationMarkdown2 = require('md/docs/subproviders/2/installation'); -const LedgerNodeHidMarkdown1 = require('md/docs/subproviders/1/ledger_node_hid'); -/* tslint:enable:no-var-requires */ - -const docSections = { - introduction: 'introduction', - installation: 'installation', - ledgerNodeHid: 'ledger-node-hid-issue', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.Subproviders, - packageName: '@0x/subproviders', - type: SupportedDocJson.TypeDoc, - displayName: 'Subproviders', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/subproviders', - markdownMenu: { - 'getting-started': [docSections.introduction, docSections.installation, docSections.ledgerNodeHid], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [docSections.introduction]: IntroMarkdown1, - [docSections.installation]: InstallationMarkdown1, - [docSections.ledgerNodeHid]: LedgerNodeHidMarkdown1, - }, - '2.1.0': { - [docSections.introduction]: IntroMarkdown1, - [docSections.installation]: InstallationMarkdown2, - [docSections.ledgerNodeHid]: LedgerNodeHidMarkdown1, - }, - }, - markdownSections: docSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/web3_wrapper_documentation.ts b/packages/website/ts/containers/web3_wrapper_documentation.ts deleted file mode 100644 index 73fea90ed..000000000 --- a/packages/website/ts/containers/web3_wrapper_documentation.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/web3_wrapper/1/introduction'); -const InstallationMarkdown1 = require('md/docs/web3_wrapper/1/installation'); -const InstallationMarkdown2 = require('md/docs/web3_wrapper/2/installation'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.Web3Wrapper, - packageName: '@0x/web3-wrapper', - type: SupportedDocJson.TypeDoc, - displayName: 'Web3Wrapper', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/web3-wrapper', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - }, - '3.1.0': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown2, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/containers/wiki.ts b/packages/website/ts/containers/wiki.ts deleted file mode 100644 index f4f2f6ec6..000000000 --- a/packages/website/ts/containers/wiki.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { Wiki as WikiComponent, WikiProps } from 'ts/pages/wiki/wiki'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { ScreenWidths } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; - -interface ConnectedState { - translate: Translate; - screenWidth: ScreenWidths; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, _ownProps: WikiProps): ConnectedState => ({ - translate: state.translate, - screenWidth: state.screenWidth, -}); - -const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const Wiki: React.ComponentClass<WikiProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(WikiComponent); diff --git a/packages/website/ts/containers/zero_ex_js_documentation.ts b/packages/website/ts/containers/zero_ex_js_documentation.ts deleted file mode 100644 index 0e4765656..000000000 --- a/packages/website/ts/containers/zero_ex_js_documentation.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { DocsInfoConfig, SupportedDocJson } from '@0x/react-docs'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdownV0 = require('md/docs/0xjs/0.0.1/introduction'); -const InstallationMarkdownV0 = require('md/docs/0xjs/0.0.1/installation'); -const AsyncMarkdownV0 = require('md/docs/0xjs/0.0.1/async'); -const ErrorsMarkdownV0 = require('md/docs/0xjs/0.0.1/errors'); -const versioningMarkdownV0 = require('md/docs/0xjs/0.0.1/versioning'); - -const IntroMarkdown1 = require('md/docs/0xjs/1.0.1/introduction'); -const InstallationMarkdown1 = require('md/docs/0xjs/1.0.1/installation'); -const AsyncMarkdownV1 = require('md/docs/0xjs/1.0.1/async'); -const ErrorsMarkdownV1 = ErrorsMarkdownV0; -const versioningMarkdownV1 = require('md/docs/0xjs/1.0.1/versioning'); - -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', - testrpc: 'testrpc', - async: 'async', - errors: 'errors', - versioning: 'versioning', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.ZeroExJs, - packageName: '0x.js', - type: SupportedDocJson.TypeDoc, - displayName: '0x.js', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/0x.js', - markdownMenu: { - 'getting-started': [ - markdownSections.introduction, - markdownSections.installation, - markdownSections.async, - markdownSections.errors, - markdownSections.versioning, - ], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdownV0, - [markdownSections.installation]: InstallationMarkdownV0, - [markdownSections.versioning]: versioningMarkdownV0, - [markdownSections.async]: AsyncMarkdownV0, - [markdownSections.errors]: ErrorsMarkdownV0, - }, - '1.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - [markdownSections.versioning]: versioningMarkdownV1, - [markdownSections.async]: AsyncMarkdownV1, - [markdownSections.errors]: ErrorsMarkdownV1, - }, - '2.0.0': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - [markdownSections.versioning]: versioningMarkdownV1, - [markdownSections.async]: AsyncMarkdownV1, - [markdownSections.errors]: ErrorsMarkdownV1, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass<DocPageProps> = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/globals.d.ts b/packages/website/ts/globals.d.ts deleted file mode 100644 index 05f3c7f88..000000000 --- a/packages/website/ts/globals.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -declare module '@reach/dialog'; -declare module 'truffle-contract'; -declare module 'whatwg-fetch'; -declare module 'thenby'; -declare module 'react-document-title'; -declare module 'react-ga'; -declare module 'reach__dialog'; -declare module 'react-flickity-component'; -declare module 'react-anchor-link-smooth-scroll'; -declare module 'react-responsive'; -declare module 'react-scrollable-anchor'; -declare module 'react-headroom'; - -declare module '*.json' { - const json: any; - /* tslint:disable */ - export default json; - /* tslint:enable */ -} - -declare module '*.svg' { - import { PureComponent, SVGProps } from 'react'; - export default class extends PureComponent<SVGProps<SVGSVGElement>> {} -} - -declare module 'web3-provider-engine/subproviders/filters'; - -// This will be defined by default in TS 2.4 -// Source: https://github.com/Microsoft/TypeScript/issues/12364 -interface System { - import<T>(module: string): Promise<T>; -} -declare var System: System; diff --git a/packages/website/ts/icons/illustrations/0x.svg b/packages/website/ts/icons/illustrations/0x.svg deleted file mode 100755 index b0810f751..000000000 --- a/packages/website/ts/icons/illustrations/0x.svg +++ /dev/null @@ -1,14 +0,0 @@ -<svg width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg"> -<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="404" height="404"> -<circle cx="202" cy="202" r="200" fill="#00AE99" stroke="#00AE99" stroke-width="3"/> -</mask> -<g mask="url(#mask0)"> -<circle cx="202" cy="202" r="200" stroke="#00AE99" stroke-width="3"/> -<circle cx="201.667" cy="68.6667" r="66.6667" stroke="#00AE99" stroke-width="3"/> -<circle cx="68.6667" cy="202.667" r="66.6667" stroke="#00AE99" stroke-width="3"/> -<path d="M168.17 260.29L167.271 259.089L165.46 260.444L167.413 261.585L168.17 260.29ZM197.32 269.2L197.219 270.696L197.226 270.697L197.32 269.2ZM237.414 258.856L238.22 260.12L238.225 260.117L237.414 258.856ZM252.653 245.439L253.801 246.405L254.55 245.515L253.874 244.568L252.653 245.439ZM241.096 229.872L242.285 228.958L242.281 228.952L242.276 228.946L241.096 229.872ZM237.72 225.571L238.901 224.645L237.582 222.965L236.449 224.775L237.72 225.571ZM219.719 241.445L218.672 242.519L219.418 243.246L220.36 242.801L219.719 241.445ZM208.264 230.282L209.311 229.207L208.392 228.312L207.365 229.081L208.264 230.282ZM143.827 169.549L145.02 168.64L143.647 166.838L142.524 168.806L143.827 169.549ZM135.133 198.43L133.637 198.329L133.636 198.337L135.133 198.43ZM145.464 238.577L144.201 239.388L145.464 238.577ZM158.862 253.837L157.895 254.984L158.786 255.736L159.735 255.057L158.862 253.837ZM174.409 242.264L175.324 243.453L175.33 243.448L175.336 243.443L174.409 242.264ZM178.705 238.885L179.632 240.064L181.287 238.761L179.516 237.623L178.705 238.885ZM162.851 220.757L161.78 219.707L161.049 220.452L161.495 221.397L162.851 220.757ZM174.102 209.286L175.173 210.337L176.082 209.41L175.295 208.377L174.102 209.286ZM235.163 145.072L236.036 146.292L237.92 144.945L235.92 143.777L235.163 145.072ZM206.014 136.162L205.91 137.658L205.913 137.658L206.014 136.162ZM165.817 146.506L166.629 147.767L166.632 147.765L165.817 146.506ZM150.578 159.922L149.43 158.956L148.681 159.846L149.357 160.793L150.578 159.922ZM162.135 175.489L160.946 176.403L160.951 176.409L160.955 176.415L162.135 175.489ZM165.511 179.791L164.331 180.717L165.634 182.378L166.773 180.6L165.511 179.791ZM183.614 163.916L184.655 162.836L183.913 162.122L182.98 162.557L183.614 163.916ZM194.354 174.26L193.313 175.341L194.212 176.206L195.226 175.48L194.354 174.26ZM259.608 235.505L258.411 236.409L259.789 238.233L260.914 236.243L259.608 235.505ZM268.2 206.931L269.696 207.033L269.697 207.024L268.2 206.931ZM257.87 166.784L259.135 165.979L259.132 165.974L257.87 166.784ZM244.471 151.524L245.439 150.378L244.547 149.625L243.598 150.304L244.471 151.524ZM228.924 163.097L228.009 161.909L228.003 161.913L227.997 161.918L228.924 163.097ZM224.629 166.477L223.701 165.298L222.034 166.609L223.826 167.744L224.629 166.477ZM240.584 184.604L239.228 185.244L239.235 185.259L239.242 185.274L240.584 184.604ZM240.687 184.809L241.767 185.849L242.502 185.086L242.029 184.139L240.687 184.809ZM229.845 196.075L228.764 195.035L227.877 195.957L228.648 196.979L229.845 196.075ZM167.413 261.585C176.201 266.718 186.346 269.964 197.219 270.696L197.421 267.703C187.019 267.002 177.321 263.898 168.926 258.994L167.413 261.585ZM197.226 270.697C212.283 271.639 226.405 267.659 238.22 260.12L236.607 257.591C225.307 264.8 211.813 268.604 197.413 267.703L197.226 270.697ZM238.225 260.117C244.08 256.348 249.307 251.742 253.801 246.405L251.506 244.473C247.204 249.583 242.203 253.989 236.602 257.594L238.225 260.117ZM253.874 244.568C250.283 239.533 246.385 234.295 242.285 228.958L239.906 230.786C243.989 236.1 247.864 241.309 251.432 246.31L253.874 244.568ZM242.276 228.946C241.713 228.229 241.151 227.512 240.588 226.795C240.026 226.078 239.463 225.362 238.901 224.645L236.54 226.497C237.103 227.213 237.665 227.93 238.228 228.647C238.791 229.364 239.353 230.081 239.916 230.798L242.276 228.946ZM236.449 224.775C232.311 231.384 226.193 236.725 219.078 240.089L220.36 242.801C227.974 239.201 234.538 233.481 238.992 226.367L236.449 224.775ZM220.766 240.371L209.311 229.207L207.217 231.356L218.672 242.519L220.766 240.371ZM207.365 229.081L167.271 259.089L169.069 261.49L209.163 231.483L207.365 229.081ZM142.524 168.806C137.505 177.601 134.368 187.549 133.637 198.329L136.63 198.532C137.33 188.214 140.33 178.703 145.13 170.293L142.524 168.806ZM133.636 198.337C132.696 213.409 136.668 227.654 144.201 239.388L146.726 237.767C139.531 226.56 135.73 212.947 136.63 198.524L133.636 198.337ZM144.201 239.388C147.965 245.25 152.565 250.484 157.895 254.984L159.83 252.691C154.727 248.383 150.327 243.376 146.726 237.767L144.201 239.388ZM159.735 255.057C164.764 251.461 169.994 247.558 175.324 243.453L173.494 241.076C168.187 245.164 162.985 249.045 157.99 252.617L159.735 255.057ZM175.336 243.443C176.768 242.317 178.2 241.19 179.632 240.064L177.777 237.706C176.345 238.832 174.913 239.959 173.481 241.086L175.336 243.443ZM179.516 237.623C172.904 233.374 167.568 227.241 164.208 220.117L161.495 221.397C165.09 229.021 170.8 235.588 177.894 240.147L179.516 237.623ZM163.922 221.807L175.173 210.337L173.031 208.236L161.78 219.707L163.922 221.807ZM175.295 208.377L145.02 168.64L142.634 170.458L172.909 210.196L175.295 208.377ZM235.92 143.777C227.132 138.643 216.987 135.398 206.114 134.665L205.913 137.658C216.315 138.359 226.012 141.463 234.407 146.367L235.92 143.777ZM206.118 134.665C191.055 133.618 176.824 137.599 165.003 145.246L166.632 147.765C177.926 140.459 191.515 136.657 205.91 137.658L206.118 134.665ZM165.006 145.244C159.151 149.013 153.924 153.619 149.43 158.956L151.725 160.888C156.027 155.779 161.028 151.372 166.629 147.767L165.006 145.244ZM149.357 160.793C152.948 165.828 156.846 171.066 160.946 176.403L163.325 174.575C159.242 169.261 155.367 164.052 151.799 159.051L149.357 160.793ZM160.955 176.415C161.518 177.132 162.08 177.849 162.643 178.566C163.205 179.283 163.768 180 164.331 180.717L166.691 178.865C166.128 178.148 165.566 177.431 165.003 176.714C164.441 175.997 163.878 175.28 163.315 174.563L160.955 176.415ZM166.773 180.6C171.021 173.973 177.044 168.635 184.248 165.276L182.98 162.557C175.251 166.161 168.796 171.885 164.248 178.981L166.773 180.6ZM182.574 164.997L193.313 175.341L195.394 173.18L184.655 162.836L182.574 164.997ZM195.226 175.48L236.036 146.292L234.291 143.852L193.481 173.04L195.226 175.48ZM260.914 236.243C265.827 227.556 268.964 217.713 269.696 207.033L266.703 206.828C266.003 217.042 263.004 226.453 258.303 234.767L260.914 236.243ZM269.697 207.024C270.638 191.949 266.663 177.81 259.135 165.979L256.604 167.589C263.804 178.904 267.603 192.417 266.703 206.837L269.697 207.024ZM259.132 165.974C255.368 160.111 250.769 154.878 245.439 150.378L243.503 152.67C248.606 156.978 253.007 161.986 256.607 167.594L259.132 165.974ZM243.598 150.304C238.57 153.901 233.339 157.803 228.009 161.909L229.84 164.285C235.147 160.197 240.349 156.316 245.344 152.744L243.598 150.304ZM227.997 161.918C227.281 162.481 226.565 163.045 225.849 163.608C225.133 164.171 224.417 164.734 223.701 165.298L225.556 167.656C226.272 167.092 226.988 166.529 227.704 165.966C228.42 165.402 229.136 164.839 229.852 164.276L227.997 161.918ZM223.826 167.744C230.535 171.992 235.869 178.121 239.228 185.244L241.941 183.964C238.345 176.339 232.632 169.769 225.431 165.209L223.826 167.744ZM239.242 185.274L239.345 185.479L242.029 184.139L241.926 183.934L239.242 185.274ZM239.606 183.769L228.764 195.035L230.926 197.115L241.767 185.849L239.606 183.769ZM228.648 196.979L258.411 236.409L260.806 234.601L231.042 195.171L228.648 196.979Z" fill="#00AE99"/> -<path d="M269 135V268.333H442V135H269Z" stroke="#00AE99" stroke-width="3"/> -<path d="M339.64 269.64L270 339.281L343.913 413.194L413.554 343.554L339.64 269.64Z" stroke="#00AE99" stroke-width="3"/> -<path d="M202.5 269C202.5 269 269 269 269 335.5C269 402 202.5 402 202.5 402H-6.5C-6.5 402 -77 402 -77 335.5C-77 269 -6.5 269 -6.5 269H202.5Z" stroke="#00AE99" stroke-width="3"/> -</g> -</svg> diff --git a/packages/website/ts/icons/illustrations/buildBusiness.svg b/packages/website/ts/icons/illustrations/buildBusiness.svg deleted file mode 100755 index 48e5b3b1c..000000000 --- a/packages/website/ts/icons/illustrations/buildBusiness.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M2 45C2 68.7579 21.2421 88 45 88C68.7579 88 88 68.7579 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M78.8765 52.5843V69.7753H12.1349V52.5843M78.8765 52.5843V21.236H12.1349V52.5843M78.8765 52.5843H51.5731H39.4383H12.1349" stroke="#00AE99" stroke-width="3"/> -<path d="M56.6293 11.1236H34.3821V21.236H56.6293V11.1236Z" stroke="#00AE99" stroke-width="3"/> -<rect width="22.2472" height="6.06742" transform="matrix(1 0 0 -1 34.3821 58.6517)" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/checkmark.svg b/packages/website/ts/icons/illustrations/checkmark.svg deleted file mode 100644 index e17a7ab8b..000000000 --- a/packages/website/ts/icons/illustrations/checkmark.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="124" height="124" viewBox="0 0 124 124" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M61.878.5h.002c.327 0 .64.01.924.02l.01.001a23.966 23.966 0 0 0 .87.02C96.885 1.405 123.5 28.597 123.5 62c0 33.979-27.521 61.5-61.5 61.5S.5 95.979.5 62C.5 28.063 27.979.541 61.878.5zm.002 3C29.64 3.54 3.5 29.717 3.5 62c0 32.322 26.178 58.5 58.5 58.5s58.5-26.178 58.5-58.5c0-31.768-25.308-57.628-56.875-58.46-.32 0-.625-.01-.904-.02h-.01c-.294-.011-.56-.02-.83-.02z" fill="#00AE99"/><path fill-rule="evenodd" clip-rule="evenodd" d="M47.502 98.561l55.419-55.419L88.779 29 47.495 70.284 34.142 56.932 20 71.074l16.573 16.573.008-.007L47.502 98.56zM36.573 83.405l.008-.008 10.921 10.921L98.68 43.142l-9.9-9.9-41.284 41.285-13.353-13.352-9.9 9.9 12.331 12.33z" fill="#00AE99"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/icons/illustrations/code-repo.svg b/packages/website/ts/icons/illustrations/code-repo.svg deleted file mode 100644 index 43e412198..000000000 --- a/packages/website/ts/icons/illustrations/code-repo.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg width="82" height="82" viewBox="0 0 82 82" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M40.9185 1.43051e-06L40.9197 0C41.1377 7.15256e-07 41.3462 0.00719154 41.5359 0.0137337L41.5428 0.0139726C41.7392 0.0207458 41.9163 0.0267566 42.097 0.0267566C42.1057 0.0267566 42.1143 0.0268694 42.123 0.027095C64.2563 0.603056 82 18.7315 82 41C82 63.6526 63.6526 82 41 82C18.3474 82 0 63.6526 0 41C0 18.3752 18.3193 0.0274277 40.9185 1.43051e-06ZM40.9203 2C19.4262 2.02641 2 19.4778 2 41C2 62.548 19.452 80 41 80C62.548 80 80 62.548 80 41C80 19.8212 63.1283 2.58105 42.0835 2.02675C41.8704 2.02646 41.6666 2.01943 41.4808 2.01302L41.4739 2.01278C41.2777 2.00602 41.1008 2.00001 40.9203 2Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M10.7026 14.378C10.7026 13.8257 11.1504 13.378 11.7026 13.378H33.7762C34.3284 13.378 34.7762 13.8257 34.7762 14.378V36.4516C34.7762 37.0039 34.3284 37.4516 33.7762 37.4516H11.7026C11.1504 37.4516 10.7026 37.0039 10.7026 36.4516V14.378ZM12.7026 15.378V35.4516H32.7762V15.378H12.7026Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M38.6621 20.6785L33.0687 15.0851L34.4829 13.6709L40.3692 19.5572C40.5567 19.7447 40.6621 19.9991 40.6621 20.2643V42.3379C40.6621 42.8902 40.2143 43.3379 39.6621 43.3379H17.5885C17.3233 43.3379 17.0689 43.2325 16.8814 43.045L10.9951 37.1587L12.4093 35.7445L18.0027 41.3379H38.6621V20.6785Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M38.6621 42.338C38.6621 41.7857 39.1098 41.338 39.6621 41.338H61.7357C62.288 41.338 62.7357 41.7857 62.7357 42.338V64.4116C62.7357 64.9638 62.288 65.4116 61.7357 65.4116H39.6621C39.1098 65.4116 38.6621 64.9638 38.6621 64.4116V42.338ZM40.6621 43.338V63.4116H60.7357V43.338H40.6621Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M66.622 48.6385L61.0286 43.0451L62.4429 41.6309L68.3291 47.5172C68.5167 47.7047 68.622 47.9591 68.622 48.2243V70.2979C68.622 70.8501 68.1743 71.2979 67.622 71.2979H45.5485C45.2833 71.2979 45.0289 71.1925 44.8414 71.005L38.9551 65.1187L40.3693 63.7045L45.9627 69.2979H66.622V48.6385Z" fill="#00AE99"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/coin.svg b/packages/website/ts/icons/illustrations/coin.svg deleted file mode 100644 index a1fb123a4..000000000 --- a/packages/website/ts/icons/illustrations/coin.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="88" height="88" viewBox="0 0 88 88" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M44 87c23.748 0 43-19.252 43-43S67.748 1 44 1 1 20.252 1 44s19.252 43 43 43z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M43.999 78.4c18.998 0 34.4-15.401 34.4-34.4 0-18.998-15.401-34.4-34.4-34.4S9.599 25.002 9.599 44C9.599 63 25 78.4 43.999 78.4z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M35.1 57.76v1h20.529v-7.395h-6.098V26.738H42.36l-.254.173-6.568 4.456-.438.298v8.906l1.561-1.06 5.006-3.397v15.251H35.1v6.395z" stroke="#00AE99" stroke-width="2"/><path d="M9.597 43.766c7.115-1.173 12.588-7.271 12.588-14.777 0-3.362-1.095-6.41-2.971-8.913-5.864 6.177-9.538 14.542-9.617 23.69zM9.597 44.234c.079 9.226 3.753 17.513 9.617 23.69a14.719 14.719 0 0 0 2.97-8.913c0-7.506-5.472-13.682-12.587-14.777zM78.399 43.766c-7.115-1.173-12.587-7.271-12.587-14.777 0-3.362 1.094-6.41 2.97-8.913 5.864 6.177 9.539 14.542 9.617 23.69zM78.399 44.235c-.079 9.225-3.753 17.512-9.617 23.689a14.718 14.718 0 0 1-2.97-8.913c0-7.506 5.472-13.682 12.587-14.776z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/></svg> diff --git a/packages/website/ts/icons/illustrations/consistently-ship.svg b/packages/website/ts/icons/illustrations/consistently-ship.svg deleted file mode 100644 index 733655a3f..000000000 --- a/packages/website/ts/icons/illustrations/consistently-ship.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="104" height="104" viewBox="0 0 104 104" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M37.5485 62.3767L10.6742 80.0615M16.1162 86.694L39.2493 63.9073" stroke="#00AE99" stroke-width="2.5"/> -<path d="M43.1605 67.4788L29.2115 96.3881M21.8987 91.9664L41.2898 65.7782" stroke="#00AE99" stroke-width="2.5"/> -<path d="M64.6767 66.0071L63.4346 66.1475L63.4346 66.1475L64.6767 66.0071ZM65.0025 50.4035L66.2054 50.7435L65.0025 50.4035ZM71.1301 36.7515L70.153 35.9719L70.1082 36.0281L70.0701 36.0891L71.1301 36.7515ZM61.2375 73.5299L60.4186 74.4743L61.3787 75.3068L62.1953 74.3331L61.2375 73.5299ZM47.4561 66.4802L48.3306 67.3734L48.3678 67.337L48.4018 67.2977L47.4561 66.4802ZM45.1781 66.5118L45.9955 65.5661L45.9955 65.5661L45.1781 66.5118ZM44.504 67.2916L45.2499 68.2947L45.36 68.2128L45.4497 68.109L44.504 67.2916ZM43.2195 67.2024L44.037 66.2568L44.037 66.2568L43.2195 67.2024ZM51.486 57.3064L50.6457 58.2318L50.657 58.2421L50.6685 58.2521L51.486 57.3064ZM62.7637 71.4218L63.819 72.0917L63.819 72.0917L62.7637 71.4218ZM76.5283 23.4963L77.6859 23.0248L77.5727 22.7469L77.3457 22.5507L76.5283 23.4963ZM35.9701 41.1929L36.0109 42.4422L36.0109 42.4422L35.9701 41.1929ZM51.3624 38.6129L50.8519 37.4718L51.3624 38.6129ZM63.9842 30.5744L64.793 31.5275L64.8478 31.481L64.8969 31.4285L63.9842 30.5744ZM29.0241 45.6843L28.0908 44.8528L27.2455 45.8017L28.2082 46.6313L29.0241 45.6843ZM37.9936 58.3007L37.0479 57.4833L37.0139 57.5226L36.9833 57.5647L37.9936 58.3007ZM38.2919 60.5593L39.1094 59.6137L39.1094 59.6137L38.2919 60.5593ZM37.6179 61.3391L36.6722 60.5217L36.5825 60.6255L36.5174 60.7463L37.6179 61.3391ZM37.8919 62.5972L38.7094 61.6516L38.7094 61.6515L37.8919 62.5972ZM46.4878 52.9859L45.6704 53.9316L45.6819 53.9416L45.6937 53.9513L46.4878 52.9859ZM30.8892 43.8692L30.0736 42.9219L30.0736 42.9219L30.8892 43.8692ZM76.3188 23.3153L77.1362 22.3696L76.9092 22.1734L76.6179 22.1016L76.3188 23.3153ZM70.1348 36.0655L51.3508 57.796L53.2421 59.4309L72.0261 37.7004L70.1348 36.0655ZM65.9188 65.8667C65.5634 62.7233 64.3047 57.4681 66.2054 50.7435L63.7996 50.0635C61.7311 57.3817 63.1075 63.2547 63.4346 66.1475L65.9188 65.8667ZM66.2054 50.7435C67.7494 45.2809 70.8444 39.5677 72.1902 37.4138L70.0701 36.0891C68.6538 38.3557 65.431 44.2919 63.7996 50.0635L66.2054 50.7435ZM72.1073 37.531C72.8165 36.642 73.9266 35.0937 74.9321 33.5888C75.9127 32.1211 76.8909 30.5525 77.2543 29.671L74.943 28.7181C74.6915 29.3283 73.864 30.6874 72.8534 32.1999C71.8677 33.6752 70.801 35.1596 70.153 35.9719L72.1073 37.531ZM62.0564 72.5855L50.6963 62.7347L49.0585 64.6235L60.4186 74.4743L62.0564 72.5855ZM48.9317 62.8617L46.5104 65.6628L48.4018 67.2977L50.823 64.4966L48.9317 62.8617ZM46.5816 65.5871C46.6163 65.5531 46.6022 65.5735 46.5354 65.6101C46.4766 65.6423 46.4098 65.6684 46.3459 65.6814C46.2855 65.6937 46.2383 65.6924 46.1986 65.6831C46.1638 65.6751 46.0953 65.6523 45.9955 65.5661L44.3607 67.4575C45.1854 68.1704 46.1014 68.2823 46.8439 68.1313C47.5166 67.9946 48.0515 67.6467 48.3306 67.3734L46.5816 65.5871ZM44.2324 65.6944L43.5584 66.4741L45.4497 68.109L46.1238 67.3293L44.2324 65.6944ZM43.7582 66.2885C43.804 66.2544 43.8326 66.2427 43.8431 66.2387C43.857 66.2334 43.8754 66.2284 43.9003 66.2268C43.9278 66.2251 43.9618 66.228 43.9962 66.2392C44.0323 66.251 44.0456 66.2643 44.037 66.2568L42.4021 68.1481C43.5138 69.1091 44.7467 68.6688 45.2499 68.2947L43.7582 66.2885ZM50.6685 58.2521C51.1247 58.6464 51.5236 59.8632 50.612 60.9178L52.5033 62.5527C54.3763 60.3859 53.7352 57.5984 52.3034 56.3607L50.6685 58.2521ZM50.612 60.9178L48.9317 62.8617L50.823 64.4966L52.5033 62.5527L50.612 60.9178ZM62.1953 74.3331C62.6486 73.7926 63.2417 73.0013 63.819 72.0917L61.7083 70.7519C61.1892 71.5698 60.6611 72.2719 60.2798 72.7266L62.1953 74.3331ZM63.819 72.0917C64.381 71.2063 64.9483 70.1773 65.3541 69.1342C65.7512 68.1137 66.0422 66.9586 65.9188 65.8667L63.4346 66.1475C63.4916 66.6522 63.3613 67.3615 63.0243 68.2277C62.6961 69.0712 62.2166 69.9513 61.7083 70.7519L63.819 72.0917ZM50.6948 62.7335L45.811 58.5118L44.1761 60.4032L49.0599 64.6248L50.6948 62.7335ZM48.0426 55.9286C49.1315 56.8715 50.1183 57.753 50.6457 58.2318L52.3263 56.381C51.7849 55.8894 50.7834 54.9948 49.679 54.0386L48.0426 55.9286ZM40.7648 64.3497L44.3607 67.4575L45.9955 65.5661L42.3996 62.4582L40.7648 64.3497ZM39.6096 65.7343L42.4021 68.1481L44.037 66.2568L41.2445 63.8429L39.6096 65.7343ZM77.2543 29.671C77.6017 28.8283 77.9174 27.7261 78.0507 26.5812C78.1821 25.4521 78.1499 24.1638 77.6859 23.0248L75.3706 23.9679C75.6133 24.5637 75.6738 25.3787 75.5675 26.2921C75.463 27.1897 75.2106 28.0692 74.943 28.7181L77.2543 29.671ZM62.9156 29.8252L44.1315 51.5557L46.0229 53.1906L64.8069 31.4601L62.9156 29.8252ZM36.0109 42.4422C38.9206 42.3473 44.9309 42.8595 51.8728 39.7539L50.8519 37.4718C44.4731 40.3255 39.0911 39.8404 35.9294 39.9436L36.0109 42.4422ZM51.8728 39.7539C57.3477 37.3047 62.7552 33.2568 64.793 31.5275L63.1754 29.6213C61.2389 31.2646 56.0337 35.1537 50.8519 37.4718L51.8728 39.7539ZM64.8969 31.4285C65.6069 30.6698 66.9213 29.3996 68.2385 28.2108C69.5889 26.992 70.814 25.9765 71.3813 25.6394L70.1041 23.4903C69.2845 23.9774 67.8738 25.1723 66.5635 26.3549C65.2199 27.5676 63.8485 28.89 63.0715 29.7203L64.8969 31.4285ZM28.2082 46.6313L39.5989 56.4466L41.2308 54.5527L29.8401 44.7374L28.2082 46.6313ZM39.4692 54.6822L37.0479 57.4833L38.9392 59.1182L41.3605 56.3171L39.4692 54.6822ZM36.9833 57.5647C36.7532 57.8804 36.4864 58.46 36.4484 59.1453C36.4065 59.9019 36.6497 60.7921 37.4745 61.505L39.1094 59.6137C39.0096 59.5275 38.9772 59.4629 38.9642 59.4297C38.9494 59.3918 38.9412 59.3452 38.9446 59.2836C38.9482 59.2185 38.9644 59.1487 38.9878 59.0859C39.0143 59.0144 39.0324 58.9976 39.0039 59.0368L36.9833 57.5647ZM37.3462 59.7419L36.6722 60.5217L38.5635 62.1566L39.2376 61.3768L37.3462 59.7419ZM36.5174 60.7463C36.22 61.2983 35.9627 62.5819 37.0745 63.5429L38.7094 61.6515C38.7007 61.6441 38.7158 61.6554 38.7326 61.6893C38.7487 61.7218 38.7565 61.755 38.7588 61.7825C38.7609 61.8074 38.7585 61.8263 38.7553 61.8408C38.7529 61.8517 38.7454 61.8817 38.7183 61.9319L36.5174 60.7463ZM47.3052 52.0403C45.8734 50.8026 43.0225 50.5715 41.1495 52.7383L43.0408 54.3732C43.9524 53.3186 45.2142 53.5373 45.6704 53.9316L47.3052 52.0403ZM41.1495 52.7383L39.4692 54.6822L41.3605 56.3171L43.0408 54.3732L41.1495 52.7383ZM29.9575 46.5158C30.3523 46.0726 30.9705 45.4485 31.7047 44.8165L30.0736 42.9219C29.2572 43.6247 28.56 44.3261 28.0908 44.8528L29.9575 46.5158ZM31.7047 44.8165C32.4234 44.1978 33.2248 43.596 34.012 43.1492C34.8203 42.6904 35.5033 42.4588 36.0109 42.4422L35.9294 39.9436C34.8311 39.9794 33.7302 40.4345 32.7779 40.975C31.8045 41.5275 30.8684 42.2377 30.0736 42.9219L31.7047 44.8165ZM39.5974 56.4453L44.4813 60.667L46.1161 58.7756L41.2323 54.554L39.5974 56.4453ZM49.9826 54.3011C48.8767 53.3467 47.8466 52.4851 47.2819 52.0206L45.6937 53.9513C46.2438 54.4038 47.2588 55.2527 48.3493 56.1937L49.9826 54.3011ZM42.7049 62.7221L39.1094 59.6137L37.4744 61.5049L41.0699 64.6133L42.7049 62.7221ZM41.5018 64.0654L38.7094 61.6516L37.0745 63.5429L39.8669 65.9567L41.5018 64.0654ZM71.3813 25.6394C71.9847 25.2807 72.8184 24.9037 73.6914 24.6705C74.5799 24.4331 75.395 24.375 76.0197 24.529L76.6179 22.1016C75.4237 21.8073 74.1443 21.9618 73.0462 22.2552C71.9326 22.5527 70.8876 23.0246 70.1041 23.4903L71.3813 25.6394ZM77.3457 22.5507L77.1362 22.3696L75.5013 24.2609L75.7108 24.442L77.3457 22.5507Z" fill="#00AE99"/> -<path d="M52 102C79.6142 102 102 79.6142 102 52C102 24.3858 79.6142 2 52 2C24.3858 2 2 24.3858 2 52C2 79.6142 24.3858 102 52 102Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/customize.svg b/packages/website/ts/icons/illustrations/customize.svg deleted file mode 100644 index 1f018ee7a..000000000 --- a/packages/website/ts/icons/illustrations/customize.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="152" height="152" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M76 151c41.421 0 75-33.579 75-75S117.421 1 76 1 1 34.579 1 76s33.579 75 75 75z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M120.5 122.906H31.503c-12.943 0-23.478-10.485-23.478-23.478 0-12.993 10.485-23.478 23.478-23.478H120.5" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M120.499 122.906c12.967 0 23.478-10.511 23.478-23.478 0-12.967-10.511-23.478-23.478-23.478-12.967 0-23.478 10.511-23.478 23.478 0 12.967 10.511 23.478 23.478 23.478z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M120.5 122.906H31.503c-12.943 0-23.478-10.485-23.478-23.478 0-12.993 10.485-23.478 23.478-23.478H120.5" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M120.499 122.906c12.967 0 23.478-10.511 23.478-23.478 0-12.967-10.511-23.478-23.478-23.478-12.967 0-23.478 10.511-23.478 23.478 0 12.967 10.511 23.478 23.478 23.478z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M31.5 29.093h88.996c12.943 0 23.478 10.485 23.478 23.478 0 12.993-10.485 23.478-23.478 23.478H31.499" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M31.503 76.052c12.967 0 23.478-10.512 23.478-23.478 0-12.967-10.511-23.479-23.478-23.479-12.966 0-23.478 10.512-23.478 23.479 0 12.966 10.512 23.478 23.478 23.478z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/icons/illustrations/decentralisedLoans.svg b/packages/website/ts/icons/illustrations/decentralisedLoans.svg deleted file mode 100755 index 72d0de7fc..000000000 --- a/packages/website/ts/icons/illustrations/decentralisedLoans.svg +++ /dev/null @@ -1,13 +0,0 @@ -<svg width="151" height="150" viewBox="0 0 151 150" fill="none" xmlns="http://www.w3.org/2000/svg"> -<circle cx="76" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> -<rect x="3" y="75" width="45.9619" height="45.9619" transform="rotate(-45 3 75)" stroke="#00AE99" stroke-width="3"/> -<rect x="85" y="75" width="45" height="45" transform="rotate(-45 85 75)" stroke="#00AE99" stroke-width="3"/> -<path d="M89 79L76 92M100 115L85 100L71.5 113.5L63 105L76 92M100 115L113 102M100 115L106 121C97.6605 129.494 89.3395 138.006 81 146.5L38.5 104M76 92L63 79" stroke="#00AE99" stroke-width="3"/> -<path d="M63.5 71.5L76.5 58.5M52.5 35.5L67.5 50.5L81 37L89.5 45.5L76.5 58.5M52.5 35.5L39.5 48.5M52.5 35.5L46.5 29.5C54.8395 21.0061 63.1605 12.4939 71.5 4L114 46.5M76.5 58.5L89.5 71.5" stroke="#00AE99" stroke-width="3"/> -<path d="M93 134.5L87 128.5" stroke="#00AE99" stroke-width="3"/> -<path d="M99 128L93.5 122.5" stroke="#00AE99" stroke-width="3"/> -<path d="M87 140L81.5 134.5" stroke="#00AE99" stroke-width="3"/> -<path d="M60.5 16.5L66.5 22.5" stroke="#00AE99" stroke-width="3"/> -<path d="M54.5 23L60 28.5" stroke="#00AE99" stroke-width="3"/> -<path d="M66.5 11L72 16.5" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/description.svg b/packages/website/ts/icons/illustrations/description.svg deleted file mode 100755 index 1887b182e..000000000 --- a/packages/website/ts/icons/illustrations/description.svg +++ /dev/null @@ -1,21 +0,0 @@ -<svg width="353" height="80" viewBox="0 0 353 80" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M130.818 77C151.253 77 167.818 60.4345 167.818 40C167.818 19.5655 151.253 3 130.818 3C110.384 3 93.8181 19.5655 93.8181 40C93.8181 60.4345 110.384 77 130.818 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M140.505 11.9474V21.0965H149.654" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M149.655 21.0964V49.351H124.562V11.9473H140.506L149.655 21.0964Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M121.131 68.0529V58.9038H111.982" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M111.982 58.9039V30.6494H137.075V68.053H121.131L111.982 58.9039Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M40 77C60.4345 77 77 60.4345 77 40C77 19.5655 60.4345 3 40 3C19.5655 3 3.00001 19.5655 3.00001 40C3.00001 60.4345 19.5655 77 40 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M40.0037 76.9359C60.4007 76.9359 76.9357 60.4009 76.9357 40.0038C76.9357 19.6068 60.4007 3.07178 40.0037 3.07178C19.6066 3.07178 3.07159 19.6068 3.07159 40.0038C3.07159 60.4009 19.6066 76.9359 40.0037 76.9359Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M30.0225 54.7728V56.2728H31.5225H51.4155H52.9155V54.7728V48.9811V47.4811H51.4155H46.3684V22.5411V21.0411H44.8684H38.5732H38.1123L37.7309 21.2999L30.6803 26.0843L30.0225 26.5306V27.3255V34.2922V37.1228L32.3648 35.5335L37.0732 32.3385V47.4811H31.5225H30.0225V48.9811V54.7728Z" stroke="#00AE99" stroke-width="3"/> -<path d="M3.06793 39.7483C10.7062 38.4893 16.5817 31.9422 16.5817 23.8843C16.5817 20.275 15.4066 17.0015 13.3921 14.3156C7.09688 20.9465 3.15187 29.9277 3.06793 39.7483Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M3.06793 40.2518C3.15187 50.1563 7.09688 59.0535 13.3921 65.6845C15.4066 62.9986 16.5817 59.725 16.5817 56.1158C16.5817 48.0579 10.7062 41.4269 3.06793 40.2518Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M76.9322 39.7483C69.294 38.4893 63.4184 31.9422 63.4184 23.8843C63.4184 20.275 64.5936 17.0015 66.608 14.3156C72.9033 20.9465 76.8483 29.9277 76.9322 39.7483Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M76.9321 40.2518C76.8482 50.1563 72.9031 59.0536 66.6079 65.6846C64.5934 62.9986 63.4183 59.7251 63.4183 56.1158C63.4183 48.0579 69.2939 41.4269 76.9321 40.2518Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M221.987 77C242.421 77 258.987 60.4345 258.987 40C258.987 19.5655 242.421 3 221.987 3C201.552 3 184.987 19.5655 184.987 40C184.987 60.4345 201.552 77 221.987 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M221.987 77C242.421 77 258.987 60.4345 258.987 40C258.987 19.5655 242.421 3 221.987 3C201.552 3 184.987 19.5655 184.987 40C184.987 60.4345 201.552 77 221.987 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M225.754 38.1178V16.3887H228.848V10.2668H215.125V16.3887H218.219V38.1178C211.156 39.7996 205.908 46.1905 205.908 53.725C205.908 62.605 213.106 69.8032 221.986 69.8032C230.866 69.8032 238.065 62.605 238.065 53.725C238.065 46.1232 232.817 39.7996 225.754 38.1178Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M228.848 10.1979H215.124V16.3197H228.848V10.1979Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M208.6 44.7092H235.307" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M312.805 77C333.239 77 349.805 60.4345 349.805 40C349.805 19.5655 333.239 3 312.805 3C292.37 3 275.805 19.5655 275.805 40C275.805 60.4345 292.37 77 312.805 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M312.607 15.2613L290.287 45.3102H312.607L312.668 64.4778L334.926 34.3678H312.607V15.2613Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/descriptionBolt.svg b/packages/website/ts/icons/illustrations/descriptionBolt.svg deleted file mode 100755 index 45e51240f..000000000 --- a/packages/website/ts/icons/illustrations/descriptionBolt.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M38.8049 76C59.2395 76 75.8049 59.4345 75.8049 39C75.8049 18.5655 59.2395 2 38.8049 2C18.3704 2 1.80493 18.5655 1.80493 39C1.80493 59.4345 18.3704 76 38.8049 76Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M38.6065 14.2613L16.2874 44.3102H38.6065L38.6679 63.4778L60.9257 33.3678H38.6065V14.2613Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/descriptionCoin.svg b/packages/website/ts/icons/illustrations/descriptionCoin.svg deleted file mode 100755 index d1015b98d..000000000 --- a/packages/website/ts/icons/illustrations/descriptionCoin.svg +++ /dev/null @@ -1,9 +0,0 @@ -<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M39 76C59.4345 76 76 59.4345 76 39C76 18.5655 59.4345 2 39 2C18.5655 2 2.00001 18.5655 2.00001 39C2.00001 59.4345 18.5655 76 39 76Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M39.0037 75.9359C59.4007 75.9359 75.9357 59.4009 75.9357 39.0038C75.9357 18.6068 59.4007 2.07178 39.0037 2.07178C18.6066 2.07178 2.07159 18.6068 2.07159 39.0038C2.07159 59.4009 18.6066 75.9359 39.0037 75.9359Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M29.0225 53.7728V55.2728H30.5225H50.4155H51.9155V53.7728V47.9811V46.4811H50.4155H45.3684V21.5411V20.0411H43.8684H37.5732H37.1123L36.7309 20.2999L29.6803 25.0843L29.0225 25.5306V26.3255V33.2922V36.1228L31.3648 34.5335L36.0732 31.3385V46.4811H30.5225H29.0225V47.9811V53.7728Z" stroke="#00AE99" stroke-width="3"/> -<path d="M2.06793 38.7483C9.70615 37.4893 15.5817 30.9422 15.5817 22.8843C15.5817 19.275 14.4066 16.0015 12.3921 13.3156C6.09688 19.9465 2.15187 28.9277 2.06793 38.7483Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M2.06793 39.2518C2.15187 49.1563 6.09688 58.0535 12.3921 64.6845C14.4066 61.9986 15.5817 58.725 15.5817 55.1158C15.5817 47.0579 9.70615 40.4269 2.06793 39.2518Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M75.9322 38.7483C68.294 37.4893 62.4184 30.9422 62.4184 22.8843C62.4184 19.275 63.5936 16.0015 65.608 13.3156C71.9033 19.9465 75.8483 28.9277 75.9322 38.7483Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M75.9321 39.2518C75.8482 49.1563 71.9031 58.0536 65.6079 64.6846C63.5934 61.9986 62.4183 58.7251 62.4183 55.1158C62.4183 47.0579 68.2939 40.4269 75.9321 39.2518Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/descriptionCopy.svg b/packages/website/ts/icons/illustrations/descriptionCopy.svg deleted file mode 100755 index 6c9b5f0fc..000000000 --- a/packages/website/ts/icons/illustrations/descriptionCopy.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M38.8181 3.5C19.212 3.5 3.31812 19.3939 3.31812 39C3.31812 58.6061 19.212 74.5 38.8181 74.5C58.4242 74.5 74.3181 58.6061 74.3181 39C74.3181 19.3939 58.4242 3.5 38.8181 3.5ZM0.318115 39C0.318115 17.737 17.5552 0.5 38.8181 0.5C60.0811 0.5 77.3181 17.737 77.3181 39C77.3181 60.263 60.0811 77.5 38.8181 77.5C17.5552 77.5 0.318115 60.263 0.318115 39Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M47.0054 10.9473H50.0054V18.5964H57.6545V21.5964H47.0054V10.9473Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M31.0619 9.44727H49.1268L59.1546 19.475V49.8509H31.0619V9.44727ZM34.0619 12.4473V46.8509H56.1546V20.7177L47.8842 12.4473H34.0619Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9818 56.4038H30.6309V67.0529H27.6309V59.4038H19.9818V56.4038Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M18.4818 28.1494H46.5745V68.553H28.5096L18.4818 58.5253V28.1494ZM21.4818 31.1494V57.2826L29.7522 65.553H43.5745V31.1494H21.4818Z" fill="#00AE99"/> -</svg>
\ No newline at end of file diff --git a/packages/website/ts/icons/illustrations/descriptionFlask.svg b/packages/website/ts/icons/illustrations/descriptionFlask.svg deleted file mode 100755 index 703b069d5..000000000 --- a/packages/website/ts/icons/illustrations/descriptionFlask.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M38.9868 76C59.4213 76 75.9868 59.4345 75.9868 39C75.9868 18.5655 59.4213 2 38.9868 2C18.5523 2 1.9868 18.5655 1.9868 39C1.9868 59.4345 18.5523 76 38.9868 76Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M38.9868 76C59.4213 76 75.9868 59.4345 75.9868 39C75.9868 18.5655 59.4213 2 38.9868 2C18.5523 2 1.9868 18.5655 1.9868 39C1.9868 59.4345 18.5523 76 38.9868 76Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M42.7537 37.1178V15.3887H45.8483V9.26685H32.1246V15.3887H35.2192V37.1178C28.1555 38.7996 22.9083 45.1905 22.9083 52.725C22.9083 61.605 30.1064 68.8032 38.9864 68.8032C47.8664 68.8032 55.0646 61.605 55.0646 52.725C55.0646 45.1232 49.8174 38.7996 42.7537 37.1178Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M45.848 9.19794H32.1243V15.3197H45.848V9.19794Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M25.5996 43.7092H52.3069" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/eficientDesign.svg b/packages/website/ts/icons/illustrations/eficientDesign.svg deleted file mode 100755 index 6b8f852c3..000000000 --- a/packages/website/ts/icons/illustrations/eficientDesign.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M45 88C68.7482 88 88 68.7482 88 45C88 21.2518 68.7482 2 45 2C21.2518 2 2 21.2518 2 45C2 68.7482 21.2518 88 45 88Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M70.2962 31.8956L57.4584 19.3542L44.833 32.1067L57.6708 44.6481L70.2962 31.8956Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M74.8267 14.5717L57.4829 19.3431L70.311 31.8859L74.8267 14.5717Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M32.184 19.5506L19.5587 32.3031L32.3965 44.8445L45.0218 32.092L32.184 19.5506Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M14.7418 15.0572L19.5451 32.2857L32.1719 19.5429L14.7418 15.0572Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M19.698 57.5441L32.5358 70.0856L45.1612 57.3331L32.3234 44.7916L19.698 57.5441Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M15.1732 74.8574L32.517 70.086L19.6889 57.5432L15.1732 74.8574Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M57.8244 69.8803L70.4497 57.1278L57.6119 44.5863L44.9865 57.3389L57.8244 69.8803Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M75.2582 74.3715L70.4548 57.1429L57.8281 69.8858L75.2582 74.3715Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/eth-based-tokens.svg b/packages/website/ts/icons/illustrations/eth-based-tokens.svg deleted file mode 100644 index b0370d234..000000000 --- a/packages/website/ts/icons/illustrations/eth-based-tokens.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="84" height="84" viewBox="0 0 84 84" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M42.1187 1.19995L42.1199 1.19995C42.3379 1.19995 42.5464 1.20714 42.7361 1.21368L42.743 1.21392C42.9394 1.2207 43.1165 1.22671 43.2972 1.22671C43.3058 1.22671 43.3145 1.22682 43.3232 1.22705C65.4565 1.80301 83.2002 19.9314 83.2002 42.1999C83.2002 64.8526 64.8528 83.1999 42.2002 83.1999C19.5476 83.1999 1.2002 64.8526 1.2002 42.1999C1.2002 19.5752 19.5195 1.22738 42.1187 1.19995ZM42.1205 3.19995C20.6264 3.22636 3.2002 20.6778 3.2002 42.1999C3.2002 63.748 20.6521 81.1999 42.2002 81.1999C63.7482 81.1999 81.2002 63.748 81.2002 42.1999C81.2002 21.0212 64.3285 3.781 43.2837 3.2267C43.0706 3.22641 42.8668 3.21938 42.681 3.21297L42.6741 3.21274C42.4779 3.20597 42.301 3.19997 42.1205 3.19995Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M68.0979 42.2001C68.0979 42.5434 67.9218 42.8627 67.6314 43.0459L42.7337 58.7489C42.4077 58.9544 41.9927 58.9544 41.6667 58.7489L16.769 43.0459C16.4786 42.8628 16.3025 42.5434 16.3025 42.2001C16.3025 41.8567 16.4786 41.5374 16.769 41.3543L41.6667 25.6513C41.9927 25.4457 42.4077 25.4457 42.7337 25.6513L67.6314 41.3543C67.9218 41.5374 68.0979 41.8567 68.0979 42.2001ZM42.2002 27.6794L19.177 42.2001L42.2002 56.7208L65.2234 42.2001L42.2002 27.6794Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M66.1803 49.8738C66.5224 50.2245 66.5601 50.7714 66.2693 51.1656L43.005 82.7131C42.8165 82.9687 42.5178 83.1196 42.2002 83.1196C41.8826 83.1196 41.5838 82.9687 41.3953 82.7131L18.1311 51.1656C17.8403 50.7714 17.878 50.2245 18.2201 49.8739C18.5621 49.5232 19.1079 49.4719 19.5092 49.7528L42.2002 65.6307L64.8912 49.7528C65.2925 49.4719 65.8383 49.5232 66.1803 49.8738ZM61.0375 54.8904L42.7735 67.6705C42.4292 67.9114 41.9711 67.9114 41.6268 67.6705L23.3628 54.8904L42.2002 80.4347L61.0375 54.8904Z" fill="#00AE99"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M42.2002 1.28039C42.5439 1.28039 42.8635 1.45687 43.0465 1.74773L68.1713 41.6673L66.4786 42.7326L42.2002 4.15775L17.9218 42.7327L16.2291 41.6673L41.3539 1.74773C41.5369 1.45687 41.8565 1.28039 42.2002 1.28039Z" fill="#00AE99"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/extensibleArchitecture.svg b/packages/website/ts/icons/illustrations/extensibleArchitecture.svg deleted file mode 100755 index 7674b3289..000000000 --- a/packages/website/ts/icons/illustrations/extensibleArchitecture.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M45.0089 45.022L80.128 45.022L80.128 68.6648L68.5 68.6648" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M44.9968 45.0043L69.8295 69.837L53.1116 86.5548L44.9968 78.4399" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M45 44.9999V80.119H21.3572V69" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M44.9932 44.9767L20.1605 69.8094L3.44264 53.0916L11.5575 44.9767" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M45.0066 44.9802L9.88753 44.9802L9.88753 21.3373L21 21.3373" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M45.0057 44.9928L20.173 20.1601L36.8908 3.44228L45.0057 11.5571" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M45.0133 44.9977L45.0133 9.87867L68.6561 9.87867L68.6561 21" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M45.0249 45.006H62H78.4605L86.5754 36.8911L69.8575 20.1733L45.0249 45.006Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M45 88C68.7482 88 88 68.7482 88 45C88 21.2518 68.7482 2 45 2C21.2518 2 2 21.2518 2 45C2 68.7482 21.2518 88 45 88Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/flexibleIntegration.svg b/packages/website/ts/icons/illustrations/flexibleIntegration.svg deleted file mode 100755 index dee44d4c0..000000000 --- a/packages/website/ts/icons/illustrations/flexibleIntegration.svg +++ /dev/null @@ -1,12 +0,0 @@ -<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M75 148C115.317 148 148 115.317 148 75C148 34.6832 115.317 2 75 2C34.6832 2 2 34.6832 2 75C2 115.317 34.6832 148 75 148Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<rect x="45" y="4" width="30" height="71" rx="15" stroke="#00AE99" stroke-width="3"/> -<rect x="45" y="4" width="30" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> -<rect x="116" y="45" width="30" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> -<rect x="75" y="116" width="30" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> -<rect x="4" y="75" width="30" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> -<rect x="75" y="75" width="30" height="71" rx="15" stroke="#00AE99" stroke-width="3"/> -<rect x="75" y="45" width="71" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> -<rect x="4" y="75" width="71" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> -<path d="M43.5 19V60H46.5V19H43.5ZM30 73.5C22.5442 73.5 16.5 67.4558 16.5 60H13.5C13.5 69.1127 20.8873 76.5 30 76.5V73.5ZM43.5 60C43.5 67.4558 37.4558 73.5 30 73.5V76.5C39.1127 76.5 46.5 69.1127 46.5 60H43.5ZM106.5 131V90H103.5V131H106.5ZM120 76.5C127.456 76.5 133.5 82.5442 133.5 90H136.5C136.5 80.8873 129.113 73.5 120 73.5V76.5ZM120 73.5C110.887 73.5 103.5 80.8873 103.5 90H106.5C106.5 82.5442 112.544 76.5 120 76.5V73.5ZM131 43.5H90V46.5H131V43.5ZM90 43.5C82.5442 43.5 76.5 37.4558 76.5 30H73.5C73.5 39.1127 80.8873 46.5 90 46.5V43.5ZM90 13.5C80.8873 13.5 73.5 20.8873 73.5 30H76.5C76.5 22.5442 82.5442 16.5 90 16.5V13.5ZM19 106.5H60V103.5H19V106.5ZM73.5 120C73.5 127.456 67.4558 133.5 60 133.5V136.5C69.1127 136.5 76.5 129.113 76.5 120H73.5ZM60 106.5C67.4558 106.5 73.5 112.544 73.5 120H76.5C76.5 110.887 69.1127 103.5 60 103.5V106.5ZM139.099 40.8017C136.843 42.4964 134.041 43.5 131 43.5V46.5C134.713 46.5 138.143 45.2719 140.901 43.2004L139.099 40.8017ZM90 16.5H116.5V13.5H90V16.5ZM16.5 60V33H13.5V60H16.5ZM40.8008 10.8995C42.496 13.1559 43.5 15.9585 43.5 19H46.5C46.5 15.2865 45.2714 11.8556 43.1992 9.09752L40.8008 10.8995ZM19 103.5C15.2865 103.5 11.8556 104.729 9.09752 106.801L10.8995 109.199C13.1559 107.504 15.9585 106.5 19 106.5V103.5ZM60 133.5H33V136.5H60V133.5ZM109.199 139.1C107.504 136.844 106.5 134.041 106.5 131H103.5C103.5 134.714 104.729 138.144 106.801 140.902L109.199 139.1ZM133.5 90V116.5H136.5V90H133.5Z" fill="#00AE99"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/flexibleIntegration0xInstant.svg b/packages/website/ts/icons/illustrations/flexibleIntegration0xInstant.svg deleted file mode 100755 index bb5116b8b..000000000 --- a/packages/website/ts/icons/illustrations/flexibleIntegration0xInstant.svg +++ /dev/null @@ -1,17 +0,0 @@ -<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M125 247C192.379 247 247 192.379 247 125C247 57.6213 192.379 3 125 3C57.6213 3 3 57.6213 3 125C3 192.379 57.6213 247 125 247Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M125 2V49.5839C125 63.4281 113.777 74.651 99.9329 74.651V74.651C86.0887 74.651 74.8658 63.4281 74.8658 49.5839V13" stroke="#00AE99" stroke-width="3"/> -<rect x="25" y="75" width="50.1342" height="50.1342" rx="25.0671" stroke="#00AE99" stroke-width="3"/> -<rect x="125" y="25" width="50.1342" height="50.1342" rx="25.0671" stroke="#00AE99" stroke-width="3"/> -<rect x="108" y="88" width="34" height="34" rx="17" stroke="#00AE99" stroke-width="3"/> -<rect x="175" y="125" width="50.1342" height="50.1342" rx="25.0671" stroke="#00AE99" stroke-width="3"/> -<rect x="75" y="175" width="50.1342" height="50.1342" rx="25.0671" stroke="#00AE99" stroke-width="3"/> -<path d="M125 248V200.067C125 186.223 136.223 175 150.067 175V175C163.911 175 175.134 186.223 175.134 200.067V236.5" stroke="#00AE99" stroke-width="3"/> -<path d="M246.5 125H200.067C186.223 125 175 113.777 175 99.9328V99.9328C175 86.0886 186.223 74.8657 200.067 74.8657H235.5" stroke="#00AE99" stroke-width="3"/> -<path d="M200 73.5001H150V76.5001H200V73.5001ZM150 73.5001C137.021 73.5001 126.5 62.9788 126.5 50.0001H123.5C123.5 64.6356 135.364 76.5001 150 76.5001V73.5001ZM150 23.5001C135.364 23.5001 123.5 35.3645 123.5 50.0001H126.5C126.5 37.0214 137.021 26.5001 150 26.5001V23.5001ZM223.12 54.2318C221.128 65.1907 211.533 73.5001 200 73.5001V76.5001C213.009 76.5001 223.825 67.1282 226.072 54.7682L223.12 54.2318ZM150 26.5001H195V23.5001H150V26.5001Z" fill="#00AE99"/> -<path d="M3 125H49.5839C63.4281 125 74.651 136.223 74.651 150.067V150.067C74.651 163.911 63.4281 175.134 49.5839 175.134H14" stroke="#00AE99" stroke-width="3"/> -<path d="M73.5 50V100H76.5V50H73.5ZM50 123.5C37.0213 123.5 26.5 112.979 26.5 100H23.5C23.5 114.636 35.3645 126.5 50 126.5V123.5ZM73.5 100C73.5 112.979 62.9787 123.5 50 123.5V126.5C64.6355 126.5 76.5 114.636 76.5 100H73.5ZM223.5 150V194H226.5V150H223.5ZM176.5 200V150H173.5V200H176.5ZM200 126.5C212.979 126.5 223.5 137.021 223.5 150H226.5C226.5 135.364 214.636 123.5 200 123.5V126.5ZM200 123.5C185.364 123.5 173.5 135.364 173.5 150H176.5C176.5 137.021 187.021 126.5 200 126.5V123.5ZM50 176.5H100V173.5H50V176.5ZM123.5 200C123.5 212.979 112.979 223.5 100 223.5V226.5C114.636 226.5 126.5 214.636 126.5 200H123.5ZM100 176.5C112.979 176.5 123.5 187.021 123.5 200H126.5C126.5 185.364 114.636 173.5 100 173.5V176.5ZM54.7016 26.9701C65.4275 29.1474 73.5 38.6326 73.5 50H76.5C76.5 37.1778 67.3949 26.4855 55.2984 24.0301L54.7016 26.9701ZM26.5 100V55H23.5V100H26.5ZM100 223.5H55V226.5H100V223.5ZM50 173.5C37.1778 173.5 26.4855 182.605 24.0301 194.702L26.9701 195.298C29.1474 184.572 38.6326 176.5 50 176.5V173.5ZM195.768 223.12C184.809 221.128 176.5 211.533 176.5 200H173.5C173.5 213.009 182.872 223.825 195.232 226.072L195.768 223.12Z" fill="#00AE99"/> -<rect x="75" y="75" width="100" height="100" stroke="#00AE99" stroke-width="3"/> -<rect x="86" y="144" width="78" height="19" stroke="#00AE99" stroke-width="3"/> -<path d="M88 134H162" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/flexibleOrders.svg b/packages/website/ts/icons/illustrations/flexibleOrders.svg deleted file mode 100755 index f4545ae38..000000000 --- a/packages/website/ts/icons/illustrations/flexibleOrders.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="91" height="90" viewBox="0 0 91 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M2 45C2 68.7579 21.2421 88 45 88C68.7579 88 88 68.7579 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M67.7548 20.2253V59.6647C67.7548 65.8083 62.7745 70.7886 56.6309 70.7886V70.7886C50.4873 70.7886 45.507 65.8083 45.507 59.6647V31.3492C45.507 25.2057 40.5266 20.2253 34.383 20.2253V20.2253C28.2395 20.2253 23.2591 25.2057 23.2591 31.3492V70.7886M67.7548 20.2253L60.676 27.3042M67.7548 20.2253L74.8337 27.3042M23.2591 70.7886L15.6746 63.2041M23.2591 70.7886L30.8436 63.2041" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/gamingAndCollectibles.svg b/packages/website/ts/icons/illustrations/gamingAndCollectibles.svg deleted file mode 100755 index c66af5088..000000000 --- a/packages/website/ts/icons/illustrations/gamingAndCollectibles.svg +++ /dev/null @@ -1,18 +0,0 @@ -<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> -<circle cx="116" cy="34" r="32" stroke="#00AE99" stroke-width="3"/> -<circle cx="116" cy="34" r="14" stroke="#00AE99" stroke-width="3"/> -<path d="M116 5L121.216 17.9481L133.046 10.5385L129.655 24.0794L143.581 25.0385L132.878 34L143.581 42.9615L129.655 43.9206L133.046 57.4615L121.216 50.0519L116 63L110.784 50.0519L98.9542 57.4615L102.345 43.9206L88.4194 42.9615L99.122 34L88.4194 25.0385L102.345 24.0794L98.9542 10.5385L110.784 17.9481L116 5Z" stroke="#00AE99" stroke-width="3"/> -<circle cx="34" cy="34" r="32" stroke="#00AE99" stroke-width="3"/> -<path d="M66 34H45M2 34H23" stroke="#00AE99" stroke-width="3"/> -<circle cx="34" cy="34" r="11" stroke="#00AE99" stroke-width="3"/> -<circle cx="34" cy="34" r="4" stroke="#00AE99" stroke-width="3"/> -<circle cx="116" cy="116" r="32" stroke="#00AE99" stroke-width="3"/> -<circle cx="116" cy="116" r="6" stroke="#00AE99" stroke-width="3"/> -<path d="M103 114C103 110.686 100.314 108 97 108C93.6863 108 91 110.686 91 114" stroke="#00AE99" stroke-width="3"/> -<path d="M141 114C141 110.686 138.314 108 135 108C131.686 108 129 110.686 129 114" stroke="#00AE99" stroke-width="3"/> -<path d="M116 122V125C116 128.866 112.866 132 109 132V132C105.134 132 102 128.866 102 125V124" stroke="#00AE99" stroke-width="3"/> -<path d="M123 133V134C123 137.866 119.866 141 116 141V141C112.134 141 109 137.866 109 134V133" stroke="#00AE99" stroke-width="3"/> -<path d="M116 122V125C116 128.866 119.134 132 123 132V132C126.866 132 130 128.866 130 125V124" stroke="#00AE99" stroke-width="3"/> -<circle cx="34" cy="116" r="32" stroke="#00AE99" stroke-width="3"/> -<path d="M33.5556 142L7 113.1M33.5556 142L61 113.1M33.5556 142L22 113.1M33.5556 142L46.4444 113.1M7 113.1L16.8889 98H33.5556M7 113.1H22M61 113.1L51.1111 98H33.5556M61 113.1H46.4444M22 113.1H46.4444M22 113.1L33.5556 98M46.4444 113.1L33.5556 98" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/generateRevenueForYourBusiness-large.svg b/packages/website/ts/icons/illustrations/generateRevenueForYourBusiness-large.svg deleted file mode 100755 index 681b8c41e..000000000 --- a/packages/website/ts/icons/illustrations/generateRevenueForYourBusiness-large.svg +++ /dev/null @@ -1,28 +0,0 @@ -<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M177.423 216C176.501 218.606 176 221.411 176 224.333C176 227.953 176.769 231.394 178.154 234.5" stroke="#00AE99" stroke-width="3"/> -<path d="M177.423 199.333C176.501 201.94 176 204.745 176 207.667C176 216.712 180.804 224.636 188 229.025" stroke="#00AE99" stroke-width="3"/> -<path d="M224.577 182.667C225.499 185.273 226 188.078 226 191C226 191.504 225.985 192.004 225.956 192.5M177.423 182.667C176.501 185.273 176 188.078 176 191C176 204.807 187.193 216 201 216C202.712 216 204.384 215.828 206 215.5" stroke="#00AE99" stroke-width="3"/> -<path d="M224.577 166C225.499 168.606 226 171.411 226 174.333C226 188.14 214.807 199.333 201 199.333C187.193 199.333 176 188.14 176 174.333C176 171.411 176.501 168.606 177.423 166" stroke="#00AE99" stroke-width="3"/> -<path d="M224.577 149.333C225.499 151.94 226 154.745 226 157.667C226 171.474 214.807 182.667 201 182.667C187.193 182.667 176 171.474 176 157.667C176 154.745 176.501 151.94 177.423 149.333" stroke="#00AE99" stroke-width="3"/> -<path d="M224.577 132.667C225.499 135.273 226 138.078 226 141C226 154.807 214.807 166 201 166C187.193 166 176 154.807 176 141C176 138.078 176.501 135.273 177.423 132.667" stroke="#00AE99" stroke-width="3"/> -<path d="M224.577 116C225.499 118.606 226 121.411 226 124.333C226 138.14 214.807 149.333 201 149.333C187.193 149.333 176 138.14 176 124.333C176 121.411 176.501 118.606 177.423 116" stroke="#00AE99" stroke-width="3"/> -<path d="M224.577 99.3333C225.499 101.94 226 104.745 226 107.667C226 121.474 214.807 132.667 201 132.667C187.193 132.667 176 121.474 176 107.667C176 104.745 176.501 101.94 177.423 99.3333" stroke="#00AE99" stroke-width="3"/> -<ellipse cx="201" cy="91" rx="25" ry="25" stroke="#00AE99" stroke-width="3"/> -<path d="M193.5 101V102.5H195H207H208.5V101V97.2266V95.7266H207H204.551V80V78.5H203.051H199.253H198.762L198.366 78.7901L194.113 81.9073L193.5 82.3568V83.1172V87.6563V90.6153L195.887 88.8661L197.753 87.4982V95.7266H195H193.5V97.2266V101Z" stroke="#00AE99" stroke-width="3"/> -<path d="M148.577 216.667C149.499 219.273 150 222.078 150 225C150 233.805 145.449 241.546 138.57 246M101.423 216.667C100.501 219.273 100 222.078 100 225C100 233.805 104.551 241.546 111.43 246" stroke="#00AE99" stroke-width="3"/> -<path d="M148.577 234.667C149.499 237.273 150 240.078 150 243C150 243.335 149.993 243.668 149.98 244M101.423 234.667C100.501 237.273 100 240.078 100 243C100 243.335 100.007 243.668 100.02 244" stroke="#00AE99" stroke-width="3"/> -<path d="M148.577 200C149.499 202.606 150 205.411 150 208.333C150 222.14 138.807 233.333 125 233.333C111.193 233.333 100 222.14 100 208.333C100 205.411 100.501 202.606 101.423 200" stroke="#00AE99" stroke-width="3"/> -<path d="M148.577 183.333C149.499 185.94 150 188.745 150 191.667C150 205.474 138.807 216.667 125 216.667C111.193 216.667 100 205.474 100 191.667C100 188.745 100.501 185.94 101.423 183.333" stroke="#00AE99" stroke-width="3"/> -<path d="M148.577 166.667C149.499 169.273 150 172.078 150 175C150 188.807 138.807 200 125 200C111.193 200 100 188.807 100 175C100 172.078 100.501 169.273 101.423 166.667" stroke="#00AE99" stroke-width="3"/> -<path d="M148.577 150C149.499 152.606 150 155.411 150 158.333C150 172.14 138.807 183.333 125 183.333C111.193 183.333 100 172.14 100 158.333C100 155.411 100.501 152.606 101.423 150" stroke="#00AE99" stroke-width="3"/> -<path d="M148.577 133.333C149.499 135.94 150 138.745 150 141.667C150 155.474 138.807 166.667 125 166.667C111.193 166.667 100 155.474 100 141.667C100 138.745 100.501 135.94 101.423 133.333" stroke="#00AE99" stroke-width="3"/> -<circle cx="125" cy="125" r="25" stroke="#00AE99" stroke-width="3"/> -<path d="M117.5 135V136.5H119H131H132.5V135V131.227V129.727H131H128.551V114V112.5H127.051H123.253H122.762L122.366 112.79L118.113 115.907L117.5 116.357V117.117V121.656V124.615L119.887 122.866L121.753 121.498V129.727H119H117.5V131.227V135Z" stroke="#00AE99" stroke-width="3"/> -<path d="M71.5775 216.333C72.4987 218.94 73 221.745 73 224.667C73 227.966 72.3608 231.116 71.1996 234" stroke="#00AE99" stroke-width="3"/> -<path d="M71.5774 199.667C72.4987 202.273 73 205.078 73 208C73 216.834 68.4176 224.599 61.5 229.045" stroke="#00AE99" stroke-width="3"/> -<path d="M23 191.333C23 188.411 23.5013 185.606 24.4225 183M71.5774 183C72.4987 185.606 73 188.411 73 191.333C73 205.14 61.8071 216.333 48 216.333C46.8122 216.333 45.6437 216.25 44.5 216.09" stroke="#00AE99" stroke-width="3"/> -<path d="M71.5774 166.333C72.4987 168.94 73 171.745 73 174.667C73 188.474 61.8071 199.667 48 199.667C34.1929 199.667 23 188.474 23 174.667C23 171.745 23.5013 168.94 24.4225 166.333" stroke="#00AE99" stroke-width="3"/> -<ellipse cx="48" cy="158" rx="25" ry="25" stroke="#00AE99" stroke-width="3"/> -<path d="M40.5 168V169.5H42H54H55.5V168V164.227V162.727H54H51.5506V147V145.5H50.0506H46.2532H45.7623L45.3665 145.79L41.1133 148.907L40.5 149.357V150.117V154.656V157.615L42.8867 155.866L44.7532 154.498V162.727H42H40.5V164.227V168Z" stroke="#00AE99" stroke-width="3"/> -<circle cx="125" cy="125" r="121.667" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/getInTouch.svg b/packages/website/ts/icons/illustrations/getInTouch.svg deleted file mode 100755 index f44365351..000000000 --- a/packages/website/ts/icons/illustrations/getInTouch.svg +++ /dev/null @@ -1,13 +0,0 @@ -<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> -<circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> -<path d="M113 75C113 85.3064 108.897 94.6546 102.235 101.5C98.4048 105.436 71 132.5 71 132.5V112.792C51.8933 110.793 37 94.6359 37 75C37 54.0132 54.0132 37 75 37C95.9868 37 113 54.0132 113 75Z" stroke="#00AE99" stroke-width="3"/> -<circle cx="75" cy="75" r="4" stroke="#00AE99" stroke-width="3"/> -<circle cx="91" cy="75" r="4" stroke="#00AE99" stroke-width="3"/> -<circle cx="59" cy="75" r="4" stroke="#00AE99" stroke-width="3"/> -<path d="M76 37H137.5" stroke="#00AE99" stroke-width="3"/> -<path d="M37 73.5L37 12M113 137.5L113 75" stroke="#00AE99" stroke-width="3"/> -<path d="M13 113H71.5" stroke="#00AE99" stroke-width="3"/> -<path d="M49.087 47.5264L92.574 4.03932" stroke="#00AE99" stroke-width="3"/> -<path d="M47.3192 100.913L3.8321 57.4259M146.314 92.4277L102.12 48.2335" stroke="#00AE99" stroke-width="3"/> -<path d="M58.2793 145.814L101.766 102.327" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/getStarted.svg b/packages/website/ts/icons/illustrations/getStarted.svg deleted file mode 100644 index 627e1810b..000000000 --- a/packages/website/ts/icons/illustrations/getStarted.svg +++ /dev/null @@ -1,13 +0,0 @@ -<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g> -<circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> -<circle cx="75" cy="75" r="58" stroke="#00AE99" stroke-width="3"/> -<path d="M62.9792 62.9792L36.6447 113.355L87.0208 87.0208M62.9792 62.9792L113.355 36.6447L87.0208 87.0208M62.9792 62.9792L87.0208 87.0208" stroke="#00AE99" stroke-width="3"/> -<path d="M75 2V17M75 133V148" stroke="#00AE99" stroke-width="3"/> -<path d="M2 75L17 75M133 75L148 75" stroke="#00AE99" stroke-width="3"/> -<path d="M11.7801 38.5L24.7705 46M125.229 104L138.22 111.5" stroke="#00AE99" stroke-width="3"/> -<path d="M38.5001 11.7801L46.0001 24.7705M104 125.229L111.5 138.22" stroke="#00AE99" stroke-width="3"/> -<path d="M111.5 11.7801L104 24.7705M46 125.229L38.5 138.22" stroke="#00AE99" stroke-width="3"/> -<path d="M138.22 38.5L125.229 46M24.7705 104L11.7801 111.5" stroke="#00AE99" stroke-width="3"/> -</g> -</svg> diff --git a/packages/website/ts/icons/illustrations/launchKit.svg b/packages/website/ts/icons/illustrations/launchKit.svg deleted file mode 100644 index fa11584af..000000000 --- a/packages/website/ts/icons/illustrations/launchKit.svg +++ /dev/null @@ -1,18 +0,0 @@ -<svg width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg"> -<circle cx="202" cy="202" r="200" stroke="#00AE99" stroke-width="3"/> -<rect x="61" y="251" width="39" height="92" rx="19.5" stroke="#00AE99" stroke-width="3"/> -<rect x="100" y="251" width="39" height="92" rx="19.5" stroke="#00AE99" stroke-width="3"/> -<rect x="139" y="251" width="39" height="92" rx="19.5" stroke="#00AE99" stroke-width="3"/> -<rect x="61" y="251" width="39" height="39" rx="19.5" stroke="#00AE99" stroke-width="3"/> -<rect x="100" y="251" width="39" height="39" rx="19.5" stroke="#00AE99" stroke-width="3"/> -<rect x="139" y="304" width="39" height="39" rx="19.5" stroke="#00AE99" stroke-width="3"/> -<rect x="178" y="304" width="39" height="39" rx="19.5" stroke="#00AE99" stroke-width="3"/> -<rect x="178" y="251" width="39" height="92" rx="19.5" stroke="#00AE99" stroke-width="3"/> -<circle cx="100" cy="212" r="39" stroke="#00AE99" stroke-width="3"/> -<circle cx="178" cy="212" r="39" stroke="#00AE99" stroke-width="3"/> -<rect x="61" y="79" width="156" height="94" stroke="#00AE99" stroke-width="3"/> -<rect width="39" height="18" transform="matrix(1 0 0 -1 84 79)" stroke="#00AE99" stroke-width="3"/> -<rect width="39" height="18" transform="matrix(1 0 0 -1 155 79)" stroke="#00AE99" stroke-width="3"/> -<path d="M217 94V61H250M217 94L250 61M217 94H250V61M217 94V241.125M250 61H333M333 61H343V251H217V241.125M333 61V241.125H217" stroke="#00AE99" stroke-width="3"/> -<path d="M275.825 252L218 343H341L275.825 252Z" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/launchKit_versionB.svg b/packages/website/ts/icons/illustrations/launchKit_versionB.svg deleted file mode 100755 index 45f9ecc75..000000000 --- a/packages/website/ts/icons/illustrations/launchKit_versionB.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg"> -<circle cx="202" cy="202" r="200" stroke="#00AE99" stroke-width="3"/> -<path d="M111.093 201.667L201.622 292.195M111.093 201.667L24.7433 115.316L115.098 24.6137L188.958 98.4738M111.093 201.667L24.7432 288.017L114.053 379.764L201.622 292.195M111.093 201.667L167.107 145.653M292.151 201.667L201.622 292.195M292.151 201.667L379.546 289.062L289.191 379.764L201.622 292.195M292.151 201.667L380.59 113.227L290.236 22.5243L214.983 97.7774M292.151 201.667L236.137 145.653M201.622 292.195L201.622 400.137M201.622 400.137L254.81 346.95M201.622 400.137L148.435 346.95" stroke="#00AE99" stroke-width="3"/> -<path d="M202 85L262 145H142L202 85Z" stroke="#00AE99" stroke-width="3"/> -<path d="M202 146L262 205H142L202 146Z" stroke="#00AE99" stroke-width="3"/> -<path d="M245 249L202 206L159 249" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/legalResources.svg b/packages/website/ts/icons/illustrations/legalResources.svg deleted file mode 100755 index a8ba7fceb..000000000 --- a/packages/website/ts/icons/illustrations/legalResources.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M2.00001 45C2.00001 68.7578 21.2421 88 45 88C68.7579 88 88 68.7578 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2.00001 21.2709 2.00001 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M45 76V11M45 76H15H75H45ZM45 11H24M45 11H66M24 11L4 47M24 11L44 47M66 11L46 47M66 11L86 47M4 47H44M4 47C4 47 4 65 24 65C44 65 44 47 44 47M46 47H86M46 47C46 47 46 65 66 65C85.25 65 86 47 86 47" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/logo-mark.svg b/packages/website/ts/icons/illustrations/logo-mark.svg deleted file mode 100644 index 4e9c9d2cb..000000000 --- a/packages/website/ts/icons/illustrations/logo-mark.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M6.30134 18.9605L8.63004 16.5511L5.73498 12.6444L2.04888 7.4287C0.746637 9.65112 0 12.2381 0 15C0 19.5753 2.04888 23.6718 5.28027 26.4229L9.95919 23.1161C8.36771 22.1247 7.08565 20.6812 6.30134 18.9605Z" fill="white"/> -<path d="M11.0395 6.30134L13.4489 8.63004L17.3556 5.73498L22.5713 2.04888C20.3489 0.746637 17.7619 0 15 0C10.4247 0 6.32825 2.04888 3.57713 5.28027L6.88386 9.95919C7.87534 8.36771 9.31883 7.08565 11.0395 6.30134Z" fill="white"/> -<path d="M21.37 13.4489L24.265 17.3556L27.9511 22.5713C29.2534 20.3489 30 17.7619 30 15C30 10.4247 27.9511 6.32825 24.7197 3.57713L20.0408 6.88386C21.6323 7.87534 22.9144 9.31883 23.6987 11.0395L21.37 13.4489Z" fill="white"/> -<path d="M26.4229 24.7197L23.1161 20.0408C22.1247 21.6323 20.6812 22.9144 18.9605 23.6987L16.5511 21.37L12.6444 24.265L7.4287 27.9511C9.65112 29.2534 12.2381 30 15 30C19.5753 30 23.6718 27.9511 26.4229 24.7197Z" fill="white"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/logo-outlined.svg b/packages/website/ts/icons/illustrations/logo-outlined.svg deleted file mode 100644 index a09d2355f..000000000 --- a/packages/website/ts/icons/illustrations/logo-outlined.svg +++ /dev/null @@ -1,14 +0,0 @@ -<svg width="400" height="406" viewBox="0 0 400 406" fill="none" xmlns="http://www.w3.org/2000/svg"> -<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="400" height="406"> -<ellipse cx="200" cy="202.967" rx="200" ry="202.744" fill="#C4C4C4"/> -</mask> -<g mask="url(#mask0)"> -<path d="M162.629 260.116L161.587 258.71L159.447 260.297L161.753 261.631L162.629 260.116ZM193.062 269.329L192.945 271.075L192.953 271.076L193.062 269.329ZM234.92 258.634L235.854 260.113L235.86 260.109L234.92 258.634ZM250.83 244.761L252.163 245.895L253.051 244.85L252.25 243.738L250.83 244.761ZM238.764 228.665L240.146 227.592L240.141 227.585L240.135 227.578L238.764 228.665ZM235.24 224.217L236.612 223.13L235.079 221.196L233.761 223.282L235.24 224.217ZM216.446 240.631L215.231 241.89L216.098 242.727L217.189 242.216L216.446 240.631ZM204.487 229.088L205.702 227.829L204.636 226.8L203.445 227.682L204.487 229.088ZM137.215 166.291L138.602 165.224L137.006 163.149L135.699 165.418L137.215 166.291ZM128.139 196.154L126.393 196.035L126.392 196.044L128.139 196.154ZM138.924 237.666L137.455 238.618H137.455L138.924 237.666ZM152.912 253.445L151.79 254.787L152.824 255.652L153.924 254.873L152.912 253.445ZM169.143 241.478L170.204 242.87L170.211 242.864L170.218 242.859L169.143 241.478ZM173.628 237.984L174.703 239.364L176.66 237.839L174.567 236.507L173.628 237.984ZM157.077 219.24L155.833 218.008L154.968 218.882L155.497 219.992L157.077 219.24ZM168.822 207.379L170.066 208.611L171.142 207.524L170.209 206.312L168.822 207.379ZM232.57 140.982L233.582 142.41L235.808 140.833L233.447 139.467L232.57 140.982ZM202.138 131.769L202.018 133.515L202.021 133.515L202.138 131.769ZM160.173 142.464L161.114 143.94L161.117 143.938L160.173 142.464ZM144.263 156.337L142.93 155.203L142.042 156.248L142.843 157.36L144.263 156.337ZM156.329 172.433L154.946 173.506L154.952 173.513L154.957 173.52L156.329 172.433ZM159.853 176.881L158.481 177.968L159.996 179.88L161.322 177.832L159.853 176.881ZM178.753 160.467L179.961 159.201L179.1 158.379L178.019 158.878L178.753 160.467ZM189.965 171.163L188.757 172.429L189.8 173.424L190.976 172.591L189.965 171.163ZM258.091 234.489L256.699 235.55L258.301 237.651L259.611 235.357L258.091 234.489ZM267.06 204.944L268.806 205.065L268.807 205.054L267.06 204.944ZM256.276 163.432L257.748 162.486L257.744 162.48L256.276 163.432ZM242.287 147.653L243.41 146.311L242.376 145.446L241.276 146.225L242.287 147.653ZM226.057 159.62L224.995 158.228L224.988 158.234L224.981 158.239L226.057 159.62ZM221.572 163.114L220.496 161.734L218.526 163.27L220.642 164.597L221.572 163.114ZM238.23 181.858L236.65 182.61L236.658 182.628L236.667 182.646L238.23 181.858ZM238.336 182.07L239.592 183.289L240.46 182.395L239.899 181.282L238.336 182.07ZM227.018 193.719L225.763 192.499L224.712 193.58L225.626 194.779L227.018 193.719ZM161.753 261.631C170.951 266.952 181.568 270.316 192.945 271.075L193.178 267.583C182.345 266.86 172.246 263.658 163.505 258.601L161.753 261.631ZM192.953 271.076C208.709 272.053 223.488 267.928 235.854 260.113L233.985 257.154C222.219 264.589 208.167 268.512 193.17 267.583L192.953 271.076ZM235.86 260.109C241.988 256.203 247.459 251.428 252.163 245.895L249.497 243.628C245.018 248.896 239.811 253.44 233.979 257.158L235.86 260.109ZM252.25 243.738C248.498 238.53 244.428 233.112 240.146 227.592L237.381 229.737C241.642 235.231 245.687 240.615 249.41 245.784L252.25 243.738ZM240.135 227.578C239.548 226.837 238.961 226.095 238.373 225.354C237.786 224.613 237.199 223.872 236.612 223.13L233.868 225.304C234.455 226.045 235.043 226.786 235.63 227.528C236.217 228.269 236.805 229.01 237.392 229.751L240.135 227.578ZM233.761 223.282C229.462 230.082 223.103 235.581 215.704 239.046L217.189 242.216C225.166 238.48 232.048 232.542 236.719 225.152L233.761 223.282ZM217.662 239.372L205.702 227.829L203.272 230.347L215.231 241.89L217.662 239.372ZM203.445 227.682L161.587 258.71L163.671 261.522L205.529 230.494L203.445 227.682ZM135.699 165.418C130.444 174.538 127.159 184.855 126.393 196.035L129.885 196.274C130.614 185.639 133.736 175.836 138.732 167.165L135.699 165.418ZM126.392 196.044C125.407 211.676 129.568 226.449 137.455 238.618L140.392 236.714C132.904 225.162 128.949 211.131 129.886 196.264L126.392 196.044ZM137.455 238.618C141.395 244.696 146.211 250.122 151.79 254.787L154.035 252.102C148.722 247.66 144.14 242.496 140.392 236.714L137.455 238.618ZM153.924 254.873C159.176 251.152 164.638 247.116 170.204 242.87L168.081 240.087C162.542 244.313 157.113 248.324 151.901 252.017L153.924 254.873ZM170.218 242.859C171.713 241.694 173.208 240.529 174.703 239.364L172.552 236.603C171.057 237.768 169.562 238.933 168.067 240.098L170.218 242.859ZM174.567 236.507C167.693 232.132 162.147 225.819 158.657 218.488L155.497 219.992C159.267 227.91 165.253 234.728 172.688 239.46L174.567 236.507ZM158.32 220.471L170.066 208.611L167.579 206.148L155.833 218.008L158.32 220.471ZM170.209 206.312L138.602 165.224L135.828 167.358L167.435 208.446L170.209 206.312ZM233.447 139.467C224.248 134.146 213.631 130.782 202.254 130.023L202.021 133.515C212.855 134.238 222.953 137.44 231.694 142.497L233.447 139.467ZM202.258 130.023C186.496 128.937 171.602 133.064 159.229 140.991L161.117 143.938C172.876 136.404 187.027 132.482 202.018 133.515L202.258 130.023ZM159.232 140.989C153.105 144.895 147.634 149.67 142.93 155.203L145.596 157.47C150.075 152.202 155.282 147.658 161.114 143.94L159.232 140.989ZM142.843 157.36C146.594 162.568 150.665 167.986 154.946 173.506L157.712 171.361C153.451 165.867 149.406 160.483 145.683 155.314L142.843 157.36ZM154.957 173.52C155.545 174.261 156.132 175.003 156.719 175.744C157.307 176.485 157.894 177.226 158.481 177.968L161.225 175.794C160.637 175.053 160.05 174.312 159.463 173.57C158.875 172.829 158.288 172.088 157.701 171.347L154.957 173.52ZM161.322 177.832C165.736 171.011 171.997 165.515 179.487 162.056L178.019 158.878C169.919 162.619 163.152 168.561 158.384 175.93L161.322 177.832ZM177.545 161.733L188.757 172.429L191.173 169.896L179.961 159.201L177.545 161.733ZM190.976 172.591L233.582 142.41L231.559 139.554L188.953 169.735L190.976 172.591ZM259.611 235.357C264.754 226.349 268.04 216.141 268.806 205.065L265.315 204.823C264.586 215.35 261.465 225.05 256.571 233.621L259.611 235.357ZM268.807 205.054C269.792 189.418 265.63 174.754 257.748 162.486L254.803 164.378C262.298 176.043 266.251 189.971 265.314 204.834L268.807 205.054ZM257.744 162.48C253.804 156.402 248.989 150.976 243.41 146.311L241.165 148.996C246.478 153.438 251.059 158.602 254.807 164.384L257.744 162.48ZM241.276 146.225C236.024 149.946 230.561 153.982 224.995 158.228L227.118 161.011C232.657 156.785 238.086 152.774 243.299 149.081L241.276 146.225ZM224.981 158.239C224.234 158.822 223.486 159.404 222.739 159.987C221.991 160.569 221.244 161.151 220.496 161.734L222.648 164.495C223.395 163.912 224.143 163.33 224.89 162.747C225.637 162.165 226.385 161.583 227.132 161L224.981 158.239ZM220.642 164.597C227.616 168.971 233.159 175.281 236.65 182.61L239.81 181.106C236.039 173.186 230.05 166.365 222.502 161.632L220.642 164.597ZM236.667 182.646L236.774 182.858L239.899 181.282L239.792 181.07L236.667 182.646ZM237.081 180.85L225.763 192.499L228.273 194.938L239.592 183.289L237.081 180.85ZM225.626 194.779L256.699 235.55L259.483 233.428L228.41 192.658L225.626 194.779Z" fill="#00AE99"/> -<ellipse cx="60.0003" cy="200.535" rx="68" ry="68.9328" stroke="#00AE99" stroke-width="3.5"/> -<ellipse cx="201.6" cy="61.8583" rx="68.8" ry="69.7438" stroke="#00AE99" stroke-width="3.5"/> -<rect x="267.2" y="133.224" width="137.6" height="137.866" stroke="#00AE99" stroke-width="3.5"/> -<rect width="99.6242" height="99.6242" transform="matrix(0.702274 -0.711907 0.702274 0.711907 271.273 342.124)" stroke="#00AE99" stroke-width="3.5"/> -<path d="M267.2 340.833C267.2 301.418 235.248 269.467 195.834 269.467H-11.2003V412.198H195.834C235.248 412.198 267.2 380.247 267.2 340.833V340.833Z" stroke="#00AE99" stroke-width="3.5"/> -</g> -<path d="M398.25 202.967C398.25 313.996 309.468 403.961 200 403.961C90.532 403.961 1.75 313.996 1.75 202.967C1.75 91.939 90.532 1.97368 200 1.97368C309.468 1.97368 398.25 91.939 398.25 202.967Z" stroke="#00AE99" stroke-width="3.5"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/long-term-impact.svg b/packages/website/ts/icons/illustrations/long-term-impact.svg deleted file mode 100644 index dbd051598..000000000 --- a/packages/website/ts/icons/illustrations/long-term-impact.svg +++ /dev/null @@ -1,9 +0,0 @@ -<svg width="104" height="104" viewBox="0 0 104 104" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M52 102C79.6142 102 102 79.6142 102 52C102 24.3858 79.6142 2 52 2C24.3858 2 2 24.3858 2 52C2 79.6142 24.3858 102 52 102Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M51.8639 91.7959C73.9553 91.7959 91.8639 73.8873 91.8639 51.7959C91.8639 29.7045 73.9553 11.7959 51.8639 11.7959C29.7726 11.7959 11.864 29.7045 11.864 51.7959C11.864 73.8873 29.7726 91.7959 51.8639 91.7959Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M51.8636 91.7959C65.0741 91.7959 75.7833 73.8873 75.7833 51.7959C75.7833 29.7045 65.0741 11.7959 51.8636 11.7959C38.6531 11.7959 27.9438 29.7045 27.9438 51.7959C27.9438 73.8873 38.6531 91.7959 51.8636 91.7959Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M51.864 11.7959V91.7959" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M91.8639 51.796H11.864" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M86.6201 71.7827H17.1084" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M86.6201 31.7823H17.1084" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -</svg>
\ No newline at end of file diff --git a/packages/website/ts/icons/illustrations/low-cost.svg b/packages/website/ts/icons/illustrations/low-cost.svg deleted file mode 100644 index da0d2e27c..000000000 --- a/packages/website/ts/icons/illustrations/low-cost.svg +++ /dev/null @@ -1,30 +0,0 @@ -<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg"> -<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="80" height="80"> -<path d="M40 78.9333C61.5023 78.9333 78.9333 61.5023 78.9333 40C78.9333 18.4977 61.5023 1.06665 40 1.06665C18.4977 1.06665 1.06665 18.4977 1.06665 40C1.06665 61.5023 18.4977 78.9333 40 78.9333Z" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10"/> -</mask> -<g mask="url(#mask0)"> -<ellipse cx="40" cy="75" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="40" cy="70" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="40" cy="65" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="40" cy="60" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="40" cy="55" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<circle cx="40" cy="49" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<circle cx="40" cy="43" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="17" cy="88" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="17" cy="83" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="17" cy="78" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="17" cy="73" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="17" cy="68" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<circle cx="17" cy="62" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<circle cx="17" cy="56" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="63" cy="69" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="63" cy="63" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="63" cy="58" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="63" cy="53" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="63" cy="48" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<ellipse cx="63" cy="43" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<circle cx="63" cy="37" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<circle cx="63" cy="31" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="2"/> -<circle cx="40" cy="40" r="38.9333" stroke="#00AE99" stroke-width="2"/> -</g> -</svg> diff --git a/packages/website/ts/icons/illustrations/marketingDesignHelp.svg b/packages/website/ts/icons/illustrations/marketingDesignHelp.svg deleted file mode 100755 index 1e65bd54f..000000000 --- a/packages/website/ts/icons/illustrations/marketingDesignHelp.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M45 88C68.7482 88 88 68.7482 88 45C88 21.2518 68.7482 2 45 2C21.2518 2 2 21.2518 2 45C2 68.7482 21.2518 88 45 88Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M70.2962 31.8956L57.4583 19.3541L44.833 32.1066L57.6708 44.6481L70.2962 31.8956Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M74.8267 14.5717L57.4829 19.3431L70.311 31.8859L74.8267 14.5717Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M32.184 19.5506L19.5587 32.3031L32.3965 44.8446L45.0218 32.092L32.184 19.5506Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M14.7418 15.0572L19.5451 32.2858L32.1719 19.5429L14.7418 15.0572Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M19.698 57.5441L32.5358 70.0856L45.1612 57.3331L32.3234 44.7916L19.698 57.5441Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M15.1732 74.8574L32.517 70.086L19.6889 57.5432L15.1732 74.8574Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M57.8243 69.8803L70.4497 57.1277L57.6119 44.5863L44.9865 57.3388L57.8243 69.8803Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -<path d="M75.2581 74.3715L70.4548 57.1429L57.828 69.8857L75.2581 74.3715Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/milestoneGrants.svg b/packages/website/ts/icons/illustrations/milestoneGrants.svg deleted file mode 100755 index 2c581864f..000000000 --- a/packages/website/ts/icons/illustrations/milestoneGrants.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M2 45C2 68.7578 21.2421 88 45 88C68.7579 88 88 68.7578 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M86.5 55.5L45 14L3.5 55.5" stroke="#00AE99" stroke-width="3"/> -<path d="M45 14C41.1667 18.8333 35.8 30.8 45 40C56.5 51.5 52 59.5 45 67C38.5223 73.9404 40.1798 83.4498 44.0292 88" stroke="#00AE99" stroke-width="3"/> -<path d="M78 73L45 40L12 73" stroke="#00AE99" stroke-width="3"/> -<path d="M62.5 84.5L45 67L27.5 84.5" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/networkedLiquidity-small.svg b/packages/website/ts/icons/illustrations/networkedLiquidity-small.svg deleted file mode 100755 index 4b65a5353..000000000 --- a/packages/website/ts/icons/illustrations/networkedLiquidity-small.svg +++ /dev/null @@ -1,20 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M39 8.48029C33.2192 9.42014 27.8875 11.702 23.335 14.9961M50.9349 8.48029C56.7423 9.41185 62.0964 11.6963 66.6651 15M75 23.3344C78.2924 27.8864 80.574 33.2182 81.5163 39M81.5163 51.0017C80.574 56.7845 78.2925 62.1161 75 66.6678M66.6651 75.002C62.0964 78.306 56.7423 80.5917 50.9349 81.5271M39 81.5165C33.2177 80.5746 27.8865 78.2936 23.335 75.002M15 66.6678C11.7076 62.1161 9.42602 56.7845 8.48376 51.0017M8.48376 39.0004C9.42608 33.2186 11.7078 27.8868 14.9996 23.3344" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M42.163 47.837C40.6123 46.2863 40.6123 43.7489 42.163 42.163C43.7137 40.6123 46.2511 40.6123 47.837 42.163C49.3877 43.7137 49.3877 46.2511 47.837 47.837C46.2511 49.3877 43.7137 49.3877 42.163 47.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M42.163 30.837C40.6123 29.2863 40.6123 26.7489 42.163 25.163C43.7137 23.6123 46.2511 23.6123 47.837 25.163C49.3877 26.7137 49.3877 29.2511 47.837 30.837C46.2511 32.3877 43.7137 32.3877 42.163 30.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M42.163 64.837C40.6123 63.2863 40.6123 60.7489 42.163 59.163C43.7137 57.6123 46.2511 57.6123 47.837 59.163C49.3877 60.7137 49.3877 63.2511 47.837 64.837C46.2511 66.3877 43.7137 66.3877 42.163 64.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M40.7445 12.2555C38.4185 9.92952 38.4185 6.12335 40.7445 3.74449C43.0705 1.4185 46.8766 1.4185 49.2555 3.74449C51.5815 6.07048 51.5815 9.87665 49.2555 12.2555C46.8766 14.5815 43.0705 14.5815 40.7445 12.2555Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M40.7445 86.2555C38.4185 83.9295 38.4185 80.1233 40.7445 77.7445C43.0705 75.4185 46.8766 75.4185 49.2555 77.7445C51.5815 80.0705 51.5815 83.8767 49.2555 86.2555C46.8766 88.5815 43.0705 88.5815 40.7445 86.2555Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M30.837 47.837C29.2863 49.3877 26.7489 49.3877 25.163 47.837C23.6123 46.2863 23.6123 43.7489 25.163 42.163C26.7137 40.6123 29.2511 40.6123 30.837 42.163C32.3877 43.7489 32.3877 46.2863 30.837 47.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M64.837 47.837C63.2863 49.3877 60.7489 49.3877 59.163 47.837C57.6123 46.2863 57.6123 43.7489 59.163 42.163C60.7137 40.6123 63.2511 40.6123 64.837 42.163C66.3877 43.7489 66.3877 46.2863 64.837 47.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M12.2555 49.2555C9.92952 51.5815 6.12335 51.5815 3.74449 49.2555C1.4185 46.9295 1.4185 43.1234 3.74449 40.7445C6.07048 38.4185 9.87665 38.4185 12.2555 40.7445C14.5815 43.1233 14.5815 46.9295 12.2555 49.2555Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M86.2555 49.2555C83.9295 51.5815 80.1233 51.5815 77.7445 49.2555C75.4185 46.9295 75.4185 43.1234 77.7445 40.7445C80.0705 38.4185 83.8767 38.4185 86.2555 40.7445C88.5815 43.1233 88.5815 46.9295 86.2555 49.2555Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M32.9792 36.9913C30.7863 36.9913 28.992 35.1971 28.9671 32.9792C28.9671 30.7862 30.7614 28.992 32.9792 28.9671C35.1722 28.9671 36.9665 30.7613 36.9914 32.9792C36.9665 35.1971 35.1722 36.9913 32.9792 36.9913Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M57.0209 61.0329C54.8279 61.0329 53.0337 59.2387 53.0087 57.0208C53.0087 54.8278 54.803 53.0336 57.0209 53.0087C59.2138 53.0087 61.0081 54.8029 61.033 57.0208C61.0081 59.2387 59.2138 61.0329 57.0209 61.0329Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M18.8371 24.8552C15.5476 24.8552 12.8563 22.1639 12.8189 18.837C12.8189 15.5476 15.5103 12.8562 18.8371 12.8188C22.1265 12.8188 24.8179 15.5102 24.8553 18.837C24.8179 22.1639 22.1265 24.8552 18.8371 24.8552Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M71.163 77.1812C67.8736 77.1812 65.1822 74.4898 65.1448 71.163C65.1448 67.8735 67.8362 65.1822 71.163 65.1448C74.4525 65.1448 77.1438 67.8361 77.1812 71.163C77.1438 74.4898 74.4525 77.1812 71.163 77.1812Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M36.9913 57.0209C36.9913 59.2138 35.197 61.0081 32.9791 61.033C30.7862 61.033 28.9919 59.2388 28.967 57.0209C28.967 54.8279 30.7612 53.0337 32.9791 53.0088C35.197 53.0337 36.9913 54.8279 36.9913 57.0209Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M61.0329 32.9793C61.0329 35.1722 59.2386 36.9665 57.0208 36.9914C54.8278 36.9914 53.0335 35.1971 53.0086 32.9793C53.0086 30.7863 54.8029 28.992 57.0208 28.9671C59.2386 28.992 61.0329 30.7863 61.0329 32.9793Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M24.8552 71.163C24.8552 74.4525 22.1639 77.1438 18.837 77.1812C15.5476 77.1812 12.8562 74.4899 12.8188 71.163C12.8188 67.8736 15.5102 65.1822 18.837 65.1448C22.1639 65.1822 24.8552 67.8736 24.8552 71.163Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M77.1812 18.8371C77.1812 22.1266 74.4898 24.8179 71.163 24.8553C67.8735 24.8553 65.1822 22.1639 65.1448 18.8371C65.1448 15.5477 67.8361 12.8563 71.163 12.8189C74.4898 12.8563 77.1812 15.5477 77.1812 18.8371Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/networkedLiquidity.svg b/packages/website/ts/icons/illustrations/networkedLiquidity.svg deleted file mode 100755 index e03488ac7..000000000 --- a/packages/website/ts/icons/illustrations/networkedLiquidity.svg +++ /dev/null @@ -1,20 +0,0 @@ -<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M34.6667 7.53809C29.5282 8.37352 24.7889 10.4019 20.7422 13.3299M45.2755 7.53809C50.4376 8.36615 55.1968 10.3967 59.2579 13.3334M66.6667 20.7417C69.5933 24.788 71.6214 29.5274 72.4589 34.6667M72.4589 45.3349C71.6214 50.4752 69.5933 55.2144 66.6667 59.2604M59.2579 66.6685C55.1968 69.6054 50.4376 71.6372 45.2755 72.4686M34.6667 72.4592C29.5269 71.6219 24.788 69.5944 20.7422 66.6685M13.3334 59.2604C10.4068 55.2144 8.3787 50.4752 7.54114 45.3349M7.54114 34.6671C8.37875 29.5277 10.407 24.7883 13.333 20.7417" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M37.4782 42.5218C36.0999 41.1434 36.0999 38.8879 37.4782 37.4782C38.8566 36.0999 41.1121 36.0999 42.5218 37.4782C43.9002 38.8566 43.9002 41.1121 42.5218 42.5218C41.1121 43.9002 38.8566 43.9002 37.4782 42.5218Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M37.4784 27.4107C36.1 26.0323 36.1 23.7768 37.4784 22.3671C38.8567 20.9888 41.1122 20.9888 42.5219 22.3671C43.9003 23.7455 43.9003 26.001 42.5219 27.4107C41.1122 28.7891 38.8567 28.7891 37.4784 27.4107Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M37.4784 57.633C36.1 56.2546 36.1 53.9991 37.4784 52.5894C38.8567 51.2111 41.1122 51.2111 42.5219 52.5894C43.9003 53.9678 43.9003 56.2233 42.5219 57.633C41.1122 59.0114 38.8567 59.0114 37.4784 57.633Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M36.2174 10.8938C34.1499 8.82629 34.1499 5.44303 36.2174 3.32849C38.285 1.26095 41.6682 1.26095 43.7828 3.32849C45.8503 5.39604 45.8503 8.7793 43.7828 10.8938C41.6682 12.9614 38.285 12.9614 36.2174 10.8938Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M36.2174 76.6717C34.1499 74.6041 34.1499 71.2209 36.2174 69.1063C38.285 67.0388 41.6682 67.0388 43.7828 69.1063C45.8503 71.1739 45.8503 74.5571 43.7828 76.6717C41.6682 78.7392 38.285 78.7392 36.2174 76.6717Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M27.4107 42.5218C26.0323 43.9001 23.7768 43.9001 22.3671 42.5218C20.9888 41.1434 20.9888 38.8879 22.3671 37.4782C23.7455 36.0998 26.001 36.0998 27.4107 37.4782C28.7891 38.8879 28.7891 41.1434 27.4107 42.5218Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M57.633 42.5218C56.2546 43.9001 53.9991 43.9001 52.5894 42.5218C51.2111 41.1434 51.2111 38.8879 52.5894 37.4782C53.9678 36.0998 56.2233 36.0998 57.633 37.4782C59.0114 38.8879 59.0114 41.1434 57.633 42.5218Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M10.8938 43.7827C8.82629 45.8503 5.44303 45.8503 3.32849 43.7827C1.26095 41.7152 1.26095 38.3319 3.32849 36.2174C5.39604 34.1498 8.7793 34.1498 10.8938 36.2174C12.9614 38.3319 12.9614 41.7152 10.8938 43.7827Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M76.6717 43.7827C74.6041 45.8503 71.2209 45.8503 69.1063 43.7827C67.0388 41.7152 67.0388 38.3319 69.1063 36.2174C71.1739 34.1498 74.5571 34.1498 76.6717 36.2174C78.7392 38.3319 78.7392 41.7152 76.6717 43.7827Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M29.3149 32.8813C27.3656 32.8813 25.7707 31.2864 25.7486 29.3149C25.7486 27.3656 27.3435 25.7708 29.3149 25.7486C31.2642 25.7486 32.8591 27.3435 32.8813 29.3149C32.8591 31.2864 31.2642 32.8813 29.3149 32.8813Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M50.6853 54.2516C48.736 54.2516 47.1411 52.6568 47.119 50.6853C47.119 48.736 48.7138 47.1411 50.6853 47.119C52.6346 47.119 54.2295 48.7138 54.2516 50.6853C54.2295 52.6568 52.6346 54.2516 50.6853 54.2516Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M16.7441 22.0936C13.8202 22.0936 11.4279 19.7013 11.3946 16.7441C11.3946 13.8202 13.787 11.4279 16.7441 11.3946C19.6681 11.3946 22.0604 13.787 22.0936 16.7441C22.0604 19.7013 19.6681 22.0936 16.7441 22.0936Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M63.2561 68.6056C60.3321 68.6056 57.9398 66.2133 57.9066 63.2561C57.9066 60.3321 60.2989 57.9398 63.2561 57.9066C66.18 57.9066 68.5724 60.2989 68.6056 63.2561C68.5724 66.2133 66.1801 68.6056 63.2561 68.6056Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M32.8813 50.6853C32.8813 52.6346 31.2864 54.2295 29.3149 54.2516C27.3656 54.2516 25.7708 52.6568 25.7486 50.6853C25.7486 48.736 27.3435 47.1411 29.3149 47.119C31.2864 47.1411 32.8813 48.736 32.8813 50.6853Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M54.2516 29.3149C54.2516 31.2642 52.6568 32.8591 50.6853 32.8813C48.736 32.8813 47.1411 31.2864 47.119 29.3149C47.119 27.3656 48.7138 25.7708 50.6853 25.7486C52.6568 25.7708 54.2516 27.3656 54.2516 29.3149Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M22.0936 63.2561C22.0936 66.1801 19.7013 68.5724 16.7441 68.6056C13.8202 68.6056 11.4279 66.2133 11.3946 63.2561C11.3946 60.3322 13.787 57.9398 16.7441 57.9066C19.7013 57.9398 22.0936 60.3322 22.0936 63.2561Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M68.6056 16.7441C68.6056 19.6681 66.2133 22.0604 63.2561 22.0937C60.3321 22.0937 57.9398 19.7013 57.9066 16.7442C57.9066 13.8202 60.2989 11.4279 63.2561 11.3946C66.2133 11.4279 68.6056 13.8202 68.6056 16.7441Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/orderBooks.svg b/packages/website/ts/icons/illustrations/orderBooks.svg deleted file mode 100755 index 44e001ff0..000000000 --- a/packages/website/ts/icons/illustrations/orderBooks.svg +++ /dev/null @@ -1,8 +0,0 @@ -<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> -<circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> -<path d="M75 64V75M75 75H69V128H75M75 75H81V128H75M75 128V139" stroke="#00AE99" stroke-width="3"/> -<path d="M98 16V27M98 27H92V75H98M98 27H104V75H98M98 75V86" stroke="#00AE99" stroke-width="3"/> -<path d="M52 16V27M52 27H46V75H52M52 27H58V75H52M52 75V86" stroke="#00AE99" stroke-width="3"/> -<path d="M29 64V75M29 75H23V100H29M29 75H35V100H29M29 100V111" stroke="#00AE99" stroke-width="3"/> -<path d="M121 64V75M121 75H115V100H121M121 75H127V100H121M121 100V111" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/predictionMarkets.svg b/packages/website/ts/icons/illustrations/predictionMarkets.svg deleted file mode 100755 index 820b79416..000000000 --- a/packages/website/ts/icons/illustrations/predictionMarkets.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M126.5 126.737C139.78 113.518 148 95.2188 148 75C148 34.6832 115.317 2 75 2C34.6832 2 2 34.6832 2 75C2 94.9638 10.0138 113.056 23 126.235" stroke="#00AE99" stroke-width="3"/> -<path d="M127 4V22M127 40V22M127 22H109H145" stroke="#00AE99" stroke-width="3"/> -<path d="M104 37V45M104 53V45M104 45H96H112" stroke="#00AE99" stroke-width="3"/> -<rect x="19" y="137" width="112" height="11" stroke="#00AE99" stroke-width="3"/> -<rect x="23" y="126" width="104" height="11" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/protocol.svg b/packages/website/ts/icons/illustrations/protocol.svg deleted file mode 100644 index 5c9c1531a..000000000 --- a/packages/website/ts/icons/illustrations/protocol.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg"><g style="mix-blend-mode:screen" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"><path d="M72 132.722c33.536 0 60.722-27.186 60.722-60.722S105.536 11.278 72 11.278 11.278 38.464 11.278 72 38.464 132.722 72 132.722z"/><path d="M72 20.557A9.278 9.278 0 1 0 72 2a9.278 9.278 0 0 0 0 18.557zM114.942 38.336a9.278 9.278 0 1 0-9.278-9.278 9.278 9.278 0 0 0 9.278 9.278zM132.722 81.278A9.278 9.278 0 0 0 142 72a9.278 9.278 0 0 0-9.278-9.278 9.278 9.278 0 1 0 0 18.556zM114.942 124.221a9.279 9.279 0 1 0 0-18.557 9.279 9.279 0 0 0 0 18.557zM72 142a9.278 9.278 0 0 0 9.278-9.278 9.278 9.278 0 1 0-18.556 0A9.278 9.278 0 0 0 72 142zM29.058 124.221a9.278 9.278 0 0 0 9.278-9.279 9.278 9.278 0 0 0-9.278-9.278 9.278 9.278 0 0 0-9.279 9.278 9.278 9.278 0 0 0 9.279 9.279zM11.278 81.278a9.278 9.278 0 1 0 0-18.556 9.278 9.278 0 0 0 0 18.556zM29.058 38.336a9.278 9.278 0 1 0 0-18.557 9.278 9.278 0 0 0 0 18.557zM68.114 75.886c-2.138-2.137-2.138-5.635 0-7.82 2.137-2.138 5.635-2.138 7.82 0 2.138 2.137 2.138 5.634 0 7.82-2.185 2.138-5.683 2.138-7.82 0zM49.363 75.886c-2.137-2.137-2.137-5.635 0-7.82 2.137-2.138 5.635-2.138 7.821 0 2.137 2.137 2.137 5.634 0 7.82a5.571 5.571 0 0 1-7.821 0zM30.66 75.886c-2.137-2.137-2.137-5.635 0-7.82 2.138-2.138 5.636-2.138 7.822 0 2.137 2.137 2.137 5.634 0 7.82-2.186 2.138-5.684 2.138-7.821 0zM86.816 75.886c-2.137-2.137-2.137-5.635 0-7.82 2.138-2.138 5.635-2.138 7.821 0 2.138 2.137 2.138 5.634 0 7.82-2.186 2.138-5.683 2.138-7.82 0zM105.518 75.886c-2.137-2.137-2.137-5.635 0-7.82 2.138-2.138 5.635-2.138 7.821 0 2.138 2.137 2.138 5.634 0 7.82-2.186 2.138-5.683 2.138-7.821 0zM53.25 58.738c0-3.06 2.477-5.489 5.489-5.489 3.06 0 5.489 2.477 5.489 5.49 0 3.06-2.478 5.489-5.49 5.489-3.011.048-5.489-2.43-5.489-5.49zM40.036 45.525c0-3.06 2.478-5.489 5.49-5.489 3.06 0 5.489 2.477 5.489 5.49 0 3.06-2.478 5.489-5.49 5.489a5.453 5.453 0 0 1-5.489-5.49zM79.724 85.213c0-3.06 2.477-5.49 5.49-5.49 3.06 0 5.488 2.478 5.488 5.49 0 3.06-2.477 5.49-5.489 5.49-3.06.048-5.49-2.43-5.49-5.49zM92.937 98.475c0-3.06 2.477-5.49 5.49-5.49a5.483 5.483 0 0 1 5.488 5.49c0 3.06-2.477 5.489-5.489 5.489s-5.49-2.478-5.49-5.49zM85.213 53.25c3.06 0 5.49 2.477 5.49 5.488 0 3.06-2.478 5.49-5.49 5.49a5.483 5.483 0 0 1-5.49-5.49 5.483 5.483 0 0 1 5.49-5.489zM98.475 40.036c3.06 0 5.489 2.477 5.489 5.49 0 3.06-2.477 5.489-5.49 5.489a5.484 5.484 0 0 1-5.489-5.49c-.048-3.06 2.43-5.489 5.49-5.489zM58.739 79.724c3.06 0 5.489 2.477 5.489 5.489 0 3.06-2.478 5.49-5.49 5.49a5.483 5.483 0 0 1-5.489-5.49c0-3.06 2.478-5.49 5.49-5.49zM45.525 92.937c3.06 0 5.49 2.477 5.49 5.49a5.483 5.483 0 0 1-5.49 5.488 5.483 5.483 0 0 1-5.489-5.489 5.484 5.484 0 0 1 5.49-5.49zM68.114 49.363c2.137-2.138 5.635-2.138 7.82 0 2.138 2.137 2.138 5.635 0 7.82-2.137 2.138-5.634 2.138-7.82 0a5.483 5.483 0 0 1 0-7.82zM68.114 30.66c2.137-2.137 5.635-2.137 7.82 0 2.138 2.138 2.138 5.636 0 7.822-2.137 2.137-5.634 2.137-7.82 0-2.186-2.186-2.186-5.684 0-7.821zM68.114 86.816c2.137-2.137 5.635-2.137 7.82 0 2.138 2.138 2.138 5.635 0 7.821-2.137 2.137-5.634 2.137-7.82 0-2.186-2.186-2.186-5.683 0-7.82zM68.114 105.518c2.137-2.137 5.635-2.137 7.82 0 2.138 2.138 2.138 5.635 0 7.821-2.137 2.138-5.634 2.138-7.82 0-2.186-2.186-2.186-5.683 0-7.821z"/></g></svg>
\ No newline at end of file diff --git a/packages/website/ts/icons/illustrations/ready-to-build.svg b/packages/website/ts/icons/illustrations/ready-to-build.svg deleted file mode 100644 index a26a4e236..000000000 --- a/packages/website/ts/icons/illustrations/ready-to-build.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="152" height="152" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M76 151c41.421 0 75-33.579 75-75S117.421 1 76 1 1 34.579 1 76s33.579 75 75 75z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M76 1.502l-30.852 44.8H76L76.05 76l30.803-44.9H76.001V1.502zM76 75.997l-30.853 44.799H76l.05 29.699 30.803-44.899H76V75.997z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10" stroke-linejoin="round"/><path d="M1.502 75.998l44.8 30.852V75.998L76 75.948 31.1 45.144v30.853H1.503zM76 76l45.101 31.522V76L151 75.95l-45.202-31.47V76H76z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10" stroke-linejoin="round"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/icons/illustrations/recruitingSupport.svg b/packages/website/ts/icons/illustrations/recruitingSupport.svg deleted file mode 100755 index d630b23d7..000000000 --- a/packages/website/ts/icons/illustrations/recruitingSupport.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M2 45C2 68.7578 21.2421 88 45 88C68.7579 88 88 68.7578 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M30 45C30 53.2876 36.7124 60 45 60C53.2876 60 60 53.2876 60 45C60 36.8528 53.5084 30.2207 45.4114 30.01C45.2609 30.01 45.1204 30 44.9699 30C36.7023 30.01 30 36.7224 30 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M21 45C21 58.2602 31.7398 69 45 69C58.2602 69 69 58.2602 69 45C69 31.9645 58.6134 21.3532 45.6582 21.0161C45.4174 21.0161 45.1926 21 44.9518 21C31.7237 21.0161 21 31.7559 21 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M56.5 56L76 75.5" stroke="#00AE99" stroke-width="3"/> -<path d="M45 70.5C54.0057 70.5 62.1515 74.8777 67.8311 81.94L70.1689 80.06C63.9926 72.3798 55.0243 67.5 45 67.5V70.5ZM45 67.5C34.9757 67.5 26.0074 72.3798 19.8311 80.06L22.1689 81.94C27.8485 74.8777 35.9943 70.5 45 70.5V67.5Z" fill="#00AE99"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/right-thing.svg b/packages/website/ts/icons/illustrations/right-thing.svg deleted file mode 100644 index eba2bbc36..000000000 --- a/packages/website/ts/icons/illustrations/right-thing.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="104" height="104" viewBox="0 0 104 104" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M52 102C79.6142 102 102 79.6142 102 52C102 24.3858 79.6142 2 52 2C24.3858 2 2 24.3858 2 52C2 79.6142 24.3858 102 52 102Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M92.0611 24.6135C81.9235 14.476 65.4872 14.476 55.3496 24.6135L51.6804 28.286L48.008 24.6135C37.8704 14.476 21.4341 14.476 11.2965 24.6135C1.15897 34.7511 1.15897 51.1874 11.2965 61.325L14.969 64.9974L51.6804 101.706L88.3918 64.9942L92.0643 61.3218C102.199 51.1874 102.199 34.7511 92.0611 24.6135Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M81.2925 45.1702C73.8581 37.7358 61.8044 37.7358 54.3731 45.1702L51.6796 47.8637L48.9861 45.1702C41.5517 37.7358 29.4979 37.7358 22.0635 45.1702C14.6291 52.6046 14.6291 64.6583 22.0635 72.0928L24.757 74.7863L51.6764 101.709L78.599 74.7863L81.2925 72.0928C88.7269 64.6583 88.7269 52.6046 81.2925 45.1702Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M70.5248 65.73C65.7935 60.9987 58.1223 60.9987 53.3942 65.73L51.6796 67.4446L49.9649 65.73C45.2336 60.9987 37.5625 60.9987 32.8344 65.73C28.1031 70.4613 28.1031 78.1324 32.8344 82.8605L34.5491 84.5752L51.6796 101.706L68.8101 84.5752L70.5248 82.8605C75.256 78.1292 75.256 70.4613 70.5248 65.73Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/robustSmartContracts.svg b/packages/website/ts/icons/illustrations/robustSmartContracts.svg deleted file mode 100755 index 060f2d00c..000000000 --- a/packages/website/ts/icons/illustrations/robustSmartContracts.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M45 88C68.7482 88 88 68.7482 88 45C88 21.2518 68.7482 2 45 2C21.2518 2 2 21.2518 2 45C2 68.7482 21.2518 88 45 88Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M70 29V79H20V11H52M70 29L52 11M70 29V11H52" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M30 45H60M30 55H60M30 65H60" stroke="#00AE99" stroke-width="3"/> -<path d="M52 11V29H70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/rocketship.svg b/packages/website/ts/icons/illustrations/rocketship.svg deleted file mode 100644 index e9b4b83ab..000000000 --- a/packages/website/ts/icons/illustrations/rocketship.svg +++ /dev/null @@ -1,9 +0,0 @@ -<svg width="124" height="124" viewBox="0 0 124 124" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M44.6582 74.4521L12.4089 95.6738M18.9394 103.633L46.699 76.2888" stroke="#00AE99" stroke-width="2.5"/> -<path d="M51.3926 80.5745L34.6538 115.266M25.8784 109.96L49.1477 78.5338" stroke="#00AE99" stroke-width="2.5"/> -<path d="M77.212 78.8086L75.9699 78.949L75.9699 78.949L77.212 78.8086ZM77.603 60.0842L76.4001 59.7443L77.603 60.0842ZM84.9562 43.7018L83.979 42.9223L83.9342 42.9785L83.8961 43.0394L84.9562 43.7018ZM73.085 87.8359L72.2661 88.7803L73.2262 89.6128L74.0428 88.6391L73.085 87.8359ZM56.5473 79.3763L57.4218 80.2694L57.459 80.2331L57.493 80.1937L56.5473 79.3763ZM53.8137 79.4142L54.6312 78.4685L54.6311 78.4685L53.8137 79.4142ZM53.0049 80.3499L53.7507 81.3531L53.8608 81.2712L53.9505 81.1674L53.0049 80.3499ZM51.4635 80.243L52.2809 79.2973L52.2809 79.2973L51.4635 80.243ZM61.3832 68.3677L60.5429 69.2931L60.5542 69.3034L60.5658 69.3134L61.3832 68.3677ZM74.9165 85.3062L75.9718 85.9761L75.9718 85.9761L74.9165 85.3062ZM91.434 27.7957L92.5916 27.3241L92.4784 27.0462L92.2514 26.85L91.434 27.7957ZM42.7642 49.0315L42.8049 50.2809L42.8049 50.2809L42.7642 49.0315ZM61.2349 45.9355L61.7453 47.0765L61.2349 45.9355ZM76.3811 36.2894L77.1898 37.2424L77.2446 37.1959L77.2937 37.1435L76.3811 36.2894ZM34.429 54.4212L33.4956 53.5898L32.6503 54.5386L33.613 55.3682L34.429 54.4212ZM45.1923 69.5609L44.2467 68.7435L44.2127 68.7828L44.182 68.8248L45.1923 69.5609ZM45.5503 72.2712L46.3678 71.3256L46.3678 71.3256L45.5503 72.2712ZM44.7415 73.207L43.7958 72.3895L43.7061 72.4933L43.641 72.6141L44.7415 73.207ZM45.0703 74.7167L45.8878 73.771L45.8878 73.771L45.0703 74.7167ZM55.3854 63.1831L54.5679 64.1288L54.5795 64.1388L54.5913 64.1485L55.3854 63.1831ZM36.667 52.2431L35.8515 51.2958L35.8515 51.2958L36.667 52.2431ZM91.1826 27.5784L92 26.6327L91.773 26.4365L91.4817 26.3647L91.1826 27.5784ZM83.9509 43.0422L61.4101 69.1188L63.3014 70.7536L85.8422 44.6771L83.9509 43.0422ZM78.4541 78.6681C78.0305 74.9211 76.5083 68.5531 78.8059 60.4242L76.4001 59.7443C73.9348 68.4667 75.5746 75.4525 75.9699 78.949L78.4541 78.6681ZM78.8059 60.4242C80.6674 53.8382 84.3943 46.96 86.0163 44.3642L83.8961 43.0394C82.2037 45.748 78.349 52.8492 76.4001 59.7443L78.8059 60.4242ZM85.9334 44.4813C86.7782 43.4222 88.106 41.5706 89.3107 39.7677C90.4904 38.002 91.6492 36.1406 92.0741 35.11L89.7628 34.1571C89.4497 34.9164 88.4417 36.5683 87.232 38.3788C86.0471 40.1522 84.7628 41.9398 83.979 42.9223L85.9334 44.4813ZM73.904 86.8915L60.2718 75.0706L58.634 76.9594L72.2661 88.7803L73.904 86.8915ZM58.5072 75.1976L55.6017 78.5589L57.493 80.1937L60.3985 76.8324L58.5072 75.1976ZM55.6728 78.4831C55.6952 78.4612 55.6589 78.4988 55.5624 78.5515C55.474 78.5998 55.3704 78.6413 55.265 78.6627C55.163 78.6835 55.0696 78.6837 54.9818 78.6633C54.8989 78.6441 54.7803 78.5974 54.6312 78.4685L52.9963 80.3599C53.9198 81.1581 54.9373 81.2805 55.7629 81.1126C56.5187 80.959 57.1181 80.5669 57.4218 80.2694L55.6728 78.4831ZM52.8681 78.5968L52.0592 79.5325L53.9505 81.1674L54.7594 80.2317L52.8681 78.5968ZM52.2591 79.3468C52.279 79.332 52.2917 79.3249 52.2958 79.3226C52.3006 79.32 52.302 79.3197 52.3006 79.3202C52.2965 79.3217 52.2938 79.3219 52.2957 79.3217C52.2974 79.3216 52.3007 79.3216 52.3054 79.3221C52.3102 79.3227 52.3147 79.3237 52.3182 79.3249C52.3218 79.326 52.3213 79.3263 52.3164 79.3236C52.3115 79.3208 52.2994 79.3133 52.2809 79.2973L50.646 81.1886C51.8617 82.2394 53.2052 81.7587 53.7507 81.3531L52.2591 79.3468ZM60.5658 69.3134C61.2107 69.8709 61.7136 71.4882 60.5236 72.8649L62.4149 74.4998C64.5664 72.0109 63.8212 68.8229 62.2006 67.422L60.5658 69.3134ZM60.5236 72.8649L58.5072 75.1976L60.3985 76.8324L62.4149 74.4998L60.5236 72.8649ZM74.0428 88.6391C74.5796 87.999 75.2848 87.0584 75.9718 85.9761L73.8611 84.6363C73.2323 85.627 72.5921 86.4784 72.1273 87.0326L74.0428 88.6391ZM75.9718 85.9761C76.6408 84.9221 77.3127 83.7022 77.792 82.4704C78.2624 81.2613 78.5956 79.9197 78.4541 78.6681L75.9699 78.949C76.045 79.6133 75.8726 80.509 75.4621 81.5639C75.0605 82.5961 74.4763 83.6671 73.8611 84.6363L75.9718 85.9761ZM75.7339 84.3606L62.2867 72.7367L60.6518 74.628L74.099 86.2519L75.7339 84.3606ZM60.2703 75.0693L54.4097 70.0034L52.7748 71.8947L58.6354 76.9607L60.2703 75.0693ZM57.4148 66.5254C58.723 67.6581 59.9087 68.7173 60.5429 69.2931L62.2235 67.4423C61.5753 66.8537 60.3749 65.7815 59.0512 64.6354L57.4148 66.5254ZM48.6813 76.6305L52.9964 80.3599L54.6311 78.4685L50.316 74.739L48.6813 76.6305ZM47.2951 78.2921L50.646 81.1886L52.2809 79.2973L48.9299 76.4007L47.2951 78.2921ZM92.0741 35.11C92.483 34.1181 92.8555 32.8177 93.0125 31.4685C93.1677 30.1352 93.1262 28.6366 92.5916 27.3241L90.2763 28.2672C90.5897 29.0365 90.6594 30.0618 90.5293 31.1795C90.4011 32.2814 90.0918 33.359 89.7628 34.1571L92.0741 35.11ZM75.2878 35.5538L52.747 61.6303L54.6383 63.2652L77.1792 37.1886L75.2878 35.5538ZM42.8049 50.2809C46.3218 50.1661 53.4713 50.778 61.7453 47.0765L60.7244 44.7945C53.0135 48.244 46.4923 47.6592 42.7234 47.7822L42.8049 50.2809ZM61.7453 47.0765C68.2859 44.1505 74.7546 39.309 77.1898 37.2424L75.5723 35.3363C73.2384 37.3168 66.9718 41.9996 60.7244 44.7945L61.7453 47.0765ZM77.2937 37.1435C78.1525 36.2258 79.7355 34.6963 81.3187 33.2674C82.9352 31.8084 84.4239 30.572 85.1299 30.1523L83.8526 28.0033C82.8943 28.5728 81.2201 29.9887 79.6437 31.4115C78.034 32.8643 76.3941 34.446 75.4684 35.4352L77.2937 37.1435ZM33.613 55.3682L47.2819 67.1466L48.9138 65.2527L35.2449 53.4743L33.613 55.3682ZM47.1522 65.3822L44.2467 68.7435L46.138 70.3784L49.0435 67.0171L47.1522 65.3822ZM44.182 68.8248C43.9317 69.1684 43.6304 69.8183 43.5877 70.5883C43.5411 71.4295 43.8094 72.4187 44.7329 73.2169L46.3678 71.3256C46.2187 71.1967 46.1553 71.0861 46.1243 71.0068C46.0914 70.9229 46.0781 70.8305 46.0839 70.7266C46.0899 70.6192 46.1159 70.5106 46.1509 70.4161C46.1892 70.3131 46.221 70.2717 46.2026 70.297L44.182 68.8248ZM44.6047 71.4538L43.7958 72.3895L45.6871 74.0244L46.496 73.0887L44.6047 71.4538ZM43.641 72.6141C43.3186 73.2126 43.0373 74.6115 44.2529 75.6624L45.8878 73.771C45.8693 73.755 45.8601 73.7441 45.8566 73.7397C45.8532 73.7353 45.8534 73.7348 45.8551 73.7381C45.8567 73.7414 45.8584 73.7457 45.8597 73.7504C45.8609 73.7549 45.8613 73.7583 45.8614 73.7599C45.8616 73.7618 45.8613 73.7592 45.8623 73.7549C45.8626 73.7534 45.8624 73.7548 45.8606 73.76C45.8589 73.7644 45.8537 73.7779 45.8419 73.7998L43.641 72.6141ZM56.2028 62.2375C54.5822 60.8366 51.32 60.5606 49.1686 63.0495L51.0599 64.6844C52.25 63.3077 53.9229 63.5713 54.5679 64.1288L56.2028 62.2375ZM49.1686 63.0495L47.1522 65.3822L49.0435 67.0171L51.0599 64.6844L49.1686 63.0495ZM35.3623 55.2527C35.8435 54.7125 36.5933 53.9559 37.4825 53.1904L35.8515 51.2958C34.88 52.1321 34.0513 52.966 33.4956 53.5898L35.3623 55.2527ZM37.4825 53.1904C38.3526 52.4414 39.3278 51.7084 40.291 51.1617C41.2754 50.6029 42.1367 50.3027 42.8049 50.2809L42.7234 47.7822C41.4645 47.8233 40.1853 48.347 39.057 48.9875C37.9074 49.6399 36.7976 50.4813 35.8515 51.2958L37.4825 53.1904ZM35.8496 53.1887L49.2968 64.8126L50.9317 62.9213L37.4845 51.2974L35.8496 53.1887ZM47.2804 67.1453L53.141 72.2113L54.7759 70.3199L48.9153 65.254L47.2804 67.1453ZM59.4158 64.9506C58.0903 63.8066 56.8557 62.774 56.1795 62.2178L54.5913 64.1485C55.2529 64.6927 56.4724 65.7127 57.7825 66.8433L59.4158 64.9506ZM50.6824 75.0557L46.3678 71.3256L44.7328 73.2168L49.0474 76.9469L50.6824 75.0557ZM49.2387 76.6676L45.8878 73.771L44.2529 75.6624L47.6038 78.559L49.2387 76.6676ZM85.1299 30.1523C85.872 29.7113 86.8935 29.2494 87.9652 28.9631C89.0523 28.6726 90.0769 28.5933 90.8835 28.792L91.4817 26.3647C90.1056 26.0255 88.6168 26.2013 87.3199 26.5478C86.0077 26.8984 84.7749 27.4551 83.8526 28.0033L85.1299 30.1523ZM92.2514 26.85L92 26.6327L90.3651 28.524L90.6165 28.7413L92.2514 26.85Z" fill="#00AE99"/> -<path d="M66.0818 13.4286V16.2857M66.0818 19.1428V16.2857M66.0818 16.2857H63.2246H68.9389" stroke="#00AE99" stroke-width="2.5"/> -<path d="M108.122 62V64.8571M108.122 67.7143V64.8571M108.122 64.8571H105.265H110.979" stroke="#00AE99" stroke-width="2.5"/> -<path d="M37.9182 25.6735V28.5307M37.9182 31.3878V28.5307M37.9182 28.5307H35.061H40.7753" stroke="#00AE99" stroke-width="2.5"/> -<path d="M62 122C95.1371 122 122 95.1371 122 62C122 28.8629 95.1371 2 62 2C28.8629 2 2 28.8629 2 62C2 95.1371 28.8629 122 62 122Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/secureTrading.svg b/packages/website/ts/icons/illustrations/secureTrading.svg deleted file mode 100755 index 109ddbb5b..000000000 --- a/packages/website/ts/icons/illustrations/secureTrading.svg +++ /dev/null @@ -1,15 +0,0 @@ -<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M1.77759 39.9988C1.77759 61.1163 18.8812 78.2199 39.9987 78.2199C61.1161 78.2199 78.2198 61.1163 78.2198 39.9988C78.2198 19.2392 61.6786 2.34016 41.0469 1.80328C40.6634 1.80328 40.3055 1.77771 39.922 1.77771C18.8556 1.80328 1.77759 18.9069 1.77759 39.9988Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M13.3328 13.3329H66.6645V66.6646H55.8315H23.3325H13.3328V13.3329Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M60.659 19.3108H19.3107V60.6591H27.0635H52.2601H60.659V19.3108Z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M13.0186 39.985H19.3107" stroke="#00AE99" stroke-width="2"/> -<path d="M13.0186 30.9962H19.3107" stroke="#00AE99" stroke-width="2"/> -<path d="M13.0186 48.9738H19.3107" stroke="#00AE99" stroke-width="2"/> -<circle cx="39.9849" cy="39.985" r="12.5843" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -<path d="M39.9849 27.4008V34.5918" stroke="#00AE99" stroke-width="2"/> -<path d="M28.5898 34.6449L35.1013 37.6964" stroke="#00AE99" stroke-width="2"/> -<path d="M31.359 49.1481L36.2881 43.9121" stroke="#00AE99" stroke-width="2"/> -<path d="M48.6516 49.1094L43.6992 43.8955" stroke="#00AE99" stroke-width="2"/> -<path d="M51.3879 34.6621L44.8719 37.7039" stroke="#00AE99" stroke-width="2"/> -<circle cx="39.9849" cy="39.985" r="4.49438" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/social-discord.svg b/packages/website/ts/icons/illustrations/social-discord.svg deleted file mode 100644 index 144f6e061..000000000 --- a/packages/website/ts/icons/illustrations/social-discord.svg +++ /dev/null @@ -1,3 +0,0 @@ -<svg width="40" height="44" viewBox="0 0 40 44" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M34.8156 0C37.3489 0 39.3921 2.04861 39.5129 4.45939V43.2425L34.6895 39.1471L32.0409 36.7363L29.1509 34.2175L30.3581 38.1904H5.06478C2.5387 38.1904 0.488281 36.2715 0.488281 33.7292V4.46839C0.488281 2.05762 2.5423 0.00540532 5.07379 0.00540532H34.803L34.8156 0ZM23.7924 10.2395H23.7383L23.3744 10.5998C27.1095 11.6809 28.9166 13.3691 28.9166 13.3691C26.5095 12.1656 24.3401 11.5638 22.1708 11.3205C20.6033 11.0773 19.0357 11.2052 17.7114 11.3205H17.3511C16.5042 11.3205 14.7025 11.6809 12.2881 12.6448C11.4467 13.0106 10.9638 13.2502 10.9638 13.2502C10.9638 13.2502 12.7692 11.4449 16.7475 10.4809L16.5042 10.2377C16.5042 10.2377 13.4917 10.1224 10.2395 12.5259C10.2395 12.5259 6.98727 18.1907 6.98727 25.1744C6.98727 25.1744 8.78905 28.3094 13.7313 28.4284C13.7313 28.4284 14.452 27.468 15.1817 26.623C12.407 25.7798 11.3259 24.0933 11.3259 24.0933C11.3259 24.0933 11.5674 24.2122 11.9295 24.4536H12.0376C12.0917 24.4536 12.1169 24.4807 12.1457 24.5077V24.5185C12.1746 24.5473 12.1998 24.5726 12.2539 24.5726C12.8484 24.8176 13.443 25.059 13.9295 25.2933C14.7691 25.6572 15.8484 26.0194 17.1727 26.259C18.8483 26.5023 20.769 26.6194 22.9564 26.259C24.0374 26.0158 25.1185 25.778 26.1996 25.2951C26.9023 24.9347 27.7671 24.5744 28.7166 23.9672C28.7166 23.9672 27.6356 25.6536 24.7437 26.4969C25.3383 27.3365 26.1761 28.2986 26.1761 28.2986C31.1202 28.1905 33.0409 25.0554 33.149 25.1888C33.149 18.2159 29.8788 12.5403 29.8788 12.5403C26.9329 10.353 24.1762 10.2701 23.6897 10.2701L23.7906 10.2341L23.7924 10.2395ZM24.0951 18.1907C25.3617 18.1907 26.3834 19.2718 26.3834 20.5961C26.3834 21.9294 25.3563 23.0104 24.0951 23.0104C22.8339 23.0104 21.8068 21.9294 21.8068 20.6069C21.8105 19.2736 22.8393 18.1961 24.0951 18.1961V18.1907ZM15.9096 18.1907C17.1709 18.1907 18.1907 19.2718 18.1907 20.5961C18.1907 21.9294 17.1637 23.0104 15.9024 23.0104C14.6412 23.0104 13.6142 21.9294 13.6142 20.6069C13.6142 19.2736 14.6412 18.1961 15.9024 18.1961L15.9096 18.1907Z" fill="white"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/social-fb.svg b/packages/website/ts/icons/illustrations/social-fb.svg deleted file mode 100644 index e50cf107a..000000000 --- a/packages/website/ts/icons/illustrations/social-fb.svg +++ /dev/null @@ -1,3 +0,0 @@ -<svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M35.9037 0H2.09633C0.938917 0 0 0.938917 0 2.09633V35.9037C0 37.0627 0.938917 38 2.09633 38H20.2952V23.2845H15.3409V17.5513H20.2952V13.3158C20.2952 8.40908 23.294 5.73958 27.6719 5.73958C29.7698 5.73958 31.5733 5.89317 32.0989 5.96283V11.0928H29.0573C26.6823 11.0928 26.22 12.2344 26.22 13.8969V17.556H31.8947L31.1584 23.3035H26.22V38H35.9021C37.0627 38 38 37.0627 38 35.9037V2.09633C38 0.938917 37.0627 0 35.9037 0Z" fill="white"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/social-github.svg b/packages/website/ts/icons/illustrations/social-github.svg deleted file mode 100644 index ef0025582..000000000 --- a/packages/website/ts/icons/illustrations/social-github.svg +++ /dev/null @@ -1,3 +0,0 @@ -<svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M19 0.17334C8.5025 0.17334 0 8.68059 0 19.1733C0 27.5698 5.4435 34.69 12.9913 37.1996C13.9412 37.3785 14.2896 36.7911 14.2896 36.286C14.2896 35.8348 14.2738 34.6393 14.2658 33.056C8.98067 34.2023 7.866 30.5068 7.866 30.5068C7.0015 28.3139 5.75225 27.7281 5.75225 27.7281C4.03117 26.5501 5.88525 26.5738 5.88525 26.5738C7.79317 26.7068 8.79542 28.5308 8.79542 28.5308C10.4896 31.4363 13.243 30.5971 14.3292 30.111C14.5002 28.8823 14.9894 28.0448 15.5325 27.5698C11.3129 27.0948 6.878 25.4608 6.878 18.1806C6.878 16.1064 7.61425 14.4123 8.83342 13.0823C8.61967 12.6025 7.97842 10.6708 8.99967 8.05359C8.99967 8.05359 10.5909 7.54376 14.2247 10.0011C15.7447 9.57834 17.3597 9.36934 18.9747 9.35984C20.5897 9.36934 22.2047 9.57834 23.7247 10.0011C27.3347 7.54376 28.9259 8.05359 28.9259 8.05359C29.9472 10.6708 29.3059 12.6025 29.1159 13.0823C30.3272 14.4123 31.0634 16.1064 31.0634 18.1806C31.0634 25.4798 26.6222 27.0868 22.3947 27.5539C23.0597 28.1239 23.6772 29.2893 23.6772 31.0689C23.6772 33.6118 23.6534 35.6543 23.6534 36.2718C23.6534 36.7705 23.9859 37.3643 24.9597 37.1743C32.5613 34.6821 38 27.5571 38 19.1733C38 8.68059 29.4928 0.17334 19 0.17334Z" fill="white"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/social-newsletter.svg b/packages/website/ts/icons/illustrations/social-newsletter.svg deleted file mode 100644 index 572cb8ed9..000000000 --- a/packages/website/ts/icons/illustrations/social-newsletter.svg +++ /dev/null @@ -1,3 +0,0 @@ -<svg width="38" height="30" viewBox="0 0 38 30" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M38 3.125V26.875C38 28.2208 36.9708 29.25 35.625 29.25H33.25V7.69608L19 17.9292L4.75 7.69608V29.25H2.375C1.02758 29.25 0 28.2208 0 26.875V3.125C0 2.45208 0.2565 1.85833 0.682417 1.434C1.10833 1.00333 1.70367 0.75 2.375 0.75H3.16667L19 12.2292L34.8333 0.75H35.625C36.2979 0.75 36.8917 1.0065 37.3176 1.434C37.7451 1.85833 38 2.45208 38 3.125Z" fill="white"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/social-reddit.svg b/packages/website/ts/icons/illustrations/social-reddit.svg deleted file mode 100644 index b93510b36..000000000 --- a/packages/website/ts/icons/illustrations/social-reddit.svg +++ /dev/null @@ -1,3 +0,0 @@ -<svg width="50" height="41" viewBox="0 0 50 41" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M4.49975 24.6813C4.37725 25.2447 4.31396 25.8246 4.31396 26.4105C4.31396 33.4398 13.3012 39.1687 24.3505 39.1687C35.3957 39.1687 44.383 33.4439 44.383 26.4105C44.383 25.8511 44.3238 25.2958 44.2156 24.7588L44.1849 24.6935C44.1421 24.5812 44.1257 24.4689 44.1257 24.3566C43.5092 21.9577 41.8452 19.7813 39.4382 18.0215C39.3463 17.9888 39.2585 17.9418 39.1809 17.8785C39.1278 17.8377 39.089 17.7928 39.0441 17.7479C35.3855 15.2285 30.1508 13.6483 24.3526 13.6483C18.6054 13.6483 13.4217 15.1979 9.76307 17.6723C9.73449 17.7091 9.70386 17.7397 9.66303 17.7724C9.58341 17.8398 9.49154 17.8949 9.39762 17.9255C6.93542 19.6854 5.22861 21.8801 4.59162 24.3015C4.59162 24.4199 4.56304 24.5343 4.51608 24.6506L4.49975 24.6813ZM24.4526 35.7898C20.7899 35.7898 18.2113 34.9956 16.5658 33.3459C16.2126 32.9907 16.2126 32.4129 16.5658 32.0556C16.9251 31.7188 17.5049 31.7188 17.8622 32.0556C19.1484 33.3398 21.3024 33.9809 24.4526 33.9809C27.6008 33.9809 29.7425 33.3684 31.0246 32.0842C31.3615 31.7494 31.9433 31.7494 32.3088 32.0842C32.6457 32.4517 32.6457 33.0336 32.3088 33.4011C30.6571 35.0507 28.0928 35.8469 24.424 35.8469L24.4526 35.7898ZM17.0905 20.3285C15.2244 20.3285 13.6667 21.8903 13.6667 23.7523C13.6667 25.6102 15.2244 27.121 17.0905 27.121C18.9565 27.121 20.4612 25.6102 20.4612 23.7523C20.4612 21.8903 18.9524 20.3285 17.0905 20.3285ZM31.8576 20.3285C29.9915 20.3285 28.4317 21.8903 28.4317 23.7523C28.4317 25.6102 29.9915 27.121 31.8576 27.121C33.7236 27.121 35.2283 25.6102 35.2283 23.7523C35.2283 21.8903 33.7196 20.3285 31.8576 20.3285ZM41.1429 17.0721C43.2601 18.7728 44.8178 20.7899 45.612 23.001C46.5308 22.315 47.08 21.237 47.08 20.0427C47.08 17.997 45.416 16.3351 43.3683 16.3351C42.5537 16.3351 41.7799 16.5984 41.1429 17.0762V17.0721ZM5.53486 16.3392C3.4871 16.3392 1.82522 18.0051 1.82522 20.0508C1.82522 21.1594 2.31317 22.1905 3.14003 22.8867C3.95872 20.6837 5.53282 18.6952 7.65815 17.0149C7.04158 16.5862 6.30455 16.3432 5.5369 16.3432V16.3392H5.53486ZM24.3526 41C12.2947 41 2.48875 34.4566 2.48875 26.4187C2.48875 25.8572 2.5357 25.308 2.62758 24.767C1.00856 23.7605 0 21.9863 0 20.0427C0 16.9884 2.50508 14.5037 5.56344 14.5037C6.9395 14.5037 8.22368 15.006 9.23225 15.8961C13.0215 13.4645 18.1276 11.9333 23.7523 11.8292L27.4517 0.55124L28.2766 0.745195C28.2766 0.745195 28.3092 0.745194 28.3092 0.749278L36.931 2.77662C37.6334 1.1474 39.2544 0 41.147 0C43.6562 0 45.7019 2.0498 45.7019 4.561C45.7019 7.07629 43.6541 9.122 41.147 9.122C38.6399 9.122 36.5942 7.0722 36.5942 4.56917L28.7318 2.7072L25.7368 11.8476C31.1471 12.0619 36.0409 13.5911 39.7097 15.9737C40.7183 15.0264 42.0453 14.5058 43.452 14.5058C46.5104 14.5058 49.0011 16.9823 49.0011 20.0406C49.0011 22.0557 47.8987 23.8911 46.1878 24.8691C46.247 25.3897 46.3082 25.8777 46.3082 26.3983C46.2776 34.4382 36.4962 40.9816 24.422 40.9816L24.3526 41ZM41.051 1.82726C39.5402 1.82726 38.3153 3.05019 38.3153 4.55896C38.3153 6.06568 39.5402 7.29474 41.051 7.29474C42.5455 7.29474 43.7664 6.06976 43.7664 4.57121C43.7664 3.07469 42.5455 1.85176 41.0163 1.85176L41.051 1.82726Z" fill="white"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/social-twitter.svg b/packages/website/ts/icons/illustrations/social-twitter.svg deleted file mode 100644 index bc8e2f7d7..000000000 --- a/packages/website/ts/icons/illustrations/social-twitter.svg +++ /dev/null @@ -1,3 +0,0 @@ -<svg width="45" height="36" viewBox="0 0 45 36" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M44.8202 4.28708C43.1869 5.00497 41.4429 5.49403 39.6067 5.71733C41.478 4.58974 42.9175 2.81253 43.5985 0.692059C41.8434 1.71631 39.8983 2.46189 37.8276 2.87712C36.1741 1.10729 33.8174 0 31.2005 0C26.1863 0 22.1206 4.06562 22.1206 9.07428C22.1206 9.79402 22.2037 10.4861 22.355 11.1486C14.807 10.7924 8.11705 7.16789 3.63989 1.68862C2.85186 3.02107 2.41079 4.56944 2.41079 6.25622C2.41079 9.41201 4.01637 12.1858 6.44872 13.8153C4.95941 13.7674 3.55869 13.3577 2.33697 12.6785V12.7911C2.33697 17.1926 5.46139 20.8633 9.61928 21.6993C8.85709 21.9041 8.05246 22.0149 7.22752 22.0149C6.64804 22.0149 6.09255 21.9595 5.53705 21.8562C6.70156 25.4604 10.0493 28.0884 14.0337 28.1622C10.9333 30.5964 7.00422 32.047 2.77251 32.047C2.05276 32.047 1.33487 32.0045 0.613281 31.9233C4.65306 34.4959 9.41258 36 14.5597 36C31.2687 36 40.3947 22.1662 40.3947 10.189C40.3947 9.80325 40.3947 9.41385 40.367 9.0263C42.1405 7.75475 43.6889 6.14733 44.9069 4.32399L44.8202 4.28708Z" fill="white"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/stableTokens.svg b/packages/website/ts/icons/illustrations/stableTokens.svg deleted file mode 100755 index 9e854b0e6..000000000 --- a/packages/website/ts/icons/illustrations/stableTokens.svg +++ /dev/null @@ -1,10 +0,0 @@ -<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> -<circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> -<path d="M32 96H119M32 96V85H119V96M32 96H36V106.5H48M103 142V106.5M48 142V106.5M119 96H115V106.5H103M103 106.5H92.25M48 106.5H58.75M75.5 106.5V148M75.5 106.5H58.75M75.5 106.5H92.25M58.75 106.5V146M92.25 106.5V146" stroke="#00AE99" stroke-width="3"/> -<path d="M75.3265 76.5343C93.1472 76.5343 107.594 62.0878 107.594 44.2672C107.594 26.4465 93.1472 12 75.3265 12C57.5058 12 43.0593 26.4465 43.0593 44.2672C43.0593 62.0878 57.5058 76.5343 75.3265 76.5343Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M66.4197 57.1739V58.6739H67.9197H85.2999H86.7999V57.1739V52.1138V50.6138H85.2999H81.0799V29.0134V27.5134H79.5799H74.0798H73.6189L73.2375 27.7722L67.0774 31.9523L66.4197 32.3986V33.1935V39.2803V42.1109L68.7619 40.5215L72.5798 37.9308V50.6138H67.9197H66.4197V52.1138V57.1739Z" stroke="#00AE99" stroke-width="3"/> -<path d="M43.0593 44.0473C49.7328 42.9472 54.8662 37.2271 54.8662 30.187C54.8662 27.0337 53.8395 24.1736 52.0795 21.8269C46.5794 27.6203 43.1327 35.4671 43.0593 44.0473Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M43.0593 44.4871C43.1327 53.1405 46.5794 60.914 52.0795 66.7074C53.8395 64.3607 54.8662 61.5007 54.8662 58.3473C54.8662 51.3072 49.7328 45.5137 43.0593 44.4871Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M107.594 44.0473C100.92 42.9472 95.7869 37.2271 95.7869 30.187C95.7869 27.0337 96.8135 24.1736 98.5736 21.8269C104.074 27.6203 107.52 35.4671 107.594 44.0473Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M107.594 44.4871C107.52 53.1405 104.074 60.914 98.5736 66.7074C96.8135 64.3607 95.7869 61.5007 95.7869 58.3473C95.7869 51.3072 100.92 45.5137 107.594 44.4871Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/standardForExchange.svg b/packages/website/ts/icons/illustrations/standardForExchange.svg deleted file mode 100755 index f8075ed6d..000000000 --- a/packages/website/ts/icons/illustrations/standardForExchange.svg +++ /dev/null @@ -1,12 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g clip-path="url(#clip0)"> -<path d="M2 45C2 68.7579 21.2421 88 45 88C68.7579 88 88 68.7579 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M30 21L2 45L30 69V56.5H59.5V69L88 45L59.5 21V34H30V21Z" stroke="#00AE99" stroke-width="3"/> -<path d="M45 1V89" stroke="#00AE99" stroke-width="3"/> -</g> -<defs> -<clipPath id="clip0"> -<rect width="90" height="90" fill="white"/> -</clipPath> -</defs> -</svg> diff --git a/packages/website/ts/icons/illustrations/support.svg b/packages/website/ts/icons/illustrations/support.svg deleted file mode 100644 index 368e7cc02..000000000 --- a/packages/website/ts/icons/illustrations/support.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="152" height="152" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M76 151c41.421 0 75-33.579 75-75S117.421 1 76 1 1 34.579 1 76s33.579 75 75 75z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M114.869 14.138H38.226v124.818h76.643V14.138z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M101.73 26.189H51.365v100.73h50.365V26.189z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M76.547 76.554c13.908 0 25.183-11.275 25.183-25.183 0-13.907-11.275-25.182-25.183-25.182-13.907 0-25.182 11.275-25.182 25.182 0 13.908 11.275 25.183 25.182 25.183zM76.547 126.919c13.908 0 25.183-11.274 25.183-25.182S90.455 76.554 76.547 76.554c-13.907 0-25.182 11.275-25.182 25.183s11.275 25.182 25.182 25.182z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/icons/illustrations/supportForAllEthereumStandards-large.svg b/packages/website/ts/icons/illustrations/supportForAllEthereumStandards-large.svg deleted file mode 100755 index 1f840204a..000000000 --- a/packages/website/ts/icons/illustrations/supportForAllEthereumStandards-large.svg +++ /dev/null @@ -1,28 +0,0 @@ -<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g clip-path="url(#clip0)"> -<path d="M192.122 112.755C221.878 112.755 246 88.6333 246 58.8776C246 29.1218 221.878 5 192.122 5C162.367 5 138.245 29.1218 138.245 58.8776C138.245 88.6333 162.367 112.755 192.122 112.755Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M206.229 18.0288V31.3513H219.551" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M219.551 31.3511V72.494H183.012V18.0287H206.229L219.551 31.3511Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M178.016 99.7268V86.4043H164.694" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M164.694 86.4045V45.2616H201.233V99.7269H178.016L164.694 86.4045Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M59.8776 114.323C89.6333 114.323 113.755 90.2008 113.755 60.445C113.755 30.6893 89.6333 6.56747 59.8776 6.56747C30.1218 6.56747 6 30.6893 6 60.445C6 90.2008 30.1218 114.323 59.8776 114.323Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M59.8775 114.224C89.5786 114.224 113.656 90.1464 113.656 60.4453C113.656 30.7442 89.5786 6.66666 59.8775 6.66666C30.1764 6.66666 6.09888 30.7442 6.09888 60.4453C6.09888 90.1464 30.1764 114.224 59.8775 114.224Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M46.0329 81.9563V83.4563H47.5329H76.5H78V81.9563V73.5229V72.0229H76.5H68.4665V35.0223V33.5223H66.9665H57.7997H57.3388L56.9574 33.7811L46.6906 40.7478L46.0329 41.1942V41.9891V52.1337V54.9643L48.3751 53.3749L56.2997 47.9975V72.0229H47.5329H46.0329V73.5229V81.9563Z" stroke="#00AE99" stroke-width="3"/> -<path d="M6.09889 60.0786C17.2213 58.2452 25.777 48.7118 25.777 36.9782C25.777 31.7226 24.0658 26.9559 21.1325 23.0447C11.9656 32.7004 6.22112 45.7784 6.09889 60.0786Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M6.09889 60.8116C6.22112 75.2341 11.9656 88.1898 21.1325 97.8456C24.0658 93.9344 25.777 89.1676 25.777 83.912C25.777 72.1785 17.2213 62.5228 6.09889 60.8116Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M113.656 60.0786C102.534 58.2452 93.9781 48.7118 93.9781 36.9782C93.9781 31.7226 95.6892 26.9559 98.6226 23.0447C107.789 32.7004 113.534 45.7784 113.656 60.0786Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M113.656 60.8117C113.534 75.2342 107.789 88.1899 98.6226 97.8456C95.6892 93.9345 93.9781 89.1677 93.9781 83.9121C93.9781 72.1786 102.534 62.5229 113.656 60.8117Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M59.8776 246.567C89.6333 246.567 113.755 222.446 113.755 192.69C113.755 162.934 89.6333 138.812 59.8776 138.812C30.1218 138.812 6 162.934 6 192.69C6 222.446 30.1218 246.567 59.8776 246.567Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M59.8776 246.567C89.6333 246.567 113.755 222.446 113.755 192.69C113.755 162.934 89.6333 138.812 59.8776 138.812C30.1218 138.812 6 162.934 6 192.69C6 222.446 30.1218 246.567 59.8776 246.567Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M65.3633 189.944V158.303H69.8695V149.389H49.8858V158.303H54.3919V189.944C44.1062 192.393 36.4654 201.699 36.4654 212.67C36.4654 225.601 46.947 236.083 59.8776 236.083C72.8082 236.083 83.2899 225.601 83.2899 212.67C83.2899 201.601 75.6491 192.393 65.3633 189.944Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M69.8694 149.294H49.8857V158.208H69.8694V149.294Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M40.3837 199.547H79.2735" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M192.122 246.567C221.878 246.567 246 222.446 246 192.69C246 162.934 221.878 138.812 192.122 138.812C162.367 138.812 138.245 162.934 138.245 192.69C138.245 222.446 162.367 246.567 192.122 246.567Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M191.833 156.667L159.333 200.422H191.833L191.923 228.333L224.333 184.489H191.833V156.667Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</g> -<defs> -<clipPath id="clip0"> -<rect width="250" height="250" fill="white"/> -</clipPath> -</defs> -</svg> diff --git a/packages/website/ts/icons/illustrations/supportForAllEthereumStandards.svg b/packages/website/ts/icons/illustrations/supportForAllEthereumStandards.svg deleted file mode 100755 index 32a4d8602..000000000 --- a/packages/website/ts/icons/illustrations/supportForAllEthereumStandards.svg +++ /dev/null @@ -1,21 +0,0 @@ -<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M152.898 90.2041C176.703 90.2041 196 70.9066 196 47.102C196 23.2974 176.703 4 152.898 4C129.093 4 109.796 23.2974 109.796 47.102C109.796 70.9066 129.093 90.2041 152.898 90.2041Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M164.183 14.423V25.081H174.841" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M174.841 25.0809V57.9952H145.61V14.4229H164.183L174.841 25.0809Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M141.613 79.7814V69.1234H130.955" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M130.955 69.1236V36.2093H160.186V79.7815H141.613L130.955 69.1236Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M47.102 91.4581C70.9066 91.4581 90.2041 72.1606 90.2041 48.356C90.2041 24.5514 70.9066 5.25398 47.102 5.25398C23.2974 5.25398 4 24.5514 4 48.356C4 72.1606 23.2974 91.4581 47.102 91.4581Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M47.102 91.3791C70.8629 91.3791 90.1249 72.1171 90.1249 48.3562C90.1249 24.5953 70.8629 5.33333 47.102 5.33333C23.3411 5.33333 4.0791 24.5953 4.0791 48.3562C4.0791 72.1171 23.3411 91.3791 47.102 91.3791Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M35.9761 65.5651V66.8151H37.2261H60.3998H61.6498V65.5651V58.8183V57.5683H60.3998H54.023V28.0178V26.7678H52.773H45.4395H45.0555L44.7377 26.9835L36.5242 32.5569L35.9761 32.9289V33.5913V41.7069V44.0658L37.928 42.7413L44.1895 38.4924V57.5683H37.2261H35.9761V58.8183V65.5651Z" stroke="#00AE99" stroke-width="2.5"/> -<path d="M4.0791 48.0629C12.977 46.5962 19.8216 38.9694 19.8216 29.5826C19.8216 25.3781 18.4527 21.5647 16.106 18.4357C8.77251 26.1603 4.17688 36.6227 4.0791 48.0629Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M4.0791 48.6493C4.17688 60.1873 8.77251 70.5519 16.106 78.2765C18.4527 75.1475 19.8216 71.3341 19.8216 67.1296C19.8216 57.7428 12.977 50.0182 4.0791 48.6493Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M90.1248 48.0629C81.2269 46.5962 74.3823 38.9694 74.3823 29.5826C74.3823 25.3781 75.7512 21.5647 78.0979 18.4357C85.4314 26.1603 90.027 36.6227 90.1248 48.0629Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M90.1248 48.6494C90.027 60.1874 85.4314 70.552 78.0979 78.2765C75.7512 75.1476 74.3823 71.3342 74.3823 67.1297C74.3823 57.7429 81.2269 50.0183 90.1248 48.6494Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M47.102 197.254C70.9066 197.254 90.2041 177.957 90.2041 154.152C90.2041 130.347 70.9066 111.05 47.102 111.05C23.2974 111.05 4 130.347 4 154.152C4 177.957 23.2974 197.254 47.102 197.254Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M47.102 197.254C70.9066 197.254 90.2041 177.957 90.2041 154.152C90.2041 130.347 70.9066 111.05 47.102 111.05C23.2974 111.05 4 130.347 4 154.152C4 177.957 23.2974 197.254 47.102 197.254Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M51.4904 151.955V126.642H55.0953V119.511H39.1084V126.642H42.7133V151.955C34.4847 153.914 28.3721 161.359 28.3721 170.136C28.3721 180.481 36.7574 188.866 47.1019 188.866C57.4464 188.866 65.8317 180.481 65.8317 170.136C65.8317 161.281 59.719 153.914 51.4904 151.955Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M55.0953 119.435H39.1084V126.566H55.0953V119.435Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M31.5068 159.638H62.6187" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M152.898 197.254C176.703 197.254 196 177.957 196 154.152C196 130.347 176.703 111.05 152.898 111.05C129.093 111.05 109.796 130.347 109.796 154.152C109.796 177.957 129.093 197.254 152.898 197.254Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -<path d="M152.667 125.333L126.667 160.338H152.667L152.738 182.667L178.667 147.591H152.667V125.333Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/techSupport.svg b/packages/website/ts/icons/illustrations/techSupport.svg deleted file mode 100755 index e52084f67..000000000 --- a/packages/website/ts/icons/illustrations/techSupport.svg +++ /dev/null @@ -1,13 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<circle cx="45" cy="45" r="43" stroke="#00AE99" stroke-width="3"/> -<circle cx="45" cy="45" r="26.5068" stroke="#00AE99" stroke-width="3"/> -<circle cx="45" cy="45" r="10.0137" stroke="#00AE99" stroke-width="3"/> -<path d="M88 45C88 49.5545 84.3079 53.2466 79.7534 53.2466C75.199 53.2466 71.5068 49.5545 71.5068 45" stroke="#00AE99" stroke-width="3"/> -<path d="M18.4932 45C18.4932 40.4455 14.801 36.7534 10.2466 36.7534C5.69212 36.7534 2 40.4455 2 45" stroke="#00AE99" stroke-width="3"/> -<path d="M37.9193 37.9193C34.6988 41.1397 29.4773 41.1397 26.2568 37.9193C23.0363 34.6988 23.0363 29.4773 26.2568 26.2568" stroke="#00AE99" stroke-width="3"/> -<path d="M63.7432 63.743C66.9637 60.5225 66.9637 55.3011 63.7432 52.0806C60.5227 48.8601 55.3013 48.8601 52.0808 52.0806" stroke="#00AE99" stroke-width="3"/> -<path d="M45 18.4932C49.5545 18.4932 53.2466 14.801 53.2466 10.2466C53.2466 5.69212 49.5545 2 45 2" stroke="#00AE99" stroke-width="3"/> -<path d="M45 88C40.4455 88 36.7534 84.3079 36.7534 79.7534C36.7534 75.199 40.4455 71.5068 45 71.5068" stroke="#00AE99" stroke-width="3"/> -<path d="M26.2568 63.7433C29.4773 66.9638 34.6988 66.9638 37.9193 63.7433C41.1397 60.5228 41.1397 55.3014 37.9193 52.0809" stroke="#00AE99" stroke-width="3"/> -<path d="M52.0808 37.9193C48.8603 34.6988 48.8603 29.4774 52.0808 26.2569C55.3013 23.0364 60.5227 23.0364 63.7432 26.2569" stroke="#00AE99" stroke-width="3"/> -</svg> diff --git a/packages/website/ts/icons/illustrations/tokens.svg b/packages/website/ts/icons/illustrations/tokens.svg deleted file mode 100644 index 966615265..000000000 --- a/packages/website/ts/icons/illustrations/tokens.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="249" height="251" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M192 112c30.376 0 55-24.624 55-55S222.376 2 192 2s-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M206.4 15.3v13.6H220" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M220 28.9v42h-37.3V15.3h23.7L220 28.9zM177.6 98.7V85.1H164" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M164 85.1v-42h37.3v55.6h-23.7L164 85.1zM57 113.6c30.376 0 55-24.624 55-55s-24.624-55-55-55-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M57 102.6c24.3 0 44-19.7 44-44s-19.7-44-44-44-44 19.7-44 44 19.7 44 44 44z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M45.4 76.2v1.5h26.7v-9.9h-7.8V36.3h-9.461l-.381.259-8.4 5.7-.658.446V54.63l2.342-1.589 6.058-4.11V67.8h-8.4V76.2z" stroke="#00AE99" stroke-width="3"/><path d="M13 58.3c9.1-1.5 16.1-9.3 16.1-18.9 0-4.3-1.4-8.2-3.8-11.4-7.5 7.9-12.2 18.6-12.3 30.3zM13 58.9c.1 11.8 4.8 22.4 12.3 30.3 2.4-3.2 3.8-7.1 3.8-11.4 0-9.6-7-17.5-16.1-18.9zM101 58.3c-9.1-1.5-16.1-9.3-16.1-18.9 0-4.3 1.4-8.2 3.8-11.4 7.5 7.9 12.2 18.6 12.3 30.3zM101 58.9c-.1 11.8-4.8 22.4-12.3 30.3-2.4-3.2-3.8-7.1-3.8-11.4 0-9.6 7-17.5 16.1-18.9zM57 248.6c30.376 0 55-24.624 55-55s-24.624-55-55-55-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M57 248.6c30.376 0 55-24.624 55-55s-24.624-55-55-55-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M62.6 190.8v-32.3h4.6v-9.1H46.8v9.1h4.6v32.3c-10.5 2.5-18.3 12-18.3 23.2 0 13.2 10.7 23.9 23.9 23.9s23.9-10.7 23.9-23.9c0-11.3-7.8-20.7-18.3-23.2z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M67.2 149.3H46.8v9.1h20.4v-9.1zM37.1 200.6h39.7M192 248.6c30.376 0 55-24.624 55-55s-24.624-55-55-55-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M192 149.6l-36.4 52.9H192l.1 35.1 36.3-53H192v-35z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/icons/illustrations/vcIntroductions.svg b/packages/website/ts/icons/illustrations/vcIntroductions.svg deleted file mode 100755 index 024cadab3..000000000 --- a/packages/website/ts/icons/illustrations/vcIntroductions.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M2 45C2 68.7578 21.2421 88 45 88C68.7579 88 88 68.7578 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> -<path d="M45 4L9 28H81L45 4Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M40 28L40 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M26 28L26 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M63 28L63 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M17 28L17 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M50 28L50 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M73 28L73 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -<path d="M12 72.5V71H78V72.5M71.5 79H18.5" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> -</svg> diff --git a/packages/website/ts/icons/logo-with-type.svg b/packages/website/ts/icons/logo-with-type.svg deleted file mode 100644 index 25abf149e..000000000 --- a/packages/website/ts/icons/logo-with-type.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="81" height="40" viewBox="0 0 81 40" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.402 25.28l3.105-3.212-3.86-5.209-4.915-6.954A19.904 19.904 0 0 0 0 20c0 6.1 2.732 11.562 7.04 15.23l6.239-4.408a12.796 12.796 0 0 1-4.877-5.541zM14.72 8.402l3.212 3.105 5.209-3.86 6.954-4.915A19.904 19.904 0 0 0 20 0C13.9 0 8.438 2.732 4.77 7.04l4.408 6.239a12.795 12.795 0 0 1 5.541-4.877zM28.493 17.932l3.86 5.209 4.915 6.954A19.904 19.904 0 0 0 40 20c0-6.1-2.732-11.562-7.04-15.23L26.72 9.178a12.796 12.796 0 0 1 4.877 5.541l-3.105 3.213zM35.23 32.96l-4.408-6.239a12.795 12.795 0 0 1-5.541 4.877l-3.213-3.105-5.209 3.86-6.954 4.915A19.904 19.904 0 0 0 20 40c6.1 0 11.562-2.732 15.23-7.04z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M51.726 19.689c0-6.471 2.704-9.689 6.912-9.689 4.19 0 6.947 3.27 6.947 9.689 0 6.418-2.758 9.671-6.947 9.671-4.19 0-6.912-3.253-6.912-9.671zm6.894-7.59c-3.04 0-4.543 2.815-4.543 7.607 0 2.256.336 4.005.972 5.282l5.975-12.085c-.69-.542-1.485-.804-2.404-.804zm-2.351 14.428c.672.507 1.45.77 2.369.77 3.04 0 4.578-2.834 4.578-7.59 0-2.204-.318-3.936-.972-5.247l-5.975 12.067zm24.377-10.93l-3.853 6.47L81 29.027h-2.581l-3.377-5.63h-.954l-3.447 5.63h-2.51l4.224-6.872-3.8-6.559h2.44l3.11 5.334h.973l3.182-5.334h2.386z" fill="#fff"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx deleted file mode 100644 index 7bb018d17..000000000 --- a/packages/website/ts/index.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import { MuiThemeProvider } from 'material-ui/styles'; -import * as React from 'react'; -import { render } from 'react-dom'; -import { Provider } from 'react-redux'; -import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'; -import { MetaTags } from 'ts/components/meta_tags'; -import { DocsHome } from 'ts/containers/docs_home'; -import { FAQ } from 'ts/containers/faq'; -import { NotFound } from 'ts/containers/not_found'; -import { Wiki } from 'ts/containers/wiki'; -import { createLazyComponent } from 'ts/lazy_component'; -import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; -import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage'; -import { store } from 'ts/redux/store'; -import { WebsiteLegacyPaths, WebsitePaths } from 'ts/types'; -import { muiTheme } from 'ts/utils/mui_theme'; - -// Next (new website) routes. We should rename them later -import { NextAboutJobs } from 'ts/pages/about/jobs'; -import { NextAboutMission } from 'ts/pages/about/mission'; -import { NextAboutPress } from 'ts/pages/about/press'; -import { NextAboutTeam } from 'ts/pages/about/team'; -import { NextEcosystem } from 'ts/pages/ecosystem'; -import { Next0xInstant } from 'ts/pages/instant'; -import { NextLanding } from 'ts/pages/landing'; -import { NextLaunchKit } from 'ts/pages/launch_kit'; -import { NextMarketMaker } from 'ts/pages/market_maker'; -import { NextWhy } from 'ts/pages/why'; - -// Check if we've introduced an update that requires us to clear the tradeHistory local storage entries -tradeHistoryStorage.clearIfRequired(); -trackedTokenStorage.clearIfRequired(); - -import 'less/all.less'; - -// We pass modulePromise returning lambda instead of module promise, -// cause we only want to import the module when the user navigates to the page. -// At the same time webpack statically parses for import() to determine bundle chunk split points -// so each lazy import needs it's own `import()` declaration. - -const LazyPortal = createLazyComponent('Portal', async () => - import(/* webpackChunkName: "portal" */ 'ts/containers/portal'), -); -const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'), -); -const LazyContractWrappersDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "contractWrapperDocs" */ 'ts/containers/contract_wrappers_documentation'), -); -const LazyMigrationsDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "migrationsDocs" */ 'ts/containers/migrations_documentation'), -); -const LazyOrderWatcherDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "orderWatcherDocs" */ 'ts/containers/order_watcher_documentation'), -); -const LazySmartContractsDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "smartContractDocs" */ 'ts/containers/smart_contracts_documentation'), -); -const LazyConnectDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "connectDocs" */ 'ts/containers/connect_documentation'), -); -const LazyWeb3WrapperDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "web3WrapperDocs" */ 'ts/containers/web3_wrapper_documentation'), -); -const LazySolCompilerDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "solCompilerDocs" */ 'ts/containers/sol_compiler_documentation'), -); -const LazyJSONSchemasDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "jsonSchemasDocs" */ 'ts/containers/json_schemas_documentation'), -); -const LazySolCoverageDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "solCoverageDocs" */ 'ts/containers/sol_coverage_documentation'), -); -const LazySolTraceDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "solTraceDocs" */ 'ts/containers/sol_trace_documentation'), -); -const LazySolProfilerDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "solProfilerDocs" */ 'ts/containers/sol_profiler_documentation'), -); -const LazySubprovidersDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "subproviderDocs" */ 'ts/containers/subproviders_documentation'), -); -const LazyOrderUtilsDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "orderUtilsDocs" */ 'ts/containers/order_utils_documentation'), -); -const LazyEthereumTypesDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "ethereumTypesDocs" */ 'ts/containers/ethereum_types_documentation'), -); -const LazyAssetBuyerDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "assetBuyerDocs" */ 'ts/containers/asset_buyer_documentation'), -); - -const DOCUMENT_TITLE = '0x: The Protocol for Trading Tokens'; -const DOCUMENT_DESCRIPTION = 'An Open Protocol For Decentralized Exchange On The Ethereum Blockchain'; - -render( - <div> - <MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} /> - <Router> - <div> - <MuiThemeProvider muiTheme={muiTheme}> - <Provider store={store}> - <div> - <Switch> - {/* Next (new site) routes */} - <Route exact={true} path="/" component={NextLanding as any} /> - <Route exact={true} path={WebsitePaths.Why} component={NextWhy as any} /> - <Route - exact={true} - path={WebsitePaths.MarketMaker} - component={NextMarketMaker as any} - /> - <Route exact={true} path={WebsitePaths.Instant} component={Next0xInstant as any} /> - <Route exact={true} path={WebsitePaths.LaunchKit} component={NextLaunchKit as any} /> - <Route exact={true} path={WebsitePaths.Ecosystem} component={NextEcosystem as any} /> - <Route - exact={true} - path={WebsitePaths.AboutMission} - component={NextAboutMission as any} - /> - <Route exact={true} path={WebsitePaths.AboutTeam} component={NextAboutTeam as any} /> - <Route exact={true} path={WebsitePaths.AboutPress} component={NextAboutPress as any} /> - <Route exact={true} path={WebsitePaths.AboutJobs} component={NextAboutJobs as any} /> - {/* - Note(ez): We remove/replace all old routes with next routes - once we're ready to put a ring on it. for now let's keep em there for reference - */} - <Redirect from="/otc" to={`${WebsitePaths.Portal}`} /> - <Route path={WebsitePaths.Portal} component={LazyPortal} /> - <Route path={WebsitePaths.FAQ} component={FAQ as any} /> - <Route path={WebsitePaths.Wiki} component={Wiki as any} /> - - <Route - path={`${WebsitePaths.ZeroExJs}/:version?`} - component={LazyZeroExJSDocumentation} - /> - <Route - path={`${WebsitePaths.ContractWrappers}/:version?`} - component={LazyContractWrappersDocumentation} - /> - <Route - path={`${WebsitePaths.Migrations}/:version?`} - component={LazyMigrationsDocumentation} - /> - <Route - path={`${WebsitePaths.OrderWatcher}/:version?`} - component={LazyOrderWatcherDocumentation} - /> - <Route - path={`${WebsitePaths.Connect}/:version?`} - component={LazyConnectDocumentation} - /> - <Route - path={`${WebsitePaths.SolCompiler}/:version?`} - component={LazySolCompilerDocumentation} - /> - <Route - path={`${WebsitePaths.SolCoverage}/:version?`} - component={LazySolCoverageDocumentation} - /> - <Route - path={`${WebsitePaths.SolTrace}/:version?`} - component={LazySolTraceDocumentation} - /> - <Route - path={`${WebsitePaths.SolProfiler}/:version?`} - component={LazySolProfilerDocumentation} - /> - <Route - path={`${WebsitePaths.JSONSchemas}/:version?`} - component={LazyJSONSchemasDocumentation} - /> - <Route - path={`${WebsitePaths.Subproviders}/:version?`} - component={LazySubprovidersDocumentation} - /> - <Route - path={`${WebsitePaths.OrderUtils}/:version?`} - component={LazyOrderUtilsDocumentation} - /> - <Route - path={`${WebsitePaths.Web3Wrapper}/:version?`} - component={LazyWeb3WrapperDocumentation} - /> - <Route - path={`${WebsitePaths.SmartContracts}/:version?`} - component={LazySmartContractsDocumentation} - /> - <Route - path={`${WebsitePaths.EthereumTypes}/:version?`} - component={LazyEthereumTypesDocumentation} - /> - <Route - path={`${WebsitePaths.AssetBuyer}/:version?`} - component={LazyAssetBuyerDocumentation} - /> - <Route path={WebsitePaths.Docs} component={DocsHome as any} /> - {/* Legacy endpoints */} - <Route - path={`${WebsiteLegacyPaths.ZeroExJs}/:version?`} - component={LazyZeroExJSDocumentation} - /> - <Route - path={`${WebsiteLegacyPaths.Web3Wrapper}/:version?`} - component={LazyWeb3WrapperDocumentation} - /> - <Route - path={`${WebsiteLegacyPaths.Deployer}/:version?`} - component={LazySolCompilerDocumentation} - /> - <Redirect from={WebsiteLegacyPaths.Jobs} to={WebsitePaths.AboutJobs} /> - <Redirect from={WebsitePaths.Careers} to={WebsitePaths.AboutJobs} /> - <Route component={NotFound as any} /> - </Switch> - </div> - </Provider> - </MuiThemeProvider> - </div> - </Router> - </div>, - document.getElementById('app'), -); diff --git a/packages/website/ts/lazy_component.tsx b/packages/website/ts/lazy_component.tsx deleted file mode 100644 index 9d3b9944a..000000000 --- a/packages/website/ts/lazy_component.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -interface LazyComponentProps { - reactComponentPromise: Promise<React.ComponentClass<any>>; - reactComponentProps: any; -} - -interface LazyComponentState { - component?: React.ComponentClass<any>; -} - -/** - * This component is used for rendering components that are lazily loaded from other chunks. - * Source: https://reacttraining.com/react-router/web/guides/code-splitting - */ -export class LazyComponent extends React.Component<LazyComponentProps, LazyComponentState> { - constructor(props: LazyComponentProps) { - super(props); - this.state = { - component: undefined, - }; - } - public componentWillMount(): void { - // tslint:disable-next-line:no-floating-promises - this._loadComponentFireAndForgetAsync(this.props); - } - public componentWillReceiveProps(nextProps: LazyComponentProps): void { - if (nextProps.reactComponentPromise !== this.props.reactComponentPromise) { - // tslint:disable-next-line:no-floating-promises - this._loadComponentFireAndForgetAsync(nextProps); - } - } - public render(): React.ReactNode { - return _.isUndefined(this.state.component) - ? null - : React.createElement(this.state.component, this.props.reactComponentProps); - } - private async _loadComponentFireAndForgetAsync(props: LazyComponentProps): Promise<void> { - const component = await props.reactComponentPromise; - this.setState({ - component, - }); - } -} - -/** - * [createLazyComponent description] - * @param componentName name of exported component - * @param lazyImport lambda returning module promise - * we pass a lambda because we only want to require a module if it's used - * @example `const LazyPortal = createLazyComponent('Portal', () => import<any>('ts/containers/portal'));`` - */ -export const createLazyComponent = (componentName: string, lazyImport: () => Promise<any>) => { - return (props: any) => { - const reactComponentPromise = (async (): Promise<React.ComponentClass<any>> => { - const mod = await lazyImport(); - const component = mod[componentName]; - if (_.isUndefined(component)) { - throw new Error(`Did not find exported component: ${componentName}`); - } - return component; - })(); - return <LazyComponent reactComponentPromise={reactComponentPromise} reactComponentProps={props} />; - }; -}; diff --git a/packages/website/ts/local_storage/local_storage.ts b/packages/website/ts/local_storage/local_storage.ts deleted file mode 100644 index 13d9ca401..000000000 --- a/packages/website/ts/local_storage/local_storage.ts +++ /dev/null @@ -1,45 +0,0 @@ -import * as _ from 'lodash'; - -export const localStorage = { - doesExist(): boolean { - return !!window.localStorage; - }, - getItemIfExists(key: string): string { - if (!localStorage.doesExist) { - return undefined; - } - const item = window.localStorage.getItem(key); - if (_.isNull(item) || item === 'undefined') { - return ''; - } - return item; - }, - setItem(key: string, value: string): void { - if (!localStorage.doesExist || _.isUndefined(value)) { - return; - } - window.localStorage.setItem(key, value); - }, - removeItem(key: string): void { - if (!localStorage.doesExist) { - return; - } - window.localStorage.removeItem(key); - }, - getObject(key: string): object | undefined { - const item = localStorage.getItemIfExists(key); - if (item) { - return JSON.parse(item); - } - return undefined; - }, - setObject(key: string, value: object): void { - localStorage.setItem(key, JSON.stringify(value)); - }, - getAllKeys(): string[] { - if (!localStorage.doesExist) { - return []; - } - return _.keys(window.localStorage); - }, -}; diff --git a/packages/website/ts/local_storage/state_storage.ts b/packages/website/ts/local_storage/state_storage.ts deleted file mode 100644 index 517784b5b..000000000 --- a/packages/website/ts/local_storage/state_storage.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { localStorage } from 'ts/local_storage/local_storage'; -import { INITIAL_STATE, State } from 'ts/redux/reducer'; - -const STORAGE_NAME = 'persistedState'; - -export const stateStorage = { - saveState(partialState: Partial<State>): void { - localStorage.setObject(STORAGE_NAME, partialState); - }, - getPersistedState(): Partial<State> { - return localStorage.getObject(STORAGE_NAME); - }, - getPersistedDefaultState(): State { - return { ...INITIAL_STATE, ...stateStorage.getPersistedState() }; - }, -}; diff --git a/packages/website/ts/local_storage/tracked_token_storage.ts b/packages/website/ts/local_storage/tracked_token_storage.ts deleted file mode 100644 index b1b579aef..000000000 --- a/packages/website/ts/local_storage/tracked_token_storage.ts +++ /dev/null @@ -1,71 +0,0 @@ -import * as _ from 'lodash'; -import { localStorage } from 'ts/local_storage/local_storage'; -import { Token, TokenByAddress, TrackedTokensByUserAddress } from 'ts/types'; -import { configs } from 'ts/utils/configs'; - -const TRACKED_TOKENS_KEY = 'trackedTokens'; -const TRACKED_TOKENS_CLEAR_KEY = 'lastClearTrackedTokensDate'; - -export const trackedTokenStorage = { - // Clear trackedTokens localStorage if we've updated the config variable in an update - // that introduced a backward incompatible change requiring the tracked tokens to be re-set - clearIfRequired(): void { - const lastClearFillDate = localStorage.getItemIfExists(TRACKED_TOKENS_CLEAR_KEY); - if (lastClearFillDate !== configs.LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE) { - localStorage.removeItem(TRACKED_TOKENS_KEY); - } - localStorage.setItem(TRACKED_TOKENS_CLEAR_KEY, configs.LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE); - }, - addTrackedTokenToUser(userAddress: string, networkId: number, token: Token): void { - const trackedTokensByUserAddress = trackedTokenStorage.getTrackedTokensByUserAddress(); - let trackedTokensByNetworkId = trackedTokensByUserAddress[userAddress]; - if (_.isUndefined(trackedTokensByNetworkId)) { - trackedTokensByNetworkId = {}; - } - const trackedTokens = !_.isUndefined(trackedTokensByNetworkId[networkId]) - ? trackedTokensByNetworkId[networkId] - : []; - trackedTokens.push(token); - trackedTokensByNetworkId[networkId] = trackedTokens; - trackedTokensByUserAddress[userAddress] = trackedTokensByNetworkId; - const trackedTokensByUserAddressJSONString = JSON.stringify(trackedTokensByUserAddress); - localStorage.setItem(TRACKED_TOKENS_KEY, trackedTokensByUserAddressJSONString); - }, - getTrackedTokensByUserAddress(): TrackedTokensByUserAddress { - const trackedTokensJSONString = localStorage.getItemIfExists(TRACKED_TOKENS_KEY); - if (_.isEmpty(trackedTokensJSONString)) { - return {}; - } - const trackedTokensByUserAddress = JSON.parse(trackedTokensJSONString); - return trackedTokensByUserAddress; - }, - getTrackedTokensByAddress(userAddress: string, networkId: number): TokenByAddress { - const trackedTokensByAddress: TokenByAddress = {}; - const trackedTokensJSONString = localStorage.getItemIfExists(TRACKED_TOKENS_KEY); - if (_.isEmpty(trackedTokensJSONString)) { - return trackedTokensByAddress; - } - const trackedTokensByUserAddress = JSON.parse(trackedTokensJSONString); - const trackedTokensByNetworkId = trackedTokensByUserAddress[userAddress]; - if (_.isUndefined(trackedTokensByNetworkId)) { - return trackedTokensByAddress; - } - const trackedTokens = trackedTokensByNetworkId[networkId]; - _.each(trackedTokens, (trackedToken: Token) => { - trackedTokensByAddress[trackedToken.address] = trackedToken; - }); - return trackedTokensByAddress; - }, - removeTrackedToken(userAddress: string, networkId: number, tokenAddress: string): void { - const trackedTokensByUserAddress = trackedTokenStorage.getTrackedTokensByUserAddress(); - const trackedTokensByNetworkId = trackedTokensByUserAddress[userAddress]; - const trackedTokens = trackedTokensByNetworkId[networkId]; - const remainingTrackedTokens = _.filter(trackedTokens, (token: Token) => { - return token.address !== tokenAddress; - }); - trackedTokensByNetworkId[networkId] = remainingTrackedTokens; - trackedTokensByUserAddress[userAddress] = trackedTokensByNetworkId; - const trackedTokensByUserAddressJSONString = JSON.stringify(trackedTokensByUserAddress); - localStorage.setItem(TRACKED_TOKENS_KEY, trackedTokensByUserAddressJSONString); - }, -}; diff --git a/packages/website/ts/local_storage/trade_history_storage.tsx b/packages/website/ts/local_storage/trade_history_storage.tsx deleted file mode 100644 index ef6a0a1aa..000000000 --- a/packages/website/ts/local_storage/trade_history_storage.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; -import { localStorage } from 'ts/local_storage/local_storage'; -import { Fill } from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; - -const FILLS_KEY = 'fills'; -const FILLS_LATEST_BLOCK = 'fillsLatestBlock'; -const FILL_CLEAR_KEY = 'lastClearFillDate'; - -export const tradeHistoryStorage = { - // Clear all fill related localStorage if we've updated the config variable in an update - // that introduced a backward incompatible change requiring the user to re-fetch the fills from - // the blockchain - clearIfRequired(): void { - const lastClearFillDate = localStorage.getItemIfExists(FILL_CLEAR_KEY); - if (lastClearFillDate !== configs.LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE) { - const localStorageKeys = localStorage.getAllKeys(); - _.each(localStorageKeys, key => { - if (_.startsWith(key, `${FILLS_KEY}-`) || _.startsWith(key, `${FILLS_LATEST_BLOCK}-`)) { - localStorage.removeItem(key); - } - }); - } - localStorage.setItem(FILL_CLEAR_KEY, configs.LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE); - }, - addFillToUser(userAddress: string, networkId: number, fill: Fill): void { - const fillsByHash = tradeHistoryStorage.getUserFillsByHash(userAddress, networkId); - const fillHash = tradeHistoryStorage._getFillHash(fill); - const doesFillExist = !_.isUndefined(fillsByHash[fillHash]); - if (doesFillExist) { - return; // noop - } - fillsByHash[fillHash] = fill; - const userFillsJSONString = JSON.stringify(fillsByHash); - const userFillsKey = tradeHistoryStorage._getUserFillsKey(userAddress, networkId); - localStorage.setItem(userFillsKey, userFillsJSONString); - }, - removeFillFromUser(userAddress: string, networkId: number, fill: Fill): void { - const fillsByHash = tradeHistoryStorage.getUserFillsByHash(userAddress, networkId); - const fillHash = tradeHistoryStorage._getFillHash(fill); - const doesFillExist = !_.isUndefined(fillsByHash[fillHash]); - if (!doesFillExist) { - return; // noop - } - delete fillsByHash[fillHash]; - const userFillsJSONString = JSON.stringify(fillsByHash); - const userFillsKey = tradeHistoryStorage._getUserFillsKey(userAddress, networkId); - localStorage.setItem(userFillsKey, userFillsJSONString); - }, - getUserFillsByHash(userAddress: string, networkId: number): { [fillHash: string]: Fill } { - const userFillsKey = tradeHistoryStorage._getUserFillsKey(userAddress, networkId); - const userFillsJSONString = localStorage.getItemIfExists(userFillsKey); - if (_.isEmpty(userFillsJSONString)) { - return {}; - } - const userFillsByHash = JSON.parse(userFillsJSONString); - _.each(userFillsByHash, fill => { - fill.paidMakerFee = new BigNumber(fill.paidMakerFee); - fill.paidTakerFee = new BigNumber(fill.paidTakerFee); - fill.filledTakerTokenAmount = new BigNumber(fill.filledTakerTokenAmount); - fill.filledMakerTokenAmount = new BigNumber(fill.filledMakerTokenAmount); - }); - return userFillsByHash; - }, - getFillsLatestBlock(userAddress: string, networkId: number): number { - const userFillsLatestBlockKey = tradeHistoryStorage._getFillsLatestBlockKey(userAddress, networkId); - const blockNumberStr = localStorage.getItemIfExists(userFillsLatestBlockKey); - if (_.isEmpty(blockNumberStr)) { - return constants.GENESIS_ORDER_BLOCK_BY_NETWORK_ID[networkId]; - } - const blockNumber = _.parseInt(blockNumberStr); - return blockNumber; - }, - setFillsLatestBlock(userAddress: string, networkId: number, blockNumber: number): void { - const userFillsLatestBlockKey = tradeHistoryStorage._getFillsLatestBlockKey(userAddress, networkId); - localStorage.setItem(userFillsLatestBlockKey, `${blockNumber}`); - }, - _getUserFillsKey(userAddress: string, networkId: number): string { - const userFillsKey = `${FILLS_KEY}-${userAddress}-${networkId}`; - return userFillsKey; - }, - _getFillsLatestBlockKey(userAddress: string, networkId: number): string { - const userFillsLatestBlockKey = `${FILLS_LATEST_BLOCK}-${userAddress}-${networkId}`; - return userFillsLatestBlockKey; - }, - _getFillHash(fill: Fill): string { - const fillJSON = JSON.stringify(fill); - const fillHash = ethUtil.sha256(fillJSON); - return fillHash.toString('hex'); - }, -}; diff --git a/packages/website/ts/pages/about/jobs.tsx b/packages/website/ts/pages/about/jobs.tsx deleted file mode 100644 index 85c25a75f..000000000 --- a/packages/website/ts/pages/about/jobs.tsx +++ /dev/null @@ -1,238 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; -import styled from 'styled-components'; - -import { AboutPageLayout } from 'ts/components/aboutPageLayout'; -import { Link } from 'ts/components/link'; -import { Column, FlexWrap, Section } from 'ts/components/newLayout'; -import { Heading, Paragraph } from 'ts/components/text'; -import { Container } from 'ts/components/ui/container'; -import { colors } from 'ts/style/colors'; -import { WebsiteBackendJobInfo } from 'ts/types'; -import { backendClient } from 'ts/utils/backend_client'; -import { constants } from 'ts/utils/constants'; - -const OPEN_POSITIONS_HASH = 'positions'; - -interface PositionProps { - title: string; - location: string; - href: string; -} - -interface PositionItemProps { - position: PositionProps; -} - -const Position: React.FunctionComponent<PositionItemProps> = (props: PositionItemProps) => { - const { position } = props; - return ( - <PositionWrap> - <StyledColumn width="50%"> - <Container position="relative" top="-3px" paddingRight="12px"> - <Heading asElement="h3" size="small" fontWeight="400" marginBottom="0"> - <a href={position.href} target="_blank"> - {position.title} - </a> - </Heading> - </Container> - </StyledColumn> - - <StyledColumn width="30%" padding="0 40px 0 0"> - <Paragraph isMuted={true} marginBottom="0"> - {position.location} - </Paragraph> - </StyledColumn> - - <StyledColumn width="20%"> - <Paragraph marginBottom="0" textAlign="right" color={colors.brandDark} fontWeight={400}> - <Link href={position.href} target="_blank"> - Apply - </Link> - </Paragraph> - </StyledColumn> - </PositionWrap> - ); -}; - -export interface NextAboutJobsProps {} -interface NextAboutJobsState { - jobInfos: WebsiteBackendJobInfo[]; -} - -export class NextAboutJobs extends React.Component<NextAboutJobsProps, NextAboutJobsState> { - private _isUnmounted: boolean; - private static _convertJobInfoToPositionProps(jobInfo: WebsiteBackendJobInfo): PositionProps { - return { - title: jobInfo.title, - location: jobInfo.office, - href: jobInfo.url, - }; - } - constructor(props: NextAboutJobsProps) { - super(props); - this.state = { - jobInfos: [], - }; - } - - public componentWillMount(): void { - // tslint:disable-next-line:no-floating-promises - this._fetchJobInfosAsync(); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - } - public render(): React.ReactNode { - const positions = this.state.jobInfos.map(jobInfo => NextAboutJobs._convertJobInfoToPositionProps(jobInfo)); - return ( - <AboutPageLayout - title="Join Us in Our Mission" - description={ - <> - <Paragraph size="medium"> - To create a tokenized world where all value can flow freely. - </Paragraph> - <Paragraph size="medium"> - We are growing an ecosystem of businesses and projects by solving difficult challenges to - make our technology intuitive, flexible, and accessible to all. Join us in building - infrastructure upon which the exchange of all assets will take place. - </Paragraph> - </> - } - linkLabel="Our mission and values" - href={constants.URL_MISSION_AND_VALUES_BLOG_POST} - > - <DocumentTitle title="Jobs at 0x" /> - <Section bgColor="#F3F6F4" isFlex={true} maxWidth="1170px" wrapWidth="100%"> - <Column maxWidth="442px"> - <Heading size="medium" marginBottom="30px"> - Powered by a Diverse, Global Community - </Heading> - - <Paragraph> - We're a highly technical team with varied backgrounds in engineering, science, business, - finance, and research. While the Core Team is headquartered in San Francisco, there are 30+ - teams building on 0x and hundreds of thousands of participants behind our efforts worldwide. - We're passionate about open-source software and decentralized technology's potential to act - as an equalizing force in the world. - </Paragraph> - </Column> - - <Column maxWidth="600px"> - <ImageWrap> - <img src="/images/jobs/map@2x.png" height="365" alt="Map of community" /> - </ImageWrap> - </Column> - </Section> - - <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> - <Column> - <Heading size="medium">Benefits</Heading> - </Column> - - <Column maxWidth="826px"> - <BenefitsList> - <li>Comprehensive Insurance</li> - <li>Unlimited Vacation</li> - <li>Meals and snacks provided daily</li> - <li>Flexible hours and liberal work-from-home-policy</li> - <li>Supportive of remote working</li> - <li>Transportation, phone, and wellness expense</li> - <li>Relocation assistance</li> - <li>Optional team excursions</li> - <li>Competitive salary</li> - <li>Cryptocurrency based compensation</li> - </BenefitsList> - </Column> - </Section> - - <Section id={OPEN_POSITIONS_HASH} isFlex={true} maxWidth="1170px" wrapWidth="100%"> - <Column> - <Heading size="medium"> - Current - <br /> - Openings - </Heading> - </Column> - - <Column maxWidth="826px"> - {_.map(positions, (position, index) => ( - <Position key={`position-${index}`} position={position} /> - ))} - </Column> - </Section> - </AboutPageLayout> - ); - } - private async _fetchJobInfosAsync(): Promise<void> { - try { - if (!this._isUnmounted) { - this.setState({ - jobInfos: [], - }); - } - const jobInfos = await backendClient.getJobInfosAsync(); - if (!this._isUnmounted) { - this.setState({ - jobInfos, - }); - } - } catch (error) { - if (!this._isUnmounted) { - this.setState({ - jobInfos: [], - }); - } - } - } -} - -const BenefitsList = styled.ul` - color: #000; - font-weight: 300; - line-height: 1.444444444; - list-style: disc; - columns: auto 2; - column-gap: 80px; - - li { - margin-bottom: 1em; - } -`; - -const ImageWrap = styled.figure` - @media (min-width: 768px) { - height: 600px; - padding-left: 60px; - display: flex; - align-items: flex-end; - } -`; - -const StyledColumn = styled(Column)` - flex-shrink: 0; - - @media (max-width: 768px) { - & + & { - margin-top: 15px; - } - } -`; - -const PositionWrap = styled(FlexWrap)` - margin-bottom: 40px; - padding-bottom: 30px; - position: relative; - - &:after { - content: ''; - width: 100%; - position: absolute; - bottom: 0; - left: 0; - height: 1px; - background-color: #e3e3e3; - } -`; diff --git a/packages/website/ts/pages/about/mission.tsx b/packages/website/ts/pages/about/mission.tsx deleted file mode 100644 index ab8949fae..000000000 --- a/packages/website/ts/pages/about/mission.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; -import styled from 'styled-components'; - -import { AboutPageLayout } from 'ts/components/aboutPageLayout'; -import { Definition } from 'ts/components/definition'; -import { Image } from 'ts/components/image'; -import { Column, Section } from 'ts/components/newLayout'; -import { Heading } from 'ts/components/text'; -import { constants } from 'ts/utils/constants'; - -const values = [ - { - title: 'Do The Right Thing', - description: - 'We acknowledge the broad subjectivity behind doing “the right thing,” and are committed to rigorously exploring its nuance in our decision making. We believe this responsibility drives our decision making above all else, and pledge to act in the best interest of our peers, community, and society as a whole.', - icon: 'right-thing', - }, - { - title: 'Consistently Ship', - description: - 'Achieving our mission requires dedication and diligence. We aspire to be an organization that consistently ships. We set high-impact goals that are rooted in data and pride ourselves in consistently outputting outstanding results across the organization.', - icon: 'consistently-ship', - }, - { - title: 'Focus on Long-term Impact', - description: - 'We anticipate that over time, awareness of the fundamentally disruptive nature of frictionless global exchange will cause some to see this technology as a threat. There will be setbacks, some will claim that this technology is too disruptive, and we will face adversity. Persistence and a healthy long-term focus will see us through these battles.', - icon: 'long-term-impact', - }, -]; - -export const NextAboutMission = () => ( - <AboutPageLayout - title="Creating a tokenized world where all value can flow freely." - description="0x is important infrastructure for the emerging crypto economy and enables markets to be created that couldn't have existed before. As more assets become tokenized, public blockchains provide the opportunity to establish a new financial stack that is more efficient, transparent, and equitable than any system in the past." - linkLabel="Our mission and values" - href={constants.URL_MISSION_AND_VALUES_BLOG_POST} - > - <DocumentTitle title="Our Mission - 0x" /> - <Section isFullWidth={true} isPadded={false}> - <FullWidthImage> - <Image src="/images/about/about-office.png" alt="0x Offices" isCentered={true} /> - </FullWidthImage> - </Section> - - <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> - <Column> - <Heading size="medium" maxWidth="226px"> - Core Values - </Heading> - </Column> - - <Column width="70%" maxWidth="826px"> - <Column width="100%" maxWidth="800px"> - {_.map(values, (item, index) => ( - <StyledDefinition - icon={item.icon} - title={item.title} - description={item.description} - isInlineIcon={true} - iconSize="large" - /> - ))} - </Column> - </Column> - </Section> - </AboutPageLayout> -); - -const StyledDefinition = styled(Definition)` - & + & { - margin-top: 30px; - padding-top: 30px; - border-top: 1px solid #eaeaea; - } -`; - -const FullWidthImage = styled.figure` - width: 100vw; - margin-left: calc(50% - 50vw); - - img { - width: 100%; - height: 100%; - object-fit: cover; - } - - @media (min-width: 768px) { - height: 500px; - } - - @media (max-width: 768px) { - height: 400px; - } -`; diff --git a/packages/website/ts/pages/about/press.tsx b/packages/website/ts/pages/about/press.tsx deleted file mode 100644 index 03003d656..000000000 --- a/packages/website/ts/pages/about/press.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; -import styled from 'styled-components'; - -import { AboutPageLayout } from 'ts/components/aboutPageLayout'; -import { Button } from 'ts/components/button'; -import { Column, FlexWrap } from 'ts/components/newLayout'; -import { Paragraph } from 'ts/components/text'; - -interface HighlightProps { - logo: string; - title?: string; - text: string; - href: string; -} - -interface HighlightItemProps { - highlight: HighlightProps; -} - -const highlights: HighlightProps[] = [ - { - logo: '/images/press/logo-forbes.png', - title: 'Forbes', - text: - '0x Instant is aiming to aid businesses and developers such as news sites, crypto wallets, dApps or price trackers to monetize or add a new revenue stream to their existing pipeline.', - href: - 'https://www.forbes.com/sites/rebeccacampbell1/2018/12/06/0x-launches-instant-delivers-an-easy-and-flexible-way-to-buy-crypto-tokens/#bfb73a843561', - }, - { - logo: '/images/press/logo-venturebeat.png', - title: 'VentureBeat', - text: '0x leads the way for ‘tokenization’ of the world, and collectible game items are next', - href: - 'https://venturebeat.com/2018/09/24/0x-leads-the-way-for-tokenization-of-the-world-and-collectible-game-items-are-next/', - }, - { - logo: '/images/press/logo-fortune.png', - title: 'Fortune', - text: - 'In the future, many traditional investments like real estate and corporate shares will come in the form of digital tokens that are bought and transferred on a blockchain.', - href: 'http://fortune.com/2018/09/06/0x-harbor-blockchain/', - }, - { - logo: '/images/press/logo-techcrunch.png', - title: 'TechCrunch', - text: - '0x allows any developer to quickly build their own decentralized cryptocurrency exchange and decide their own fees.', - href: 'https://techcrunch.com/2018/07/16/0x/', - }, -]; - -export const NextAboutPress = () => ( - <AboutPageLayout - title="Press Highlights" - description={ - <> - <Paragraph size="medium" marginBottom="60px"> - Want to write about 0x? <a href="mailto:team@0xproject.com">Get in touch.</a> - </Paragraph> - - {_.map(highlights, (highlight, index) => ( - <Highlight key={`highlight-${index}`} highlight={highlight} /> - ))} - </> - } - > - <DocumentTitle title="Press Highlights - 0x" /> - </AboutPageLayout> -); - -export const Highlight: React.FunctionComponent<HighlightItemProps> = (props: HighlightItemProps) => { - const { highlight } = props; - return ( - <HighlightWrap> - <Column> - <img src={highlight.logo} alt={highlight.title} /> - </Column> - - <Column width="60%" maxWidth="560px"> - <Paragraph isMuted={false}>{highlight.text}</Paragraph> - <Button href={highlight.href} isWithArrow={true} isNoBorder={true} target="_blank"> - Read Article - </Button> - </Column> - </HighlightWrap> - ); -}; - -const HighlightWrap = styled(FlexWrap)` - border-top: 1px solid #eaeaea; - padding: 30px 0; -`; diff --git a/packages/website/ts/pages/about/team.tsx b/packages/website/ts/pages/about/team.tsx deleted file mode 100644 index 808fea049..000000000 --- a/packages/website/ts/pages/about/team.tsx +++ /dev/null @@ -1,296 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; -import styled from 'styled-components'; - -import { colors } from 'ts/style/colors'; - -import { AboutPageLayout } from 'ts/components/aboutPageLayout'; -import { Column, Section } from 'ts/components/newLayout'; -import { Heading, Paragraph } from 'ts/components/text'; -import { WebsitePaths } from 'ts/types'; - -interface TeamMember { - name: string; - title: string; - imageUrl?: string; -} - -const team: TeamMember[] = [ - { - imageUrl: '/images/team/willw.jpg', - name: 'Will Warren', - title: 'co-founder & CEO', - }, - { - imageUrl: '/images/team/amirb.jpg', - name: 'Amir Bandeali', - title: 'Co-founder & CTO', - }, - { - imageUrl: '/images/team/fabiob.jpg', - name: 'Fabio Berger', - title: 'engineering manager', - }, - { - imageUrl: '/images/team/alexv.jpg', - name: 'Alex Xu', - title: 'Director of operations', - }, - { - imageUrl: '/images/team/leonidL.jpg', - name: 'Leonid Logvinov', - title: 'engineer', - }, - { - imageUrl: '/images/team/benb.jpg', - name: 'Ben Burns', - title: 'designer', - }, - { - imageUrl: '/images/team/brandonm.jpg', - name: 'Brandon Millman', - title: 'senior engineer', - }, - { - imageUrl: '/images/team/toms.jpg', - name: 'Tom Schmidt', - title: 'product lead', - }, - { - imageUrl: '/images/team/jacobe.jpg', - name: 'Jacob Evans', - title: 'ecosystem engineer', - }, - { - imageUrl: '/images/team/blake.jpg', - name: 'Blake Henderson', - title: 'ecosystem programs lead', - }, - { - imageUrl: '/images/team/zack.jpg', - name: 'Zack Skelly', - title: 'lead recruiter', - }, - { - imageUrl: '/images/team/greg.jpg', - name: 'Greg Hysen', - title: 'blockchain engineer', - }, - { - imageUrl: '/images/team/remcoB.jpg', - name: 'Remco Bloemen', - title: 'technical fellow', - }, - { - imageUrl: '/images/team/francesco.jpg', - name: 'Francesco Agosti', - title: 'engineer', - }, - { - imageUrl: '/images/team/melo.jpg', - name: 'Mel Oberto', - title: 'people operations associate', - }, - { - imageUrl: '/images/team/alexb.jpg', - name: 'Alex Browne', - title: 'engineer in residence', - }, - { - imageUrl: '/images/team/peterz.jpg', - name: 'Peter Zeitz', - title: 'research fellow', - }, - { - imageUrl: '/images/team/chrisk.jpg', - name: 'Chris Kalani', - title: 'director of design', - }, - { - imageUrl: '/images/team/clayr.jpg', - name: 'Clay Robbins', - title: 'ecosystem development lead', - }, - { - imageUrl: '/images/team/mattt.jpg', - name: 'Matt Taylor', - title: 'marketing lead', - }, - { - imageUrl: '/images/team/eugenea.jpg', - name: 'Eugene Aumson', - title: 'engineer', - }, - { - imageUrl: '/images/team/weijew.jpg', - name: 'Weijie Wu', - title: 'research fellow', - }, - { - imageUrl: '/images/team/rahuls.jpg', - name: 'Rahul Singireddy', - title: 'relayer success manager', - }, - { - imageUrl: '/images/team/jasons.jpg', - name: 'Jason Somensatto', - title: 'strategic legal counsel', - }, - { - imageUrl: '/images/team/steveK.jpg', - name: 'Steve Klebanoff', - title: 'senior engineer', - }, - { - imageUrl: '/images/team/xianny.jpg', - name: 'Xianny Ng', - title: 'engineer', - }, - { - imageUrl: '/images/team/oshirob.png', - name: 'Brent Oshiro', - title: 'community engagement lead', - }, - { - imageUrl: '/images/team/marcs.jpg', - name: 'Marc Savino', - title: 'technical sourcer', - }, -]; - -const advisors: TeamMember[] = [ - { - imageUrl: '/images/team/advisors/frede.jpg', - name: 'Fred Ehrsam', - title: 'Advisor', - }, - { - imageUrl: '/images/team/advisors/olafc.jpg', - name: 'Olaf Carlson-Wee', - title: 'Advisor', - }, - { - imageUrl: '/images/team/advisors/joeyk.jpg', - name: 'Joey Krug', - title: 'Advisor', - }, - { - imageUrl: '/images/team/advisors/lindax.jpg', - name: 'Linda Xie', - title: 'Advisor', - }, - { - imageUrl: '/images/team/advisors/davids.jpg', - name: 'David Sacks', - title: 'Advisor', - }, -]; - -export const NextAboutTeam = () => ( - <AboutPageLayout - title="We are a global, growing team" - description="We are a distributed team with backgrounds in engineering, academic research, business, and design. The 0x Core Team is passionate about accelerating the adoption decentralized technology and believe in its potential to be an equalizing force in the world. Join us and do the most impactful work of your life." - linkLabel="Join the team" - to={WebsitePaths.AboutJobs} - > - <DocumentTitle title="Our Team - 0x" /> - <Section maxWidth="1170px" wrapWidth="100%" isFlex={true} flexBreakpoint="900px"> - <Column> - <Heading size="medium">0x Team</Heading> - </Column> - - <Column width="70%" maxWidth="800px"> - <StyledGrid> - {_.map(team, (info: TeamMember, index: number) => ( - <Member key={`team-${index}`} name={info.name} title={info.title} imageUrl={info.imageUrl} /> - ))} - </StyledGrid> - </Column> - </Section> - - <Section bgColor="#F3F6F4" maxWidth="1170px" wrapWidth="100%" flexBreakpoint="900px" isFlex={true}> - <Column> - <Heading size="medium">Advisors</Heading> - </Column> - - <Column width="70%" maxWidth="800px"> - <StyledGrid> - {_.map(advisors, (info: TeamMember, index: number) => ( - <Member key={`advisor-${index}`} name={info.name} title={info.title} imageUrl={info.imageUrl} /> - ))} - </StyledGrid> - </Column> - </Section> - </AboutPageLayout> -); - -const StyledGrid = styled.div` - &:after { - content: ''; - clear: both; - } -`; - -const Member = ({ name, title, imageUrl }: TeamMember) => ( - <StyledMember> - <img src={imageUrl} alt={name} /> - <Name>{name}</Name> - <MemberTitle isMuted={0.5} size={14} style={{ textTransform: 'capitalize' }}> - {title} - </MemberTitle> - </StyledMember> -); - -const StyledMember = styled.div` - margin-bottom: 10px; - float: left; - width: calc(50% - 15px); - margin-right: 15px; - - @media (max-width: 600px) { - &:nth-child(2n + 1) { - clear: left; - } - } - - img, - svg { - width: 100%; - height: auto; - object-fit: contain; - margin-bottom: 10px; - } - - @media (min-width: 600px) { - width: calc(33.3333% - 30px); - margin-right: 20px; - - &:nth-child(3n + 1) { - clear: left; - } - } - - @media (min-width: 900px) { - width: calc(25% - 30px); - - &:nth-child(3n + 1) { - clear: none; - } - - &:nth-child(4n + 1) { - clear: left; - } - } -`; - -const Name = styled.h3` - color: ${colors.textDarkPrimary}; - font-size: 14px; - line-height: 1; - margin: 0; -`; - -const MemberTitle = styled(Paragraph)` - font-size: 14px; -`; diff --git a/packages/website/ts/pages/community.tsx b/packages/website/ts/pages/community.tsx deleted file mode 100644 index 7c02fed82..000000000 --- a/packages/website/ts/pages/community.tsx +++ /dev/null @@ -1,289 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import styled from 'styled-components'; - -import { colors } from 'ts/style/colors'; - -import { Banner } from 'ts/components/banner'; -import { Button } from 'ts/components/button'; -import { Icon } from 'ts/components/icon'; -import { ModalContact } from 'ts/components/modals/modal_contact'; -import { Column, Section, WrapGrid } from 'ts/components/newLayout'; -import { SiteWrap } from 'ts/components/siteWrap'; -import { Heading, Paragraph } from 'ts/components/text'; - -interface EventProps { - title: string; - date: string; - signupUrl: string; - imageUrl: string; -} - -interface CommunityLinkProps { - bgColor: string; - title?: string; - icon?: string; - url: string; -} - -const events: EventProps[] = [ - { - title: '0x London Meetup', - date: 'October 20th 2018', - imageUrl: '/images/events/london.jpg', - signupUrl: '#', - }, - { - title: '0x Berlin Meetup', - date: 'October 20th 2018', - imageUrl: '/images/events/berlin.jpg', - signupUrl: '#', - }, - { - title: '0x San Francisco Meetup', - date: 'October 20th 2018', - imageUrl: '/images/events/sf.jpg', - signupUrl: '#', - }, -]; -const communityLinks: CommunityLinkProps[] = [ - { - bgColor: '#1DA1F2', - title: 'Twitter', - icon: 'social-twitter', - url: 'https://twitter.com/0xProject', - }, - { - bgColor: '#FF4500', - title: 'Reddit', - icon: 'social-reddit', - url: 'https://twitter.com/0xProject', - }, - { - bgColor: '#7289DA', - title: 'Twitter', - icon: 'social-discord', - url: 'https://twitter.com/0xProject', - }, - { - bgColor: '#3B5998', - title: 'Facebook', - icon: 'social-fb', - url: 'https://twitter.com/0xProject', - }, - { - bgColor: '#181717', - title: 'GitHub', - icon: 'social-github', - url: 'https://twitter.com/0xProject', - }, - { - bgColor: '#003831', - title: 'Newsletter', - icon: 'social-newsletter', - url: 'https://twitter.com/0xProject', - }, -]; - -export class NextCommunity extends React.Component { - public state = { - isContactModalOpen: false, - }; - public render(): React.ReactNode { - return ( - <SiteWrap theme="light"> - <Section isTextCentered={true}> - <Column> - <Heading size="medium" isCentered={true}> - Community - </Heading> - <Paragraph size="medium" isCentered={true} isMuted={true} marginBottom="0"> - The 0x community is a global, passionate group of crypto developers and enthusiasts. The - official channels below provide a great forum for connecting and engaging with the - community. - </Paragraph> - <LinkWrap> - <Button to="#" isWithArrow={true} isAccentColor={true}> - Join the 0x community - </Button> - </LinkWrap> - </Column> - </Section> - - <Section isFullWidth={true}> - <WrapGrid - isTextCentered={true} - isWrapped={true} - isFullWidth={false} - isCentered={false} - maxWidth="1151px" - > - {_.map(communityLinks, (link: CommunityLinkProps, index: number) => ( - <CommunityLink - key={`cl-${index}`} - icon={link.icon} - title={link.title} - bgColor={link.bgColor} - url={link.url} - /> - ))} - </WrapGrid> - </Section> - - <EventsWrapper - bgColor={colors.backgroundLight} - isFullWidth={true} - isCentered={true} - isTextCentered={true} - > - <Column maxWidth="720px"> - <Heading size="medium" asElement="h2" isCentered={true} maxWidth="507px" marginBottom="30px"> - Upcoming Events - </Heading> - <Paragraph size="medium" isCentered={true} isMuted={true}> - 0x meetups happen all over the world on a monthly basis and are hosted by devoted members of - the community. Want to host a meetup in your city? Reach out for help finding a venue, - connecting with local 0x mentors, and promoting your events. - </Paragraph> - <LinkWrap> - <Button to="#" isWithArrow={true} isAccentColor={true}> - Get in Touch - </Button> - <Button to="#" isWithArrow={true} isAccentColor={true}> - Join Newsletter - </Button> - </LinkWrap> - </Column> - <WrapGrid - isTextCentered={true} - isWrapped={true} - isFullWidth={false} - isCentered={false} - maxWidth="1149px" - > - {_.map(events, (ev: EventProps, index: number) => ( - <Event - key={`event-${index}`} - title={ev.title} - date={ev.date} - signupUrl={ev.signupUrl} - imageUrl={ev.imageUrl} - /> - ))} - </WrapGrid> - </EventsWrapper> - - <Banner - heading="Ready to get started?" - subline="Dive into our docs, or contact us if needed" - mainCta={{ text: 'Get Started', href: '/docs' }} - secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} - /> - <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> - </SiteWrap> - ); - } - - public _onOpenContactModal = (): void => { - this.setState({ isContactModalOpen: true }); - }; - - public _onDismissContactModal = (): void => { - this.setState({ isContactModalOpen: false }); - }; -} - -const Event: React.FunctionComponent<EventProps> = (event: EventProps) => ( - <StyledEvent> - <EventIcon name="logo-mark" size={30} margin={0} /> - <EventImage src={event.imageUrl} alt="" /> - <EventContent> - <Heading color={colors.white} size="small" marginBottom="0"> - {event.title} - </Heading> - <Paragraph color={colors.white} isMuted={0.65}> - {event.date} - </Paragraph> - <Button color={colors.white} href={event.signupUrl} isWithArrow={true}> - Sign Up - </Button> - </EventContent> - </StyledEvent> -); - -const CommunityLink: React.FunctionComponent<CommunityLinkProps> = (props: CommunityLinkProps) => ( - <StyledCommunityLink bgColor={props.bgColor} href={props.url}> - <CommunityIcon name={props.icon} size={44} margin={0} /> - <CommunityTitle color={colors.white} isMuted={false} marginBottom="0"> - {props.title} - </CommunityTitle> - </StyledCommunityLink> -); - -// Events -const EventsWrapper = styled(Section)` - display: flex; - align-items: center; - flex-direction: column; -`; - -// Event -const StyledEvent = styled.div` - background-color: ${colors.brandDark}; - width: calc((100% / 3) - 30px); - text-align: left; - height: 424px; - margin-top: 130px; - position: relative; -`; - -const EventIcon = styled(Icon)` - position: absolute; - top: 30px; - left: 30px; -`; - -const EventImage = styled.img` - width: 100%; - height: 260px; - object-fit: cover; -`; - -const EventContent = styled.div` - padding: 30px 30px; -`; - -interface StyledCommunityLinkProps { - bgColor: string; -} -const StyledCommunityLink = styled.a` - background-color: ${(props: StyledCommunityLinkProps) => props.bgColor}; - color: ${colors.white}; - width: 175px; - height: 175px; - text-align: center; - position: relative; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -`; - -const CommunityTitle = styled(Paragraph)` - font-size: 20px; - font-weight: 400; -`; - -const CommunityIcon = styled(Icon)` - margin-bottom: 20px; -`; - -// Misc -const LinkWrap = styled.div` - display: inline-flex; - margin-top: 60px; - - a + a { - margin-left: 60px; - } -`; diff --git a/packages/website/ts/pages/documentation/developers_page.tsx b/packages/website/ts/pages/documentation/developers_page.tsx deleted file mode 100644 index 0b725c514..000000000 --- a/packages/website/ts/pages/documentation/developers_page.tsx +++ /dev/null @@ -1,201 +0,0 @@ -import { colors, constants as sharedConstants, utils as sharedUtils } from '@0x/react-shared'; -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'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { media } from 'ts/style/media'; -import { styled } from 'ts/style/theme'; -import { BrowserType, OperatingSystemType, ScreenWidths } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; -import { utils } from 'ts/utils/utils'; - -const THROTTLE_TIMEOUT = 100; -const TOP_BAR_HEIGHT = 80; -const browserType = utils.getBrowserType(); -let SCROLLBAR_WIDTH; -switch (browserType) { - case BrowserType.Firefox: - // HACK: Firefox doesn't allow styling of their scrollbar's. - // Source: https://stackoverflow.com/questions/6165472/custom-css-scrollbar-for-firefox - const os = utils.getOperatingSystem(); - SCROLLBAR_WIDTH = os === OperatingSystemType.Windows ? 17 : 15; - break; - - case BrowserType.Edge: - // Edge's scrollbar is placed outside of the div content and doesn't - // need to be accounted for - SCROLLBAR_WIDTH = 0; - break; - - default: - SCROLLBAR_WIDTH = 4; -} -const SIDEBAR_PADDING = 22; - -export interface DevelopersPageProps { - location: Location; - translate: Translate; - screenWidth: ScreenWidths; - dispatcher: Dispatcher; - mainContent: React.ReactNode; - sidebar: React.ReactNode; -} - -export interface DevelopersPageState { - isSidebarScrolling: boolean; -} - -const isUserOnMobile = sharedUtils.isUserOnMobile(); - -const scrollableContainerStyles = ` - position: absolute; - top: ${TOP_BAR_HEIGHT}px; - left: 0px; - bottom: 0px; - right: 0px; - overflow-x: hidden; - overflow-y: scroll; - -webkit-overflow-scrolling: touch; - /* Required for hide/show onHover of scrollbar on Microsoft Edge */ - -ms-overflow-style: -ms-autohiding-scrollbar; -`; - -interface SidebarContainerProps { - className?: string; -} - -const SidebarContainer = styled.div<SidebarContainerProps>` - ${scrollableContainerStyles} - padding-top: 27px; - padding-left: ${SIDEBAR_PADDING}px; - padding-right: ${SIDEBAR_PADDING}px; - overflow: hidden; - &:hover { - overflow: auto; - padding-right: ${SIDEBAR_PADDING - SCROLLBAR_WIDTH}px; - } -`; - -interface MainContentContainerProps { - className?: string; -} - -const MainContentContainer = styled.div<MainContentContainerProps>` - ${scrollableContainerStyles} - padding-top: 0px; - padding-left: 50px; - padding-right: 50px; - overflow: ${isUserOnMobile ? 'auto' : 'hidden'}; - &:hover { - padding-right: ${50 - SCROLLBAR_WIDTH}px; - overflow: auto; - } - ${media.small` - padding-left: 20px; - padding-right: 20px; - &:hover { - padding-right: ${20 - SCROLLBAR_WIDTH}px; - overflow: auto; - } - `} -`; - -export class DevelopersPage extends React.Component<DevelopersPageProps, DevelopersPageState> { - private readonly _throttledScreenWidthUpdate: () => void; - private readonly _throttledSidebarScrolling: () => void; - private _sidebarScrollClearingInterval: number; - constructor(props: DevelopersPageProps) { - super(props); - this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); - this._throttledSidebarScrolling = _.throttle(this._onSidebarScroll.bind(this), THROTTLE_TIMEOUT); - this.state = { - isSidebarScrolling: false, - }; - } - public componentDidMount(): void { - window.addEventListener('resize', this._throttledScreenWidthUpdate); - window.scrollTo(0, 0); - this._sidebarScrollClearingInterval = window.setInterval(() => { - this.setState({ - isSidebarScrolling: false, - }); - }, 1000); - } - public componentWillUnmount(): void { - window.removeEventListener('resize', this._throttledScreenWidthUpdate); - window.clearInterval(this._sidebarScrollClearingInterval); - } - public render(): React.ReactNode { - const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; - const mainContentPadding = isSmallScreen ? 20 : 50; - return ( - <Container - className="flex items-center overflow-hidden" - width="100%" - background={`linear-gradient(to right, ${colors.grey100} 0%, ${colors.grey100} 50%, ${ - colors.white - } 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" - width={270} - paddingLeft={22} - paddingRight={22} - paddingTop={0} - backgroundColor={colors.grey100} - > - <Container - borderBottom={this.state.isSidebarScrolling ? `1px solid ${colors.grey300}` : 'none'} - paddingBottom="2px" - > - <Container paddingTop="30px" paddingLeft="10px" paddingBottom="8px"> - <DocsLogo /> - </Container> - </Container> - <SidebarContainer onWheel={this._throttledSidebarScrolling}> - <Container paddingBottom="100px"> - {this.props.screenWidth !== ScreenWidths.Sm && this.props.sidebar} - </Container> - </SidebarContainer> - </Container> - <Container - className="relative" - width={isSmallScreen ? '100vw' : 786} - paddingBottom="100px" - backgroundColor={colors.white} - > - <Container paddingLeft={mainContentPadding} paddingRight={mainContentPadding}> - <DocsTopBar - location={this.props.location} - screenWidth={this.props.screenWidth} - translate={this.props.translate} - sidebar={this.props.sidebar} - /> - </Container> - <MainContentContainer id={sharedConstants.SCROLL_CONTAINER_ID}> - {this.props.mainContent} - </MainContentContainer> - </Container> - </Container> - </Container> - ); - } - private _onSidebarScroll(_event: React.FormEvent<HTMLInputElement>): void { - this.setState({ - isSidebarScrolling: true, - }); - } - private _updateScreenWidth(): void { - const newScreenWidth = utils.getScreenWidth(); - this.props.dispatcher.updateScreenWidth(newScreenWidth); - } -} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/pages/documentation/doc_page.tsx b/packages/website/ts/pages/documentation/doc_page.tsx deleted file mode 100644 index 14bad7329..000000000 --- a/packages/website/ts/pages/documentation/doc_page.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { - DocAgnosticFormat, - DocReference, - DocsInfo, - GeneratedDocJson, - SupportedDocJson, - TypeDocUtils, -} from '@0x/react-docs'; -import findVersions from 'find-versions'; -import * as _ from 'lodash'; -import CircularProgress from 'material-ui/CircularProgress'; -import * as React from 'react'; -import semverSort from 'semver-sort'; -import { SidebarHeader } from 'ts/components/documentation/sidebar_header'; -import { NestedSidebarMenu } from 'ts/components/nested_sidebar_menu'; -import { Container } from 'ts/components/ui/container'; -import { DevelopersPage } from 'ts/pages/documentation/developers_page'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { DocPackages, ScreenWidths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { docUtils } from 'ts/utils/doc_utils'; -import { Translate } from 'ts/utils/translate'; -import { utils } from 'ts/utils/utils'; - -const isDevelopmentOrStaging = utils.isDevelopment() || utils.isStaging(); -const ZERO_EX_JS_VERSION_MISSING_TOPLEVEL_PATH = '0.32.4'; - -const docIdToSubpackageName: { [id: string]: string } = { - [DocPackages.ZeroExJs]: '0x.js', - [DocPackages.Connect]: 'connect', - [DocPackages.SmartContracts]: 'contracts', - [DocPackages.Web3Wrapper]: 'web3-wrapper', - [DocPackages.ContractWrappers]: 'contract-wrappers', - [DocPackages.SolCompiler]: 'sol-compiler', - [DocPackages.JSONSchemas]: 'json-schemas', - [DocPackages.SolCoverage]: 'sol-coverage', - [DocPackages.SolProfiler]: 'sol-profiler', - [DocPackages.SolTrace]: 'sol-trace', - [DocPackages.Subproviders]: 'subproviders', - [DocPackages.OrderUtils]: 'order-utils', - [DocPackages.OrderWatcher]: 'order-watcher', - [DocPackages.EthereumTypes]: 'ethereum-types', - [DocPackages.AssetBuyer]: 'asset-buyer', - [DocPackages.Migrations]: 'migrations', -}; - -export interface DocPageProps { - location: Location; - dispatcher: Dispatcher; - docsVersion: string; - availableDocVersions: string[]; - docsInfo: DocsInfo; - translate: Translate; - screenWidth: ScreenWidths; -} - -interface DocPageState { - docAgnosticFormat?: DocAgnosticFormat; -} - -export class DocPage extends React.Component<DocPageProps, DocPageState> { - private _isUnmounted: boolean; - constructor(props: DocPageProps) { - super(props); - this._isUnmounted = false; - this.state = { - docAgnosticFormat: undefined, - }; - } - public componentWillMount(): void { - const pathName = this.props.location.pathname; - const lastSegment = pathName.substr(pathName.lastIndexOf('/') + 1); - const versions = findVersions(lastSegment); - const preferredVersionIfExists = versions.length > 0 ? versions[0] : undefined; - // tslint:disable-next-line:no-floating-promises - this._fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - } - public render(): React.ReactNode { - const sourceUrl = this._getSourceUrl(); - const sectionNameToLinks = _.isUndefined(this.state.docAgnosticFormat) - ? {} - : this.props.docsInfo.getSectionNameToLinks(this.state.docAgnosticFormat); - const mainContent = _.isUndefined(this.state.docAgnosticFormat) ? ( - <div className="flex justify-center">{this._renderLoading()}</div> - ) : ( - <DocReference - selectedVersion={this.props.docsVersion} - availableVersions={this.props.availableDocVersions} - docsInfo={this.props.docsInfo} - docAgnosticFormat={this.state.docAgnosticFormat} - sourceUrl={sourceUrl} - /> - ); - const sidebar = _.isUndefined(this.state.docAgnosticFormat) ? ( - <div /> - ) : ( - <NestedSidebarMenu - sidebarHeader={this._renderSidebarHeader()} - sectionNameToLinks={sectionNameToLinks} - screenWidth={this.props.screenWidth} - /> - ); - return ( - <DevelopersPage - sidebar={sidebar} - mainContent={mainContent} - location={this.props.location} - screenWidth={this.props.screenWidth} - translate={this.props.translate} - dispatcher={this.props.dispatcher} - /> - ); - } - private _renderSidebarHeader(): React.ReactNode { - return ( - <SidebarHeader - screenWidth={this.props.screenWidth} - title={this.props.docsInfo.displayName} - docsVersion={this.props.docsVersion} - availableDocVersions={this.props.availableDocVersions} - onVersionSelected={this._onVersionSelected.bind(this)} - /> - ); - } - private _renderLoading(): React.ReactNode { - return ( - <Container className="pt4"> - <Container className="center pb2"> - <CircularProgress size={40} thickness={5} /> - </Container> - <Container className="center pt2" paddingBottom="11px"> - Loading documentation... - </Container> - </Container> - ); - } - private async _fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists?: string): Promise<void> { - const folderName = docIdToSubpackageName[this.props.docsInfo.id]; - const docBucketRoot = isDevelopmentOrStaging - ? constants.S3_STAGING_DOC_BUCKET_ROOT - : constants.S3_DOC_BUCKET_ROOT; - const versionToFilePath = await docUtils.getVersionToFilePathAsync(docBucketRoot, folderName); - const versions = _.keys(versionToFilePath); - this.props.dispatcher.updateAvailableDocVersions(versions); - const sortedVersions = semverSort.desc(versions); - const latestVersion = sortedVersions[0]; - - let versionToFetch = latestVersion; - if (!_.isUndefined(preferredVersionIfExists)) { - const preferredVersionFileNameIfExists = versionToFilePath[preferredVersionIfExists]; - if (!_.isUndefined(preferredVersionFileNameIfExists)) { - versionToFetch = preferredVersionIfExists; - } - } - this.props.dispatcher.updateCurrentDocsVersion(versionToFetch); - - const versionFilePathToFetch = versionToFilePath[versionToFetch]; - const versionDocObj = await docUtils.getJSONDocFileAsync(versionFilePathToFetch, docBucketRoot); - let docAgnosticFormat; - if (this.props.docsInfo.type === SupportedDocJson.TypeDoc) { - docAgnosticFormat = new TypeDocUtils( - versionDocObj as GeneratedDocJson, - this.props.docsInfo, - ).convertToDocAgnosticFormat(); - } else if (this.props.docsInfo.type === SupportedDocJson.SolDoc) { - // documenting solidity. - docAgnosticFormat = versionDocObj as DocAgnosticFormat; - // HACK: need to modify docsInfo like convertToDocAgnosticFormat() would do - this.props.docsInfo.markdownMenu.Contracts = []; - _.each(docAgnosticFormat, (_docObj, sectionName) => { - this.props.docsInfo.sections[sectionName] = sectionName; - this.props.docsInfo.markdownMenu.Contracts.push(sectionName); - }); - } - - if (!this._isUnmounted) { - this.setState({ - docAgnosticFormat, - }); - } - } - private _getSourceUrl(): string { - const url = this.props.docsInfo.packageUrl; - let pkg = docIdToSubpackageName[this.props.docsInfo.id]; - let tagPrefix = pkg; - const packagesWithNamespace = ['connect']; - if (_.includes(packagesWithNamespace, pkg)) { - tagPrefix = `@0x/${pkg}`; - } - // HACK: The following three lines exist for backward compatibility reasons - // Before exporting types from other packages as part of the 0x.js interface, - // all TypeDoc generated paths omitted the topLevel `0x.js` segment. Now it - // adds it, and for that reason, we need to make sure we don't add it twice in - // the source links we generate. - const semvers = semverSort.desc([this.props.docsVersion, ZERO_EX_JS_VERSION_MISSING_TOPLEVEL_PATH]); - const isVersionAfterTopLevelPathChange = semvers[0] !== ZERO_EX_JS_VERSION_MISSING_TOPLEVEL_PATH; - pkg = this.props.docsInfo.id === DocPackages.ZeroExJs && isVersionAfterTopLevelPathChange ? '' : `/${pkg}`; - - const sourceUrl = `${url}/blob/${tagPrefix}%40${this.props.docsVersion}/packages${pkg}`; - return sourceUrl; - } - private _onVersionSelected(semver: string): void { - let path = window.location.pathname; - const lastChar = path[path.length - 1]; - if (_.isFinite(_.parseInt(lastChar))) { - const pathSections = path.split('/'); - pathSections.pop(); - path = pathSections.join('/'); - } - const baseUrl = utils.getCurrentBaseUrl(); - window.location.href = `${baseUrl}${path}/${semver}${window.location.hash}`; - } -} diff --git a/packages/website/ts/pages/documentation/docs_home.tsx b/packages/website/ts/pages/documentation/docs_home.tsx deleted file mode 100644 index 219903147..000000000 --- a/packages/website/ts/pages/documentation/docs_home.tsx +++ /dev/null @@ -1,498 +0,0 @@ -import { ALink, colors, Link } from '@0x/react-shared'; -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { OverviewContent } from 'ts/components/documentation/overview_content'; -import { NestedSidebarMenu } from 'ts/components/nested_sidebar_menu'; -import { Button } from 'ts/components/ui/button'; -import { DevelopersPage } from 'ts/pages/documentation/developers_page'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { Categories, Deco, Key, Package, ScreenWidths, TutorialInfo, WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -const TUTORIALS: TutorialInfo[] = [ - { - iconUrl: '/images/developers/tutorials/develop_on_ethereum.svg', - description: Key.DevelopOnEthereumDescription, - link: { - title: Key.DevelopOnEthereum, - to: `${WebsitePaths.Wiki}#Ethereum-Development`, - }, - }, - { - iconUrl: '/images/developers/tutorials/build_a_relayer.svg', - description: Key.BuildARelayerDescription, - link: { - title: Key.BuildARelayer, - to: `${WebsitePaths.Wiki}#Build-A-Relayer`, - }, - }, - { - iconUrl: '/images/developers/tutorials/0x_order_basics.svg', - description: Key.OrderBasicsDescription, - link: { - title: Key.OrderBasics, - to: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`, - }, - }, - { - iconUrl: '/images/developers/tutorials/use_shared_liquidity.svg', - description: Key.UseNetworkedLiquidityDescription, - link: { - title: Key.UseNetworkedLiquidity, - to: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`, - }, - }, - { - iconUrl: '/images/developers/tutorials/integrate_0x_instant.svg', - description: Key.Integrate0xInstantDescription, - link: { - title: Key.Integrate0xInstant, - to: `${WebsitePaths.Wiki}#Get-Started-With-Instant`, - }, - }, -]; - -const CATEGORY_TO_PACKAGES: ObjectMap<Package[]> = { - [Categories.ZeroExProtocolTypescript]: [ - { - description: - 'A library for interacting with the 0x protocol. It is a high level package which combines a number of smaller specific-purpose packages such as [order-utils](https://0x.org/docs/order-utils) and [contract-wrappers](https://0x.org/docs/contract-wrappers).', - link: { - title: '0x.js', - to: WebsitePaths.ZeroExJs, - }, - }, - { - description: - 'A Typescript starter project that will walk you through the basics of how to interact with 0x Protocol and trade of an SRA relayer', - link: { - title: '0x starter project', - to: 'https://github.com/0xProject/0x-starter-project', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'Launch a 0x relayer in under a minute with Launch Kit. `0x-launch-kit` is an open-source, free-to-use 0x relayer template that you can use as a starting point for your own project.', - link: { - title: '0x launch kit', - to: 'https://github.com/0xProject/0x-launch-kit', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'Reference documentation for the 0x smart contracts. Helpful for dApp developer wanting to integrate 0x at the smart contract level.', - link: { - title: '0x smart contracts', - to: WebsitePaths.SmartContracts, - }, - }, - { - description: - 'An http & websocket client for interacting with relayers that have implemented the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api)', - link: { - title: '@0x/connect', - to: WebsitePaths.Connect, - }, - }, - { - description: - 'Typescript/Javascript wrappers of the 0x protocol Ethereum smart contracts. Use this library to call methods on the 0x smart contracts, subscribe to contract events and to fetch information stored in contracts.', - link: { - title: '@0x/contract-wrappers', - to: WebsitePaths.ContractWrappers, - }, - }, - { - description: - "A package to deploy the 0x protocol's system of smart contracts to the testnet of your choice", - link: { - title: '@0x/migrations', - to: WebsitePaths.Migrations, - }, - }, - { - description: - 'A collection of 0x-related JSON-schemas (incl. SRA request/response schemas, 0x order message format schema, etc...)', - link: { - title: '@0x/json-schemas', - to: WebsitePaths.JSONSchemas, - }, - }, - { - description: - 'A set of utils for working with 0x orders. It includes utilities for creating, signing, validating 0x orders, encoding/decoding assetData and much more.', - link: { - title: '@0x/order-utils', - to: WebsitePaths.OrderUtils, - }, - }, - { - description: - "A daemon that watches a set of 0x orders and emits events when an order's fillability has changed. Can be used by a relayer to prune their orderbook or by a trader to keep their view of the market up-to-date.", - link: { - title: '@0x/order-watcher', - to: WebsitePaths.OrderWatcher, - }, - }, - { - description: - 'A tiny utility library for getting known deployed contract addresses for a particular network.', - link: { - title: '@0x/contract-addresses', - to: 'https://www.npmjs.com/package/@0x/contract-addresses', - shouldOpenInNewTab: true, - }, - }, - { - description: 'Smart contract compilation artifacts for the latest version of the 0x protocol.', - link: { - title: '@0x/contract-artifacts', - to: 'https://www.npmjs.com/package/@0x/contract-artifacts', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'Contains the Standard Relayer API OpenAPI Spec. The package distributes both a javascript object version and a json version.', - link: { - title: '@0x/sra-spec', - to: 'https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-spec', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'Convenience package for buying assets represented on the Ethereum blockchain using 0x. In its simplest form, the package helps in the usage of the [0x forwarder contract](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md), which allows users to execute [Wrapped Ether](https://weth.io/) based 0x orders without having to set allowances, wrap Ether or own ZRX, meaning they can buy tokens with Ether alone. Given some liquidity (0x signed orders), it helps estimate the Ether cost of buying a certain asset (giving a range) and then buying that asset.', - link: { - title: '@0x/asset-buyer', - to: WebsitePaths.AssetBuyer, - }, - }, - ], - [Categories.ZeroExProtocolPython]: [ - { - description: - "A library for interacting with 0x orders. Generate an orderHash, sign an order, validate it's signature and more.", - link: { - title: '0x-order-utils', - to: 'https://pypi.org/project/0x-order-utils/', - shouldOpenInNewTab: true, - }, - }, - { - description: 'A Standard Relayer API client', - link: { - title: '0x-sra-client', - to: 'https://pypi.org/project/0x-sra-client/', - shouldOpenInNewTab: true, - }, - }, - { - description: 'Package containing the addresses at which the 0x smart contracts have been deployed', - link: { - title: '0x-contract-addresses', - to: 'https://pypi.org/project/0x-contract-addresses/', - shouldOpenInNewTab: true, - }, - }, - { - description: 'Package containing the 0x smart contract compilation artifacts', - link: { - title: '0x-contract-artifacts', - to: 'https://pypi.org/project/0x-contract-artifacts/', - shouldOpenInNewTab: true, - }, - }, - { - description: '0x JSON schemas for those developing on top of 0x protocol', - link: { - title: '0x-json-schemas', - to: 'https://pypi.org/project/0x-json-schemas/', - shouldOpenInNewTab: true, - }, - }, - { - description: 'Demo project showing how to interact with the 0x smart contracts using Python', - link: { - title: '0x-contract-demo', - to: 'https://github.com/0xProject/0x-monorepo/blob/development/python-packages/contract_demo/README.md', - shouldOpenInNewTab: true, - }, - }, - ], - [Categories.Ethereum]: [ - { - description: - "This package allows you to generate TypeScript contract wrappers from ABI files. It's heavily inspired by Geth abigen but takes a different approach. You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions.", - link: { - title: 'abi-gen', - to: 'https://github.com/0xProject/0x-monorepo/tree/development/packages/abi-gen', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'A collection of Typescript types that are useful when working on an Ethereum-based project (e.g RawLog, Transaction, TxData, SolidityTypes, etc...).', - link: { - title: 'ethereum-types', - to: WebsitePaths.EthereumTypes, - }, - }, - { - description: - 'A wrapper around [solc-js](https://github.com/ethereum/solc-js) that adds smart re-compilation, ability to compile an entire project, Solidity version specific compilation, standard input description support and much more.', - link: { - title: '@0x/sol-compiler', - to: WebsitePaths.SolCompiler, - }, - }, - { - description: - 'A Solidity code coverage tool. Sol-coverage uses transaction traces to figure out which lines of your code has been covered by your tests.', - link: { - title: '@0x/sol-coverage', - to: WebsitePaths.SolCoverage, - }, - }, - { - description: - 'A Solidity profiler. Sol-profiler uses transaction traces to figure out line-by-line gas consumption.', - link: { - title: '@0x/sol-profiler', - to: WebsitePaths.SolProfiler, - }, - }, - { - description: - 'A Solidity revert trace tool. Sol-trace prints human-readable revert trace whenever the revert happens.', - link: { - title: '@0x/sol-trace', - to: WebsitePaths.SolTrace, - }, - }, - { - description: - 'A collection of subproviders to use with [web3-provider-engine](https://www.npmjs.com/package/web3-provider-engine) (e.g subproviders for interfacing with Ledger hardware wallet, Mnemonic wallet, private key wallet, etc...)', - link: { - title: '@0x/subproviders', - to: WebsitePaths.Subproviders, - }, - }, - { - description: - 'A raw Ethereum JSON RPC client to simplify interfacing with Ethereum nodes. Also includes some convenience functions for awaiting transactions to be mined, converting between token units, etc...', - link: { - title: '@0x/web3-wrapper', - to: WebsitePaths.Web3Wrapper, - }, - }, - ], - [Categories.CommunityMaintained]: [ - { - description: - 'Node.js worker originally built for 0x Tracker which extracts 0x fill events from the Ethereum blockchain and persists them to MongoDB. Support for both V1 and V2 of the 0x protocol is included with events tagged against the protocol version they belong to.', - link: { - title: '0x Event Extractor', - to: 'https://github.com/0xTracker/0x-event-extractor', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'Node.js worker built for 0x Tracker which performs various ETL tasks related to the 0x protocol trading data and other information used on 0x Tracker.', - link: { - title: '0x Tracker Worker', - to: 'https://github.com/0xTracker/0x-tracker-worker', - shouldOpenInNewTab: true, - }, - }, - { - description: - "ERCdEX's Javascript SDK for trading on their relayer, as well as other Aquaduct partner relayers", - link: { - title: 'Aquaduct', - to: 'https://www.npmjs.com/package/aqueduct', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'SDKs for automation using Aqueduct & ERC dEX. Aqueduct Server is a lightweight, portable and secure server that runs locally on any workstation. The server exposes a small number of foundational endpoints that enable working with the decentralized Aqueduct liquidity pool from any context or programming language.', - link: { - title: 'Aquaduct Server SDK', - to: 'https://github.com/ERCdEX/aqueduct-server-sdk', - shouldOpenInNewTab: true, - }, - }, - { - description: "The ERCdEX Trade Widget let's any website provide token liquidity to it's users", - link: { - to: 'https://github.com/ERCdEX/widget', - title: 'ERCdEX Widget', - shouldOpenInNewTab: true, - }, - }, - { - description: "ERCdEX's Java SDK for trading on their relayer, as well as other Aquaduct partner relayers", - link: { - to: 'https://github.com/ERCdEX/java', - title: 'ERCdEX Java SDK', - shouldOpenInNewTab: true, - }, - }, - { - description: "ERCdEX's Python SDK for trading on their relayer, as well as other Aquaduct partner relayers", - link: { - to: 'https://github.com/ERCdEX/python', - title: 'ERCdEX Python SDK', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'A set of command-line tools for creating command-line scripts for interacting with the Ethereum blockchain in general, and 0x in particular', - link: { - title: 'Massive', - to: 'https://github.com/NoteGio/massive', - shouldOpenInNewTab: true, - }, - }, - { - description: 'An open-source API-only Relayer written in Go', - link: { - to: 'https://github.com/NoteGio/openrelay', - title: 'OpenRelay', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'A JavaScript Library for Interacting with OpenRelay.xyz and other 0x Standard Relayer API Implementations', - link: { - title: 'OpenRelay.js', - to: 'https://github.com/NoteGio/openrelay.js', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'The Radar Relay SDK is a software development kit that simplifies the interactions with Radar Relay’s APIs', - link: { - title: 'Radar SDK', - to: 'https://github.com/RadarRelay/sdk', - shouldOpenInNewTab: true, - }, - }, - { - description: - 'The Ocean provides a simple REST API, WebSockets API, and JavaScript library to help you integrate decentralized trading into your existing trading strategy.', - link: { - title: 'The Ocean Javascript SDK', - to: 'https://github.com/TheOceanTrade/theoceanx-javascript', - shouldOpenInNewTab: true, - }, - }, - { - description: "Tokenlon SDK provides APIs for developers to trade of imToken's relayer", - link: { - to: 'https://www.npmjs.com/package/tokenlon-sdk', - title: 'Tokenlon Javascript SDK', - shouldOpenInNewTab: true, - }, - }, - { - description: 'A small library that implements the 0x order assetData encoding/decoding in Java', - link: { - to: 'https://github.com/wildnothing/asset-data-decoder', - title: 'AssetData decoder library in Java', - shouldOpenInNewTab: true, - }, - }, - ], -}; - -export interface DocsHomeProps { - location: Location; - translate: Translate; - screenWidth: ScreenWidths; - tutorials: TutorialInfo[]; - categoryToPackages: ObjectMap<Package[]>; - dispatcher: Dispatcher; -} - -export interface DocsHomeState {} - -export class DocsHome extends React.Component<DocsHomeProps, DocsHomeState> { - public render(): React.ReactNode { - const sectionNameToLinks: ObjectMap<ALink[]> = { - 'Starter guides': _.map(TUTORIALS, tutorialInfo => { - return { - ...tutorialInfo.link, - title: this.props.translate.get(tutorialInfo.link.title as Key, Deco.Cap), - }; - }), - [Categories.ZeroExProtocolTypescript]: _.map( - CATEGORY_TO_PACKAGES[Categories.ZeroExProtocolTypescript], - pkg => pkg.link, - ), - [Categories.Ethereum]: _.map(CATEGORY_TO_PACKAGES[Categories.Ethereum], pkg => pkg.link), - [Categories.CommunityMaintained]: _.map( - CATEGORY_TO_PACKAGES[Categories.CommunityMaintained], - pkg => pkg.link, - ), - }; - const mainContent = ( - <OverviewContent - translate={this.props.translate} - tutorials={TUTORIALS} - categoryToPackages={CATEGORY_TO_PACKAGES} - /> - ); - const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; - const sidebar = ( - <NestedSidebarMenu - sidebarHeader={isSmallScreen ? this._renderSidebarHeader() : undefined} - sectionNameToLinks={sectionNameToLinks} - shouldReformatMenuItemNames={false} - screenWidth={this.props.screenWidth} - /> - ); - return ( - <DevelopersPage - mainContent={mainContent} - sidebar={sidebar} - location={this.props.location} - screenWidth={this.props.screenWidth} - translate={this.props.translate} - dispatcher={this.props.dispatcher} - /> - ); - } - private _renderSidebarHeader(): React.ReactNode { - const menuItems = _.map(constants.DEVELOPER_TOPBAR_LINKS, menuItemInfo => { - return ( - <Link - key={`menu-item-${menuItemInfo.title}`} - to={menuItemInfo.to} - shouldOpenInNewTab={menuItemInfo.shouldOpenInNewTab} - > - <Button - borderRadius="4px" - padding="0.4em 0.375em" - width="100%" - fontColor={colors.grey800} - fontSize="14px" - textAlign="left" - > - {this.props.translate.get(menuItemInfo.title as Key, Deco.Cap)} - </Button> - </Link> - ); - }); - return menuItems; - } -} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/pages/ecosystem.tsx b/packages/website/ts/pages/ecosystem.tsx deleted file mode 100644 index 8e367b21f..000000000 --- a/packages/website/ts/pages/ecosystem.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; -import styled from 'styled-components'; - -import { colors } from 'ts/style/colors'; - -import { Button } from 'ts/components/button'; -import { Icon } from 'ts/components/icon'; -import { Column, Section, WrapGrid } from 'ts/components/newLayout'; -import { SiteWrap } from 'ts/components/siteWrap'; -import { Heading, Paragraph } from 'ts/components/text'; -import { constants } from 'ts/utils/constants'; - -interface BenefitProps { - title: string; - icon: string; - description: string; -} - -const benefits: BenefitProps[] = [ - { - icon: 'milestoneGrants', - title: 'Milestone Grants', - description: - 'Receive non-dilutive capital ranging from $10,000 to $100,000, with grant sizes awarded based on the quality of your team, vision, execution, and community involvement.', - }, - { - icon: 'vcIntroductions', - title: 'VC Introductions', - description: 'Connect with leading venture capital firms that could participate in your next funding round.', - }, - { - icon: 'techSupport', - title: 'Technical Support', - description: 'Receive ongoing technical assistance from knowledgeable and responsive 0x developers.', - }, - { - icon: 'recruitingSupport', - title: 'Recruiting Assistance', - description: 'Grow your team by accessing an exclusive pool of top engineering and business operations talent.', - }, - { - icon: 'eficientDesign', - title: 'Marketing and Design Help', - description: - 'Get strategic advice on product positioning, customer acquisition, and UI/UX design that can impact the growth of your business.', - }, - { - icon: 'legalResources', - title: 'Legal Resources', - description: 'Access important legal resources that will help you navigate the regulatory landscape.', - }, -]; - -export const NextEcosystem = () => ( - <SiteWrap theme="light"> - <DocumentTitle title="Ecosystem Acceleration Program: Jumpstart your Business on 0x" /> - <Section isTextCentered={true}> - <Column> - <Heading size="medium" isCentered={true}> - Jumpstart your Business on 0x - </Heading> - <Paragraph size="medium" isCentered={true} isMuted={true} marginBottom="0"> - The Ecosystem Acceleration Program gives teams access to a variety of services including funding, - dedicated technical support, and recruiting assistance. We created the Ecosystem Acceleration - Program to bolster the expansion of both infrastructure projects and relayers building on 0x. - </Paragraph> - <LinkWrap> - <Button - href={constants.URL_ECOSYSTEM_APPLY} - isWithArrow={true} - isAccentColor={true} - shouldUseAnchorTag={true} - > - Apply now - </Button> - <Button - href={constants.URL_ECOSYSTEM_BLOG_POST} - isWithArrow={true} - isAccentColor={true} - shouldUseAnchorTag={true} - target="_blank" - > - Learn More - </Button> - </LinkWrap> - </Column> - </Section> - - <Section bgColor={colors.backgroundLight} isFullWidth={true}> - <Column> - <Heading - size={34} - fontWeight="400" - asElement="h2" - isCentered={true} - maxWidth="507px" - marginBottom="70px" - > - Join a vibrant ecosystem of projects in the 0x Network. - </Heading> - </Column> - <WrapGrid isTextCentered={true} isWrapped={true} isFullWidth={true}> - {_.map(benefits, (benefit: BenefitProps, index) => ( - <Column key={`benefit-${index}`} width="33%" padding="0 45px 30px"> - <Icon name={benefit.icon} size="medium" margin={[0, 0, 'small', 0]} /> - <Heading color={colors.textDarkPrimary} size="small" marginBottom="10px" isCentered={true}> - {benefit.title} - </Heading> - <Paragraph isMuted={true} isCentered={true}> - {benefit.description} - </Paragraph> - </Column> - ))} - </WrapGrid> - </Section> - </SiteWrap> -); - -const LinkWrap = styled.div` - display: inline-flex; - margin-top: 60px; - - a + a { - margin-left: 60px; - } -`; diff --git a/packages/website/ts/pages/faq/faq.tsx b/packages/website/ts/pages/faq/faq.tsx deleted file mode 100644 index 548db1d1d..000000000 --- a/packages/website/ts/pages/faq/faq.tsx +++ /dev/null @@ -1,453 +0,0 @@ -import { colors, Styles } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import * as DocumentTitle from 'react-document-title'; -import { Footer } from 'ts/components/old_footer'; -import { TopBar } from 'ts/components/top_bar/top_bar'; -import { Question } from 'ts/pages/faq/question'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { FAQQuestion, FAQSection, WebsitePaths } from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -export interface FAQProps { - source: string; - location: Location; - translate: Translate; - dispatcher: Dispatcher; -} - -interface FAQState {} - -const styles: Styles = { - thin: { - fontWeight: 100, - }, -}; - -const sections: FAQSection[] = [ - { - name: '0x Protocol', - questions: [ - { - prompt: 'What is 0x?', - answer: ( - <div> - At its core, 0x is an open and non-rent seeking protocol that facilitates trustless, low - friction exchange of Ethereum-based assets. Developers can use 0x as a platform to build - exchange applications on top of ( - <a href={`${configs.BASE_URL}${WebsitePaths.ZeroExJs}#introduction`} target="blank"> - 0x.js - </a>{' '} - is a Javascript library for interacting with the 0x protocol). For end users, 0x will be the - infrastructure of a wide variety of user-facing applications i.e.{' '} - <a href={`${configs.BASE_URL}${WebsitePaths.Portal}`} target="blank"> - 0x Portal - </a> - , a decentralized application that facilitates trustless trading of Ethereum-based tokens - between known counterparties. - </div> - ), - }, - { - prompt: 'What problem does 0x solve?', - answer: ( - <div> - In the two years since the Ethereum blockchain’s genesis block, numerous decentralized - applications (dApps) have created Ethereum smart contracts for peer-to-peer exchange. Rapid - iteration and a lack of best practices have left the blockchain scattered with proprietary and - application-specific implementations. As a result, end users are exposed to numerous smart - contracts of varying quality and security, with unique configuration processes and learning - curves, all of which implement the same functionality. This approach imposes unnecessary costs - on the network by fragmenting end users according to the particular dApp each user happens to be - using, eliminating valuable network effects around liquidity. 0x is the solution to this problem - by acting as modular, unopinionated building blocks that may be assembled and reconfigured. - </div> - ), - }, - { - prompt: 'How is 0x different from a centralized exchange like Poloniex or ShapeShift?', - answer: ( - <div> - <ul> - <li>0x is a protocol for exchange, not a user-facing exchange application.</li> - <li> - 0x is decentralized and trustless; there is no central party which can be hacked, run - away with customer funds or be subjected to government regulations. Hacks of Mt. Gox, - Shapeshift and Bitfinex have demonstrated that these types of systemic risks are - palpable. - </li> - <li> - Rather than a proprietary system that exists to extract rent for its owners, 0x is - public infrastructure that is funded by a globally distributed community of - stakeholders. While the protocol is free to use, it enables for-profit user-facing - exchange applications to be built on top of the protocol. - </li> - </ul> - </div> - ), - }, - { - prompt: 'If 0x protocol is free to use, where do transaction fees come in?', - answer: ( - <div> - 0x protocol uses off-chain order books to massively reduce friction costs for market makers and - ensure that the blockchain is only used for trade settlement. Hosting and maintaining an - off-chain order book is a service; to incent “Relayers” to provide this service they must be - able to charge transaction fees on trading activity. Relayers are free to set their transaction - fees to any value they desire. We expect Relayers to be highly competitive and transaction fees - to approach an efficient economic equilibrium over time. - </div> - ), - }, - { - prompt: 'What are the differences between 0x protocol and state channels?', - answer: ( - <div> - <div> - Participants in a state channel pass cryptographically signed messages back and forth, - accumulating intermediate state changes without publishing them to the canonical chain until - the channel is closed. State channels are ideal for “bar tab” applications where numerous - intermediate state changes may be accumulated off-chain before being settled by a final - on-chain transaction (i.e. day trading, poker, turn-based games). - </div> - <ul> - <li> - While state channels drastically reduce the number of on-chain transactions for specific - use cases, numerous on-chain transactions and a security deposit are required to open - and safely close a state channel making them less efficient than 0x for executing - one-time trades. - </li> - <li> - State channels are isolated from the Ethereum blockchain meaning that they cannot - interact with smart contracts. 0x is designed to be integrated directly into smart - contracts so trades can be executed programmatically in a single line of Solidity code. - </li> - </ul> - </div> - ), - }, - { - prompt: 'What types of digital assets are supported by 0x?', - answer: ( - <div> - 0x supports all Ethereum-based assets that adhere to the ERC20 token standard. There are many - ERC20 tokens, worth a combined $2.2B, and more tokens are created each month. We believe that, - by 2020, thousands of assets will be tokenized and moved onto the Ethereum blockchain including - traditional securities such as equities, bonds and derivatives, fiat currencies and scarce - digital goods such as video game items. In the future, cross-blockchain solutions such as{' '} - <a href="https://cosmos.network/" target="_blank"> - Cosmos - </a>{' '} - and{' '} - <a href="http://polkadot.io/" target="_blank"> - Polkadot - </a>{' '} - will allow cryptocurrencies to freely move between blockchains and, naturally, currencies such - as Bitcoin will end up being represented as ERC20 tokens on the Ethereum blockchain. - </div> - ), - }, - { - prompt: '0x is open source: what prevents someone from forking the protocol?', - answer: ( - <div> - Ethereum and Bitcoin are both open source protocols. Each protocol has been forked, but the - resulting clone networks have seen little adoption (as measured by transaction count or market - cap). This is because users have little to no incentive to switch over to a clone network if the - original has initial network effects and a talented developer team behind it. An exception is in - the case that a protocol includes a controversial feature such as a method of rent extraction or - a monetary policy that favors one group of users over another (Zcash developer subsidy - for - better or worse - resulted in Zclassic). Perceived inequality can provide a strong enough - incentive that users will fork the original protocol’s codebase and spin up a new network that - eliminates the controversial feature. In the case of 0x, there is no rent extraction and no - users are given special permissions. 0x protocol is upgradable. Cutting-edge technical - capabilities can be integrated into 0x via decentralized governance (see section below), - eliminating incentives to fork off of the original protocol and sacrifice the network effects - surrounding liquidity that result from the shared protocol and settlement layer. - </div> - ), - }, - ], - }, - { - name: '0x Token (ZRX)', - questions: [ - { - prompt: 'Explain how the 0x protocol token (zrx) works.', - answer: ( - <div> - <div> - 0x protocol token (ZRX) is utilized in two ways: 1) to solve the{' '} - <a href="https://en.wikipedia.org/wiki/Coordination_game" target="_blank"> - coordination problem - </a>{' '} - and drive network effects around liquidity, creating a feedback loop where early adopters of - the protocol benefit from wider adoption and 2) to be used for decentralized governance over - 0x protocol's update mechanism. In more detail: - </div> - <ul> - <li> - ZRX tokens are used by Makers and Takers (market participants that generate and consume - orders, respectively) to pay transaction fees to Relayers (entities that host and - maintain public order books). - </li> - <li> - ZRX tokens are used for decentralized governance over 0x protocol’s update mechanism - which allows its underlying smart contracts to be replaced and improved over time. An - update mechanism is needed because 0x is built upon Ethereum’s rapidly evolving - technology stack, decentralized governance is needed because 0x protocol’s smart - contracts will have access to user funds and numerous dApps will need to plug into 0x - smart contracts. Decentralized governance ensures that this update process is secure and - minimizes disruption to the network. - </li> - </ul> - </div> - ), - }, - { - prompt: 'Why must transaction fees be denominated in 0x token (ZRX) rather than ETH?', - answer: ( - <div> - 0x protocol’s decentralized update mechanism is analogous to proof-of-stake. To maximize the - alignment of stakeholder and end user incentives, the staked asset must provide utility within - the protocol. - </div> - ), - }, - { - prompt: 'How will decentralized governance work?', - answer: ( - <div> - Decentralized governance is an ongoing focus of research; it will involve token voting with ZRX. - Ultimately the solution will maximize security while also maximizing the protocol’s ability to - absorb new innovations. Until the governance structure is formalized and encoded within 0x DAO, - a multi-sig will be used as a placeholder. - </div> - ), - }, - ], - }, - { - name: 'ZRX Token Launch and Fund Use', - questions: [ - { - prompt: 'What is the total supply of ZRX tokens?', - answer: <div>1,000,000,000 ZRX. Fixed supply.</div>, - }, - { - prompt: 'When was the token launch? Was there a pre-sale?', - answer: <div>The token launch was on August 15th, 2017. There was no pre-sale.</div>, - }, - { - prompt: 'What will the token launch proceeds be used for?', - answer: ( - <div> - 100% of the proceeds raised in the token launch will be used to fund the development of free and - open source software, tools and infrastructure that support the protocol and surrounding - ecosystem. Check out our{' '} - <a - href="https://docs.google.com/document/d/1_RVa-_bkU92fWRsC8eNy4vYjcTt-WC8GtqyyjbTd-oY" - target="_blank" - > - development roadmap - </a> - . - </div> - ), - }, - { - prompt: 'What will be the initial distribution of ZRX tokens?', - answer: ( - <div> - <div className="center" style={{ width: '100%' }}> - <img style={{ width: 350 }} src="/images/zrx_pie_chart.png" /> - </div> - <div className="py1"> - <div className="bold pb1">Token Launch (50%)</div> - <div> - ZRX is inherently a governance token that plays a critical role in the process of - upgrading 0x protocol. We are fully committed to formulating a functional and - theoretically sound governance model and we plan to dedicate significant resources to - R&D. - </div> - </div> - <div className="py1"> - <div className="bold pb1">Retained by 0x (15%)</div> - <div> - The 0x core development team will be able to sustain itself for approximately five years - using funds raised through the token launch. If 0x protocol proves to be as foundational - a technology as we believe it to be, the retained ZRX tokens will allow the 0x core - development team to sustain operations beyond the first 5 years. - </div> - </div> - <div className="py1"> - <div className="bold pb1">Developer Fund (15%)</div> - <div> - The Developer Fund will be used to make targeted capital injections into high potential - projects and teams that are attempting to grow the 0x ecosystem, strategic partnerships, - hackathon prizes and community development activities. - </div> - </div> - <div className="py1"> - <div className="bold pb1">Founding Team (10%)</div> - <div> - The founding team’s allocation of ZRX will vest over a traditional 4 year vesting - schedule with a one year cliff. We believe this should be standard practice for any team - that is committed to making their project a long term success. - </div> - </div> - <div className="py1"> - <div className="bold pb1">Early Backers & Advisors (10%)</div> - <div> - Our backers and advisors have provided capital, resources and guidance that have allowed - us to fill out our team, setup a robust legal entity and build a fully functional - product before launching a token. As a result, we have a proven track record and can - offer a token that holds genuine utility. - </div> - </div> - </div> - ), - }, - { - prompt: 'Can I mine ZRX tokens?', - answer: ( - <div> - No, the total supply of ZRX tokens is fixed and there is no continuous issuance model. Users - that facilitate trading over 0x protocol by operating a Relayer earn transaction fees - denominated in ZRX; as more trading activity is generated, more transaction fees are earned. - </div> - ), - }, - { - prompt: 'Will there be a lockup period for ZRX tokens sold in the token launch?', - answer: <div>No, ZRX tokens sold in the token launch will immediately be liquid.</div>, - }, - { - prompt: 'Will there be a lockup period for tokens allocated to the founding team?', - answer: ( - <div> - Yes. ZRX tokens allocated to founders, advisors and staff members will be released over a 4 year - vesting schedule with a 25% cliff upon completion of the initial token launch and 25% released - each subsequent year in monthly installments. Staff members hired after the token launch will - have a 4 year vesting schedule with a one year cliff. - </div> - ), - }, - { - prompt: 'Which cryptocurrencies will be accepted in the token launch?', - answer: <div>ETH.</div>, - }, - { - prompt: 'When will 0x be live?', - answer: ( - <div> - An alpha version of 0x has been live on our private test network since January 2017. Version 1.0 - of 0x protocol will be deployed to the canonical Ethereum blockchain after a round of security - audits and prior to the public token launch. 0x will be using the 0x protocol during our token - launch. - </div> - ), - }, - { - prompt: 'Where can I find a development roadmap?', - answer: ( - <div> - Check it out{' '} - <a - href="https://drive.google.com/open?id=14IP1N8mt3YdsAoqYTyruMnZswpklUs3THyS1VXx71fo" - target="_blank" - > - here - </a> - . - </div> - ), - }, - ], - }, - { - name: 'Team', - questions: [ - { - prompt: 'Where is 0x based?', - answer: <div>0x was founded in SF and is driven by a diverse group of contributors.</div>, - }, - { - prompt: 'How can I get involved?', - answer: ( - <div> - Join our{' '} - <a href={constants.URL_ZEROEX_CHAT} target="_blank"> - Discord - </a> - ! As an open source project, 0x will rely on a worldwide community of passionate developers to - contribute proposals, ideas and code. - </div> - ), - }, - { - prompt: 'Why the name 0x?', - answer: ( - <div> - 0x is the prefix for hexadecimal numeric constants including Ethereum addresses. In a more - abstract context, as the first open protocol for exchange 0x represents the beginning of the end - for the exchange industry’s rent seeking oligopoly: zero exchange. - </div> - ), - }, - { - prompt: 'How do you pronounce 0x?', - answer: <div>We pronounce 0x as “zero-ex,” but you are free to pronounce it however you please.</div>, - }, - ], - }, -]; - -export class FAQ extends React.Component<FAQProps, FAQState> { - public componentDidMount(): void { - window.scrollTo(0, 0); - } - public render(): React.ReactNode { - return ( - <div> - <DocumentTitle title="0x FAQ" /> - <TopBar blockchainIsLoaded={false} location={this.props.location} translate={this.props.translate} /> - <div id="faq" className="mx-auto max-width-4 pt4" style={{ color: colors.grey800 }}> - <h1 className="center" style={{ ...styles.thin }}> - 0x FAQ - </h1> - <div className="sm-px2 md-px2 lg-px0 pb4">{this._renderSections()}</div> - </div> - <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} /> - </div> - ); - } - private _renderSections(): React.ReactNode { - const renderedSections = _.map(sections, (section: FAQSection, i: number) => { - const isFirstSection = i === 0; - return ( - <div key={section.name}> - <h3>{section.name}</h3> - {this._renderQuestions(section.questions, isFirstSection)} - </div> - ); - }); - return renderedSections; - } - private _renderQuestions(questions: FAQQuestion[], isFirstSection: boolean): React.ReactNode { - const renderedQuestions = _.map(questions, (question: FAQQuestion, i: number) => { - const isFirstQuestion = i === 0; - return ( - <Question - key={question.prompt} - prompt={question.prompt} - answer={question.answer} - shouldDisplayExpanded={isFirstSection && isFirstQuestion} - /> - ); - }); - return renderedQuestions; - } -} diff --git a/packages/website/ts/pages/faq/question.tsx b/packages/website/ts/pages/faq/question.tsx deleted file mode 100644 index 413ffb6ce..000000000 --- a/packages/website/ts/pages/faq/question.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { Card, CardHeader, CardText } from 'material-ui/Card'; -import * as React from 'react'; - -export interface QuestionProps { - prompt: string; - answer: React.ReactNode; - shouldDisplayExpanded: boolean; -} - -interface QuestionState { - isExpanded: boolean; -} - -export class Question extends React.Component<QuestionProps, QuestionState> { - constructor(props: QuestionProps) { - super(props); - this.state = { - isExpanded: props.shouldDisplayExpanded, - }; - } - public render(): React.ReactNode { - return ( - <div className="py1"> - <Card - initiallyExpanded={this.props.shouldDisplayExpanded} - onExpandChange={this._onExchangeChange.bind(this)} - > - <CardHeader - title={this.props.prompt} - style={{ - borderBottom: this.state.isExpanded ? '1px solid rgba(0, 0, 0, 0.19)' : 'none', - }} - titleStyle={{ color: colors.darkerGrey }} - actAsExpander={true} - showExpandableButton={true} - /> - <CardText expandable={true}> - <div style={{ lineHeight: 1.4 }}>{this.props.answer}</div> - </CardText> - </Card> - </div> - ); - } - private _onExchangeChange(): void { - this.setState({ - isExpanded: !this.state.isExpanded, - }); - } -} diff --git a/packages/website/ts/pages/fullscreen_message.tsx b/packages/website/ts/pages/fullscreen_message.tsx deleted file mode 100644 index 675f27a01..000000000 --- a/packages/website/ts/pages/fullscreen_message.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Styles } from '@0x/react-shared'; -import * as React from 'react'; - -export interface FullscreenMessageProps { - headerText: string; - bodyText: string; -} - -const styles: Styles = { - thin: { - fontWeight: 100, - }, -}; - -export const FullscreenMessage = (props: FullscreenMessageProps) => { - return ( - <div className="mx-auto max-width-4 py4"> - <div className="center py4"> - <div className="py4"> - <div className="py4"> - <h1 style={styles.thin}>{props.headerText}</h1> - <div className="py1"> - <div className="py3">{props.bodyText}</div> - </div> - </div> - </div> - </div> - </div> - ); -}; diff --git a/packages/website/ts/pages/instant.tsx b/packages/website/ts/pages/instant.tsx deleted file mode 100644 index 586665d5b..000000000 --- a/packages/website/ts/pages/instant.tsx +++ /dev/null @@ -1,255 +0,0 @@ -import { utils as sharedUtils } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; -import styled, { keyframes } from 'styled-components'; - -import { Banner } from 'ts/components/banner'; -import { Button } from 'ts/components/button'; -import { Definition } from 'ts/components/definition'; -import { Hero } from 'ts/components/hero'; -import { Section, SectionProps } from 'ts/components/newLayout'; -import { SiteWrap } from 'ts/components/siteWrap'; -import { Heading, Paragraph } from 'ts/components/text'; -import { Configurator } from 'ts/pages/instant/configurator'; -import { colors } from 'ts/style/colors'; -import { WebsitePaths } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -import { ModalContact } from '../components/modals/modal_contact'; - -const CONFIGURATOR_MIN_WIDTH_PX = 1050; - -export const getStartedClick = () => { - if (window.innerWidth < CONFIGURATOR_MIN_WIDTH_PX) { - utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`); - } else { - sharedUtils.setUrlHash('configurator'); - sharedUtils.scrollToHash('configurator', ''); - } -}; - -const featuresData = [ - { - title: 'Support ERC-20 and ERC-721 tokens', - icon: 'supportForAllEthereumStandards-large', - description: - 'Seamlessly integrate token purchasing into your product experience by offering digital assets ranging from in-game items to stablecoins.', - links: [ - { - label: 'Get Started', - onClick: getStartedClick, - shouldUseAnchorTag: true, - }, - { - label: 'Explore the Docs', - url: `${WebsitePaths.Wiki}#Get-Started-With-Instant`, - }, - ], - }, - { - title: 'Generate revenue for your business', - icon: 'generateRevenueForYourBusiness-large', - description: - 'With just a few lines of code, you can earn up to 5% in affiliate fees on every transaction from your crypto wallet or dApp.', - links: [ - { - label: 'Learn about affiliate fees', - url: `${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`, - }, - ], - }, - { - title: 'Easy and flexible integration', - icon: 'flexibleIntegration0xInstant', - description: - 'Use our out-of-the-box design or customize the user interface by integrating via the AssetBuyer engine.. You can also tap into 0x networked liquidity or choose your own liquidity pool.', - links: [ - { - label: 'Explore AssetBuyer', - url: `${WebsitePaths.Docs}/asset-buyer`, - }, - ], - }, -]; - -interface Props { - theme: { - bgColor: string; - textColor: string; - linkColor: string; - }; -} - -export class Next0xInstant extends React.Component<Props> { - public state = { - isContactModalOpen: false, - }; - public render(): React.ReactNode { - return ( - <SiteWrap> - <DocumentTitle title="0x Instant: Quick and secure crypto purchasing" /> - <Hero - title="Introducing 0x Instant" - description="A free and flexible way to offer simple crypto purchasing in any app or website" - actions={<Button onClick={getStartedClick}>Get Started</Button>} - /> - - <Section isFullWidth={true} isPadded={false} padding="30px 0"> - <MarqueeWrap> - <div> - {[...Array(18)].map((item, index) => ( - <Card key={`card-${index}`} index={index}> - <img src={`/images/0x-instant/widget-${(index % 6) + 1}.png`} /> - </Card> - ))} - </div> - </MarqueeWrap> - </Section> - - <Section> - {_.map(featuresData, (item, index) => ( - <Definition - key={`definition-${index}`} - icon={item.icon} - title={item.title} - description={item.description} - isInlineIcon={true} - iconSize={240} - actions={item.links} - /> - ))} - </Section> - - <ConfiguratorSection - id="configurator" - maxWidth="1386px" - padding="0 58px 70px" - bgColor={colors.backgroundDark} - > - <Heading>0x Instant Configurator</Heading> - <Configurator /> - </ConfiguratorSection> - - <Banner - heading="Need more flexibility?" - subline="Dive into our docs, or contact us if needed" - mainCta={{ text: 'Explore the Docs', href: `${WebsitePaths.Wiki}#Get-Started-With-Instant` }} - secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} - /> - <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> - - <Section maxWidth="1170px" isPadded={false} padding="60px 0"> - <Paragraph size="small" isMuted={0.5}> - Disclaimer: The laws and regulations applicable to the use and exchange of digital assets and - blockchain-native tokens, including through any software developed using the licensed work - created by ZeroEx Intl. (the “Work”), vary by jurisdiction. As set forth in the Apache License, - Version 2.0 applicable to the Work, developers are “solely responsible for determining the - appropriateness of using or redistributing the Work,” which includes responsibility for ensuring - compliance with any such applicable laws and regulations. - </Paragraph> - <Paragraph size="small" isMuted={0.5}> - See the Apache License, Version 2.0 for the specific language governing all applicable - permissions and limitations. - </Paragraph> - </Section> - </SiteWrap> - ); - } - - public _onOpenContactModal = (): void => { - this.setState({ isContactModalOpen: true }); - }; - - public _onDismissContactModal = (): void => { - this.setState({ isContactModalOpen: false }); - }; -} - -// scroll animation calc is simply (imageWidth * totalRepetitions) / 2 -// img width is 370px -const scroll = keyframes` - 0% { transform: translate3d(-2220px, 0, 0) } - 100% { transform: translate3d(-4440px, 0, 0) } -`; - -const scrollMobile = keyframes` - 0% { transform: translate3d(0, 0, 0) } - 100% { transform: translate3d(-1800px, 0, 0) } -`; - -const fadeUp = keyframes` - 0% { - opacity: 0; - transform: translateY(50px); - } - 100% { - opacity: 1; - transform: translateY(0px); - } -`; - -const ConfiguratorSection = styled(Section)<SectionProps>` - @media (max-width: ${CONFIGURATOR_MIN_WIDTH_PX}px) { - display: none; - } -`; - -// width = 370 * 12 -// mobile width = 300 -const MarqueeWrap = styled.div` - width: 100vw; - height: 514px; - padding-bottom: 60px; - - @media (max-width: 768px) { - width: calc(100% + 60px); - margin-left: -30px; - overflow: hidden; - } - - > div { - height: auto; - display: flex; - will-change: transform; - transform: translate3d(-2220px, 0, 0); - } - - @media (min-width: 768px) { - > div { - width: 6660px; - animation: ${scroll} 70s linear infinite; - } - } - - @media (max-width: 768px) { - > div { - width: 5400px; - animation: ${scrollMobile} 70s linear infinite; - } - } -`; - -const Card = styled.div<{ index: number }>` - opacity: 0; - flex-shrink: 0; - transform: translateY(10px); - will-change: opacity, transform; - animation: ${fadeUp} 0.75s ${props => `${props.index * 0.05}s`} forwards; - - img { - height: auto; - } - - @media (min-width: 768px) { - img { - width: 370px; - } - } - - @media (max-width: 768px) { - img { - width: 300px; - } - } -`; diff --git a/packages/website/ts/pages/instant/code_demo.tsx b/packages/website/ts/pages/instant/code_demo.tsx deleted file mode 100644 index c59f148b8..000000000 --- a/packages/website/ts/pages/instant/code_demo.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import * as React from 'react'; -import * as CopyToClipboard from 'react-copy-to-clipboard'; -import SyntaxHighlighter from 'react-syntax-highlighter'; - -import { Button } from 'ts/components/button'; -import { Container } from 'ts/components/ui/container'; -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}> - <StyledButton>{copyButtonText}</StyledButton> - </CopyToClipboard> - </Container> - <SyntaxHighlighter language="html" style={customStyle} showLineNumbers={true} PreTag={CustomPre}> - {this.props.children} - </SyntaxHighlighter> - </Container> - ); - } - private readonly _handleCopyClick = () => { - this.setState({ didCopyCode: true }); - }; -} - -const StyledButton = styled(Button)` - border-radius: 4px; - font-size: 15px; - font-weight: 400; - padding: 9px 21px 7px; -`; diff --git a/packages/website/ts/pages/instant/config_generator.tsx b/packages/website/ts/pages/instant/config_generator.tsx deleted file mode 100644 index 29fce85db..000000000 --- a/packages/website/ts/pages/instant/config_generator.tsx +++ /dev/null @@ -1,329 +0,0 @@ -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 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 { 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'; - -// New components -import { Heading } from 'ts/components/text'; -import { Select, SelectItemConfig } from 'ts/pages/instant/select'; - -import { assetMetaDataMap } from '../../../../instant/src/data/asset_meta_data_map'; -import { ERC20AssetMetaData, ZeroExInstantBaseConfig } from '../../../../instant/src/types'; - -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="Liquidity Source"> - <Select - shouldIncludeEmpty={false} - id="" - value={value.orderSource} - items={this._generateItems()} - onChange={this._handleSRASelection.bind(this)} - /> - </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} - isDisabled={ - _.isUndefined(value.affiliateInfo) || - _.isUndefined(value.affiliateInfo.feeRecipient) || - _.isEmpty(value.affiliateInfo.feeRecipient) - } - /> - </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 => ({ - label: endpoint, - value: endpoint, - onClick: this._handleSRASelection.bind(this, endpoint), - })); - }; - private readonly _handleAffiliatePercentageLearnMoreClick = (): void => { - window.open(`${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`, '_blank'); - }; - private readonly _handleSRASelection = (event: React.ChangeEvent<HTMLSelectElement>) => { - const sraEndpoint = event.target.value; - 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} color={colors.brandLight} /> - </Container> - <CheckboxText isSelected={isSelected}> - {metaData.symbol.toUpperCase()} — {metaData.name} - </CheckboxText> - </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"> - <Heading size="small" marginBottom="0" isFlex={true}> - <span>{title}</span> - {isOptional && <OptionalText> Optional</OptionalText>} - </Heading> - {actionText && <OptionalAction onClick={onActionTextClick}>{actionText}</OptionalAction>} - </Container> - {children} - </Container> -); - -ConfigGeneratorSection.defaultProps = { - marginBottom: '30px', -}; - -const OptionalText = styled.span` - display: inline; - font-size: 14px; - color: #999999; - flex-shrink: 0; -`; - -interface CheckboxTextProps { - isSelected?: boolean; -} - -const CheckboxText = styled.span<CheckboxTextProps>` - font-size: 14px; - line-height: 18px; - color: ${props => (props.isSelected ? colors.brandDark : '#666666')}; -`; - -const OptionalAction = styled(OptionalText)` - cursor: pointer; -`; diff --git a/packages/website/ts/pages/instant/config_generator_address_input.tsx b/packages/website/ts/pages/instant/config_generator_address_input.tsx deleted file mode 100644 index 890e39da6..000000000 --- a/packages/website/ts/pages/instant/config_generator_address_input.tsx +++ /dev/null @@ -1,84 +0,0 @@ -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 { Paragraph } from 'ts/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; - 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); - 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; - } -`; diff --git a/packages/website/ts/pages/instant/configurator.tsx b/packages/website/ts/pages/instant/configurator.tsx deleted file mode 100644 index a63e1752e..000000000 --- a/packages/website/ts/pages/instant/configurator.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import styled from 'styled-components'; - -import { CodeDemo } from 'ts/pages/instant/code_demo'; -import { ConfigGenerator } from 'ts/pages/instant/config_generator'; - -import { Link } from 'ts/components/link'; -import { Column, FlexWrap } from 'ts/components/newLayout'; -import { Heading } from 'ts/components/text'; -import { WebsitePaths } from 'ts/types'; - -import { ZeroExInstantBaseConfig } from '../../../../instant/src/types'; - -export interface ConfiguratorState { - instantConfig: ZeroExInstantBaseConfig; -} - -export class Configurator extends React.Component { - public state: ConfiguratorState = { - instantConfig: { - orderSource: 'https://api.radarrelay.com/0x/v2/', - availableAssetDatas: undefined, - affiliateInfo: { - feeRecipient: '', - feePercentage: 0, - }, - }, - }; - public render(): React.ReactNode { - const codeToDisplay = this._generateCodeDemoCode(); - return ( - <FlexWrap isFlex={true}> - <Column width="442px" padding="0 70px 0 0"> - <ConfigGenerator value={this.state.instantConfig} onConfigChange={this._handleConfigChange} /> - </Column> - <Column width="100%"> - <HeadingWrapper> - <Heading size="small" marginBottom="15px"> - Code Snippet - </Heading> - <Link href={`${WebsitePaths.Wiki}#Get-Started-With-Instant`} isBlock={true} target="_blank"> - Explore the Docs - </Link> - </HeadingWrapper> - <CodeDemo key={codeToDisplay}>{codeToDisplay}</CodeDemo> - </Column> - </FlexWrap> - ); - } - 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.0x.org/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 ]`; - }; -} - -const HeadingWrapper = styled.div` - display: flex; - justify-content: space-between; - - a { - transform: translateY(-8px); - } -`; diff --git a/packages/website/ts/pages/instant/fee_percentage_slider.tsx b/packages/website/ts/pages/instant/fee_percentage_slider.tsx deleted file mode 100644 index c4d9f908f..000000000 --- a/packages/website/ts/pages/instant/fee_percentage_slider.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import Slider from 'rc-slider'; -import * as React from 'react'; -import styled from 'styled-components'; -import 'ts/pages/instant/rc-slider.css'; - -import { colors } from 'ts/style/colors'; - -const SliderWithTooltip = (Slider as any).createSliderWithTooltip(Slider); -// tslint:disable-next-line:no-unused-expression - -export interface FeePercentageSliderProps { - value: number; - isDisabled?: boolean; - onChange: (value: number) => void; -} - -export class FeePercentageSlider extends React.Component<FeePercentageSliderProps> { - public render(): React.ReactNode { - return ( - <StyledSlider - min={0} - max={0.05} - step={0.0025} - value={this.props.value} - disabled={this.props.isDisabled} - onChange={this.props.onChange} - tipFormatter={this._feePercentageSliderFormatter} - tipProps={{ placement: 'bottom', overlayStyle: { backgroundColor: '#fff', borderRadius: '4px' } }} - trackStyle={{ - backgroundColor: colors.brandLight, - }} - railStyle={{ - backgroundColor: 'rgba(255, 255, 255, 0.2)', - }} - handleStyle={{ - border: 'none', - boxShadow: 'none', - }} - activeDotStyle={{ - boxShadow: 'none', - border: 'none', - }} - /> - ); - } - private readonly _feePercentageSliderFormatter = (value: number): React.ReactNode => { - return <Text>{`${(value * 100).toFixed(2)}%`}</Text>; - }; -} - -const StyledSlider = styled(SliderWithTooltip)` - .rc-slider-tooltip__inner { - box-shadow: none !important; - background-color: ${colors.white} !important; - border-radius: 4px !important; - padding: 3px 12px !important; - height: auto !important; - position: relative; - top: 7px; - &:after { - border: solid transparent; - content: ' '; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-width: 6px; - bottom: 100%; - left: 100%; - border-bottom-color: ${colors.white}; - margin-left: -60%; - } - } -`; - -const Text = styled.span` - color: #000000; - font-size: 12px; - line-height: 18px; -`; diff --git a/packages/website/ts/pages/instant/rc-slider.css b/packages/website/ts/pages/instant/rc-slider.css deleted file mode 100644 index 63038324e..000000000 --- a/packages/website/ts/pages/instant/rc-slider.css +++ /dev/null @@ -1,295 +0,0 @@ -.rc-slider { - position: relative; - height: 14px; - padding: 5px 0; - width: 100%; - border-radius: 6px; - -ms-touch-action: none; - touch-action: none; - box-sizing: border-box; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} - -.rc-slider * { - box-sizing: border-box; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} - -.rc-slider-rail { - position: absolute; - width: 100%; - background-color: #e9e9e9; - height: 4px; - border-radius: 6px; -} - -.rc-slider-track { - position: absolute; - left: 0; - height: 4px; - border-radius: 6px; - background-color: #abe2fb; -} - -.rc-slider-handle { - position: absolute; - margin-left: -7px; - margin-top: -5px; - width: 14px; - height: 14px; - cursor: pointer; - cursor: -webkit-grab; - cursor: grab; - border-radius: 50%; - border: solid 2px #96dbfa; - background-color: #fff; - -ms-touch-action: pan-x; - touch-action: pan-x; -} - -.rc-slider-handle:focus { - border-color: #57c5f7; - box-shadow: 0 0 0 5px #96dbfa; - outline: none; -} - -.rc-slider-handle-click-focused:focus { - border-color: #96dbfa; - box-shadow: unset; -} - -.rc-slider-handle:hover { - border-color: #57c5f7; -} - -.rc-slider-handle:active { - border-color: #57c5f7; - box-shadow: 0 0 5px #57c5f7; - cursor: -webkit-grabbing; - cursor: grabbing; -} - -.rc-slider-mark { - position: absolute; - top: 18px; - left: 0; - width: 100%; - font-size: 12px; -} - -.rc-slider-mark-text { - position: absolute; - display: inline-block; - vertical-align: middle; - text-align: center; - cursor: pointer; - color: #999; -} - -.rc-slider-mark-text-active { - color: #666; -} - -.rc-slider-step { - position: absolute; - width: 100%; - height: 4px; - background: transparent; -} - -.rc-slider-dot { - position: absolute; - bottom: -2px; - margin-left: -4px; - width: 8px; - height: 8px; - border: 2px solid #e9e9e9; - background-color: #fff; - cursor: pointer; - border-radius: 50%; - vertical-align: middle; -} - -.rc-slider-dot-active { - border-color: #96dbfa; -} - -.rc-slider-disabled { - opacity: 0.2; -} - -.rc-slider-disabled .rc-slider-track { - background-color: #ccc; -} - -.rc-slider-disabled .rc-slider-handle, -.rc-slider-disabled .rc-slider-dot { - border-color: #ccc; - box-shadow: none; - background-color: #fff; - cursor: not-allowed; -} - -.rc-slider-disabled .rc-slider-mark-text, -.rc-slider-disabled .rc-slider-dot { - cursor: not-allowed !important; -} - -.rc-slider-vertical { - width: 14px; - height: 100%; - padding: 0 5px; -} - -.rc-slider-vertical .rc-slider-rail { - height: 100%; - width: 4px; -} - -.rc-slider-vertical .rc-slider-track { - left: 5px; - bottom: 0; - width: 4px; -} - -.rc-slider-vertical .rc-slider-handle { - margin-left: -5px; - margin-bottom: -7px; - -ms-touch-action: pan-y; - touch-action: pan-y; -} - -.rc-slider-vertical .rc-slider-mark { - top: 0; - left: 18px; - height: 100%; -} - -.rc-slider-vertical .rc-slider-step { - height: 100%; - width: 4px; -} - -.rc-slider-vertical .rc-slider-dot { - left: 2px; - margin-bottom: -4px; -} - -.rc-slider-vertical .rc-slider-dot:first-child { - margin-bottom: -4px; -} - -.rc-slider-vertical .rc-slider-dot:last-child { - margin-bottom: -4px; -} - -.rc-slider-tooltip-zoom-down-enter, -.rc-slider-tooltip-zoom-down-appear { - animation-duration: .3s; - animation-fill-mode: both; - display: block !important; - animation-play-state: paused; -} - -.rc-slider-tooltip-zoom-down-leave { - animation-duration: .3s; - animation-fill-mode: both; - display: block !important; - animation-play-state: paused; -} - -.rc-slider-tooltip-zoom-down-enter.rc-slider-tooltip-zoom-down-enter-active, -.rc-slider-tooltip-zoom-down-appear.rc-slider-tooltip-zoom-down-appear-active { - animation-name: rcSliderTooltipZoomDownIn; - animation-play-state: running; -} - -.rc-slider-tooltip-zoom-down-leave.rc-slider-tooltip-zoom-down-leave-active { - animation-name: rcSliderTooltipZoomDownOut; - animation-play-state: running; -} - -.rc-slider-tooltip-zoom-down-enter, -.rc-slider-tooltip-zoom-down-appear { - transform: scale(0, 0); - animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); -} - -.rc-slider-tooltip-zoom-down-leave { - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); -} - -@keyframes rcSliderTooltipZoomDownIn { - 0% { - opacity: 0; - transform-origin: 50% 100%; - transform: scale(0, 0); - } - - 100% { - transform-origin: 50% 100%; - transform: scale(1, 1); - } -} - -@keyframes rcSliderTooltipZoomDownOut { - 0% { - transform-origin: 50% 100%; - transform: scale(1, 1); - } - - 100% { - opacity: 0; - transform-origin: 50% 100%; - transform: scale(0, 0); - } -} - -.rc-slider-tooltip { - position: absolute; - left: -9999px; - top: -9999px; - visibility: visible; - box-sizing: border-box; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} - -.rc-slider-tooltip * { - box-sizing: border-box; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} - -.rc-slider-tooltip-hidden { - display: none; -} - -.rc-slider-tooltip-placement-top { - padding: 4px 0 8px 0; -} - -.rc-slider-tooltip-inner { - padding: 4px 6px 4px; - min-width: 24px; - height: 24px; - font-size: 12px; - line-height: 1; - color: #000; - text-align: center; - text-decoration: none; -} - -.rc-slider-tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} - -.rc-slider-tooltip-placement-top .rc-slider-tooltip-arrow { - bottom: 4px; - left: 50%; - margin-left: -4px; - border-width: 4px 4px 0; - border-top-color: #6c6c6c; -} diff --git a/packages/website/ts/pages/instant/select.tsx b/packages/website/ts/pages/instant/select.tsx deleted file mode 100644 index d4146cfb0..000000000 --- a/packages/website/ts/pages/instant/select.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -export interface SelectItemConfig { - label: string; - value?: string; - onClick?: () => void; -} - -interface SelectProps { - value?: string; - id: string; - items: SelectItemConfig[]; - emptyText?: string; - onChange?: (ev: React.ChangeEvent<HTMLSelectElement>) => void; - shouldIncludeEmpty: boolean; -} - -export const Select: React.FunctionComponent<SelectProps> = ({ - value, - id, - items, - shouldIncludeEmpty, - emptyText, - onChange, -}) => { - return ( - <Container> - <StyledSelect id={id} onChange={onChange}> - {shouldIncludeEmpty && <option value="">{emptyText}</option>} - {items.map((item, index) => ( - <option - key={`${id}-item-${index}`} - value={item.value} - selected={item.value === value} - onClick={item.onClick} - > - {item.label} - </option> - ))} - </StyledSelect> - <Caret width="12" height="7" fill="none" xmlns="http://www.w3.org/2000/svg"> - <path d="M11 1L6 6 1 1" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> - </Caret> - </Container> - ); -}; - -Select.defaultProps = { - emptyText: 'Select...', - shouldIncludeEmpty: true, -}; - -const Container = styled.div` - background-color: #fff; - border-radius: 4px; - display: flex; - width: 100%; - position: relative; -`; - -const StyledSelect = styled.select` - appearance: none; - border: 0; - font-size: 1rem; - width: 100%; - padding: 20px 20px 20px 20px; -`; - -const Caret = styled.svg` - position: absolute; - right: 20px; - top: calc(50% - 4px); -`; diff --git a/packages/website/ts/pages/landing.tsx b/packages/website/ts/pages/landing.tsx deleted file mode 100644 index b47d34dce..000000000 --- a/packages/website/ts/pages/landing.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; - -import { SectionLandingAbout } from 'ts/components/sections/landing/about'; -import { SectionLandingClients } from 'ts/components/sections/landing/clients'; -import { SectionLandingCta } from 'ts/components/sections/landing/cta'; -import { SectionLandingHero } from 'ts/components/sections/landing/hero'; -import { SiteWrap } from 'ts/components/siteWrap'; - -import { ModalContact } from 'ts/components/modals/modal_contact'; - -interface Props { - theme: { - bgColor: string; - textColor: string; - linkColor: string; - }; -} - -export class NextLanding extends React.Component<Props> { - public state = { - isContactModalOpen: false, - }; - public render(): React.ReactNode { - return ( - <SiteWrap theme="dark"> - <DocumentTitle title="0x: The protocol for trading tokens on Ethereum" /> - <SectionLandingHero /> - <SectionLandingAbout /> - <SectionLandingClients /> - <SectionLandingCta onContactClick={this._onOpenContactModal} /> - <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> - </SiteWrap> - ); - } - - public _onOpenContactModal = (): void => { - this.setState({ isContactModalOpen: true }); - }; - - public _onDismissContactModal = (): void => { - this.setState({ isContactModalOpen: false }); - }; -} diff --git a/packages/website/ts/pages/launch_kit.tsx b/packages/website/ts/pages/launch_kit.tsx deleted file mode 100644 index dd4de4d99..000000000 --- a/packages/website/ts/pages/launch_kit.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; - -import { Hero } from 'ts/components/hero'; - -import { Banner } from 'ts/components/banner'; -import { Button } from 'ts/components/button'; -import { Definition } from 'ts/components/definition'; -import { Icon } from 'ts/components/icon'; -import { SiteWrap } from 'ts/components/siteWrap'; - -import { Section } from 'ts/components/newLayout'; -import { constants } from 'ts/utils/constants'; - -import { ModalContact } from '../components/modals/modal_contact'; - -const offersData = [ - { - icon: 'supportForAllEthereumStandards', - title: 'Perfect for developers who need a simple drop-in marketplace', - description: ( - <ul> - <li>Quickly launch a market for your project’s token</li> - <li>Seamlessly create an in-game marketplace for digital items and collectables</li> - <li>Easily build a 0x relayer for your local market</li> - </ul> - ), - }, -]; - -export class NextLaunchKit extends React.Component { - public state = { - isContactModalOpen: false, - }; - public render(): React.ReactNode { - return ( - <SiteWrap theme="dark"> - <DocumentTitle title="0x Launch Kit: Launch a relayer in under a minute" /> - <Hero - isLargeTitle={false} - isFullWidth={false} - title="0x Launch Kit" - description="Launch a relayer in under a minute" - figure={<Icon name="launchKit" size="hero" margin={['small', 0, 'small', 0]} />} - actions={<HeroActions />} - /> - - <Section bgColor="dark" isFlex={true} maxWidth="1170px"> - <Definition - title="Networked Liquidity Pool" - titleSize="small" - description="Tap into and share liquidity with other relayers" - icon="networkedLiquidity" - iconSize="medium" - isInline={true} - /> - - <Definition - title="Extensible Code Repo" - titleSize="small" - description="Fork and extend to support modes of exchange" - icon="code-repo" - iconSize="medium" - isInline={true} - /> - - <Definition - title="Exchange Ethereum based Tokens" - titleSize="small" - description="Enable trading for any ERC-20 or ERC-721 asset" - icon="eth-based-tokens" - iconSize="medium" - isInline={true} - /> - </Section> - - <Section> - {_.map(offersData, (item, index) => ( - <Definition - key={`offers-${index}`} - icon={item.icon} - title={item.title} - description={item.description} - isInlineIcon={true} - iconSize={240} - /> - ))} - </Section> - - <Banner - heading="Need more flexibility?" - subline="Dive into our docs, or contact us if needed" - mainCta={{ - text: 'Get Started', - href: `${constants.URL_LAUNCH_KIT}/#table-of-contents`, - shouldOpenInNewTab: true, - }} - secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} - /> - <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> - </SiteWrap> - ); - } - - public _onOpenContactModal = (): void => { - this.setState({ isContactModalOpen: true }); - }; - - public _onDismissContactModal = (): void => { - this.setState({ isContactModalOpen: false }); - }; -} - -const HeroActions = () => ( - <React.Fragment> - <Button href={constants.URL_LAUNCH_KIT} isInline={true} target="_blank"> - Get Started - </Button> - - <Button href={constants.URL_LAUNCH_KIT_BLOG_POST} isTransparent={true} isInline={true} target="_blank"> - Learn More! - </Button> - </React.Fragment> -); diff --git a/packages/website/ts/pages/market_maker.tsx b/packages/website/ts/pages/market_maker.tsx deleted file mode 100644 index 854870358..000000000 --- a/packages/website/ts/pages/market_maker.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import * as _ from 'lodash'; -import { opacify } from 'polished'; -import * as React from 'react'; - -import { Banner } from 'ts/components/banner'; -import { Button } from 'ts/components/button'; -import { Action, Definition } from 'ts/components/definition'; -import { Hero } from 'ts/components/hero'; -import { ModalContact, ModalContactType } from 'ts/components/modals/modal_contact'; -import { Section } from 'ts/components/newLayout'; -import { SiteWrap } from 'ts/components/siteWrap'; -import { colors } from 'ts/style/colors'; -import { WebsitePaths } from 'ts/types'; - -interface OfferData { - icon: string; - title: string; - description: string; - links?: Action[]; -} -export interface NextMarketMakerProps {} - -export class NextMarketMaker extends React.Component<NextMarketMakerProps> { - public state = { - isContactModalOpen: false, - }; - - private readonly _offersData: OfferData[]; - - constructor(props: NextMarketMakerProps) { - super(props); - this._offersData = [ - { - icon: 'supportForAllEthereumStandards', - title: 'Comprehensive Tutorials', - description: - 'Stay on the bleeding edge of crypto by learning how to market make on decentralized exchanges. The network of 0x relayers provides market makers a first-mover advantage to capture larger spreads, find arbitrage opportunities, and trade on new types of exchanges like prediction markets and non-fungible token marketplaces.', - links: [ - { - label: 'Explore the Docs', - url: `${WebsitePaths.Wiki}#Market-Making-on-0x`, - }, - ], - }, - { - icon: 'generateRevenueForYourBusiness-large', - title: 'Market Making Compensation', - description: 'Accepted applicants can receive up to $15,000 for completing onboarding', - }, - { - icon: 'getInTouch', - title: 'Dedicated Support', - description: - 'The 0x team will provide 1:1 onboarding assistance and promptly answer all your questions. They will walk you through the tutorials so that you know how to read 0x order types, spin up an Ethereum node, and execute trades on the blockchain.', - links: [ - { - label: 'Contact Us', - onClick: this._onOpenContactModal, - shouldUseAnchorTag: true, - }, - ], - }, - ]; - } - - public render(): React.ReactNode { - return ( - <SiteWrap theme="light"> - <Hero - maxWidth="865px" - maxWidthHeading="715px" - isLargeTitle={false} - isFullWidth={false} - isCenteredMobile={false} - title="Bring liquidity to the markets of the future" - description="Market makers (MMs) are important stakeholders in the 0x ecosystem. The Market Making Program provides a set of resources that help onboard MMs to bring liquidity to the 0x network. The Program includes tutorials, monetary incentives, and 1:1 support from the 0x team." - actions={this._renderHeroActions()} - /> - - <Section bgColor="light" isFlex={true} maxWidth="1170px"> - <Definition - title="Secure Trading" - titleSize="small" - description="Take full custody of your assets to eliminate counterparty risk" - icon="secureTrading" - iconSize="medium" - isInline={true} - /> - - <Definition - title="Networked Liquidity Pool" - titleSize="small" - description="Use one pool of capital across multiple relayers to trade against a large group of takers" - icon="networkedLiquidity" - iconSize="medium" - isInline={true} - /> - - <Definition - title="Low Cost" - titleSize="small" - description="Pay no gas fees to make 0x orders" - icon="low-cost" - iconSize="medium" - isInline={true} - /> - </Section> - - <Section> - {_.map(this._offersData, (item, index) => ( - <Definition - key={`offers-${index}`} - icon={item.icon} - title={item.title} - description={item.description} - isInlineIcon={true} - iconSize={240} - fontSize="medium" - actions={item.links} - /> - ))} - </Section> - - <Banner - heading="Start trading today." - subline="Check out our Market Making tutorials to get started" - mainCta={{ text: 'Tutorials', href: `${WebsitePaths.Wiki}#Market-Making-on-0x` }} - secondaryCta={{ text: 'Apply Now', onClick: this._onOpenContactModal }} - /> - <ModalContact - isOpen={this.state.isContactModalOpen} - onDismiss={this._onDismissContactModal} - modalContactType={ModalContactType.MarketMaker} - /> - </SiteWrap> - ); - } - - private readonly _onOpenContactModal = (): void => { - this.setState({ isContactModalOpen: true }); - }; - - private readonly _onDismissContactModal = (): void => { - this.setState({ isContactModalOpen: false }); - }; - - private readonly _renderHeroActions = () => ( - <> - <Button href={`${WebsitePaths.Wiki}#Market-Making-on-0x`} bgColor="dark" isInline={true}> - Get Started - </Button> - <Button - onClick={this._onOpenContactModal} - borderColor={opacify(0.4)(colors.brandDark)} - isTransparent={true} - isInline={true} - > - Apply Now - </Button> - </> - ); -} diff --git a/packages/website/ts/pages/not_found.tsx b/packages/website/ts/pages/not_found.tsx deleted file mode 100644 index 6abd8fc80..000000000 --- a/packages/website/ts/pages/not_found.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import * as React from 'react'; -import { Footer } from 'ts/components/old_footer'; -import { TopBar } from 'ts/components/top_bar/top_bar'; -import { FullscreenMessage } from 'ts/pages/fullscreen_message'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { Translate } from 'ts/utils/translate'; - -export interface NotFoundProps { - location: Location; - translate: Translate; - dispatcher: Dispatcher; -} - -export const NotFound = (props: NotFoundProps) => { - return ( - <div> - <TopBar blockchainIsLoaded={false} location={props.location} translate={props.translate} /> - <FullscreenMessage - headerText={'404 Not Found'} - bodyText={"Hm... looks like we couldn't find what you are looking for."} - /> - <Footer translate={props.translate} dispatcher={props.dispatcher} /> - </div> - ); -}; diff --git a/packages/website/ts/pages/why.tsx b/packages/website/ts/pages/why.tsx deleted file mode 100644 index 48888d10a..000000000 --- a/packages/website/ts/pages/why.tsx +++ /dev/null @@ -1,302 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import DocumentTitle from 'react-document-title'; -import ScrollableAnchor, { configureAnchors } from 'react-scrollable-anchor'; -import styled from 'styled-components'; - -import { Banner } from 'ts/components/banner'; -import { Button } from 'ts/components/button'; -import { Definition } from 'ts/components/definition'; -import { Hero } from 'ts/components/hero'; -import { Column, Section, WrapSticky } from 'ts/components/newLayout'; -import { SiteWrap } from 'ts/components/siteWrap'; -import { Slide, Slider } from 'ts/components/slider/slider'; -import { Heading } from 'ts/components/text'; - -import { ModalContact } from '../components/modals/modal_contact'; - -const offersData = [ - { - icon: 'robustSmartContracts', - title: 'Robust Smart Contracts', - description: `0x Protocol's smart contracts have been put through two rounds of rigorous security audits.`, - }, - { - icon: 'extensibleArchitecture', - title: 'Extensible Architecture', - description: `0x's modular pipeline enables you to plug in your own smart contracts through an extensible API.`, - }, - { - icon: 'eficientDesign', - title: 'Efficient Design', - description: `0x’s off-chain order relay with on-chain settlement is a gas efficient approach to p2p exchange, reducing blockchain bloat.`, - }, -]; - -const functionalityData = [ - { - icon: 'secureTrading', - title: 'Secure Non-custodial Trading', - description: 'Enable tokens to be traded wallet-to-wallet with no deposits or withdrawals.', - }, - { - icon: 'flexibleOrders', - title: 'Flexible Order Types', - description: 'Choose to sell assets at a specific “buy it now” price or allow potential buyers to submit bids.', - }, - { - icon: 'buildBusiness', - title: 'Build a Business', - description: - 'Monetize your product by taking fees on each transaction and join a growing number of relayers in the 0x ecosystem.', - }, -]; - -const useCaseSlides = [ - { - icon: 'gamingAndCollectibles', - title: 'Games & Collectibles', - description: - 'Artists and game makers are tokenizing digital art and in-game items known as non-fungible tokens (NFTs). 0x enables these creators to add exchange functionality by providing the ability to build marketplaces for NFT trading.', - }, - { - icon: 'predictionMarkets', - title: 'Prediction Markets', - description: - 'Decentralized prediction markets and cryptodervivative platforms generate sets of tokens that represent a financial stake in the outcomes of events. 0x allows these tokens to be instantly tradable in liquid markets.', - }, - { - icon: 'orderBooks', - title: 'Order Books', - description: - 'There are thousands of decentralized apps and protocols that have native utility tokens. 0x provides professional exchanges with the ability to host order books and facilitates the exchange of these assets.', - }, - { - icon: 'decentralisedLoans', - title: 'Decentralized Loans', - description: - 'Efficient lending requires liquid markets where investors can buy and re-sell loans. 0x enables an ecosystem of lenders to self-organize and efficiently determine market prices for all outstanding loans.', - }, - { - icon: 'stableTokens', - title: 'Stable Tokens', - description: - 'Novel economic constructs such as stable coins require efficient, liquid markets to succeed. 0x will facilitate the underlying economic mechanisms that allow these tokens to remain stable.', - }, -]; - -configureAnchors({ offset: -60 }); - -export class NextWhy extends React.Component { - public state = { - isContactModalOpen: false, - }; - public render(): React.ReactNode { - const buildAction = ( - <Button href="/docs" isWithArrow={true} isAccentColor={true}> - Build on 0x - </Button> - ); - return ( - <SiteWrap theme="dark"> - <DocumentTitle title="Features & Benefits - 0x" /> - <Hero - title="The exchange layer for the crypto economy" - description="The world's assets are becoming tokenized on public blockchains. 0x Protocol is free, open-source infrastructure that developers and businesses utilize to build products that enable the purchasing and trading of crypto tokens." - actions={buildAction} - /> - - <Section bgColor="dark" isFlex={true} maxWidth="1170px"> - <Definition - title="Support for all Ethereum Standards" - titleSize="small" - description="0x Protocol facilitates the decentralized exchange of a growing number of Ethereum-based tokens, including all ERC-20 and ERC-721 assets." - icon="supportForAllEthereumStandards" - iconSize="large" - isInline={true} - /> - - <Definition - title="Networked Liquidity" - titleSize="small" - description="0x is lowering the barrier to entry by building a layer of networked liquidity that allows businesses to tap into a shared pool of digital assets." - icon="networkedLiquidity" - iconSize="large" - isInline={true} - /> - - <Definition - title="Flexible Integration" - titleSize="small" - description="0x is a modular system that enables businesses and projects, known as relayers, to easily add exchange functionality to any product experience." - icon="flexibleIntegration" - iconSize="large" - isInline={true} - /> - </Section> - - <Section maxWidth="1170px" isFlex={true} isFullWidth={true}> - <Column> - <NavStickyWrap offsetTop="130px"> - <ChapterLink href="#benefits">Benefits</ChapterLink> - <ChapterLink href="#cases">Use Cases</ChapterLink> - <ChapterLink href="#functionality">Features</ChapterLink> - </NavStickyWrap> - </Column> - - <Column width="55%" maxWidth="826px"> - <Column width="100%" maxWidth="560px" padding="0 30px 0 0"> - <ScrollableAnchor id="benefits"> - <SectionWrap> - <SectionTitle size="medium" marginBottom="60px" isNoBorder={true}> - What 0x offers - </SectionTitle> - - {_.map(offersData, (item, index) => ( - <Definition - key={`offers-${index}`} - icon={item.icon} - title={item.title} - titleSize="small" - description={item.description} - isWithMargin={true} - /> - ))} - </SectionWrap> - </ScrollableAnchor> - - <ScrollableAnchor id="cases"> - <SectionWrap isNotRelative={true}> - <SectionTitle size="medium" marginBottom="60px"> - Use Cases - </SectionTitle> - <Slider> - {_.map(useCaseSlides, (item, index) => ( - <Slide - key={`useCaseSlide-${index}`} - heading={item.title} - text={item.description} - icon={item.icon} - /> - ))} - </Slider> - </SectionWrap> - </ScrollableAnchor> - - <ScrollableAnchor id="functionality"> - <SectionWrap> - <SectionTitle size="medium" marginBottom="60px"> - Exchange Functionality - </SectionTitle> - - {_.map(functionalityData, (item, index) => ( - <Definition - key={`functionality-${index}`} - icon={item.icon} - title={item.title} - titleSize="small" - description={item.description} - isWithMargin={true} - /> - ))} - </SectionWrap> - </ScrollableAnchor> - </Column> - </Column> - </Section> - - <Banner - heading="Ready to get started?" - subline="Dive into our docs, or contact us if needed" - mainCta={{ text: 'Get Started', href: '/docs' }} - secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} - /> - <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> - </SiteWrap> - ); - } - - public _onOpenContactModal = (): void => { - this.setState({ isContactModalOpen: true }); - }; - - public _onDismissContactModal = (): void => { - this.setState({ isContactModalOpen: false }); - }; -} - -interface SectionProps { - isNotRelative?: boolean; -} - -const SectionWrap = styled.div<SectionProps>` - position: ${props => !props.isNotRelative && 'relative'}; - - & + & { - padding-top: 60px; - margin-top: 60px; - } - - @media (min-width: 768px) { - & + &:before { - width: 100vw; - } - } - - @media (max-width: 768px) { - text-align: left; - - & + &:before { - width: 100%; - } - } -`; - -interface SectionTitleProps { - isNoBorder?: boolean; -} -const SectionTitle = styled(Heading)<SectionTitleProps>` - position: relative; - - ${props => - !props.isNoBorder && - ` - &:before { - content: ''; - width: 100vw; - position: absolute; - top: -53px; - left: 0; - height: 1px; - background-color: #3d3d3d; - } - `} - - @media (max-width: 768px) { - &:before { - width: calc(100vw - 60px); - } - } -`; - -const NavStickyWrap = styled(WrapSticky)` - padding-left: 60px; - z-index: 15; - - @media (max-width: 768px) { - display: none; - } -`; - -const ChapterLink = styled.a` - color: ${props => props.theme.textColor}; - font-size: 22px; - margin-bottom: 25px; - display: block; - opacity: 0.8; - - &:hover, - &:active { - opacity: 1; - } -`; diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx deleted file mode 100644 index c3c1600a5..000000000 --- a/packages/website/ts/pages/wiki/wiki.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import { - ALink, - colors, - constants as sharedConstants, - HeaderSizes, - Link, - MarkdownSection, - utils as sharedUtils, -} from '@0x/react-shared'; -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; -import CircularProgress from 'material-ui/CircularProgress'; -import * as React from 'react'; -import { SidebarHeader } from 'ts/components/documentation/sidebar_header'; -import { NestedSidebarMenu } from 'ts/components/nested_sidebar_menu'; -import { Button } from 'ts/components/ui/button'; -import { Container } from 'ts/components/ui/container'; -import { DevelopersPage } from 'ts/pages/documentation/developers_page'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { Article, ArticlesBySection, Deco, Key, ScreenWidths } from 'ts/types'; -import { backendClient } from 'ts/utils/backend_client'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; -import { utils } from 'ts/utils/utils'; - -const WIKI_NOT_READY_BACKOUT_TIMEOUT_MS = 5000; - -export interface WikiProps { - source: string; - location: Location; - dispatcher: Dispatcher; - translate: Translate; - screenWidth: ScreenWidths; -} - -interface WikiState { - articlesBySection: ArticlesBySection; - isHoveringSidebar: boolean; -} - -export class Wiki extends React.Component<WikiProps, WikiState> { - private _wikiBackoffTimeoutId: number; - private _isUnmounted: boolean; - constructor(props: WikiProps) { - super(props); - this._isUnmounted = false; - this.state = { - articlesBySection: undefined, - isHoveringSidebar: false, - }; - } - public componentWillMount(): void { - // tslint:disable-next-line:no-floating-promises - this._fetchArticlesBySectionAsync(); - } - public componentWillUnmount(): void { - this._isUnmounted = true; - clearTimeout(this._wikiBackoffTimeoutId); - } - public render(): React.ReactNode { - const sectionNameToLinks = _.isUndefined(this.state.articlesBySection) - ? {} - : this._getSectionNameToLinks(this.state.articlesBySection); - - const mainContent = _.isUndefined(this.state.articlesBySection) ? ( - <div className="flex justify-center">{this._renderLoading()}</div> - ) : ( - <div id="wiki" style={{ paddingRight: 2 }}> - {this._renderWikiArticles()} - </div> - ); - const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; - const sidebar = _.isUndefined(this.state.articlesBySection) ? ( - <div /> - ) : ( - <NestedSidebarMenu - sidebarHeader={isSmallScreen ? this._renderSidebarHeader() : undefined} - sectionNameToLinks={sectionNameToLinks} - screenWidth={this.props.screenWidth} - /> - ); - return ( - <DevelopersPage - sidebar={sidebar} - mainContent={mainContent} - location={this.props.location} - screenWidth={this.props.screenWidth} - translate={this.props.translate} - dispatcher={this.props.dispatcher} - /> - ); - } - private _renderSidebarHeader(): React.ReactNode { - const menuItems = _.map(constants.DEVELOPER_TOPBAR_LINKS, menuItemInfo => { - return ( - <Link - key={`menu-item-${menuItemInfo.title}`} - to={menuItemInfo.to} - shouldOpenInNewTab={menuItemInfo.shouldOpenInNewTab} - > - <Button - borderRadius="4px" - padding="0.4em 0.375em" - width="100%" - fontColor={colors.grey800} - fontSize="14px" - textAlign="left" - > - {this.props.translate.get(menuItemInfo.title as Key, Deco.Cap)} - </Button> - </Link> - ); - }); - const wikiTitle = this.props.translate.get(Key.Wiki, Deco.Cap); - return ( - <Container> - <SidebarHeader screenWidth={this.props.screenWidth} title={wikiTitle} /> - {menuItems} - </Container> - ); - } - private _renderLoading(): React.ReactNode { - return ( - <Container className="pt4"> - <Container className="center pb2"> - <CircularProgress size={40} thickness={5} /> - </Container> - <Container className="center pt2" paddingBottom="11px"> - Loading wiki... - </Container> - </Container> - ); - } - private _renderWikiArticles(): React.ReactNode { - const sectionNames = _.keys(this.state.articlesBySection); - const sections = _.map(sectionNames, sectionName => this._renderSection(sectionName)); - return sections; - } - private _renderSection(sectionName: string): React.ReactNode { - const articles = this.state.articlesBySection[sectionName]; - const renderedArticles = _.map(articles, (article: Article) => { - const githubLink = `${constants.URL_GITHUB_WIKI}/edit/master/${sectionName}/${article.fileName}`; - return ( - <div key={`markdown-section-${article.title}`}> - <MarkdownSection - sectionName={article.title} - markdownContent={article.content} - headerSize={HeaderSizes.H2} - githubLink={githubLink} - /> - </div> - ); - }); - return <div key={`section-${sectionName}`}>{renderedArticles}</div>; - } - private async _fetchArticlesBySectionAsync(): Promise<void> { - try { - const articlesBySection = await backendClient.getWikiArticlesBySectionAsync(); - if (!this._isUnmounted) { - this.setState( - { - articlesBySection, - }, - async () => { - await utils.onPageLoadPromise; - const hash = this.props.location.hash.slice(1); - sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); - }, - ); - } - } catch (err) { - const errMsg = `${err}`; - if (_.includes(errMsg, `${constants.HTTP_NO_CONTENT_STATUS_CODE}`)) { - // We need to backoff and try fetching again later - this._wikiBackoffTimeoutId = window.setTimeout(() => { - // tslint:disable-next-line:no-floating-promises - this._fetchArticlesBySectionAsync(); - }, WIKI_NOT_READY_BACKOUT_TIMEOUT_MS); - return; - } - } - } - private _getSectionNameToLinks(articlesBySection: ArticlesBySection): ObjectMap<ALink[]> { - const sectionNames = _.keys(articlesBySection); - const sectionNameToLinks: ObjectMap<ALink[]> = {}; - for (const sectionName of sectionNames) { - const articles = articlesBySection[sectionName]; - const articleLinks = _.map(articles, article => { - return { - to: sharedUtils.getIdFromName(article.title), - title: article.title, - }; - }); - sectionNameToLinks[sectionName] = articleLinks; - } - return sectionNameToLinks; - } -} diff --git a/packages/website/ts/redux/analyticsMiddleware.ts b/packages/website/ts/redux/analyticsMiddleware.ts deleted file mode 100644 index 51d39a5d7..000000000 --- a/packages/website/ts/redux/analyticsMiddleware.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Middleware } from 'redux'; -import { State } from 'ts/redux/reducer'; -import { ActionTypes } from 'ts/types'; -import { analytics } from 'ts/utils/analytics'; - -export const analyticsMiddleware: Middleware = store => next => action => { - const nextAction = next(action); - const nextState = (store.getState() as any) as State; - switch (action.type) { - case ActionTypes.UpdateInjectedProviderName: - analytics.addEventProperties({ - injectedProviderName: nextState.injectedProviderName, - }); - break; - case ActionTypes.UpdateNetworkId: - analytics.addEventProperties({ - networkId: nextState.networkId, - }); - break; - case ActionTypes.UpdateUserAddress: - analytics.addUserProperties({ - ethAddress: nextState.userAddress, - }); - break; - case ActionTypes.UpdateUserEtherBalance: - if (nextState.userEtherBalanceInWei) { - analytics.addUserProperties({ - ethBalance: nextState.userEtherBalanceInWei.toString(), - }); - } - break; - default: - break; - } - return nextAction; -}; diff --git a/packages/website/ts/redux/dispatcher.ts b/packages/website/ts/redux/dispatcher.ts deleted file mode 100644 index e85afd3b1..000000000 --- a/packages/website/ts/redux/dispatcher.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import { Dispatch } from 'redux'; -import { State } from 'ts/redux/reducer'; -import { - ActionTypes, - AssetToken, - BlockchainErrs, - Language, - PortalOrder, - ProviderType, - ScreenWidths, - Side, - SideToAssetToken, - Token, - TokenByAddress, -} from 'ts/types'; - -export class Dispatcher { - private readonly _dispatch: Dispatch<State>; - constructor(dispatch: Dispatch<State>) { - this._dispatch = dispatch; - } - // Portal - public resetState(): void { - this._dispatch({ - type: ActionTypes.ResetState, - }); - } - public updateNodeVersion(nodeVersion: string): void { - this._dispatch({ - data: nodeVersion, - type: ActionTypes.UpdateNodeVersion, - }); - } - public updateScreenWidth(screenWidth: ScreenWidths): void { - this._dispatch({ - data: screenWidth, - type: ActionTypes.UpdateScreenWidth, - }); - } - public swapAssetTokenSymbols(): void { - this._dispatch({ - type: ActionTypes.SwapAssetTokens, - }); - } - public updateOrderSalt(salt: BigNumber): void { - this._dispatch({ - data: salt, - type: ActionTypes.UpdateOrderSalt, - }); - } - public updateUserSuppliedOrderCache(order: PortalOrder): void { - this._dispatch({ - data: order, - type: ActionTypes.UpdateUserSuppliedOrderCache, - }); - } - public updateShouldBlockchainErrDialogBeOpen(shouldBeOpen: boolean): void { - this._dispatch({ - data: shouldBeOpen, - type: ActionTypes.UpdateShouldBlockchainErrDialogBeOpen, - }); - } - public updateChosenAssetToken(side: Side, token: AssetToken): void { - this._dispatch({ - data: { - side, - token, - }, - type: ActionTypes.UpdateChosenAssetToken, - }); - } - public updateChosenAssetTokenAddress(side: Side, address: string): void { - this._dispatch({ - data: { - address, - side, - }, - type: ActionTypes.UpdateChosenAssetTokenAddress, - }); - } - public updateOrderTakerAddress(address: string): void { - this._dispatch({ - data: address, - type: ActionTypes.UpdateOrderTakerAddress, - }); - } - public updateUserAddress(address?: string): void { - this._dispatch({ - data: address, - type: ActionTypes.UpdateUserAddress, - }); - } - public updateOrderExpiry(unixTimestampSec: BigNumber): void { - this._dispatch({ - data: unixTimestampSec, - type: ActionTypes.UpdateOrderExpiry, - }); - } - public encounteredBlockchainError(err: BlockchainErrs): void { - this._dispatch({ - data: err, - type: ActionTypes.BlockchainErrEncountered, - }); - } - public updateBlockchainIsLoaded(isLoaded: boolean): void { - this._dispatch({ - data: isLoaded, - type: ActionTypes.UpdateBlockchainIsLoaded, - }); - } - public addTokenToTokenByAddress(token: Token): void { - this._dispatch({ - data: token, - type: ActionTypes.AddTokenToTokenByAddress, - }); - } - public removeTokenToTokenByAddress(token: Token): void { - this._dispatch({ - data: token, - type: ActionTypes.RemoveTokenFromTokenByAddress, - }); - } - public batchDispatch( - tokenByAddress: TokenByAddress, - networkId: number, - userAddressIfExists: string | undefined, - sideToAssetToken: SideToAssetToken, - ): void { - this._dispatch({ - data: { - tokenByAddress, - networkId, - userAddressIfExists, - sideToAssetToken, - }, - type: ActionTypes.BatchDispatch, - }); - } - public updateTokenByAddress(tokens: Token[]): void { - this._dispatch({ - data: tokens, - type: ActionTypes.UpdateTokenByAddress, - }); - } - public forceTokenStateRefetch(): void { - this._dispatch({ - type: ActionTypes.ForceTokenStateRefetch, - }); - } - public updateSignature(signature: string): void { - this._dispatch({ - data: signature, - type: ActionTypes.UpdateOrderSignature, - }); - } - public updateUserWeiBalance(balance?: BigNumber): void { - this._dispatch({ - data: balance, - type: ActionTypes.UpdateUserEtherBalance, - }); - } - public updateNetworkId(networkId: number): void { - this._dispatch({ - data: networkId, - type: ActionTypes.UpdateNetworkId, - }); - } - public updateOrderFillAmount(amount: BigNumber): void { - this._dispatch({ - data: amount, - type: ActionTypes.UpdateOrderFillAmount, - }); - } - - public updatePortalOnboardingShowing(isShowing: boolean): void { - this._dispatch({ - data: isShowing, - type: ActionTypes.UpdatePortalOnboardingShowing, - }); - } - - // Docs - public updateCurrentDocsVersion(version: string): void { - this._dispatch({ - data: version, - type: ActionTypes.UpdateLibraryVersion, - }); - } - public updateAvailableDocVersions(versions: string[]): void { - this._dispatch({ - data: versions, - type: ActionTypes.UpdateAvailableLibraryVersions, - }); - } - - // Shared - public showFlashMessage(msg: string | React.ReactNode): void { - this._dispatch({ - data: msg, - type: ActionTypes.ShowFlashMessage, - }); - } - public hideFlashMessage(): void { - this._dispatch({ - type: ActionTypes.HideFlashMessage, - }); - } - public updateProviderType(providerType: ProviderType): void { - this._dispatch({ - type: ActionTypes.UpdateProviderType, - data: providerType, - }); - } - public updateInjectedProviderName(injectedProviderName: string): void { - this._dispatch({ - type: ActionTypes.UpdateInjectedProviderName, - data: injectedProviderName, - }); - } - public updateSelectedLanguage(language: Language): void { - this._dispatch({ - type: ActionTypes.UpdateSelectedLanguage, - data: language, - }); - } -} diff --git a/packages/website/ts/redux/reducer.ts b/packages/website/ts/redux/reducer.ts deleted file mode 100644 index 51c77ba47..000000000 --- a/packages/website/ts/redux/reducer.ts +++ /dev/null @@ -1,361 +0,0 @@ -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import * as moment from 'moment'; -import { - Action, - ActionTypes, - BlockchainErrs, - PortalOrder, - ProviderType, - ScreenWidths, - Side, - SideToAssetToken, - TokenByAddress, -} from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; -import { utils } from 'ts/utils/utils'; - -// Instead of defaulting the docs version to an empty string, we pre-populate it with -// a valid version value. This does not need to be updated however, since onLoad, it -// is always replaced with a value retrieved from our S3 bucket. -const DEFAULT_DOCS_VERSION = '0.0.0'; - -export interface State { - // Portal - blockchainErr: BlockchainErrs; - blockchainIsLoaded: boolean; - networkId: number; - orderExpiryTimestamp: BigNumber; - orderFillAmount: BigNumber; - orderTakerAddress: string; - orderSignature: string; - orderSalt: BigNumber; - nodeVersion: string; - screenWidth: ScreenWidths; - shouldBlockchainErrDialogBeOpen: boolean; - sideToAssetToken: SideToAssetToken; - tokenByAddress: TokenByAddress; - lastForceTokenStateRefetch: number; - userAddress: string; - userEtherBalanceInWei?: BigNumber; - portalOnboardingStep: number; - isPortalOnboardingShowing: boolean; - hasPortalOnboardingBeenClosed: boolean; - // Note: cache of supplied orderJSON in fill order step. Do not use for anything else. - userSuppliedOrderCache: PortalOrder; - - // Docs - docsVersion: string; - availableDocVersions: string[]; - - // Shared - flashMessage: string | React.ReactNode; - providerType: ProviderType; - injectedProviderName: string; - translate: Translate; -} - -export const INITIAL_STATE: State = { - // Portal - blockchainErr: BlockchainErrs.NoError, - blockchainIsLoaded: false, - networkId: undefined, - orderExpiryTimestamp: utils.initialOrderExpiryUnixTimestampSec(), - orderFillAmount: undefined, - orderSignature: '', - orderTakerAddress: constants.NULL_ADDRESS, - orderSalt: generatePseudoRandomSalt(), - nodeVersion: undefined, - screenWidth: utils.getScreenWidth(), - shouldBlockchainErrDialogBeOpen: false, - sideToAssetToken: { - [Side.Deposit]: {}, - [Side.Receive]: {}, - }, - tokenByAddress: {}, - lastForceTokenStateRefetch: moment().unix(), - userAddress: '', - userEtherBalanceInWei: undefined, - userSuppliedOrderCache: undefined, - portalOnboardingStep: 0, - isPortalOnboardingShowing: false, - hasPortalOnboardingBeenClosed: false, - // Docs - docsVersion: DEFAULT_DOCS_VERSION, - availableDocVersions: [DEFAULT_DOCS_VERSION], - // Shared - flashMessage: undefined, - providerType: ProviderType.Injected, - injectedProviderName: '', - translate: new Translate(), -}; - -export function reducer(state: State = INITIAL_STATE, action: Action): State { - switch (action.type) { - // Portal - case ActionTypes.ResetState: - return { - ...INITIAL_STATE, - translate: state.translate, - }; - - case ActionTypes.UpdateOrderSalt: { - return { - ...state, - orderSalt: action.data, - }; - } - - case ActionTypes.UpdateSelectedLanguage: { - return { - ...state, - translate: new Translate(action.data), - }; - } - - case ActionTypes.UpdateNodeVersion: { - return { - ...state, - nodeVersion: action.data, - }; - } - - case ActionTypes.UpdateOrderFillAmount: { - return { - ...state, - orderFillAmount: action.data, - }; - } - - case ActionTypes.UpdateShouldBlockchainErrDialogBeOpen: { - return { - ...state, - shouldBlockchainErrDialogBeOpen: action.data, - }; - } - - case ActionTypes.UpdateUserEtherBalance: { - return { - ...state, - userEtherBalanceInWei: action.data, - }; - } - - case ActionTypes.UpdateUserSuppliedOrderCache: { - return { - ...state, - userSuppliedOrderCache: action.data, - }; - } - - case ActionTypes.AddTokenToTokenByAddress: { - const newTokenByAddress = { ...state.tokenByAddress }; - newTokenByAddress[action.data.address] = action.data; - return { - ...state, - tokenByAddress: newTokenByAddress, - }; - } - - case ActionTypes.RemoveTokenFromTokenByAddress: { - const newTokenByAddress = { ...state.tokenByAddress }; - delete newTokenByAddress[action.data.address]; - return { - ...state, - tokenByAddress: newTokenByAddress, - }; - } - - case ActionTypes.UpdateTokenByAddress: { - const tokenByAddress = { ...state.tokenByAddress }; - const tokens = action.data; - _.each(tokens, token => { - const updatedToken = { - ...tokenByAddress[token.address], - ...token, - }; - tokenByAddress[token.address] = updatedToken; - }); - return { - ...state, - tokenByAddress, - }; - } - - case ActionTypes.BatchDispatch: { - const userAddress = _.isUndefined(action.data.userAddressIfExists) ? '' : action.data.userAddressIfExists; - return { - ...state, - networkId: action.data.networkId, - userAddress, - sideToAssetToken: action.data.sideToAssetToken, - tokenByAddress: action.data.tokenByAddress, - }; - } - - case ActionTypes.ForceTokenStateRefetch: - return { - ...state, - lastForceTokenStateRefetch: moment().unix(), - }; - - case ActionTypes.UpdateOrderSignature: { - return { - ...state, - orderSignature: action.data, - }; - } - - case ActionTypes.UpdateScreenWidth: { - return { - ...state, - screenWidth: action.data, - }; - } - - case ActionTypes.UpdateBlockchainIsLoaded: { - return { - ...state, - blockchainIsLoaded: action.data, - }; - } - - case ActionTypes.BlockchainErrEncountered: { - return { - ...state, - blockchainErr: action.data, - }; - } - - case ActionTypes.UpdateNetworkId: { - return { - ...state, - networkId: action.data, - }; - } - - case ActionTypes.UpdateChosenAssetToken: { - const newSideToAssetToken = { - ...state.sideToAssetToken, - [action.data.side]: action.data.token, - }; - return { - ...state, - sideToAssetToken: newSideToAssetToken, - }; - } - - case ActionTypes.UpdateChosenAssetTokenAddress: { - const newAssetToken = { ...state.sideToAssetToken[action.data.side] }; - newAssetToken.address = action.data.address; - const newSideToAssetToken = { - ...state.sideToAssetToken, - [action.data.side]: newAssetToken, - }; - return { - ...state, - sideToAssetToken: newSideToAssetToken, - }; - } - - case ActionTypes.SwapAssetTokens: { - const newSideToAssetToken = { - [Side.Deposit]: state.sideToAssetToken[Side.Receive], - [Side.Receive]: state.sideToAssetToken[Side.Deposit], - }; - return { - ...state, - sideToAssetToken: newSideToAssetToken, - }; - } - - case ActionTypes.UpdateOrderExpiry: { - return { - ...state, - orderExpiryTimestamp: action.data, - }; - } - - case ActionTypes.UpdateOrderTakerAddress: { - return { - ...state, - orderTakerAddress: action.data, - }; - } - - case ActionTypes.UpdateUserAddress: { - const userAddress = _.isUndefined(action.data) ? '' : action.data; - return { - ...state, - userAddress, - }; - } - - case ActionTypes.UpdatePortalOnboardingStep: { - const portalOnboardingStep = action.data; - return { - ...state, - portalOnboardingStep, - }; - } - - case ActionTypes.UpdatePortalOnboardingShowing: { - const isPortalOnboardingShowing = action.data; - return { - ...state, - isPortalOnboardingShowing, - hasPortalOnboardingBeenClosed: !isPortalOnboardingShowing ? true : state.hasPortalOnboardingBeenClosed, - // always start onboarding from the beginning - portalOnboardingStep: 0, - }; - } - - // Docs - case ActionTypes.UpdateLibraryVersion: { - return { - ...state, - docsVersion: action.data, - }; - } - case ActionTypes.UpdateAvailableLibraryVersions: { - return { - ...state, - availableDocVersions: action.data, - }; - } - - // Shared - case ActionTypes.ShowFlashMessage: { - return { - ...state, - flashMessage: action.data, - }; - } - - case ActionTypes.HideFlashMessage: { - return { - ...state, - flashMessage: undefined, - }; - } - - case ActionTypes.UpdateProviderType: { - return { - ...state, - providerType: action.data, - }; - } - - case ActionTypes.UpdateInjectedProviderName: { - return { - ...state, - injectedProviderName: action.data, - }; - } - - default: - return state; - } -} diff --git a/packages/website/ts/redux/store.ts b/packages/website/ts/redux/store.ts deleted file mode 100644 index 006241371..000000000 --- a/packages/website/ts/redux/store.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as _ from 'lodash'; -import { applyMiddleware, createStore, Store as ReduxStore } from 'redux'; -import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'; -import { stateStorage } from 'ts/local_storage/state_storage'; -import { analyticsMiddleware } from 'ts/redux/analyticsMiddleware'; -import { reducer, State } from 'ts/redux/reducer'; - -const ONE_SECOND = 1000; - -export const store: ReduxStore<State> = createStore( - reducer, - stateStorage.getPersistedDefaultState(), - composeWithDevTools(applyMiddleware(analyticsMiddleware)), -); -store.subscribe( - _.throttle(() => { - const state = store.getState(); - // Persisted state - stateStorage.saveState({ - hasPortalOnboardingBeenClosed: state.hasPortalOnboardingBeenClosed, - isPortalOnboardingShowing: state.isPortalOnboardingShowing, - }); - }, ONE_SECOND), -); diff --git a/packages/website/ts/schemas/metadata_schema.ts b/packages/website/ts/schemas/metadata_schema.ts deleted file mode 100644 index cd4045d10..000000000 --- a/packages/website/ts/schemas/metadata_schema.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const orderMetadataSchema = { - id: '/OrderMetadata', - properties: { - makerToken: { $ref: '/PortalTokenMetadata' }, - takerToken: { $ref: '/PortalTokenMetadata' }, - }, - required: ['makerToken', 'takerToken'], - type: 'object', -}; diff --git a/packages/website/ts/schemas/portal_order_schema.ts b/packages/website/ts/schemas/portal_order_schema.ts deleted file mode 100644 index 15e61f5e4..000000000 --- a/packages/website/ts/schemas/portal_order_schema.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const portalOrderSchema = { - id: '/PortalOrder', - properties: { - signedOrder: { $ref: '/signedOrderSchema' }, - metadata: { $ref: '/OrderMetadata' }, - }, - required: ['signedOrder', 'metadata'], - type: 'object', -}; diff --git a/packages/website/ts/schemas/portal_token_metadata.ts b/packages/website/ts/schemas/portal_token_metadata.ts deleted file mode 100644 index 0455c2ac1..000000000 --- a/packages/website/ts/schemas/portal_token_metadata.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const portalTokenMetadataSchema = { - id: '/PortalTokenMetadata', - properties: { - name: { type: 'string' }, - symbol: { type: 'string' }, - decimals: { type: 'number' }, - }, - required: ['name', 'symbol', 'decimals'], - type: 'object', -}; diff --git a/packages/website/ts/schemas/validator.ts b/packages/website/ts/schemas/validator.ts deleted file mode 100644 index 128d943e1..000000000 --- a/packages/website/ts/schemas/validator.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { SchemaValidator } from '@0x/json-schemas'; -import { orderMetadataSchema } from 'ts/schemas/metadata_schema'; -import { portalOrderSchema } from 'ts/schemas/portal_order_schema'; -import { portalTokenMetadataSchema } from 'ts/schemas/portal_token_metadata'; - -const validator = new SchemaValidator(); -validator.addSchema(portalTokenMetadataSchema); -validator.addSchema(orderMetadataSchema); -validator.addSchema(portalOrderSchema); - -export { validator }; diff --git a/packages/website/ts/style/colors.ts b/packages/website/ts/style/colors.ts deleted file mode 100644 index 356d72f7e..000000000 --- a/packages/website/ts/style/colors.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { colors as sharedColors } from '@0x/react-shared'; - -const appColors = { - walletBoxShadow: 'rgba(0, 0, 0, 0.05)', - walletBorder: '#ededee', - walletDefaultItemBackground: '#fbfbfc', - walletFocusedItemBackground: '#f0f1f4', - allowanceToggleShadow: 'rgba(0, 0, 0, 0)', - wrapEtherConfirmationButton: sharedColors.mediumBlue, - drawerMenuBackground: '#4a4a4a', - menuItemDefaultSelectedBackground: '#424242', - jobsPageBackground: sharedColors.grey50, - jobsPageOpenPositionRow: sharedColors.grey100, - metaMaskOrange: '#f68c24', - metaMaskTransparentOrange: 'rgba(255, 248, 242, 0.8)', - brandLight: '#00AE99', - brandDark: '#003831', - backgroundDark: '#111A19', - backgroundBlack: '#000000', - backgroundLight: '#F3F6F4', - textDarkPrimary: '#000000', - textDarkSecondary: '#5C5C5C', - white: '#fff', - instantPrimaryBackground: '#222222', - instantSecondaryBackground: '#333333', - instantTertiaryBackground: '#444444', -}; - -export const colors = { - ...sharedColors, - ...appColors, -}; diff --git a/packages/website/ts/style/keyframes.ts b/packages/website/ts/style/keyframes.ts deleted file mode 100644 index 28ea50247..000000000 --- a/packages/website/ts/style/keyframes.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { keyframes } from 'ts/style/theme'; - -export const rotate = keyframes` - 100% { - transform: rotate(360deg); - } -`; - -export const dash = keyframes` - 0% { - stroke-dasharray: 1, 150; - stroke-dashoffset: 0; - } - 50% { - stroke-dasharray: 90, 150; - stroke-dashoffset: -35; - } - 100% { - stroke-dasharray: 90, 150; - stroke-dashoffset: -124; - } -`; diff --git a/packages/website/ts/style/media.ts b/packages/website/ts/style/media.ts deleted file mode 100644 index 870d9a277..000000000 --- a/packages/website/ts/style/media.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { css } from 'ts/style/theme'; -import { ScreenWidths } from 'ts/types'; - -const generateMediaWrapper = (screenWidth: ScreenWidths) => (...args: any[]) => css` - @media (max-width: ${screenWidth}em) { - ${css.apply(css, args)}; - } -`; - -export const media = { - small: generateMediaWrapper(ScreenWidths.Sm), - medium: generateMediaWrapper(ScreenWidths.Md), - large: generateMediaWrapper(ScreenWidths.Lg), -}; diff --git a/packages/website/ts/style/theme.ts b/packages/website/ts/style/theme.ts deleted file mode 100644 index 94bd0169a..000000000 --- a/packages/website/ts/style/theme.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as styledComponents from 'styled-components'; - -// tslint:disable:no-unnecessary-type-assertion -const { - default: styled, - css, - createGlobalStyle, - keyframes, - ThemeProvider, -} = styledComponents as styledComponents.ThemedStyledComponentsModule<IThemeInterface>; -// tslint:enable:no-unnecessary-type-assertion - -export interface IThemeInterface {} - -export const theme = {}; - -export { styled, css, createGlobalStyle, keyframes, ThemeProvider }; diff --git a/packages/website/ts/style/z_index.ts b/packages/website/ts/style/z_index.ts deleted file mode 100644 index a3998f59b..000000000 --- a/packages/website/ts/style/z_index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const zIndex = { - topBar: 1100, - aboveTopBar: 1101, - overlay: 1105, - aboveOverlay: 1106, -}; diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts deleted file mode 100644 index 081c6d014..000000000 --- a/packages/website/ts/types.ts +++ /dev/null @@ -1,668 +0,0 @@ -import { ALink } from '@0x/react-shared'; -import { ObjectMap, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Provider } from 'ethereum-types'; -import * as React from 'react'; - -export enum Side { - Receive = 'RECEIVE', - Deposit = 'DEPOSIT', -} - -export interface Token { - iconUrl?: string; - name: string; - address: string; - symbol: string; - decimals: number; - isRegistered: boolean; - trackedTimestamp?: number; -} - -export interface TokenByAddress { - [address: string]: Token; -} - -export interface Styleable { - style: React.CSSProperties; - children: React.ReactNode; -} - -export interface AssetToken { - address?: string; - amount?: BigNumber; -} - -export interface SideToAssetToken { - [side: string]: AssetToken; -} - -export interface HashData { - depositAmount: BigNumber; - depositTokenContractAddr: string; - feeRecipientAddress: string; - makerFee: BigNumber; - orderExpiryTimestamp: BigNumber; - orderMakerAddress: string; - orderTakerAddress: string; - receiveAmount: BigNumber; - receiveTokenContractAddr: string; - takerFee: BigNumber; - orderSalt: BigNumber; -} - -export interface OrderToken { - name: string; - symbol: string; - decimals: number; -} - -export interface OrderMetadata { - makerToken: OrderToken; - takerToken: OrderToken; -} - -export interface PortalOrder { - signedOrder: SignedOrder; - metadata: OrderMetadata; -} - -export interface Fill { - logIndex: number; - maker: string; - taker: string; - makerToken: string; - takerToken: string; - filledMakerTokenAmount: BigNumber; - filledTakerTokenAmount: BigNumber; - paidMakerFee: BigNumber; - paidTakerFee: BigNumber; - orderHash: string; - transactionHash: string; - blockTimestamp: number; -} - -export enum BalanceErrs { - IncorrectNetworkForFaucet, - FaucetRequestFailed, - FaucetQueueIsFull, - MintingFailed, - SendFailed, - AllowanceSettingFailed, -} - -export enum ActionTypes { - // Portal - BatchDispatch = 'BATCH_DISPATCH', - UpdateScreenWidth = 'UPDATE_SCREEN_WIDTH', - UpdateNodeVersion = 'UPDATE_NODE_VERSION', - ResetState = 'RESET_STATE', - AddTokenToTokenByAddress = 'ADD_TOKEN_TO_TOKEN_BY_ADDRESS', - BlockchainErrEncountered = 'BLOCKCHAIN_ERR_ENCOUNTERED', - UpdateBlockchainIsLoaded = 'UPDATE_BLOCKCHAIN_IS_LOADED', - UpdateNetworkId = 'UPDATE_NETWORK_ID', - UpdateChosenAssetToken = 'UPDATE_CHOSEN_ASSET_TOKEN', - UpdateChosenAssetTokenAddress = 'UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS', - UpdateOrderTakerAddress = 'UPDATE_ORDER_TAKER_ADDRESS', - UpdateOrderSalt = 'UPDATE_ORDER_SALT', - UpdateOrderSignature = 'UPDATE_ORDER_SIGNATURE', - UpdateTokenByAddress = 'UPDATE_TOKEN_BY_ADDRESS', - RemoveTokenFromTokenByAddress = 'REMOVE_TOKEN_FROM_TOKEN_BY_ADDRESS', - ForceTokenStateRefetch = 'FORCE_TOKEN_STATE_REFETCH', - UpdateOrderExpiry = 'UPDATE_ORDER_EXPIRY', - SwapAssetTokens = 'SWAP_ASSET_TOKENS', - UpdateUserAddress = 'UPDATE_USER_ADDRESS', - UpdateUserEtherBalance = 'UPDATE_USER_ETHER_BALANCE', - UpdateUserSuppliedOrderCache = 'UPDATE_USER_SUPPLIED_ORDER_CACHE', - UpdateOrderFillAmount = 'UPDATE_ORDER_FILL_AMOUNT', - UpdateShouldBlockchainErrDialogBeOpen = 'UPDATE_SHOULD_BLOCKCHAIN_ERR_DIALOG_BE_OPEN', - UpdatePortalOnboardingStep = 'UPDATE_ONBOARDING_STEP', - UpdatePortalOnboardingShowing = 'UPDATE_PORTAL_ONBOARDING_SHOWING', - - // Docs - UpdateLibraryVersion = 'UPDATE_LIBRARY_VERSION', - UpdateAvailableLibraryVersions = 'UPDATE_AVAILABLE_LIBRARY_VERSIONS', - - // Shared - ShowFlashMessage = 'SHOW_FLASH_MESSAGE', - HideFlashMessage = 'HIDE_FLASH_MESSAGE', - UpdateProviderType = 'UPDATE_PROVIDER_TYPE', - UpdateInjectedProviderName = 'UPDATE_INJECTED_PROVIDER_NAME', - UpdateSelectedLanguage = 'UPDATE_SELECTED_LANGUAGE', -} - -export interface Action { - type: ActionTypes; - data?: any; -} - -export interface TrackedTokensByNetworkId { - [networkId: number]: Token[]; -} - -export interface TrackedTokensByUserAddress { - [userAddress: string]: TrackedTokensByNetworkId; -} - -export interface ProfileInfo { - name: string; - title?: string; - description: string; - image: string; - linkedIn?: string; - github?: string; - angellist?: string; - medium?: string; - twitter?: string; -} - -export interface Partner { - name: string; - logo: string; - url: string; -} - -export interface Statistic { - title: string; - figure: string; -} - -export interface StatisticByKey { - [key: string]: Statistic; -} - -export interface ERC20MarketInfo { - etherMarketCapUsd: number; - numLiquidERC20Tokens: number; - marketCapERC20TokensUsd: number; -} - -export enum ExchangeContractErrs { - OrderFillExpired = 'ORDER_FILL_EXPIRED', - OrderAlreadyCancelledOrFilled = 'ORDER_ALREADY_CANCELLED_OR_FILLED', - OrderRemainingFillAmountZero = 'ORDER_REMAINING_FILL_AMOUNT_ZERO', - OrderFillRoundingError = 'ORDER_FILL_ROUNDING_ERROR', - FillBalanceAllowanceError = 'FILL_BALANCE_ALLOWANCE_ERROR', - InsufficientTakerBalance = 'INSUFFICIENT_TAKER_BALANCE', - InsufficientTakerAllowance = 'INSUFFICIENT_TAKER_ALLOWANCE', - InsufficientMakerBalance = 'INSUFFICIENT_MAKER_BALANCE', - InsufficientMakerAllowance = 'INSUFFICIENT_MAKER_ALLOWANCE', - TransactionSenderIsNotFillOrderTaker = 'TRANSACTION_SENDER_IS_NOT_FILL_ORDER_TAKER', - InsufficientRemainingFillAmount = 'INSUFFICIENT_REMAINING_FILL_AMOUNT', -} - -export interface ContractResponse { - logs: ContractEvent[]; -} - -export interface ContractEvent { - event: string; - args: any; -} - -export type ValidatedBigNumberCallback = (isValid: boolean, amount?: BigNumber) => void; -// Associated values are in `em` units -export enum ScreenWidths { - Sm = 40, - Md = 52, - Lg = 64, -} - -export enum AlertTypes { - Error, - Success, -} - -export enum BlockchainErrs { - AContractNotDeployedOnNetwork = 'A_CONTRACT_NOT_DEPLOYED_ON_NETWORK', - DisconnectedFromEthereumNode = 'DISCONNECTED_FROM_ETHEREUM_NODE', - DefaultTokensNotInTokenRegistry = 'DEFAULT_TOKENS_NOT_IN_TOKEN_REGISTRY', - NoError = 'NO_ERROR', -} - -export enum BlockchainCallErrs { - ContractDoesNotExist = 'CONTRACT_DOES_NOT_EXIST', - UserHasNoAssociatedAddresses = 'USER_HAS_NO_ASSOCIATED_ADDRESSES', - UnhandledError = 'UNHANDLED_ERROR', - TokenAddressIsInvalid = 'TOKEN_ADDRESS_IS_INVALID', -} - -export enum Environments { - Development = 'DEVELOPMENT', - Dogfood = 'DOGFOOD', - Staging = 'STAGING', - Production = 'PRODUCTION', - Unknown = 'UNKNOWN', -} - -export type ContractInstance = any; // TODO: add type definition for Contract - -export interface FAQQuestion { - prompt: string; - answer: React.ReactNode; -} -export interface FAQSection { - name: string; - questions: FAQQuestion[]; -} - -export interface S3FileObject { - Key: { - _text: string; - }; -} - -export enum ProviderType { - Injected = 'INJECTED', - Ledger = 'LEDGER', -} - -export interface Fact { - title: string; - explanation: string; - image: string; -} - -interface LedgerGetAddressResult { - address: string; -} -interface LedgerSignResult { - v: string; - r: string; - s: string; -} -interface LedgerCommunication { - close_async: () => Promise<void>; -} -export interface LedgerEthConnection { - getAddress_async: ( - derivationPath: string, - askForDeviceConfirmation: boolean, - shouldGetChainCode: boolean, - ) => Promise<LedgerGetAddressResult>; - signPersonalMessage_async: (derivationPath: string, messageHex: string) => Promise<LedgerSignResult>; - signTransaction_async: (derivationPath: string, txHex: string) => Promise<LedgerSignResult>; - comm: LedgerCommunication; -} -export interface SignPersonalMessageParams { - data: string; -} - -export interface PublicNodeUrlsByNetworkId { - [networkId: number]: string[]; -} - -export interface JSONRPCPayload { - params: any[]; - method: string; -} - -export interface BlogPost { - image: string; - date: string; - title: string; - description: string; - url: string; -} - -export interface Article { - section: string; - title: string; - content: string; - fileName: string; -} - -export interface ArticlesBySection { - [section: string]: Article[]; -} - -export interface DialogConfigs { - title: string; - isModal: boolean; - actions: any[]; -} - -export enum TokenVisibility { - All = 'ALL', - Untracked = 'UNTRACKED', - Tracked = 'TRACKED', -} - -export interface VersionToFilePath { - [version: string]: string; -} - -export enum Docs { - ZeroExJs, - SmartContracts, -} - -export enum WebsiteLegacyPaths { - ZeroExJs = '/docs/0xjs', - Web3Wrapper = '/docs/web3_wrapper', - Deployer = '/docs/deployer', - Jobs = '/jobs', -} - -export enum WebsitePaths { - Portal = '/portal', - Wiki = '/wiki', - Docs = '/docs', - ZeroExJs = '/docs/0x.js', - Home = '/', - FAQ = '/faq', // tslint:disable-line:enum-naming - About = '/about', - AboutMission = '/about/mission', - AboutTeam = '/about/team', - AboutPress = '/about/press', - AboutJobs = '/about/jobs', - Community = '/community', - LaunchKit = '/launch-kit', - Instant = '/instant', - Ecosystem = '/eap', - MarketMaker = '/market-maker', - Why = '/why', - Whitepaper = '/pdfs/0x_white_paper.pdf', - SmartContracts = '/docs/contracts', - Connect = '/docs/connect', - Web3Wrapper = '/docs/web3-wrapper', - ContractWrappers = '/docs/contract-wrappers', - OrderWatcher = '/docs/order-watcher', - SolCompiler = '/docs/sol-compiler', - JSONSchemas = '/docs/json-schemas', - SolCoverage = '/docs/sol-coverage', - SolProfiler = '/docs/sol-profiler', - SolTrace = '/docs/sol-trace', - Subproviders = '/docs/subproviders', - OrderUtils = '/docs/order-utils', - EthereumTypes = '/docs/ethereum-types', - AssetBuyer = '/docs/asset-buyer', - Migrations = '/docs/migrations', - Careers = '/careers', -} - -export enum DocPackages { - Connect = 'CONNECT', - ZeroExJs = 'ZERO_EX_JS', - SmartContracts = 'SMART_CONTRACTS', - Web3Wrapper = 'WEB3_WRAPPER', - SolCompiler = 'SOL_COMPILER', - JSONSchemas = 'JSON_SCHEMAS', - SolCoverage = 'SOL_COVERAGE', - SolTrace = 'SOL_TRACE', - SolProfiler = 'SOL_PROFILER', - Subproviders = 'SUBPROVIDERS', - OrderUtils = 'ORDER_UTILS', - EthereumTypes = 'ETHEREUM_TYPES', - ContractWrappers = 'CONTRACT_WRAPPERS', - OrderWatcher = 'ORDER_WATCHER', - AssetBuyer = 'ASSET_BUYER', - Migrations = 'MIGRATIONS', -} - -export enum Key { - TopHeader = 'TOP_HEADER', - TopTagline = 'TOP_TAGLINE', - BuildCallToAction = 'BUILD_CALL_TO_ACTION', - CommunityCallToAction = 'COMMUNITY_CALL_TO_ACTION', - ProjectsHeader = 'PROJECTS_HEADER', - FullListPrompt = 'FULL_LIST_PROMPT', - FullListLink = 'FULL_LIST_LINK', - TokenizedSectionHeader = 'TOKENIZED_SECTION_HEADER', - TokenizedSectionDescription = 'TOKENIZED_SECTION_DESCRIPTION', - Currency = 'CURRENCY', - TraditionalAssets = 'TRADITIONAL_ASSETS', - DigitalGoods = 'DIGITAL_GOODS', - OffChainOrderRelay = 'OFFCHAIN_ORDER_RELAY', - OnChainSettlement = 'ONCHAIN_SETTLEMENT', - OffChainOnChainDescription = 'OFFCHAIN_ONCHAIN_DESCRIPTION', - RelayersHeader = 'RELAYERS_HEADER', - BenefitsHeader = 'BENEFITS_HEADER', - UseCasesHeader = 'USE_CASES_HEADER', - BenefitOneTitle = 'BENEFIT_ONE_TITLE', - BenefitOneDescription = 'BENEFIT_ONE_DESCRIPTION', - BenefitTwoTitle = 'BENEFIT_TWO_TITLE', - BenefitTwoDescription = 'BENEFIT_TWO_DESCRIPTION', - BenefitThreeTitle = 'BENEFIT_THREE_TITLE', - BenefitThreeDescription = 'BENEFIT_THREE_DESCRIPTION', - BuildingBlockSectionHeader = 'BUILDING_BLOCK_SECTION_HEADER', - BuildingBlockSectionDescription = 'BUILDING_BLOCK_SECTION_DESCRIPTION', - DevToolsPrompt = 'DEV_TOOLS_PROMPT', - SmartContract = 'SMART_CONTRACT', - Docs = 'DOCS', - DecentralizedGovernance = 'DECENTRALIZED_GOVERNANCE', - DecentralizedGovernanceDescription = 'DECENTRALIZED_GOVERNANCE_DESCRIPTION', - PredictionMarkets = 'PREDICTION_MARKETS', - PredictionMarketsDescription = 'PREDICTION_MARKETS_DESCRIPTION', - StableTokens = 'STABLE_TOKENS', - StableTokensDescription = 'STABLE_TOKENS_DESCRIPTION', - DecentralizedLoans = 'DECENTRALIZED_LOANS', - DecentralizedLoansDescription = 'DECENTRALIZED_LOANS_DESCRIPTION', - FundManagement = 'FUND_MANAGEMENT', - FundManagementDescription = 'FUND_MANAGEMENT_DESCRIPTION', - GamingAndCollectables = 'GAMING_AND_COLLECTABLES', - GamingAndCollectablesDescription = 'GAMING_AND_COLLECTABLES_DESCRIPTION', - OrderBooks = 'ORDER_BOOKS', - OrderBooksDescription = 'ORDER_BOOKS_DESCRIPTION', - FinalCallToAction = 'FINAL_CALL_TO_ACTION', - Documentation = 'DOCUMENTATION', - Community = 'COMMUNITY', - Organization = 'ORGANIZATION', - About = 'ABOUT', - Careers = 'CAREERS', - Contact = 'CONTACT', - SolCompiler = 'SOL_COMPILER', - JsonSchemas = 'JSON_SCHEMAS', - SolCov = 'SOL_COV', - EthereumTypes = 'ETHEREUM_TYPES', - Subproviders = 'SUBPROVIDERS', - ZeroExJs = '0X_JS', - ContractWrappers = 'CONTRACT_WRAPPERS', - OrderWatcher = 'ORDER_WATCHER', - AssetBuyer = 'ASSET_BUYER', - Blog = 'BLOG', - Forum = 'FORUM', - Connect = 'CONNECT', - Whitepaper = 'WHITEPAPER', - Wiki = 'WIKI', - Web3Wrapper = 'WEB3_WRAPPER', - OrderUtils = 'ORDER_UTILS', - And = 'AND', - Faq = 'FAQ', - SmartContracts = 'SMART_CONTRACTS', - StandardRelayerApi = 'STANDARD_RELAYER_API', - PortalDApp = 'PORTAL_DAPP', - Website = 'WEBSITE', - Developers = 'DEVELOPERS', - Home = 'HOME', - Discord = 'DISCORD', - TradeCallToAction = 'TRADE_CALL_TO_ACTION', - OurMissionAndValues = 'OUR_MISSION_AND_VALUES', - BuildARelayer = 'BUILD_A_RELAYER', - BuildARelayerDescription = 'BUILD_A_RELAYER_DESCRIPTION', - DevelopOnEthereum = 'DEVELOP_ON_ETHEREUM', - DevelopOnEthereumDescription = 'DEVELOP_ON_ETHEREUM_DESCRIPTION', - OrderBasics = 'ORDER_BASICS', - OrderBasicsDescription = 'ORDER_BASICS_DESCRIPTION', - UseNetworkedLiquidity = 'USE_NETWORKED_LIQUIDITY', - UseNetworkedLiquidityDescription = 'USE_NETWORKED_LIQUIDITY_DESCRIPTION', - Integrate0xInstant = 'INTEGRATE_0X_INSTANT', - Integrate0xInstantDescription = 'INTEGRATE_0X_INSTANT_DESCRIPTION', - ViewAllDocumentation = 'VIEW_ALL_DOCUMENTATION', - Sandbox = 'SANDBOX', - Github = 'GITHUB', - LiveChat = 'LIVE_CHAT', - LibrariesAndTools = 'LIBRARIES_AND_TOOLS', - LibrariesAndToolsDescription = 'LIBRARIES_AND_TOOLS_DESCRIPTION', - More = 'MORE', - StartBuildOn0x = 'START_BUILDING_ON_0X', - StartBuildOn0xDescription = 'START_BUILDING_ON_0X_DESCRIPTION', - LaunchKit = 'LAUNCH_KIT', - LaunchKitPitch = 'LAUNCH_KIT_PITCH', - ExploreTheDocs = 'EXPLORE_THE_DOCS', - EnableTrading = 'ENABLE_TRADING', - ForkAndExtend = 'FORK_AND_EXTEND', - LocalMarket = 'LOCAL_MARKET', - SeemlesslyCreate = 'SEEMLESSLY_CREATE', - QuicklyLaunch = 'QUICKLY_LAUNCH', - TapIntoAndShare = 'TAP_INTO_AND_SHARE', - PerfectForDevelopers = 'PERFECT_FOR_DEVELOPERS', - GetInTouch = 'GET_IN_TOUCH', - LearnMore = 'LEARN_MORE', - GetStarted = 'GET_STARTED', - ProtocolSpecification = 'PROTOCOL_SPECIFICATION', -} - -export enum SmartContractDocSections { - Introduction = 'Introduction', - Exchange = 'Exchange', - TokenTransferProxy = 'TokenTransferProxy', - TokenRegistry = 'TokenRegistry', - ZRXToken = 'ZRXToken', -} - -export enum Language { - English = 'EN', - Spanish = 'ES', - Chinese = 'ZH', - Korean = 'KO', - Russian = 'RU', -} - -export enum Deco { - Cap, - CapWords, - Upper, -} - -export interface MaterialUIPosition { - vertical: 'bottom' | 'top' | 'center'; - horizontal: 'left' | 'middle' | 'right'; -} - -export enum Providers { - Parity = 'PARITY', - Metamask = 'METAMASK', - Mist = 'MIST', - CoinbaseWallet = 'COINBASE_WALLET', - Cipher = 'CIPHER', -} - -export interface InjectedProviderUpdate { - selectedAddress: string; - networkVersion: string; -} - -export interface InjectedProviderObservable { - subscribe(updateHandler: (update: InjectedProviderUpdate) => void): void; - unsubscribe(updateHandler: (update: InjectedProviderUpdate) => void): void; -} - -export interface TimestampMsRange { - startTimestampMs: number; - endTimestampMs: number; -} - -export interface OutdatedWrappedEtherByNetworkId { - [networkId: number]: { - address: string; - timestampMsRange: TimestampMsRange; - }; -} - -export type ItemByAddress<T> = ObjectMap<T>; - -export type TokenStateByAddress = ItemByAddress<TokenState>; - -export interface TokenState { - balance: BigNumber; - allowance: BigNumber; - isLoaded: boolean; - price?: BigNumber; -} - -export interface WebsiteBackendRelayerInfo { - name: string; - weeklyTxnVolume?: string; - url: string; - appUrl?: string; - headerImgUrl?: string; - logoImgUrl?: string; - primaryColor?: string; - topTokens: WebsiteBackendTokenInfo[]; -} - -export interface WebsiteBackendPriceInfo { - [symbol: string]: string; -} - -export interface WebsiteBackendTokenInfo { - address: string; - decimals: number; - name: string; - symbol: string; -} - -export interface WebsiteBackendGasInfo { - safeSlow: number; - average: number; - fast: number; - fastest: number; -} - -export interface WebsiteBackendJobInfo { - id: number; - title: string; - department: string; - office: string; - url: string; -} - -export enum BrowserType { - Chrome = 'Chrome', - Firefox = 'Firefox', - Opera = 'Opera', - Safari = 'Safari', - Edge = 'Edge', - Other = 'Other', -} - -export enum OperatingSystemType { - Android = 'Android', - iOS = 'iOS', // tslint:disable-line:enum-naming - Mac = 'Mac', - Windows = 'Windows', - WindowsPhone = 'WindowsPhone', - Linux = 'Linux', - Other = 'Other', -} - -export enum AccountState { - Disconnected = 'Disconnected', - Ready = 'Ready', - Loading = 'Loading', - Locked = 'Locked', -} - -export interface InjectedProvider extends Provider { - publicConfigStore?: InjectedProviderObservable; -} - -export interface TutorialInfo { - iconUrl: string; - description: string; - link: ALink; -} - -export enum Categories { - ZeroExProtocolTypescript = '0x Protocol (Typescript/Javascript)', - ZeroExProtocolPython = '0x Protocol (Python)', - Ethereum = 'Ethereum (Typescript/Javascript)', - CommunityMaintained = 'Community Maintained', -} - -export interface Package { - description: string; - link: ALink; -} -// tslint:disable:max-file-line-count diff --git a/packages/website/ts/utils/analytics.ts b/packages/website/ts/utils/analytics.ts deleted file mode 100644 index e990b4fc7..000000000 --- a/packages/website/ts/utils/analytics.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { assetDataUtils } from '@0x/order-utils'; -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; -import { PortalOrder } from 'ts/types'; -import { utils } from 'ts/utils/utils'; - -export interface HeapAnalytics { - loaded: boolean; - identify(id: string, idType: string): void; - track(eventName: string, eventProperties?: ObjectMap<string | number>): void; - resetIdentity(): void; - addUserProperties(properties: ObjectMap<string | number>): void; - addEventProperties(properties: ObjectMap<string | number>): void; - removeEventProperty(property: string): void; - clearEventProperties(): void; -} -export class Analytics { - private _heap: HeapAnalytics; - public static init(): Analytics { - return new Analytics(Analytics.getHeap()); - } - public static getHeap(): HeapAnalytics { - const heap = (window as any).heap; - if (!_.isUndefined(heap)) { - return heap; - } else { - throw new Error('Could not find the Heap SDK on the page.'); - } - } - constructor(heap: HeapAnalytics) { - this._heap = heap; - } - // tslint:disable:no-floating-promises - // HeapAnalytics Wrappers - public identify(id: string, idType: string): void { - this._heapLoadedGuardAsync(() => this._heap.identify(id, idType)); - } - public track(eventName: string, eventProperties?: ObjectMap<string | number>): void { - this._heapLoadedGuardAsync(() => this._heap.track(eventName, eventProperties)); - } - public resetIdentity(): void { - this._heapLoadedGuardAsync(() => this._heap.resetIdentity()); - } - public addUserProperties(properties: ObjectMap<string | number>): void { - this._heapLoadedGuardAsync(() => this._heap.addUserProperties(properties)); - } - public addEventProperties(properties: ObjectMap<string | number>): void { - this._heapLoadedGuardAsync(() => this._heap.addEventProperties(properties)); - } - public removeEventProperty(property: string): void { - this._heapLoadedGuardAsync(() => this._heap.removeEventProperty(property)); - } - public clearEventProperties(): void { - this._heapLoadedGuardAsync(() => this._heap.clearEventProperties()); - } - // tslint:enable:no-floating-promises - // Custom methods - public trackOrderEvent(eventName: string, order: PortalOrder): void { - const takerTokenAmount = order.signedOrder.takerAssetAmount.toString(); - const makerTokenAmount = order.signedOrder.makerAssetAmount.toString(); - const takerToken = assetDataUtils.decodeERC20AssetData(order.signedOrder.takerAssetData).tokenAddress; - const makerToken = assetDataUtils.decodeERC20AssetData(order.signedOrder.makerAssetData).tokenAddress; - const orderLoggingData = { - takerTokenAmount, - makerTokenAmount, - takerToken, - makerToken, - }; - this.track(eventName, orderLoggingData); - } - /** - * Heap is not available as a UMD module, and additionally has the strange property of replacing itself with - * a different object once it's loaded. - * Instead of having an await call before every analytics use, we opt to have the awaiting logic in here by - * guarding every API call with the guard below. - */ - private async _heapLoadedGuardAsync(callback: () => void): Promise<void> { - if (this._heap.loaded) { - callback(); - return undefined; - } - await utils.onPageLoadPromise; - // HACK: Reset heap to loaded heap - this._heap = (window as any).heap; - callback(); - } -} - -export const analytics = Analytics.init(); diff --git a/packages/website/ts/utils/backend_client.ts b/packages/website/ts/utils/backend_client.ts deleted file mode 100644 index 5164211df..000000000 --- a/packages/website/ts/utils/backend_client.ts +++ /dev/null @@ -1,61 +0,0 @@ -import * as _ from 'lodash'; - -import { - ArticlesBySection, - WebsiteBackendGasInfo, - WebsiteBackendJobInfo, - WebsiteBackendPriceInfo, - WebsiteBackendRelayerInfo, - WebsiteBackendTokenInfo, -} from 'ts/types'; -import { fetchUtils } from 'ts/utils/fetch_utils'; -import { utils } from 'ts/utils/utils'; - -const ETH_GAS_STATION_ENDPOINT = '/eth_gas_station'; -const JOBS_ENDPOINT = '/jobs'; -const PRICES_ENDPOINT = '/prices'; -const RELAYERS_ENDPOINT = '/relayers'; -const TOKENS_ENDPOINT = '/tokens'; -const WIKI_ENDPOINT = '/wiki'; -const SUBSCRIBE_SUBSTACK_NEWSLETTER_ENDPOINT = '/newsletter_subscriber/substack'; - -export const backendClient = { - async getGasInfoAsync(): Promise<WebsiteBackendGasInfo> { - const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), ETH_GAS_STATION_ENDPOINT); - return result; - }, - async getJobInfosAsync(): Promise<WebsiteBackendJobInfo[]> { - const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), JOBS_ENDPOINT); - return result; - }, - async getPriceInfoAsync(tokenSymbols: string[]): Promise<WebsiteBackendPriceInfo> { - if (_.isEmpty(tokenSymbols)) { - return {}; - } - const joinedTokenSymbols = tokenSymbols.join(','); - const queryParams = { - tokens: joinedTokenSymbols, - }; - const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), PRICES_ENDPOINT, queryParams); - return result; - }, - async getRelayerInfosAsync(): Promise<WebsiteBackendRelayerInfo[]> { - const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), RELAYERS_ENDPOINT); - return result; - }, - async getTokenInfosAsync(): Promise<WebsiteBackendTokenInfo[]> { - const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), TOKENS_ENDPOINT); - return result; - }, - async getWikiArticlesBySectionAsync(): Promise<ArticlesBySection> { - const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), WIKI_ENDPOINT); - return result; - }, - async subscribeToNewsletterAsync(email: string): Promise<Response> { - const result = await fetchUtils.postAsync(utils.getBackendBaseUrl(), SUBSCRIBE_SUBSTACK_NEWSLETTER_ENDPOINT, { - email, - referrer: window.location.href, - }); - return result; - }, -}; diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts deleted file mode 100644 index 7cc854ca0..000000000 --- a/packages/website/ts/utils/configs.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { OutdatedWrappedEtherByNetworkId, PublicNodeUrlsByNetworkId } from 'ts/types'; - -const BASE_URL = window.location.origin; -const INFURA_API_KEY = 'T5WSC8cautR4KXyYgsRs'; - -export const configs = { - AMOUNT_DISPLAY_PRECSION: 5, - BACKEND_BASE_PROD_URL: 'https://website-api.0x.org', - BACKEND_BASE_STAGING_URL: 'https://staging-website-api.0x.org', - BASE_URL, - BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208', - DEFAULT_DERIVATION_PATH: `44'/60'/0'`, - // WARNING: ZRX & WETH MUST always be default trackedTokens - DEFAULT_TRACKED_TOKEN_SYMBOLS: ['WETH', 'ZRX'], - DOMAIN_STAGING: 'staging-0xproject.s3-website-us-east-1.amazonaws.com', - DOMAIN_DOGFOOD: 'dogfood.0x.org', - DOMAINS_DEVELOPMENT: ['0xproject.localhost:3572', 'localhost:3572', '127.0.0.1'], - DOMAIN_PRODUCTION: '0x.org', - GOOGLE_ANALYTICS_ID: 'UA-98720122-1', - LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE: '2017-11-22', - LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE: '2018-9-7', - OUTDATED_WRAPPED_ETHERS: [ - { - 42: { - address: '0x05d090b51c40b020eab3bfcb6a2dff130df22e9c', - timestampMsRange: { - startTimestampMs: 1502455607000, - endTimestampMs: 1513790926000, - }, - }, - 1: { - address: '0x2956356cd2a2bf3202f771f50d3d14a367b48070', - timestampMsRange: { - startTimestampMs: 1502455607000, - endTimestampMs: 1513790926000, - }, - }, - }, - ] as OutdatedWrappedEtherByNetworkId[], - // The order matters. We first try first node and only then fall back to others. - PUBLIC_NODE_URLS_BY_NETWORK_ID: { - [1]: [`https://mainnet.infura.io/${INFURA_API_KEY}`, 'https://mainnet.0x.org'], - [42]: [`https://kovan.infura.io/${INFURA_API_KEY}`, 'https://kovan.0x.org'], - [3]: [`https://ropsten.infura.io/${INFURA_API_KEY}`], - [4]: [`https://rinkeby.infura.io/${INFURA_API_KEY}`], - } as PublicNodeUrlsByNetworkId, - SYMBOLS_OF_MINTABLE_KOVAN_TOKENS: ['ZRX', 'MKR', 'MLN', 'GNT', 'DGD', 'REP'], - SYMBOLS_OF_MINTABLE_ROPSTEN_TOKENS: ['ZRX', 'MKR', 'MLN', 'GNT', 'DGD', 'REP'], -}; diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts deleted file mode 100644 index 03c1a0b83..000000000 --- a/packages/website/ts/utils/constants.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { ALink } from '@0x/react-shared'; -import { BigNumber } from '@0x/utils'; -import { Key, WebsitePaths } from 'ts/types'; - -const URL_FORUM = 'https://forum.0x.org'; -const URL_ZEROEX_CHAT = 'https://discord.gg/d3FTX3M'; - -export const constants = { - DECIMAL_PLACES_ETH: 18, - DECIMAL_PLACES_ZRX: 18, - ETHER_TOKEN_SYMBOL: 'WETH', - ZRX_TOKEN_SYMBOL: 'ZRX', - ETHER_SYMBOL: 'ETH', - TOKEN_AMOUNT_DISPLAY_PRECISION: 4, - GENESIS_ORDER_BLOCK_BY_NETWORK_ID: { - 1: 4145578, - 42: 3117574, - 50: 0, - 3: 1719261, - 4: 1570919, - } as { [networkId: number]: number }, - HOME_SCROLL_DURATION_MS: 500, - HTTP_NO_CONTENT_STATUS_CODE: 204, - LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER: 'didAcceptPortalDisclaimer', - LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE: 'hasDismissedWethNotice', - MAKER_FEE: new BigNumber(0), - MAINNET_NAME: 'Main network', - MINT_AMOUNT: new BigNumber('100000000000000000000'), - NETWORK_ID_MAINNET: 1, - NETWORK_ID_KOVAN: 42, - NETWORK_ID_TESTRPC: 50, - NETWORK_ID_ROPSTEN: 3, - NULL_ADDRESS: '0x0000000000000000000000000000000000000000', - PROVIDER_NAME_LEDGER: 'Ledger', - PROVIDER_NAME_METAMASK: 'MetaMask', - PROVIDER_NAME_PARITY_SIGNER: 'Parity Signer', - PROVIDER_NAME_MIST: 'Mist', - PROVIDER_NAME_CIPHER: 'Cipher Browser', - PROVIDER_NAME_COINBASE_WALLET: 'Coinbase Wallet', - PROVIDER_NAME_GENERIC: 'Injected Web3', - PROVIDER_NAME_PUBLIC: '0x Public', - ROLLBAR_ACCESS_TOKEN: '32c39bfa4bb6440faedc1612a9c13d28', - S3_DOC_BUCKET_ROOT: 'https://s3.amazonaws.com/doc-jsons', - S3_STAGING_DOC_BUCKET_ROOT: 'https://s3.amazonaws.com/staging-doc-jsons', - SUCCESS_STATUS: 200, - UNAVAILABLE_STATUS: 503, - TAKER_FEE: new BigNumber(0), - TESTNET_NAME: 'Kovan', - NUMERAL_USD_FORMAT: '$0,0.00', - EMAIL_JOBS: 'jobs@0x.org', - PROJECT_URL_ETHFINEX: 'https://www.ethfinex.com/', - PROJECT_URL_AMADEUS: 'http://amadeusrelay.org', - PROJECT_URL_DDEX: 'https://ddex.io', - PROJECT_URL_DECENT_EX: 'https://decent.exchange', - PROJECT_URL_DEXTROID: 'https://www.dextroid.io', - PROJECT_URL_ERC_DEX: 'https://ercdex.com', - PROJECT_URL_OPEN_RELAY: 'https://openrelay.xyz', - PROJECT_URL_RADAR_RELAY: 'https://radarrelay.com', - PROJECT_URL_PARADEX: 'https://paradex.io', - PROJECT_URL_DYDX: 'https://dydx.exchange', - PROJECT_URL_MELONPORT: 'https://melonport.com', - PROJECT_URL_DISTRICT_0X: 'https://district0x.io', - PROJECT_URL_DHARMA: 'https://dharma.io', - PROJECT_URL_LENDROID: 'https://lendroid.com', - PROJECT_URL_MAKER: 'https://makerdao.com', - PROJECT_URL_ARAGON: 'https://aragon.one', - PROJECT_URL_BLOCKNET: 'https://blocknet.co', - PROJECT_URL_0CEAN: 'https://theocean.trade', - PROJECT_URL_IMTOKEN: 'https://tokenlon.token.im/', - PROJECT_URL_AUGUR: 'https://augur.net', - PROJECT_URL_AUCTUS: 'https://auctus.org', - PROJECT_URL_OPEN_ANX: 'https://www.openanx.org', - PROJECT_URL_IDT: 'https://kinalpha.com', - URL_ANGELLIST: 'https://angel.co/0xproject/jobs', - URL_APACHE_LICENSE: 'http://www.apache.org/licenses/LICENSE-2.0', - URL_BITLY_API: 'https://api-ssl.bitly.com', - URL_BLOG: 'https://blog.0xproject.com', - URL_DISCOURSE_FORUM: 'https://forum.0x.org', - URL_ECOSYSTEM_APPLY: 'https://0x.smapply.io/', - URL_ECOSYSTEM_BLOG_POST: 'https://blog.0xproject.com/announcing-the-0x-ecosystem-acceleration-program-89d1cb89d565', - URL_FIREFOX_U2F_ADDON: 'https://addons.mozilla.org/en-US/firefox/addon/u2f-support-add-on/', - URL_TESTNET_FAUCET: 'https://faucet.0x.org', - URL_GITHUB_ORG: 'https://github.com/0xProject', - URL_GITHUB_WIKI: 'https://github.com/0xProject/wiki', - URL_FORUM, - URL_PROTOCOL_SPECIFICATION: - 'https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md', - URL_METAMASK_CHROME_STORE: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn', - URL_METAMASK_FIREFOX_STORE: 'https://addons.mozilla.org/en-US/firefox/addon/ether-metamask/', - URL_COINBASE_WALLET_IOS_APP_STORE: 'https://itunes.apple.com/us/app/coinbase-wallet/id1278383455?mt=8', - URL_COINBASE_WALLET_ANDROID_APP_STORE: 'https://play.google.com/store/apps/details?id=org.toshi&hl=en', - URL_METAMASK_HOMEPAGE: 'https://metamask.io/', - URL_METAMASK_OPERA_STORE: 'https://addons.opera.com/en/extensions/details/metamask/', - URL_MIST_DOWNLOAD: 'https://github.com/ethereum/mist/releases', - URL_PARITY_CHROME_STORE: - 'https://chrome.google.com/webstore/detail/parity-ethereum-integrati/himekenlppkgeaoeddcliojfddemadig', - URL_REDDIT: 'https://reddit.com/r/0xproject', - URL_SANDBOX: 'https://codesandbox.io/s/1qmjyp7p5j', - URL_STANDARD_RELAYER_API_GITHUB: 'https://github.com/0xProject/standard-relayer-api/blob/master/README.md', - URL_TWITTER: 'https://twitter.com/0xproject', - URL_FACEBOOK: 'https://www.facebook.com/0xProject/', - URL_WETH_IO: 'https://weth.io/', - URL_CANONICAL_WETH_POST: 'https://blog.0xproject.com/canonical-weth-a9aa7d0279dd', - URL_ZEROEX_CHAT, - URL_LAUNCH_KIT: 'https://github.com/0xProject/0x-launch-kit', - URL_LAUNCH_KIT_BLOG_POST: 'https://blog.0xproject.com/introducing-the-0x-launch-kit-4acdc3453585', - URL_WEB3_DOCS: 'https://github.com/ethereum/wiki/wiki/JavaScript-API', - URL_WEB3_DECODED_LOG_ENTRY_EVENT: - 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L123', - URL_WEB3_LOG_ENTRY_EVENT: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L127', - URL_WEB3_PROVIDER_DOCS: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L150', - URL_BIGNUMBERJS_GITHUB: 'http://mikemcl.github.io/bignumber.js', - URL_MISSION_AND_VALUES_BLOG_POST: 'https://blog.0xproject.com/the-0x-mission-and-values-181a58706f9f', - DEVELOPER_TOPBAR_LINKS: [ - { - title: Key.Wiki, - to: WebsitePaths.Wiki, - }, - { - title: Key.Forum, - to: URL_FORUM, - shouldOpenInNewTab: true, - }, - { - title: Key.LiveChat, - to: URL_ZEROEX_CHAT, - shouldOpenInNewTab: true, - }, - ] as ALink[], -}; diff --git a/packages/website/ts/utils/doc_utils.ts b/packages/website/ts/utils/doc_utils.ts deleted file mode 100644 index 6be164e6e..000000000 --- a/packages/website/ts/utils/doc_utils.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { DocAgnosticFormat, GeneratedDocJson } from '@0x/react-docs'; -import { fetchAsync, logUtils } from '@0x/utils'; -import * as _ from 'lodash'; -import { S3FileObject, VersionToFilePath } from 'ts/types'; -import convert from 'xml-js'; - -export const docUtils = { - async getVersionToFilePathAsync(s3DocJsonRoot: string, folderName: string): Promise<VersionToFilePath> { - const versionFilePaths = await docUtils.getVersionFileNamesAsync(s3DocJsonRoot, folderName); - const versionToFilePath: VersionToFilePath = {}; - _.each(versionFilePaths, filePath => { - const version = filePath.split('/v')[1].replace('.json', ''); - versionToFilePath[version] = filePath; - }); - return versionToFilePath; - }, - async getVersionFileNamesAsync(s3DocJsonRoot: string, folderName: string): Promise<string[]> { - const response = await fetchAsync(s3DocJsonRoot); - if (response.status !== 200) { - // TODO: Show the user an error message when the docs fail to load - const errMsg = await response.text(); - logUtils.log(`Failed to load JSON file list: ${response.status} ${errMsg}`); - throw new Error(errMsg); - } - const responseXML = await response.text(); - const responseJSONString = convert.xml2json(responseXML, { - compact: true, - }); - const responseObj = JSON.parse(responseJSONString); - const fileObjs: S3FileObject[] = _.isArray(responseObj.ListBucketResult.Contents) - ? (responseObj.ListBucketResult.Contents as S3FileObject[]) - : [responseObj.ListBucketResult.Contents]; - - /* - * S3 simply pre-fixes files in "folders" with the folder name. Thus, since we - * store docJSONs for multiple packages in a single S3 bucket, we must filter out - * the versionFileNames for a given folder here (ignoring folder entries) - * - * Example S3 response: - * <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> - * <Name>staging-doc-jsons</Name> - * <Prefix/> - * <Marker/> - * <MaxKeys>1000</MaxKeys> - * <IsTruncated>false</IsTruncated> - * <Contents> - * <Key>0xjs/</Key> - * <LastModified>2018-03-16T13:17:46.000Z</LastModified> - * <ETag>"d41d8cd98f00b204e9800998ecf8427e"</ETag> - * <Size>0</Size> - * <StorageClass>STANDARD</StorageClass> - * </Contents> - * <Contents> - * <Key>0xjs/v0.1.0.json</Key> - * <LastModified>2018-03-16T13:18:23.000Z</LastModified> - * <ETag>"b4f7f74913aab4a5ad1e6a58fcb3b274"</ETag> - * <Size>1039050</Size> - * <StorageClass>STANDARD</StorageClass> - * </Contents> - */ - const relevantObjs = _.filter(fileObjs, fileObj => { - const key = fileObj.Key._text; - const isInFolderOfInterest = _.includes(key, folderName); - const isFileEntry = !_.endsWith(key, '/'); - return isInFolderOfInterest && isFileEntry; - }); - - const versionFilePaths = _.map(relevantObjs, fileObj => { - return fileObj.Key._text; - }); - return versionFilePaths; - }, - async getJSONDocFileAsync(filePath: string, s3DocJsonRoot: string): Promise<GeneratedDocJson | DocAgnosticFormat> { - const endpoint = `${s3DocJsonRoot}/${filePath}`; - const response = await fetchAsync(endpoint); - if (response.status !== 200) { - // TODO: Show the user an error message when the docs fail to load - const errMsg = await response.text(); - logUtils.log(`Failed to load Doc JSON: ${response.status} ${errMsg}`); - throw new Error(errMsg); - } - const jsonDocObj = await response.json(); - return jsonDocObj; - }, -}; diff --git a/packages/website/ts/utils/documentation_container.ts b/packages/website/ts/utils/documentation_container.ts deleted file mode 100644 index 54e8a2c1a..000000000 --- a/packages/website/ts/utils/documentation_container.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DocsInfo, DocsInfoConfig } from '@0x/react-docs'; -import { Dispatch } from 'redux'; -import { DocPageProps } from 'ts/pages/documentation/doc_page'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { ScreenWidths } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; - -export interface ConnectedState { - docsVersion: string; - availableDocVersions: string[]; - docsInfo: DocsInfo; - translate: Translate; - screenWidth: ScreenWidths; -} - -export interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -export const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const getMapStateToProps = (docsInfoConfig: DocsInfoConfig) => { - const docsInfo = new DocsInfo(docsInfoConfig); - const mapStateToProps = (state: State, _ownProps: DocPageProps): ConnectedState => ({ - docsVersion: state.docsVersion, - availableDocVersions: state.availableDocVersions, - translate: state.translate, - docsInfo, - screenWidth: state.screenWidth, - }); - return mapStateToProps; -}; diff --git a/packages/website/ts/utils/error_reporter.ts b/packages/website/ts/utils/error_reporter.ts deleted file mode 100644 index 8e24060ac..000000000 --- a/packages/website/ts/utils/error_reporter.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { logUtils } from '@0x/utils'; -import Rollbar from 'rollbar'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { utils } from 'ts/utils/utils'; - -// Suggested way to include Rollbar with Webpack -// https://github.com/rollbar/rollbar.js/tree/master/examples/webpack -const rollbarConfig = { - accessToken: constants.ROLLBAR_ACCESS_TOKEN, - captureUncaught: true, - captureUnhandledRejections: true, - itemsPerMinute: 10, - maxItems: 500, - payload: { - environment: utils.getEnvironment(), - client: { - javascript: { - source_map_enabled: true, - // This is only defined in production environments. - code_version: process.env.GIT_SHA, - guess_uncaught_frames: true, - }, - }, - }, - uncaughtErrorLevel: 'error', - hostWhiteList: [configs.DOMAIN_PRODUCTION, configs.DOMAIN_STAGING], - ignoredMessages: [ - // Errors from the third-party scripts - 'Script error', - // Network errors or ad-blockers - 'TypeError: Failed to fetch', - 'Exchange has not been deployed to detected network (network/artifact mismatch)', - // Source: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/7VU0_VvC7mE - "undefined is not an object (evaluating '__gCrWeb.autofill.extractForms')", - // Source: http://stackoverflow.com/questions/43399818/securityerror-from-facebook-and-cross-domain-messaging - 'SecurityError (DOM Exception 18)', - ], -}; - -const rollbar = new Rollbar(rollbarConfig); - -export const errorReporter = { - report(err: Error): void { - if (utils.isDevelopment()) { - return; // Let's not log development errors to rollbar - } - rollbar.error(err, (rollbarErr: Error) => { - if (rollbarErr) { - logUtils.log(`Error reporting to rollbar, ignoring: ${rollbarErr}`); - } - }); - }, -}; diff --git a/packages/website/ts/utils/fake_token_registry.ts b/packages/website/ts/utils/fake_token_registry.ts deleted file mode 100644 index 607dd2553..000000000 --- a/packages/website/ts/utils/fake_token_registry.ts +++ /dev/null @@ -1,879 +0,0 @@ -export interface FakeTokenRegistryEntry { - address: string; - name: string; - symbol: string; - decimals: number; -} - -export const fakeTokenRegistry: { [networkId: string]: FakeTokenRegistryEntry[] } = { - '1': [ - { - address: '0xe41d2489571d322189246dafa5ebde1f4699f498', - name: '0x Protocol Token', - symbol: 'ZRX', - decimals: 18, - }, - { - address: '0x4156d3342d5c385a87d264f90653733592000581', - name: 'Salt', - symbol: 'SALT', - decimals: 8, - }, - { - address: '0x05f4a42e251f2d52b8ed15e9fedaacfcef1fad27', - name: 'Zilliqa', - symbol: 'ZIL', - decimals: 12, - }, - { - address: '0xe0b7927c4af23765cb51314a0e0521a9645f0e2a', - name: 'Digix DAO Token', - symbol: 'DGD', - decimals: 9, - }, - { - address: '0xfa05a73ffe78ef8f1a739473e462c54bae6567d9', - name: 'Lunyr', - symbol: 'LUN', - decimals: 18, - }, - { - address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - name: 'Wrapped Ether', - symbol: 'WETH', - decimals: 18, - }, - { - address: '0xbeb9ef514a379b997e0798fdcc901ee474b6d9a1', - name: 'Melon Token', - symbol: 'MLN', - decimals: 18, - }, - { - address: '0x9a642d6b3368ddc662ca244badf32cda716005bc', - name: 'Qtum', - symbol: 'QTUM', - decimals: 18, - }, - { - address: '0xd26114cd6ee289accf82350c8d8487fedb8a0c07', - name: 'OmiseGO', - symbol: 'OMG', - decimals: 18, - }, - { - address: '0xb97048628db6b661d4c2aa833e95dbe1a905b280', - name: 'TenXPay', - symbol: 'PAY', - decimals: 18, - }, - { - address: '0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0', - name: 'Eos', - symbol: 'EOS', - decimals: 18, - }, - { - address: '0x888666ca69e0f178ded6d75b5726cee99a87d698', - name: 'Iconomi', - symbol: 'ICN', - decimals: 18, - }, - { - address: '0x744d70fdbe2ba4cf95131626614a1763df805b9e', - name: 'StatusNetwork', - symbol: 'SNT', - decimals: 18, - }, - { - address: '0x6810e776880c02933d47db1b9fc05908e5386b96', - name: 'Gnosis', - symbol: 'GNO', - decimals: 18, - }, - { - address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', - name: 'Basic Attention Token', - symbol: 'BAT', - decimals: 18, - }, - { - address: '0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac', - name: 'Storj', - symbol: 'STORJ', - decimals: 8, - }, - { - address: '0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c', - name: 'Bancor', - symbol: 'BNT', - decimals: 18, - }, - { - address: '0x960b236a07cf122663c4303350609a66a7b288c0', - name: 'Aragon', - symbol: 'ANT', - decimals: 18, - }, - { - address: '0x0abdace70d3790235af448c88547603b945604ea', - name: 'district0x', - symbol: 'DNT', - decimals: 18, - }, - { - address: '0xaec2e87e0a235266d9c5adc9deb4b2e29b54d009', - name: 'SingularDTV', - symbol: 'SNGLS', - decimals: 0, - }, - { - address: '0x419d0d8bdd9af5e606ae2232ed285aff190e711b', - name: 'FunFair', - symbol: 'FUN', - decimals: 8, - }, - { - address: '0xaf30d2a7e90d7dc361c8c4585e9bb7d2f6f15bc7', - name: 'FirstBlood', - symbol: '1ST', - decimals: 18, - }, - { - address: '0x08711d3b02c8758f2fb3ab4e80228418a7f8e39c', - name: 'Edgeless', - symbol: 'EDG', - decimals: 0, - }, - { - address: '0x9992ec3cf6a55b00978cddf2b27bc6882d88d1ec', - name: 'Polymath', - symbol: 'POLY', - decimals: 18, - }, - { - address: '0x607f4c5bb672230e8672085532f7e901544a7375', - name: 'iExec', - symbol: 'RLC', - decimals: 9, - }, - { - address: '0x667088b212ce3d06a1b553a7221e1fd19000d9af', - name: 'Wings', - symbol: 'WINGS', - decimals: 18, - }, - { - address: '0x41e5560054824ea6b0732e656e3ad64e20e94e45', - name: 'Civic', - symbol: 'CVC', - decimals: 8, - }, - { - address: '0xb63b606ac810a52cca15e44bb630fd42d8d1d83d', - name: 'Monaco', - symbol: 'MCO', - decimals: 8, - }, - { - address: '0xf433089366899d83a9f26a773d59ec7ecf30355e', - name: 'Metal', - symbol: 'MTL', - decimals: 8, - }, - { - address: '0x12fef5e57bf45873cd9b62e9dbd7bfb99e32d73e', - name: 'Cofoundit', - symbol: 'CFI', - decimals: 18, - }, - { - address: '0xaaaf91d9b90df800df4f55c205fd6989c977e73a', - name: 'Monolith TKN', - symbol: 'TKN', - decimals: 8, - }, - { - address: '0xe7775a6e9bcf904eb39da2b68c5efb4f9360e08c', - name: 'Token-as-a-Service', - symbol: 'TAAS', - decimals: 6, - }, - { - address: '0x2e071d2966aa7d8decb1005885ba1977d6038a65', - name: 'DICE', - symbol: 'ROL', - decimals: 16, - }, - { - address: '0xcb94be6f13a1182e4a4b6140cb7bf2025d28e41b', - name: 'Trustcoin', - symbol: 'TRST', - decimals: 6, - }, - { - address: '0x1776e1f26f98b1a5df9cd347953a26dd3cb46671', - name: 'Numeraire', - symbol: 'NMR', - decimals: 18, - }, - { - address: '0x7c5a0ce9267ed19b22f8cae653f198e3e8daf098', - name: 'Santiment Network Token', - symbol: 'SAN', - decimals: 18, - }, - { - address: '0xdd974d5c2e2928dea5f71b9825b8b646686bd200', - name: 'Kyber Network Crystal', - symbol: 'KNC', - decimals: 18, - }, - { - address: '0xb7cb1c96db6b22b0d3d9536e0108d062bd488f74', - name: 'Walton', - symbol: 'WTC', - decimals: 18, - }, - { - address: '0xd0d6d6c5fe4a677d343cc433536bb717bae167dd', - name: 'adToken', - symbol: 'ADT', - decimals: 9, - }, - { - address: '0x42d6622dece394b54999fbd73d108123806f6a18', - name: 'SpankChain', - symbol: 'SPANK', - decimals: 18, - }, - { - address: '0x701c244b988a513c945973defa05de933b23fe1d', - name: 'openANX', - symbol: 'OAX', - decimals: 18, - }, - { - address: '0x514910771af9ca656af840dff83e8264ecf986ca', - name: 'ChainLink', - symbol: 'LINK', - decimals: 18, - }, - { - address: '0x8f8221afbb33998d8584a2b05749ba73c37a938a', - name: 'Request Network', - symbol: 'REQ', - decimals: 18, - }, - { - address: '0x27054b13b1b798b345b591a4d22e6562d47ea75a', - name: 'AirSwap', - symbol: 'AST', - decimals: 4, - }, - { - address: '0xf0ee6b27b759c9893ce4f094b49ad28fd15a23e4', - name: 'Enigma', - symbol: 'ENG', - decimals: 8, - }, - { - address: '0x818fc6c2ec5986bc6e2cbf00939d90556ab12ce5', - name: 'Kin', - symbol: 'KIN', - decimals: 18, - }, - { - address: '0x27dce1ec4d3f72c3e457cc50354f1f975ddef488', - name: 'AirToken', - symbol: 'AIR', - decimals: 8, - }, - { - address: '0x12480e24eb5bec1a9d4369cab6a80cad3c0a377a', - name: 'Substratum', - symbol: 'SUB', - decimals: 2, - }, - { - address: '0x0e8d6b471e332f140e7d9dbb99e5e3822f728da6', - name: 'ABYSS', - symbol: 'ABYSS', - decimals: 18, - }, - { - address: '0x4ceda7906a5ed2179785cd3a40a69ee8bc99c466', - name: 'AION', - symbol: 'AION', - decimals: 8, - }, - { - address: '0xd8912c10681d8b21fd3742244f44658dba12264e', - name: 'Pluton', - symbol: 'PLU', - decimals: 18, - }, - { - address: '0x1a7a8bd9106f2b8d977e08582dc7d24c723ab0db', - name: 'AppCoins', - symbol: 'APPC', - decimals: 18, - }, - { - address: '0xba5f11b16b155792cf3b2e6880e8706859a8aeb6', - name: 'Aeron', - symbol: 'ARN', - decimals: 8, - }, - { - address: '0xfec0cf7fe078a500abf15f1284958f22049c2c7e', - name: 'Maecenas ART Token', - symbol: 'ART', - decimals: 18, - }, - { - address: '0x0f5d2fb29fb7d3cfee444a200298f468908cc942', - name: 'Decentraland', - symbol: 'MANA', - decimals: 18, - }, - { - address: '0x1c4481750daa5ff521a2a7490d9981ed46465dbd', - name: 'BlockMason Credit Protocol Token', - symbol: 'BCPT', - decimals: 18, - }, - { - address: '0x55296f69f40ea6d20e478533c15a6b08b654e758', - name: 'XY Oracle', - symbol: 'XYO', - decimals: 18, - }, - { - address: '0xd7732e3783b0047aa251928960063f863ad022d8', - name: 'BrahmaOS', - symbol: 'BRM', - decimals: 18, - }, - { - address: '0x7d4b8cce0591c9044a22ee543533b72e976e36c3', - name: 'Change Coin', - symbol: 'CAG', - decimals: 18, - }, - { - address: '0x1d462414fe14cf489c7a21cac78509f4bf8cd7c0', - name: 'CanYaCoin', - symbol: 'CAN', - decimals: 6, - }, - { - address: '0x1234567461d3f8db7496581774bd869c83d51c93', - name: 'BitClave', - symbol: 'CAT', - decimals: 18, - }, - { - address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - name: 'Dai Stablecoin v1.0', - symbol: 'DAI', - decimals: 18, - }, - { - address: '0x0cf0ee63788a0849fe5297f3407f701e122cc023', - name: 'Streamr DATAcoin', - symbol: 'DATA', - decimals: 18, - }, - { - address: '0x151202c9c18e495656f372281f493eb7698961d5', - name: 'DEBITUM', - symbol: 'DEB', - decimals: 18, - }, - { - address: '0xba2184520a1cc49a6159c57e61e1844e085615b6', - name: 'HelloGold Token', - symbol: 'HGT', - decimals: 8, - }, - { - address: '0x13f11c9905a08ca76e3e853be63d4f0944326c72', - name: 'Divi Exchange Token', - symbol: 'DIVX', - decimals: 18, - }, - { - address: '0x5b26c5d0772e5bbac8b3182ae9a13f9bb2d03765', - name: 'EDU Token', - symbol: 'EDU', - decimals: 8, - }, - { - address: '0xd49ff13661451313ca1553fd6954bd1d9b6e02b9', - name: 'ElectrifyAsia', - symbol: 'ELEC', - decimals: 18, - }, - { - address: '0x95daaab98046846bf4b2853e23cba236fa394a31', - name: 'EtheremonToken', - symbol: 'EMONT', - decimals: 8, - }, - { - address: '0x5bc7e5f0ab8b2e10d2d0a3f21739fce62459aef3', - name: 'Hut34 Entropy Token', - symbol: 'ENTR', - decimals: 18, - }, - { - address: '0x923108a439c4e8c2315c4f6521e5ce95b44e9b4c', - name: 'Devery.io', - symbol: 'EVE', - decimals: 18, - }, - { - address: '0xf8e386eda857484f5a12e4b5daa9984e06e73705', - name: 'Indorse Token', - symbol: 'IND', - decimals: 18, - }, - { - address: '0x4f4f0db4de903b88f2b1a2847971e231d54f8fd3', - name: 'Geens Platform Token', - symbol: 'GEE', - decimals: 8, - }, - { - address: '0x543ff227f64aa17ea132bf9886cab5db55dcaddf', - name: 'DAOstack', - symbol: 'GEN', - decimals: 18, - }, - { - address: '0x8a854288a5976036a725879164ca3e91d30c6a1b', - name: 'Guaranteed Entrance Token', - symbol: 'GET', - decimals: 18, - }, - { - address: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2', - name: 'Maker', - symbol: 'MKR', - decimals: 18, - }, - { - address: '0x9af839687f6c94542ac5ece2e317daae355493a1', - name: 'Hydro Protocol Token', - symbol: 'HOT', - decimals: 18, - }, - { - address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', - name: 'JET8 Token', - symbol: 'J8T', - decimals: 8, - }, - { - address: '0x8727c112c712c4a03371ac87a74dd6ab104af768', - name: 'Jetcoin Institute Token', - symbol: 'JET', - decimals: 18, - }, - { - address: '0xa4e8c3ec456107ea67d3075bf9e3df3a75823db0', - name: 'Loom Network Token', - symbol: 'LOOM', - decimals: 18, - }, - { - address: '0x957c30ab0426e0c93cd8241e2c60392d08c6ac8e', - name: 'Modum Token', - symbol: 'MOD', - decimals: 0, - }, - { - address: '0x2ef27bf41236bd859a95209e17a43fbd26851f92', - name: 'MORPH', - symbol: 'MORPH', - decimals: 4, - }, - { - address: '0x263c618480dbe35c300d8d5ecda19bbb986acaed', - name: 'MOT', - symbol: 'MOT', - decimals: 18, - }, - { - address: '0xffe02ee4c69edf1b340fcad64fbd6b37a7b9e265', - name: 'NANJCOIN', - symbol: 'NANJ', - decimals: 8, - }, - { - address: '0xc15a399c4ea7815fe36857c9e290ee452a5d6b21', - name: 'BoatPilot Token', - symbol: 'NAVI', - decimals: 18, - }, - { - address: '0x9e46a38f5daabe8683e10793b06749eef7d733d1', - name: 'PolySwarm Nectar', - symbol: 'NCT', - decimals: 18, - }, - { - address: '0xa54ddc7b3cce7fc8b1e3fa0256d0db80d2c10970', - name: 'NEVERDIE Coin', - symbol: 'NDC', - decimals: 18, - }, - { - address: '0xb62132e35a6c13ee1ee0f84dc5d40bad8d815206', - name: 'Nexo', - symbol: 'NEXO', - decimals: 18, - }, - { - address: '0x0235fe624e044a05eed7a43e16e3083bc8a4287a', - name: 'Original Crypto Coin', - symbol: 'OCC', - decimals: 18, - }, - { - address: '0xb5dbc6d3cf380079df3b27135664b6bcf45d1869', - name: 'Omix', - symbol: 'OMX', - decimals: 8, - }, - { - address: '0xfedae5642668f8636a11987ff386bfd215f942ee', - name: 'PolicyPal Network Token', - symbol: 'PAL', - decimals: 18, - }, - { - address: '0x2604fa406be957e542beb89e6754fcde6815e83f', - name: 'Playkey Token', - symbol: 'PKT', - decimals: 18, - }, - { - address: '0xe477292f1b3268687a29376116b0ed27a9c76170', - name: 'Herocoin', - symbol: 'PLAY', - decimals: 18, - }, - { - address: '0x1985365e9f78359a9b6ad760e32412f4a445e862', - name: 'Augur', - symbol: 'REP', - decimals: 18, - }, - { - address: '0x408e41876cccdc0f92210600ef50372656052a38', - name: 'Republic Protocol', - symbol: 'REN', - decimals: 18, - }, - { - address: '0xd0929d411954c47438dc1d871dd6081f5c5e149c', - name: 'Refereum', - symbol: 'RFR', - decimals: 4, - }, - { - address: '0x3d1ba9be9f66b8ee101911bc36d3fb562eac2244', - name: 'Rivetz', - symbol: 'RVT', - decimals: 18, - }, - { - address: '0x6888a16ea9792c15a4dcf2f6c623d055c8ede792', - name: 'Spectiv Signal Token', - symbol: 'SIG', - decimals: 18, - }, - { - address: '0x20f7a3ddf244dc9299975b4da1c39f8d5d75f05a', - name: 'Sapien Network Token', - symbol: 'SPN', - decimals: 6, - }, - { - address: '0xbbff862d906e348e9946bfb2132ecb157da3d4b4', - name: 'Sharder', - symbol: 'SS', - decimals: 18, - }, - { - address: '0x12b306fa98f4cbb8d4457fdff3a0a0a56f07ccdf', - name: 'Spectre.ai D-Token', - symbol: 'SXDT', - decimals: 18, - }, - { - address: '0xff3519eeeea3e76f1f699ccce5e23ee0bdda41ac', - name: 'Blockchain Capital', - symbol: 'BCAP', - decimals: 0, - }, - { - address: '0xced1a8529125d1bd06b54a7b01210df357d00885', - name: 'Too Real Badge', - symbol: 'TRL', - decimals: 0, - }, - { - address: '0xc86d054809623432210c107af2e3f619dcfbf652', - name: 'SENTINEL PROTOCOL', - symbol: 'UPP', - decimals: 18, - }, - { - address: '0x27f610bf36eca0939093343ac28b1534a721dbb4', - name: 'Wand Token', - symbol: 'WAND', - decimals: 18, - }, - { - address: '0x056017c55ae7ae32d12aef7c679df83a85ca75ff', - name: 'WyvernToken', - symbol: 'WYV', - decimals: 18, - }, - { - address: '0x5ca9a71b1d01849c0a95490cc00559717fcf0d1d', - name: 'Aeternity', - symbol: 'AE', - decimals: 18, - }, - { - address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', - name: 'Ink Protocol', - symbol: 'XNK', - decimals: 18, - }, - { - address: '0x0f513ffb4926ff82d7f60a05069047aca295c413', - name: 'CrowdstartCoin', - symbol: 'XSC', - decimals: 18, - }, - { - address: '0xb9e7f8568e08d5659f5d29c4997173d84cdf2607', - name: 'Swarm City Token', - symbol: 'SWT', - decimals: 18, - }, - { - address: '0x6531f133e6deebe7f2dce5a0441aa7ef330b4e53', - name: 'Chronobank TIME', - symbol: 'TIME', - decimals: 8, - }, - { - address: '0xf230b790e05390fc8295f4d3f60332c93bed42e2', - name: 'Tronix', - symbol: 'TRX', - decimals: 6, - }, - { - address: '0x5c543e7ae0a1104f78406c340e9c64fd9fce5170', - name: 'vSlice', - symbol: 'VSL', - decimals: 0, - }, - { - address: '0x4df812f6064def1e5e029f1ca858777cc98d2d81', - name: 'Xaurum', - symbol: 'XAUR', - decimals: 8, - }, - ], - '42': [ - { - address: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570', - name: '0x Protocol Token', - symbol: 'ZRX', - decimals: 18, - }, - { - address: '0x323b5d4c32345ced77393b3530b1eed0f346429d', - name: 'Melon Token', - symbol: 'MLN', - decimals: 18, - }, - { - address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba', - name: 'Maker DAO', - symbol: 'MKR', - decimals: 18, - }, - { - address: '0xeee3870657e4716670f185df08652dd848fe8f7e', - name: 'Digix DAO Token', - symbol: 'DGD', - decimals: 18, - }, - { - address: '0xb18845c260f680d5b9d84649638813e342e4f8c9', - name: 'Augur Reputation Token', - symbol: 'REP', - decimals: 18, - }, - { - address: '0xef7fff64389b814a946f3e92105513705ca6b990', - name: 'Golem Network Token', - symbol: 'GNT', - decimals: 18, - }, - { - address: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', - name: 'Wrapped Ether', - symbol: 'WETH', - decimals: 18, - }, - ], - '3': [ - { - address: '0xdf18648f5b4357d6cc1e27f7699af4f77ff44558', - name: 'token0', - symbol: 'TKN0', - decimals: 0, - }, - { - address: '0xd7cdcde4302a60c4d74a11eee21fbf455f476021', - name: 'token1', - symbol: 'TKN1', - decimals: 1, - }, - { - address: '0xf080f68c2113d40ff6a8528863f431908680900a', - name: 'token2', - symbol: 'TKN2', - decimals: 2, - }, - { - address: '0xe982b5c62434c98e27d15fed40447dda6b75c4eb', - name: 'token3', - symbol: 'TKN3', - decimals: 3, - }, - { - address: '0x2427d136751c1ca70480d3b2091261d639090a50', - name: 'token4', - symbol: 'TKN4', - decimals: 4, - }, - { - address: '0x7d3eca8ec55bb32bd0056edb9485b07a53d3fbfd', - name: 'token5', - symbol: 'TKN5', - decimals: 5, - }, - { - address: '0xff3c22e0a9014e9b4b1cf7a54bf39ab3107f6123', - name: 'token6', - symbol: 'TKN6', - decimals: 6, - }, - { - address: '0xdec283d9e188397c841ab59d9d9160fd47bc56f8', - name: 'token7', - symbol: 'TKN7', - decimals: 7, - }, - { - address: '0xedf5fd2f60d8fefbfa8011f2769b39657c54c3fd', - name: 'token8', - symbol: 'TKN8', - decimals: 8, - }, - { - address: '0xcd59fe7fa1a1a0ff536966a599b631d9cd5f2914', - name: 'token9', - symbol: 'TKN9', - decimals: 9, - }, - { - address: '0xaece1ee1813d56a5897f19ad50164565203b459f', - name: 'token10', - symbol: 'TKN10', - decimals: 10, - }, - { - address: '0xaab3f0619e529b1f1823be291daa7fcd38a15927', - name: 'token11', - symbol: 'TKN11', - decimals: 11, - }, - { - address: '0x2c46ad0b19cb1c1f3e51ae90d80654a227b08d30', - name: 'token12', - symbol: 'TKN12', - decimals: 12, - }, - { - address: '0x68977f3286a503f2b3930506f1b3a17dafbd9524', - name: 'token13', - symbol: 'TKN13', - decimals: 13, - }, - { - address: '0xe5c400b9ee56b823c6193a662041389624609db6', - name: 'token14', - symbol: 'TKN14', - decimals: 14, - }, - { - address: '0xf16ea9b23ddbeb6b16d253edf6b595da4009bb8b', - name: 'token16', - symbol: 'TKN16', - decimals: 16, - }, - { - address: '0x739a83860971e900c4bbbb92be6cfb9d459ef94a', - name: 'token15', - symbol: 'TKN15', - decimals: 15, - }, - { - address: '0x5eba21470cf683fe91b594afe7106039e38f3312', - name: 'token17', - symbol: 'TKN17', - decimals: 17, - }, - { - address: '0xc0ddd5df448907bb3f50350f3fe7a1da3fb2a2ee', - name: 'token18', - symbol: 'TKN18', - decimals: 18, - }, - { - address: '0x30fa25e53f8031014166fbd5e4bbeac0cd25df74', - name: 'token19', - symbol: 'TKN19', - decimals: 19, - }, - { - address: '0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d', - name: '0x Protocol Token', - symbol: 'ZRX', - decimals: 18, - }, - { - address: '0xc778417e063141139fce010982780140aa0cd5ab', - name: 'Ether Token', - symbol: 'WETH', - decimals: 18, - }, - { - address: '0x14823db576c11e4a54ca9e01ca0b28b18d3d1187', - name: 'b0x Protocol Token', - symbol: 'B0X', - decimals: 18, - }, - ], -}; // tslint:disable:max-file-line-count diff --git a/packages/website/ts/utils/fetch_utils.ts b/packages/website/ts/utils/fetch_utils.ts deleted file mode 100644 index 9afc5904d..000000000 --- a/packages/website/ts/utils/fetch_utils.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { fetchAsync, logUtils } from '@0x/utils'; -import * as _ from 'lodash'; -import * as queryString from 'query-string'; - -import { errorReporter } from 'ts/utils/error_reporter'; - -const logErrorIfPresent = (response: Response, requestedURL: string) => { - if (response.status !== 200) { - const errorText = `Error requesting url: ${requestedURL}, ${response.status}: ${response.statusText}`; - logUtils.log(errorText); - const error = Error(errorText); - errorReporter.report(error); - throw error; - } -}; - -export const fetchUtils = { - async requestAsync(baseUrl: string, path: string, queryParams?: object): Promise<any> { - const query = queryStringFromQueryParams(queryParams); - const url = `${baseUrl}${path}${query}`; - const response = await fetchAsync(url); - logErrorIfPresent(response, url); - const result = await response.json(); - return result; - }, - async postAsync(baseUrl: string, path: string, body: object): Promise<Response> { - const url = `${baseUrl}${path}`; - const response = await fetchAsync(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }); - logErrorIfPresent(response, url); - return response; - }, -}; - -function queryStringFromQueryParams(queryParams?: object): string { - // if params are undefined or empty, return an empty string - if (_.isUndefined(queryParams) || _.isEmpty(queryParams)) { - return ''; - } - // stringify the formatted object - const stringifiedParams = queryString.stringify(queryParams); - return `?${stringifiedParams}`; -} diff --git a/packages/website/ts/utils/mui_theme.ts b/packages/website/ts/utils/mui_theme.ts deleted file mode 100644 index 3f32254de..000000000 --- a/packages/website/ts/utils/mui_theme.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { colors } from '@0x/react-shared'; -import { getMuiTheme } from 'material-ui/styles'; - -export const muiTheme = getMuiTheme({ - appBar: { - height: 45, - color: colors.white, - textColor: colors.black, - }, - palette: { - accent1Color: colors.lightBlueA700, - pickerHeaderColor: colors.mediumBlue, - primary1Color: colors.mediumBlue, - primary2Color: colors.mediumBlue, - textColor: colors.grey700, - }, - datePicker: { - color: colors.grey700, - textColor: colors.white, - calendarTextColor: colors.grey, - selectColor: colors.darkestGrey, - selectTextColor: colors.white, - }, - timePicker: { - color: colors.grey700, - textColor: colors.white, - accentColor: colors.white, - headerColor: colors.darkestGrey, - selectColor: colors.darkestGrey, - selectTextColor: colors.darkestGrey, - }, -}); diff --git a/packages/website/ts/utils/order_parser.ts b/packages/website/ts/utils/order_parser.ts deleted file mode 100644 index 8938fbc53..000000000 --- a/packages/website/ts/utils/order_parser.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { orderParsingUtils } from '@0x/order-utils'; -import { logUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import { portalOrderSchema } from 'ts/schemas/portal_order_schema'; -import { validator } from 'ts/schemas/validator'; -import { PortalOrder } from 'ts/types'; - -export const orderParser = { - parseQueryString(queryString: string): PortalOrder | undefined { - if (queryString.length === 0) { - return undefined; - } - const queryParams = queryString.substring(1).split('&'); - const orderQueryParam = _.find(queryParams, queryParam => { - const queryPair = queryParam.split('='); - return queryPair[0] === 'order'; - }); - if (_.isUndefined(orderQueryParam)) { - return undefined; - } - const orderPair = orderQueryParam.split('='); - if (orderPair.length !== 2) { - return undefined; - } - const order = JSON.parse(decodeURIComponent(orderPair[1])); - const validationResult = validator.validate(order, portalOrderSchema); - if (validationResult.errors.length > 0) { - logUtils.log(`Invalid shared order: ${validationResult.errors}`); - return undefined; - } - const signedOrder = _.get(order, 'signedOrder'); - const convertedSignedOrder = orderParsingUtils.convertOrderStringFieldsToBigNumber(signedOrder); - const result = { - ...order, - signedOrder: convertedSignedOrder, - }; - return result; - }, - parseJsonString(orderJson: string): PortalOrder { - const order = JSON.parse(orderJson); - const signedOrder = _.get(order, 'signedOrder'); - const convertedSignedOrder = orderParsingUtils.convertOrderStringFieldsToBigNumber(signedOrder); - const result = { - ...order, - signedOrder: convertedSignedOrder, - }; - return result; - }, -}; diff --git a/packages/website/ts/utils/token_address_overrides.ts b/packages/website/ts/utils/token_address_overrides.ts deleted file mode 100644 index 5e7275964..000000000 --- a/packages/website/ts/utils/token_address_overrides.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ObjectMap } from '@0x/types'; -import { constants } from 'ts/utils/constants'; - -// Map of networkId -> tokenSymbol -> tokenAddress -export type TokenOverrides = ObjectMap<ObjectMap<string>>; - -export const tokenAddressOverrides: TokenOverrides = { - [constants.NETWORK_ID_KOVAN]: { - ZRX: '0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa', - REP: '0x8cb3971b8eb709c14616bd556ff6683019e90d9c', - DGD: '0xa4f468c9c692eb6b4b8b06270dae7a2cfeedcde9', - GNT: '0x31fb614e223706f15d0d3c5f4b08bdf0d5c78623', - MKR: '0x7b6b10caa9e8e9552ba72638ea5b47c25afea1f3', - MLN: '0x17e394d1df6ce29d042195ea38411a98ff3ead94', - }, - [constants.NETWORK_ID_ROPSTEN]: { - ZRX: '0xff67881f8d12f372d91baae9752eb3631ff0ed00', - REP: '0xb0b443fe0e8a04c4c85e8fda9c5c1ccc057d6653', - DGD: '0xc4895a5aafa2708d6bc1294e20ec839aad156b1d', - GNT: '0x7f8acc55a359ca4517c30510566ac35b800f7cac', - MKR: '0x06732516acd125b6e83c127752ed5f027e1b276e', - MLN: '0x823ebe83d39115536274a8617e00a1ff3544fd63', - }, -}; diff --git a/packages/website/ts/utils/translate.ts b/packages/website/ts/utils/translate.ts deleted file mode 100644 index af5c766a9..000000000 --- a/packages/website/ts/utils/translate.ts +++ /dev/null @@ -1,101 +0,0 @@ -import * as _ from 'lodash'; -import { Deco, Key, Language } from 'ts/types'; - -import chinese from '../../translations/chinese.json'; -import english from '../../translations/english.json'; -import korean from '../../translations/korean.json'; -import russian from '../../translations/russian.json'; -import spanish from '../../translations/spanish.json'; - -const languageToTranslations = { - [Language.English]: english, - [Language.Spanish]: spanish, - [Language.Chinese]: chinese, - [Language.Korean]: korean, - [Language.Russian]: russian, -}; - -const languagesWithoutCaps = [Language.Chinese, Language.Korean]; - -interface Translation { - [key: string]: string; -} - -export class Translate { - private _selectedLanguage: Language; - private _translation: Translation; - constructor(desiredLanguage?: Language) { - if (!_.isUndefined(desiredLanguage)) { - this.setLanguage(desiredLanguage); - return; - } - const browserLanguage = (window.navigator as any).userLanguage || window.navigator.language || 'en-US'; - let language = Language.English; - if (_.includes(browserLanguage, 'es-')) { - language = Language.Spanish; - } else if (_.includes(browserLanguage, 'zh-')) { - language = Language.Chinese; - } else if (_.includes(browserLanguage, 'ko-')) { - language = Language.Korean; - } else if (_.includes(browserLanguage, 'ru-')) { - language = Language.Russian; - } - this.setLanguage(language); - } - public getLanguage(): Language { - return this._selectedLanguage; - } - public setLanguage(language: Language): void { - const isLanguageSupported = !_.isUndefined(languageToTranslations[language]); - if (!isLanguageSupported) { - throw new Error(`${language} not supported`); - } - this._selectedLanguage = language; - this._translation = languageToTranslations[language]; - } - public get(key: Key, decoration?: Deco): string { - let text = this._translation[key]; - // if a translation does not exist for a certain language, fallback to english - // if it still doesn't exist in english, throw an error - if (_.isUndefined(text)) { - const englishTranslation: Translation = languageToTranslations[Language.English]; - const englishText = englishTranslation[key]; - if (!_.isUndefined(englishText)) { - text = englishText; - } else { - throw new Error( - `Translation key not available in ${this._selectedLanguage} or ${Language.English}: ${key}`, - ); - } - } - if (!_.isUndefined(decoration) && !_.includes(languagesWithoutCaps, this._selectedLanguage)) { - switch (decoration) { - case Deco.Cap: - text = this._capitalize(text); - break; - - case Deco.Upper: - text = text.toUpperCase(); - break; - - case Deco.CapWords: - const words = text.split(' '); - const capitalizedWords = _.map(words, (w: string, i: number) => { - if (w.length === 1) { - return w; - } - return this._capitalize(w); - }); - text = capitalizedWords.join(' '); - break; - - default: - throw new Error(`Unrecognized decoration: ${decoration}`); - } - } - return text; - } - private _capitalize(text: string): string { - return `${text.charAt(0).toUpperCase()}${text.slice(1)}`; - } -} diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts deleted file mode 100644 index e84f9d0cc..000000000 --- a/packages/website/ts/utils/utils.ts +++ /dev/null @@ -1,483 +0,0 @@ -import { ContractWrappersError } from '@0x/contract-wrappers'; -import { assetDataUtils, OrderError } from '@0x/order-utils'; -import { constants as sharedConstants, Networks } from '@0x/react-shared'; -import { ExchangeContractErrs } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as bowser from 'bowser'; -import deepEqual from 'deep-equal'; -import * as _ from 'lodash'; -import * as moment from 'moment'; -import * as numeral from 'numeral'; - -import { Provider } from 'ethereum-types'; -import { - AccountState, - BlockchainCallErrs, - BrowserType, - Environments, - OperatingSystemType, - PortalOrder, - Providers, - ProviderType, - ScreenWidths, - Side, - SideToAssetToken, - Token, - TokenByAddress, - TokenState, -} from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import * as u2f from 'ts/vendor/u2f_api'; - -export const utils = { - assert(condition: boolean, message: string): void { - if (!condition) { - throw new Error(message); - } - }, - isNumeric(n: string): boolean { - return !isNaN(parseFloat(n)) && isFinite(Number(n)); - }, - // This default unix timestamp is used for orders where the user does not specify an expiry date. - // It is a fixed constant so that both the redux store's INITIAL_STATE and components can check for - // whether a user has set an expiry date or not. It is set unrealistically high so as not to collide - // with actual values a user would select. - initialOrderExpiryUnixTimestampSec(): BigNumber { - const m = moment('2050-01-01'); - return new BigNumber(m.unix()); - }, - convertToUnixTimestampSeconds(date: moment.Moment, time?: moment.Moment): BigNumber { - const finalMoment = date; - if (!_.isUndefined(time)) { - finalMoment.hours(time.hours()); - finalMoment.minutes(time.minutes()); - } - return new BigNumber(finalMoment.unix()); - }, - convertToMomentFromUnixTimestamp(unixTimestampSec: BigNumber): moment.Moment { - return moment.unix(unixTimestampSec.toNumber()); - }, - convertToReadableDateTimeFromUnixTimestamp(unixTimestampSec: BigNumber): string { - const m = utils.convertToMomentFromUnixTimestamp(unixTimestampSec); - const formattedDate: string = m.format('h:MMa MMMM D YYYY'); - return formattedDate; - }, - generateOrder( - exchangeAddress: string, - sideToAssetToken: SideToAssetToken, - expirationTimeSeconds: BigNumber, - orderTakerAddress: string, - orderMakerAddress: string, - makerFee: BigNumber, - takerFee: BigNumber, - feeRecipientAddress: string, - signature: string, - tokenByAddress: TokenByAddress, - orderSalt: BigNumber, - ): PortalOrder { - const makerToken = tokenByAddress[sideToAssetToken[Side.Deposit].address]; - const takerToken = tokenByAddress[sideToAssetToken[Side.Receive].address]; - const order = { - signedOrder: { - senderAddress: constants.NULL_ADDRESS, - makerAddress: orderMakerAddress, - takerAddress: orderTakerAddress, - makerFee, - takerFee, - makerAssetAmount: sideToAssetToken[Side.Deposit].amount, - takerAssetAmount: sideToAssetToken[Side.Receive].amount, - makerAssetData: assetDataUtils.encodeERC20AssetData(makerToken.address), - takerAssetData: assetDataUtils.encodeERC20AssetData(takerToken.address), - expirationTimeSeconds, - feeRecipientAddress, - salt: orderSalt, - signature, - exchangeAddress, - }, - metadata: { - makerToken: { - name: makerToken.name, - symbol: makerToken.symbol, - decimals: makerToken.decimals, - }, - takerToken: { - name: takerToken.name, - symbol: takerToken.symbol, - decimals: takerToken.decimals, - }, - }, - }; - return order; - }, - async sleepAsync(ms: number): Promise<NodeJS.Timer> { - return new Promise<NodeJS.Timer>(resolve => setTimeout(resolve, ms)); - }, - deepEqual(actual: any, expected: any, opts?: { strict: boolean }): boolean { - return deepEqual(actual, expected, opts); - }, - getColSize(items: number): number { - const bassCssGridSize = 12; // Source: http://basscss.com/#basscss-grid - const colSize = bassCssGridSize / items; - if (!_.isInteger(colSize)) { - throw new Error(`Number of cols must be divisible by ${bassCssGridSize}`); - } - return colSize; - }, - getScreenWidth(): ScreenWidths { - const documentEl = document.documentElement; - const body = document.getElementsByTagName('body')[0]; - const widthInPx = window.innerWidth || documentEl.clientWidth || body.clientWidth; - const bodyStyles: any = window.getComputedStyle(document.querySelector('body')); - const widthInEm = widthInPx / parseFloat(bodyStyles['font-size']); - - // This logic mirrors the CSS media queries in BassCSS for the `lg-`, `md-` and `sm-` CSS - // class prefixes. Do not edit these. - if (widthInEm > ScreenWidths.Lg) { - return ScreenWidths.Lg; - } else if (widthInEm > ScreenWidths.Md) { - return ScreenWidths.Md; - } else { - return ScreenWidths.Sm; - } - }, - async isU2FSupportedAsync(): Promise<boolean> { - const w = window as any; - return new Promise((resolve: (isSupported: boolean) => void) => { - if (w.u2f && !w.u2f.getApiVersion) { - // u2f object was found (Firefox with extension) - resolve(true); - } else { - // u2f object was not found. Using Google polyfill - // HACK: u2f.getApiVersion will simply not return a version if the - // U2F call fails for any reason. Because of this, we set a hard 3sec - // timeout to the request on our end. - const getApiVersionTimeoutMs = 3000; - const intervalId = setTimeout(() => { - resolve(false); - }, getApiVersionTimeoutMs); - u2f.getApiVersion((_version: number) => { - clearTimeout(intervalId); - resolve(true); - }); - } - }); - }, - // This checks the error message returned from an injected Web3 instance on the page - // after a user was prompted to sign a message or send a transaction and decided to - // reject the request. - didUserDenyWeb3Request(errMsg: string): boolean { - const metamaskDenialErrMsg = 'User denied'; - const paritySignerDenialErrMsg = 'Request has been rejected'; - const ledgerDenialErrMsg = 'Invalid status 6985'; - const isUserDeniedErrMsg = - _.includes(errMsg, metamaskDenialErrMsg) || - _.includes(errMsg, paritySignerDenialErrMsg) || - _.includes(errMsg, ledgerDenialErrMsg); - return isUserDeniedErrMsg; - }, - getAddressBeginAndEnd(address: string): string { - const truncatedAddress = `${address.substring(0, 6)}...${address.substr(-4)}`; // 0x3d5a...b287 - return truncatedAddress; - }, - getReadableAccountState(accountState: AccountState, userAddress: string): string { - switch (accountState) { - case AccountState.Loading: - return 'Loading...'; - case AccountState.Ready: - return utils.getAddressBeginAndEnd(userAddress); - case AccountState.Locked: - return 'Please Unlock'; - case AccountState.Disconnected: - return 'Connect a Wallet'; - default: - return ''; - } - }, - getAccountState( - isBlockchainReady: boolean, - providerType: ProviderType, - injectedProviderName: string, - userAddress?: string, - ): AccountState { - const isAddressAvailable = !_.isUndefined(userAddress) && !_.isEmpty(userAddress); - const isExternallyInjectedProvider = utils.isExternallyInjected(providerType, injectedProviderName); - if (!isBlockchainReady) { - return AccountState.Loading; - } else if (isAddressAvailable) { - return AccountState.Ready; - // tslint:disable-next-line: prefer-conditional-expression - } else if (isExternallyInjectedProvider) { - return AccountState.Locked; - } else { - return AccountState.Disconnected; - } - }, - hasUniqueNameAndSymbol(tokens: Token[], token: Token): boolean { - if (token.isRegistered) { - return true; // Since it's registered, it is the canonical token - } - const registeredTokens = _.filter(tokens, t => t.isRegistered); - const tokenWithSameNameIfExists = _.find(registeredTokens, { - name: token.name, - }); - const isUniqueName = _.isUndefined(tokenWithSameNameIfExists); - const tokenWithSameSymbolIfExists = _.find(registeredTokens, { - name: token.symbol, - }); - const isUniqueSymbol = _.isUndefined(tokenWithSameSymbolIfExists); - return isUniqueName && isUniqueSymbol; - }, - zeroExErrToHumanReadableErrMsg(error: ContractWrappersError | ExchangeContractErrs, takerAddress: string): string { - const ContractWrappersErrorToHumanReadableError: { [error: string]: string } = { - [BlockchainCallErrs.UserHasNoAssociatedAddresses]: 'User has no addresses available', - [OrderError.InvalidSignature]: 'Order signature is not valid', - [ContractWrappersError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network', - [ContractWrappersError.InvalidJump]: 'Invalid jump occured while executing the transaction', - [ContractWrappersError.OutOfGas]: 'Transaction ran out of gas', - }; - const exchangeContractErrorToHumanReadableError: { - [error: string]: string; - } = { - [ExchangeContractErrs.OrderFillExpired]: 'This order has expired', - [ExchangeContractErrs.OrderCancelExpired]: 'This order has expired', - [ExchangeContractErrs.OrderCancelled]: 'This order has been cancelled', - [ExchangeContractErrs.OrderFillAmountZero]: "Order fill amount can't be 0", - [ExchangeContractErrs.OrderRemainingFillAmountZero]: 'This order has already been completely filled', - [ExchangeContractErrs.OrderFillRoundingError]: - 'Rounding error will occur when filling this order. Please try filling a different amount.', - [ExchangeContractErrs.InsufficientTakerBalance]: - 'Taker no longer has a sufficient balance to complete this order', - [ExchangeContractErrs.InsufficientTakerAllowance]: - 'Taker no longer has a sufficient allowance to complete this order', - [ExchangeContractErrs.InsufficientMakerBalance]: - 'Maker no longer has a sufficient balance to complete this order', - [ExchangeContractErrs.InsufficientMakerAllowance]: - 'Maker no longer has a sufficient allowance to complete this order', - [ExchangeContractErrs.InsufficientTakerFeeBalance]: 'Taker no longer has a sufficient balance to pay fees', - [ExchangeContractErrs.InsufficientTakerFeeAllowance]: - 'Taker no longer has a sufficient allowance to pay fees', - [ExchangeContractErrs.InsufficientMakerFeeBalance]: 'Maker no longer has a sufficient balance to pay fees', - [ExchangeContractErrs.InsufficientMakerFeeAllowance]: - 'Maker no longer has a sufficient allowance to pay fees', - [ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker]: `This order can only be filled by ${takerAddress}`, - [ExchangeContractErrs.InsufficientRemainingFillAmount]: 'Insufficient remaining fill amount', - }; - const humanReadableErrorMsg = - exchangeContractErrorToHumanReadableError[error] || ContractWrappersErrorToHumanReadableError[error]; - return humanReadableErrorMsg; - }, - isParityNode(nodeVersion: string): boolean { - return _.includes(nodeVersion, 'Parity'); - }, - isTestRpc(nodeVersion: string): boolean { - return _.includes(nodeVersion, 'TestRPC'); - }, - isTestNetwork(networkId: number): boolean { - const isTestNetwork = _.includes( - [ - sharedConstants.NETWORK_ID_BY_NAME[Networks.Kovan], - sharedConstants.NETWORK_ID_BY_NAME[Networks.Rinkeby], - sharedConstants.NETWORK_ID_BY_NAME[Networks.Ropsten], - ], - networkId, - ); - return isTestNetwork; - }, - getCurrentBaseUrl(): string { - const port = window.location.port; - const hasPort = !_.isUndefined(port); - const baseUrl = `https://${window.location.hostname}${hasPort ? `:${port}` : ''}`; - return baseUrl; - }, - onPageLoadPromise: new Promise<void>((resolve, _reject) => { - if (document.readyState === 'complete') { - resolve(); - return; - } - window.onload = () => resolve(); - }), - getProviderType(provider: Provider): Providers | string { - const constructorName = provider.constructor.name; - let parsedProviderName = constructorName; - // https://ethereum.stackexchange.com/questions/24266/elegant-way-to-detect-current-provider-int-web3-js - switch (constructorName) { - case 'EthereumProvider': - parsedProviderName = Providers.Mist; - break; - - default: - parsedProviderName = constructorName; - break; - } - if ((provider as any).isParity) { - parsedProviderName = Providers.Parity; - } else if ((provider as any).isMetaMask) { - parsedProviderName = Providers.Metamask; - } else if (!_.isUndefined(_.get(window, 'SOFA'))) { - parsedProviderName = Providers.CoinbaseWallet; - } else if (!_.isUndefined(_.get(window, '__CIPHER__'))) { - parsedProviderName = Providers.Cipher; - } - return parsedProviderName; - }, - getBackendBaseUrl(): string { - return utils.isDogfood() ? configs.BACKEND_BASE_STAGING_URL : configs.BACKEND_BASE_PROD_URL; - }, - isDevelopment(): boolean { - return _.includes(configs.DOMAINS_DEVELOPMENT, window.location.host); - }, - isStaging(): boolean { - return _.includes(window.location.href, configs.DOMAIN_STAGING); - }, - isExternallyInjected(providerType: ProviderType, injectedProviderName: string): boolean { - return providerType === ProviderType.Injected && injectedProviderName !== constants.PROVIDER_NAME_PUBLIC; - }, - isDogfood(): boolean { - return _.includes(window.location.href, configs.DOMAIN_DOGFOOD); - }, - isProduction(): boolean { - return _.includes(window.location.href, configs.DOMAIN_PRODUCTION); - }, - getEnvironment(): Environments { - if (utils.isDogfood()) { - return Environments.Dogfood; - } - if (utils.isDevelopment()) { - return Environments.Development; - } - if (utils.isStaging()) { - return Environments.Staging; - } - if (utils.isProduction()) { - return Environments.Production; - } - return Environments.Unknown; - }, - getEthToken(tokenByAddress: TokenByAddress): Token { - return utils.getTokenBySymbol(constants.ETHER_TOKEN_SYMBOL, tokenByAddress); - }, - getZrxToken(tokenByAddress: TokenByAddress): Token { - return utils.getTokenBySymbol(constants.ZRX_TOKEN_SYMBOL, tokenByAddress); - }, - getTokenBySymbol(symbol: string, tokenByAddress: TokenByAddress): Token { - const tokens = _.values(tokenByAddress); - const token = _.find(tokens, { symbol }); - return token; - }, - getTrackedTokens(tokenByAddress: TokenByAddress): Token[] { - const allTokens = _.values(tokenByAddress); - const trackedTokens = _.filter(allTokens, t => utils.isTokenTracked(t)); - return trackedTokens; - }, - getFormattedAmountFromToken(token: Token, tokenState: TokenState): string { - return utils.getFormattedAmount(tokenState.balance, token.decimals); - }, - format(value: BigNumber, format: string): string { - const formattedAmount = numeral(value).format(format); - if (_.isNaN(formattedAmount)) { - // https://github.com/adamwdraper/Numeral-js/issues/596 - return numeral(new BigNumber(0)).format(format); - } - return formattedAmount; - }, - getFormattedAmount(amount: BigNumber, decimals: number): string { - const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals); - // if the unit amount is less than 1, show the natural number of decimal places with a max of 4 - // if the unit amount is greater than or equal to 1, show only 2 decimal places - const lessThanOnePrecision = Math.min(constants.TOKEN_AMOUNT_DISPLAY_PRECISION, unitAmount.decimalPlaces()); - const greaterThanOnePrecision = 2; - const precision = unitAmount.lt(1) ? lessThanOnePrecision : greaterThanOnePrecision; - const format = `0,0.${_.repeat('0', precision)}`; - return utils.format(unitAmount, format); - }, - getUsdValueFormattedAmount(amount: BigNumber, decimals: number, price: BigNumber): string { - const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals); - const value = unitAmount.multipliedBy(price); - return utils.format(value, constants.NUMERAL_USD_FORMAT); - }, - openUrl(url: string): void { - window.open(url, '_blank'); - }, - isMobileWidth(screenWidth: ScreenWidths): boolean { - return screenWidth === ScreenWidths.Sm; - }, - isMobileOperatingSystem(): boolean { - return bowser.mobile; - }, - getBrowserType(): BrowserType { - if (bowser.chrome) { - return BrowserType.Chrome; - } else if (bowser.firefox) { - return BrowserType.Firefox; - } else if (bowser.opera) { - return BrowserType.Opera; - } else if (bowser.msedge) { - return BrowserType.Edge; - } else if (bowser.safari) { - return BrowserType.Safari; - } else { - return BrowserType.Other; - } - }, - getOperatingSystem(): OperatingSystemType { - if (bowser.android) { - return OperatingSystemType.Android; - } else if (bowser.ios) { - return OperatingSystemType.iOS; - } else if (bowser.mac) { - return OperatingSystemType.Mac; - } else if (bowser.windows) { - return OperatingSystemType.Windows; - } else if (bowser.windowsphone) { - return OperatingSystemType.WindowsPhone; - } else if (bowser.linux) { - return OperatingSystemType.Linux; - } else { - return OperatingSystemType.Other; - } - }, - isTokenTracked(token: Token): boolean { - return !_.isUndefined(token.trackedTimestamp); - }, - // Returns a [downloadLink, isOnMobile] tuple. - getBestWalletDownloadLinkAndIsMobile(): [string, boolean] { - const browserType = utils.getBrowserType(); - const isOnMobile = utils.isMobileOperatingSystem(); - const operatingSystem = utils.getOperatingSystem(); - let downloadLink; - if (isOnMobile) { - switch (operatingSystem) { - case OperatingSystemType.Android: - downloadLink = constants.URL_COINBASE_WALLET_ANDROID_APP_STORE; - break; - case OperatingSystemType.iOS: - downloadLink = constants.URL_COINBASE_WALLET_IOS_APP_STORE; - break; - default: - // Coinbase wallet is only supported on these mobile OSes - just default to iOS - downloadLink = constants.URL_COINBASE_WALLET_IOS_APP_STORE; - } - } else { - switch (browserType) { - case BrowserType.Chrome: - downloadLink = constants.URL_METAMASK_CHROME_STORE; - break; - case BrowserType.Firefox: - downloadLink = constants.URL_METAMASK_FIREFOX_STORE; - break; - case BrowserType.Opera: - downloadLink = constants.URL_METAMASK_OPERA_STORE; - break; - default: - downloadLink = constants.URL_METAMASK_HOMEPAGE; - } - } - return [downloadLink, isOnMobile]; - }, - getTokenIconUrl(symbol: string): string { - const result = `/images/token_icons/${symbol}.png`; - return result; - }, -}; diff --git a/packages/website/ts/vendor/u2f_api.js b/packages/website/ts/vendor/u2f_api.js deleted file mode 100644 index 3b538d817..000000000 --- a/packages/website/ts/vendor/u2f_api.js +++ /dev/null @@ -1,760 +0,0 @@ -//Copyright 2014-2015 Google Inc. All rights reserved. - -//Use of this source code is governed by a BSD-style -//license that can be found in the LICENSE file or at -//https://developers.google.com/open-source/licenses/bsd - -/** - * @fileoverview The U2F api. - */ -'use strict'; - - -/** - * Namespace for the U2F api. - * @type {Object} - */ -var u2f = u2f || {}; - -/** - * Require integration - */ -if (typeof module != "undefined") { - module.exports = u2f; -} - -/** - * FIDO U2F Javascript API Version - * @number - */ -var js_api_version; - -/** - * The U2F extension id - * @const {string} - */ -// The Chrome packaged app extension ID. -// Uncomment this if you want to deploy a server instance that uses -// the package Chrome app and does not require installing the U2F Chrome extension. - u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd'; -// The U2F Chrome extension ID. -// Uncomment this if you want to deploy a server instance that uses -// the U2F Chrome extension to authenticate. -// u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne'; - - -/** - * Message types for messsages to/from the extension - * @const - * @enum {string} - */ -u2f.MessageTypes = { - 'U2F_REGISTER_REQUEST': 'u2f_register_request', - 'U2F_REGISTER_RESPONSE': 'u2f_register_response', - 'U2F_SIGN_REQUEST': 'u2f_sign_request', - 'U2F_SIGN_RESPONSE': 'u2f_sign_response', - 'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request', - 'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response' -}; - - -/** - * Response status codes - * @const - * @enum {number} - */ -u2f.ErrorCodes = { - 'OK': 0, - 'OTHER_ERROR': 1, - 'BAD_REQUEST': 2, - 'CONFIGURATION_UNSUPPORTED': 3, - 'DEVICE_INELIGIBLE': 4, - 'TIMEOUT': 5 -}; - - -/** - * A message for registration requests - * @typedef {{ - * type: u2f.MessageTypes, - * appId: ?string, - * timeoutSeconds: ?number, - * requestId: ?number - * }} - */ -u2f.U2fRequest; - - -/** - * A message for registration responses - * @typedef {{ - * type: u2f.MessageTypes, - * responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse), - * requestId: ?number - * }} - */ -u2f.U2fResponse; - - -/** - * An error object for responses - * @typedef {{ - * errorCode: u2f.ErrorCodes, - * errorMessage: ?string - * }} - */ -u2f.Error; - -/** - * Data object for a single sign request. - * @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}} - */ -u2f.Transport; - - -/** - * Data object for a single sign request. - * @typedef {Array<u2f.Transport>} - */ -u2f.Transports; - -/** - * Data object for a single sign request. - * @typedef {{ - * version: string, - * challenge: string, - * keyHandle: string, - * appId: string - * }} - */ -u2f.SignRequest; - - -/** - * Data object for a sign response. - * @typedef {{ - * keyHandle: string, - * signatureData: string, - * clientData: string - * }} - */ -u2f.SignResponse; - - -/** - * Data object for a registration request. - * @typedef {{ - * version: string, - * challenge: string - * }} - */ -u2f.RegisterRequest; - - -/** - * Data object for a registration response. - * @typedef {{ - * version: string, - * keyHandle: string, - * transports: Transports, - * appId: string - * }} - */ -u2f.RegisterResponse; - - -/** - * Data object for a registered key. - * @typedef {{ - * version: string, - * keyHandle: string, - * transports: ?Transports, - * appId: ?string - * }} - */ -u2f.RegisteredKey; - - -/** - * Data object for a get API register response. - * @typedef {{ - * js_api_version: number - * }} - */ -u2f.GetJsApiVersionResponse; - - -//Low level MessagePort API support - -/** - * Sets up a MessagePort to the U2F extension using the - * available mechanisms. - * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback - */ -u2f.getMessagePort = function(callback) { - if (typeof chrome != 'undefined' && chrome.runtime) { - // The actual message here does not matter, but we need to get a reply - // for the callback to run. Thus, send an empty signature request - // in order to get a failure response. - var msg = { - type: u2f.MessageTypes.U2F_SIGN_REQUEST, - signRequests: [] - }; - chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() { - if (!chrome.runtime.lastError) { - // We are on a whitelisted origin and can talk directly - // with the extension. - u2f.getChromeRuntimePort_(callback); - } else { - // chrome.runtime was available, but we couldn't message - // the extension directly, use iframe - u2f.getIframePort_(callback); - } - }); - } else if (u2f.isAndroidChrome_()) { - u2f.getAuthenticatorPort_(callback); - } else if (u2f.isIosChrome_()) { - u2f.getIosPort_(callback); - } else { - // chrome.runtime was not available at all, which is normal - // when this origin doesn't have access to any extensions. - u2f.getIframePort_(callback); - } -}; - -/** - * Detect chrome running on android based on the browser's useragent. - * @private - */ -u2f.isAndroidChrome_ = function() { - var userAgent = navigator.userAgent; - return userAgent.indexOf('Chrome') != -1 && - userAgent.indexOf('Android') != -1; -}; - -/** - * Detect chrome running on iOS based on the browser's platform. - * @private - */ -u2f.isIosChrome_ = function() { - return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1; -}; - -/** - * Connects directly to the extension via chrome.runtime.connect. - * @param {function(u2f.WrappedChromeRuntimePort_)} callback - * @private - */ -u2f.getChromeRuntimePort_ = function(callback) { - var port = chrome.runtime.connect(u2f.EXTENSION_ID, - {'includeTlsChannelId': true}); - setTimeout(function() { - callback(new u2f.WrappedChromeRuntimePort_(port)); - }, 0); -}; - -/** - * Return a 'port' abstraction to the Authenticator app. - * @param {function(u2f.WrappedAuthenticatorPort_)} callback - * @private - */ -u2f.getAuthenticatorPort_ = function(callback) { - setTimeout(function() { - callback(new u2f.WrappedAuthenticatorPort_()); - }, 0); -}; - -/** - * Return a 'port' abstraction to the iOS client app. - * @param {function(u2f.WrappedIosPort_)} callback - * @private - */ -u2f.getIosPort_ = function(callback) { - setTimeout(function() { - callback(new u2f.WrappedIosPort_()); - }, 0); -}; - -/** - * A wrapper for chrome.runtime.Port that is compatible with MessagePort. - * @param {Port} port - * @constructor - * @private - */ -u2f.WrappedChromeRuntimePort_ = function(port) { - this.port_ = port; -}; - -/** - * Format and return a sign request compliant with the JS API version supported by the extension. - * @param {Array<u2f.SignRequest>} signRequests - * @param {number} timeoutSeconds - * @param {number} reqId - * @return {Object} - */ -u2f.formatSignRequest_ = - function(appId, challenge, registeredKeys, timeoutSeconds, reqId) { - if (js_api_version === undefined || js_api_version < 1.1) { - // Adapt request to the 1.0 JS API - var signRequests = []; - for (var i = 0; i < registeredKeys.length; i++) { - signRequests[i] = { - version: registeredKeys[i].version, - challenge: challenge, - keyHandle: registeredKeys[i].keyHandle, - appId: appId - }; - } - return { - type: u2f.MessageTypes.U2F_SIGN_REQUEST, - signRequests: signRequests, - timeoutSeconds: timeoutSeconds, - requestId: reqId - }; - } - // JS 1.1 API - return { - type: u2f.MessageTypes.U2F_SIGN_REQUEST, - appId: appId, - challenge: challenge, - registeredKeys: registeredKeys, - timeoutSeconds: timeoutSeconds, - requestId: reqId - }; -}; - -/** - * Format and return a register request compliant with the JS API version supported by the extension.. - * @param {Array<u2f.SignRequest>} signRequests - * @param {Array<u2f.RegisterRequest>} signRequests - * @param {number} timeoutSeconds - * @param {number} reqId - * @return {Object} - */ -u2f.formatRegisterRequest_ = - function(appId, registeredKeys, registerRequests, timeoutSeconds, reqId) { - if (js_api_version === undefined || js_api_version < 1.1) { - // Adapt request to the 1.0 JS API - for (var i = 0; i < registerRequests.length; i++) { - registerRequests[i].appId = appId; - } - var signRequests = []; - for (var i = 0; i < registeredKeys.length; i++) { - signRequests[i] = { - version: registeredKeys[i].version, - challenge: registerRequests[0], - keyHandle: registeredKeys[i].keyHandle, - appId: appId - }; - } - return { - type: u2f.MessageTypes.U2F_REGISTER_REQUEST, - signRequests: signRequests, - registerRequests: registerRequests, - timeoutSeconds: timeoutSeconds, - requestId: reqId - }; - } - // JS 1.1 API - return { - type: u2f.MessageTypes.U2F_REGISTER_REQUEST, - appId: appId, - registerRequests: registerRequests, - registeredKeys: registeredKeys, - timeoutSeconds: timeoutSeconds, - requestId: reqId - }; -}; - - -/** - * Posts a message on the underlying channel. - * @param {Object} message - */ -u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) { - this.port_.postMessage(message); -}; - - -/** - * Emulates the HTML 5 addEventListener interface. Works only for the - * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage. - * @param {string} eventName - * @param {function({data: Object})} handler - */ -u2f.WrappedChromeRuntimePort_.prototype.addEventListener = - function(eventName, handler) { - var name = eventName.toLowerCase(); - if (name == 'message' || name == 'onmessage') { - this.port_.onMessage.addListener(function(message) { - // Emulate a minimal MessageEvent object - handler({'data': message}); - }); - } else { - console.error('WrappedChromeRuntimePort only supports onMessage'); - } -}; - -/** - * Wrap the Authenticator app with a MessagePort interface. - * @constructor - * @private - */ -u2f.WrappedAuthenticatorPort_ = function() { - this.requestId_ = -1; - this.requestObject_ = null; -} - -/** - * Launch the Authenticator intent. - * @param {Object} message - */ -u2f.WrappedAuthenticatorPort_.prototype.postMessage = function(message) { - var intentUrl = - u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ + - ';S.request=' + encodeURIComponent(JSON.stringify(message)) + - ';end'; - document.location = intentUrl; -}; - -/** - * Tells what type of port this is. - * @return {String} port type - */ -u2f.WrappedAuthenticatorPort_.prototype.getPortType = function() { - return "WrappedAuthenticatorPort_"; -}; - - -/** - * Emulates the HTML 5 addEventListener interface. - * @param {string} eventName - * @param {function({data: Object})} handler - */ -u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function(eventName, handler) { - var name = eventName.toLowerCase(); - if (name == 'message') { - var self = this; - /* Register a callback to that executes when - * chrome injects the response. */ - window.addEventListener( - 'message', self.onRequestUpdate_.bind(self, handler), false); - } else { - console.error('WrappedAuthenticatorPort only supports message'); - } -}; - -/** - * Callback invoked when a response is received from the Authenticator. - * @param function({data: Object}) callback - * @param {Object} message message Object - */ -u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ = - function(callback, message) { - var messageObject = JSON.parse(message.data); - var intentUrl = messageObject['intentURL']; - - var errorCode = messageObject['errorCode']; - var responseObject = null; - if (messageObject.hasOwnProperty('data')) { - responseObject = /** @type {Object} */ ( - JSON.parse(messageObject['data'])); - } - - callback({'data': responseObject}); -}; - -/** - * Base URL for intents to Authenticator. - * @const - * @private - */ -/* -u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ = - 'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE'; -*/ -u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ = - 'intent:#Intent;action=com.ledger.android.u2f.bridge.AUTHENTICATE'; - - -/** - * Wrap the iOS client app with a MessagePort interface. - * @constructor - * @private - */ -u2f.WrappedIosPort_ = function() {}; - -/** - * Launch the iOS client app request - * @param {Object} message - */ -u2f.WrappedIosPort_.prototype.postMessage = function(message) { - var str = JSON.stringify(message); - var url = "u2f://auth?" + encodeURI(str); - location.replace(url); -}; - -/** - * Tells what type of port this is. - * @return {String} port type - */ -u2f.WrappedIosPort_.prototype.getPortType = function() { - return "WrappedIosPort_"; -}; - -/** - * Emulates the HTML 5 addEventListener interface. - * @param {string} eventName - * @param {function({data: Object})} handler - */ -u2f.WrappedIosPort_.prototype.addEventListener = function(eventName, handler) { - var name = eventName.toLowerCase(); - if (name !== 'message') { - console.error('WrappedIosPort only supports message'); - } -}; - -/** - * Sets up an embedded trampoline iframe, sourced from the extension. - * @param {function(MessagePort)} callback - * @private - */ -u2f.getIframePort_ = function(callback) { - // Create the iframe - var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID; - var iframe = document.createElement('iframe'); - iframe.src = iframeOrigin + '/u2f-comms.html'; - iframe.setAttribute('style', 'display:none'); - document.body.appendChild(iframe); - - var channel = new MessageChannel(); - var ready = function(message) { - if (message.data == 'ready') { - channel.port1.removeEventListener('message', ready); - callback(channel.port1); - } else { - console.error('First event on iframe port was not "ready"'); - } - }; - channel.port1.addEventListener('message', ready); - channel.port1.start(); - - iframe.addEventListener('load', function() { - // Deliver the port to the iframe and initialize - iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]); - }); -}; - - -//High-level JS API - -/** - * Default extension response timeout in seconds. - * @const - */ -u2f.EXTENSION_TIMEOUT_SEC = 30; - -/** - * A singleton instance for a MessagePort to the extension. - * @type {MessagePort|u2f.WrappedChromeRuntimePort_} - * @private - */ -u2f.port_ = null; - -/** - * Callbacks waiting for a port - * @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>} - * @private - */ -u2f.waitingForPort_ = []; - -/** - * A counter for requestIds. - * @type {number} - * @private - */ -u2f.reqCounter_ = 0; - -/** - * A map from requestIds to client callbacks - * @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse)) - * |function((u2f.Error|u2f.SignResponse)))>} - * @private - */ -u2f.callbackMap_ = {}; - -/** - * Creates or retrieves the MessagePort singleton to use. - * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback - * @private - */ -u2f.getPortSingleton_ = function(callback) { - if (u2f.port_) { - callback(u2f.port_); - } else { - if (u2f.waitingForPort_.length == 0) { - u2f.getMessagePort(function(port) { - u2f.port_ = port; - u2f.port_.addEventListener('message', - /** @type {function(Event)} */ (u2f.responseHandler_)); - - // Careful, here be async callbacks. Maybe. - while (u2f.waitingForPort_.length) - u2f.waitingForPort_.shift()(u2f.port_); - }); - } - u2f.waitingForPort_.push(callback); - } -}; - -/** - * Handles response messages from the extension. - * @param {MessageEvent.<u2f.Response>} message - * @private - */ -u2f.responseHandler_ = function(message) { - var response = message.data; - var reqId = response['requestId']; - if (!reqId || !u2f.callbackMap_[reqId]) { - console.error('Unknown or missing requestId in response.'); - return; - } - var cb = u2f.callbackMap_[reqId]; - delete u2f.callbackMap_[reqId]; - cb(response['responseData']); -}; - -/** - * Dispatches an array of sign requests to available U2F tokens. - * If the JS API version supported by the extension is unknown, it first sends a - * message to the extension to find out the supported API version and then it sends - * the sign request. - * @param {string=} appId - * @param {string=} challenge - * @param {Array<u2f.RegisteredKey>} registeredKeys - * @param {function((u2f.Error|u2f.SignResponse))} callback - * @param {number=} opt_timeoutSeconds - */ -u2f.sign = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) { - if (js_api_version === undefined) { - // Send a message to get the extension to JS API version, then send the actual sign request. - u2f.getApiVersion( - function (response) { - js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version']; - //console.log("Extension JS API Version: ", js_api_version); - u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds); - }); - } else { - // We know the JS API version. Send the actual sign request in the supported API version. - u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds); - } -}; - -/** - * Dispatches an array of sign requests to available U2F tokens. - * @param {string=} appId - * @param {string=} challenge - * @param {Array<u2f.RegisteredKey>} registeredKeys - * @param {function((u2f.Error|u2f.SignResponse))} callback - * @param {number=} opt_timeoutSeconds - */ -u2f.sendSignRequest = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) { - u2f.getPortSingleton_(function(port) { - var reqId = ++u2f.reqCounter_; - u2f.callbackMap_[reqId] = callback; - var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ? - opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC); - var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId); - port.postMessage(req); - }); -}; - -/** - * Dispatches register requests to available U2F tokens. An array of sign - * requests identifies already registered tokens. - * If the JS API version supported by the extension is unknown, it first sends a - * message to the extension to find out the supported API version and then it sends - * the register request. - * @param {string=} appId - * @param {Array<u2f.RegisterRequest>} registerRequests - * @param {Array<u2f.RegisteredKey>} registeredKeys - * @param {function((u2f.Error|u2f.RegisterResponse))} callback - * @param {number=} opt_timeoutSeconds - */ -u2f.register = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) { - if (js_api_version === undefined) { - // Send a message to get the extension to JS API version, then send the actual register request. - u2f.getApiVersion( - function (response) { - js_api_version = response['js_api_version'] === undefined ? 0: response['js_api_version']; - //console.log("Extension JS API Version: ", js_api_version); - u2f.sendRegisterRequest(appId, registerRequests, registeredKeys, - callback, opt_timeoutSeconds); - }); - } else { - // We know the JS API version. Send the actual register request in the supported API version. - u2f.sendRegisterRequest(appId, registerRequests, registeredKeys, - callback, opt_timeoutSeconds); - } -}; - -/** - * Dispatches register requests to available U2F tokens. An array of sign - * requests identifies already registered tokens. - * @param {string=} appId - * @param {Array<u2f.RegisterRequest>} registerRequests - * @param {Array<u2f.RegisteredKey>} registeredKeys - * @param {function((u2f.Error|u2f.RegisterResponse))} callback - * @param {number=} opt_timeoutSeconds - */ -u2f.sendRegisterRequest = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) { - u2f.getPortSingleton_(function(port) { - var reqId = ++u2f.reqCounter_; - u2f.callbackMap_[reqId] = callback; - var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ? - opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC); - var req = u2f.formatRegisterRequest_( - appId, registeredKeys, registerRequests, timeoutSeconds, reqId); - port.postMessage(req); - }); -}; - - -/** - * Dispatches a message to the extension to find out the supported - * JS API version. - * If the user is on a mobile phone and is thus using Google Authenticator instead - * of the Chrome extension, don't send the request and simply return 0. - * @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback - * @param {number=} opt_timeoutSeconds - */ -u2f.getApiVersion = function(callback, opt_timeoutSeconds) { - u2f.getPortSingleton_(function(port) { - // If we are using Android Google Authenticator or iOS client app, - // do not fire an intent to ask which JS API version to use. - if (port.getPortType) { - var apiVersion; - switch (port.getPortType()) { - case 'WrappedIosPort_': - case 'WrappedAuthenticatorPort_': - apiVersion = 1.1; - break; - - default: - apiVersion = 0; - break; - } - callback({ 'js_api_version': apiVersion }); - return; - } - var reqId = ++u2f.reqCounter_; - u2f.callbackMap_[reqId] = callback; - var req = { - type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST, - timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ? - opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC), - requestId: reqId - }; - port.postMessage(req); - }); -}; |