Merge pull request #67 from gnosis/feature/provider-ui-design-improvements

Feature: Design Welcome route including Header's Provider
This commit is contained in:
Adolfo Panizo 2018-09-06 17:11:19 +02:00 committed by GitHub
commit 1b1a140e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 1536 additions and 475 deletions

View File

@ -1,2 +1,3 @@
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono:300,400,500" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

View File

@ -65,7 +65,7 @@
"ethereumjs-abi": "^0.6.5",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^1.1.11",
"flow-bin": "^0.66.0",
"flow-bin": "^0.79.1",
"fs-extra": "^5.0.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.0.4",
@ -102,8 +102,8 @@
},
"dependencies": {
"@gnosis.pm/util-contracts": "^0.2.14",
"@material-ui/core": "^1.2.1",
"@material-ui/icons": "^1.1.0",
"@material-ui/core": "^3.0.1",
"@material-ui/icons": "^3.0.1",
"final-form": "^4.2.1",
"history": "^4.7.2",
"react-final-form": "^3.1.2",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 99 KiB

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono:300,400,500" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<title>Multisig Safe</title>
</head>

View File

@ -2,16 +2,17 @@
import React from 'react'
import Block from '~/components/layout/Block'
import Link from '~/components/layout/Link'
import Paragraph from '~/components/layout/Paragraph'
import { WELCOME_ADDRESS, SAFELIST_ADDRESS } from '~/routes/routes'
import styles from './index.scss'
const Footer = () => (
<Block className={styles.footer}>
<Link padding="md" to={WELCOME_ADDRESS}>
Welcome
<Link to={WELCOME_ADDRESS}>
<Paragraph size="sm" color="primary" noMargin>Welcome</Paragraph>
</Link>
<Link to={SAFELIST_ADDRESS}>
Safe List
<Paragraph size="sm" color="primary" noMargin>Safe List</Paragraph>
</Link>
</Block>
)

View File

@ -1,7 +1,12 @@
.footer {
font-size: $smallFontSize;
display: grid;
grid-template-columns: 1fr auto auto;
justify-items: end;
grid-template-columns: 100px 100px 1fr;
grid-template-rows: 36px;
justify-items: center;
align-items: center;
border: solid 0.5px $border;
background-color: white;
}
@media only screen and (max-width: $(screenXs)px) {

View File

@ -11,6 +11,6 @@ const FrameDecorator = story => (
</div>
)
storiesOf('Components', module)
storiesOf('Components /Footer', module)
.addDecorator(FrameDecorator)
.add('Footer', () => <Component />)
.add('Loaded', () => <Component />)

View File

@ -1,6 +1,12 @@
// @flow
import { fetchProvider } from '~/logic/wallets/store/actions'
import { fetchProvider, removeProvider } from '~/logic/wallets/store/actions'
export type Actions = {
fetchProvider: typeof fetchProvider,
removeProvider: typeof removeProvider,
}
export default {
fetchProvider,
removeProvider,
}

View File

@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="80" height="80" viewBox="0 0 80 80">
<defs>
<circle id="a" cx="36.129" cy="36.129" r="36.129"/>
</defs>
<g fill="none" fill-rule="evenodd">
<g>
<use fill="#E4E8F1" xlink:href="#a"/>
<path fill="#A2A8BA" d="M33.234 36.695l-2.569 15.782h12.58l-2.566-15.782c2.861-1.372 4.848-4.254 4.848-7.603 0-4.662-3.835-8.447-8.57-8.447-4.73 0-8.57 3.785-8.57 8.447-.005 3.352 1.979 6.23 4.847 7.603"/>
</g>
<g fill-rule="nonzero" transform="translate(38.71 38.71)">
<circle cx="20.645" cy="20.645" r="20.645" fill="#FD7890"/>
<path fill="#FFF" d="M20.645 30.968l4.301-5.506a7.354 7.354 0 0 0-4.3-1.376 7.354 7.354 0 0 0-4.302 1.376l4.301 5.506zm0-20.645c-4.839 0-9.307 1.536-12.903 4.129l2.15 2.752c2.987-2.156 6.715-3.44 10.753-3.44s7.766 1.284 10.753 3.44l2.15-2.752c-3.596-2.593-8.064-4.13-12.903-4.13zm0 6.881c-3.226 0-6.2 1.021-8.602 2.753l2.15 2.753a10.978 10.978 0 0 1 6.452-2.065c2.425 0 4.66.769 6.452 2.065l2.15-2.753c-2.401-1.732-5.376-2.753-8.602-2.753z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="nonzero">
<circle cx="8" cy="8" r="8" fill="#FFC05F"/>
<path fill="#FFF" d="M8 12l1.667-2.133A2.85 2.85 0 0 0 8 9.333c-.625 0-1.204.2-1.667.534L8 12zm0-8a8.529 8.529 0 0 0-5 1.6l.833 1.067A7.104 7.104 0 0 1 8 5.333c1.565 0 3.01.498 4.167 1.334L13 5.6A8.529 8.529 0 0 0 8 4zm0 2.667a5.68 5.68 0 0 0-3.333 1.066L5.5 8.8C6.194 8.298 7.06 8 8 8s1.806.298 2.5.8l.833-1.067A5.68 5.68 0 0 0 8 6.667z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 542 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="nonzero">
<circle cx="8" cy="8" r="8" fill="#467EE5"/>
<path fill="#FFF" d="M8 12l1.667-2.133A2.85 2.85 0 0 0 8 9.333c-.625 0-1.204.2-1.667.534L8 12zm0-8a8.529 8.529 0 0 0-5 1.6l.833 1.067A7.104 7.104 0 0 1 8 5.333c1.565 0 3.01.498 4.167 1.334L13 5.6A8.529 8.529 0 0 0 8 4zm0 2.667a5.68 5.68 0 0 0-3.333 1.066L5.5 8.8C6.194 8.298 7.06 8 8 8s1.806.298 2.5.8l.833-1.067A5.68 5.68 0 0 0 8 6.667z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 542 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
<circle cx="208" cy="203" r="3" fill="none" fill-rule="evenodd" stroke="#FF685E" stroke-width="3" transform="translate(-203 -198)"/>
</svg>

After

Width:  |  Height:  |  Size: 228 B

View File

@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="31" viewBox="0 0 90 31">
<defs>
<path id="a" d="M17.361.154H.251v30.612h17.11V.154z"/>
</defs>
<g fill="none" fill-rule="evenodd">
<path fill="#28B2FA" d="M10.72 15.695l-4.436-4.41a3.215 3.215 0 0 0-.642 1.923 3.159 3.159 0 0 0 3.154 3.154c.722 0 1.39-.24 1.924-.667"/>
<g transform="translate(.564)">
<mask id="b" fill="#fff">
<use xlink:href="#a"/>
</mask>
<path fill="#28B2FA" d="M4.834 5.658c2.686-2.638 6.206-4.07 9.98-4.07h.024c.042 0 .083.002.125.003V15.92L4.834 5.658zM14.787.154c-4.38 0-8.458 1.793-11.447 4.99l-.482.514 12.105 12.286v2.203l-.048.048-3.114-3.173a5.636 5.636 0 0 1-5.04.64 5.684 5.684 0 0 1-3.395-7.27c.152-.46.38-.87.632-1.253L2.656 7.782l-.253.435A14.9 14.9 0 0 0 .25 15.922c-.024 8.166 6.56 14.843 14.638 14.843l2.473.001V.156L14.787.154z" mask="url(#b)"/>
</g>
<path fill="#28B2FA" d="M30.322 15.799c0-6.843-5.568-12.41-12.413-12.414v1.486c6.026.003 10.927 4.903 10.927 10.928 0 6.022-4.901 10.924-10.927 10.927v1.485c6.845-.003 12.413-5.57 12.413-12.412"/>
<path fill="#28B2FA" d="M20.718 15.547l-.591 3.637h2.898l-.591-3.637a1.947 1.947 0 0 0 1.117-1.752c0-1.074-.884-1.946-1.975-1.946-1.09 0-1.974.872-1.974 1.946a1.941 1.941 0 0 0 1.116 1.752M20.026 7.314c.726.185 1.006-.9.28-1.086-.726-.186-1.006.9-.28 1.086M23.194 8.888c.567.475 1.28-.374.714-.85-.567-.474-1.28.375-.714.85M25.309 12.094c.326.67 1.325.178.999-.492-.326-.667-1.326-.176-1 .492M20.026 24.283c.726-.186 1.006.9.28 1.086-.726.186-1.006-.9-.28-1.086M23.194 22.145c.567-.476 1.28.374.714.848-.567.475-1.28-.374-.714-.848M25.309 19.502c.326-.669 1.325-.177.999.493-.326.667-1.326.176-1-.493M26.372 15.798c0 .753 1.129.753 1.129 0 0-.752-1.129-.752-1.129 0"/>
<g fill="#28B2FA">
<path d="M44.805 11.465c-.318-.27-.709-.5-1.172-.695-.463-.191-.99-.365-1.581-.52a34.85 34.85 0 0 1-1.247-.347c-.33-.1-.589-.201-.778-.315-.19-.109-.321-.233-.394-.37a1.026 1.026 0 0 1-.108-.488v-.033c0-.286.125-.527.376-.719.251-.193.628-.29 1.13-.29.502 0 1.005.103 1.507.307a8.455 8.455 0 0 1 1.538.834l1.34-1.917a6.922 6.922 0 0 0-1.983-1.09 7.116 7.116 0 0 0-2.37-.38c-.602 0-1.153.081-1.653.248-.5.164-.93.401-1.291.71-.36.307-.64.676-.84 1.1-.199.423-.298.9-.298 1.428v.033c0 .575.091 1.052.276 1.439.183.385.443.707.778.965.335.26.741.477 1.221.654.48.176 1.016.336 1.608.479.49.121.889.238 1.196.347.307.111.547.22.72.33.172.11.29.23.352.356.06.127.09.273.09.44v.031c0 .343-.147.608-.443.802-.295.192-.71.289-1.246.289-.67 0-1.287-.128-1.85-.38a7.641 7.641 0 0 1-1.648-1.025l-1.523 1.8a6.964 6.964 0 0 0 2.343 1.398 7.87 7.87 0 0 0 2.629.455c.635 0 1.214-.081 1.737-.24a3.997 3.997 0 0 0 1.35-.694 3.16 3.16 0 0 0 .88-1.124c.21-.446.316-.955.316-1.53v-.032c0-.506-.082-.942-.242-1.305a2.657 2.657 0 0 0-.72-.951M66.26 17.341h2.483v-4.606h5.387v-2.38h-5.387V7.821h6.111v-2.38H66.26zM82.338 15.013v-2.498h5.404v-2.33h-5.404V7.77h6.141V5.44h-8.63v11.9h8.711v-2.328zM56.773 12.667h-2.184l.658-2.41A1.153 1.153 0 0 1 54.59 9.2c0-.635.488-1.15 1.093-1.15.603 0 1.09.515 1.09 1.15 0 .473-.27.879-.657 1.055l.658 2.41zm.047-7.225h-2.277l-4.81 11.9h2.518l1.026-2.65h4.747l1.026 2.65h2.583l-4.813-11.9z"/>
</g>
<text fill="#4A5579" font-family="Montserrat-Regular, Montserrat" font-size="7" letter-spacing=".3">
<tspan x="35.725" y="27.412">TEAM EDITIO</tspan> <tspan x="84.903" y="27.412">N</tspan>
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Isolation_Mode" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 697.7 119.5" style="enable-background:new 0 0 697.7 119.5;" xml:space="preserve">
<style type="text/css">
.st0{fill:#00A6C4;}
</style>
<g>
<g>
<path class="st0" d="M399.6,64.3v22.6c-6.2,4.7-15.4,8-23.8,8c-18.1,0-32.2-13.6-32.2-31.1c0-17.5,14.3-30.9,32.9-30.9
c8.8,0,17.5,3.3,23.6,8.6l-5.9,7.6c-4.7-4.4-11.3-7-17.7-7c-12.5,0-22.3,9.5-22.3,21.7c0,12.3,9.9,21.8,22.4,21.8
c4.6,0,9.7-1.6,14.1-4.2V64.3H399.6z"/>
<path class="st0" d="M461.2,94.4l-32.7-44v44h-10.3V33.1h10.2l32.9,44.1V33.1h10.2v61.3H461.2z"/>
<path class="st0" d="M551.4,63.7c0,17.5-14.2,31.1-32.5,31.1c-18.3,0-32.5-13.6-32.5-31.1c0-17.6,14.2-30.9,32.5-30.9
C537.3,32.8,551.4,46.2,551.4,63.7z M496.9,63.7c0,12.2,10.1,21.8,22.1,21.8c12,0,21.8-9.6,21.8-21.8c0-12.2-9.8-21.6-21.8-21.6
C506.9,42.1,496.9,51.6,496.9,63.7z"/>
<path class="st0" d="M608.1,38.9l-4.3,9.1c-6.7-4-13.3-5.7-18-5.7c-6,0-10,2.3-10,6.4c0,13.4,33.1,6.2,33,28.3
c0,11-9.6,17.7-23.1,17.7c-9.6,0-18.7-3.9-25.1-9.7l4.5-8.9c6.3,5.8,14.2,8.9,20.8,8.9c7.2,0,11.5-2.7,11.5-7.4
c0-13.7-33.1-6-33.1-27.9c0-10.5,9-17.1,22.3-17.1C594.6,32.6,602.4,35.2,608.1,38.9z"/>
<path class="st0" d="M624.9,94.4V33.1h10.3v61.3H624.9z"/>
<path class="st0" d="M696.9,38.9l-4.3,9.1c-6.7-4-13.3-5.7-18-5.7c-6,0-10,2.3-10,6.4c0,13.4,33.1,6.2,33,28.3
c0,11-9.6,17.7-23.1,17.7c-9.6,0-18.7-3.9-25.1-9.7l4.5-8.9c6.3,5.8,14.2,8.9,20.8,8.9c7.2,0,11.5-2.7,11.5-7.4
c0-13.7-33.1-6-33.1-27.9c0-10.5,9-17.1,22.3-17.1C683.4,32.6,691.2,35.2,696.9,38.9z"/>
</g>
<g>
<path class="st0" d="M200.7,29.9l-4.4,4.4c3.5,5.5,4.6,12.4,2.2,19c-4,11.2-16.4,17.1-27.7,13.1c-1.6-0.6-3.1-1.3-4.4-2.2
l-14.1,14.1L140,65.9c-5.7,3.8-13,4.9-19.9,2.5c-11.6-4.2-17.6-16.9-13.4-28.4c0.6-1.8,1.5-3.4,2.5-4.9l-5.3-5.3l-1,1.7
c-5.5,9-8.5,19.4-8.5,30.1c-0.1,31.9,25.9,58,57.8,58h0.1c31.9,0,57.8-25.9,57.9-57.8c0-10.6-2.9-21-8.4-30.1L200.7,29.9z"/>
<path class="st0" d="M115.7,41.6c-1.5,2-2.4,4.5-2.4,7.2c0,6.5,5.3,11.8,11.8,11.8c2.7,0,5.2-0.9,7.2-2.5L115.7,41.6z"/>
<g>
<path class="st0" d="M173.6,57.1c1.9,1.3,4.1,2,6.6,2c6.5,0,11.8-5.3,11.8-11.8c0-2.4-0.7-4.7-2-6.6L173.6,57.1z"/>
</g>
<g>
<path class="st0" d="M152.5,69.5l-47.8-48l1.9-2C118.4,7,134.5,0,151.8,0h0.1c17.5,0,34.3,7.5,46,20.5l1.8,2L152.5,69.5z
M112.5,21.5l40,40.1l39.5-39.3c-10.6-10.6-25-16.7-40-16.7h-0.1C137,5.6,123.1,11.2,112.5,21.5z"/>
</g>
<g>
<g>
<path class="st0" d="M99.8,100.4l-5.6-0.4c-23.8-1.5-56.6-7.4-77.8-26.5C3.3,61.8,0.8,50.7,0.7,50.2L0,46.8h86.6L86.1,50
c-0.4,2.9-0.6,5.9-0.6,8.8c0,13.2,3.8,26,11.1,36.9L99.8,100.4z"/>
</g>
<g>
<path class="st0" d="M204.6,100.4l3.1-4.7c7.3-10.9,11.1-23.6,11.1-36.7c0-3-0.2-6.1-0.6-9l-0.4-3.2h86.6l-0.7,3.4
c-0.1,0.5-2.6,11.6-15.6,23.3c-21.2,19.1-54.1,25-77.9,26.5L204.6,100.4z"/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Ebene_4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1077 881" style="enable-background:new 0 0 1077 881;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:10;}
.st1{stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
.st2{fill:none;stroke:#000000;stroke-width:5;stroke-miterlimit:10;}
</style>
<polygon id="outline" class="st0" points="343,282 323,340 333,400 326,405 339,415 329,421 341,432 333,438 350,457 321,543
344,627 432,598 484,624 543,625 590,597 675,625 698,541 671,457 687,438 677,432 689,422 681,415 693,406 685,401 696,339
678,286 561,332 460,332 "/>
<polygon class="st1" points="483,389 427,437 350,457 333,438 341,432 329,421 339,415 326,405 333,400 323,340 343,282 "/>
<polygon class="st1" points="539,389 678,286 696,337 685,401 693,406 681,415 689,422 677,432 687,438 671,457 593,436 "/>
<polygon class="st1" points="483,512 439,501 468,487 "/>
<polygon class="st1" points="544,512 583,501 555,487 "/>
<polygon class="st1" points="494,556 535,556 543,561 547,594 544,591 487,591 483,595 486,561 "/>
<path class="st2" d="M696.5,541.5l-111-5l-38,23c-5,3-10,6-10,6"/>
<path class="st2" d="M488.5,565.5c0,0-5-3-10-6l-38-23l-111,5l-9,1"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Ebene_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1077 881" style="enable-background:new 0 0 1077 881;" xml:space="preserve">
<g>
<path d="M1038,396c-1.6,0.5-1,1.9-1,3c0,2.3-0.2,4.6-0.5,6.9c-1.1,8.8-3.7,23.2-5.8,31.9c-0.4,1.8-0.9,3.6-1.4,5.4
c-2.1,7.5-4.3,15-7.3,22.2c-4.1,9.6-8.4,19.2-13.7,28.2c-3.2,5.3-6.3,10.7-9.9,15.8c-4.5,6.4-9.4,12.6-14.5,18.6
c-4.9,5.9-10.4,11.1-15.8,16.6c-7.3,7.4-15.3,14-23.8,20c-5.9,4.1-11.6,8.5-17.6,12.5c-10.7,7-21.8,13.4-33.5,18.5
c-7.6,3.3-15.3,6.4-23.1,9.1c-7,2.4-14.2,4.5-21.4,6.3c-6,1.5-12.1,2.3-18.2,3.3c-5.6,1-11.3,1.6-17,2.3c-3.6,0.4-7.2,0.3-10.8,0.8
c-9.2,1.4-18.5,0.9-27.8,0.9c-3.1,0-6.2-0.7-9.3-0.9c-3-0.2-6,0.3-9-0.1c-5.7-0.8-11.3-1.6-17-2c-4.8-0.4-9.5-2.1-14.3-2.7
c-10.3-1.3-20.3-4.2-30.3-6.8c-5.5-1.5-11-3-16.4-4.9c-12.6-4.2-25.1-8.6-37.3-13.9c-4.5-1.9-9-3.9-13.6-5.5c-4.2-1.4-5-4.9-2-7.4
c1-0.9,2-0.8,3.2-0.3c6.9,2.4,13.8,4.7,20.8,6.9c12.8,3.9,25.7,7.7,38.8,10.7c6.5,1.5,12.8,3.5,19.3,4.8c7.8,1.6,15.7,2.6,23.5,4.2
c5.3,1,10.7,1.4,16,2.2c4.5,0.7,8.9,0.5,13.3,0.8c4.4,0.3,8.8,1.2,13.3,1.1c6.8-0.2,13.5-0.7,20.2-1.3c9.6-0.8,19.3-2.5,28.8-4.5
c11.3-2.3,22.4-5.5,33.2-9.5c16.9-6.2,32.8-14.7,47.5-25.2c5.1-3.6,9.6-8.1,14.3-12.1c2-1.7,4.1-3.3,6-5.1c1.8-1.7,3.3-3.5,4.9-5.3
c0.9-1,1.6-2.1,2.5-3c8.1-8,14.9-17.1,21.3-26.5c7.5-11,13.9-22.6,19.3-34.7c4.2-9.3,7.5-19,10.2-28.9c1.6-6.1,2.4-12.4,4-18.5
c1.1-4.2-0.1-8.5,1.7-12.6c0.4-1,0.1-2.3,0.1-3.5c0-7.3,0.1-14.7,0-22c-0.1-5.6-0.2-11.2-1-16.7c-2.1-14.1-4.9-28.2-10-41.5
c-4.5-11.8-10.3-23-17.6-33.3c-4.4-6.2-8.9-12.3-14.4-17.5c-5.4-5.1-10.6-10.5-16.4-15.2c-5.6-4.5-11.7-8.3-17.8-12.1
c-5-3.2-10-6.4-15.3-8.8c-9.2-4.1-18.4-8.2-28.1-11.1c-7.5-2.2-14.9-4.3-22.7-5.2c-5.5-0.7-11-1.3-16.5-2.1
c-6-0.9-11.9-1.1-17.8-0.6c-5.3,0.4-10.7,0.3-16.1,1.6c-2.6,0.7-5.5,0.6-8.2,1.1c-5.8,0.9-11.4,2.3-17.1,3.8
c-13.2,3.4-25.7,8.6-37.5,15.3c-5.9,3.4-11.6,7.3-17.1,11.4c-13.2,9.9-24.3,22.1-35.8,33.8c-5.5,5.6-10.2,12-15.3,18.1
c-5.1,6.1-10.3,12-15.1,18.2c-5.5,7.1-10.8,14.4-16.1,21.6c-5.8,7.9-11.7,15.8-17.3,23.8c-4.4,6.3-8.5,12.8-12.7,19.2
c-5.4,8.2-10.9,16.3-16.1,24.6c-4.4,6.9-8.5,14-12.8,20.9c-3.6,5.9-7.2,11.7-10.8,17.5c-5.1,8.2-10.1,16.4-15.3,24.6
c-2.9,4.7-6,9.3-9,14c-7,11-14,22.1-21,33.1c-6,9.3-12.2,18.6-18.2,27.9c-5.9,9-11.8,18.1-17.7,27.1c-6.4,9.7-12.8,19.3-19.4,28.9
c-6.2,9-12.5,18-18.9,26.9c-5.8,8.1-11.9,16-17.8,24.1c-5.4,7.4-10.7,14.8-16.3,22.1c-3.5,4.6-7.6,8.7-11,13.3
c-5.5,7.3-12,13.7-18.2,20.3c-3.4,3.6-7.2,6.7-10.5,10.3c-1.9,2-2.9,1.9-4.6,0.3c-1.7-1.7-1.8-3.4-0.4-5.2c1.4-1.8,2.9-3.6,4.4-5.3
c4.3-5,8.8-9.9,12.9-15c6.5-8,12.5-16.4,17.8-25.2c5.3-8.8,10.6-17.6,15.8-26.5c5.1-8.7,10.1-17.5,15.1-26.4
c2.2-3.8,4.2-7.8,6.2-11.7c4.4-8.4,8.8-16.9,13.2-25.3c5.4-10.3,10.7-20.7,16-31c13.8-27.2,28-54.2,41.3-81.7
c10-20.8,20.5-41.4,30.6-62.1c4.2-8.7,8.3-17.4,12.6-26c5.1-10.2,10.4-20.4,15.7-30.5c4.3-8.1,8.6-16.2,13.1-24.2
c7.5-13,15.3-25.9,22.8-38.9c8.1-14,17.4-27.3,26.4-40.7c5.2-7.7,11.1-15,16.8-22.4c3.2-4.2,6.2-8.4,9.6-12.5
c3-3.7,6.3-7.2,9.6-10.7c3.7-3.9,7.5-7.6,11.3-11.3c13.6-13.4,29.2-23.9,46.6-31.6c12.2-5.4,24.8-9.6,37.9-12.4
c6.6-1.4,13.4-2.4,20.2-3.4c14.5-2.1,29-1.7,43.5-1.8c4.7,1.5,9.8,0.4,14.5,1.9c2.6,0.8,5.5,0.8,8.2,1.1c7.3,0.9,14.4,2.5,21.4,4.4
c11.6,3.1,22.9,7.3,33.9,12.1c8.1,3.5,15.7,8.1,23.6,12.2c6.8,3.6,13.2,7.8,19.5,12.3c3.6,2.6,7.3,5,10.6,7.9
c7,6.1,14.2,12,20.5,18.7c6.6,6.9,12.9,14,18.4,21.8c3.7,5.4,7.6,10.6,11.1,16.2c5.3,8.7,10,17.6,14.1,26.9c3,6.9,5.6,13.8,7.9,21
c2.4,7.6,4.7,15.1,5.8,23.1c0.7,4.6,2.2,9.1,2.8,13.8c0.7,5.2,0.7,10.5,1.1,15.7c0.1,1-0.7,2.4,1,2.9V396z"/>
<path d="M39,638c3.4-2.4,4-2.5,7,0.5c3.4,3.4,6.5,7.1,9.6,10.7c1.4,1.6,2.6,3.4,4.1,4.9c3.1,3.2,6.2,6.5,9.6,9.5
c7.6,6.8,15.1,13.7,23.4,19.7c8.4,6.1,17,11.7,26.4,16.1c7.7,3.6,15.7,6.1,24.1,7.6c5.2,0.9,10.3,1.8,15.5,2.2
c2.7,0.2,5.5,0.7,8.3,0.8c7.2,0.1,14.4-0.9,21.5-1.8c7.6-1,15-2.8,22.2-5.3c12.4-4.3,24.1-10,34.5-18.3c4.5-3.6,9.1-7.1,13.1-11.3
c4.8-5,9.8-9.7,14.7-14.7c6.7-6.8,12.9-14.1,18.7-21.7c5.2-6.8,10.8-13.2,15.9-20.1c6.4-8.8,12.5-18,18.6-27.1
c6.6-9.9,13.2-19.9,19.5-30c4.6-7.3,8.9-14.9,13.3-22.3c3.9-6.6,8-13.1,11.8-19.8c3.5-6.1,6.9-12.3,10.3-18.4
c3.5-6.1,7-12.2,10.5-18.3c2-3.6,3.9-7.2,5.9-10.8c4.2-7.6,8.3-15.2,12.6-22.8c5.3-9.4,10.7-18.7,16-28.1c3.6-6.4,7-13,10.6-19.4
c5.6-9.8,11.4-19.5,17.1-29.2c3.8-6.5,7.5-13,11.3-19.5c3.3-5.6,6.6-11.3,10.2-16.7c8.2-12.4,16.4-24.8,24.8-37.1
c4.9-7.2,10-14.1,15.2-21c4.7-6.3,9.6-12.5,14.6-18.6c2.9-3.6,6.2-6.9,9.3-10.3c3.2-3.6,6.3-7.3,9.7-10.6
c7.8-7.6,15.9-14.8,24.4-21.7c7.3-5.9,15-11.1,22.7-16.4c2.8-1.9,5.9-3.4,8.9-5.1c7.4-4.1,15.1-7.9,23-10.9
c8.2-3.2,16.5-6,24.8-8.8c7.2-2.4,14.7-4,22.2-5.3c3.8-0.6,7.5-0.4,11.3-0.8c1.9-0.2,2.2,1.2,2.7,2.3c0.6,1.4,0.9,3-0.5,4.1
c-0.9,0.7-2,1.1-3,1.6c-14,7.2-27.3,15.5-39.7,25.1c-4.8,3.7-9.5,7.6-13.9,11.9c-2.5,2.4-5.4,4.4-7.8,6.9
c-5.6,6-11.1,12.2-16.5,18.4c-5.5,6.3-11,12.7-16.2,19.3c-5.2,6.5-10.3,13.2-15,20c-9.3,13.4-18.6,26.9-27.6,40.5
c-6,9.1-11.6,18.5-17.4,27.8c-5.2,8.3-10.4,16.6-15.5,25c-3.8,6.3-7.4,12.7-11.1,19.1c-5.9,10-12,19.9-17.8,29.9
c-4.1,6.9-7.9,13.9-12,20.8c-3.4,5.8-6.8,11.5-10.2,17.3c-2.9,4.9-5.8,9.9-8.8,14.7c-6.3,10.3-12.6,20.6-18.9,31
c-5.9,9.8-11.7,19.6-17.8,29.3c-5.7,9.1-11.7,18.1-17.7,27.1c-4.2,6.4-8.5,12.8-13,19.1c-6.5,9.2-13,18.4-19.6,27.6
c-5.3,7.3-10.5,14.6-15.9,21.7c-3.3,4.3-6.9,8.4-10.4,12.6c-4.4,5.3-8.7,10.7-13.1,16c-0.1,0.1-0.2,0.2-0.3,0.4
c-10.6,11-20.9,22.3-32.1,32.8c-6.3,5.9-13.5,10.8-21.3,14.8c-5.2,2.7-10.3,5.9-15.6,8.3c-12.4,5.7-25.2,10.5-38.5,13.6
c-5.9,1.3-11.8,2.3-17.7,3.2c-9.8,1.5-19.6,1-29.3,0.6c-8.2-0.4-16.4-2-24.4-4.2c-14.1-3.8-27.5-9.3-40.2-16.2
c-7.3-4-14.2-8.7-20.8-13.8c-5.4-4.1-10.2-9-15.4-13.1c-5.9-4.7-10.4-10.6-15.4-16.1c-6.9-7.6-13.1-15.9-18.4-24.8
c-0.1-0.2-0.5-0.3-0.8-0.5C39,640.7,39,639.3,39,638z"/>
<path d="M909.2,422c-0.4-5.7-0.4-11.6-1.3-17.2c-1.8-11.4-4-22.7-8.2-33.5c-5-12.5-12-23.9-20.3-34.6c-6-7.7-12.4-15.1-19.8-21.5
c-8.1-7.1-16.2-14.3-25.9-19.4c-4.9-2.6-9.5-5.8-14.5-8.2c-12.4-5.8-25.2-10.5-38.5-13.7c-5.8-1.4-11.7-2.6-17.5-4.1
c-1.2-0.3-3-0.4-3.2-2.5c-0.2-2.7,0-3.7,2.7-4.6c4.4-1.5,9-2.6,13.5-3.8c5.2-1.4,10.6-1.5,15.8-3c0.2,0,0.3,0,0.5,0
c6.9-0.3,13.9-1.5,20.7-0.8c6.9,0.7,13.9,0.9,20.8,2.5c6.6,1.5,13.3,2.9,19.7,5.4c11.8,4.5,22.9,10.3,33.1,18
c8.7,6.5,16.2,14.2,23.6,22c4.1,4.4,7.6,9.5,10.5,14.8c5.5,9.8,9.8,20.2,12.2,31.3c1,4.6,1.5,9.3,2.2,14c0.6,4.1,0.7,8.2,0.8,12.3
c0.1,7.6-1.3,14.9-2.8,22.3c-1.6,8.1-4.1,15.8-8.2,22.9c-2.6,4.5-5.5,8.8-8.5,13.2c-0.6,0.9-1.8,1.3-2.8,1.9
c-1.4,0.8-2.7,0.4-3.4-0.9c-0.7-1.4-1.2-3.1-1.3-4.6c-0.2-2.6-0.1-5.3-0.1-8C909.1,422.1,909.1,422.1,909.2,422z"/>
<path d="M754.9,685c-4.6,0-7.7,0.1-10.9,0c-6.4-0.3-12.9-0.1-19.2-1.1c-13.9-2.1-27.8-4.4-41.4-8.5c-9.8-3-19.6-6-29-9.8
c-10.5-4.2-20.6-9.2-30.7-14.3c-16.1-8.3-31.2-18.4-46.3-28.5c-3.4-2.3-6.5-5-9.8-7.5c-1.3-1-2.1-3.5-1.6-4.6
c0.7-1.4,4.2-2.2,5.8-1.2c3.2,1.9,6.5,3.8,9.7,5.8c6.1,3.6,12.1,7.3,18.2,10.7c8.4,4.7,16.9,9.4,25.5,13.7
c15.5,7.6,31.4,14.2,48,19.3c9.3,2.9,18.7,5.3,28.3,7.1c6.7,1.3,13.5,2.3,20.3,3.1c3.9,0.5,7.9,0.2,11.8,1
c8.1,1.6,16.2,0.7,24.3,0.8c6.7,0,13.5-0.2,20.2-1c7.3-0.9,14.6-1.7,21.8-3c8.4-1.6,16.6-4.1,25-6.2c10.6-2.6,20.7-6.7,30.7-11
c8.9-3.8,17.2-8.9,25.8-13.3c9.7-4.9,18.5-11.1,27.3-17.3c4.3-3,8.5-6,12.8-9c1.4-1,3.3-0.7,4.7,0.6c1.1,1.1,1.3,3.1,0.2,4.5
c-0.6,0.8-1.3,1.5-2.1,2.1c-4.9,3.9-9.7,7.8-14.6,11.6c-5.6,4.3-11.1,8.7-16.8,12.8c-7.9,5.6-16,10.7-24.5,15.3
c-10,5.5-20.5,10-31.1,14.1c-9.4,3.7-19.2,5.9-28.8,8.7c-4.3,1.2-9,1.3-13.5,2.2c-5.8,1.2-11.7,1.3-17.5,2.2
C769.4,685.4,761.5,684.4,754.9,685z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 13 13">
<path fill="#4A5579" fill-rule="evenodd" d="M.658 0L0 1.936l.43 2.053-.278.216.404.313-.308.238.41.368-.26.175.595.686-.881 2.78.83 2.798 2.975-.777 1.58 1.231h1.976l1.72-1.26 2.866.806.83-2.798h.003l-.885-2.78.594-.686-.26-.174.41-.368-.307-.239.404-.313-.278-.217.43-2.052L12.341 0 8.197 1.522H4.804L.658 0zm7.427 6.826l1.693.796-2.369.683.676-1.48zm-4.863.794l1.693-.794.676 1.479-2.37-.685zm2.276 2.274l.294-.17h1.416l.277.178.093 1.033H5.401l.097-1.041z"/>
</svg>

After

Width:  |  Height:  |  Size: 557 B

View File

@ -1,40 +0,0 @@
// @flow
import * as React from 'react'
import Img from '~/components/layout/Img'
import Span from '~/components/layout/Span'
import { upperFirst } from '~/utils/css'
const IconParity = require('~/components/Header/assets/icon_parity.svg')
const IconMetamask = require('~/components/Header/assets/icon_metamask.svg')
type Props = {
provider: string,
}
const PROVIDER_METAMASK = 'METAMASK'
const PROVIDER_PARITY = 'PARITY'
const PROVIDER_ICONS = {
[PROVIDER_METAMASK]: IconMetamask,
[PROVIDER_PARITY]: IconParity,
}
const Connected = ({ provider }: Props) => {
const msg = `You are using ${upperFirst(provider.toLowerCase())} to connect to your Safe`
return (
<React.Fragment>
{ PROVIDER_ICONS[provider] &&
<Img
height={40}
src={PROVIDER_ICONS[provider]}
title={msg}
alt={msg}
/>
}
<Span>Connected</Span>
</React.Fragment>
)
}
export default Connected

View File

@ -1,30 +1,77 @@
// @flow
import React from 'react'
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Grow from '@material-ui/core/Grow'
import ClickAwayListener from '@material-ui/core/ClickAwayListener'
import Popper from '@material-ui/core/Popper'
import List from '@material-ui/core/List'
import Divider from '~/components/layout/Divider'
import openHoc, { type Open } from '~/components/hoc/OpenHoc'
import Col from '~/components/layout/Col'
import Img from '~/components/layout/Img'
import Refresh from '~/components/Refresh'
import Row from '~/components/layout/Row'
import Spacer from '~/components/Spacer'
import { border, sm, md } from '~/theme/variables'
import Provider from './Provider'
import Connected from './Connected'
import NotConnected from './NotConnected'
const logo = require('../assets/gnosis-safe-logo.svg')
const logo = require('../assets/gnosis_logo.svg')
type Props = {
provider: string,
reloadWallet: Function,
type Props = Open & {
classes: Object,
providerDetails: React$Node,
providerInfo: React$Node,
}
const Header = ({ provider, reloadWallet }: Props) => (
<Row>
<Col xs={12} center="xs" sm={6} start="sm" margin="lg">
<Img src={logo} height={40} alt="Gnosis Safe" />
</Col>
<Col xs={12} center="xs" sm={6} end="sm" middle="xs" margin="lg">
{ provider ? <Connected provider={provider} /> : <NotConnected /> }
<Refresh callback={reloadWallet} />
</Col>
</Row>
)
const styles = () => ({
root: {
backgroundColor: 'white',
padding: 0,
boxShadow: '0 0 10px 0 rgba(33, 48, 77, 0.1)',
minWidth: '280px',
left: '4px',
},
summary: {
borderBottom: `solid 2px ${border}`,
alignItems: 'center',
height: '52px',
backgroundColor: 'white',
},
logo: {
padding: `${sm} ${md}`,
flexBasis: '95px',
},
})
export default Header
const Layout = openHoc(({
open, toggle, classes, providerInfo, providerDetails,
}: Props) => (
<React.Fragment>
<Row className={classes.summary}>
<Col start="xs" middle="xs" className={classes.logo}>
<Img src={logo} height={32} alt="Gnosis Team Safe" />
</Col>
<Divider />
<Spacer />
<Divider />
<Provider open={open} toggle={toggle} info={providerInfo}>
{providerRef => (
<Popper open={open} anchorEl={providerRef.current} placement="bottom-end">
{({ TransitionProps }) => (
<Grow
{...TransitionProps}
>
<ClickAwayListener onClickAway={toggle}>
<List className={classes.root} component="div">
{providerDetails}
</List>
</ClickAwayListener>
</Grow>
)}
</Popper>
)}
</Provider>
</Row>
</React.Fragment>
))
export default withStyles(styles)(Layout)

View File

@ -1,9 +1,12 @@
// @flow
import { select } from '@storybook/addon-knobs'
import { storiesOf } from '@storybook/react'
import * as React from 'react'
import styles from '~/components/layout/PageFrame/index.scss'
import Component from './Layout'
import Layout from './Layout'
import ProviderInfo from './ProviderInfo'
import ProviderDetails from './ProviderInfo/UserDetails'
import ProviderDisconnected from './ProviderDisconnected'
import ConnectDetails from './ProviderDisconnected/ConnectDetails'
const FrameDecorator = story => (
<div className={styles.frame}>
@ -11,10 +14,34 @@ const FrameDecorator = story => (
</div>
)
storiesOf('Components', module)
storiesOf('Components /Header', module)
.addDecorator(FrameDecorator)
.add('Header', () => {
// https://github.com/storybooks/storybook/tree/master/addons/knobs#select
const provider = select('Status by Provider', ['', 'UNKNOWN', 'METAMASK', 'PARITY'], 'METAMASK')
return <Component provider={provider} reloadWallet={() => {}} />
.add('Connected', () => {
const provider = 'Metamask'
const userAddress = '0x873faa4cddd5b157e8e5a57e7a5479afc5d30moe'
const network = 'RINKEBY'
const info = <ProviderInfo provider={provider} network={network} userAddress={userAddress} connected />
const details = <ProviderDetails provider={provider} network={network} userAddress={userAddress} connected />
return <Layout providerInfo={info} providerDetails={details} />
})
.add('Disconnected', () => {
const info = <ProviderDisconnected />
const details = <ConnectDetails />
return <Layout providerInfo={info} providerDetails={details} />
})
.add('Connection Error', () => {
const provider = 'Metamask'
const userAddress = '0x873faa4cddd5b157e8e5a57e7a5479afc5d30moe'
const network = 'RINKEBY'
const info = <ProviderInfo provider={provider} network={network} userAddress={userAddress} connected={false} />
const details = (<ProviderDetails
provider={provider}
network={network}
userAddress={userAddress}
connected={false}
/>)
return <Layout providerInfo={info} providerDetails={details} />
})

View File

@ -1,5 +0,0 @@
// @flow
import React from 'react'
import Span from '~/components/layout/Span'
export default () => <Span>Not Connected</Span>

View File

@ -0,0 +1,74 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import IconButton from '@material-ui/core/IconButton'
import ExpandLess from '@material-ui/icons/ExpandLess'
import ExpandMore from '@material-ui/icons/ExpandMore'
import Col from '~/components/layout/Col'
import { type Open } from '~/components/hoc/OpenHoc'
import { sm, md } from '~/theme/variables'
type Props = Open & {
classes: Object,
popupDetails: React$Node,
info: React$Node,
children: Function,
}
const styles = () => ({
root: {
height: '100%',
display: 'flex',
alignItems: 'center',
flexBasis: '250px',
},
provider: {
padding: `${sm} ${md}`,
alignItems: 'center',
flex: '1 1 auto',
display: 'flex',
cursor: 'pointer',
},
expand: {
width: '30px',
height: '30px',
},
})
type ProviderRef = { current: null | HTMLDivElement }
class Provider extends React.Component<Props> {
constructor(props: Props) {
super(props)
this.myRef = React.createRef()
}
myRef: ProviderRef
render() {
const {
open, toggle, children, classes, info,
} = this.props
return (
<React.Fragment>
<div ref={this.myRef} className={classes.root}>
<Col end="sm" middle="xs" className={classes.provider}>
{ info }
<IconButton
onClick={toggle}
disableRipple
className={classes.expand}
>
{ open ? <ExpandLess /> : <ExpandMore />}
</IconButton>
</Col>
</div>
{ children(this.myRef) }
</React.Fragment>
)
}
}
export default withStyles(styles)(Provider)

View File

@ -0,0 +1,64 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Paragraph from '~/components/layout/Paragraph'
import Button from '~/components/layout/Button'
import Img from '~/components/layout/Img'
import Row from '~/components/layout/Row'
import { md, lg } from '~/theme/variables'
const connectedLogo = require('../../assets/connect-wallet.svg')
type Props = {
classes: Object,
onConnect: Function,
}
const styles = () => ({
container: {
padding: `${md} 12px`,
},
logo: {
justifyContent: 'center',
},
text: {
letterSpacing: '-0.6px',
flexGrow: 1,
textAlign: 'center',
},
connect: {
padding: `${md} ${lg}`,
},
connectText: {
letterSpacing: '1px',
},
img: {
margin: '0px 2px',
},
})
const ConnectDetails = ({ classes, onConnect }: Props) => (
<React.Fragment>
<div className={classes.container}>
<Row margin="lg" align="center">
<Paragraph className={classes.text} size="lg" noMargin weight="bolder">Connect a Wallet</Paragraph>
</Row>
</div>
<Row className={classes.logo} margin="lg">
<Img className={classes.img} src={connectedLogo} height={75} alt="Connect a Wallet" />
</Row>
<Row className={classes.connect}>
<Button
onClick={onConnect}
size="medium"
variant="raised"
color="primary"
fullWidth
>
<Paragraph className={classes.connectText} size="sm" weight="regular" color="white" noMargin>CONNECT</Paragraph>
</Button>
</Row>
</React.Fragment>
)
export default withStyles(styles)(ConnectDetails)

View File

@ -0,0 +1,43 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Paragraph from '~/components/layout/Paragraph'
import Col from '~/components/layout/Col'
import Img from '~/components/layout/Img'
import { type Open } from '~/components/hoc/OpenHoc'
import { md } from '~/theme/variables'
const connectWallet = require('../../assets/connect-wallet.svg')
type Props = Open & {
classes: Object,
children: Function,
}
const styles = () => ({
network: {
fontFamily: 'Montserrat, sans-serif',
},
account: {
padding: `0 ${md}`,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
flexGrow: 1,
},
connect: {
letterSpacing: '-0.5px',
},
})
const ProviderDesconnected = ({ classes }: Props) => (
<React.Fragment>
<Img src={connectWallet} height={35} alt="Status connected" />
<Col end="sm" middle="xs" layout="column" className={classes.account}>
<Paragraph size="sm" transform="capitalize" className={classes.network} noMargin weight="bold">Not Connected</Paragraph>
<Paragraph size="sm" color="fancy" className={classes.connect} noMargin>Connect Wallet</Paragraph>
</Col>
</React.Fragment>
)
export default withStyles(styles)(ProviderDesconnected)

View File

@ -0,0 +1,151 @@
// @flow
import * as React from 'react'
import OpenInNew from '@material-ui/icons/OpenInNew'
import { withStyles } from '@material-ui/core/styles'
import Paragraph from '~/components/layout/Paragraph'
import Button from '~/components/layout/Button'
import Identicon from '~/components/Identicon'
import Bold from '~/components/layout/Bold'
import Hairline from '~/components/layout/Hairline'
import Img from '~/components/layout/Img'
import Row from '~/components/layout/Row'
import Block from '~/components/layout/Block'
import Spacer from '~/components/Spacer'
import { xs, sm, md, lg, background } from '~/theme/variables'
import { upperFirst } from '~/utils/css'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import { openInEtherScan } from '~/logic/wallets/getWeb3'
const metamask = require('../../assets/metamask.svg')
const connectedLogo = require('../../assets/connected.svg')
const connectedWarning = require('../../assets/connected-error.svg')
const dot = require('../../assets/dotRinkeby.svg')
type Props = {
provider: string,
connected: boolean,
network: string,
userAddress: string,
classes: Object,
onDisconnect: Function,
}
const openIconStyle = {
height: '16px',
color: '#467ee5',
}
const styles = () => ({
container: {
padding: `${md} 12px`,
display: 'flex',
flexDirection: 'column',
},
identicon: {
justifyContent: 'center',
padding: `0 ${md}`,
},
user: {
borderRadius: '3px',
backgroundColor: background,
margin: '0 auto',
padding: sm,
},
details: {
padding: `0 ${lg}`,
height: '20px',
alignItems: 'center',
},
address: {
flexGrow: 1,
textAlign: 'center',
letterSpacing: '-0.5px',
},
open: {
paddingLeft: sm,
width: 'auto',
'&:hover': {
cursor: 'pointer',
},
},
disconnect: {
padding: `${md} ${lg}`,
},
disconnectText: {
letterSpacing: '1px',
},
logo: {
margin: `0px ${xs}`,
},
})
const UserDetails = ({
provider, connected, network, userAddress, classes, onDisconnect,
}: Props) => {
const status = connected ? 'Connected' : 'Connection error'
const address = userAddress ? shortVersionOf(userAddress, 6) : 'Address not available'
const identiconAddress = userAddress || 'random'
const connectionLogo = connected ? connectedLogo : connectedWarning
const color = connected ? 'primary' : 'warning'
return (
<React.Fragment>
<Block className={classes.container}>
<Row className={classes.identicon} margin="md" align="center">
<Identicon address={identiconAddress} diameter={60} />
</Row>
<Block align="center" className={classes.user}>
<Paragraph className={classes.address} size="sm" noMargin>{address}</Paragraph>
{ userAddress &&
<OpenInNew className={classes.open} style={openIconStyle} onClick={openInEtherScan(userAddress, network)} />
}
</Block>
</Block>
<Hairline margin="xs" />
<Row className={classes.details}>
<Paragraph size="sm" noMargin align="right">Status </Paragraph>
<Spacer />
<Img className={classes.logo} src={connectionLogo} height={16} alt="Conection Status" />
<Paragraph size="sm" noMargin align="right" color={color}>
<Bold>
{status}
</Bold>
</Paragraph>
</Row>
<Hairline margin="xs" />
<Row className={classes.details}>
<Paragraph size="sm" noMargin align="right">Client </Paragraph>
<Spacer />
<Img className={classes.logo} src={metamask} height={16} alt="Metamask client" />
<Paragraph size="sm" noMargin align="right">
<Bold>
{upperFirst(provider)}
</Bold>
</Paragraph>
</Row>
<Hairline margin="xs" />
<Row className={classes.details}>
<Paragraph size="sm" noMargin align="right">Network </Paragraph>
<Spacer />
<Img className={classes.logo} src={dot} height={16} alt="Network" />
<Paragraph size="sm" noMargin align="right">
<Bold>{upperFirst(network)}</Bold>
</Paragraph>
</Row>
<Hairline margin="xs" />
<Row className={classes.disconnect}>
<Button
onClick={onDisconnect}
size="medium"
variant="raised"
color="primary"
fullWidth
>
<Paragraph className={classes.disconnectText} size="sm" weight="regular" color="white" noMargin>DISCONNECT</Paragraph>
</Button>
</Row>
</React.Fragment>
)
}
export default withStyles(styles)(UserDetails)

View File

@ -0,0 +1,64 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Paragraph from '~/components/layout/Paragraph'
import Col from '~/components/layout/Col'
import Img from '~/components/layout/Img'
import { sm } from '~/theme/variables'
import Identicon from '~/components/Identicon'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
const connectedLogo = require('../../assets/connected.svg')
const connectedWarning = require('../../assets/connected-error.svg')
type Props = {
provider: string,
network: string,
classes: Object,
userAddress: string,
connected: boolean,
}
const styles = () => ({
network: {
fontFamily: 'Montserrat, sans-serif',
},
logo: {
top: '10px',
position: 'relative',
right: '13px',
},
account: {
paddingRight: sm,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
flexGrow: 1,
},
address: {
letterSpacing: '-0.5px',
},
})
const ProviderInfo = ({
provider, network, userAddress, connected, classes,
}: Props) => {
const providerText = `${provider} [${network}]`
const cutAddress = connected ? shortVersionOf(userAddress, 6) : 'Connection Error'
const color = connected ? 'primary' : 'warning'
const logo = connected ? connectedLogo : connectedWarning
const identiconAddress = userAddress || 'random'
return (
<React.Fragment>
<Identicon address={identiconAddress} diameter={30} />
<Img className={classes.logo} src={logo} height={20} alt="Connection status" />
<Col end="sm" middle="xs" layout="column" className={classes.account}>
<Paragraph size="sm" transform="capitalize" className={classes.network} noMargin weight="bold">{providerText}</Paragraph>
<Paragraph size="sm" className={classes.address} noMargin color={color}>{cutAddress}</Paragraph>
</Col>
</React.Fragment>
)
}
export default withStyles(styles)(ProviderInfo)

View File

@ -1,29 +1,81 @@
// @flow
import * as React from 'react'
import { connect } from 'react-redux'
import { logComponentStack, type Info } from '~/utils/logBoundaries'
import ProviderInfo from './component/ProviderInfo'
import ProviderDetails from './component/ProviderInfo/UserDetails'
import ProviderDisconnected from './component/ProviderDisconnected'
import ConnectDetails from './component/ProviderDisconnected/ConnectDetails'
import Layout from './component/Layout'
import actions from './actions'
import selector from './selector'
import actions, { type Actions } from './actions'
import selector, { type SelectorProps } from './selector'
type Props = {
provider: string,
fetchProvider: Function,
type Props = Actions & SelectorProps
type State = {
hasError: boolean,
}
class Header extends React.PureComponent<Props> {
class Header extends React.PureComponent<Props, State> {
state = {
hasError: false,
}
componentDidMount() {
this.props.fetchProvider()
}
reloadWallet = () => {
componentDidCatch(error: Error, info: Info) {
this.setState({ hasError: true })
logComponentStack(error, info)
}
onDisconnect = () => {
this.props.removeProvider()
}
onConnect = () => {
this.props.fetchProvider()
}
getProviderInfoBased = () => {
const { hasError } = this.state
const {
loaded, available, provider, network, userAddress,
} = this.props
if (hasError || !loaded) {
return <ProviderDisconnected />
}
return <ProviderInfo provider={provider} network={network} userAddress={userAddress} connected={available} />
}
getProviderDetailsBased = () => {
const { hasError } = this.state
const {
loaded, available, provider, network, userAddress,
} = this.props
if (hasError || !loaded) {
return <ConnectDetails onConnect={this.onConnect} />
}
return (<ProviderDetails
provider={provider}
network={network}
userAddress={userAddress}
connected={available}
onDisconnect={this.onDisconnect}
/>)
}
render() {
const { provider } = this.props
return (
<Layout provider={provider} reloadWallet={this.reloadWallet} />
)
const info = this.getProviderInfoBased()
const details = this.getProviderDetailsBased()
return <Layout providerInfo={info} providerDetails={details} />
}
}

View File

@ -1,7 +1,19 @@
// @flow
import { createStructuredSelector } from 'reselect'
import { providerNameSelector } from '~/logic/wallets/store/selectors'
import { providerNameSelector, userAccountSelector, networkSelector, availableSelector, loadedSelector } from '~/logic/wallets/store/selectors'
export type SelectorProps = {
provider: string,
userAddress: string,
network: string,
loaded: boolean,
available: boolean,
}
export default createStructuredSelector({
provider: providerNameSelector,
userAddress: userAccountSelector,
network: networkSelector,
loaded: loadedSelector,
available: availableSelector,
})

View File

@ -0,0 +1,366 @@
/* eslint-disable */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.blockies = {})));
}(this, (function (exports) {
'use strict';
/**
* A handy class to calculate color values.
*
* @version 1.0
* @author Robert Eisele <robert@xarg.org>
* @copyright Copyright (c) 2010, Robert Eisele
* @link http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
*/
// helper functions for that ctx
function write(buffer, offs) {
for (var i = 2; i < arguments.length; i++) {
for (var j = 0; j < arguments[i].length; j++) {
buffer[offs++] = arguments[i].charAt(j);
}
}
}
function byte2(w) {
return String.fromCharCode((w >> 8) & 255, w & 255);
}
function byte4(w) {
return String.fromCharCode((w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w & 255);
}
function byte2lsb(w) {
return String.fromCharCode(w & 255, (w >> 8) & 255);
}
var PNG = function (width, height, depth) {
this.width = width;
this.height = height;
this.depth = depth;
// pixel data and row filter identifier size
this.pix_size = height * (width + 1);
// deflate header, pix_size, block headers, adler32 checksum
this.data_size = 2 + this.pix_size + 5 * Math.floor((0xfffe + this.pix_size) / 0xffff) + 4;
// offsets and sizes of Png chunks
this.ihdr_offs = 0; // IHDR offset and size
this.ihdr_size = 4 + 4 + 13 + 4;
this.plte_offs = this.ihdr_offs + this.ihdr_size; // PLTE offset and size
this.plte_size = 4 + 4 + 3 * depth + 4;
this.trns_offs = this.plte_offs + this.plte_size; // tRNS offset and size
this.trns_size = 4 + 4 + depth + 4;
this.idat_offs = this.trns_offs + this.trns_size; // IDAT offset and size
this.idat_size = 4 + 4 + this.data_size + 4;
this.iend_offs = this.idat_offs + this.idat_size; // IEND offset and size
this.iend_size = 4 + 4 + 4;
this.buffer_size = this.iend_offs + this.iend_size; // total PNG size
this.buffer = new Array();
this.palette = new Object();
this.pindex = 0;
var _crc32 = new Array();
// initialize buffer with zero bytes
for (var i = 0; i < this.buffer_size; i++) {
this.buffer[i] = "\x00";
}
// initialize non-zero elements
write(this.buffer, this.ihdr_offs, byte4(this.ihdr_size - 12), 'IHDR', byte4(width), byte4(height), "\x08\x03");
write(this.buffer, this.plte_offs, byte4(this.plte_size - 12), 'PLTE');
write(this.buffer, this.trns_offs, byte4(this.trns_size - 12), 'tRNS');
write(this.buffer, this.idat_offs, byte4(this.idat_size - 12), 'IDAT');
write(this.buffer, this.iend_offs, byte4(this.iend_size - 12), 'IEND');
// initialize deflate header
var header = ((8 + (7 << 4)) << 8) | (3 << 6);
header += 31 - (header % 31);
write(this.buffer, this.idat_offs + 8, byte2(header));
// initialize deflate block headers
for (var i = 0; (i << 16) - 1 < this.pix_size; i++) {
var size, bits;
if (i + 0xffff < this.pix_size) {
size = 0xffff;
bits = "\x00";
} else {
size = this.pix_size - (i << 16) - i;
bits = "\x01";
}
write(this.buffer, this.idat_offs + 8 + 2 + (i << 16) + (i << 2), bits, byte2lsb(size), byte2lsb(~size));
}
/* Create crc32 lookup table */
for (var i = 0; i < 256; i++) {
var c = i;
for (var j = 0; j < 8; j++) {
if (c & 1) {
c = -306674912 ^ ((c >> 1) & 0x7fffffff);
} else {
c = (c >> 1) & 0x7fffffff;
}
}
_crc32[i] = c;
}
// compute the index into a png for a given pixel
this.index = function (x, y) {
var i = y * (this.width + 1) + x + 1;
var j = this.idat_offs + 8 + 2 + 5 * Math.floor((i / 0xffff) + 1) + i;
return j;
};
// convert a color and build up the palette
this.color = function (red, green, blue, alpha) {
alpha = alpha >= 0 ? alpha : 255;
var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue;
if (typeof this.palette[color] == "undefined") {
if (this.pindex == this.depth) return "\x00";
var ndx = this.plte_offs + 8 + 3 * this.pindex;
this.buffer[ndx + 0] = String.fromCharCode(red);
this.buffer[ndx + 1] = String.fromCharCode(green);
this.buffer[ndx + 2] = String.fromCharCode(blue);
this.buffer[this.trns_offs + 8 + this.pindex] = String.fromCharCode(alpha);
this.palette[color] = String.fromCharCode(this.pindex++);
}
return this.palette[color];
};
// output a PNG string, Base64 encoded
this.getBase64 = function () {
var s = this.getDump();
var ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var c1, c2, c3, e1, e2, e3, e4;
var l = s.length;
var i = 0;
var r = "";
do {
c1 = s.charCodeAt(i);
e1 = c1 >> 2;
c2 = s.charCodeAt(i + 1);
e2 = ((c1 & 3) << 4) | (c2 >> 4);
c3 = s.charCodeAt(i + 2);
if (l < i + 2) { e3 = 64; } else { e3 = ((c2 & 0xf) << 2) | (c3 >> 6); }
if (l < i + 3) { e4 = 64; } else { e4 = c3 & 0x3f; }
r += ch.charAt(e1) + ch.charAt(e2) + ch.charAt(e3) + ch.charAt(e4);
} while ((i += 3) < l);
return r;
};
// output a PNG string
this.getDump = function () {
// compute adler32 of output pixels + row filter bytes
var BASE = 65521; /* largest prime smaller than 65536 */
var NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
var s1 = 1;
var s2 = 0;
var n = NMAX;
for (var y = 0; y < this.height; y++) {
for (var x = -1; x < this.width; x++) {
s1 += this.buffer[this.index(x, y)].charCodeAt(0);
s2 += s1;
if ((n -= 1) == 0) {
s1 %= BASE;
s2 %= BASE;
n = NMAX;
}
}
}
s1 %= BASE;
s2 %= BASE;
write(this.buffer, this.idat_offs + this.idat_size - 8, byte4((s2 << 16) | s1));
// compute crc32 of the PNG chunks
function crc32(png, offs, size) {
var crc = -1;
for (var i = 4; i < size - 4; i += 1) {
crc = _crc32[(crc ^ png[offs + i].charCodeAt(0)) & 0xff] ^ ((crc >> 8) & 0x00ffffff);
}
write(png, offs + size - 4, byte4(crc ^ -1));
}
crc32(this.buffer, this.ihdr_offs, this.ihdr_size);
crc32(this.buffer, this.plte_offs, this.plte_size);
crc32(this.buffer, this.trns_offs, this.trns_size);
crc32(this.buffer, this.idat_offs, this.idat_size);
crc32(this.buffer, this.iend_offs, this.iend_size);
// convert PNG to string
return "\x89PNG\r\n\x1A\n" + this.buffer.join('');
};
this.fillRect = function (x, y, w, h, color) {
for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) {
this.buffer[this.index(x + i, y + j)] = color;
}
}
};
};
// https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
/**
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param {number} h The hue
* @param {number} s The saturation
* @param {number} l The lightness
* @return {Array} The RGB representation
*/
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
function hsl2rgb(h, s, l) {
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), 255];
}
// The random number is a js implementation of the Xorshift PRNG
var randseed = new Array(4); // Xorshift: [x, y, z, w] 32 bit values
function seedrand(seed) {
for (var i = 0; i < randseed.length; i++) {
randseed[i] = 0;
}
for (var i = 0; i < seed.length; i++) {
randseed[i % 4] = (randseed[i % 4] << 5) - randseed[i % 4] + seed.charCodeAt(i);
}
}
function rand() {
// based on Java's String.hashCode(), expanded to 4 32bit values
var t = randseed[0] ^ (randseed[0] << 11);
randseed[0] = randseed[1];
randseed[1] = randseed[2];
randseed[2] = randseed[3];
randseed[3] = randseed[3] ^ (randseed[3] >> 19) ^ t ^ (t >> 8);
return (randseed[3] >>> 0) / (1 << 31 >>> 0);
}
function createColor() {
//saturation is the whole color spectrum
var h = Math.floor(rand() * 360);
//saturation goes from 40 to 100, it avoids greyish colors
var s = rand() * 60 + 40;
//lightness can be anything from 0 to 100, but probabilities are a bell curve around 50%
var l = (rand() + rand() + rand() + rand()) * 25;
return [h / 360, s / 100, l / 100];
}
function createImageData(size) {
var width = size; // Only support square icons for now
var height = size;
var dataWidth = Math.ceil(width / 2);
var mirrorWidth = width - dataWidth;
var data = [];
for (var y = 0; y < height; y++) {
var row = [];
for (var x = 0; x < dataWidth; x++) {
// this makes foreground and background color to have a 43% (1/2.3) probability
// spot color has 13% chance
row[x] = Math.floor(rand() * 2.3);
}
var r = row.slice(0, mirrorWidth);
r.reverse();
row = row.concat(r);
for (var i = 0; i < row.length; i++) {
data.push(row[i]);
}
}
return data;
}
function buildOpts(opts) {
if (!opts.seed) {
throw 'No seed provided'
}
seedrand(opts.seed);
return Object.assign({
size: 8,
scale: 16,
color: createColor(),
bgcolor: createColor(),
spotcolor: createColor(),
}, opts)
}
function toDataUrl(address) {
const opts = buildOpts({ seed: address.toLowerCase() });
const imageData = createImageData(opts.size);
const width = Math.sqrt(imageData.length);
const p = new PNG(opts.size * opts.scale, opts.size * opts.scale, 3);
const bgcolor = p.color(...hsl2rgb(...opts.bgcolor));
const color = p.color(...hsl2rgb(...opts.color));
const spotcolor = p.color(...hsl2rgb(...opts.spotcolor));
for (var i = 0; i < imageData.length; i++) {
var row = Math.floor(i / width);
var col = i % width;
// if data is 0, leave the background
if (imageData[i]) {
// if data is 2, choose spot color, if 1 choose foreground
const pngColor = imageData[i] == 1 ? color : spotcolor;
p.fillRect(col * opts.scale, row * opts.scale, opts.scale, opts.scale, pngColor);
}
}
return `data:image/png;base64,${p.getBase64()}`;
}
exports.toDataUrl = toDataUrl;
Object.defineProperty(exports, '__esModule', { value: true });
})));

View File

@ -0,0 +1,67 @@
// @flow
import * as React from 'react'
import { toDataUrl } from './blockies'
type Props = {
address: string,
diameter: number,
}
type IdenticonRef = { current: null | HTMLDivElement }
export default class Identicon extends React.PureComponent<Props> {
constructor(props: Props) {
super(props)
this.identicon = React.createRef()
}
componentDidMount = () => {
const { address, diameter } = this.props
const image = this.generateBlockieIdenticon(address, diameter)
if (this.identicon.current) {
this.identicon.current.appendChild(image)
}
}
componentDidUpdate = () => {
const { address, diameter } = this.props
const image = this.generateBlockieIdenticon(address, diameter)
if (!this.identicon.current) {
return
}
const { children } = this.identicon.current
for (let i = 0; i < children.length; i += 1) {
this.identicon.current.removeChild(children[i])
}
this.identicon.current.appendChild(image)
}
getStyleFrom = (diameter: number) => ({
width: diameter,
height: diameter,
})
generateBlockieIdenticon = (address: string, diameter: number) => {
const image = new window.Image()
image.src = toDataUrl(address)
image.height = diameter
image.width = diameter
image.style.borderRadius = `${diameter / 2}px`
return image
}
identicon: IdenticonRef
render() {
const style = this.getStyleFrom(this.props.diameter)
return (
<div style={style} ref={this.identicon} />
)
}
}

View File

@ -0,0 +1,8 @@
// @flow
import * as React from 'react'
const style = {
flexGrow: 1,
}
export default () => <div style={style} />

View File

@ -164,6 +164,7 @@ class GnoStepper extends React.PureComponent<Props, State> {
const styles = {
root: {
flex: '1 1 auto',
backgroundColor: 'transparent',
},
}

View File

@ -2,12 +2,11 @@
import classNames from 'classnames/bind'
import React, { PureComponent } from 'react'
import { capitalize } from '~/utils/css'
import { type Size } from '~/theme/size'
import styles from './index.scss'
const cx = classNames.bind(styles)
type Size = 'sm' | 'md' | 'lg' | 'xl'
type Props = {
margin?: Size,
padding?: Size,

View File

@ -1,6 +1,9 @@
.block {
width: 100%;
overflow: hidden;
}
.xs {
margin-bottom: $xs;
}
.sm {
@ -19,6 +22,10 @@
margin-bottom: $xl;
}
.paddingXs {
padding-top: $xs;
}
.paddingSm {
padding-top: $sm;
}

View File

@ -1,4 +1,26 @@
// @flow
import * as React from 'react'
import Button from '@material-ui/core/Button'
import { withStyles } from '@material-ui/core/styles'
export default Button
const styles = {
root: {
borderRadius: 0,
},
}
type Props = {
minWidth?: number
}
const calculateStyleBased = minWidth => ({
minWidth: `${minWidth}px`,
})
const GnoButton = ({ minWidth, ...props }: Props) => {
const style = minWidth ? calculateStyleBased(minWidth) : undefined
return <Button style={style} {...props} />
}
export default withStyles(styles)(GnoButton)

View File

@ -39,8 +39,8 @@ const Col = ({
}: Props) => {
const colClassNames = cx(
'col',
start ? capitalize(start, 'start') : undefined,
center ? capitalize(center, 'center') : undefined,
start ? capitalize(start, 'start') : undefined,
end ? capitalize(end, 'end') : undefined,
top ? capitalize(top, 'top') : undefined,
middle ? capitalize(middle, 'middle') : undefined,

View File

@ -0,0 +1,14 @@
// @flow
import * as React from 'react'
import { border } from '~/theme/variables'
const style = {
height: '100%',
border: `solid 1px ${border}`,
}
const Divider = () => (
<div style={style} />
)
export default Divider

View File

@ -1,15 +1,23 @@
// @flow
import * as React from 'react'
import { type Size, getSize } from '~/theme/size'
import { border } from '~/theme/variables'
const hairlineStyle = {
const calculateStyleFrom = (margin: Size) => ({
width: '100%',
height: '2px',
backgroundColor: '#d5d4d6',
margin: '20px 0px',
height: '1px',
backgroundColor: border,
margin: `${getSize(margin)} 0px`,
})
type Props = {
margin?: Size,
}
const Hairline = () => (
<div style={hairlineStyle} />
)
const Hairline = ({ margin = 'md' }: Props) => {
const style = calculateStyleFrom(margin)
return <div style={style} />
}
export default Hairline

View File

@ -10,7 +10,7 @@ type HeadingTag = 'h1' | 'h2' | 'h3' | 'h4';
type Props = {
align?: 'left' | 'center' | 'right',
margin?: 'sm' | 'md' | 'lg',
margin?: 'sm' | 'md' | 'lg' | 'xl',
tag: HeadingTag,
truncate?: boolean,
children: React$Node,

View File

@ -1,22 +1,31 @@
.heading {
font-weight: $boldFontWeight;
font-weight: normal;
line-height: normal;
margin: 0;
}
.h1 {
line-height: 36px;
font-weight: 500;
letter-spacing: -1px;
font-size: $(fontSizeHeadingLg)px;
}
.h2 {
line-height: 28px;
font-size: $(fontSizeHeadingMd)px;
}
.h3 {
line-height: 21px;
font-weight: bold;
font-family: 'Roboto Mono', monospace;
font-size: $(fontSizeHeadingSm)px;
}
.h4 {
line-height: 21px;
font-family: 'Roboto Mono', monospace;
font-size: $(fontSizeHeadingXs)px;
}
@ -45,3 +54,7 @@
.marginLg {
margin: 0 0 $lg 0;
}
.marginXl {
margin: 0 0 $xl 0;
}

View File

@ -1,7 +1,8 @@
.page {
display: flex;
flex-direction: column;
flex: 1 0 auto;
flex-direction: column;
padding: $xl;
}
.center {

View File

@ -1,7 +1,6 @@
.frame {
display: flex;
flex-direction: column;
flex: 1 0 auto;
background-color: white;
padding: $xl;
flex: 1 1 auto;
max-width: 100%;
}

View File

@ -8,20 +8,25 @@ const cx = classNames.bind(styles)
type Props = {
align?: 'right' | 'center' | 'left',
noMargin?: boolean,
bold?: boolean,
weight?: 'light' | 'regular' | 'bolder' | 'bold',
size?: 'sm' | 'md' | 'lg' | 'xl',
color?: 'soft' | 'medium' | 'dark' | 'primary',
children: React$Node
color?: 'soft' | 'medium' | 'dark' | 'white' | 'fancy' | 'primary' | 'warning',
transform?: 'capitalize' | 'lowercase' | 'uppercase',
children: React$Node,
className?: string,
}
class Paragraph extends React.PureComponent<Props> {
render() {
const {
bold, children, color, align, size, noMargin, ...props
weight, children, color, align, size, transform, noMargin, className, ...props
} = this.props
return (
<p className={cx(styles.paragraph, { bold }, { noMargin }, size, align)} {...props}>
<p
className={cx(styles.paragraph, className, weight, { noMargin }, size, color, transform, align)}
{...props}
>
{ children }
</p>
)

View File

@ -1,6 +1,6 @@
.paragraph {
text-overflow: ellipsis;
overflow-x: inherit;
overflow-x: inherit;
}
.soft {
@ -15,8 +15,31 @@
color: black;
}
.fancy {
color: $fancy;
}
.warning {
color: $warning;
}
.primary {
color: #00a6c4;
color: $fontColor;
}
.white {
color: white;
}
.capitalize {
text-transform: capitalize
}
.lowercase {
text-transform: lowercase
}
.uppercase {
text-transform: uppercase
}
.noMargin{
@ -47,10 +70,22 @@
font-size: $largeFontSize;
}
.lg {
.xl {
font-size: $extraLargeFontSize;
}
.light {
font-weight: $lightFont;
}
.regular {
font-weight: $regularFont;
}
.bolder {
font-weight: $bolderFont;
}
.bold {
font-weight: bold;
font-weight: $boldFont;
}

View File

@ -16,7 +16,7 @@
}
.marginLg {
margin-bottom: $xl;
margin-bottom: $lg;
}
.marginXl {

View File

@ -10,19 +10,16 @@ body {
left: 0;
right: 0;
overflow-x: hidden;
color: #1f5f76;
font-family: 'Montserrat', sans-serif;
color: $fontColor;
font-family: 'Roboto Mono', monospace;
font-size: $mediumFontSize;
margin: 0;
margin: 0;
background-color: $background;
}
body>div:first-child {
display: flex;
flex: 1 1 auto;
flex-direction: column;
min-height: calc(100% - (2 * $xl));
padding: $xl;
background-image: linear-gradient(to bottom, $primary, #1a829d, #1a829d, #1f5f76);
min-height: 100%;
}
h1, h2, h3 {

View File

@ -118,8 +118,14 @@ export const executeDailyLimit = async (
const gas = await calculateGasOf(dailyLimitData, sender, dailyLimitModule.address)
const gasPrice = await calculateGasPrice()
const txReceipt = await dailyLimitModule.executeDailyLimit(0, to, valueInWei, { from: sender, gas, gasPrice })
checkReceiptStatus(txReceipt.tx)
try {
const txReceipt = await dailyLimitModule.executeDailyLimit(0, to, valueInWei, { from: sender, gas, gasPrice })
await checkReceiptStatus(txReceipt.tx)
return Promise.resolve(txReceipt.tx)
} catch (err) {
return Promise.reject(new Error(err))
}
/*
// Temporarily disabled for daily limit operations
@ -128,5 +134,4 @@ export const executeDailyLimit = async (
await submitOperation(safeAddress, to, Number(valueInWei), data, operation, nonce, txReceipt.tx, sender, 'execution')
*/
return txReceipt.tx
}

View File

@ -10,3 +10,10 @@ export const sameAddress = (firstAddress: string, secondAddress: string): boolea
return firstAddress.toLowerCase() === secondAddress.toLowerCase()
}
export const shortVersionOf = (address: string, cut: number) => {
const initial = cut
const final = 42 - cut
return `${address.substring(0, initial)}...${address.substring(final)}`
}

View File

@ -9,7 +9,7 @@ export const EMPTY_DATA = '0x'
export const checkReceiptStatus = async (hash: string) => {
if (!hash) {
throw new Error('No valid Tx hash to get receipt from')
return Promise.reject(new Error('No valid Tx hash to get receipt from'))
}
const web3 = getWeb3()
@ -17,13 +17,15 @@ export const checkReceiptStatus = async (hash: string) => {
const { status } = txReceipt
if (!status) {
throw new Error('No status found on this transaction receipt')
return Promise.reject(new Error('No status found on this transaction receipt'))
}
const hasError = status === '0x0'
if (hasError) {
throw new Error('Obtained a transaction failure in the receipt')
return Promise.reject(new Error('Obtained a transaction failure in the receipt'))
}
return Promise.resolve()
}
export const calculateGasPrice = async () => {
@ -50,7 +52,11 @@ export const calculateGasPrice = async () => {
export const calculateGasOf = async (data: Object, from: string, to: string) => {
const web3 = getWeb3()
const gas = await promisify(cb => web3.eth.estimateGas({ data, from, to }, cb))
try {
const gas = await promisify(cb => web3.eth.estimateGas({ data, from, to }, cb))
return gas * 2
return gas * 2
} catch (err) {
return Promise.reject(new Error(err))
}
}

View File

@ -4,6 +4,39 @@ import Web3 from 'web3'
import type { ProviderProps } from '~/logic/wallets/store/model/provider'
import { promisify } from '~/utils/promisify'
export const ETHEREUM_NETWORK = {
MAIN: 'MAIN',
MORDEN: 'MORDEN',
ROPSTEN: 'ROPSTEN',
RINKEBY: 'RINKEBY',
KOVAN: 'KOVAN',
UNKNOWN: 'UNKNOWN',
}
export const WALLET_PROVIDER = {
METAMASK: 'METAMASK',
PARITY: 'PARITY',
REMOTE: 'REMOTE',
UPORT: 'UPORT',
}
export const ETHEREUM_NETWORK_IDS = {
// $FlowFixMe
1: ETHEREUM_NETWORK.MAIN,
// $FlowFixMe
2: ETHEREUM_NETWORK.MORDEN,
// $FlowFixMe
3: ETHEREUM_NETWORK.ROPSTEN,
// $FlowFixMe
4: ETHEREUM_NETWORK.RINKEBY,
// $FlowFixMe
42: ETHEREUM_NETWORK.KOVAN,
}
export const openInEtherScan = (address: string, network: string) => () => {
window.open(`https://${network}.etherscan.io/address/${address}`)
}
let web3
export const getWeb3 = () => web3 || new Web3(window.web3.currentProvider)
@ -19,10 +52,16 @@ const getAccountFrom: Function = async (web3Provider): Promise<string | null> =>
return accounts && accounts.length > 0 ? accounts[0] : null
}
const getNetworkIdFrom = async (web3Provider) => {
const networkId = await promisify(cb => web3Provider.version.getNetwork(cb))
return networkId
}
export const getProviderInfo: Function = async (): Promise<ProviderProps> => {
if (typeof window.web3 === 'undefined') {
return {
name: '', available: false, loaded: false, account: '',
name: '', available: false, loaded: false, account: '', network: 0,
}
}
@ -34,8 +73,10 @@ export const getProviderInfo: Function = async (): Promise<ProviderProps> => {
console.log('Injected web3 detected.')
}
const name = isMetamask(web3) ? 'METAMASK' : 'UNKNOWN'
const name = isMetamask(web3) ? WALLET_PROVIDER.METAMASK : 'UNKNOWN'
const account = await getAccountFrom(web3)
const network = await getNetworkIdFrom(web3)
const available = account !== null
return {
@ -43,6 +84,7 @@ export const getProviderInfo: Function = async (): Promise<ProviderProps> => {
available,
loaded: true,
account,
network,
}
}

View File

@ -7,11 +7,11 @@ import addProvider from './addProvider'
export const processProviderResponse = (dispatch: ReduxDispatch<*>, response: ProviderProps) => {
const {
name, available, loaded, account,
name, available, loaded, account, network,
} = response
const walletRecord = makeProvider({
name, available, loaded, account,
name, available, loaded, account, network,
})
dispatch(addProvider(walletRecord))

View File

@ -3,3 +3,4 @@ export * from './addProvider'
export * from './fetchProvider'
export { default as addProvider } from './addProvider'
export { default as fetchProvider } from './fetchProvider'
export { default as removeProvider } from './removeProvider'

View File

@ -0,0 +1,17 @@
// @flow
import type { Dispatch as ReduxDispatch } from 'redux'
import { makeProvider, type ProviderProps, type Provider } from '~/logic/wallets/store/model/provider'
import addProvider from './addProvider'
export default () => async (dispatch: ReduxDispatch<*>) => {
const providerProps: ProviderProps = {
name: '',
available: false,
loaded: false,
account: '',
network: 0,
}
const provider: Provider = makeProvider(providerProps)
dispatch(addProvider(provider))
}

View File

@ -7,6 +7,7 @@ export type ProviderProps = {
loaded: boolean,
available: boolean,
account: string,
network: number,
}
export const makeProvider: RecordFactory<ProviderProps> = Record({
@ -14,6 +15,7 @@ export const makeProvider: RecordFactory<ProviderProps> = Record({
loaded: false,
available: false,
account: '',
network: 0,
})
export type Provider = RecordOf<ProviderProps>

View File

@ -2,6 +2,7 @@
import { createSelector } from 'reselect'
import type { Provider } from '~/logic/wallets/store/model/provider'
import { PROVIDER_REDUCER_ID } from '~/logic/wallets/store/reducer/provider'
import { ETHEREUM_NETWORK_IDS, ETHEREUM_NETWORK } from '~/logic/wallets/getWeb3'
const providerSelector = (state: any): Provider => state[PROVIDER_REDUCER_ID]
@ -18,9 +19,27 @@ export const providerNameSelector = createSelector(
providerSelector,
(provider: Provider) => {
const name = provider.get('name')
const loaded = provider.get('loaded')
const available = provider.get('available')
return loaded && available ? name : undefined
return name ? name.toLowerCase() : undefined
},
)
export const networkSelector = createSelector(
providerSelector,
(provider: Provider) => {
const networkId = provider.get('network')
const network = ETHEREUM_NETWORK_IDS[networkId] || ETHEREUM_NETWORK.UNKNOWN
return network
},
)
export const loadedSelector = createSelector(
providerSelector,
(provider: Provider) => provider.get('loaded'),
)
export const availableSelector = createSelector(
providerSelector,
(provider: Provider) => provider.get('available'),
)

View File

@ -16,7 +16,7 @@ const providerReducerTests = () => {
expect(providerName).toEqual(undefined)
})
it('should return undefined when Metamask is loaded but not available', () => {
it('should return metamask when Metamask is loaded but not available', () => {
// GIVEN
const reduxStore = { [PROVIDER_REDUCER_ID]: ProviderFactory.metamaskLoaded }
@ -24,7 +24,7 @@ const providerReducerTests = () => {
const providerName = providerNameSelector(reduxStore)
// THEN
expect(providerName).toEqual(undefined)
expect(providerName).toEqual('metamask')
})
it('should return METAMASK when Metamask is loaded and available', () => {
@ -35,7 +35,7 @@ const providerReducerTests = () => {
const providerName = providerNameSelector(reduxStore)
// THEN
expect(providerName).toEqual('METAMASK')
expect(providerName).toEqual('metamask')
})
})
}

View File

@ -25,7 +25,7 @@ const providerReducerTests = () => {
it('reducer should return default Provider record when no Metamask is loaded', () => {
// GIVEN
const emptyResponse: ProviderProps = {
name: '', loaded: false, available: false, account: '',
name: '', loaded: false, available: false, account: '', network: 0,
}
// WHEN
@ -39,7 +39,7 @@ const providerReducerTests = () => {
it('reducer should return avaiable with its default value when is loaded but not available', () => {
// GIVEN
const metamaskLoaded: ProviderProps = {
name: 'METAMASK', loaded: true, available: false, account: '',
name: 'METAMASK', loaded: true, available: false, account: '', network: 0,
}
// WHEN
@ -53,7 +53,7 @@ const providerReducerTests = () => {
it('reducer should return metamask provider when it is loaded and available', () => {
// GIVEN
const metamask: ProviderProps = {
name: 'METAMASK', loaded: true, available: true, account: '',
name: 'METAMASK', loaded: true, available: true, account: '', network: 0,
}
// WHEN

View File

@ -54,7 +54,7 @@ const Owners = (props: Props) => {
<Row key={`owner${(index)}`}>
<Col xs={11} xsOffset={1}>
<Block margin="sm">
<Paragraph bold>Owner {index + 1}</Paragraph>
<Paragraph weight="bold">Owner {index + 1}</Paragraph>
<Block margin="sm">
<Field
name={getOwnerNameBy(index)}

View File

@ -32,7 +32,7 @@ type Props = Open & SelectorProps & {
export const PROCESS_TXS = 'PROCESS TRANSACTION'
class GnoTransaction extends React.PureComponent<Props, {}> {
class GnoTransaction extends React.PureComponent<Props> {
onProccesClick = () => this.props.onProcessTx(this.props.transaction, this.props.confirmed)
hasConfirmed = (userAddress: string, confirmations: List<Confirmation>): boolean =>
@ -102,10 +102,10 @@ class GnoTransaction extends React.PureComponent<Props, {}> {
destination={transaction.get('destination')}
threshold={threshold}
/> }
<Hairline />
<Hairline margin="md" />
</React.Fragment>
)
}
}
export default connect(selector)(openHoc(GnoTransaction))
export default openHoc(connect(selector)(GnoTransaction))

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
<path fill="#FFF" fill-rule="nonzero" d="M14 8H8v6H6V8H0V6h6V0h2v6h6z"/>
</svg>

After

Width:  |  Height:  |  Size: 168 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="13" viewBox="0 0 16 13">
<path fill="#65707E" fill-rule="nonzero" d="M1.6 0A1.6 1.6 0 0 0 0 1.6v8.8A1.6 1.6 0 0 0 1.6 12v.8h1.6V12H12v.8h1.6V12a1.6 1.6 0 0 0 1.6-1.6v-.8h.8V8h-.8V4h.8V2.4h-.8v-.8A1.6 1.6 0 0 0 13.6 0h-12zm0 1.6h12v8.8h-12V1.6zm7.6 1.2a3.2 3.2 0 1 0 0 6.4 3.2 3.2 0 0 0 0-6.4zM2.4 4v4H4V4H2.4zm6.8.4a1.6 1.6 0 1 1 0 3.2 1.6 1.6 0 0 1 0-3.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 430 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1,13 +1,16 @@
// @flow
import * as React from 'react'
import Block from '~/components/layout/Block'
import Heading from '~/components/layout/Heading'
import Img from '~/components/layout/Img'
import Button from '~/components/layout/Button'
import Link from '~/components/layout/Link'
import { OPEN_ADDRESS } from '~/routes/routes'
import { sm } from '~/theme/variables'
import styles from './Layout.scss'
const vault = require('../assets/vault.svg')
const safe = require('../assets/safe.svg')
const plus = require('../assets/new.svg')
type Props = {
provider: string
@ -15,26 +18,63 @@ type Props = {
type SafeProps = {
provider: string,
size?: 'small' | 'medium',
size?: 'small' | 'medium' | 'large',
}
const buttonStyle = {
marginLeft: sm,
}
export const CreateSafe = ({ size, provider }: SafeProps) => (
<Button
component={Link}
to={OPEN_ADDRESS}
variant="raised"
size={size || 'medium'}
color="primary"
disabled={!provider}
minWidth={240}
>
<Link to={OPEN_ADDRESS} color="white">Create a new Safe</Link>
<Img src={plus} height={16} alt="Safe" />
<div style={buttonStyle}>Create new Safe</div>
</Button>
)
export const LoadSafe = ({ size, provider }: SafeProps) => (
<Button
component={Link}
to={OPEN_ADDRESS}
variant="outlined"
size={size || 'medium'}
color="primary"
disabled={!provider}
minWidth={240}
>
<Img src={safe} height={16} alt="Safe" />
<div style={buttonStyle}>Load existing Safe</div>
</Button>
)
const Welcome = ({ provider }: Props) => (
<Block className={styles.safe}>
<Img alt="Safe Box" src={vault} height={330} />
<Heading tag="h1" align="center">
Welcome to the Gnosis
</Heading>
<Heading tag="h1" align="center" margin="lg">
Safe Team Edition
</Heading>
<Heading tag="h4" align="center" margin="xl">
The Gnosis Safe Team Edition is geared towards teams managing <br />
shared crypto funds. It is an improvement of the existing Gnosis <br />
MultiSig wallet with redesigned smart contracts, cheaper setup and <br />
transaction costs as well as an enhanced user experience.
</Heading>
<Block className={styles.safeActions} margin="md">
<CreateSafe provider={provider} />
<CreateSafe size="large" provider={provider} />
</Block>
<Block className={styles.safeActions} margin="md">
<LoadSafe size="large" provider={provider} />
</Block>
</Block>
)

View File

@ -1,18 +1,15 @@
.safe {
display: grid;
justify-content: center;
grid-row-gap: $xl;
justify-items: center;
margin-top: $xl;
}
.safeActions {
.summary {
display: flex;
justify-content: space-around;
}
@media(max-width: $(screenXsMax)px) {
.safeActions {
grid-row-gap: $md;
display: grid;
justify-items: center;
}
.safeActions {
display: flex;
justify-content: center;
}

View File

@ -28,6 +28,6 @@ describe('Safe Blockchain Test', () => {
await executeWithdrawOn(safe, value)
// THEN
expect(executeWithdrawOn(safe, value)).rejects.toThrow('VM Exception while processing transaction: revert')
expect(executeWithdrawOn(safe, value)).rejects.toThrow('VM Exception while processing transaction: revert Daily limit has been reached')
})
})

View File

@ -1,7 +1,7 @@
// @flow
import red from '@material-ui/core/colors/red'
import { createMuiTheme } from '@material-ui/core/styles'
import { primary, secondary } from './variables'
import { mediumFontSize, primary, secondary, md, lg } from './variables'
export type WithStyles = {
classes: Object,
@ -25,5 +25,21 @@ export default createMuiTheme({
typography: {
fontFamily: 'Montserrat,sans-serif',
},
overrides: {
MuiButton: {
root: {
fontFamily: 'Roboto Mono, monospace',
letterSpacing: '1px',
},
containedPrimary: {
backgroundColor: '#467ee5',
},
sizeLarge: {
padding: `${md} ${lg}`,
minHeight: '52px',
fontSize: mediumFontSize,
},
},
},
palette,
})

21
src/theme/size.js Normal file
View File

@ -0,0 +1,21 @@
// @flow
import { xs, sm, md, lg, xl } from '~/theme/variables'
export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
export const getSize = (size: Size) => {
switch (size) {
case 'xs':
return xs
case 'sm':
return sm
case 'md':
return md
case 'lg':
return lg
case 'xl':
return xl
default:
return md
}
}

View File

@ -1,31 +1,45 @@
// @flow
const primary = '#1798cc'
const border = '#eaebef'
const background = '#f4f4f9'
const primary = '#4a5579'
const secondary = '#13222b'
const tertiary = '#f6f9fc'
const fontColor = '#4a5579'
const fancyColor = '#fd7890'
const warningColor = '#c97c05'
const xs = '4px'
const sm = '8px'
const md = '16px'
const lg = '24px'
const xl = '42px'
const xl = '32px'
const xxl = '40px'
module.exports = Object.assign({}, {
primary,
secondary,
tertiary,
background,
fontColor,
fancy: fancyColor,
warning: warningColor,
xs,
sm,
md,
lg,
xl,
fontSizeHeadingXs: 16,
xxl,
border,
fontSizeHeadingXs: 13,
fontSizeHeadingSm: 18,
fontSizeHeadingMd: 21,
fontSizeHeadingLg: 28,
regularFontWeight: 400,
boldFontWeight: 700,
smallFontSize: '12px',
mediumFontSize: '14px',
largeFontSize: '18px',
fontSizeHeadingLg: 32,
lightFont: 300,
regularFont: 400,
bolderFont: 500,
boldFont: 700,
smallFontSize: '11px',
mediumFontSize: '13px',
largeFontSize: '15px',
extraLargeFontSize: '24px',
screenXs: 480,
screenXsMax: 767,

View File

@ -1,5 +1,5 @@
// @flow
export const upperFirst = (value: string) => value.charAt(0).toUpperCase() + value.slice(1)
export const upperFirst = (value: string) => value.charAt(0).toUpperCase() + value.toLowerCase().slice(1)
type Value = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'center' | 'end' | 'start' | number | boolean

View File

@ -0,0 +1,12 @@
// @flow
export type Info = {
componentStack: string,
}
export const logComponentStack = (error: Error, info: Info) => {
// eslint-disable-next-line
console.log(error)
// eslint-disable-next-line
console.log(info.componentStack)
}

111
yarn.lock
View File

@ -860,12 +860,17 @@
"@babel/plugin-syntax-dynamic-import" "7.0.0-beta.51"
"@babel/plugin-syntax-import-meta" "7.0.0-beta.51"
"@babel/runtime@^7.0.0-beta.42":
version "7.0.0-beta.51"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.51.tgz#48b8ed18307034c6620f643514650ca2ccc0165a"
"@babel/runtime@7.0.0", "@babel/runtime@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c"
dependencies:
core-js "^2.5.7"
regenerator-runtime "^0.11.1"
regenerator-runtime "^0.12.0"
"@babel/runtime@7.0.0-rc.1":
version "7.0.0-rc.1"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-rc.1.tgz#42f36fc5817911c89ea75da2b874054922967616"
dependencies:
regenerator-runtime "^0.12.0"
"@babel/template@7.0.0-beta.44":
version "7.0.0-beta.44"
@ -935,11 +940,11 @@
version "0.2.14"
resolved "https://registry.yarnpkg.com/@gnosis.pm/util-contracts/-/util-contracts-0.2.14.tgz#587cd6268a7d08dbc0d08b1c7bd375e19549d833"
"@material-ui/core@^1.2.1":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-1.2.2.tgz#b074bdaa679d68af235b4d3f108f828ddcf6c1bc"
"@material-ui/core@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-3.0.1.tgz#e8476394a42d89ae404355ddbc093db4d044b225"
dependencies:
"@babel/runtime" "^7.0.0-beta.42"
"@babel/runtime" "7.0.0"
"@types/jss" "^9.5.3"
"@types/react-transition-group" "^2.0.8"
brcast "^3.0.1"
@ -949,6 +954,7 @@
deepmerge "^2.0.1"
dom-helpers "^3.2.1"
hoist-non-react-statics "^2.5.0"
is-plain-object "^2.0.4"
jss "^9.3.3"
jss-camel-case "^6.0.0"
jss-default-unit "^8.0.2"
@ -958,20 +964,20 @@
jss-vendor-prefixer "^7.0.0"
keycode "^2.1.9"
normalize-scroll-left "^0.1.2"
popper.js "^1.14.1"
prop-types "^15.6.0"
react-event-listener "^0.6.0"
react-event-listener "^0.6.2"
react-jss "^8.1.0"
react-popper "^1.0.0"
react-transition-group "^2.2.1"
recompose "^0.27.0"
scroll "^2.0.3"
recompose "^0.29.0"
warning "^4.0.1"
"@material-ui/icons@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-1.1.0.tgz#4d025df7b0ba6ace8d6710079ed76013a4d26595"
"@material-ui/icons@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-3.0.1.tgz#671fb3d04dcaf9351dbbd2bf82ae2ae72e3d93cd"
dependencies:
recompose "^0.26.0 || ^0.27.0"
"@babel/runtime" "7.0.0"
recompose "^0.29.0"
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
@ -3963,13 +3969,6 @@ create-react-class@^15.5.2, create-react-class@^15.6.0, create-react-class@^15.6
loose-envify "^1.3.1"
object-assign "^4.1.1"
create-react-context@^0.2.1:
version "0.2.2"
resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.2.tgz#9836542f9aaa22868cd7d4a6f82667df38019dca"
dependencies:
fbjs "^0.8.0"
gud "^1.0.0"
cross-spawn@5.1.0, cross-spawn@^5.0.1, cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@ -5370,7 +5369,7 @@ fb-watchman@^2.0.0:
dependencies:
bser "^2.0.0"
fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.12, fbjs@^0.8.16, fbjs@^0.8.9:
fbjs@^0.8.1, fbjs@^0.8.12, fbjs@^0.8.16, fbjs@^0.8.9:
version "0.8.17"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
dependencies:
@ -5519,9 +5518,9 @@ flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
flow-bin@^0.66.0:
version "0.66.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.66.0.tgz#a96dde7015dc3343fd552a7b4963c02be705ca26"
flow-bin@^0.79.1:
version "0.79.1"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.79.1.tgz#01c9f427baa6556753fa878c192d42e1ecb764b6"
flow-parser@^0.*:
version "0.74.0"
@ -5968,10 +5967,6 @@ growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
gud@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
gzip-size@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520"
@ -9670,12 +9665,6 @@ radium@^0.19.0, radium@^0.19.4:
inline-style-prefixer "^2.0.5"
prop-types "^15.5.8"
rafl@~1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/rafl/-/rafl-1.2.2.tgz#fe930f758211020d47e38815f5196a8be4150740"
dependencies:
global "~4.3.0"
ramda@^0.24.1:
version "0.24.1"
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857"
@ -9790,11 +9779,11 @@ react-error-overlay@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"
react-event-listener@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.1.tgz#41c7a80a66b398c27dd511e22712b02f3d4eccca"
react-event-listener@^0.6.2:
version "0.6.3"
resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.3.tgz#8eab88129a76e095ed8aa684c29679eded1e843d"
dependencies:
"@babel/runtime" "^7.0.0-beta.42"
"@babel/runtime" "7.0.0-rc.1"
prop-types "^15.6.0"
warning "^4.0.1"
@ -9867,17 +9856,6 @@ react-onclickoutside@^6.5.0:
version "6.7.1"
resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.7.1.tgz#6a5b5b8b4eae6b776259712c89c8a2b36b17be93"
react-popper@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.0.0.tgz#b99452144e8fe4acc77fa3d959a8c79e07a65084"
dependencies:
babel-runtime "6.x.x"
create-react-context "^0.2.1"
popper.js "^1.14.1"
prop-types "^15.6.1"
typed-styles "^0.0.5"
warning "^3.0.0"
react-redux@^5.0.7:
version "5.0.7"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8"
@ -10132,7 +10110,7 @@ rechoir@^0.6.2:
dependencies:
resolve "^1.1.6"
"recompose@^0.26.0 || ^0.27.0", recompose@^0.27.0, recompose@^0.27.1:
recompose@^0.27.1:
version "0.27.1"
resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.27.1.tgz#1a49e931f183634516633bbb4f4edbfd3f38a7ba"
dependencies:
@ -10143,6 +10121,17 @@ rechoir@^0.6.2:
react-lifecycles-compat "^3.0.2"
symbol-observable "^1.0.4"
recompose@^0.29.0:
version "0.29.0"
resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.29.0.tgz#f1a4e20d5f24d6ef1440f83924e821de0b1bccef"
dependencies:
"@babel/runtime" "^7.0.0"
change-emitter "^0.1.2"
fbjs "^0.8.1"
hoist-non-react-statics "^2.3.1"
react-lifecycles-compat "^3.0.2"
symbol-observable "^1.0.4"
recursive-readdir@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.1.tgz#90ef231d0778c5ce093c9a48d74e5c5422d13a99"
@ -10214,6 +10203,10 @@ regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
regenerator-runtime@^0.12.0:
version "0.12.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
regenerator-transform@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
@ -10655,12 +10648,6 @@ scoped-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
scroll@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/scroll/-/scroll-2.0.3.tgz#0951b785544205fd17753bc3d294738ba16fc2ab"
dependencies:
rafl "~1.2.1"
scrypt.js@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.2.0.tgz#af8d1465b71e9990110bedfc593b9479e03a8ada"
@ -11820,10 +11807,6 @@ type-is@~1.6.15, type-is@~1.6.16:
media-typer "0.3.0"
mime-types "~2.1.18"
typed-styles@^0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.5.tgz#a60df245d482a9b1adf9c06c078d0f06085ed1cf"
typedarray@^0.0.6, typedarray@~0.0.5:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"