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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import GradientBg from '@parity/ui/lib/GradientBg';
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';

View File

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

View File

@ -16,10 +16,11 @@
import React, { Component } from 'react';
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 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';
@ -27,11 +28,15 @@ export default class DappCard extends Component {
static propTypes = {
app: PropTypes.object.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 () {
const { app, availability, className } = this.props;
const { app, availability, className, pinned } = this.props;
if (app.onlyPersonal && availability !== 'personal') {
return null;
@ -39,26 +44,28 @@ export default class DappCard extends Component {
return (
<div className={ [styles.card, className].join(' ') }>
<Container
className={ styles.content }
link={ `/${app.id}` }
>
<DappIcon
app={ app }
className={ styles.image }
/>
<div className={ styles.title }>
{ app.name }
</div>
<div className={ styles.description }>
{ app.description }
</div>
<DappVouchFor
app={ app }
className={ styles.vouching }
maxNumber={ 10 }
/>
</Container>
<Button
size='mini'
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
app={ app }
className={ styles.image }
/>
<Header
as='h5'
textAlign='center'
className={ styles.title }
>
{app.name}
</Header>
</Link>
</div>
</div>
);
}

View File

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

View File

@ -45,48 +45,62 @@ class Dapps extends Component {
this.store.loadAllApps();
}
render () {
const { availability } = this.props;
const applications = [].concat(this.store.visibleLocal, this.store.visibleViews, this.store.visibleBuiltin, this.store.visibleNetwork);
handlePin = (appId) => {
if (this.store.displayApps[appId].pinned) {
this.store.unpinApp(appId);
} else {
this.store.pinApp(appId);
}
}
renderSection = (apps) => (
apps && apps.length > 0 &&
<div className={ styles.dapps }>
{
apps.map((app, index) => (
<DappCard
app={ app }
pinned={ this.store.displayApps[app.id] && this.store.displayApps[app.id].pinned }
availability={ this.props.availability }
className={ styles.dapp }
key={ `${index}_${app.id}` }
onPin={ this.handlePin }
/>
))
}
</div>
)
render () {
return (
<Page className={ styles.dapps }>
<Page className={ styles.layout }>
{this.renderSection(this.store.pinnedApps)}
{this.renderSection(this.store.visibleUnpinned)}
{
applications.map((app, index) => (
<DappCard
app={ app }
availability={ availability }
className={ styles.dapp }
key={ `${index}_${app.id}` }
/>
))
}
{
this.store.externalOverlayVisible
? (
<div className={ styles.overlay }>
<div>
<FormattedMessage
id='dapps.external.warning'
defaultMessage='Applications made available on the network by 3rd-party authors are not affiliated with Parity nor are they published by Parity. Each remain under the control of their respective authors. Please ensure that you understand the goals for each before interacting.'
/>
</div>
<div>
<Checkbox
className={ styles.accept }
label={
<FormattedMessage
id='dapps.external.accept'
defaultMessage='I understand that these applications are not affiliated with Parity'
/>
}
checked={ false }
onClick={ this.onClickAcceptExternal }
/>
</div>
this.store.externalOverlayVisible &&
(
<div className={ styles.overlay }>
<div>
<FormattedMessage
id='dapps.external.warning'
defaultMessage='Applications made available on the network by 3rd-party authors are not affiliated with Parity nor are they published by Parity. Each remain under the control of their respective authors. Please ensure that you understand the goals for each before interacting.'
/>
</div>
)
: null
<div>
<Checkbox
className={ styles.accept }
label={
<FormattedMessage
id='dapps.external.accept'
defaultMessage='I understand that these applications are not affiliated with Parity'
/>
}
checked={ false }
onClick={ this.onClickAcceptExternal }
/>
</div>
</div>
)
}
</Page>
);

View File

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