aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website')
-rw-r--r--packages/website/md/docs/sol-compiler/introduction.md21
-rw-r--r--packages/website/md/docs/web3_wrapper/introduction.md2
-rw-r--r--packages/website/package.json5
-rw-r--r--packages/website/public/images/lock_icon.svg3
-rw-r--r--packages/website/public/images/setup_account_icon.svg3
-rw-r--r--packages/website/public/images/team/alexbrowne.pngbin0 -> 146699 bytes
-rw-r--r--packages/website/public/images/token_icons/1ST.png (renamed from packages/website/public/images/token_icons/firstblood.jpg)bin7872 -> 7872 bytes
-rw-r--r--packages/website/public/images/token_icons/ABYSS.pngbin0 -> 13633 bytes
-rw-r--r--packages/website/public/images/token_icons/ADT.pngbin0 -> 10747 bytes
-rw-r--r--packages/website/public/images/token_icons/AE.pngbin0 -> 12322 bytes
-rw-r--r--packages/website/public/images/token_icons/AION.pngbin0 -> 2777 bytes
-rw-r--r--packages/website/public/images/token_icons/AIR.pngbin0 -> 20802 bytes
-rw-r--r--packages/website/public/images/token_icons/ANT.pngbin0 -> 42477 bytes
-rw-r--r--packages/website/public/images/token_icons/APCC.pngbin0 -> 19592 bytes
-rw-r--r--packages/website/public/images/token_icons/APPC.pngbin0 -> 19592 bytes
-rw-r--r--packages/website/public/images/token_icons/ARN.pngbin0 -> 16200 bytes
-rw-r--r--packages/website/public/images/token_icons/ART.pngbin0 -> 12430 bytes
-rw-r--r--packages/website/public/images/token_icons/AST.pngbin0 -> 14169 bytes
-rw-r--r--packages/website/public/images/token_icons/BAT.pngbin0 -> 6188 bytes
-rw-r--r--packages/website/public/images/token_icons/BCAP.pngbin0 -> 7787 bytes
-rw-r--r--packages/website/public/images/token_icons/BCPT.pngbin0 -> 10283 bytes
-rw-r--r--packages/website/public/images/token_icons/BNT.pngbin0 -> 4011 bytes
-rw-r--r--packages/website/public/images/token_icons/BRM.pngbin0 -> 18794 bytes
-rw-r--r--packages/website/public/images/token_icons/CAG.pngbin0 -> 11062 bytes
-rw-r--r--packages/website/public/images/token_icons/CAN.pngbin0 -> 10234 bytes
-rw-r--r--packages/website/public/images/token_icons/CAT.pngbin0 -> 23361 bytes
-rw-r--r--packages/website/public/images/token_icons/CFI.pngbin0 -> 11105 bytes
-rw-r--r--packages/website/public/images/token_icons/CVC.png (renamed from packages/website/public/images/token_icons/civic.png)bin10700 -> 10700 bytes
-rw-r--r--packages/website/public/images/token_icons/DAI.pngbin0 -> 6926 bytes
-rw-r--r--packages/website/public/images/token_icons/DATA.pngbin0 -> 13313 bytes
-rw-r--r--packages/website/public/images/token_icons/DEB.pngbin0 -> 13991 bytes
-rw-r--r--packages/website/public/images/token_icons/DGD.pngbin0 -> 23282 bytes
-rw-r--r--packages/website/public/images/token_icons/DIVX.pngbin0 -> 5110 bytes
-rw-r--r--packages/website/public/images/token_icons/DNT.pngbin0 -> 10054 bytes
-rw-r--r--packages/website/public/images/token_icons/EDG.png (renamed from packages/website/public/images/token_icons/edgeless.png)bin2712 -> 2712 bytes
-rw-r--r--packages/website/public/images/token_icons/EDU.pngbin0 -> 13535 bytes
-rw-r--r--packages/website/public/images/token_icons/ELEC.pngbin0 -> 11379 bytes
-rw-r--r--packages/website/public/images/token_icons/EMONT.pngbin0 -> 10523 bytes
-rw-r--r--packages/website/public/images/token_icons/ENG.pngbin0 -> 6767 bytes
-rw-r--r--packages/website/public/images/token_icons/ENTR.pngbin0 -> 3951 bytes
-rw-r--r--packages/website/public/images/token_icons/EVE.pngbin0 -> 5895 bytes
-rw-r--r--packages/website/public/images/token_icons/FUN.pngbin0 -> 14973 bytes
-rw-r--r--packages/website/public/images/token_icons/GEE.pngbin0 -> 10235 bytes
-rw-r--r--packages/website/public/images/token_icons/GEN.pngbin0 -> 5280 bytes
-rw-r--r--packages/website/public/images/token_icons/GET.pngbin0 -> 11930 bytes
-rw-r--r--packages/website/public/images/token_icons/GNO.pngbin0 -> 16559 bytes
-rw-r--r--packages/website/public/images/token_icons/GNT.png (renamed from packages/website/public/images/token_icons/golem.png)bin2990 -> 2990 bytes
-rw-r--r--packages/website/public/images/token_icons/HGT.pngbin0 -> 5709 bytes
-rw-r--r--packages/website/public/images/token_icons/HOT.pngbin0 -> 4578 bytes
-rw-r--r--packages/website/public/images/token_icons/ICN.pngbin0 -> 3962 bytes
-rw-r--r--packages/website/public/images/token_icons/IND.pngbin0 -> 4583 bytes
-rw-r--r--packages/website/public/images/token_icons/J8T.pngbin0 -> 10835 bytes
-rw-r--r--packages/website/public/images/token_icons/JET.pngbin0 -> 18374 bytes
-rw-r--r--packages/website/public/images/token_icons/KIN.pngbin0 -> 6075 bytes
-rw-r--r--packages/website/public/images/token_icons/KNC.pngbin0 -> 8396 bytes
-rw-r--r--packages/website/public/images/token_icons/LINK.pngbin0 -> 11267 bytes
-rw-r--r--packages/website/public/images/token_icons/LOOM.pngbin0 -> 9491 bytes
-rw-r--r--packages/website/public/images/token_icons/LUN.pngbin0 -> 13648 bytes
-rw-r--r--packages/website/public/images/token_icons/MANA.pngbin0 -> 17411 bytes
-rw-r--r--packages/website/public/images/token_icons/MCO.pngbin0 -> 6487 bytes
-rw-r--r--packages/website/public/images/token_icons/MKR.pngbin0 -> 6967 bytes
-rw-r--r--packages/website/public/images/token_icons/MLN.png (renamed from packages/website/public/images/token_icons/melon.png)bin3408 -> 3408 bytes
-rw-r--r--packages/website/public/images/token_icons/MOD.pngbin0 -> 7088 bytes
-rw-r--r--packages/website/public/images/token_icons/MORPH.pngbin0 -> 8919 bytes
-rw-r--r--packages/website/public/images/token_icons/MOT.pngbin0 -> 6069 bytes
-rw-r--r--packages/website/public/images/token_icons/MTL.pngbin0 -> 3540 bytes
-rw-r--r--packages/website/public/images/token_icons/NANJ.pngbin0 -> 11577 bytes
-rw-r--r--packages/website/public/images/token_icons/NAVI.pngbin0 -> 6827 bytes
-rw-r--r--packages/website/public/images/token_icons/NCT.pngbin0 -> 5462 bytes
-rw-r--r--packages/website/public/images/token_icons/NDC.pngbin0 -> 20972 bytes
-rw-r--r--packages/website/public/images/token_icons/NEXO.pngbin0 -> 4689 bytes
-rw-r--r--packages/website/public/images/token_icons/NMR.pngbin0 -> 21822 bytes
-rw-r--r--packages/website/public/images/token_icons/OAX.pngbin0 -> 6331 bytes
-rw-r--r--packages/website/public/images/token_icons/OCC.pngbin0 -> 7774 bytes
-rw-r--r--packages/website/public/images/token_icons/OMG.pngbin0 -> 5311 bytes
-rw-r--r--packages/website/public/images/token_icons/OMX.pngbin0 -> 7320 bytes
-rw-r--r--packages/website/public/images/token_icons/PAL.pngbin0 -> 13196 bytes
-rw-r--r--packages/website/public/images/token_icons/PAY.png (renamed from packages/website/public/images/token_icons/tenx.png)bin7276 -> 7276 bytes
-rw-r--r--packages/website/public/images/token_icons/PKT.pngbin0 -> 5900 bytes
-rw-r--r--packages/website/public/images/token_icons/PLAY.pngbin0 -> 3226 bytes
-rw-r--r--packages/website/public/images/token_icons/PLU.pngbin0 -> 51829 bytes
-rw-r--r--packages/website/public/images/token_icons/POLY.pngbin0 -> 9350 bytes
-rw-r--r--packages/website/public/images/token_icons/REN.pngbin0 -> 17682 bytes
-rw-r--r--packages/website/public/images/token_icons/REP.pngbin0 -> 13905 bytes
-rw-r--r--packages/website/public/images/token_icons/REQ.pngbin0 -> 4476 bytes
-rw-r--r--packages/website/public/images/token_icons/RFR.pngbin0 -> 8319 bytes
-rw-r--r--packages/website/public/images/token_icons/RLC.pngbin0 -> 9856 bytes
-rw-r--r--packages/website/public/images/token_icons/ROL.pngbin0 -> 16279 bytes
-rw-r--r--packages/website/public/images/token_icons/RVT.pngbin0 -> 9294 bytes
-rw-r--r--packages/website/public/images/token_icons/SALT.pngbin0 -> 5912 bytes
-rw-r--r--packages/website/public/images/token_icons/SAN.pngbin0 -> 7569 bytes
-rw-r--r--packages/website/public/images/token_icons/SIG.pngbin0 -> 9885 bytes
-rw-r--r--packages/website/public/images/token_icons/SNGLS.pngbin0 -> 8475 bytes
-rw-r--r--packages/website/public/images/token_icons/SNT.pngbin0 -> 6530 bytes
-rw-r--r--packages/website/public/images/token_icons/SPANK.pngbin0 -> 16743 bytes
-rw-r--r--packages/website/public/images/token_icons/SPN.pngbin0 -> 4760 bytes
-rw-r--r--packages/website/public/images/token_icons/SS.pngbin0 -> 2576 bytes
-rw-r--r--packages/website/public/images/token_icons/STORJ.pngbin0 -> 8117 bytes
-rw-r--r--packages/website/public/images/token_icons/SUB.pngbin0 -> 15424 bytes
-rw-r--r--packages/website/public/images/token_icons/SWT.pngbin0 -> 1215 bytes
-rw-r--r--packages/website/public/images/token_icons/SXDT.pngbin0 -> 4323 bytes
-rw-r--r--packages/website/public/images/token_icons/TIME.pngbin0 -> 33752 bytes
-rw-r--r--packages/website/public/images/token_icons/TKN.pngbin0 -> 3743 bytes
-rw-r--r--packages/website/public/images/token_icons/TRL.pngbin0 -> 447936 bytes
-rw-r--r--packages/website/public/images/token_icons/TRST.pngbin0 -> 26306 bytes
-rw-r--r--packages/website/public/images/token_icons/TRX.pngbin0 -> 7941 bytes
-rw-r--r--packages/website/public/images/token_icons/UPP.pngbin0 -> 7700 bytes
-rw-r--r--packages/website/public/images/token_icons/VSL.pngbin0 -> 17717 bytes
-rw-r--r--packages/website/public/images/token_icons/WAND.pngbin0 -> 9201 bytes
-rw-r--r--packages/website/public/images/token_icons/WETH.png (renamed from packages/website/public/images/token_icons/ether_erc20.png)bin7584 -> 7584 bytes
-rw-r--r--packages/website/public/images/token_icons/WTC.pngbin0 -> 8234 bytes
-rw-r--r--packages/website/public/images/token_icons/WYV.pngbin0 -> 9261 bytes
-rw-r--r--packages/website/public/images/token_icons/XAUR.pngbin0 -> 5150 bytes
-rw-r--r--packages/website/public/images/token_icons/XNK.pngbin0 -> 4117 bytes
-rw-r--r--packages/website/public/images/token_icons/XSC.pngbin0 -> 17956 bytes
-rw-r--r--packages/website/public/images/token_icons/XYO.pngbin0 -> 13793 bytes
-rw-r--r--packages/website/public/images/token_icons/ZIL.pngbin0 -> 4444 bytes
-rw-r--r--packages/website/public/images/token_icons/ZRX.png (renamed from packages/website/public/images/token_icons/zero_ex.png)bin17905 -> 17905 bytes
-rw-r--r--packages/website/public/images/token_icons/adtoken.pngbin5150 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/aragon.pngbin14012 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/augur.pngbin23161 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/bancor.pngbin2274 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/basicattentiontoken.pngbin7082 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/bitquence.pngbin14293 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/btc.pngbin5742 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/clams.pngbin18866 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/cofound-it.pngbin5403 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/default.pngbin20225 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/digixdao.pngbin34397 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/district0x.pngbin25007 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/eos.pngbin2168 -> 6979 bytes
-rw-r--r--packages/website/public/images/token_icons/etheroll.pngbin22736 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/funfair.pngbin18800 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/gnosis.pngbin7554 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/iconomi.pngbin810 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/iexec.pngbin1910 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/lunyr.pngbin5734 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/makerdao.pngbin3161 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/metal.pngbin1295 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/monaco.pngbin6984 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/numeraire.pngbin10272 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/omisego.pngbin5976 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/santiment.pngbin4698 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/singularity.pngbin3849 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/status.pngbin3445 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/storjcoinx.pngbin9453 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/taas.pngbin7823 -> 14580 bytes
-rw-r--r--packages/website/public/images/token_icons/tokencard.pngbin14586 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/trust.pngbin14428 -> 0 bytes
-rw-r--r--packages/website/public/images/token_icons/wings.pngbin16143 -> 3822 bytes
-rw-r--r--packages/website/public/images/toshi_logo.jpgbin0 -> 4611 bytes
-rw-r--r--packages/website/public/images/unlock-mm.pngbin0 -> 21137 bytes
-rw-r--r--packages/website/public/index.html13
-rw-r--r--packages/website/translations/english.json3
-rw-r--r--packages/website/ts/artifacts/Exchange.json610
-rw-r--r--packages/website/ts/blockchain.ts70
-rw-r--r--packages/website/ts/blockchain_watcher.ts7
-rw-r--r--packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx2
-rw-r--r--packages/website/ts/components/dialogs/ledger_config_dialog.tsx5
-rw-r--r--packages/website/ts/components/dialogs/send_dialog.tsx1
-rw-r--r--packages/website/ts/components/eth_wrappers.tsx7
-rw-r--r--packages/website/ts/components/generate_order/asset_picker.tsx40
-rw-r--r--packages/website/ts/components/inputs/balance_bounded_input.tsx35
-rw-r--r--packages/website/ts/components/inputs/eth_amount_input.tsx4
-rw-r--r--packages/website/ts/components/inputs/token_amount_input.tsx2
-rw-r--r--packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx14
-rw-r--r--packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx47
-rw-r--r--packages/website/ts/components/onboarding/onboarding_card.tsx112
-rw-r--r--packages/website/ts/components/onboarding/onboarding_flow.tsx70
-rw-r--r--packages/website/ts/components/onboarding/onboarding_tooltip.tsx13
-rw-r--r--packages/website/ts/components/onboarding/portal_onboarding_flow.tsx85
-rw-r--r--packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx12
-rw-r--r--packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx19
-rw-r--r--packages/website/ts/components/portal/portal.tsx78
-rw-r--r--packages/website/ts/components/relayer_index/relayer_grid_tile.tsx9
-rw-r--r--packages/website/ts/components/relayer_index/relayer_top_tokens.tsx63
-rw-r--r--packages/website/ts/components/top_bar/provider_display.tsx118
-rw-r--r--packages/website/ts/components/top_bar/provider_picker.tsx79
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx51
-rw-r--r--packages/website/ts/components/top_bar/top_bar_menu_item.tsx26
-rw-r--r--packages/website/ts/components/ui/balance.tsx27
-rw-r--r--packages/website/ts/components/ui/button.tsx21
-rw-r--r--packages/website/ts/components/ui/container.tsx15
-rw-r--r--packages/website/ts/components/ui/drop_down.tsx52
-rw-r--r--packages/website/ts/components/ui/image.tsx4
-rw-r--r--packages/website/ts/components/ui/simple_menu.tsx88
-rw-r--r--packages/website/ts/components/ui/text.tsx7
-rw-r--r--packages/website/ts/components/wallet/body_overlay.tsx36
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx127
-rw-r--r--packages/website/ts/components/wallet/wrap_ether_item.tsx5
-rw-r--r--packages/website/ts/containers/subproviders_documentation.ts3
-rw-r--r--packages/website/ts/pages/about/about.tsx29
-rw-r--r--packages/website/ts/pages/landing/landing.tsx12
-rw-r--r--packages/website/ts/redux/store.ts4
-rw-r--r--packages/website/ts/style/media.ts14
-rw-r--r--packages/website/ts/types.ts40
-rw-r--r--packages/website/ts/utils/analytics.ts11
-rw-r--r--packages/website/ts/utils/configs.ts43
-rw-r--r--packages/website/ts/utils/constants.ts7
-rw-r--r--packages/website/ts/utils/translate.ts13
-rw-r--r--packages/website/ts/utils/utils.ts100
201 files changed, 1578 insertions, 709 deletions
diff --git a/packages/website/md/docs/sol-compiler/introduction.md b/packages/website/md/docs/sol-compiler/introduction.md
index aa1939006..fcd80f47b 100644
--- a/packages/website/md/docs/sol-compiler/introduction.md
+++ b/packages/website/md/docs/sol-compiler/introduction.md
@@ -1,13 +1,8 @@
-Welcome to the [sol-compiler](https://github.com/0xProject/0x-monorepo/tree/development/packages/sol-compiler) documentation! Sol-compiler is a tool for compiling Solidity smart contracts and generating artifacts with ease.
-
-It serves a similar purpose as parts of the [Truffle framework](http://truffleframework.com/), but with the UNIX philosophy in mind: Make each program do one thing well. This tool is for intermediate to advanced Solidity developers that require greater configurability and reliability.
-
-Sol-compiler has the following advantages over Truffle:
-
-* Compile each smart contract with a specific version of Solidity.
-* Improved artifact files:
- * Storage of constructor args, source maps and paths to all requisite source files.
- * An easy to maintain codebase: TypeScript + Single repo.
- * Supports Solidity version ranges - contract compiled with latest Solidity version that satisfies the range.
-
-Sol-compiler can be used as a command-line tool or as an imported module.
+Welcome to the [sol-compiler](https://github.com/0xProject/0x-monorepo/tree/development/packages/sol-compiler) documentation! Sol-compiler is a wrapper around [solc-js](https://www.npmjs.com/package/solc) that adds:
+
+* Smart re-compilation: Only recompiles when smart contracts have changed
+* Ability to compile an entire project instead of only individual `.sol` files
+* Compilation using the Solidity version specified at the top of each individual `.sol` file
+* Proper parsing of Solidity version ranges
+* Support for the standard [input description](https://solidity.readthedocs.io/en/develop/using-the-compiler.html#input-description) for what information you'd like added to the resulting `artifacts` file (i.e 100% configurable artifacts content).
+* Storage of constructor args, source maps and paths to all dependency source files.
diff --git a/packages/website/md/docs/web3_wrapper/introduction.md b/packages/website/md/docs/web3_wrapper/introduction.md
index ea2f4cf0d..17bd316f1 100644
--- a/packages/website/md/docs/web3_wrapper/introduction.md
+++ b/packages/website/md/docs/web3_wrapper/introduction.md
@@ -1 +1 @@
-Welcome to the [Web3Wrapper](https://github.com/0xProject/0x-monorepo/tree/development/packages/web3-wrapper) documentation! Web3Wrapper is a convenience library that wraps Web3 v0.x, providing promise-based endpoints and a consistent API.
+Welcome to the [Web3Wrapper](https://github.com/0xProject/0x-monorepo/tree/development/packages/web3-wrapper) documentation! Web3-wrapper is a JSON-RPC client for Ethereum nodes. It is a type-safe alternative to [Web3.js](https://github.com/ethereum/web3.js/) written in TypeScript.
diff --git a/packages/website/package.json b/packages/website/package.json
index c7b689356..a5768a60b 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -38,6 +38,7 @@
"lodash": "^4.17.4",
"material-ui": "^0.17.1",
"moment": "2.21.0",
+ "numeral": "^2.0.6",
"polished": "^1.9.2",
"query-string": "^6.0.0",
"react": "15.6.1",
@@ -57,8 +58,7 @@
"styled-components": "^3.3.0",
"thenby": "^1.2.3",
"truffle-contract": "2.0.1",
- "web3": "^0.20.0",
- "web3-provider-engine": "^14.0.4",
+ "web3-provider-engine": "14.0.6",
"whatwg-fetch": "^2.0.3",
"xml-js": "^1.6.4"
},
@@ -71,6 +71,7 @@
"@types/lodash": "4.14.104",
"@types/material-ui": "0.18.0",
"@types/node": "^8.0.53",
+ "@types/numeral": "^0.0.22",
"@types/query-string": "^5.1.0",
"@types/react": "16.3.13",
"@types/react-copy-to-clipboard": "^4.2.0",
diff --git a/packages/website/public/images/lock_icon.svg b/packages/website/public/images/lock_icon.svg
new file mode 100644
index 000000000..83e8191a1
--- /dev/null
+++ b/packages/website/public/images/lock_icon.svg
@@ -0,0 +1,3 @@
+<svg width="26" height="32" viewBox="0 0 26 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6.47619 0C3.79509 0 1.60489 2.21216 1.60489 4.92014V6.33135C0.717479 6.33135 -3.60127e-08 7.05602 -3.60127e-08 7.95232V14.379C-3.60127e-08 15.2753 0.717479 16 1.60489 16H11.3475C12.2349 16 12.9524 15.2753 12.9524 14.379V7.95232C12.9524 7.05602 12.2349 6.33135 11.3475 6.33135V4.92014C11.3475 2.21216 9.1573 0 6.47619 0ZM9.6482 6.33135H3.30418V4.92014C3.30418 3.16567 4.72026 1.71633 6.47619 1.71633C8.23213 1.71633 9.6482 3.16567 9.6482 4.92014V6.33135Z" transform="scale(2)" fill="black"/>
+</svg>
diff --git a/packages/website/public/images/setup_account_icon.svg b/packages/website/public/images/setup_account_icon.svg
new file mode 100644
index 000000000..eaa5b2fd6
--- /dev/null
+++ b/packages/website/public/images/setup_account_icon.svg
@@ -0,0 +1,3 @@
+<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.5 9C16.5 13.1421 13.1421 16.5 9 16.5C4.85791 16.5 1.5 13.1421 1.5 9C1.5 4.85791 4.85791 1.5 9 1.5C13.1421 1.5 16.5 4.85791 16.5 9ZM18 9C18 13.9706 13.9707 18 9 18C4.0293 18 0 13.9706 0 9C0 4.02942 4.0293 0 9 0C13.9707 0 18 4.02942 18 9ZM9.21973 5.7196C9.5127 5.42664 9.9873 5.42664 10.2803 5.7196L13.0806 8.51953C13.373 8.8125 13.373 9.28735 13.0806 9.5802L10.2803 12.3802C9.9873 12.6731 9.5127 12.6731 9.21973 12.3802C8.92676 12.0873 8.92676 11.6124 9.21973 11.3196L10.7393 9.7998H4.75C4.33594 9.7998 4 9.46399 4 9.0498C4 8.63562 4.33594 8.2998 4.75 8.2998H10.7393L9.21973 6.78015C8.92676 6.4873 8.92676 6.01245 9.21973 5.7196Z" transform="scale(2)" fill="#3289F1"/>
+</svg>
diff --git a/packages/website/public/images/team/alexbrowne.png b/packages/website/public/images/team/alexbrowne.png
new file mode 100644
index 000000000..76a61913e
--- /dev/null
+++ b/packages/website/public/images/team/alexbrowne.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/firstblood.jpg b/packages/website/public/images/token_icons/1ST.png
index 9cd23b10e..9cd23b10e 100644
--- a/packages/website/public/images/token_icons/firstblood.jpg
+++ b/packages/website/public/images/token_icons/1ST.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ABYSS.png b/packages/website/public/images/token_icons/ABYSS.png
new file mode 100644
index 000000000..6ed2efef8
--- /dev/null
+++ b/packages/website/public/images/token_icons/ABYSS.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ADT.png b/packages/website/public/images/token_icons/ADT.png
new file mode 100644
index 000000000..2e7f3f54f
--- /dev/null
+++ b/packages/website/public/images/token_icons/ADT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/AE.png b/packages/website/public/images/token_icons/AE.png
new file mode 100644
index 000000000..01dc13dda
--- /dev/null
+++ b/packages/website/public/images/token_icons/AE.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/AION.png b/packages/website/public/images/token_icons/AION.png
new file mode 100644
index 000000000..a2bfb9253
--- /dev/null
+++ b/packages/website/public/images/token_icons/AION.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/AIR.png b/packages/website/public/images/token_icons/AIR.png
new file mode 100644
index 000000000..ab3a13b6d
--- /dev/null
+++ b/packages/website/public/images/token_icons/AIR.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ANT.png b/packages/website/public/images/token_icons/ANT.png
new file mode 100644
index 000000000..437a8f21a
--- /dev/null
+++ b/packages/website/public/images/token_icons/ANT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/APCC.png b/packages/website/public/images/token_icons/APCC.png
new file mode 100644
index 000000000..4294618be
--- /dev/null
+++ b/packages/website/public/images/token_icons/APCC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/APPC.png b/packages/website/public/images/token_icons/APPC.png
new file mode 100644
index 000000000..4294618be
--- /dev/null
+++ b/packages/website/public/images/token_icons/APPC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ARN.png b/packages/website/public/images/token_icons/ARN.png
new file mode 100644
index 000000000..0d17bb0dd
--- /dev/null
+++ b/packages/website/public/images/token_icons/ARN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ART.png b/packages/website/public/images/token_icons/ART.png
new file mode 100644
index 000000000..194f58fa0
--- /dev/null
+++ b/packages/website/public/images/token_icons/ART.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/AST.png b/packages/website/public/images/token_icons/AST.png
new file mode 100644
index 000000000..25d7c00ee
--- /dev/null
+++ b/packages/website/public/images/token_icons/AST.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/BAT.png b/packages/website/public/images/token_icons/BAT.png
new file mode 100644
index 000000000..840ed0a16
--- /dev/null
+++ b/packages/website/public/images/token_icons/BAT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/BCAP.png b/packages/website/public/images/token_icons/BCAP.png
new file mode 100644
index 000000000..acf50e368
--- /dev/null
+++ b/packages/website/public/images/token_icons/BCAP.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/BCPT.png b/packages/website/public/images/token_icons/BCPT.png
new file mode 100644
index 000000000..e1ecbeafe
--- /dev/null
+++ b/packages/website/public/images/token_icons/BCPT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/BNT.png b/packages/website/public/images/token_icons/BNT.png
new file mode 100644
index 000000000..a3b91ec34
--- /dev/null
+++ b/packages/website/public/images/token_icons/BNT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/BRM.png b/packages/website/public/images/token_icons/BRM.png
new file mode 100644
index 000000000..109c21ef5
--- /dev/null
+++ b/packages/website/public/images/token_icons/BRM.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/CAG.png b/packages/website/public/images/token_icons/CAG.png
new file mode 100644
index 000000000..2aa368381
--- /dev/null
+++ b/packages/website/public/images/token_icons/CAG.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/CAN.png b/packages/website/public/images/token_icons/CAN.png
new file mode 100644
index 000000000..7fdf3a9b9
--- /dev/null
+++ b/packages/website/public/images/token_icons/CAN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/CAT.png b/packages/website/public/images/token_icons/CAT.png
new file mode 100644
index 000000000..c59b6b15d
--- /dev/null
+++ b/packages/website/public/images/token_icons/CAT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/CFI.png b/packages/website/public/images/token_icons/CFI.png
new file mode 100644
index 000000000..b1f2e6db9
--- /dev/null
+++ b/packages/website/public/images/token_icons/CFI.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/civic.png b/packages/website/public/images/token_icons/CVC.png
index 1daf28d00..1daf28d00 100644
--- a/packages/website/public/images/token_icons/civic.png
+++ b/packages/website/public/images/token_icons/CVC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/DAI.png b/packages/website/public/images/token_icons/DAI.png
new file mode 100644
index 000000000..bf7da4a01
--- /dev/null
+++ b/packages/website/public/images/token_icons/DAI.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/DATA.png b/packages/website/public/images/token_icons/DATA.png
new file mode 100644
index 000000000..43f2e6dde
--- /dev/null
+++ b/packages/website/public/images/token_icons/DATA.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/DEB.png b/packages/website/public/images/token_icons/DEB.png
new file mode 100644
index 000000000..c729fd265
--- /dev/null
+++ b/packages/website/public/images/token_icons/DEB.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/DGD.png b/packages/website/public/images/token_icons/DGD.png
new file mode 100644
index 000000000..cb81ecb45
--- /dev/null
+++ b/packages/website/public/images/token_icons/DGD.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/DIVX.png b/packages/website/public/images/token_icons/DIVX.png
new file mode 100644
index 000000000..d8d50f1f8
--- /dev/null
+++ b/packages/website/public/images/token_icons/DIVX.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/DNT.png b/packages/website/public/images/token_icons/DNT.png
new file mode 100644
index 000000000..b4ac550f6
--- /dev/null
+++ b/packages/website/public/images/token_icons/DNT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/edgeless.png b/packages/website/public/images/token_icons/EDG.png
index 606784154..606784154 100644
--- a/packages/website/public/images/token_icons/edgeless.png
+++ b/packages/website/public/images/token_icons/EDG.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/EDU.png b/packages/website/public/images/token_icons/EDU.png
new file mode 100644
index 000000000..d74785e5a
--- /dev/null
+++ b/packages/website/public/images/token_icons/EDU.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ELEC.png b/packages/website/public/images/token_icons/ELEC.png
new file mode 100644
index 000000000..cc1a3745a
--- /dev/null
+++ b/packages/website/public/images/token_icons/ELEC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/EMONT.png b/packages/website/public/images/token_icons/EMONT.png
new file mode 100644
index 000000000..ba7fe4a3d
--- /dev/null
+++ b/packages/website/public/images/token_icons/EMONT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ENG.png b/packages/website/public/images/token_icons/ENG.png
new file mode 100644
index 000000000..6f83a35ea
--- /dev/null
+++ b/packages/website/public/images/token_icons/ENG.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ENTR.png b/packages/website/public/images/token_icons/ENTR.png
new file mode 100644
index 000000000..2936c20e2
--- /dev/null
+++ b/packages/website/public/images/token_icons/ENTR.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/EVE.png b/packages/website/public/images/token_icons/EVE.png
new file mode 100644
index 000000000..d78362134
--- /dev/null
+++ b/packages/website/public/images/token_icons/EVE.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/FUN.png b/packages/website/public/images/token_icons/FUN.png
new file mode 100644
index 000000000..a473a1c72
--- /dev/null
+++ b/packages/website/public/images/token_icons/FUN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/GEE.png b/packages/website/public/images/token_icons/GEE.png
new file mode 100644
index 000000000..887cc8429
--- /dev/null
+++ b/packages/website/public/images/token_icons/GEE.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/GEN.png b/packages/website/public/images/token_icons/GEN.png
new file mode 100644
index 000000000..b1fe28370
--- /dev/null
+++ b/packages/website/public/images/token_icons/GEN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/GET.png b/packages/website/public/images/token_icons/GET.png
new file mode 100644
index 000000000..6a5fbdf63
--- /dev/null
+++ b/packages/website/public/images/token_icons/GET.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/GNO.png b/packages/website/public/images/token_icons/GNO.png
new file mode 100644
index 000000000..7c7d09433
--- /dev/null
+++ b/packages/website/public/images/token_icons/GNO.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/golem.png b/packages/website/public/images/token_icons/GNT.png
index e61a4367d..e61a4367d 100644
--- a/packages/website/public/images/token_icons/golem.png
+++ b/packages/website/public/images/token_icons/GNT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/HGT.png b/packages/website/public/images/token_icons/HGT.png
new file mode 100644
index 000000000..b35c601a3
--- /dev/null
+++ b/packages/website/public/images/token_icons/HGT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/HOT.png b/packages/website/public/images/token_icons/HOT.png
new file mode 100644
index 000000000..0c7f61755
--- /dev/null
+++ b/packages/website/public/images/token_icons/HOT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ICN.png b/packages/website/public/images/token_icons/ICN.png
new file mode 100644
index 000000000..e7eebad10
--- /dev/null
+++ b/packages/website/public/images/token_icons/ICN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/IND.png b/packages/website/public/images/token_icons/IND.png
new file mode 100644
index 000000000..edc3d217b
--- /dev/null
+++ b/packages/website/public/images/token_icons/IND.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/J8T.png b/packages/website/public/images/token_icons/J8T.png
new file mode 100644
index 000000000..74a2f4855
--- /dev/null
+++ b/packages/website/public/images/token_icons/J8T.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/JET.png b/packages/website/public/images/token_icons/JET.png
new file mode 100644
index 000000000..f34a28481
--- /dev/null
+++ b/packages/website/public/images/token_icons/JET.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/KIN.png b/packages/website/public/images/token_icons/KIN.png
new file mode 100644
index 000000000..a38d656e1
--- /dev/null
+++ b/packages/website/public/images/token_icons/KIN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/KNC.png b/packages/website/public/images/token_icons/KNC.png
new file mode 100644
index 000000000..7ebe359b7
--- /dev/null
+++ b/packages/website/public/images/token_icons/KNC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/LINK.png b/packages/website/public/images/token_icons/LINK.png
new file mode 100644
index 000000000..0873f72c9
--- /dev/null
+++ b/packages/website/public/images/token_icons/LINK.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/LOOM.png b/packages/website/public/images/token_icons/LOOM.png
new file mode 100644
index 000000000..0da2c41c9
--- /dev/null
+++ b/packages/website/public/images/token_icons/LOOM.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/LUN.png b/packages/website/public/images/token_icons/LUN.png
new file mode 100644
index 000000000..d661bdc9f
--- /dev/null
+++ b/packages/website/public/images/token_icons/LUN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/MANA.png b/packages/website/public/images/token_icons/MANA.png
new file mode 100644
index 000000000..52cdffa69
--- /dev/null
+++ b/packages/website/public/images/token_icons/MANA.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/MCO.png b/packages/website/public/images/token_icons/MCO.png
new file mode 100644
index 000000000..7c3c5bfa0
--- /dev/null
+++ b/packages/website/public/images/token_icons/MCO.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/MKR.png b/packages/website/public/images/token_icons/MKR.png
new file mode 100644
index 000000000..6da588979
--- /dev/null
+++ b/packages/website/public/images/token_icons/MKR.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/melon.png b/packages/website/public/images/token_icons/MLN.png
index 29f58e631..29f58e631 100644
--- a/packages/website/public/images/token_icons/melon.png
+++ b/packages/website/public/images/token_icons/MLN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/MOD.png b/packages/website/public/images/token_icons/MOD.png
new file mode 100644
index 000000000..4fbe66b83
--- /dev/null
+++ b/packages/website/public/images/token_icons/MOD.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/MORPH.png b/packages/website/public/images/token_icons/MORPH.png
new file mode 100644
index 000000000..a9a8dd067
--- /dev/null
+++ b/packages/website/public/images/token_icons/MORPH.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/MOT.png b/packages/website/public/images/token_icons/MOT.png
new file mode 100644
index 000000000..b5457f9f1
--- /dev/null
+++ b/packages/website/public/images/token_icons/MOT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/MTL.png b/packages/website/public/images/token_icons/MTL.png
new file mode 100644
index 000000000..3297462ce
--- /dev/null
+++ b/packages/website/public/images/token_icons/MTL.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/NANJ.png b/packages/website/public/images/token_icons/NANJ.png
new file mode 100644
index 000000000..0c54c5bde
--- /dev/null
+++ b/packages/website/public/images/token_icons/NANJ.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/NAVI.png b/packages/website/public/images/token_icons/NAVI.png
new file mode 100644
index 000000000..3dc359c47
--- /dev/null
+++ b/packages/website/public/images/token_icons/NAVI.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/NCT.png b/packages/website/public/images/token_icons/NCT.png
new file mode 100644
index 000000000..879c8d085
--- /dev/null
+++ b/packages/website/public/images/token_icons/NCT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/NDC.png b/packages/website/public/images/token_icons/NDC.png
new file mode 100644
index 000000000..b16890ca3
--- /dev/null
+++ b/packages/website/public/images/token_icons/NDC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/NEXO.png b/packages/website/public/images/token_icons/NEXO.png
new file mode 100644
index 000000000..f6459a39f
--- /dev/null
+++ b/packages/website/public/images/token_icons/NEXO.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/NMR.png b/packages/website/public/images/token_icons/NMR.png
new file mode 100644
index 000000000..8767f019a
--- /dev/null
+++ b/packages/website/public/images/token_icons/NMR.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/OAX.png b/packages/website/public/images/token_icons/OAX.png
new file mode 100644
index 000000000..7a53e71af
--- /dev/null
+++ b/packages/website/public/images/token_icons/OAX.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/OCC.png b/packages/website/public/images/token_icons/OCC.png
new file mode 100644
index 000000000..049812208
--- /dev/null
+++ b/packages/website/public/images/token_icons/OCC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/OMG.png b/packages/website/public/images/token_icons/OMG.png
new file mode 100644
index 000000000..c1552abf2
--- /dev/null
+++ b/packages/website/public/images/token_icons/OMG.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/OMX.png b/packages/website/public/images/token_icons/OMX.png
new file mode 100644
index 000000000..0c3485d79
--- /dev/null
+++ b/packages/website/public/images/token_icons/OMX.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/PAL.png b/packages/website/public/images/token_icons/PAL.png
new file mode 100644
index 000000000..211e42ea5
--- /dev/null
+++ b/packages/website/public/images/token_icons/PAL.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/tenx.png b/packages/website/public/images/token_icons/PAY.png
index d9ffca043..d9ffca043 100644
--- a/packages/website/public/images/token_icons/tenx.png
+++ b/packages/website/public/images/token_icons/PAY.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/PKT.png b/packages/website/public/images/token_icons/PKT.png
new file mode 100644
index 000000000..169390929
--- /dev/null
+++ b/packages/website/public/images/token_icons/PKT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/PLAY.png b/packages/website/public/images/token_icons/PLAY.png
new file mode 100644
index 000000000..9b141a6ec
--- /dev/null
+++ b/packages/website/public/images/token_icons/PLAY.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/PLU.png b/packages/website/public/images/token_icons/PLU.png
new file mode 100644
index 000000000..6f9b0344e
--- /dev/null
+++ b/packages/website/public/images/token_icons/PLU.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/POLY.png b/packages/website/public/images/token_icons/POLY.png
new file mode 100644
index 000000000..03ded07dc
--- /dev/null
+++ b/packages/website/public/images/token_icons/POLY.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/REN.png b/packages/website/public/images/token_icons/REN.png
new file mode 100644
index 000000000..f70856e9f
--- /dev/null
+++ b/packages/website/public/images/token_icons/REN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/REP.png b/packages/website/public/images/token_icons/REP.png
new file mode 100644
index 000000000..c767f4b6f
--- /dev/null
+++ b/packages/website/public/images/token_icons/REP.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/REQ.png b/packages/website/public/images/token_icons/REQ.png
new file mode 100644
index 000000000..3c0e8ed9a
--- /dev/null
+++ b/packages/website/public/images/token_icons/REQ.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/RFR.png b/packages/website/public/images/token_icons/RFR.png
new file mode 100644
index 000000000..05d71c4f3
--- /dev/null
+++ b/packages/website/public/images/token_icons/RFR.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/RLC.png b/packages/website/public/images/token_icons/RLC.png
new file mode 100644
index 000000000..c21dee4c4
--- /dev/null
+++ b/packages/website/public/images/token_icons/RLC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ROL.png b/packages/website/public/images/token_icons/ROL.png
new file mode 100644
index 000000000..430fa9af1
--- /dev/null
+++ b/packages/website/public/images/token_icons/ROL.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/RVT.png b/packages/website/public/images/token_icons/RVT.png
new file mode 100644
index 000000000..4f32c0e87
--- /dev/null
+++ b/packages/website/public/images/token_icons/RVT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SALT.png b/packages/website/public/images/token_icons/SALT.png
new file mode 100644
index 000000000..ce425eed5
--- /dev/null
+++ b/packages/website/public/images/token_icons/SALT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SAN.png b/packages/website/public/images/token_icons/SAN.png
new file mode 100644
index 000000000..36aa6a554
--- /dev/null
+++ b/packages/website/public/images/token_icons/SAN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SIG.png b/packages/website/public/images/token_icons/SIG.png
new file mode 100644
index 000000000..33af7f085
--- /dev/null
+++ b/packages/website/public/images/token_icons/SIG.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SNGLS.png b/packages/website/public/images/token_icons/SNGLS.png
new file mode 100644
index 000000000..16bf28819
--- /dev/null
+++ b/packages/website/public/images/token_icons/SNGLS.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SNT.png b/packages/website/public/images/token_icons/SNT.png
new file mode 100644
index 000000000..6f072cffb
--- /dev/null
+++ b/packages/website/public/images/token_icons/SNT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SPANK.png b/packages/website/public/images/token_icons/SPANK.png
new file mode 100644
index 000000000..aab84ef90
--- /dev/null
+++ b/packages/website/public/images/token_icons/SPANK.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SPN.png b/packages/website/public/images/token_icons/SPN.png
new file mode 100644
index 000000000..c569c4687
--- /dev/null
+++ b/packages/website/public/images/token_icons/SPN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SS.png b/packages/website/public/images/token_icons/SS.png
new file mode 100644
index 000000000..127e42c45
--- /dev/null
+++ b/packages/website/public/images/token_icons/SS.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/STORJ.png b/packages/website/public/images/token_icons/STORJ.png
new file mode 100644
index 000000000..4539afb4a
--- /dev/null
+++ b/packages/website/public/images/token_icons/STORJ.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SUB.png b/packages/website/public/images/token_icons/SUB.png
new file mode 100644
index 000000000..633bcbbd1
--- /dev/null
+++ b/packages/website/public/images/token_icons/SUB.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SWT.png b/packages/website/public/images/token_icons/SWT.png
new file mode 100644
index 000000000..910d9fdbf
--- /dev/null
+++ b/packages/website/public/images/token_icons/SWT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/SXDT.png b/packages/website/public/images/token_icons/SXDT.png
new file mode 100644
index 000000000..b37e92050
--- /dev/null
+++ b/packages/website/public/images/token_icons/SXDT.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/TIME.png b/packages/website/public/images/token_icons/TIME.png
new file mode 100644
index 000000000..920cc7636
--- /dev/null
+++ b/packages/website/public/images/token_icons/TIME.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/TKN.png b/packages/website/public/images/token_icons/TKN.png
new file mode 100644
index 000000000..e1b276416
--- /dev/null
+++ b/packages/website/public/images/token_icons/TKN.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/TRL.png b/packages/website/public/images/token_icons/TRL.png
new file mode 100644
index 000000000..afd5815ba
--- /dev/null
+++ b/packages/website/public/images/token_icons/TRL.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/TRST.png b/packages/website/public/images/token_icons/TRST.png
new file mode 100644
index 000000000..0ba34778f
--- /dev/null
+++ b/packages/website/public/images/token_icons/TRST.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/TRX.png b/packages/website/public/images/token_icons/TRX.png
new file mode 100644
index 000000000..56338957c
--- /dev/null
+++ b/packages/website/public/images/token_icons/TRX.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/UPP.png b/packages/website/public/images/token_icons/UPP.png
new file mode 100644
index 000000000..bc90081a0
--- /dev/null
+++ b/packages/website/public/images/token_icons/UPP.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/VSL.png b/packages/website/public/images/token_icons/VSL.png
new file mode 100644
index 000000000..b3d0950d2
--- /dev/null
+++ b/packages/website/public/images/token_icons/VSL.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/WAND.png b/packages/website/public/images/token_icons/WAND.png
new file mode 100644
index 000000000..e22531e21
--- /dev/null
+++ b/packages/website/public/images/token_icons/WAND.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ether_erc20.png b/packages/website/public/images/token_icons/WETH.png
index bc8beae8b..bc8beae8b 100644
--- a/packages/website/public/images/token_icons/ether_erc20.png
+++ b/packages/website/public/images/token_icons/WETH.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/WTC.png b/packages/website/public/images/token_icons/WTC.png
new file mode 100644
index 000000000..06aac0617
--- /dev/null
+++ b/packages/website/public/images/token_icons/WTC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/WYV.png b/packages/website/public/images/token_icons/WYV.png
new file mode 100644
index 000000000..d63aa857b
--- /dev/null
+++ b/packages/website/public/images/token_icons/WYV.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/XAUR.png b/packages/website/public/images/token_icons/XAUR.png
new file mode 100644
index 000000000..c356cc9dd
--- /dev/null
+++ b/packages/website/public/images/token_icons/XAUR.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/XNK.png b/packages/website/public/images/token_icons/XNK.png
new file mode 100644
index 000000000..04b2ebf80
--- /dev/null
+++ b/packages/website/public/images/token_icons/XNK.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/XSC.png b/packages/website/public/images/token_icons/XSC.png
new file mode 100644
index 000000000..7f70686aa
--- /dev/null
+++ b/packages/website/public/images/token_icons/XSC.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/XYO.png b/packages/website/public/images/token_icons/XYO.png
new file mode 100644
index 000000000..81314d2ff
--- /dev/null
+++ b/packages/website/public/images/token_icons/XYO.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/ZIL.png b/packages/website/public/images/token_icons/ZIL.png
new file mode 100644
index 000000000..197227803
--- /dev/null
+++ b/packages/website/public/images/token_icons/ZIL.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/zero_ex.png b/packages/website/public/images/token_icons/ZRX.png
index 8ed9a984b..8ed9a984b 100644
--- a/packages/website/public/images/token_icons/zero_ex.png
+++ b/packages/website/public/images/token_icons/ZRX.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/adtoken.png b/packages/website/public/images/token_icons/adtoken.png
deleted file mode 100644
index 59290af6b..000000000
--- a/packages/website/public/images/token_icons/adtoken.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/aragon.png b/packages/website/public/images/token_icons/aragon.png
deleted file mode 100644
index d162aab24..000000000
--- a/packages/website/public/images/token_icons/aragon.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/augur.png b/packages/website/public/images/token_icons/augur.png
deleted file mode 100644
index b7d61100a..000000000
--- a/packages/website/public/images/token_icons/augur.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/bancor.png b/packages/website/public/images/token_icons/bancor.png
deleted file mode 100644
index d2b2fa472..000000000
--- a/packages/website/public/images/token_icons/bancor.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/basicattentiontoken.png b/packages/website/public/images/token_icons/basicattentiontoken.png
deleted file mode 100644
index 77e7dfb1f..000000000
--- a/packages/website/public/images/token_icons/basicattentiontoken.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/bitquence.png b/packages/website/public/images/token_icons/bitquence.png
deleted file mode 100644
index d8a2c6960..000000000
--- a/packages/website/public/images/token_icons/bitquence.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/btc.png b/packages/website/public/images/token_icons/btc.png
deleted file mode 100644
index 1d9fc8347..000000000
--- a/packages/website/public/images/token_icons/btc.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/clams.png b/packages/website/public/images/token_icons/clams.png
deleted file mode 100644
index 04c2ba7d3..000000000
--- a/packages/website/public/images/token_icons/clams.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/cofound-it.png b/packages/website/public/images/token_icons/cofound-it.png
deleted file mode 100644
index 7bccd6248..000000000
--- a/packages/website/public/images/token_icons/cofound-it.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/default.png b/packages/website/public/images/token_icons/default.png
deleted file mode 100644
index 5c9ea4b0f..000000000
--- a/packages/website/public/images/token_icons/default.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/digixdao.png b/packages/website/public/images/token_icons/digixdao.png
deleted file mode 100644
index f292db716..000000000
--- a/packages/website/public/images/token_icons/digixdao.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/district0x.png b/packages/website/public/images/token_icons/district0x.png
deleted file mode 100644
index 7427b1146..000000000
--- a/packages/website/public/images/token_icons/district0x.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/eos.png b/packages/website/public/images/token_icons/eos.png
index a08f3c042..622df61bc 100644
--- a/packages/website/public/images/token_icons/eos.png
+++ b/packages/website/public/images/token_icons/eos.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/etheroll.png b/packages/website/public/images/token_icons/etheroll.png
deleted file mode 100644
index 89dd5e04b..000000000
--- a/packages/website/public/images/token_icons/etheroll.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/funfair.png b/packages/website/public/images/token_icons/funfair.png
deleted file mode 100644
index 1b7c67ec6..000000000
--- a/packages/website/public/images/token_icons/funfair.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/gnosis.png b/packages/website/public/images/token_icons/gnosis.png
deleted file mode 100644
index 0111846d0..000000000
--- a/packages/website/public/images/token_icons/gnosis.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/iconomi.png b/packages/website/public/images/token_icons/iconomi.png
deleted file mode 100644
index 3499e4765..000000000
--- a/packages/website/public/images/token_icons/iconomi.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/iexec.png b/packages/website/public/images/token_icons/iexec.png
deleted file mode 100644
index ef4860457..000000000
--- a/packages/website/public/images/token_icons/iexec.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/lunyr.png b/packages/website/public/images/token_icons/lunyr.png
deleted file mode 100644
index f77094ba5..000000000
--- a/packages/website/public/images/token_icons/lunyr.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/makerdao.png b/packages/website/public/images/token_icons/makerdao.png
deleted file mode 100644
index adbc9f38c..000000000
--- a/packages/website/public/images/token_icons/makerdao.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/metal.png b/packages/website/public/images/token_icons/metal.png
deleted file mode 100644
index d8a8c33ec..000000000
--- a/packages/website/public/images/token_icons/metal.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/monaco.png b/packages/website/public/images/token_icons/monaco.png
deleted file mode 100644
index 865341fd3..000000000
--- a/packages/website/public/images/token_icons/monaco.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/numeraire.png b/packages/website/public/images/token_icons/numeraire.png
deleted file mode 100644
index 698f7cfdd..000000000
--- a/packages/website/public/images/token_icons/numeraire.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/omisego.png b/packages/website/public/images/token_icons/omisego.png
deleted file mode 100644
index 40a86b9d7..000000000
--- a/packages/website/public/images/token_icons/omisego.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/santiment.png b/packages/website/public/images/token_icons/santiment.png
deleted file mode 100644
index 05ce98c1d..000000000
--- a/packages/website/public/images/token_icons/santiment.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/singularity.png b/packages/website/public/images/token_icons/singularity.png
deleted file mode 100644
index 9db788935..000000000
--- a/packages/website/public/images/token_icons/singularity.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/status.png b/packages/website/public/images/token_icons/status.png
deleted file mode 100644
index a73ba23ba..000000000
--- a/packages/website/public/images/token_icons/status.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/storjcoinx.png b/packages/website/public/images/token_icons/storjcoinx.png
deleted file mode 100644
index 87c4d4292..000000000
--- a/packages/website/public/images/token_icons/storjcoinx.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/taas.png b/packages/website/public/images/token_icons/taas.png
index 4cca722f7..266e3690b 100644
--- a/packages/website/public/images/token_icons/taas.png
+++ b/packages/website/public/images/token_icons/taas.png
Binary files differ
diff --git a/packages/website/public/images/token_icons/tokencard.png b/packages/website/public/images/token_icons/tokencard.png
deleted file mode 100644
index 490c1be69..000000000
--- a/packages/website/public/images/token_icons/tokencard.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/trust.png b/packages/website/public/images/token_icons/trust.png
deleted file mode 100644
index 62b412b41..000000000
--- a/packages/website/public/images/token_icons/trust.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/token_icons/wings.png b/packages/website/public/images/token_icons/wings.png
index cd0eb4213..c0a9ce527 100644
--- a/packages/website/public/images/token_icons/wings.png
+++ b/packages/website/public/images/token_icons/wings.png
Binary files differ
diff --git a/packages/website/public/images/toshi_logo.jpg b/packages/website/public/images/toshi_logo.jpg
new file mode 100644
index 000000000..3cf451d24
--- /dev/null
+++ b/packages/website/public/images/toshi_logo.jpg
Binary files differ
diff --git a/packages/website/public/images/unlock-mm.png b/packages/website/public/images/unlock-mm.png
new file mode 100644
index 000000000..531c95dd2
--- /dev/null
+++ b/packages/website/public/images/unlock-mm.png
Binary files differ
diff --git a/packages/website/public/index.html b/packages/website/public/index.html
index 4c0985c71..060f2c3c2 100644
--- a/packages/website/public/index.html
+++ b/packages/website/public/index.html
@@ -70,7 +70,18 @@
})(document, 'script', 'twitter-wjs');
</script>
<!-- End Twitter SDK -->
-
+ <!-- Hotjar Tracking Code for https://0xproject.com/ -->
+ <script>
+ (function (h, o, t, j, a, r) {
+ h.hj = h.hj || function () { (h.hj.q = h.hj.q || []).push(arguments) };
+ h._hjSettings = { hjid: 935597, hjsv: 6 };
+ a = o.getElementsByTagName('head')[0];
+ r = o.createElement('script'); r.async = 1;
+ r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
+ a.appendChild(r);
+ })(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
+ </script>
+ <!-- End Hotjar Tracking Code -->
<!-- Main -->
<script type="text/javascript" crossorigin="anonymous" src="/bundle.js" charset="utf-8"></script>
</body>
diff --git a/packages/website/translations/english.json b/packages/website/translations/english.json
index 04fb0507a..d94dbb29e 100644
--- a/packages/website/translations/english.json
+++ b/packages/website/translations/english.json
@@ -76,5 +76,6 @@
"WEBSITE": "website",
"DEVELOPERS": "developers",
"HOME": "home",
- "ROCKETCHAT": "rocket.chat"
+ "ROCKETCHAT": "rocket.chat",
+ "TRADE_CALL_TO_ACTION": "trade on 0x"
}
diff --git a/packages/website/ts/artifacts/Exchange.json b/packages/website/ts/artifacts/Exchange.json
new file mode 100644
index 000000000..af8db7360
--- /dev/null
+++ b/packages/website/ts/artifacts/Exchange.json
@@ -0,0 +1,610 @@
+{
+ "contract_name": "Exchange",
+ "abi": [
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "numerator",
+ "type": "uint256"
+ },
+ {
+ "name": "denominator",
+ "type": "uint256"
+ },
+ {
+ "name": "target",
+ "type": "uint256"
+ }
+ ],
+ "name": "isRoundingError",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "name": "filled",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "name": "cancelled",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "orderAddresses",
+ "type": "address[5][]"
+ },
+ {
+ "name": "orderValues",
+ "type": "uint256[6][]"
+ },
+ {
+ "name": "fillTakerTokenAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "shouldThrowOnInsufficientBalanceOrAllowance",
+ "type": "bool"
+ },
+ {
+ "name": "v",
+ "type": "uint8[]"
+ },
+ {
+ "name": "r",
+ "type": "bytes32[]"
+ },
+ {
+ "name": "s",
+ "type": "bytes32[]"
+ }
+ ],
+ "name": "fillOrdersUpTo",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "orderAddresses",
+ "type": "address[5]"
+ },
+ {
+ "name": "orderValues",
+ "type": "uint256[6]"
+ },
+ {
+ "name": "cancelTakerTokenAmount",
+ "type": "uint256"
+ }
+ ],
+ "name": "cancelOrder",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "ZRX_TOKEN_CONTRACT",
+ "outputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "orderAddresses",
+ "type": "address[5][]"
+ },
+ {
+ "name": "orderValues",
+ "type": "uint256[6][]"
+ },
+ {
+ "name": "fillTakerTokenAmounts",
+ "type": "uint256[]"
+ },
+ {
+ "name": "v",
+ "type": "uint8[]"
+ },
+ {
+ "name": "r",
+ "type": "bytes32[]"
+ },
+ {
+ "name": "s",
+ "type": "bytes32[]"
+ }
+ ],
+ "name": "batchFillOrKillOrders",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "orderAddresses",
+ "type": "address[5]"
+ },
+ {
+ "name": "orderValues",
+ "type": "uint256[6]"
+ },
+ {
+ "name": "fillTakerTokenAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "v",
+ "type": "uint8"
+ },
+ {
+ "name": "r",
+ "type": "bytes32"
+ },
+ {
+ "name": "s",
+ "type": "bytes32"
+ }
+ ],
+ "name": "fillOrKillOrder",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "orderHash",
+ "type": "bytes32"
+ }
+ ],
+ "name": "getUnavailableTakerTokenAmount",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "signer",
+ "type": "address"
+ },
+ {
+ "name": "hash",
+ "type": "bytes32"
+ },
+ {
+ "name": "v",
+ "type": "uint8"
+ },
+ {
+ "name": "r",
+ "type": "bytes32"
+ },
+ {
+ "name": "s",
+ "type": "bytes32"
+ }
+ ],
+ "name": "isValidSignature",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "numerator",
+ "type": "uint256"
+ },
+ {
+ "name": "denominator",
+ "type": "uint256"
+ },
+ {
+ "name": "target",
+ "type": "uint256"
+ }
+ ],
+ "name": "getPartialAmount",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "TOKEN_TRANSFER_PROXY_CONTRACT",
+ "outputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "orderAddresses",
+ "type": "address[5][]"
+ },
+ {
+ "name": "orderValues",
+ "type": "uint256[6][]"
+ },
+ {
+ "name": "fillTakerTokenAmounts",
+ "type": "uint256[]"
+ },
+ {
+ "name": "shouldThrowOnInsufficientBalanceOrAllowance",
+ "type": "bool"
+ },
+ {
+ "name": "v",
+ "type": "uint8[]"
+ },
+ {
+ "name": "r",
+ "type": "bytes32[]"
+ },
+ {
+ "name": "s",
+ "type": "bytes32[]"
+ }
+ ],
+ "name": "batchFillOrders",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "orderAddresses",
+ "type": "address[5][]"
+ },
+ {
+ "name": "orderValues",
+ "type": "uint256[6][]"
+ },
+ {
+ "name": "cancelTakerTokenAmounts",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "batchCancelOrders",
+ "outputs": [],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "orderAddresses",
+ "type": "address[5]"
+ },
+ {
+ "name": "orderValues",
+ "type": "uint256[6]"
+ },
+ {
+ "name": "fillTakerTokenAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "shouldThrowOnInsufficientBalanceOrAllowance",
+ "type": "bool"
+ },
+ {
+ "name": "v",
+ "type": "uint8"
+ },
+ {
+ "name": "r",
+ "type": "bytes32"
+ },
+ {
+ "name": "s",
+ "type": "bytes32"
+ }
+ ],
+ "name": "fillOrder",
+ "outputs": [
+ {
+ "name": "filledTakerTokenAmount",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "orderAddresses",
+ "type": "address[5]"
+ },
+ {
+ "name": "orderValues",
+ "type": "uint256[6]"
+ }
+ ],
+ "name": "getOrderHash",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "EXTERNAL_QUERY_GAS_LIMIT",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint16"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "VERSION",
+ "outputs": [
+ {
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "payable": false,
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "name": "_zrxToken",
+ "type": "address"
+ },
+ {
+ "name": "_tokenTransferProxy",
+ "type": "address"
+ }
+ ],
+ "payable": false,
+ "type": "constructor"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "maker",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "taker",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "feeRecipient",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "makerToken",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "takerToken",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "filledMakerTokenAmount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "name": "filledTakerTokenAmount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "name": "paidMakerFee",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "name": "paidTakerFee",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "name": "tokens",
+ "type": "bytes32"
+ },
+ {
+ "indexed": false,
+ "name": "orderHash",
+ "type": "bytes32"
+ }
+ ],
+ "name": "LogFill",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "maker",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "feeRecipient",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "makerToken",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "takerToken",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "cancelledMakerTokenAmount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "name": "cancelledTakerTokenAmount",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "name": "tokens",
+ "type": "bytes32"
+ },
+ {
+ "indexed": false,
+ "name": "orderHash",
+ "type": "bytes32"
+ }
+ ],
+ "name": "LogCancel",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "errorId",
+ "type": "uint8"
+ },
+ {
+ "indexed": true,
+ "name": "orderHash",
+ "type": "bytes32"
+ }
+ ],
+ "name": "LogError",
+ "type": "event"
+ }
+ ],
+ "networks": {
+ "1": {
+ "address": "0x12459c951127e0c374ff9105dda097662a027093"
+ },
+ "3": {
+ "address": "0x479cc461fecd078f766ecc58533d6f69580cf3ac"
+ },
+ "4": {
+ "address": "0x1d16ef40fac01cec8adac2ac49427b9384192c05"
+ },
+ "42": {
+ "address": "0x90fe2af704b34e0224bf2299c838e04d4dcf1364"
+ },
+ "50": {
+ "address": "0x48bacb9266a570d521063ef5dd96e61686dbe788"
+ }
+ }
+}
diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts
index d18c34c32..fde134b18 100644
--- a/packages/website/ts/blockchain.ts
+++ b/packages/website/ts/blockchain.ts
@@ -12,10 +12,10 @@ import {
import { isValidOrderHash, signOrderHashAsync } from '@0xproject/order-utils';
import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
import {
- InjectedWeb3Subprovider,
ledgerEthereumBrowserClientFactoryAsync,
LedgerSubprovider,
RedundantSubprovider,
+ SignerSubprovider,
Subprovider,
} from '@0xproject/subproviders';
import {
@@ -46,6 +46,7 @@ import {
Fill,
InjectedProviderObservable,
InjectedProviderUpdate,
+ InjectedWeb3,
Order as PortalOrder,
Providers,
ProviderType,
@@ -59,13 +60,15 @@ 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';
-import Web3 = require('web3');
import ProviderEngine = require('web3-provider-engine');
import FilterSubprovider = require('web3-provider-engine/subproviders/filters');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
import * as MintableArtifacts from '../contracts/Mintable.json';
+// HACK: remove this hard-coded abi and use @0xproject/contract-wrappers
+import * as Exchange from './artifacts/Exchange.json';
+
const BLOCK_NUMBER_BACK_TRACK = 50;
const GWEI_IN_WEI = 1000000000;
@@ -73,6 +76,8 @@ 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.Toshi]: constants.PROVIDER_NAME_TOSHI,
+ [Providers.Cipher]: constants.PROVIDER_NAME_CIPHER,
};
export class Blockchain {
@@ -87,6 +92,7 @@ export class Blockchain {
private _userAddressIfExists: string;
private _ledgerSubprovider: LedgerSubprovider;
private _defaultGasPrice: BigNumber;
+ private _watchGasPriceIntervalId: NodeJS.Timer;
private static _getNameGivenProvider(provider: Provider): string {
const providerType = utils.getProviderType(provider);
const providerNameIfExists = providerToName[providerType];
@@ -95,8 +101,19 @@ export class Blockchain {
}
return providerNameIfExists;
}
- private static _getInjectedWeb3(): any {
- return (window as any).web3;
+ private static _getInjectedWeb3(): InjectedWeb3 {
+ const injectedWeb3IfExists = (window as any).web3;
+ // Our core assumptions about the injected web3 object is that it has the following
+ // properties and methods.
+ if (
+ _.isUndefined(injectedWeb3IfExists) ||
+ _.isUndefined(injectedWeb3IfExists.version) ||
+ _.isUndefined(injectedWeb3IfExists.version.getNetwork) ||
+ _.isUndefined(injectedWeb3IfExists.currentProvider)
+ ) {
+ return undefined;
+ }
+ return injectedWeb3IfExists;
}
private static async _getInjectedWeb3ProviderNetworkIdIfExistsAsync(): Promise<number | undefined> {
// Hack: We need to know the networkId the injectedWeb3 is connected to (if it is defined) in
@@ -117,7 +134,7 @@ export class Blockchain {
return networkIdIfExists;
}
private static async _getProviderAsync(
- injectedWeb3: Web3,
+ injectedWeb3: InjectedWeb3,
networkIdIfExists: number,
shouldUserLedgerProvider: boolean = false,
): Promise<[Provider, LedgerSubprovider | undefined]> {
@@ -151,7 +168,7 @@ export class Blockchain {
// 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 ProviderEngine();
- provider.addProvider(new InjectedWeb3Subprovider(injectedWeb3.currentProvider));
+ provider.addProvider(new SignerSubprovider(injectedWeb3.currentProvider));
provider.addProvider(new FilterSubprovider());
const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => {
return new RpcSubprovider({
@@ -183,13 +200,11 @@ export class Blockchain {
}
constructor(dispatcher: Dispatcher) {
this._dispatcher = dispatcher;
- const defaultGasPrice = GWEI_IN_WEI * 30;
+ 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._updateDefaultGasPriceAsync();
- // tslint:disable-next-line:no-floating-promises
this._onPageLoadInitFireAndForgetAsync();
}
public async networkIdUpdatedFireAndForgetAsync(newNetworkId: number): Promise<void> {
@@ -524,6 +539,7 @@ export class Blockchain {
this._blockchainWatcher.destroy();
this._injectedProviderObservable.unsubscribe(this._injectedProviderUpdateHandler);
this._stopWatchingExchangeLogFillEvents();
+ this._stopWatchingGasPrice();
}
public async fetchTokenInformationAsync(): Promise<void> {
utils.assert(
@@ -611,7 +627,9 @@ export class Blockchain {
);
const provider = this._contractWrappers.getProvider();
const web3Wrapper = new Web3Wrapper(provider);
- web3Wrapper.abiDecoder.addABI(this._contractWrappers.exchange.abi);
+ // HACK: remove this hard-coded abi and use @0xproject/contract-wrappers
+ const exchangeAbi = _.get(Exchange, 'abi', []);
+ web3Wrapper.abiDecoder.addABI(exchangeAbi);
const receipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
return receipt;
}
@@ -756,7 +774,7 @@ export class Blockchain {
_.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 = configs.ICON_URL_BY_SYMBOL[t.symbol];
+ const iconUrl = utils.getTokenIconUrl(t.symbol);
const token: Token = {
iconUrl,
address: t.address,
@@ -785,8 +803,30 @@ export class Blockchain {
this._updateProviderName(injectedWeb3IfExists);
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,
@@ -832,10 +872,10 @@ export class Blockchain {
this._dispatcher.updateNetworkId(networkId);
await this._rehydrateStoreWithContractEventsAsync();
}
- private _updateProviderName(injectedWeb3: Web3): void {
- const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
+ private _updateProviderName(injectedWeb3IfExists: InjectedWeb3): void {
+ const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3IfExists);
const providerName = doesInjectedWeb3Exist
- ? Blockchain._getNameGivenProvider(injectedWeb3.currentProvider)
+ ? Blockchain._getNameGivenProvider(injectedWeb3IfExists.currentProvider)
: constants.PROVIDER_NAME_PUBLIC;
this._dispatcher.updateInjectedProviderName(providerName);
}
@@ -882,7 +922,7 @@ export class Blockchain {
private async _updateDefaultGasPriceAsync(): Promise<void> {
try {
const gasInfo = await backendClient.getGasInfoAsync();
- const gasPriceInGwei = new BigNumber(gasInfo.average / 10);
+ const gasPriceInGwei = new BigNumber(gasInfo.fast / 10);
const gasPriceInWei = gasPriceInGwei.mul(1000000000);
this._defaultGasPrice = gasPriceInWei;
} catch (err) {
diff --git a/packages/website/ts/blockchain_watcher.ts b/packages/website/ts/blockchain_watcher.ts
index df5f73fd1..4b23aa98a 100644
--- a/packages/website/ts/blockchain_watcher.ts
+++ b/packages/website/ts/blockchain_watcher.ts
@@ -10,6 +10,7 @@ export class BlockchainWatcher {
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;
@@ -43,11 +44,9 @@ export class BlockchainWatcher {
);
}
private async _updateBalanceAsync(): Promise<void> {
- let prevNodeVersion: string;
- // Check for node version changes
const currentNodeVersion = await this._web3Wrapper.getNodeVersionAsync();
- if (currentNodeVersion !== prevNodeVersion) {
- prevNodeVersion = currentNodeVersion;
+ if (this._prevNodeVersionIfExists !== currentNodeVersion) {
+ this._prevNodeVersionIfExists = currentNodeVersion;
this._dispatcher.updateNodeVersion(currentNodeVersion);
}
diff --git a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx
index 9ac78e80e..7b09cc92c 100644
--- a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx
+++ b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx
@@ -103,7 +103,6 @@ export class EthWethConversionDialog extends React.Component<
shouldCheckAllowance={false}
onChange={this._onValueChange.bind(this)}
amount={this.state.value}
- onVisitBalancesPageClick={this.props.onCancelled}
/>
) : (
<EthAmountInput
@@ -112,7 +111,6 @@ export class EthWethConversionDialog extends React.Component<
onChange={this._onValueChange.bind(this)}
shouldCheckBalance={true}
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- onVisitBalancesPageClick={this.props.onCancelled}
/>
)}
<div className="pt1" style={{ fontSize: 12 }}>
diff --git a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx
index 38e4732a4..d2f373d67 100644
--- a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx
+++ b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx
@@ -29,7 +29,7 @@ interface LedgerConfigDialogProps {
toggleDialogFn: (isOpen: boolean) => void;
dispatcher: Dispatcher;
blockchain: Blockchain;
- networkId: number;
+ networkId?: number;
providerType: ProviderType;
}
@@ -44,6 +44,9 @@ interface LedgerConfigDialogState {
}
export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, LedgerConfigDialogState> {
+ public static defaultProps = {
+ networkId: 1,
+ };
constructor(props: LedgerConfigDialogProps) {
super(props);
const derivationPathIfExists = props.blockchain.getLedgerDerivationPathIfExists();
diff --git a/packages/website/ts/components/dialogs/send_dialog.tsx b/packages/website/ts/components/dialogs/send_dialog.tsx
index 421f18b4f..8a98fdf69 100644
--- a/packages/website/ts/components/dialogs/send_dialog.tsx
+++ b/packages/website/ts/components/dialogs/send_dialog.tsx
@@ -80,7 +80,6 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
shouldCheckAllowance={false}
onChange={this._onValueChange.bind(this)}
amount={this.state.value}
- onVisitBalancesPageClick={this.props.onCancelled}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
/>
</div>
diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx
index 20b446155..0b282b2a1 100644
--- a/packages/website/ts/components/eth_wrappers.tsx
+++ b/packages/website/ts/components/eth_wrappers.tsx
@@ -20,6 +20,7 @@ import {
} 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;
@@ -95,7 +96,11 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
this.props.networkId,
EtherscanLinkSuffixes.Address,
);
- const tokenLabel = this._renderToken('Wrapped Ether', etherToken.address, configs.ICON_URL_BY_SYMBOL.WETH);
+ 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;
diff --git a/packages/website/ts/components/generate_order/asset_picker.tsx b/packages/website/ts/components/generate_order/asset_picker.tsx
index 3d53a9e7d..5eada37b6 100644
--- a/packages/website/ts/components/generate_order/asset_picker.tsx
+++ b/packages/website/ts/components/generate_order/asset_picker.tsx
@@ -3,6 +3,8 @@ import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import * as moment from 'moment';
import * as React from 'react';
+import firstBy = require('thenby');
+
import { Blockchain } from 'ts/blockchain';
import { NewTokenForm } from 'ts/components/generate_order/new_token_form';
import { TrackTokenConfirmation } from 'ts/components/track_token_confirmation';
@@ -87,10 +89,10 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
return (
<Dialog
title={dialogConfigs.title}
- titleStyle={{ fontWeight: 100 }}
modal={dialogConfigs.isModal}
open={this.props.isOpen}
actions={dialogConfigs.actions}
+ autoScrollBodyContent={true}
onRequestClose={this._onCloseDialog.bind(this)}
>
{this.state.assetView === AssetViews.ASSET_PICKER && this._renderAssetPicker()}
@@ -121,9 +123,8 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
<div
className="flex flex-wrap"
style={{
- overflowY: 'auto',
- maxWidth: 720,
- maxHeight: 356,
+ maxWidth: 1000,
+ maxHeight: 600,
marginBottom: 10,
}}
>
@@ -134,15 +135,28 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
private _renderGridTiles(): React.ReactNode {
let isHovered;
let tileStyles;
- const gridTiles = _.map(this.props.tokenByAddress, (token: Token, address: string) => {
- if (
- (this.props.tokenVisibility === TokenVisibility.TRACKED && !utils.isTokenTracked(token)) ||
- (this.props.tokenVisibility === TokenVisibility.UNTRACKED && utils.isTokenTracked(token)) ||
- token.symbol === constants.ZRX_TOKEN_SYMBOL ||
- token.symbol === constants.ETHER_TOKEN_SYMBOL
- ) {
- return null; // Skip
- }
+ 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',
diff --git a/packages/website/ts/components/inputs/balance_bounded_input.tsx b/packages/website/ts/components/inputs/balance_bounded_input.tsx
index 968609030..f23beb436 100644
--- a/packages/website/ts/components/inputs/balance_bounded_input.tsx
+++ b/packages/website/ts/components/inputs/balance_bounded_input.tsx
@@ -3,9 +3,8 @@ import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import TextField from 'material-ui/TextField';
import * as React from 'react';
-import { Link } from 'react-router-dom';
import { RequiredLabel } from 'ts/components/ui/required_label';
-import { ValidatedBigNumberCallback, WebsitePaths } from 'ts/types';
+import { ValidatedBigNumberCallback } from 'ts/types';
import { utils } from 'ts/utils/utils';
interface BalanceBoundedInputProps {
@@ -18,8 +17,6 @@ interface BalanceBoundedInputProps {
shouldShowIncompleteErrs?: boolean;
shouldCheckBalance: boolean;
validate?: (amount: BigNumber) => React.ReactNode;
- onVisitBalancesPageClick?: () => void;
- shouldHideVisitBalancesLink?: boolean;
isDisabled?: boolean;
shouldShowErrs?: boolean;
shouldShowUnderline?: boolean;
@@ -35,7 +32,6 @@ interface BalanceBoundedInputState {
export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProps, BalanceBoundedInputState> {
public static defaultProps: Partial<BalanceBoundedInputProps> = {
shouldShowIncompleteErrs: false,
- shouldHideVisitBalancesLink: false,
isDisabled: false,
shouldShowErrs: true,
hintText: 'amount',
@@ -124,38 +120,11 @@ export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProp
return 'Cannot be zero';
}
if (this.props.shouldCheckBalance && amount.gt(balance)) {
- return <span>Insufficient balance. {this._renderIncreaseBalanceLink()}</span>;
+ return <span>Insufficient balance.</span>;
}
const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount);
return errMsg;
}
- private _renderIncreaseBalanceLink(): React.ReactNode {
- if (this.props.shouldHideVisitBalancesLink) {
- return null;
- }
-
- const increaseBalanceText = 'Increase balance';
- const linkStyle = {
- cursor: 'pointer',
- color: colors.darkestGrey,
- textDecoration: 'underline',
- display: 'inline',
- };
- if (_.isUndefined(this.props.onVisitBalancesPageClick)) {
- return (
- <Link to={`${WebsitePaths.Portal}/balances`} style={linkStyle}>
- {increaseBalanceText}
- </Link>
- );
- } else {
- return (
- <div onClick={this.props.onVisitBalancesPageClick} style={linkStyle}>
- {increaseBalanceText}
- </div>
- );
- }
- }
-
private _setAmountState(amount: string, balance: BigNumber, callback: () => void = _.noop): void {
const errorMsg = this._validate(amount, balance);
this.props.onErrorMsgChange(errorMsg);
diff --git a/packages/website/ts/components/inputs/eth_amount_input.tsx b/packages/website/ts/components/inputs/eth_amount_input.tsx
index 1f0f27410..552d4277a 100644
--- a/packages/website/ts/components/inputs/eth_amount_input.tsx
+++ b/packages/website/ts/components/inputs/eth_amount_input.tsx
@@ -14,9 +14,7 @@ interface EthAmountInputProps {
onChange: ValidatedBigNumberCallback;
onErrorMsgChange?: (errorMsg: React.ReactNode) => void;
shouldShowIncompleteErrs: boolean;
- onVisitBalancesPageClick?: () => void;
shouldCheckBalance: boolean;
- shouldHideVisitBalancesLink?: boolean;
shouldShowErrs?: boolean;
shouldShowUnderline?: boolean;
style?: React.CSSProperties;
@@ -46,8 +44,6 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou
onErrorMsgChange={this.props.onErrorMsgChange}
shouldCheckBalance={this.props.shouldCheckBalance}
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
- onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
- shouldHideVisitBalancesLink={this.props.shouldHideVisitBalancesLink}
hintText={this.props.hintText}
shouldShowErrs={this.props.shouldShowErrs}
shouldShowUnderline={this.props.shouldShowUnderline}
diff --git a/packages/website/ts/components/inputs/token_amount_input.tsx b/packages/website/ts/components/inputs/token_amount_input.tsx
index a67120320..93ef516cf 100644
--- a/packages/website/ts/components/inputs/token_amount_input.tsx
+++ b/packages/website/ts/components/inputs/token_amount_input.tsx
@@ -21,7 +21,6 @@ interface TokenAmountInputProps {
shouldCheckAllowance: boolean;
onChange: ValidatedBigNumberCallback;
onErrorMsgChange?: (errorMsg: React.ReactNode) => void;
- onVisitBalancesPageClick?: () => void;
lastForceTokenStateRefetch: number;
shouldShowErrs?: boolean;
shouldShowUnderline?: boolean;
@@ -88,7 +87,6 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
validate={this._validate.bind(this)}
shouldCheckBalance={this.props.shouldCheckBalance}
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
- onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
isDisabled={!this.state.isBalanceAndAllowanceLoaded}
hintText={this.props.hintText}
shouldShowErrs={this.props.shouldShowErrs}
diff --git a/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx b/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx
index bccdc0c18..ca71fcd50 100644
--- a/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx
+++ b/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx
@@ -1,10 +1,10 @@
import { BigNumber } from '@0xproject/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';
-import { utils } from 'ts/utils/utils';
export interface AddEthOnboardingStepProps {
userEthBalanceInWei: BigNumber;
@@ -15,13 +15,11 @@ export const AddEthOnboardingStep: React.StatelessComponent<AddEthOnboardingStep
<div className="flex items-center flex-column">
<Text>
Great! Looks like you already have{' '}
- <b>
- {utils.getFormattedAmount(
- props.userEthBalanceInWei,
- constants.DECIMAL_PLACES_ETH,
- constants.ETHER_SYMBOL,
- )}{' '}
- </b>
+ <Balance
+ amount={props.userEthBalanceInWei}
+ decimals={constants.DECIMAL_PLACES_ETH}
+ symbol={constants.ETHER_SYMBOL}
+ />{' '}
in your wallet.
</Text>
<Container marginTop="15px" marginBottom="15px">
diff --git a/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx
index a95c464af..d618c8318 100644
--- a/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx
+++ b/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx
@@ -1,19 +1,42 @@
import { colors } from '@0xproject/react-shared';
-import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
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> = () => (
- <div className="flex items-center flex-column">
- <Text>
- Before you begin, you need to connect to a wallet. This will be used across all 0x relayers and dApps.
- </Text>
- <Container marginTop="15px" marginBottom="15px">
- <ActionAccountBalanceWallet style={{ width: '50px', height: '50px' }} color={colors.orange} />
- </Container>
- <Text>Please refresh the page once you've done this to continue!</Text>
- </div>
-);
+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 the Toshi 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/toshi_logo.jpg' : '/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/onboarding_card.tsx b/packages/website/ts/components/onboarding/onboarding_card.tsx
index 48e8ab022..e1b0f304b 100644
--- a/packages/website/ts/components/onboarding/onboarding_card.tsx
+++ b/packages/website/ts/components/onboarding/onboarding_card.tsx
@@ -12,6 +12,7 @@ export type ContinueButtonDisplay = 'enabled' | 'disabled';
export interface OnboardingCardProps {
title?: string;
+ shouldCenterTitle?: boolean;
content: React.ReactNode;
isLastStep: boolean;
onClose: () => void;
@@ -23,10 +24,13 @@ export interface OnboardingCardProps {
shouldHideNextButton?: boolean;
continueButtonText?: string;
borderRadius?: string;
+ // Used for super-custom content.
+ shouldRemoveExtraSpacing?: boolean;
}
export const OnboardingCard: React.StatelessComponent<OnboardingCardProps> = ({
title,
+ shouldCenterTitle,
content,
continueButtonDisplay,
continueButtonText,
@@ -37,55 +41,75 @@ export const OnboardingCard: React.StatelessComponent<OnboardingCardProps> = ({
shouldHideBackButton,
shouldHideNextButton,
borderRadius,
-}) => (
- <Island borderRadius={borderRadius}>
- <Container paddingRight="30px" paddingLeft="30px" maxWidth={350} paddingTop="15px" paddingBottom="15px">
- <div className="flex flex-column">
- <div className="flex justify-between">
- <Title>{title}</Title>
- <Container position="relative" bottom="20px" left="15px">
- <IconButton color={colors.grey} iconName="zmdi-close" onClick={onClose}>
- Close
- </IconButton>
+ 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 marginBottom="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>
- )}
- <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>
-);
+ </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
index 1f4c6df82..91d5f2476 100644
--- a/packages/website/ts/components/onboarding/onboarding_flow.tsx
+++ b/packages/website/ts/components/onboarding/onboarding_flow.tsx
@@ -2,22 +2,44 @@ import * as React from 'react';
import { Placement, Popper, PopperChildrenProps } from 'react-popper';
import { OnboardingCard } from 'ts/components/onboarding/onboarding_card';
-import { ContinueButtonDisplay, OnboardingTooltip } from 'ts/components/onboarding/onboarding_tooltip';
+import {
+ ContinueButtonDisplay,
+ OnboardingTooltip,
+ TooltipPointerDisplay,
+} from 'ts/components/onboarding/onboarding_tooltip';
import { Animation } from 'ts/components/ui/animation';
import { Container } from 'ts/components/ui/container';
import { Overlay } from 'ts/components/ui/overlay';
import { zIndex } from 'ts/style/z_index';
-export interface Step {
+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;
- placement?: Placement;
shouldHideBackButton?: boolean;
shouldHideNextButton?: boolean;
continueButtonDisplay?: ContinueButtonDisplay;
continueButtonText?: string;
onContinueButtonClick?: () => void;
+ // Only used for very custom steps.
+ shouldRemoveExtraSpacing?: boolean;
}
export interface OnboardingFlowProps {
@@ -28,44 +50,55 @@ export interface OnboardingFlowProps {
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 = <Animation type="easeUpFromBottom">{this._renderOnboardignCard()}</Animation>;
- } else {
+ onboardingElement = <Animation type="easeUpFromBottom">{this._renderOnboardingCard()}</Animation>;
+ } else if (currentStep.position.type === 'target') {
+ const { placement, target } = currentStep.position;
onboardingElement = (
- <Popper
- referenceElement={this._getElementForStep()}
- placement={this._getCurrentStep().placement}
- positionFixed={true}
- >
+ <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.onClose} />
+ <Overlay onClick={this.props.disableCloseOnClickOutside ? undefined : this.props.onClose} />
{onboardingElement}
</div>
);
}
- private _getElementForStep(): Element {
- return document.querySelector(this._getCurrentStep().target);
- }
private _renderPopperChildren(props: PopperChildrenProps): React.ReactNode {
const customStyles = { zIndex: zIndex.aboveOverlay };
// On re-render, we want to re-center the popper.
@@ -76,7 +109,7 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
</div>
);
}
- private _renderToolTip(): React.ReactNode {
+ private _renderToolTip(tooltipPointerDisplay?: TooltipPointerDisplay): React.ReactNode {
const { steps, stepIndex } = this.props;
const step = steps[stepIndex];
const isLastStep = steps.length - 1 === stepIndex;
@@ -84,6 +117,7 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
<Container marginLeft="30px" width="400px">
<OnboardingTooltip
title={step.title}
+ shouldCenterTitle={step.shouldCenterTitle}
content={step.content}
isLastStep={isLastStep}
shouldHideBackButton={step.shouldHideBackButton}
@@ -94,12 +128,14 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
continueButtonDisplay={step.continueButtonDisplay}
continueButtonText={step.continueButtonText}
onContinueButtonClick={step.onContinueButtonClick}
+ pointerDisplay={tooltipPointerDisplay}
+ shouldRemoveExtraSpacing={step.shouldRemoveExtraSpacing}
/>
</Container>
);
}
- private _renderOnboardignCard(): React.ReactNode {
+ private _renderOnboardingCard(): React.ReactNode {
const { steps, stepIndex } = this.props;
const step = steps[stepIndex];
const isLastStep = steps.length - 1 === stepIndex;
@@ -107,6 +143,7 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
<Container position="relative" zIndex={1}>
<OnboardingCard
title={step.title}
+ shouldCenterTitle={step.shouldCenterTitle}
content={step.content}
isLastStep={isLastStep}
shouldHideBackButton={step.shouldHideBackButton}
@@ -118,6 +155,7 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
continueButtonText={step.continueButtonText}
onContinueButtonClick={step.onContinueButtonClick}
borderRadius="10px 10px 0px 0px"
+ shouldRemoveExtraSpacing={step.shouldRemoveExtraSpacing}
/>
</Container>
);
diff --git a/packages/website/ts/components/onboarding/onboarding_tooltip.tsx b/packages/website/ts/components/onboarding/onboarding_tooltip.tsx
index d8065625d..15d47908d 100644
--- a/packages/website/ts/components/onboarding/onboarding_tooltip.tsx
+++ b/packages/website/ts/components/onboarding/onboarding_tooltip.tsx
@@ -4,22 +4,27 @@ import { OnboardingCard, OnboardingCardProps } from 'ts/components/onboarding/on
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;
- pointerDirection?: PointerDirection;
+ pointerDisplay?: TooltipPointerDisplay;
}
export const OnboardingTooltip: React.StatelessComponent<OnboardingTooltipProps> = props => {
- const { pointerDirection, className, ...cardProps } = props;
+ const { pointerDisplay, className, ...cardProps } = props;
+ const card = <OnboardingCard {...cardProps} />;
+ if (pointerDisplay === 'none') {
+ return card;
+ }
return (
- <Pointer className={className} direction={pointerDirection}>
+ <Pointer className={className} direction={pointerDisplay}>
<OnboardingCard {...cardProps} />
</Pointer>
);
};
OnboardingTooltip.defaultProps = {
- pointerDirection: 'left',
+ pointerDisplay: '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
index 6bfa5c75f..20a8f0a32 100644
--- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
+++ b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
@@ -9,7 +9,12 @@ import { AddEthOnboardingStep } from 'ts/components/onboarding/add_eth_onboardin
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 { OnboardingFlow, Step } from 'ts/components/onboarding/onboarding_flow';
+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 {
@@ -18,7 +23,7 @@ import {
WrapEthOnboardingStep3,
} from 'ts/components/onboarding/wrap_eth_onboarding_step';
import { AllowanceToggle } from 'ts/containers/inputs/allowance_toggle';
-import { ProviderType, ScreenWidths, Token, TokenByAddress, TokenStateByAddress } from 'ts/types';
+import { BrowserType, ProviderType, ScreenWidths, Token, TokenByAddress, TokenStateByAddress } from 'ts/types';
import { analytics } from 'ts/utils/analytics';
import { utils } from 'ts/utils/utils';
@@ -45,8 +50,6 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
private _unlisten: () => void;
public componentDidMount(): void {
this._adjustStepIfShould();
- // Wait until the step is adjusted to decide whether we should show onboarding.
- setTimeout(this._autoStartOnboardingIfShould.bind(this), 1000);
// If there is a route change, just close onboarding.
this._unlisten = this.props.history.listen(() => this.props.updateIsRunning(false));
}
@@ -54,15 +57,18 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
this._unlisten();
}
public componentDidUpdate(prevProps: PortalOnboardingFlowProps): void {
- this._adjustStepIfShould();
- if (!prevProps.isRunning && this.props.isRunning) {
+ // 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.
- if (this.props.screenWidth === ScreenWidths.Sm) {
- document.querySelector('.wallet').scrollIntoView();
- }
+ 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()}
@@ -72,73 +78,75 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
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[] = [
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: '0x Ecosystem Setup',
content: <InstallWalletOnboardingStep />,
- placement: 'right',
shouldHideBackButton: true,
shouldHideNextButton: true,
},
{
- target: '.wallet',
- title: '0x Ecosystem Setup',
+ position: underMetamaskExtension,
+ title: 'Please Unlock Metamask...',
content: <UnlockWalletOnboardingStep />,
- placement: 'right',
shouldHideBackButton: true,
shouldHideNextButton: true,
+ shouldCenterTitle: true,
+ shouldRemoveExtraSpacing: true,
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: '0x Ecosystem Account Setup',
content: <IntroOnboardingStep />,
- placement: 'right',
shouldHideBackButton: true,
continueButtonDisplay: 'enabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 1: Add ETH',
content: (
<AddEthOnboardingStep userEthBalanceInWei={this.props.userEtherBalanceInWei || new BigNumber(0)} />
),
- placement: 'right',
continueButtonDisplay: this._userHasVisibleEth() ? 'enabled' : 'disabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 2: Wrap ETH',
content: <WrapEthOnboardingStep1 />,
- placement: 'right',
continueButtonDisplay: 'enabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 2: Wrap ETH',
content: <WrapEthOnboardingStep2 />,
- placement: 'right',
continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 2: Wrap ETH',
- content: (
- <WrapEthOnboardingStep3
- formattedWethBalanceIfExists={
- this._userHasVisibleWeth() ? this._getFormattedWethBalance() : undefined
- }
- />
- ),
- placement: 'right',
+ content: <WrapEthOnboardingStep3 wethAmount={this._getWethBalance()} />,
continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: 'Step 3: Unlock Tokens',
content: (
<SetAllowancesOnboardingStep
@@ -147,14 +155,12 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
doesUserHaveAllowancesForWethAndZrx={this._doesUserHaveAllowancesForWethAndZrx()}
/>
),
- placement: 'right',
continueButtonDisplay: this._doesUserHaveAllowancesForWethAndZrx() ? 'enabled' : 'disabled',
},
{
- target: '.wallet',
+ position: nextToWalletPosition,
title: '🎉 The Ecosystem Awaits',
content: <CongratsOnboardingStep />,
- placement: 'right',
continueButtonDisplay: 'enabled',
shouldHideNextButton: true,
continueButtonText: 'Enter the 0x Ecosystem',
@@ -177,11 +183,6 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
const ethTokenState = this.props.trackedTokenStateByAddress[ethToken.address];
return ethTokenState.balance;
}
- private _getFormattedWethBalance(): string {
- const ethToken = utils.getEthToken(this.props.tokenByAddress);
- const ethTokenState = this.props.trackedTokenStateByAddress[ethToken.address];
- return utils.getFormattedAmountFromToken(ethToken, ethTokenState);
- }
private _userHasVisibleWeth(): boolean {
return this._getWethBalance() > new BigNumber(0);
}
@@ -221,7 +222,7 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
}
private _autoStartOnboardingIfShould(): void {
if (
- (this.props.stepIndex === 0 && !this.props.isRunning) ||
+ (this.props.stepIndex === 0 && !this.props.isRunning && this.props.blockchainIsLoaded) ||
(!this.props.isRunning && !this.props.hasBeenClosed && this.props.blockchainIsLoaded)
) {
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
@@ -267,7 +268,7 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
);
}
private _handleFinalStepContinueClick(): void {
- if (utils.isMobile(this.props.screenWidth)) {
+ if (utils.isMobileWidth(this.props.screenWidth)) {
window.scrollTo(0, 0);
this.props.history.push('/portal');
}
diff --git a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx
index 0039aa545..358141520 100644
--- a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx
+++ b/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx
@@ -1,16 +1,8 @@
import * as React from 'react';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
+import { Image } from 'ts/components/ui/image';
export interface UnlockWalletOnboardingStepProps {}
export const UnlockWalletOnboardingStep: React.StatelessComponent<UnlockWalletOnboardingStepProps> = () => (
- <div className="flex items-center flex-column">
- <div className="flex items-center flex-column">
- <Container marginTop="15px" marginBottom="15px">
- <img src="/images/metamask_icon.png" height="50px" width="50px" />
- </Container>
- <Text center={true}>Unlock your metamask extension to get started.</Text>
- </div>
- </div>
+ <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
index 4d336c80f..e4332de75 100644
--- a/packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx
+++ b/packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx
@@ -1,8 +1,11 @@
import { colors } from '@0xproject/react-shared';
+import { BigNumber } from '@0xproject/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 {}
@@ -51,16 +54,20 @@ export const WrapEthOnboardingStep2: React.StatelessComponent<WrapEthOnboardingS
);
export interface WrapEthOnboardingStep3Props {
- formattedWethBalanceIfExists?: string;
+ wethAmount: BigNumber;
}
-export const WrapEthOnboardingStep3: React.StatelessComponent<WrapEthOnboardingStep3Props> = ({
- formattedWethBalanceIfExists,
-}) => (
+export const WrapEthOnboardingStep3: React.StatelessComponent<WrapEthOnboardingStep3Props> = ({ wethAmount }) => (
<div className="flex items-center flex-column">
<Text>
- You have <b>{formattedWethBalanceIfExists || '0 WETH'}</b> in your wallet.
- {formattedWethBalanceIfExists && ' Great!'}
+ 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">
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx
index 9c0cb866d..f983241fa 100644
--- a/packages/website/ts/components/portal/portal.tsx
+++ b/packages/website/ts/components/portal/portal.tsx
@@ -1,7 +1,6 @@
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
-import Help from 'material-ui/svg-icons/action/help';
import * as React from 'react';
import * as DocumentTitle from 'react-document-title';
import { Link, Route, RouteComponentProps, Switch } from 'react-router-dom';
@@ -24,6 +23,7 @@ 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 { Text } from 'ts/components/ui/text';
import { Wallet } from 'ts/components/wallet/wallet';
import { GenerateOrderForm } from 'ts/containers/generate_order_form';
@@ -91,7 +91,7 @@ interface PortalState {
interface AccountManagementItem {
pathName: string;
- headerText: string;
+ headerText?: string;
render: () => React.ReactNode;
}
@@ -106,7 +106,7 @@ 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 LARGE_LAYOUT_MARGIN = 30;
+const SIDE_PADDING = 20;
export class Portal extends React.Component<PortalProps, PortalState> {
private _blockchain: Blockchain;
@@ -225,7 +225,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
: TokenVisibility.TRACKED;
return (
<Container>
- <DocumentTitle title="0x Portal DApp" />
+ <DocumentTitle title="0x Portal" />
<TopBar
userAddress={this.props.userAddress}
networkId={this.props.networkId}
@@ -318,13 +318,17 @@ export class Portal extends React.Component<PortalProps, PortalState> {
);
}
private _renderWallet(): React.ReactNode {
- const isMobile = utils.isMobile(this.props.screenWidth);
+ const isMobile = utils.isMobileWidth(this.props.screenWidth);
// We need room to scroll down for mobile onboarding
- const marginBottom = isMobile ? '200px' : '15px';
+ const marginBottom = isMobile ? '250px' : '15px';
return (
<div>
<Container className="flex flex-column items-center">
- {isMobile && <Container marginBottom="20px">{this._renderStartOnboarding()}</Container>}
+ {isMobile && (
+ <Container marginTop="20px" marginBottom="20px">
+ {this._renderStartOnboarding()}
+ </Container>
+ )}
<Container marginBottom={marginBottom} width="100%">
<Wallet
style={
@@ -364,15 +368,15 @@ export class Portal extends React.Component<PortalProps, PortalState> {
);
}
private _renderStartOnboarding(): React.ReactNode {
- const isMobile = utils.isMobile(this.props.screenWidth);
+ 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">
- <Help style={{ width: '20px', height: '20px' }} color={colors.mediumBlue} />
- <Container marginLeft="8px">
- <Text fontColor={colors.mediumBlue} fontSize="16px" onClick={this._startOnboarding.bind(this)}>
- Learn how to set up your account
- </Text>
+ <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>
);
@@ -402,7 +406,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
},
{
pathName: `${WebsitePaths.Portal}/account`,
- headerText: 'Your Account',
+ headerText: this._isSmallScreen() ? undefined : 'Your Account',
render: this._isSmallScreen() ? this._renderWallet.bind(this) : this._renderTokenBalances.bind(this),
},
{
@@ -445,7 +449,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
private _renderAccountManagementItem(item: AccountManagementItem): React.ReactNode {
return (
<Section
- header={<TextHeader labelText={item.headerText} />}
+ header={!_.isUndefined(item.headerText) && <TextHeader labelText={item.headerText} />}
body={<Loading isLoading={!this.props.blockchainIsLoaded} content={item.render()} />}
/>
);
@@ -527,15 +531,21 @@ export class Portal extends React.Component<PortalProps, PortalState> {
);
}
private _renderRelayerIndexSection(): React.ReactNode {
- return <Section header={<TextHeader labelText="0x Relayers" />} body={this._renderRelayerIndex()} />;
- }
- private _renderRelayerIndex(): React.ReactNode {
- const isMobile = utils.isMobile(this.props.screenWidth);
+ const isMobile = utils.isMobileWidth(this.props.screenWidth);
return (
- <Container className="flex flex-column items-center">
- {isMobile && <Container marginBottom="20px">{this._renderStartOnboarding()}</Container>}
- <RelayerIndex networkId={this.props.networkId} screenWidth={this.props.screenWidth} />
- </Container>
+ <Section
+ header={!isMobile && <TextHeader labelText="0x Relayers" />}
+ body={
+ <Container className="flex flex-column items-center">
+ {isMobile && (
+ <Container marginTop="20px" marginBottom="20px">
+ {this._renderStartOnboarding()}
+ </Container>
+ )}
+ <RelayerIndex networkId={this.props.networkId} screenWidth={this.props.screenWidth} />
+ </Container>
+ }
+ />
);
}
private _renderNotFoundMessage(): React.ReactNode {
@@ -685,19 +695,19 @@ interface LargeLayoutProps {
}
const LargeLayout = (props: LargeLayoutProps) => {
return (
- <Container className="mx-auto flex flex-center" maxWidth={LARGE_LAYOUT_MAX_WIDTH}>
+ <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}
- marginLeft={LARGE_LAYOUT_MARGIN}
- >
+ <Container width={LEFT_COLUMN_WIDTH} position="fixed" zIndex={zIndex.aboveTopBar}>
{props.left}
</Container>
</div>
- <Container className="flex-auto" marginLeft={LEFT_COLUMN_WIDTH + LARGE_LAYOUT_MARGIN}>
- <Container className="flex-auto" marginLeft={LARGE_LAYOUT_MARGIN} marginRight={LARGE_LAYOUT_MARGIN}>
+ <Container className="flex-auto" marginLeft={LEFT_COLUMN_WIDTH}>
+ <Container className="flex-auto" marginLeft={SIDE_PADDING}>
{props.right}
</Container>
</Container>
@@ -711,7 +721,9 @@ interface SmallLayoutProps {
const SmallLayout = (props: SmallLayoutProps) => {
return (
<div className="flex flex-center">
- <div className="flex-auto px3">{props.content}</div>
+ <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/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
index b26bf512b..431cf145b 100644
--- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
@@ -9,6 +9,7 @@ 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';
@@ -55,7 +56,7 @@ const styles: Styles = {
};
const FALLBACK_IMG_SRC = '/images/relayer_fallback.png';
-const FALLBACK_PRIMARY_COLOR = colors.grey200;
+const FALLBACK_PRIMARY_COLOR = colors.grey300;
const NO_CONTENT_MESSAGE = '--';
const RELAYER_ICON_HEIGHT = '110px';
@@ -107,10 +108,14 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (
const GridTile = styled(PlainGridTile)`
cursor: pointer;
- transition: transform 0.2s ease;
&:hover {
+ transition: transform 0.2s ease;
transform: translate(0px, -3px);
}
+ ${media.small`
+ transform: none !important;
+ transition: none !important;
+ `};
`;
interface SectionProps {
diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
index f544fc924..c48b672e9 100644
--- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
@@ -2,44 +2,30 @@ import {
colors,
constants as sharedConstants,
EtherscanLinkSuffixes,
- Styles,
utils as sharedUtils,
} from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
-import { analytics } from 'ts/utils/analytics';
+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;
}
-const styles: Styles = {
- tokenLabel: {
- textDecoration: 'none',
- color: colors.mediumBlue,
- fontSize: 14,
- },
- followingTokenLabel: {
- paddingLeft: 16,
- },
-};
-
export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTokensProps) => {
return (
<div className="flex">
- {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo, index: number) => {
- const firstItemStyle = { ...styles.tokenLabel, ...styles.followingTokenLabel };
- const style = index !== 0 ? firstItemStyle : styles.tokenLabel;
+ {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo) => {
return (
- <TokenLink
- key={tokenInfo.address}
- tokenInfo={tokenInfo}
- style={style}
- networkId={props.networkId}
- />
+ <Container key={tokenInfo.address} marginRight="16px">
+ <TokenLink tokenInfo={tokenInfo} networkId={props.networkId} />
+ </Container>
);
})}
</div>
@@ -48,12 +34,9 @@ export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTo
interface TokenLinkProps {
tokenInfo: WebsiteBackendTokenInfo;
- style: React.CSSProperties;
networkId: number;
}
-interface TokenLinkState {
- isHovering: boolean;
-}
+interface TokenLinkState {}
class TokenLink extends React.Component<TokenLinkProps, TokenLinkState> {
constructor(props: TokenLinkProps) {
@@ -63,37 +46,21 @@ class TokenLink extends React.Component<TokenLinkProps, TokenLinkState> {
};
}
public render(): React.ReactNode {
- const style = {
- ...this.props.style,
- cursor: 'pointer',
- opacity: this.state.isHovering ? 0.5 : 1,
- };
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
const eventLabel = `${this.props.tokenInfo.symbol}-${networkName}`;
const onClick = (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
analytics.logEvent('Portal', 'Token Click', eventLabel);
+ const tokenLink = this._tokenLinkFromToken(this.props.tokenInfo, this.props.networkId);
+ utils.openUrl(tokenLink);
};
return (
- <a
- href={tokenLinkFromToken(this.props.tokenInfo, this.props.networkId)}
- target="_blank"
- style={style}
- onMouseEnter={this._onToggleHover.bind(this, true)}
- onMouseLeave={this._onToggleHover.bind(this, false)}
- onClick={onClick}
- >
+ <Text fontSize="14px" fontColor={colors.mediumBlue} onClick={onClick}>
{this.props.tokenInfo.symbol}
- </a>
+ </Text>
);
}
- private _onToggleHover(isHovering: boolean): void {
- this.setState({
- isHovering,
- });
+ private _tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number): string {
+ return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address);
}
}
-
-function tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number): string {
- return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address);
-}
diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx
index 8743e4320..806eaeea5 100644
--- a/packages/website/ts/components/top_bar/provider_display.tsx
+++ b/packages/website/ts/components/top_bar/provider_display.tsx
@@ -1,23 +1,26 @@
import { Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import CircularProgress from 'material-ui/CircularProgress';
-import RaisedButton from 'material-ui/RaisedButton';
import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
-import Lock from 'material-ui/svg-icons/action/lock';
import * as React from 'react';
import { Blockchain } from 'ts/blockchain';
-import { ProviderPicker } from 'ts/components/top_bar/provider_picker';
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 { constants } from 'ts/utils/constants';
import { utils } from 'ts/utils/utils';
const ROOT_HEIGHT = 24;
@@ -44,11 +47,7 @@ const styles: Styles = {
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
public render(): React.ReactNode {
- const isExternallyInjectedProvider = utils.isExternallyInjected(
- this.props.providerType,
- this.props.injectedProviderName,
- );
- const hoverActiveNode = (
+ const activeNode = (
<Island className="flex items-center py1 px2" style={styles.root}>
{this._renderIcon()}
<Container marginLeft="12px" marginRight="12px">
@@ -57,93 +56,34 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
{this._renderInjectedProvider()}
</Island>
);
- const hasLedgerProvider = this.props.providerType === ProviderType.Ledger;
- const horizontalPosition = isExternallyInjectedProvider || hasLedgerProvider ? 'left' : 'middle';
return (
<div style={{ width: 'fit-content', height: 48, float: 'right' }}>
<DropDown
- hoverActiveNode={hoverActiveNode}
- popoverContent={this.renderPopoverContent(isExternallyInjectedProvider, hasLedgerProvider)}
- anchorOrigin={{ horizontal: horizontalPosition, vertical: 'bottom' }}
- targetOrigin={{ horizontal: horizontalPosition, vertical: 'top' }}
+ activeNode={activeNode}
+ popoverContent={this._renderPopoverContent()}
+ anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }}
+ targetOrigin={{ horizontal: 'middle', vertical: 'top' }}
zDepth={1}
/>
</div>
);
}
- public renderPopoverContent(hasInjectedProvider: boolean, hasLedgerProvider: boolean): React.ReactNode {
- if (!this._isBlockchainReady()) {
- return null;
- } else if (hasInjectedProvider || hasLedgerProvider) {
- return (
- <ProviderPicker
- dispatcher={this.props.dispatcher}
- networkId={this.props.networkId}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- onToggleLedgerDialog={this.props.onToggleLedgerDialog}
- blockchain={this.props.blockchain}
- />
- );
- } else {
- // Nothing to connect to, show install/info popover
- return (
- <div className="px2" style={{ maxWidth: 420 }}>
- <div className="center h4 py2" style={{ color: colors.grey700 }}>
- Choose a wallet:
- </div>
- <div className="flex pb3">
- <div className="center px2">
- <div style={{ color: colors.darkGrey }}>Install a browser wallet</div>
- <div className="py2">
- <img src="/images/metamask_or_parity.png" width="135" />
- </div>
- <div>
- Use{' '}
- <a
- href={constants.URL_METAMASK_CHROME_STORE}
- target="_blank"
- style={{ color: colors.lightBlueA700 }}
- >
- Metamask
- </a>{' '}
- or{' '}
- <a
- href={constants.URL_PARITY_CHROME_STORE}
- target="_blank"
- style={{ color: colors.lightBlueA700 }}
- >
- Parity Signer
- </a>
- </div>
- </div>
- <div>
- <div
- className="pl1 ml1"
- style={{ borderLeft: `1px solid ${colors.grey300}`, height: 65 }}
- />
- <div className="py1">or</div>
- <div
- className="pl1 ml1"
- style={{ borderLeft: `1px solid ${colors.grey300}`, height: 68 }}
- />
- </div>
- <div className="px2 center">
- <div style={{ color: colors.darkGrey }}>Connect to a ledger hardware wallet</div>
- <div style={{ paddingTop: 21, paddingBottom: 29 }}>
- <img src="/images/ledger_icon.png" style={{ width: 80 }} />
- </div>
- <div>
- <RaisedButton
- style={{ width: '100%' }}
- label="Use Ledger"
- onClick={this.props.onToggleLedgerDialog}
- />
- </div>
- </div>
- </div>
- </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 {
@@ -154,7 +94,7 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
case AccountState.Loading:
return <CircularProgress size={ROOT_HEIGHT} thickness={2} />;
case AccountState.Locked:
- return <Lock color={colors.black} />;
+ return <Image src="/images/lock_icon.svg" height="20px" width="20px" />;
case AccountState.Disconnected:
return <ActionAccountBalanceWallet color={colors.mediumBlue} />;
default:
diff --git a/packages/website/ts/components/top_bar/provider_picker.tsx b/packages/website/ts/components/top_bar/provider_picker.tsx
deleted file mode 100644
index 7937f2e9d..000000000
--- a/packages/website/ts/components/top_bar/provider_picker.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import { colors, constants as sharedConstants } from '@0xproject/react-shared';
-import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { ProviderType } from 'ts/types';
-
-interface ProviderPickerProps {
- networkId: number;
- injectedProviderName: string;
- providerType: ProviderType;
- onToggleLedgerDialog: () => void;
- dispatcher: Dispatcher;
- blockchain: Blockchain;
-}
-
-interface ProviderPickerState {}
-
-export class ProviderPicker extends React.Component<ProviderPickerProps, ProviderPickerState> {
- public render(): React.ReactNode {
- const isLedgerSelected = this.props.providerType === ProviderType.Ledger;
- const menuStyle = {
- padding: 10,
- paddingTop: 15,
- paddingBottom: 15,
- };
- // Show dropdown with two options
- return (
- <div style={{ width: 225, overflow: 'hidden' }}>
- <RadioButtonGroup name="provider" defaultSelected={this.props.providerType}>
- <RadioButton
- onClick={this._onProviderRadioChanged.bind(this, ProviderType.Injected)}
- style={{ ...menuStyle, backgroundColor: !isLedgerSelected && colors.grey50 }}
- value={ProviderType.Injected}
- label={this._renderLabel(this.props.injectedProviderName, !isLedgerSelected)}
- />
- <RadioButton
- onClick={this._onProviderRadioChanged.bind(this, ProviderType.Ledger)}
- style={{ ...menuStyle, backgroundColor: isLedgerSelected && colors.grey50 }}
- value={ProviderType.Ledger}
- label={this._renderLabel('Ledger Nano S', isLedgerSelected)}
- />
- </RadioButtonGroup>
- </div>
- );
- }
- private _renderLabel(title: string, shouldShowNetwork: boolean): React.ReactNode {
- const label = (
- <div className="flex">
- <div style={{ fontSize: 14 }}>{title}</div>
- {shouldShowNetwork && this._renderNetwork()}
- </div>
- );
- return label;
- }
- private _renderNetwork(): React.ReactNode {
- const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
- return (
- <div className="flex" style={{ marginTop: 1 }}>
- <div className="relative" style={{ width: 14, paddingLeft: 14 }}>
- <img
- src={`/images/network_icons/${networkName.toLowerCase()}.png`}
- className="absolute"
- style={{ top: 6, width: 10 }}
- />
- </div>
- <div style={{ color: colors.lightGrey, fontSize: 11 }}>{networkName}</div>
- </div>
- );
- }
- private _onProviderRadioChanged(value: string): void {
- if (value === ProviderType.Ledger) {
- this.props.onToggleLedgerDialog();
- } else {
- // tslint:disable-next-line:no-floating-promises
- this.props.blockchain.updateProviderToInjectedAsync();
- }
- }
-}
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
index fac6c131f..960e5a824 100644
--- a/packages/website/ts/components/top_bar/top_bar.tsx
+++ b/packages/website/ts/components/top_bar/top_bar.tsx
@@ -11,6 +11,7 @@ import { LegacyPortalMenu } from 'ts/components/legacy_portal/legacy_portal_menu
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 { DropDown } from 'ts/components/ui/drop_down';
import { Dispatcher } from 'ts/redux/dispatcher';
import { Deco, Key, ProviderType, WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
@@ -45,6 +46,8 @@ export interface TopBarProps {
onVersionSelected?: (semver: string) => void;
sidebarHeader?: React.ReactNode;
maxWidth?: number;
+ paddingLeft?: number;
+ paddingRight?: number;
}
interface TopBarState {
@@ -67,13 +70,12 @@ const styles: Styles = {
color: colors.darkestGrey,
paddingTop: 6,
paddingBottom: 6,
- marginTop: 17,
cursor: 'pointer',
fontWeight: 400,
},
};
-const DEFAULT_HEIGHT = 59;
+const DEFAULT_HEIGHT = 68;
const EXPANDED_HEIGHT = 75;
export class TopBar extends React.Component<TopBarProps, TopBarState> {
@@ -81,6 +83,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
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;
@@ -102,7 +106,9 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
public render(): React.ReactNode {
const isNightVersion = this.props.isNightVersion;
const isExpandedDisplayType = this.props.displayType === TopBarDisplayType.Expanded;
- const parentClassNames = `flex mx-auto ${isExpandedDisplayType ? 'pl3 py1' : 'max-width-4'}`;
+ const parentClassNames = !isExpandedDisplayType
+ ? 'flex mx-auto items-center max-width-4'
+ : 'flex mx-auto items-center';
const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
const developerSectionMenuItems = [
<Link key="subMenuItem-zeroEx" to={WebsitePaths.ZeroExJs} className="text-decoration-none">
@@ -197,9 +203,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
fontSize: 25,
color: isNightVersion ? 'white' : 'black',
cursor: 'pointer',
- paddingTop: 16,
};
- const hoverActiveNode = (
+ const activeNode = (
<div className="flex relative" style={{ color: menuIconStyle.color }}>
<div style={{ paddingRight: 10 }}>{this.props.translate.get(Key.Developers, Deco.Cap)}</div>
<div className="absolute" style={{ paddingLeft: 3, right: 3, top: -2 }}>
@@ -211,20 +216,26 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
// TODO : Remove this once we ship portal v2
const shouldShowPortalV2Drawer = this._isViewingPortal() && utils.shouldShowPortalV2();
return (
- <div style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style, ...{ height } }} className="pb1">
- <div className={parentClassNames} style={{ maxWidth: this.props.maxWidth }}>
- <div className="col col-2 sm-pl1 md-pl2 lg-pl0" style={{ paddingTop: 15 }}>
- <Link to={`${WebsitePaths.Home}`} className="text-decoration-none">
- <img src={logoUrl} height="30" />
- </Link>
- </div>
- <div className={`col col-${isExpandedDisplayType ? '8' : '9'} lg-hide md-hide`} />
- <div className={`col col-${isExpandedDisplayType ? '6' : '5'} sm-hide xs-hide`} />
+ <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}`} className="text-decoration-none">
+ <img src={logoUrl} height="30" />
+ </Link>
+ <div className="flex-auto" />
{!this._isViewingPortal() && (
<div className={menuClasses}>
- <div className="flex justify-between">
+ <div className="flex items-center justify-between">
<DropDown
- hoverActiveNode={hoverActiveNode}
+ activeNode={activeNode}
popoverContent={popoverContent}
anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }}
targetOrigin={{ horizontal: 'middle', vertical: 'top' }}
@@ -252,7 +263,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
isExternal={false}
/>
<TopBarMenuItem
- title={this.props.translate.get(Key.PortalDApp, Deco.CapWords)}
+ title={this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
path={`${WebsitePaths.Portal}`}
isPrimary={true}
style={styles.menuItem}
@@ -264,7 +275,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
)}
{this._isViewingPortal() && (
- <div className="sm-hide xs-hide col col-5" style={{ paddingTop: 8, marginRight: 36 }}>
+ <div className="sm-hide xs-hide">
<ProviderDisplay
dispatcher={this.props.dispatcher}
userAddress={this.props.userAddress}
@@ -277,12 +288,12 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
/>
</div>
)}
- <div className={`col ${isExpandedDisplayType ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}>
+ <div className={'md-hide lg-hide'}>
<div style={menuIconStyle}>
<i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} />
</div>
</div>
- </div>
+ </Container>
{shouldShowPortalV2Drawer ? this._renderPortalV2Drawer() : this._renderDrawer()}
</div>
);
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
index 2e4254cfa..25fab2868 100644
--- a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
+++ b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
@@ -3,6 +3,8 @@ import * as _ from 'lodash';
import * as React from 'react';
import { Link } from 'react-router-dom';
+import { CallToAction } from 'ts/components/ui/button';
+
const DEFAULT_STYLE = {
color: colors.darkestGrey,
};
@@ -27,23 +29,15 @@ export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarM
isNightVersion: false,
};
public render(): React.ReactNode {
- const primaryStyles = this.props.isPrimary
- ? {
- borderRadius: 4,
- border: `1px solid ${this.props.isNightVersion ? colors.grey : colors.greyishPink}`,
- marginTop: 15,
- paddingLeft: 9,
- paddingRight: 9,
- minWidth: 77,
- }
- : {};
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, ...primaryStyles, color: menuItemColor }}
- >
+ <div className={`center ${this.props.className}`} style={{ ...this.props.style, color: menuItemColor }}>
{this.props.isExternal ? (
<a
className="text-decoration-none"
@@ -51,11 +45,11 @@ export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarM
target="_blank"
href={this.props.path}
>
- {this.props.title}
+ {itemContent}
</a>
) : (
<Link to={this.props.path} className="text-decoration-none" style={{ color: linkColor }}>
- {this.props.title}
+ {itemContent}
</Link>
)}
</div>
diff --git a/packages/website/ts/components/ui/balance.tsx b/packages/website/ts/components/ui/balance.tsx
new file mode 100644
index 000000000..9e5a256b6
--- /dev/null
+++ b/packages/website/ts/components/ui/balance.tsx
@@ -0,0 +1,27 @@
+import { BigNumber } from '@0xproject/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
index 1489a74a6..2952c8859 100644
--- a/packages/website/ts/components/ui/button.tsx
+++ b/packages/website/ts/components/ui/button.tsx
@@ -11,6 +11,7 @@ export interface ButtonProps {
backgroundColor?: string;
borderColor?: string;
width?: string;
+ padding?: string;
type?: string;
isDisabled?: boolean;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
@@ -27,9 +28,8 @@ export const Button = styled(PlainButton)`
font-size: ${props => props.fontSize};
color: ${props => props.fontColor};
transition: background-color, opacity 0.5s ease;
- padding: 0.8em 2.2em;
+ padding: ${props => props.padding};
border-radius: 6px;
- box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25);
font-weight: 500;
outline: none;
font-family: ${props => props.fontFamily};
@@ -44,7 +44,6 @@ export const Button = styled(PlainButton)`
}
&:disabled {
opacity: 0.5;
- box-shadow: none;
}
&:focus {
background-color: ${props => saturate(0.2, props.backgroundColor)};
@@ -57,6 +56,7 @@ Button.defaultProps = {
width: 'auto',
fontFamily: 'Roboto',
isDisabled: false,
+ padding: '0.8em 2.2em',
};
Button.displayName = 'Button';
@@ -67,20 +67,26 @@ export interface CallToActionProps {
type?: CallToActionType;
fontSize?: string;
width?: string;
+ padding?: string;
}
-export const CallToAction: React.StatelessComponent<CallToActionProps> = ({ children, type, fontSize, width }) => {
+export const CallToAction: React.StatelessComponent<CallToActionProps> = ({
+ children,
+ type,
+ fontSize,
+ padding,
+ width,
+}) => {
const isLight = type === 'light';
- const backgroundColor = isLight ? colors.white : colors.heroGrey;
+ const backgroundColor = isLight ? colors.white : colors.mediumBlue;
const fontColor = isLight ? colors.heroGrey : colors.white;
- const borderColor = isLight ? undefined : colors.white;
return (
<Button
fontSize={fontSize}
+ padding={padding}
backgroundColor={backgroundColor}
fontColor={fontColor}
width={width}
- borderColor={borderColor}
>
{children}
</Button>
@@ -89,4 +95,5 @@ export const CallToAction: React.StatelessComponent<CallToActionProps> = ({ chil
CallToAction.defaultProps = {
type: 'dark',
+ fontSize: '14px',
};
diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx
index fb718d731..427cc6cc7 100644
--- a/packages/website/ts/components/ui/container.tsx
+++ b/packages/website/ts/components/ui/container.tsx
@@ -2,6 +2,8 @@ import * as React from 'react';
type StringOrNum = string | number;
+export type ContainerTag = 'div' | 'span';
+
export interface ContainerProps {
marginTop?: StringOrNum;
marginBottom?: StringOrNum;
@@ -17,6 +19,7 @@ export interface ContainerProps {
maxHeight?: StringOrNum;
width?: StringOrNum;
height?: StringOrNum;
+ minWidth?: StringOrNum;
minHeight?: StringOrNum;
isHidden?: boolean;
className?: string;
@@ -27,15 +30,21 @@ export interface ContainerProps {
right?: string;
bottom?: string;
zIndex?: number;
+ Tag?: ContainerTag;
}
-export const Container: React.StatelessComponent<ContainerProps> = ({ children, className, isHidden, ...style }) => {
+export const Container: React.StatelessComponent<ContainerProps> = props => {
+ const { children, className, Tag, isHidden, ...style } = props;
const visibility = isHidden ? 'hidden' : undefined;
return (
- <div style={{ ...style, visibility }} className={className}>
+ <Tag style={{ ...style, visibility }} className={className}>
{children}
- </div>
+ </Tag>
);
};
+Container.defaultProps = {
+ Tag: 'div',
+};
+
Container.displayName = 'Container';
diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx
index 22cb942f8..4d5caef08 100644
--- a/packages/website/ts/components/ui/drop_down.tsx
+++ b/packages/website/ts/components/ui/drop_down.tsx
@@ -1,4 +1,4 @@
-import Popover, { PopoverAnimationVertical } from 'material-ui/Popover';
+import Popover from 'material-ui/Popover';
import * as React from 'react';
import { MaterialUIPosition } from 'ts/types';
@@ -7,13 +7,20 @@ const DEFAULT_STYLE = {
fontSize: 14,
};
-interface DropDownProps {
- hoverActiveNode: React.ReactNode;
+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;
}
interface DropDownState {
@@ -25,6 +32,8 @@ export class DropDown extends React.Component<DropDownProps, DropDownState> {
public static defaultProps: Partial<DropDownProps> = {
style: DEFAULT_STYLE,
zDepth: 1,
+ activateEvent: DropdownMouseEvent.Hover,
+ closeEvent: DropdownMouseEvent.Hover,
};
private _isHovering: boolean;
private _popoverCloseCheckIntervalId: number;
@@ -58,46 +67,61 @@ export class DropDown extends React.Component<DropDownProps, DropDownState> {
onMouseEnter={this._onHover.bind(this)}
onMouseLeave={this._onHoverOff.bind(this)}
>
- {this.props.hoverActiveNode}
+ <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._closePopover.bind(this)}
- useLayerForClickAway={false}
- animation={PopoverAnimationVertical}
+ useLayerForClickAway={this.props.closeEvent === DropdownMouseEvent.Click}
+ animated={false}
zDepth={this.props.zDepth}
>
- <div onMouseEnter={this._onHover.bind(this)} onMouseLeave={this._onHoverOff.bind(this)}>
+ <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: true,
+ anchorEl: event.currentTarget,
+ });
+ }
+ }
private _onHover(event: React.FormEvent<HTMLInputElement>): void {
this._isHovering = true;
- this._checkIfShouldOpenPopover(event);
+ 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 _onHoverOff(): void {
- this._isHovering = false;
- }
private _checkIfShouldClosePopover(): void {
- if (!this.state.isDropDownOpen || this._isHovering) {
+ if (!this.state.isDropDownOpen) {
return; // noop
}
- this._closePopover();
+ if (this.props.closeEvent === DropdownMouseEvent.Hover && !this._isHovering) {
+ this._closePopover();
+ }
}
private _closePopover(): void {
this.setState({
diff --git a/packages/website/ts/components/ui/image.tsx b/packages/website/ts/components/ui/image.tsx
index 369dc8b7e..c4ff93531 100644
--- a/packages/website/ts/components/ui/image.tsx
+++ b/packages/website/ts/components/ui/image.tsx
@@ -6,6 +6,7 @@ export interface ImageProps {
src?: string;
fallbackSrc?: string;
height?: string | number;
+ borderRadius?: string;
width?: string | number;
}
interface ImageState {
@@ -26,6 +27,9 @@ export class Image extends React.Component<ImageProps, ImageState> {
className={this.props.className}
onError={this._onError.bind(this)}
src={src}
+ style={{
+ borderRadius: this.props.borderRadius,
+ }}
height={this.props.height}
width={this.props.width}
/>
diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx
new file mode 100644
index 000000000..74b8ef6ae
--- /dev/null
+++ b/packages/website/ts/components/ui/simple_menu.tsx
@@ -0,0 +1,88 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+import * as CopyToClipboard from 'react-copy-to-clipboard';
+import { Link } from 'react-router-dom';
+
+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}
+ 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`} style={{ textDecoration: 'none' }}>
+ <SimpleMenuItem displayText="Manage Account..." onClick={onClick} />
+ </Link>
+ );
+};
+
+export interface DifferentWalletSimpleMenuItemProps {
+ onClick?: () => void;
+}
+export const DifferentWalletSimpleMenuItem: React.StatelessComponent<DifferentWalletSimpleMenuItemProps> = ({
+ onClick,
+}) => {
+ return <SimpleMenuItem displayText="Use a Different Wallet..." onClick={onClick} />;
+};
diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx
index 88f216d4e..315f72854 100644
--- a/packages/website/ts/components/ui/text.tsx
+++ b/packages/website/ts/components/ui/text.tsx
@@ -3,7 +3,7 @@ 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';
+export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i';
export interface TextProps {
className?: string;
@@ -16,7 +16,8 @@ export interface TextProps {
center?: boolean;
fontWeight?: number | string;
textDecorationLine?: string;
- onClick?: () => void;
+ onClick?: (event: React.MouseEvent<HTMLElement>) => void;
+ hoverColor?: string;
}
const PlainText: React.StatelessComponent<TextProps> = ({ children, className, onClick, Tag }) => (
@@ -37,7 +38,7 @@ export const Text = styled(PlainText)`
${props => (props.onClick ? 'cursor: pointer' : '')};
transition: color 0.5s ease;
&:hover {
- ${props => (props.onClick ? `color: ${darken(0.1, props.fontColor)}` : '')};
+ ${props => (props.onClick ? `color: ${props.hoverColor || darken(0.3, props.fontColor)}` : '')};
}
`;
diff --git a/packages/website/ts/components/wallet/body_overlay.tsx b/packages/website/ts/components/wallet/body_overlay.tsx
index 5ced704f9..26359d0d2 100644
--- a/packages/website/ts/components/wallet/body_overlay.tsx
+++ b/packages/website/ts/components/wallet/body_overlay.tsx
@@ -9,11 +9,11 @@ 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, BrowserType, ProviderType } from 'ts/types';
-import { constants } from 'ts/utils/constants';
+import { AccountState, ProviderType } from 'ts/types';
import { utils } from 'ts/utils/utils';
const METAMASK_IMG_SRC = '/images/metamask_icon.png';
+const TOSHI_IMG_SRC = '/images/toshi_logo.jpg';
export interface BodyOverlayProps {
dispatcher: Dispatcher;
@@ -92,8 +92,10 @@ interface DisconnectedOverlayProps {
const DisconnectedOverlay = (props: DisconnectedOverlayProps) => {
return (
<div className="flex flex-column items-center">
- <GetMetaMask />
- <UseDifferentWallet fontColor={colors.mediumBlue} onClick={props.onUseDifferentWalletClicked} />
+ <GetWalletCallToAction />
+ {!utils.isMobileOperatingSystem() && (
+ <UseDifferentWallet fontColor={colors.mediumBlue} onClick={props.onUseDifferentWalletClicked} />
+ )}
</div>
);
};
@@ -112,32 +114,20 @@ const UseDifferentWallet = (props: UseDifferentWallet) => {
);
};
-const GetMetaMask = () => {
- const browserType = utils.getBrowserType();
- let extensionLink;
- switch (browserType) {
- case BrowserType.Chrome:
- extensionLink = constants.URL_METAMASK_CHROME_STORE;
- break;
- case BrowserType.Firefox:
- extensionLink = constants.URL_METAMASK_FIREFOX_STORE;
- break;
- case BrowserType.Opera:
- extensionLink = constants.URL_METAMASK_OPERA_STORE;
- break;
- default:
- extensionLink = constants.URL_METAMASK_HOMEPAGE;
- }
+const GetWalletCallToAction = () => {
+ const [downloadLink, isOnMobile] = utils.getBestWalletDownloadLinkAndIsMobile();
+ const imageUrl = isOnMobile ? TOSHI_IMG_SRC : METAMASK_IMG_SRC;
+ const text = isOnMobile ? 'Get Toshi Wallet' : 'Get MetaMask Wallet';
return (
- <a href={extensionLink} target="_blank" style={{ textDecoration: 'none' }}>
+ <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={METAMASK_IMG_SRC} width="28px" />
+ <Image src={imageUrl} width="28px" borderRadius="22%" />
<Container marginLeft="8px" marginRight="12px">
<Text fontColor={colors.white} fontSize="16px" fontWeight={500}>
- Get MetaMask Wallet
+ {text}
</Text>
</Container>
</Island>
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
index 1f1e3598a..6c1c495d7 100644
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ b/packages/website/ts/components/wallet/wallet.tsx
@@ -1,19 +1,26 @@
import { constants as sharedConstants, EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
import { BigNumber, errorUtils } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
import * as React from 'react';
-import { Link } from 'react-router-dom';
import firstBy = require('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 {
+ 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';
@@ -34,7 +41,6 @@ import {
TokenByAddress,
TokenState,
TokenStateByAddress,
- WebsitePaths,
} from 'ts/types';
import { analytics } from 'ts/utils/analytics';
import { constants } from 'ts/utils/constants';
@@ -83,9 +89,7 @@ const ICON_DIMENSION = 28;
const BODY_ITEM_KEY = 'BODY';
const HEADER_ITEM_KEY = 'HEADER';
const ETHER_ITEM_KEY = 'ETHER';
-const USD_DECIMAL_PLACES = 2;
const NO_ALLOWANCE_TOGGLE_SPACE_WIDTH = 56;
-const ACCOUNT_PATH = `${WebsitePaths.Portal}/account`;
const PLACEHOLDER_COLOR = colors.grey300;
const LOADING_ROWS_COUNT = 6;
@@ -189,6 +193,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
);
}
private _renderConnectedHeaderRows(): React.ReactElement<{}> {
+ const isMobile = this.props.screenWidth === ScreenWidths.Sm;
const userAddress = this.props.userAddress;
const accountState = this._getAccountState();
const main = (
@@ -199,15 +204,49 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
<AccountConnection accountState={accountState} injectedProviderName={this.props.injectedProviderName} />
</div>
);
+ const onClick = _.noop;
+ 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 (
- <Link key={HEADER_ITEM_KEY} to={ACCOUNT_PATH} style={{ textDecoration: 'none' }}>
- <StandardIconRow
- icon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
- main={main}
- minHeight="60px"
- backgroundColor={colors.white}
- />
- </Link>
+ <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<{}> {
@@ -231,8 +270,8 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
position: 'relative',
overflowY: this.state.isHoveringSidebar ? 'scroll' : 'hidden',
marginRight: this.state.isHoveringSidebar ? 0 : 4,
- // TODO: make this completely responsive
- maxHeight: this.props.screenWidth !== ScreenWidths.Sm ? 475 : undefined,
+ minHeight: '250px',
+ maxHeight: !utils.isMobileWidth(this.props.screenWidth) ? 'calc(90vh - 300px)' : undefined,
};
}
private _onSidebarHover(_event: React.FormEvent<HTMLInputElement>): void {
@@ -320,8 +359,24 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
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={
@@ -331,23 +386,8 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
</div>
}
accessory={this._renderAccessoryItems(accessoryItemConfig)}
- backgroundColor={shouldShowWrapEtherItem ? colors.walletFocusedItemBackground : undefined}
/>
- {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)}
- />
- )}
+ {this.state.wrappedEtherDirection === Side.Deposit && wrapEtherItem}
</div>
);
}
@@ -397,12 +437,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
</PlaceHolder>
);
} else {
- const result = utils.getFormattedAmount(amount, decimals, symbol);
- return (
- <Text fontSize="16px" fontWeight="bold" lineHeight="1em">
- {result}
- </Text>
- );
+ return <Balance amount={amount} decimals={decimals} symbol={symbol} />;
}
}
private _renderValue(
@@ -411,19 +446,11 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
price?: BigNumber,
isLoading: boolean = false,
): React.ReactNode {
- let result;
- if (!isLoading) {
- if (_.isUndefined(price)) {
- result = '--';
- } else {
- const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- const value = unitAmount.mul(price);
- const formattedAmount = value.toFixed(USD_DECIMAL_PLACES);
- result = `$${formattedAmount}`;
- }
- } else {
- result = '$0.00';
- }
+ 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">
diff --git a/packages/website/ts/components/wallet/wrap_ether_item.tsx b/packages/website/ts/components/wallet/wrap_ether_item.tsx
index 851b35f90..2b4cf93fe 100644
--- a/packages/website/ts/components/wallet/wrap_ether_item.tsx
+++ b/packages/website/ts/components/wallet/wrap_ether_item.tsx
@@ -8,6 +8,7 @@ import * as React from 'react';
import { Blockchain } from 'ts/blockchain';
import { EthAmountInput } from 'ts/components/inputs/eth_amount_input';
import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
+import { Container } from 'ts/components/ui/container';
import { Dispatcher } from 'ts/redux/dispatcher';
import { colors } from 'ts/style/colors';
import { BlockchainCallErrs, Side, Token } from 'ts/types';
@@ -94,7 +95,7 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther
const topLabelText = isWrappingEth ? 'Convert ETH into WETH 1:1' : 'Convert WETH into ETH 1:1';
return (
- <div className="flex" style={{ backgroundColor: colors.walletFocusedItemBackground }}>
+ <Container className="flex" backgroundColor={colors.walletFocusedItemBackground} paddingTop="25px">
<div>{this._renderIsEthConversionHappeningSpinner()} </div>
<div className="flex flex-column">
<div style={styles.topLabel}>{topLabelText}</div>
@@ -142,7 +143,7 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther
{this._renderErrorMsg()}
</div>
- </div>
+ </Container>
);
}
private _onValueChange(_isValid: boolean, amount?: BigNumber): void {
diff --git a/packages/website/ts/containers/subproviders_documentation.ts b/packages/website/ts/containers/subproviders_documentation.ts
index 6d4230e53..567f6a37e 100644
--- a/packages/website/ts/containers/subproviders_documentation.ts
+++ b/packages/website/ts/containers/subproviders_documentation.ts
@@ -25,6 +25,7 @@ const docSections = {
emptyWalletSubprovider: 'emptyWalletSubprovider',
fakeGasEstimateSubprovider: 'fakeGasEstimateSubprovider',
injectedWeb3Subprovider: 'injectedWeb3Subprovider',
+ signerSubprovider: 'signerSubprovider',
redundantRPCSubprovider: 'redundantRPCSubprovider',
ganacheSubprovider: 'ganacheSubprovider',
nonceTrackerSubprovider: 'nonceTrackerSubprovider',
@@ -50,6 +51,7 @@ const docsInfoConfig: DocsInfoConfig = {
['emptyWallet-subprovider']: [docSections.emptyWalletSubprovider],
['fakeGasEstimate-subprovider']: [docSections.fakeGasEstimateSubprovider],
['injectedWeb3-subprovider']: [docSections.injectedWeb3Subprovider],
+ ['signer-subprovider']: [docSections.signerSubprovider],
['redundantRPC-subprovider']: [docSections.redundantRPCSubprovider],
['ganache-subprovider']: [docSections.ganacheSubprovider],
['nonceTracker-subprovider']: [docSections.nonceTrackerSubprovider],
@@ -69,6 +71,7 @@ const docsInfoConfig: DocsInfoConfig = {
[docSections.emptyWalletSubprovider]: ['"subproviders/src/subproviders/empty_wallet_subprovider"'],
[docSections.fakeGasEstimateSubprovider]: ['"subproviders/src/subproviders/fake_gas_estimate_subprovider"'],
[docSections.injectedWeb3Subprovider]: ['"subproviders/src/subproviders/injected_web3"'],
+ [docSections.signerSubprovider]: ['"subproviders/src/subproviders/signer"'],
[docSections.redundantRPCSubprovider]: ['"subproviders/src/subproviders/redundant_rpc"'],
[docSections.ganacheSubprovider]: ['"subproviders/src/subproviders/ganache"'],
[docSections.nonceTrackerSubprovider]: ['"subproviders/src/subproviders/nonce_tracker"'],
diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx
index 0259af36f..5bb5d06a9 100644
--- a/packages/website/ts/pages/about/about.tsx
+++ b/packages/website/ts/pages/about/about.tsx
@@ -165,16 +165,24 @@ const teamRow5: ProfileInfo[] = [
},
];
-// const teamRow6: ProfileInfo[] = [
-// {
-// name: 'Chris Kalani',
-// title: 'Director of Design',
-// description: `Previously founded Wake (acquired by InVision). Early Facebook product designer.`,
-// image: 'images/team/chris.png',
-// linkedIn: 'https://www.linkedin.com/in/chriskalani/',
-// github: 'https://github.com/chriskalani',
-// },
-// ];
+const teamRow6: ProfileInfo[] = [
+ {
+ name: 'Alex Browne',
+ title: 'Engineer in Residence',
+ description: `Full-stack blockchain engineer. Previously at Plaid. Open source guru and footgun dismantler. Computer Science and Electrical Engineering at Duke.`,
+ image: 'images/team/alexbrowne.png',
+ linkedIn: 'https://www.linkedin.com/in/stephenalexbrowne/',
+ github: 'http://github.com/albrow',
+ },
+ // {
+ // name: 'Chris Kalani',
+ // title: 'Director of Design',
+ // description: `Previously founded Wake (acquired by InVision). Early Facebook product designer.`,
+ // image: 'images/team/chris.png',
+ // linkedIn: 'https://www.linkedin.com/in/chriskalani/',
+ // github: 'https://github.com/chriskalani',
+ // },
+];
const advisors: ProfileInfo[] = [
{
@@ -270,6 +278,7 @@ export class About extends React.Component<AboutProps, AboutState> {
<div className="clearfix">{this._renderProfiles(teamRow3)}</div>
<div className="clearfix">{this._renderProfiles(teamRow4)}</div>
<div className="clearfix">{this._renderProfiles(teamRow5)}</div>
+ <div className="clearfix">{this._renderProfiles(teamRow6)}</div>
</div>
<div className="pt3 pb2">
<div
diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx
index f091778f4..b2cf4d979 100644
--- a/packages/website/ts/pages/landing/landing.tsx
+++ b/packages/website/ts/pages/landing/landing.tsx
@@ -268,15 +268,11 @@ export class Landing extends React.Component<LandingProps, LandingState> {
</Link>
</div>
<div className="lg-col lg-col-6 sm-center sm-col sm-col-12">
- <a
- href={constants.URL_ZEROEX_CHAT}
- target="_blank"
- className="text-decoration-none"
- >
+ <Link to={WebsitePaths.Portal} className="text-decoration-none">
<CallToAction width="175px">
- {this.props.translate.get(Key.CommunityCallToAction, Deco.Cap)}
+ {this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
</CallToAction>
- </a>
+ </Link>
</div>
</Container>
</div>
@@ -295,7 +291,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
<div
className="mr1 px1"
style={{
- backgroundColor: colors.lightTurquois,
+ backgroundColor: colors.white,
borderRadius: 3,
color: colors.heroGrey,
height: 23,
diff --git a/packages/website/ts/redux/store.ts b/packages/website/ts/redux/store.ts
index 0d0e6cea1..2672e3f61 100644
--- a/packages/website/ts/redux/store.ts
+++ b/packages/website/ts/redux/store.ts
@@ -13,9 +13,11 @@ export const store: ReduxStore<State> = createStore(
);
store.subscribe(
_.throttle(() => {
+ const state = store.getState();
// Persisted state
stateStorage.saveState({
- hasPortalOnboardingBeenClosed: store.getState().hasPortalOnboardingBeenClosed,
+ hasPortalOnboardingBeenClosed: state.hasPortalOnboardingBeenClosed,
+ isPortalOnboardingShowing: state.isPortalOnboardingShowing,
});
}, ONE_SECOND),
);
diff --git a/packages/website/ts/style/media.ts b/packages/website/ts/style/media.ts
new file mode 100644
index 000000000..870d9a277
--- /dev/null
+++ b/packages/website/ts/style/media.ts
@@ -0,0 +1,14 @@
+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/types.ts b/packages/website/ts/types.ts
index 498a0a5b8..e8dc694f6 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -1,5 +1,6 @@
import { ECSignature } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
+import { Provider } from 'ethereum-types';
import * as React from 'react';
export enum Side {
@@ -215,10 +216,11 @@ export interface ContractEvent {
}
export type ValidatedBigNumberCallback = (isValid: boolean, amount?: BigNumber) => void;
+// Associated values are in `em` units
export enum ScreenWidths {
- Sm = 'SM',
- Md = 'MD',
- Lg = 'LG',
+ Sm = 40,
+ Md = 52,
+ Lg = 64,
}
export enum AlertTypes {
@@ -241,8 +243,8 @@ export enum BlockchainCallErrs {
}
export enum Environments {
- DEVELOPMENT,
- PRODUCTION,
+ DEVELOPMENT = 'DEVELOPMENT',
+ PRODUCTION = 'PRODUCTION',
}
export type ContractInstance = any; // TODO: add type definition for Contract
@@ -454,6 +456,7 @@ export enum Key {
Developers = 'DEVELOPERS',
Home = 'HOME',
RocketChat = 'ROCKETCHAT',
+ TradeCallToAction = 'TRADE_CALL_TO_ACTION',
}
export enum SmartContractDocSections {
@@ -487,6 +490,8 @@ export enum Providers {
Parity = 'PARITY',
Metamask = 'METAMASK',
Mist = 'MIST',
+ Toshi = 'TOSHI',
+ Cipher = 'CIPHER',
}
export interface InjectedProviderUpdate {
@@ -547,7 +552,10 @@ export interface WebsiteBackendTokenInfo {
}
export interface WebsiteBackendGasInfo {
+ safeSlow: number;
average: number;
+ fast: number;
+ fastest: number;
}
export interface WebsiteBackendJobInfo {
@@ -565,10 +573,32 @@ export enum BrowserType {
Other = 'Other',
}
+export enum OperatingSystemType {
+ Android = 'Android',
+ iOS = 'iOS',
+ 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;
+}
+
+// Minimal expected interface for an injected web3 object
+export interface InjectedWeb3 {
+ currentProvider: InjectedProvider;
+ version: {
+ getNetwork(cd: (err: Error, networkId: string) => void): void;
+ };
+}
// tslint:disable:max-file-line-count
diff --git a/packages/website/ts/utils/analytics.ts b/packages/website/ts/utils/analytics.ts
index 928e45bc3..f4bfa083f 100644
--- a/packages/website/ts/utils/analytics.ts
+++ b/packages/website/ts/utils/analytics.ts
@@ -1,8 +1,8 @@
import * as _ from 'lodash';
import * as ReactGA from 'react-ga';
+import { InjectedWeb3 } from 'ts/types';
import { configs } from 'ts/utils/configs';
import { utils } from 'ts/utils/utils';
-import * as Web3 from 'web3';
export const analytics = {
init(): void {
@@ -16,11 +16,12 @@ export const analytics = {
value,
});
},
- async logProviderAsync(web3IfExists: Web3): Promise<void> {
+ async logProviderAsync(web3IfExists: InjectedWeb3): Promise<void> {
await utils.onPageLoadAsync();
- const providerType = !_.isUndefined(web3IfExists)
- ? utils.getProviderType(web3IfExists.currentProvider)
- : 'NONE';
+ const providerType =
+ !_.isUndefined(web3IfExists) && !_.isUndefined(web3IfExists.currentProvider)
+ ? utils.getProviderType(web3IfExists.currentProvider)
+ : 'NONE';
ReactGA.ga('set', 'dimension1', providerType);
},
};
diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts
index e8a486c35..97aabd13d 100644
--- a/packages/website/ts/utils/configs.ts
+++ b/packages/website/ts/utils/configs.ts
@@ -22,50 +22,9 @@ export const configs = {
DOMAIN_DEVELOPMENT: '0xproject.localhost:3572',
DOMAIN_PRODUCTION: '0xproject.com',
ENVIRONMENT: isDevelopment ? Environments.DEVELOPMENT : Environments.PRODUCTION,
- ICON_URL_BY_SYMBOL: {
- REP: '/images/token_icons/augur.png',
- DGD: '/images/token_icons/digixdao.png',
- WETH: '/images/token_icons/ether_erc20.png',
- MLN: '/images/token_icons/melon.png',
- GNT: '/images/token_icons/golem.png',
- MKR: '/images/token_icons/makerdao.png',
- ZRX: '/images/token_icons/zero_ex.png',
- ANT: '/images/token_icons/aragon.png',
- BNT: '/images/token_icons/bancor.png',
- BAT: '/images/token_icons/basicattentiontoken.png',
- CVC: '/images/token_icons/civic.png',
- EOS: '/images/token_icons/eos.png',
- FUN: '/images/token_icons/funfair.png',
- GNO: '/images/token_icons/gnosis.png',
- ICN: '/images/token_icons/iconomi.png',
- OMG: '/images/token_icons/omisego.png',
- SNT: '/images/token_icons/status.png',
- STORJ: '/images/token_icons/storjcoinx.png',
- PAY: '/images/token_icons/tenx.png',
- QTUM: '/images/token_icons/qtum.png',
- DNT: '/images/token_icons/district0x.png',
- SNGLS: '/images/token_icons/singularity.png',
- EDG: '/images/token_icons/edgeless.png',
- '1ST': '/images/token_icons/firstblood.jpg',
- WINGS: '/images/token_icons/wings.png',
- BQX: '/images/token_icons/bitquence.png',
- LUN: '/images/token_icons/lunyr.png',
- RLC: '/images/token_icons/iexec.png',
- MCO: '/images/token_icons/monaco.png',
- ADT: '/images/token_icons/adtoken.png',
- CFI: '/images/token_icons/cofound-it.png',
- ROL: '/images/token_icons/etheroll.png',
- WGNT: '/images/token_icons/golem.png',
- MTL: '/images/token_icons/metal.png',
- NMR: '/images/token_icons/numeraire.png',
- SAN: '/images/token_icons/santiment.png',
- TAAS: '/images/token_icons/taas.png',
- TKN: '/images/token_icons/tokencard.png',
- TRST: '/images/token_icons/trust.png',
- } as { [symbol: string]: string },
GOOGLE_ANALYTICS_ID: 'UA-98720122-1',
LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE: '2017-11-22',
- LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE: '2018-6-25',
+ LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE: '2018-7-5',
OUTDATED_WRAPPED_ETHERS: [
{
42: {
diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts
index d3a2aa107..4b3443d21 100644
--- a/packages/website/ts/utils/constants.ts
+++ b/packages/website/ts/utils/constants.ts
@@ -6,7 +6,7 @@ export const constants = {
ETHER_TOKEN_SYMBOL: 'WETH',
ZRX_TOKEN_SYMBOL: 'ZRX',
ETHER_SYMBOL: 'ETH',
- TOKEN_AMOUNT_DISPLAY_PRECISION: 5,
+ TOKEN_AMOUNT_DISPLAY_PRECISION: 4,
GENESIS_ORDER_BLOCK_BY_NETWORK_ID: {
1: 4145578,
42: 3117574,
@@ -29,6 +29,8 @@ export const constants = {
PROVIDER_NAME_METAMASK: 'MetaMask',
PROVIDER_NAME_PARITY_SIGNER: 'Parity Signer',
PROVIDER_NAME_MIST: 'Mist',
+ PROVIDER_NAME_CIPHER: 'Cipher Browser',
+ PROVIDER_NAME_TOSHI: 'Toshi',
PROVIDER_NAME_GENERIC: 'Injected Web3',
PROVIDER_NAME_PUBLIC: '0x Public',
ROLLBAR_ACCESS_TOKEN: 'a6619002b51c4464928201e6ea94de65',
@@ -38,6 +40,7 @@ export const constants = {
UNAVAILABLE_STATUS: 503,
TAKER_FEE: new BigNumber(0),
TESTNET_NAME: 'Kovan',
+ NUMERAL_USD_FORMAT: '$0,0.00',
PROJECT_URL_ETHFINEX: 'https://www.ethfinex.com/',
PROJECT_URL_AMADEUS: 'http://amadeusrelay.org',
PROJECT_URL_DDEX: 'https://ddex.io',
@@ -71,6 +74,8 @@ export const constants = {
URL_GITHUB_WIKI: 'https://github.com/0xProject/wiki',
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_TOSHI_IOS_APP_STORE: 'https://itunes.apple.com/us/app/toshi-ethereum-wallet/id1278383455?mt=8',
+ URL_TOSHI_ANDROID_APP_STORE: 'https://play.google.com/store/apps/details?id=org.toshi&hl=en_US',
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',
diff --git a/packages/website/ts/utils/translate.ts b/packages/website/ts/utils/translate.ts
index 39924b6f7..1ee1a59c5 100644
--- a/packages/website/ts/utils/translate.ts
+++ b/packages/website/ts/utils/translate.ts
@@ -55,6 +55,19 @@ export class Translate {
}
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:
diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts
index 726e1815f..8c76a7592 100644
--- a/packages/website/ts/utils/utils.ts
+++ b/packages/website/ts/utils/utils.ts
@@ -8,11 +8,14 @@ import * as bowser from 'bowser';
import deepEqual = require('deep-equal');
import * as _ from 'lodash';
import * as moment from 'moment';
+import * as numeral from 'numeral';
+
import {
AccountState,
BlockchainCallErrs,
BrowserType,
Environments,
+ OperatingSystemType,
Order,
Providers,
ProviderType,
@@ -27,9 +30,6 @@ import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import * as u2f from 'ts/vendor/u2f_api';
-const LG_MIN_EM = 64;
-const MD_MIN_EM = 52;
-
const isDogfood = (): boolean => _.includes(window.location.href, configs.DOMAIN_DOGFOOD);
export const utils = {
@@ -134,9 +134,9 @@ export const utils = {
// This logic mirrors the CSS media queries in BassCSS for the `lg-`, `md-` and `sm-` CSS
// class prefixes. Do not edit these.
- if (widthInEm > LG_MIN_EM) {
+ if (widthInEm > ScreenWidths.Lg) {
return ScreenWidths.Lg;
- } else if (widthInEm > MD_MIN_EM) {
+ } else if (widthInEm > ScreenWidths.Md) {
return ScreenWidths.Md;
} else {
return ScreenWidths.Sm;
@@ -324,6 +324,7 @@ export const utils = {
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;
@@ -337,6 +338,10 @@ export const utils = {
parsedProviderName = Providers.Parity;
} else if ((provider as any).isMetaMask) {
parsedProviderName = Providers.Metamask;
+ } else if (!_.isUndefined(_.get(window, 'SOFA'))) {
+ parsedProviderName = Providers.Toshi;
+ } else if (!_.isUndefined(_.get(window, '__CIPHER__'))) {
+ parsedProviderName = Providers.Cipher;
}
return parsedProviderName;
},
@@ -354,7 +359,9 @@ export const utils = {
},
isDogfood,
shouldShowPortalV2(): boolean {
- return this.isDevelopment() || this.isStaging() || this.isDogfood();
+ // return this.isDevelopment() || this.isStaging() || this.isDogfood();
+ // TODO: Remove this method entirely after launch.
+ return true;
},
shouldShowJobsPage(): boolean {
return this.isDevelopment() || this.isStaging() || this.isDogfood();
@@ -376,20 +383,33 @@ export const utils = {
return trackedTokens;
},
getFormattedAmountFromToken(token: Token, tokenState: TokenState): string {
- return utils.getFormattedAmount(tokenState.balance, token.decimals, token.symbol);
+ return utils.getFormattedAmount(tokenState.balance, token.decimals);
},
- getFormattedAmount(amount: BigNumber, decimals: number, symbol: string): string {
+ 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 precision = unitAmount.lt(1)
+ ? Math.min(constants.TOKEN_AMOUNT_DISPLAY_PRECISION, unitAmount.decimalPlaces())
+ : 2;
+ const format = `0,0.${_.repeat('0', precision)}`;
+ const formattedAmount = numeral(unitAmount).format(format);
+ return formattedAmount;
+ },
+ getUsdValueFormattedAmount(amount: BigNumber, decimals: number, price: BigNumber): string {
const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- const precision = Math.min(constants.TOKEN_AMOUNT_DISPLAY_PRECISION, unitAmount.decimalPlaces());
- const formattedAmount = unitAmount.toFixed(precision);
- return `${formattedAmount} ${symbol}`;
+ const value = unitAmount.mul(price);
+ return numeral(value).format(constants.NUMERAL_USD_FORMAT);
},
openUrl(url: string): void {
window.open(url, '_blank');
},
- isMobile(screenWidth: ScreenWidths): boolean {
+ isMobileWidth(screenWidth: ScreenWidths): boolean {
return screenWidth === ScreenWidths.Sm;
},
+ isMobileOperatingSystem(): boolean {
+ return bowser.mobile;
+ },
getBrowserType(): BrowserType {
if (bowser.chrome) {
return BrowserType.Chrome;
@@ -401,7 +421,63 @@ export const utils = {
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_TOSHI_ANDROID_APP_STORE;
+ break;
+ case OperatingSystemType.iOS:
+ downloadLink = constants.URL_TOSHI_IOS_APP_STORE;
+ break;
+ default:
+ // Toshi is only supported on these mobile OSes - just default to iOS
+ downloadLink = constants.URL_TOSHI_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;
+ },
};