Merge pull request #67 from gnosis/feature/provider-ui-design-improvements
Feature: Design Welcome route including Header's Provider
|
@ -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">
|
|
@ -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",
|
||||
|
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 99 KiB |
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -11,6 +11,6 @@ const FrameDecorator = story => (
|
|||
</div>
|
||||
)
|
||||
|
||||
storiesOf('Components', module)
|
||||
storiesOf('Components /Footer', module)
|
||||
.addDecorator(FrameDecorator)
|
||||
.add('Footer', () => <Component />)
|
||||
.add('Loaded', () => <Component />)
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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} />
|
||||
})
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
// @flow
|
||||
import React from 'react'
|
||||
import Span from '~/components/layout/Span'
|
||||
|
||||
export default () => <Span>Not Connected</Span>
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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} />
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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 });
|
||||
|
||||
})));
|
|
@ -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} />
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
|
||||
const style = {
|
||||
flexGrow: 1,
|
||||
}
|
||||
|
||||
export default () => <div style={style} />
|
|
@ -164,6 +164,7 @@ class GnoStepper extends React.PureComponent<Props, State> {
|
|||
const styles = {
|
||||
root: {
|
||||
flex: '1 1 auto',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
flex-direction: column;
|
||||
padding: $xl;
|
||||
}
|
||||
|
||||
.center {
|
||||
|
|
|
@ -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%;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
}
|
||||
|
||||
.marginLg {
|
||||
margin-bottom: $xl;
|
||||
margin-bottom: $lg;
|
||||
}
|
||||
|
||||
.marginXl {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)}`
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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'),
|
||||
)
|
||||
|
|
|
@ -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')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -54,7 +54,7 @@ const Owners = (props: Props) => {
|
|||
<Row key={`owner${(index)}`}>
|
||||
<Col xs={11} xsOffset={1}>
|
||||
<Block margin="sm">
|
||||
<Paragraph bold>Owner Nº {index + 1}</Paragraph>
|
||||
<Paragraph weight="bold">Owner Nº {index + 1}</Paragraph>
|
||||
<Block margin="sm">
|
||||
<Field
|
||||
name={getOwnerNameBy(index)}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 |
|
@ -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 |
Before Width: | Height: | Size: 32 KiB |
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
@ -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"
|
||||
|
|