New Homepage (#7266)

* Purify dappCard style

* Add support for pinning apps

* Add a section to show pinned apps

* Cleaner code

* Bump dependency versions

* Small tweaks

* Avoid double scrollbars

* Small style updates

* Bump parity/shared version
This commit is contained in:
Amaury Martiny 2017-12-12 17:35:21 +01:00 committed by Jaco Greeff
parent c731b5ef62
commit 1851453f00
11 changed files with 201 additions and 168 deletions

32
js/package-lock.json generated
View File

@ -15,9 +15,9 @@
} }
}, },
"@parity/api": { "@parity/api": {
"version": "2.1.5", "version": "2.1.6",
"resolved": "https://registry.npmjs.org/@parity/api/-/api-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@parity/api/-/api-2.1.6.tgz",
"integrity": "sha512-HkvMIhIwDMEIyTmXqEjWn1C2qes0qJO270bQldRfCZf0XiOGXG726EzV3FUpUbVONCVQ9riDviAl3fw6D+N6nA==", "integrity": "sha512-4HuUJLGkZEAHSy5918ofepKXWvAE89VsoUN7q1Px9ASN8xLR3MWPMuNxOJZjKTqVDZWpXs8q3g7GIOVdi90BXA==",
"requires": { "requires": {
"@parity/abi": "2.1.2", "@parity/abi": "2.1.2",
"@parity/jsonrpc": "2.1.4", "@parity/jsonrpc": "2.1.4",
@ -52,8 +52,8 @@
"version": "github:js-dist-paritytech/dapp-dapp-methods#7245089a8e83274372cde3c9406ae155e2083f84", "version": "github:js-dist-paritytech/dapp-dapp-methods#7245089a8e83274372cde3c9406ae155e2083f84",
"dev": true, "dev": true,
"requires": { "requires": {
"@parity/api": "2.1.5", "@parity/api": "2.1.6",
"@parity/shared": "2.2.12", "@parity/shared": "2.2.14",
"@parity/ui": "2.2.15", "@parity/ui": "2.2.15",
"lodash": "4.17.4", "lodash": "4.17.4",
"mobx": "3.3.2", "mobx": "3.3.2",
@ -74,9 +74,9 @@
"integrity": "sha512-6bICFA1c1GBz4d7vratkoqovBezJNjc8VCwnZtpPTcyLeMshAhatPV4dGgJo/eHtlOCkKAeaAKatWZhEtXt/5g==", "integrity": "sha512-6bICFA1c1GBz4d7vratkoqovBezJNjc8VCwnZtpPTcyLeMshAhatPV4dGgJo/eHtlOCkKAeaAKatWZhEtXt/5g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@parity/api": "2.1.5", "@parity/api": "2.1.6",
"@parity/etherscan": "2.1.3", "@parity/etherscan": "2.1.3",
"@parity/shared": "2.2.12", "@parity/shared": "2.2.14",
"bignumber.js": "3.0.1", "bignumber.js": "3.0.1",
"brace": "0.9.0", "brace": "0.9.0",
"date-difference": "1.0.0", "date-difference": "1.0.0",
@ -556,7 +556,7 @@
"version": "github:js-dist-paritytech/dapp-dapp-visible#84f40feb42f1707d7f463213a990600dc11978f7", "version": "github:js-dist-paritytech/dapp-dapp-visible#84f40feb42f1707d7f463213a990600dc11978f7",
"dev": true, "dev": true,
"requires": { "requires": {
"@parity/api": "2.1.5", "@parity/api": "2.1.6",
"@parity/ui": "2.2.15", "@parity/ui": "2.2.15",
"mobx": "3.3.2", "mobx": "3.3.2",
"mobx-react": "4.3.5", "mobx-react": "4.3.5",
@ -576,9 +576,9 @@
"integrity": "sha512-6bICFA1c1GBz4d7vratkoqovBezJNjc8VCwnZtpPTcyLeMshAhatPV4dGgJo/eHtlOCkKAeaAKatWZhEtXt/5g==", "integrity": "sha512-6bICFA1c1GBz4d7vratkoqovBezJNjc8VCwnZtpPTcyLeMshAhatPV4dGgJo/eHtlOCkKAeaAKatWZhEtXt/5g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@parity/api": "2.1.5", "@parity/api": "2.1.6",
"@parity/etherscan": "2.1.3", "@parity/etherscan": "2.1.3",
"@parity/shared": "2.2.12", "@parity/shared": "2.2.14",
"bignumber.js": "3.0.1", "bignumber.js": "3.0.1",
"brace": "0.9.0", "brace": "0.9.0",
"date-difference": "1.0.0", "date-difference": "1.0.0",
@ -1103,7 +1103,7 @@
"resolved": "https://registry.npmjs.org/@parity/etherscan/-/etherscan-2.1.3.tgz", "resolved": "https://registry.npmjs.org/@parity/etherscan/-/etherscan-2.1.3.tgz",
"integrity": "sha512-GtQMaE8t7PDOcz/K4Ud+Z6EELB47+qG5V6R7iTJ4DcueXVgiMAXK5OiNeKF3Qjd1/M4FIJdFm5NTSdC7bR38+Q==", "integrity": "sha512-GtQMaE8t7PDOcz/K4Ud+Z6EELB47+qG5V6R7iTJ4DcueXVgiMAXK5OiNeKF3Qjd1/M4FIJdFm5NTSdC7bR38+Q==",
"requires": { "requires": {
"@parity/api": "2.1.5", "@parity/api": "2.1.6",
"bignumber.js": "3.0.1", "bignumber.js": "3.0.1",
"es6-promise": "4.1.1", "es6-promise": "4.1.1",
"node-fetch": "1.7.3", "node-fetch": "1.7.3",
@ -1140,9 +1140,9 @@
"version": "github:paritytech/plugin-signer-qr#c16423de5b8a8f68ebd5f1e78e084fa959329a9f" "version": "github:paritytech/plugin-signer-qr#c16423de5b8a8f68ebd5f1e78e084fa959329a9f"
}, },
"@parity/shared": { "@parity/shared": {
"version": "2.2.12", "version": "2.2.14",
"resolved": "https://registry.npmjs.org/@parity/shared/-/shared-2.2.12.tgz", "resolved": "https://registry.npmjs.org/@parity/shared/-/shared-2.2.14.tgz",
"integrity": "sha512-2ANbEOkWoqOf5ytE0K5pq7ZeqS7PVuiIwrhyxDgn8dQhpFiDLHro7pQirIEDZ8LzZK6g6V+HU38sagn6dYSRIQ==", "integrity": "sha512-YM7ZqWNyquX0+j89NPPxFBCUPgaqIVrqQ4Iqml50kz9uC/Ev07A/OB/+yYmAJ+3io6LWvDc/U5K3CpaMltTLtg==",
"requires": { "requires": {
"@parity/ledger": "2.1.2", "@parity/ledger": "2.1.2",
"eventemitter3": "2.0.3", "eventemitter3": "2.0.3",
@ -1202,9 +1202,9 @@
"resolved": "https://registry.npmjs.org/@parity/ui/-/ui-3.0.16.tgz", "resolved": "https://registry.npmjs.org/@parity/ui/-/ui-3.0.16.tgz",
"integrity": "sha512-yGQ8k2/oNxu0GyJ6eQS1AUk1O1XR//oXfaHPEBa0VuJIB7gY9lPrkG7CSNpazOrTCfhdCHgpjGe3WR5lbv0HiQ==", "integrity": "sha512-yGQ8k2/oNxu0GyJ6eQS1AUk1O1XR//oXfaHPEBa0VuJIB7gY9lPrkG7CSNpazOrTCfhdCHgpjGe3WR5lbv0HiQ==",
"requires": { "requires": {
"@parity/api": "2.1.5", "@parity/api": "2.1.6",
"@parity/etherscan": "2.1.3", "@parity/etherscan": "2.1.3",
"@parity/shared": "2.2.12", "@parity/shared": "2.2.14",
"babel-runtime": "6.26.0", "babel-runtime": "6.26.0",
"bignumber.js": "4.1.0", "bignumber.js": "4.1.0",
"brace": "0.11.0", "brace": "0.11.0",

View File

@ -140,12 +140,12 @@
"yargs": "6.6.0" "yargs": "6.6.0"
}, },
"dependencies": { "dependencies": {
"@parity/api": "^2.1.1", "@parity/api": "^2.1.6",
"@parity/plugin-signer-account": "paritytech/plugin-signer-account", "@parity/plugin-signer-account": "paritytech/plugin-signer-account",
"@parity/plugin-signer-default": "paritytech/plugin-signer-default", "@parity/plugin-signer-default": "paritytech/plugin-signer-default",
"@parity/plugin-signer-hardware": "paritytech/plugin-signer-hardware", "@parity/plugin-signer-hardware": "paritytech/plugin-signer-hardware",
"@parity/plugin-signer-qr": "paritytech/plugin-signer-qr", "@parity/plugin-signer-qr": "paritytech/plugin-signer-qr",
"@parity/shared": "^2.2.12", "@parity/shared": "2.2.14",
"@parity/ui": "^3.0.16", "@parity/ui": "^3.0.16",
"keythereum": "1.0.2", "keythereum": "1.0.2",
"lodash.flatten": "4.4.0", "lodash.flatten": "4.4.0",

View File

@ -20,37 +20,28 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100vh; height: 100vh;
overflow: hidden;
width: 100%; width: 100%;
.logo { .logo {
top: 0;
right: 0;
left: 0;
bottom: 0;
opacity: 0.2;
position: absolute; position: absolute;
padding: 2em; left: 50%;
text-align: center; top: 50%;
transform: translate(-50%, -50%);
z-index: 0; z-index: 0;
opacity: 0.2;
img {
display: inline-block;
margin: 0 auto;
}
} }
.content { .content {
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-grow: 1; flex-grow: 1;
overflow: hidden;
position: relative; position: relative;
> div:not(.logo) { /* Show scrollbar for Homepage only, dapps' scrollbar are handled inside
display: flex; * their iframe.
flex-grow: 1; */
overflow-y: scroll; & > div {
overflow-y: auto;
} }
} }

View File

@ -75,6 +75,7 @@ class Application extends Component {
return ( return (
<div className={ styles.application }> <div className={ styles.application }>
<img src={ parityLogo } className={ styles.logo } />
{ {
blockNumber blockNumber
? <Status upgradeStore={ this.upgradeStore } /> ? <Status upgradeStore={ this.upgradeStore } />
@ -107,33 +108,32 @@ class Application extends Component {
} }
renderApp () { renderApp () {
const { children } = this.props;
return [ return [
<Extension key='extension' />, <Extension key='extension' />,
<FirstRun key='firstrun' />, <FirstRun key='firstrun' />,
<Snackbar key='snackbar' />, <Snackbar key='snackbar' />,
<UpgradeParity key='upgrade' upgradeStore={ this.upgradeStore } />, <UpgradeParity key='upgrade' upgradeStore={ this.upgradeStore } />,
<Errors key='errors' />, <Errors key='errors' />,
<div key='content' className={ styles.content }> this.renderContent()
{ children }
</div>
]; ];
} }
renderMinimized () { renderMinimized () {
const { children } = this.props;
return [ return [
<Errors key='errors' />, <Errors key='errors' />,
<div key='content' className={ styles.content }> this.renderContent()
<div className={ styles.logo }>
<img src={ parityLogo } />
</div>
{ children }
</div>
]; ];
} }
renderContent () {
const { children } = this.props;
return (
<div key='content' className={ styles.content }>
{children}
</div>
);
}
} }
function mapStateToProps (state) { function mapStateToProps (state) {

View File

@ -72,7 +72,7 @@
.icons { .icons {
margin-top: 2em; margin-top: 2em;
margin-bottom: 0px; margin-bottom: 0;
} }
.icon, .icon,

View File

@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import GradientBg from '@parity/ui/lib/GradientBg'; import GradientBg from '@parity/ui/lib/GradientBg';
import Input from '@parity/ui/lib/Form/Input'; import Input from '@parity/ui/lib/Form/Input';
import { CompareIcon, ComputerIcon, DashboardIcon, VpnIcon, KeyIcon } from '@parity/ui/lib/Icons'; import { CompareIcon, ComputerIcon, DashboardIcon, KeyIcon } from '@parity/ui/lib/Icons';
import styles from './connection.css'; import styles from './connection.css';

View File

@ -16,48 +16,44 @@
*/ */
.card { .card {
padding: 0.25em; position: relative;
margin-top: 3em;
.content { .pin {
background: white; display: none;
box-sizing: content-box; position: absolute;
min-height: 100px; top: 0;
right: 1.6em;
.title { z-index: 1;
min-height: 1em;
padding-left: 72px;
} }
.description { .pin.pinned {
color: #333; display: block;
min-height: 1em; transform: rotate(45deg);
padding-left: 72px; }
padding-top: 0.25em;
opacity: 0.66; &:hover {
.pin {
display: block;
}
}
.content {
display: block;
padding-top: 1em;
.title {
margin-top: 0.8em;
} }
.image { .image {
border-radius: 8px; box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.15);
position: absolute; border-radius: 10px;
} display: block;
width: 2em;
.vouching { height: 2em;
padding: 0.5em; margin-left: auto;
margin: 0.5em 1em; margin-right: auto;
background: transparent;
position: relative;
white-space: nowrap;
img {
position: relative;
display: inline-block;
margin: 0.25em 0.25em 0.25em 0;
}
div {
right: auto;
left: 0;
}
} }
} }
} }

View File

@ -16,10 +16,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Link } from 'react-router';
import Container from '@parity/ui/lib/Container';
import DappIcon from '@parity/ui/lib/DappIcon'; import DappIcon from '@parity/ui/lib/DappIcon';
import DappVouchFor from '@parity/ui/lib/DappVouchFor'; import Header from 'semantic-ui-react/dist/commonjs/elements/Header';
import Button from 'semantic-ui-react/dist/commonjs/elements/Button';
import styles from './dappCard.css'; import styles from './dappCard.css';
@ -27,11 +28,15 @@ export default class DappCard extends Component {
static propTypes = { static propTypes = {
app: PropTypes.object.isRequired, app: PropTypes.object.isRequired,
availability: PropTypes.string.isRequired, availability: PropTypes.string.isRequired,
className: PropTypes.string className: PropTypes.string,
onPin: PropTypes.func,
pinned: PropTypes.bool
}; };
handlePin = () => this.props.onPin(this.props.app.id)
render () { render () {
const { app, availability, className } = this.props; const { app, availability, className, pinned } = this.props;
if (app.onlyPersonal && availability !== 'personal') { if (app.onlyPersonal && availability !== 'personal') {
return null; return null;
@ -39,26 +44,28 @@ export default class DappCard extends Component {
return ( return (
<div className={ [styles.card, className].join(' ') }> <div className={ [styles.card, className].join(' ') }>
<Container <Button
className={ styles.content } size='mini'
link={ `/${app.id}` } icon='pin'
> circular
className={ [styles.pin, pinned && styles.pinned].join(' ') }
onClick={ this.handlePin }
/>
<div className={ styles.content }>
<Link to={ app.url === 'web' ? '/web' : `/${app.id}` } >
<DappIcon <DappIcon
app={ app } app={ app }
className={ styles.image } className={ styles.image }
/> />
<div className={ styles.title }> <Header
{ app.name } as='h5'
textAlign='center'
className={ styles.title }
>
{app.name}
</Header>
</Link>
</div> </div>
<div className={ styles.description }>
{ app.description }
</div>
<DappVouchFor
app={ app }
className={ styles.vouching }
maxNumber={ 10 }
/>
</Container>
</div> </div>
); );
} }

View File

@ -41,15 +41,21 @@
} }
} }
.sectionTitle {
padding: 2em 0 0 4em !important;
margin-bottom: 0 !important;
}
.dapps { .dapps {
padding: 0 1.5em;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
margin: 1.5em 0; justify-content: center;
.dapp { .dapp {
flex: 0 0 25%; width: 12em;
max-width: 25%; margin-left: 2em;
min-width: 25%; margin-right: 2em;
} }
} }

View File

@ -45,25 +45,40 @@ class Dapps extends Component {
this.store.loadAllApps(); this.store.loadAllApps();
} }
render () { handlePin = (appId) => {
const { availability } = this.props; if (this.store.displayApps[appId].pinned) {
const applications = [].concat(this.store.visibleLocal, this.store.visibleViews, this.store.visibleBuiltin, this.store.visibleNetwork); this.store.unpinApp(appId);
} else {
this.store.pinApp(appId);
}
}
return ( renderSection = (apps) => (
<Page className={ styles.dapps }> apps && apps.length > 0 &&
<div className={ styles.dapps }>
{ {
applications.map((app, index) => ( apps.map((app, index) => (
<DappCard <DappCard
app={ app } app={ app }
availability={ availability } pinned={ this.store.displayApps[app.id] && this.store.displayApps[app.id].pinned }
availability={ this.props.availability }
className={ styles.dapp } className={ styles.dapp }
key={ `${index}_${app.id}` } key={ `${index}_${app.id}` }
onPin={ this.handlePin }
/> />
)) ))
} }
</div>
)
render () {
return (
<Page className={ styles.layout }>
{this.renderSection(this.store.pinnedApps)}
{this.renderSection(this.store.visibleUnpinned)}
{ {
this.store.externalOverlayVisible this.store.externalOverlayVisible &&
? ( (
<div className={ styles.overlay }> <div className={ styles.overlay }>
<div> <div>
<FormattedMessage <FormattedMessage
@ -86,7 +101,6 @@ class Dapps extends Component {
</div> </div>
</div> </div>
) )
: null
} }
</Page> </Page>
); );

View File

@ -17,46 +17,49 @@
import * as mobx from 'mobx'; import * as mobx from 'mobx';
import flatten from 'lodash.flatten'; import flatten from 'lodash.flatten';
import VisibleStore from '@parity/shared/lib/mobx/dappsStore'; import DappsStore from '@parity/shared/lib/mobx/dappsStore';
import RequestStore from './DappRequests/store'; import RequestStore from './DappRequests/store';
import methodGroups from './DappRequests/methodGroups'; import methodGroups from './DappRequests/methodGroups';
export default function execute (appId, method, params, callback) { export default function execute (appId, method, params, callback) {
const visibleStore = VisibleStore.get(); const dappsStore = DappsStore.get();
const requestStore = RequestStore.get(); const requestStore = RequestStore.get();
switch (method) { switch (method) {
case 'shell_getApps': case 'shell_getApps': {
const [displayAll] = params; const [displayAll] = params;
callback( callback(
null, null,
displayAll displayAll
? visibleStore.allApps.slice().map(mobx.toJS) ? dappsStore.allApps.slice().map(mobx.toJS)
: visibleStore.visibleApps.slice().map(mobx.toJS) : dappsStore.visibleApps.slice().map(mobx.toJS)
); );
return true; return true;
}
case 'shell_getFilteredMethods': case 'shell_getFilteredMethods': {
callback( callback(
null, null,
flatten(Object.keys(methodGroups).map(key => methodGroups[key].methods)) flatten(Object.keys(methodGroups).map(key => methodGroups[key].methods))
); );
return true; return true;
}
case 'shell_getMethodGroups': case 'shell_getMethodGroups': {
callback( callback(
null, null,
methodGroups methodGroups
); );
return true; return true;
}
case 'shell_getMethodPermissions': case 'shell_getMethodPermissions': {
callback(null, mobx.toJS(requestStore.permissions)); callback(null, mobx.toJS(requestStore.permissions));
return true; return true;
}
case 'shell_loadApp': case 'shell_loadApp': {
const [loadId, loadParams] = params; const [loadId, loadParams] = params;
const loadUrl = `/${loadId}/${loadParams || ''}`; const loadUrl = `/${loadId}/${loadParams || ''}`;
@ -64,27 +67,43 @@ export default function execute (appId, method, params, callback) {
callback(null, true); callback(null, true);
return true; return true;
}
case 'shell_requestNewToken': case 'shell_requestNewToken': {
callback(null, requestStore.createToken(appId)); callback(null, requestStore.createToken(appId));
return true; return true;
}
case 'shell_setAppVisibility': case 'shell_setAppVisibility': {
const [changeId, visibility] = params; const [appId, visibility] = params;
callback( callback(
null, null,
visibility visibility
? visibleStore.showApp(changeId) ? dappsStore.showApp(appId)
: visibleStore.hideApp(changeId) : dappsStore.hideApp(appId)
); );
return true; return true;
}
case 'shell_setMethodPermissions': case 'shell_setAppPinned': {
const [appId, pinned] = params;
callback(
null,
pinned
? dappsStore.pinApp(appId)
: dappsStore.unpinApp(appId)
);
return true;
}
case 'shell_setMethodPermissions': {
const [permissions] = params; const [permissions] = params;
callback(null, requestStore.setPermissions(permissions)); callback(null, requestStore.setPermissions(permissions));
return true; return true;
}
default: default:
return false; return false;