From 3a7708bdaa8360c2b8cce93524c10e0982b6fdc2 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 13 Feb 2017 16:44:45 +0100 Subject: [PATCH 01/34] Add React Hot Loader to DappReg dapp --- js/src/dapps/dappreg.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/js/src/dapps/dappreg.js b/js/src/dapps/dappreg.js index 1c6c397f7b0..68d2ab30a56 100644 --- a/js/src/dapps/dappreg.js +++ b/js/src/dapps/dappreg.js @@ -17,6 +17,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import injectTapEventPlugin from 'react-tap-event-plugin'; +import { AppContainer } from 'react-hot-loader'; injectTapEventPlugin(); @@ -27,6 +28,21 @@ import '../../assets/fonts/RobotoMono/font.css'; import './style.css'; ReactDOM.render( - , + + + , document.querySelector('#container') ); + +if (module.hot) { + module.hot.accept('./dappreg/Application/index.js', () => { + require('./dappreg/Application/index.js'); + + ReactDOM.render( + + + , + document.querySelector('#container') + ); + }); +} From 693639790ad93f906ef54b8d21afbf32a9db2099 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 13 Feb 2017 17:13:18 +0100 Subject: [PATCH 02/34] Updated colours --- .../dapps/dappreg/Application/application.css | 4 +++- js/src/dapps/dappreg/Button/button.css | 4 +++- js/src/dapps/dappreg/Modal/modal.css | 4 +++- js/src/dapps/dappreg/_colors.css | 18 ++++++++++++++++++ js/src/dapps/dappreg/dappsStore.js | 2 +- 5 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 js/src/dapps/dappreg/_colors.css diff --git a/js/src/dapps/dappreg/Application/application.css b/js/src/dapps/dappreg/Application/application.css index b8c2354ab04..654f9f99864 100644 --- a/js/src/dapps/dappreg/Application/application.css +++ b/js/src/dapps/dappreg/Application/application.css @@ -15,6 +15,8 @@ /* along with Parity. If not, see . */ +@import '../_colors.css'; + .body { color: #333; background: #eee; @@ -39,7 +41,7 @@ } .header { - background: #44e; + background: $blue; border-radius: 0 0 0.25em 0.25em; color: #fff; left: 0; diff --git a/js/src/dapps/dappreg/Button/button.css b/js/src/dapps/dappreg/Button/button.css index 1ec1aeb909d..c980665e674 100644 --- a/js/src/dapps/dappreg/Button/button.css +++ b/js/src/dapps/dappreg/Button/button.css @@ -15,8 +15,10 @@ /* along with Parity. If not, see . */ +@import '../_colors.css'; + .button { - background: #44e; + background: $blue; border: none; border-radius: 0.25em; color: #fff; diff --git a/js/src/dapps/dappreg/Modal/modal.css b/js/src/dapps/dappreg/Modal/modal.css index 4421b6f1394..c966aebbd75 100644 --- a/js/src/dapps/dappreg/Modal/modal.css +++ b/js/src/dapps/dappreg/Modal/modal.css @@ -15,6 +15,8 @@ /* along with Parity. If not, see . */ +@import '../_colors.css'; + .modal { .body { bottom: 0; @@ -57,7 +59,7 @@ } .header { - background: #44e; + background: $blue; color: #fff; opacity: 0.85; padding: 1em; diff --git a/js/src/dapps/dappreg/_colors.css b/js/src/dapps/dappreg/_colors.css new file mode 100644 index 00000000000..508cf59bacc --- /dev/null +++ b/js/src/dapps/dappreg/_colors.css @@ -0,0 +1,18 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +$blue: rgb(41, 128, 185); diff --git a/js/src/dapps/dappreg/dappsStore.js b/js/src/dapps/dappreg/dappsStore.js index 4998a29a8e9..1fd933debc9 100644 --- a/js/src/dapps/dappreg/dappsStore.js +++ b/js/src/dapps/dappreg/dappsStore.js @@ -354,7 +354,7 @@ export default class DappsStore { ]) .then(([contentUrl, imageUrl, manifestUrl]) => { return this - ._loadManifest(app.id, manifestHash) + ._loadManifest(app.id, manifestHash, manifestUrl) .then((manifest) => { this.setAppInfo(app, { manifest, From 4b5adc0678ebd413a60e52dd74e473faa76d0c58 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 16 Feb 2017 15:49:46 +0100 Subject: [PATCH 03/34] Add DappCards --- .../dapps/dappreg/Application/application.js | 15 ++++ js/src/dapps/dappreg/DappCard/dappCard.css | 54 +++++++++++++ js/src/dapps/dappreg/DappCard/dappCard.js | 78 +++++++++++++++++++ js/src/dapps/dappreg/DappCard/index.js | 17 ++++ js/src/dapps/dappreg/Dapps/dapps.css | 34 ++++++++ js/src/dapps/dappreg/Dapps/dapps.js | 54 +++++++++++++ js/src/dapps/dappreg/Dapps/index.js | 17 ++++ js/src/dapps/dappreg/dappsStore.js | 10 ++- 8 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 js/src/dapps/dappreg/DappCard/dappCard.css create mode 100644 js/src/dapps/dappreg/DappCard/dappCard.js create mode 100644 js/src/dapps/dappreg/DappCard/index.js create mode 100644 js/src/dapps/dappreg/Dapps/dapps.css create mode 100644 js/src/dapps/dappreg/Dapps/dapps.js create mode 100644 js/src/dapps/dappreg/Dapps/index.js diff --git a/js/src/dapps/dappreg/Application/application.js b/js/src/dapps/dappreg/Application/application.js index e92e8a7eb71..549b2ff3705 100644 --- a/js/src/dapps/dappreg/Application/application.js +++ b/js/src/dapps/dappreg/Application/application.js @@ -21,6 +21,7 @@ import DappsStore from '../dappsStore'; import ButtonBar from '../ButtonBar'; import Dapp from '../Dapp'; +import Dapps from '../Dapps'; import ModalDelete from '../ModalDelete'; import ModalRegister from '../ModalRegister'; import ModalUpdate from '../ModalUpdate'; @@ -41,6 +42,8 @@ export default class Application extends Component { ); } + const { ownDapps, otherDapps } = this.dappsStore; + return (
@@ -51,6 +54,18 @@ export default class Application extends Component {
+ +
+ + +
+
{ this.dappsStore.count } applications registered, { this.dappsStore.ownedCount } owned by user
diff --git a/js/src/dapps/dappreg/DappCard/dappCard.css b/js/src/dapps/dappreg/DappCard/dappCard.css new file mode 100644 index 00000000000..4a918179cea --- /dev/null +++ b/js/src/dapps/dappreg/DappCard/dappCard.css @@ -0,0 +1,54 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +$imgSize: 6rem; + +.card { + align-items: center; + background-color: rgba(240, 240, 240, 0.75); + display: flex; + flex-direction: column; + margin: 1rem; + padding: 1rem; + width: 9rem; +} + +.icon { + margin-bottom: 0.75rem; + overflow: hidden; + + img { + border-radius: 50%; + height: $imgSize; + width: $imgSize; + } +} + +.name { + font-size: 1.25rem; + margin-bottom: 0.5rem; + overflow: hidden; + text-align: center; + text-overflow: ellipsis; + width: 100%; +} + +.author, +.version { + font-size: 0.75rem; + text-align: center; +} diff --git a/js/src/dapps/dappreg/DappCard/dappCard.js b/js/src/dapps/dappreg/DappCard/dappCard.js new file mode 100644 index 00000000000..89d965b0819 --- /dev/null +++ b/js/src/dapps/dappreg/DappCard/dappCard.js @@ -0,0 +1,78 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component, PropTypes } from 'react'; + +import styles from './dappCard.css'; + +export default class DappCard extends Component { + static propTypes = { + dapp: PropTypes.object.isRequired + }; + + render () { + const { dapp } = this.props; + const { id, imageUrl, manifest } = dapp; + + return ( +
+
+ { this.renderImage(imageUrl) } +
+ + + { manifest && manifest.name || id } + + + { this.renderVersion(manifest) } + { this.renderAuthor(manifest) } +
+ ); + } + + renderImage (url) { + return ( + + ); + } + + renderVersion (manifest) { + if (!manifest || !manifest.version) { + return null; + } + + return ( + + v{ manifest.version } + + ); + } + + renderAuthor (manifest) { + if (!manifest || !manifest.author) { + return null; + } + + return ( + + by { manifest && manifest.author } + + ); + } +} diff --git a/js/src/dapps/dappreg/DappCard/index.js b/js/src/dapps/dappreg/DappCard/index.js new file mode 100644 index 00000000000..eed38ca781c --- /dev/null +++ b/js/src/dapps/dappreg/DappCard/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './dappCard'; diff --git a/js/src/dapps/dappreg/Dapps/dapps.css b/js/src/dapps/dappreg/Dapps/dapps.css new file mode 100644 index 00000000000..5fdeb65514a --- /dev/null +++ b/js/src/dapps/dappreg/Dapps/dapps.css @@ -0,0 +1,34 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.dapps { + background-color: rgba(255, 255, 255, 0.9); + margin: 1rem; + padding: 1rem; + text-align: left; +} + +.container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.title { + margin: 0 0 0.5rem; +} diff --git a/js/src/dapps/dappreg/Dapps/dapps.js b/js/src/dapps/dappreg/Dapps/dapps.js new file mode 100644 index 00000000000..3fd2b69cbce --- /dev/null +++ b/js/src/dapps/dappreg/Dapps/dapps.js @@ -0,0 +1,54 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component, PropTypes } from 'react'; + +import DappCard from '../DappCard'; + +import styles from './dapps.css'; + +export default class Dapps extends Component { + static propTypes = { + dapps: PropTypes.array.isRequired, + title: PropTypes.string.isRequired + }; + + render () { + const { dapps, title } = this.props; + + return ( +
+

{ title }

+
+ { this.renderDapps(dapps) } +
+
+ ); + } + + renderDapps (dapps) { + return dapps.map((dapp) => { + const { id } = dapp; + + return ( + + ); + }); + } +} diff --git a/js/src/dapps/dappreg/Dapps/index.js b/js/src/dapps/dappreg/Dapps/index.js new file mode 100644 index 00000000000..9e6dddb632c --- /dev/null +++ b/js/src/dapps/dappreg/Dapps/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './dapps'; diff --git a/js/src/dapps/dappreg/dappsStore.js b/js/src/dapps/dappreg/dappsStore.js index 1fd933debc9..02d813039c6 100644 --- a/js/src/dapps/dappreg/dappsStore.js +++ b/js/src/dapps/dappreg/dappsStore.js @@ -67,7 +67,15 @@ export default class DappsStore { } @computed get ownedCount () { - return (this.apps.filter((app) => app.isOwner) || []).length; + return this.ownDapps.length; + } + + @computed get ownDapps () { + return this.apps.filter((app) => app.isOwner); + } + + @computed get otherDapps () { + return this.apps.filter((app) => !app.isOwner); } @action copyToWip = () => { From 7b30b7046c53bef810fe3740d081a957271bf027 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 16 Feb 2017 17:13:05 +0100 Subject: [PATCH 04/34] Dapp Modal with manifest displayed --- .../dapps/dappreg/Application/application.css | 2 +- .../dapps/dappreg/Application/application.js | 5 - js/src/dapps/dappreg/DappCard/dappCard.css | 11 +- js/src/dapps/dappreg/DappCard/dappCard.js | 56 ++++++-- js/src/dapps/dappreg/DappModal/dappModal.css | 130 ++++++++++++++++++ js/src/dapps/dappreg/DappModal/dappModal.js | 108 +++++++++++++++ js/src/dapps/dappreg/DappModal/index.js | 17 +++ js/src/dapps/dappreg/_utils.css | 22 +++ 8 files changed, 333 insertions(+), 18 deletions(-) create mode 100644 js/src/dapps/dappreg/DappModal/dappModal.css create mode 100644 js/src/dapps/dappreg/DappModal/dappModal.js create mode 100644 js/src/dapps/dappreg/DappModal/index.js create mode 100644 js/src/dapps/dappreg/_utils.css diff --git a/js/src/dapps/dappreg/Application/application.css b/js/src/dapps/dappreg/Application/application.css index 654f9f99864..9acf2aae531 100644 --- a/js/src/dapps/dappreg/Application/application.css +++ b/js/src/dapps/dappreg/Application/application.css @@ -20,7 +20,7 @@ .body { color: #333; background: #eee; - padding: 4.5em 0; + padding: 3em 0 6em; text-align: center; } diff --git a/js/src/dapps/dappreg/Application/application.js b/js/src/dapps/dappreg/Application/application.js index 549b2ff3705..44f8a6efb65 100644 --- a/js/src/dapps/dappreg/Application/application.js +++ b/js/src/dapps/dappreg/Application/application.js @@ -49,11 +49,6 @@ export default class Application extends Component {
DAPP REGISTRY, a global view of distributed applications available on the network. Putting the puzzle together.
-
- - - -
. */ +@import '../_utils.css'; + $imgSize: 6rem; .card { + composes: bezier-transform; + align-items: center; background-color: rgba(240, 240, 240, 0.75); display: flex; flex-direction: column; margin: 1rem; padding: 1rem; - width: 9rem; + width: 10rem; + + &:hover { + cursor: pointer; + transform: scale(1.05); + } } .icon { diff --git a/js/src/dapps/dappreg/DappCard/dappCard.js b/js/src/dapps/dappreg/DappCard/dappCard.js index 89d965b0819..5fe006fba8e 100644 --- a/js/src/dapps/dappreg/DappCard/dappCard.js +++ b/js/src/dapps/dappreg/DappCard/dappCard.js @@ -16,6 +16,8 @@ import React, { Component, PropTypes } from 'react'; +import DappModal from '../DappModal'; + import styles from './dappCard.css'; export default class DappCard extends Component { @@ -23,29 +25,53 @@ export default class DappCard extends Component { dapp: PropTypes.object.isRequired }; + state = { + open: false + }; + render () { const { dapp } = this.props; const { id, imageUrl, manifest } = dapp; return ( -
-
- { this.renderImage(imageUrl) } -
+
+ { this.renderModal() } - - { manifest && manifest.name || id } - +
+ { this.renderImage(imageUrl) } +
- { this.renderVersion(manifest) } - { this.renderAuthor(manifest) } + + { manifest && manifest.name || id } + + + { this.renderVersion(manifest) } + { this.renderAuthor(manifest) } +
); } + renderModal () { + const { dapp } = this.props; + const { open } = this.state; + + return ( + + ); + } + renderImage (url) { return ( @@ -75,4 +101,12 @@ export default class DappCard extends Component { ); } + + handleClose = () => { + this.setState({ open: false }); + } + + handleOpen = () => { + this.setState({ open: true }); + } } diff --git a/js/src/dapps/dappreg/DappModal/dappModal.css b/js/src/dapps/dappreg/DappModal/dappModal.css new file mode 100644 index 00000000000..9dc8d9471f5 --- /dev/null +++ b/js/src/dapps/dappreg/DappModal/dappModal.css @@ -0,0 +1,130 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +@import '../_utils.css'; + +$imgSize: 5rem; + +.code { + color: #b58900; + font-family: 'Roboto Mono', monospace; + + .codeTitle { + align-items: center; + background-color: #073642; + color: #859900; + display: inline-flex; + height: 2rem; + padding: 0 0.5rem; + } + + .codeContainer { + background-color: #002b36; + padding: 0.5rem 1rem; + } + + code { + font-size: 0.75rem; + white-space: pre-wrap; + } +} + +.modal { + align-items: center; + background-color: rgba(40, 40, 40, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + opacity: 0; + position: fixed; + right: 0; + top: 0; + z-index: -1; + + &.open { + opacity: 1; + z-index: 100; + } +} + +.container { + background-color: rgba(255, 255, 255, 0.95); + display: flex; + flex-direction: column; + max-height: 90vh; + overflow: hidden; + position: relative; + width: 50rem; + + > * { + padding: 0.5rem 1rem; + } +} + +.close { + composes: bezier-transform; + + color: #888; + display: inline-block; + font-family: 'Roboto Mono', monospace; + font-size: 2rem; + padding: 0; + position: absolute; + right: 1rem; + top: 0.5rem; + + &:hover { + cursor: pointer; + transform: scale(1.1); + } +} + +.header { + align-items: center; + border-bottom: 1px solid #888; + display: flex; + flex: 0 0 auto; + flex-direction: row; +} + +.content { + flex: 1 1 auto; + overflow: auto; +} + +.icon { + margin-right: 1.5rem; + overflow: hidden; + + img { + border: 1px solid #444; + border-radius: 50%; + height: $imgSize; + width: $imgSize; + } +} + +.name { + margin-bottom: 0.25rem; +} + +.info { + color: #444; + font-size: 0.75rem; + margin-top: 0.25rem; +} diff --git a/js/src/dapps/dappreg/DappModal/dappModal.js b/js/src/dapps/dappreg/DappModal/dappModal.js new file mode 100644 index 00000000000..188e803c679 --- /dev/null +++ b/js/src/dapps/dappreg/DappModal/dappModal.js @@ -0,0 +1,108 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component, PropTypes } from 'react'; + +import styles from './dappModal.css'; + +export default class DappCard extends Component { + static propTypes = { + dapp: PropTypes.object.isRequired, + open: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired + }; + + render () { + const { dapp, open } = this.props; + const { id } = dapp; + + const classes = [ styles.modal ]; + + if (open) { + classes.push(styles.open); + } + + return ( +
+
+
+ ❌ +
+ + { this.renderHeader(dapp) } + { this.renderContent(dapp) } +
+
+ ); + } + + renderContent (dapp) { + const manifest = dapp.manifest || {}; + + return ( +
+
+
manifest.json
+
+ { JSON.stringify(manifest, null, 2) } +
+
+
+ ); + } + + renderHeader (dapp) { + const { id, imageUrl } = dapp; + const manifest = dapp.manifest || {}; + + const infos = []; + + if (manifest.version) { + infos.push(`v${manifest.version}`); + } + + if (manifest.author) { + infos.push(`by ${manifest.author}`); + } + + return ( +
+
+ +
+
+
+ { manifest.name || 'Unnamed' } +
+
+ { id } +
+
+ { infos.length > 0 ? infos.join(', ') : null } +
+
+
+ ); + } + + handleClose = () => { + this.props.onClose(); + } +} diff --git a/js/src/dapps/dappreg/DappModal/index.js b/js/src/dapps/dappreg/DappModal/index.js new file mode 100644 index 00000000000..4d14ecd275c --- /dev/null +++ b/js/src/dapps/dappreg/DappModal/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './dappModal'; diff --git a/js/src/dapps/dappreg/_utils.css b/js/src/dapps/dappreg/_utils.css new file mode 100644 index 00000000000..682120f7cd9 --- /dev/null +++ b/js/src/dapps/dappreg/_utils.css @@ -0,0 +1,22 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.bezier-transform { + transition-duration: 0.1s; + transition-property: all; + transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); +} From 6e2fe5caa90f25936792e6723707ea0610ed5f22 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 16 Feb 2017 17:53:22 +0100 Subject: [PATCH 05/34] Add input to the Dapp Modal --- js/src/dapps/dappreg/Dapp/dapp.js | 135 ------------ js/src/dapps/dappreg/DappCard/dappCard.css | 2 +- js/src/dapps/dappreg/DappCard/dappCard.js | 27 ++- js/src/dapps/dappreg/DappModal/dappModal.css | 5 +- js/src/dapps/dappreg/DappModal/dappModal.js | 208 ++++++++++++++++++- js/src/dapps/dappreg/Input/input.css | 4 + js/src/dapps/dappreg/Input/input.js | 8 +- 7 files changed, 247 insertions(+), 142 deletions(-) diff --git a/js/src/dapps/dappreg/Dapp/dapp.js b/js/src/dapps/dappreg/Dapp/dapp.js index 97c7f1f7019..2879572e233 100644 --- a/js/src/dapps/dappreg/Dapp/dapp.js +++ b/js/src/dapps/dappreg/Dapp/dapp.js @@ -15,18 +15,10 @@ // along with Parity. If not, see . import React, { Component } from 'react'; -import { observer } from 'mobx-react'; -import { api } from '../parity'; -import DappsStore from '../dappsStore'; - -import Input from '../Input'; -import SelectAccount from '../SelectAccount'; import styles from './dapp.css'; -@observer export default class Dapp extends Component { - dappsStore = DappsStore.instance(); render () { const app = this.dappsStore.isNew || this.dappsStore.isEditing @@ -44,131 +36,4 @@ export default class Dapp extends Component {
); } - - renderInputs (app) { - if (this.dappsStore.isNew) { - return null; - } - - return [ - this.renderHashInput(app, 'image', 'Image hash, as generated by Githubhint', true), - this.renderHashInput(app, 'manifest', 'Manifest hash, as generated by Githubhint'), - this.renderHashInput(app, 'content', 'Content hash, as generated by Githubhint') - ]; - } - - renderOwnerSelect (app) { - const overlayImage = ( - - ); - - return ( - - - - ); - } - - renderOwnerStatic (app) { - const overlayImage = ( - - ); - - return ( - - - - ); - } - - renderHashInput (app, type, label, withImage = false) { - const onChange = (event) => this.onChangeHash(event, type); - const hash = app[`${type}Hash`]; - - let overlayImage = null; - - if (withImage && hash) { - overlayImage = ( - - ); - } - - return ( - - - - ); - } - - onChangeHash (event, type) { - if (!this.dappsStore.isNew && !this.dappsStore.isEditing) { - return; - } - - const hash = event.target.value; - let changed = false; - let url = null; - - if (this.dappsStore.isNew) { - if (hash && hash.length) { - changed = true; - } - } else { - if (this.dappsStore.currentApp[`${type}Hash`] !== hash) { - changed = true; - } else { - url = this.dappsStore.currentApp[`${type}Url`]; - } - } - - this.dappsStore.editWip({ - [`${type}Changed`]: changed, - [`${type}Error`]: null, - [`${type}Hash`]: hash, - [`${type}Url`]: changed ? 'Resolving url from hash' : url - }); - - if (changed) { - if (hash.length) { - this.dappsStore - .lookupHash(hash) - .then((url) => { - this.dappsStore.editWip({ - [`${type}Error`]: url ? null : 'Unable to resolve url', - [`${type}Url`]: url - }); - }); - } else { - this.dappsStore.editWip({ [`${type}Url`]: null }); - } - } - } } diff --git a/js/src/dapps/dappreg/DappCard/dappCard.css b/js/src/dapps/dappreg/DappCard/dappCard.css index 7f981bf59eb..cbba0b262dc 100644 --- a/js/src/dapps/dappreg/DappCard/dappCard.css +++ b/js/src/dapps/dappreg/DappCard/dappCard.css @@ -30,7 +30,7 @@ $imgSize: 6rem; padding: 1rem; width: 10rem; - &:hover { + &:hover, &:focus { cursor: pointer; transform: scale(1.05); } diff --git a/js/src/dapps/dappreg/DappCard/dappCard.js b/js/src/dapps/dappreg/DappCard/dappCard.js index 5fe006fba8e..221daf258e8 100644 --- a/js/src/dapps/dappreg/DappCard/dappCard.js +++ b/js/src/dapps/dappreg/DappCard/dappCard.js @@ -14,7 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import keycode from 'keycode'; import React, { Component, PropTypes } from 'react'; +import ReactDOM from 'react-dom'; import DappModal from '../DappModal'; @@ -40,6 +42,9 @@ export default class DappCard extends Component {
{ this.renderImage(imageUrl) } @@ -102,8 +107,28 @@ export default class DappCard extends Component { ); } + handleKeyPress = (event) => { + const codeName = keycode(event); + + if (codeName === 'enter') { + return this.handleOpen(); + } + + return event; + } + handleClose = () => { - this.setState({ open: false }); + this.setState({ open: false }, () => { + if (!this.refs.card) { + return false; + } + + setTimeout(() => { + const element = ReactDOM.findDOMNode(this.refs.card); + + element && element.focus(); + }, 50); + }); } handleOpen = () => { diff --git a/js/src/dapps/dappreg/DappModal/dappModal.css b/js/src/dapps/dappreg/DappModal/dappModal.css index 9dc8d9471f5..0e986e54d16 100644 --- a/js/src/dapps/dappreg/DappModal/dappModal.css +++ b/js/src/dapps/dappreg/DappModal/dappModal.css @@ -22,6 +22,7 @@ $imgSize: 5rem; .code { color: #b58900; font-family: 'Roboto Mono', monospace; + margin-top: 1rem; .codeTitle { align-items: center; @@ -47,7 +48,7 @@ $imgSize: 5rem; align-items: center; background-color: rgba(40, 40, 40, 0.75); bottom: 0; - display: flex; + display: none; justify-content: center; left: 0; opacity: 0; @@ -57,6 +58,7 @@ $imgSize: 5rem; z-index: -1; &.open { + display: flex; opacity: 1; z-index: 100; } @@ -120,6 +122,7 @@ $imgSize: 5rem; } .name { + font-size: 1.25rem; margin-bottom: 0.25rem; } diff --git a/js/src/dapps/dappreg/DappModal/dappModal.js b/js/src/dapps/dappreg/DappModal/dappModal.js index 188e803c679..713e765c9a7 100644 --- a/js/src/dapps/dappreg/DappModal/dappModal.js +++ b/js/src/dapps/dappreg/DappModal/dappModal.js @@ -14,20 +14,36 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import keycode from 'keycode'; +import { observer } from 'mobx-react'; import React, { Component, PropTypes } from 'react'; +import ReactDOM from 'react-dom'; + +import { api } from '../parity'; +import DappsStore from '../dappsStore'; +import Input from '../Input'; +import SelectAccount from '../SelectAccount'; import styles from './dappModal.css'; +@observer export default class DappCard extends Component { + dappsStore = DappsStore.instance(); + static propTypes = { dapp: PropTypes.object.isRequired, open: PropTypes.bool.isRequired, onClose: PropTypes.func.isRequired }; + componentWillReceiveProps (nextProps) { + if (nextProps.open && !this.props.open) { + this.handleOpen(); + } + } + render () { const { dapp, open } = this.props; - const { id } = dapp; const classes = [ styles.modal ]; @@ -36,11 +52,22 @@ export default class DappCard extends Component { } return ( -
-
+
+
❌ @@ -58,6 +85,10 @@ export default class DappCard extends Component { return (
+
+ { this.renderInputs(dapp) } +
+
manifest.json
@@ -102,7 +133,178 @@ export default class DappCard extends Component { ); } + renderInputs (app) { + if (this.dappsStore.isNew) { + return null; + } + + return [ + this.renderHashInput(app, 'image', 'Image hash, as generated by Githubhint', true), + this.renderHashInput(app, 'manifest', 'Manifest hash, as generated by Githubhint'), + this.renderHashInput(app, 'content', 'Content hash, as generated by Githubhint') + ]; + } + + renderOwnerSelect (app) { + const overlayImage = ( + + ); + + return ( + + + + ); + } + + renderOwnerStatic (app) { + const overlayImage = ( + + ); + + return ( + + + + ); + } + + renderHashInput (app, type, label, withImage = false) { + const handleChange = (event) => { + return this.handleChangeHash(event, type); + }; + + const hash = app[`${type}Hash`]; + + const overlayImage = (withImage && hash) + ? ( + + ) + : null; + + const hint = app[`${type}Error`] || app[`${type}Hash`] || '...'; + const value = app[`${type}Url`] || ''; + + return ( + + + + ); + } + + stopEvent = (event) => { + event.stopPropagation(); + event.preventDefault(); + + return false; + } + + handleKeyPress = (event) => { + const codeName = keycode(event); + + if (codeName === 'esc') { + return this.handleClose(); + } + + return event; + } + + handleCloseKeyPress = (event) => { + const codeName = keycode(event); + + if (codeName === 'enter') { + return this.handleClose(); + } + + return event; + } + + handleOpen = () => { + if (!this.refs.container) { + return false; + } + + // Focus after the modal is open + setTimeout(() => { + const element = ReactDOM.findDOMNode(this.refs.container); + + element && element.focus(); + }, 50); + } + handleClose = () => { this.props.onClose(); } + + handleChangeHash = (event, type) => { + if (!this.dappsStore.isNew && !this.dappsStore.isEditing) { + return; + } + + const hash = event.target.value; + let changed = false; + let url = null; + + if (this.dappsStore.isNew) { + if (hash && hash.length) { + changed = true; + } + } else { + if (this.dappsStore.currentApp[`${type}Hash`] !== hash) { + changed = true; + } else { + url = this.dappsStore.currentApp[`${type}Url`]; + } + } + + this.dappsStore.editWip({ + [`${type}Changed`]: changed, + [`${type}Error`]: null, + [`${type}Hash`]: hash, + [`${type}Url`]: changed ? 'Resolving url from hash' : url + }); + + if (changed) { + if (hash.length) { + this.dappsStore + .lookupHash(hash) + .then((url) => { + this.dappsStore.editWip({ + [`${type}Error`]: url ? null : 'Unable to resolve url', + [`${type}Url`]: url + }); + }); + } else { + this.dappsStore.editWip({ [`${type}Url`]: null }); + } + } + } } diff --git a/js/src/dapps/dappreg/Input/input.css b/js/src/dapps/dappreg/Input/input.css index 7d7f74b2100..c553387a6a9 100644 --- a/js/src/dapps/dappreg/Input/input.css +++ b/js/src/dapps/dappreg/Input/input.css @@ -30,6 +30,10 @@ width: 100%; } + &.withOverlay input { + padding-right: 3em; + } + input { padding-bottom: 1.5em; diff --git a/js/src/dapps/dappreg/Input/input.js b/js/src/dapps/dappreg/Input/input.js index c72789d12b1..27084c3ed19 100644 --- a/js/src/dapps/dappreg/Input/input.js +++ b/js/src/dapps/dappreg/Input/input.js @@ -29,8 +29,14 @@ export default class Input extends Component { render () { const { children, hint, label, overlay } = this.props; + const inputClasses = [ styles.input ]; + + if (overlay) { + inputClasses.push(styles.withOverlay); + } + return ( -
+
From 64a0c17c2706d4c6ab7d3aa378d18b7c7adc0222 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 16 Feb 2017 19:11:01 +0100 Subject: [PATCH 06/34] WIP // Editing a Dapp --- .../dapps/dappreg/Application/application.js | 1 + js/src/dapps/dappreg/ButtonBar/buttonBar.js | 28 --- js/src/dapps/dappreg/DappCard/dappCard.js | 6 + js/src/dapps/dappreg/DappModal/dappModal.css | 13 ++ js/src/dapps/dappreg/DappModal/dappModal.js | 166 ++++++++++++------ js/src/dapps/dappreg/Modal/modal.css | 2 +- .../dappreg/SelectAccount/selectAccount.js | 11 +- js/src/dapps/dappreg/dappsStore.js | 5 +- 8 files changed, 148 insertions(+), 84 deletions(-) diff --git a/js/src/dapps/dappreg/Application/application.js b/js/src/dapps/dappreg/Application/application.js index 44f8a6efb65..98ddfdb8bf7 100644 --- a/js/src/dapps/dappreg/Application/application.js +++ b/js/src/dapps/dappreg/Application/application.js @@ -64,6 +64,7 @@ export default class Application extends Component {
{ this.dappsStore.count } applications registered, { this.dappsStore.ownedCount } owned by user
+ diff --git a/js/src/dapps/dappreg/ButtonBar/buttonBar.js b/js/src/dapps/dappreg/ButtonBar/buttonBar.js index cce4bb7aa1f..3d2022051f0 100644 --- a/js/src/dapps/dappreg/ButtonBar/buttonBar.js +++ b/js/src/dapps/dappreg/ButtonBar/buttonBar.js @@ -75,32 +75,4 @@ export default class ButtonBar extends Component {
); } - - onCancelClick = () => { - if (this.dappsStore.isEditing) { - this.dappsStore.setEditing(false); - } else { - this.dappsStore.setNew(false); - } - } - - onDeleteClick = () => { - this.modalStore.showDelete(); - } - - onEditClick = () => { - this.dappsStore.setEditing(true); - } - - onNewClick = () => { - this.dappsStore.setNew(true); - } - - onSaveClick = () => { - if (this.dappsStore.isEditing) { - this.modalStore.showUpdate(); - } else { - this.modalStore.showRegister(); - } - } } diff --git a/js/src/dapps/dappreg/DappCard/dappCard.js b/js/src/dapps/dappreg/DappCard/dappCard.js index 221daf258e8..591b2099cb1 100644 --- a/js/src/dapps/dappreg/DappCard/dappCard.js +++ b/js/src/dapps/dappreg/DappCard/dappCard.js @@ -18,11 +18,14 @@ import keycode from 'keycode'; import React, { Component, PropTypes } from 'react'; import ReactDOM from 'react-dom'; +import DappsStore from '../dappsStore'; import DappModal from '../DappModal'; import styles from './dappCard.css'; export default class DappCard extends Component { + dappsStore = DappsStore.instance(); + static propTypes = { dapp: PropTypes.object.isRequired }; @@ -132,6 +135,9 @@ export default class DappCard extends Component { } handleOpen = () => { + const { id } = this.props.dapp; + + this.dappsStore.setCurrentApp(id); this.setState({ open: true }); } } diff --git a/js/src/dapps/dappreg/DappModal/dappModal.css b/js/src/dapps/dappreg/DappModal/dappModal.css index 0e986e54d16..9fbea883d8c 100644 --- a/js/src/dapps/dappreg/DappModal/dappModal.css +++ b/js/src/dapps/dappreg/DappModal/dappModal.css @@ -96,6 +96,19 @@ $imgSize: 5rem; } } +.actions { + height: 0.5rem; + position: relative; + text-align: right; + top: 0.5rem; + + .button { + margin-bottom: 0; + margin-top: 0; + padding: 0.5rem 1.5rem; + } +} + .header { align-items: center; border-bottom: 1px solid #888; diff --git a/js/src/dapps/dappreg/DappModal/dappModal.js b/js/src/dapps/dappreg/DappModal/dappModal.js index 713e765c9a7..68820ec43d5 100644 --- a/js/src/dapps/dappreg/DappModal/dappModal.js +++ b/js/src/dapps/dappreg/DappModal/dappModal.js @@ -20,7 +20,9 @@ import React, { Component, PropTypes } from 'react'; import ReactDOM from 'react-dom'; import { api } from '../parity'; +import Button from '../Button'; import DappsStore from '../dappsStore'; +import ModalStore from '../modalStore'; import Input from '../Input'; import SelectAccount from '../SelectAccount'; @@ -29,6 +31,7 @@ import styles from './dappModal.css'; @observer export default class DappCard extends Component { dappsStore = DappsStore.instance(); + modalStore = ModalStore.instance(); static propTypes = { dapp: PropTypes.object.isRequired, @@ -89,6 +92,8 @@ export default class DappCard extends Component { { this.renderInputs(dapp) }
+ { this.renderActions(dapp) } +
manifest.json
@@ -99,6 +104,49 @@ export default class DappCard extends Component { ); } + renderActions (dapp) { + if (!dapp.isOwner) { + return null; + } + + const { isEditing } = this.dappsStore; + + if (isEditing) { + return ( +
+
+ ); + } + + return ( +
+
+ ); + } + renderHeader (dapp) { const { id, imageUrl } = dapp; const manifest = dapp.manifest || {}; @@ -134,17 +182,24 @@ export default class DappCard extends Component { } renderInputs (app) { - if (this.dappsStore.isNew) { - return null; - } - return [ - this.renderHashInput(app, 'image', 'Image hash, as generated by Githubhint', true), - this.renderHashInput(app, 'manifest', 'Manifest hash, as generated by Githubhint'), - this.renderHashInput(app, 'content', 'Content hash, as generated by Githubhint') + this.renderOwner(app), + this.renderHashInput(app, 'image', 'Image URL', true), + this.renderHashInput(app, 'manifest', 'Manifest URL'), + this.renderHashInput(app, 'content', 'Content URL') ]; } + renderOwner (app) { + const { isEditing } = this.dappsStore; + + if (isEditing) { + return this.renderOwnerSelect(app); + } + + return this.renderOwnerStatic(app); + } + renderOwnerSelect (app) { const overlayImage = ( - + ); } @@ -174,6 +232,7 @@ export default class DappCard extends Component { return ( { return this.handleChangeHash(event, type); }; + const { isEditing, wipApp } = this.dappsStore; + + const changed = wipApp && wipApp[`${type}Changed`]; + const error = app[`${type}Error`]; const hash = app[`${type}Hash`]; + const url = app[`${type}Url`]; - const overlayImage = (withImage && hash) + const overlayImage = (isImage && hash) ? ( ); @@ -261,50 +327,50 @@ export default class DappCard extends Component { } handleClose = () => { + this.handleCancel(); this.props.onClose(); } - handleChangeHash = (event, type) => { - if (!this.dappsStore.isNew && !this.dappsStore.isEditing) { + handleSelectOwner = (event) => { + const { value } = event.target; + + const changed = (this.dappsStore.currentApp.owner !== value); + + this.dappsStore.editWip({ + ownerChanged: changed, + owner: value + }); + } + + handleChangeHash = (event, type) => { + if (!this.dappsStore.isEditing) { return; } - const hash = event.target.value; - let changed = false; - let url = null; - - if (this.dappsStore.isNew) { - if (hash && hash.length) { - changed = true; - } - } else { - if (this.dappsStore.currentApp[`${type}Hash`] !== hash) { - changed = true; - } else { - url = this.dappsStore.currentApp[`${type}Url`]; - } - } + const url = event.target.value; + + let changed = (this.dappsStore.currentApp[`${type}Url`] !== url); this.dappsStore.editWip({ [`${type}Changed`]: changed, [`${type}Error`]: null, - [`${type}Hash`]: hash, - [`${type}Url`]: changed ? 'Resolving url from hash' : url + [`${type}Url`]: url }); + } - if (changed) { - if (hash.length) { - this.dappsStore - .lookupHash(hash) - .then((url) => { - this.dappsStore.editWip({ - [`${type}Error`]: url ? null : 'Unable to resolve url', - [`${type}Url`]: url - }); - }); - } else { - this.dappsStore.editWip({ [`${type}Url`]: null }); - } - } + handleCancel = () => { + this.dappsStore.setEditing(false); + } + + handleDelete = () => { + this.modalStore.showDelete(); + } + + handleEdit = () => { + this.dappsStore.setEditing(true); + } + + handleSave = () => { + this.modalStore.showUpdate(); } } diff --git a/js/src/dapps/dappreg/Modal/modal.css b/js/src/dapps/dappreg/Modal/modal.css index c966aebbd75..8aa87b20e84 100644 --- a/js/src/dapps/dappreg/Modal/modal.css +++ b/js/src/dapps/dappreg/Modal/modal.css @@ -25,7 +25,7 @@ right: 0; top: 0; text-align: center; - z-index: 50; + z-index: 500; .dialog { background: #fff; diff --git a/js/src/dapps/dappreg/SelectAccount/selectAccount.js b/js/src/dapps/dappreg/SelectAccount/selectAccount.js index 70ea64c45cd..3c3fadb3fd2 100644 --- a/js/src/dapps/dappreg/SelectAccount/selectAccount.js +++ b/js/src/dapps/dappreg/SelectAccount/selectAccount.js @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import React, { Component } from 'react'; +import React, { Component, PropTypes } from 'react'; import { observer } from 'mobx-react'; import DappsStore from '../dappsStore'; @@ -23,11 +23,15 @@ import DappsStore from '../dappsStore'; export default class SelectAccount extends Component { dappsStore = DappsStore.instance(); + static propTypes = { + onSelect: PropTypes.func + }; + render () { return ( @@ -44,7 +48,8 @@ export default class SelectAccount extends Component { }); } - onSelect = (event) => { + handleSelect = (event) => { this.dappsStore.setCurrentAccount(event.target.value); + this.props.onSelect && this.props.onSelect(event); } } diff --git a/js/src/dapps/dappreg/dappsStore.js b/js/src/dapps/dappreg/dappsStore.js index 02d813039c6..7b1496c2956 100644 --- a/js/src/dapps/dappreg/dappsStore.js +++ b/js/src/dapps/dappreg/dappsStore.js @@ -56,7 +56,7 @@ export default class DappsStore { const app = this.wipApp; const hasError = app.contentError || app.imageError || app.manifestError; - const isDirty = this.isNew || app.contentChanged || app.imageChanged || app.manifestChanged; + const isDirty = this.isNew || app.contentChanged || app.imageChanged || app.manifestChanged || app.ownerChanged; const isEditMode = this.isEditing || this.isNew; return isEditMode && isDirty && !hasError; @@ -113,7 +113,8 @@ export default class DappsStore { imageChanged: false, imageError: null, manifestChanged: false, - manifestError: null + manifestError: null, + ownerChanged: false }); return this.wipApp; From d52c8b89966b8c60267eb79aec3395f9061b9e3f Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Fri, 17 Feb 2017 11:31:54 +0100 Subject: [PATCH 07/34] Clean-Up --- js/src/dapps/dappreg/Button/button.css | 7 ++ js/src/dapps/dappreg/ButtonBar/buttonBar.css | 21 ----- js/src/dapps/dappreg/ButtonBar/buttonBar.js | 78 ----------------- js/src/dapps/dappreg/ButtonBar/index.js | 17 ---- js/src/dapps/dappreg/Dapp/dapp.css | 19 ----- js/src/dapps/dappreg/Dapp/dapp.js | 39 --------- js/src/dapps/dappreg/Dapp/index.js | 17 ---- js/src/dapps/dappreg/DappCard/dappCard.css | 4 + js/src/dapps/dappreg/DappCard/dappCard.js | 2 +- js/src/dapps/dappreg/DappModal/dappModal.js | 7 +- js/src/dapps/dappreg/Modal/modal.css | 2 +- js/src/dapps/dappreg/SelectDapp/index.js | 17 ---- js/src/dapps/dappreg/SelectDapp/selectDapp.js | 85 ------------------- 13 files changed, 19 insertions(+), 296 deletions(-) delete mode 100644 js/src/dapps/dappreg/ButtonBar/buttonBar.css delete mode 100644 js/src/dapps/dappreg/ButtonBar/buttonBar.js delete mode 100644 js/src/dapps/dappreg/ButtonBar/index.js delete mode 100644 js/src/dapps/dappreg/Dapp/dapp.css delete mode 100644 js/src/dapps/dappreg/Dapp/dapp.js delete mode 100644 js/src/dapps/dappreg/Dapp/index.js delete mode 100644 js/src/dapps/dappreg/SelectDapp/index.js delete mode 100644 js/src/dapps/dappreg/SelectDapp/selectDapp.js diff --git a/js/src/dapps/dappreg/Button/button.css b/js/src/dapps/dappreg/Button/button.css index c980665e674..ea89c71b624 100644 --- a/js/src/dapps/dappreg/Button/button.css +++ b/js/src/dapps/dappreg/Button/button.css @@ -16,8 +16,11 @@ */ @import '../_colors.css'; +@import '../_utils.css'; .button { + composes: bezier-transform; + background: $blue; border: none; border-radius: 0.25em; @@ -37,4 +40,8 @@ &[data-warning="true"] { background: #e44; } + + &:focus { + transform: scale(1.05); + } } diff --git a/js/src/dapps/dappreg/ButtonBar/buttonBar.css b/js/src/dapps/dappreg/ButtonBar/buttonBar.css deleted file mode 100644 index 77700ca8975..00000000000 --- a/js/src/dapps/dappreg/ButtonBar/buttonBar.css +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright 2015-2017 Parity Technologies (UK) Ltd. -/* This file is part of Parity. -/* -/* Parity is free software: you can redistribute it and/or modify -/* it under the terms of the GNU General Public License as published by -/* the Free Software Foundation, either version 3 of the License, or -/* (at your option) any later version. -/* -/* Parity is distributed in the hope that it will be useful, -/* but WITHOUT ANY WARRANTY; without even the implied warranty of -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -/* GNU General Public License for more details. -/* -/* You should have received a copy of the GNU General Public License -/* along with Parity. If not, see . -*/ - -.buttonbar { - text-align: center; - margin: 1em 0 0 0; -} diff --git a/js/src/dapps/dappreg/ButtonBar/buttonBar.js b/js/src/dapps/dappreg/ButtonBar/buttonBar.js deleted file mode 100644 index 3d2022051f0..00000000000 --- a/js/src/dapps/dappreg/ButtonBar/buttonBar.js +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -import React, { Component } from 'react'; -import { observer } from 'mobx-react'; - -import DappsStore from '../dappsStore'; -import ModalStore from '../modalStore'; - -import Button from '../Button'; -import styles from './buttonBar.css'; - -@observer -export default class ButtonBar extends Component { - dappsStore = DappsStore.instance(); - modalStore = ModalStore.instance(); - - render () { - let buttons = []; - - if (this.dappsStore.isEditing || this.dappsStore.isNew) { - buttons = [ - ); } - onClick = (event) => { + handleClick = (event) => { if (this.props.disabled) { + event.preventDefault(); + event.stopPropagation(); return; } diff --git a/js/src/dapps/dappreg/Card/card.css b/js/src/dapps/dappreg/Card/card.css new file mode 100644 index 00000000000..c6c650d5d50 --- /dev/null +++ b/js/src/dapps/dappreg/Card/card.css @@ -0,0 +1,62 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +@import '../_utils.css'; + +$imgSize: 6rem; + +.container { + display: flex; +} + +.card { + composes: bezier-transform; + + align-items: center; + background-color: rgba(240, 240, 240, 0.75); + display: flex; + flex-direction: column; + margin: 1rem; + padding: 1rem; + width: 10rem; + + &:hover, + &:focus { + cursor: pointer; + transform: scale(1.05); + } +} + +.icon { + margin-bottom: 0.75rem; + overflow: hidden; + + img { + border-radius: 50%; + height: $imgSize; + width: $imgSize; + } +} + +.name { + font-size: 1.25rem; + margin-bottom: 0.5rem; + overflow: hidden; + text-align: center; + text-overflow: ellipsis; + width: 100%; +} diff --git a/js/src/dapps/dappreg/Card/card.js b/js/src/dapps/dappreg/Card/card.js new file mode 100644 index 00000000000..f49a5336579 --- /dev/null +++ b/js/src/dapps/dappreg/Card/card.js @@ -0,0 +1,91 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import keycode from 'keycode'; +import React, { Component, PropTypes } from 'react'; +import ReactDOM from 'react-dom'; + +import styles from './card.css'; + +export default class Card extends Component { + static propTypes = { + children: PropTypes.any, + focus: PropTypes.bool, + icon: PropTypes.object, + name: PropTypes.object, + onClick: PropTypes.func.isRequired + }; + + static defaultProps = { + focus: false, + name: { value: '' } + }; + + componentWillReceiveProps (nextProps) { + if (nextProps.focus && !this.props.focus) { + this.handleFocus(); + } + } + + render () { + const { children, icon, name } = this.props; + + return ( +
+
+
+ { icon } +
+ + { name.value } + + { children } +
+
+ ); + } + + handleKeyPress = (event) => { + const codeName = keycode(event); + + if (codeName === 'enter') { + return this.handleClick(); + } + + return event; + } + + handleFocus = () => { + setTimeout(() => { + const element = ReactDOM.findDOMNode(this.refs.card); + + element && element.focus(); + }, 50); + } + + handleClick = () => { + this.props.onClick(); + } +} diff --git a/js/src/dapps/dappreg/Card/index.js b/js/src/dapps/dappreg/Card/index.js new file mode 100644 index 00000000000..30b58580637 --- /dev/null +++ b/js/src/dapps/dappreg/Card/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './card'; diff --git a/js/src/dapps/dappreg/CreateDappCard/createDappCard.js b/js/src/dapps/dappreg/CreateDappCard/createDappCard.js index 95cc6751720..87a62a15807 100644 --- a/js/src/dapps/dappreg/CreateDappCard/createDappCard.js +++ b/js/src/dapps/dappreg/CreateDappCard/createDappCard.js @@ -17,37 +17,33 @@ import React, { Component } from 'react'; import DappsStore from '../dappsStore'; +import Card from '../Card'; import ModalRegister from '../ModalRegister'; import PlusImage from '~/../assets/images/dapps/plus.svg'; -import dappCardStyles from '../DappCard/dappCard.css'; export default class CreateDappCard extends Component { state = { dappId: null, + focus: false, open: false }; dappsStore = DappsStore.instance(); render () { + const { focus } = this.state; + return ( -
+
{ this.renderModal() } -
) } + name={ { value: 'Register a dapp' } } onClick={ this.handleOpen } - tabIndex={ 0 } - > -
- -
- - - Register a dapp - -
+ />
); } @@ -71,11 +67,11 @@ export default class CreateDappCard extends Component { handleOpen = () => { const dappId = this.dappsStore.createDappId(); - this.setState({ open: true, dappId }); + this.setState({ focus: false, open: true, dappId }); } handleClose = () => { - this.setState({ open: false, dappId: null }); + this.setState({ focus: true, open: false, dappId: null }); } handleRegister = () => { diff --git a/js/src/dapps/dappreg/DappCard/dappCard.css b/js/src/dapps/dappreg/DappCard/dappCard.css index a66a4d1fd09..9ecfa529484 100644 --- a/js/src/dapps/dappreg/DappCard/dappCard.css +++ b/js/src/dapps/dappreg/DappCard/dappCard.css @@ -15,55 +15,10 @@ /* along with Parity. If not, see . */ -@import '../_utils.css'; - -$imgSize: 6rem; - -.container { - display: flex; -} - -.card { - composes: bezier-transform; - - align-items: center; - background-color: rgba(240, 240, 240, 0.75); - display: flex; - flex-direction: column; - margin: 1rem; - padding: 1rem; - width: 10rem; - - &:hover, &:focus { - cursor: pointer; - transform: scale(1.05); - } -} - .register { border: 1px dashed black; } -.icon { - margin-bottom: 0.75rem; - overflow: hidden; - - img { - border-radius: 50%; - height: $imgSize; - width: $imgSize; - } -} - -.name { - font-size: 1.25rem; - margin-bottom: 0.5rem; - overflow: hidden; - text-align: center; - text-overflow: ellipsis; - width: 100%; -} - .author, .version { font-size: 0.75rem; diff --git a/js/src/dapps/dappreg/DappCard/dappCard.js b/js/src/dapps/dappreg/DappCard/dappCard.js index d6e83517084..3b001276b17 100644 --- a/js/src/dapps/dappreg/DappCard/dappCard.js +++ b/js/src/dapps/dappreg/DappCard/dappCard.js @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import keycode from 'keycode'; import React, { Component, PropTypes } from 'react'; import ReactDOM from 'react-dom'; +import Card from '../Card'; import DappsStore from '../dappsStore'; import DappModal from '../DappModal'; @@ -31,39 +31,29 @@ export default class DappCard extends Component { }; state = { + focus: false, open: false }; render () { const { dapp } = this.props; + const { focus } = this.state; const { id, image } = dapp; const manifest = dapp.manifest.content; return ( -
+
{ this.renderModal() } -
-
- { this.renderImage(image.url) } -
- - - { manifest && manifest.name || id } - - { this.renderVersion(manifest) } { this.renderAuthor(manifest) } -
+
); } @@ -111,31 +101,11 @@ export default class DappCard extends Component { ); } - handleKeyPress = (event) => { - const codeName = keycode(event); - - if (codeName === 'enter') { - return this.handleOpen(); - } - - return event; - } - handleClose = () => { - this.setState({ open: false }, () => { - if (!this.refs.card) { - return false; - } - - setTimeout(() => { - const element = ReactDOM.findDOMNode(this.refs.card); - - element && element.focus(); - }, 50); - }); + this.setState({ focus: true, open: false }); } handleOpen = () => { - this.setState({ open: true }); + this.setState({ focus: false, open: true }); } } diff --git a/js/src/dapps/dappreg/Dapps/dapps.css b/js/src/dapps/dappreg/Dapps/dapps.css index 496831920d4..77ab087c028 100644 --- a/js/src/dapps/dappreg/Dapps/dapps.css +++ b/js/src/dapps/dappreg/Dapps/dapps.css @@ -26,6 +26,11 @@ display: flex; flex-direction: row; flex-wrap: wrap; + + > * { + flex: 0 0 auto; + display: flex; + } } .title { From 23a9b340b6e6ae3525a59699ba46edba23fb0dca Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 8 Mar 2017 19:23:57 +0100 Subject: [PATCH 22/34] Dashed Register Card --- js/src/dapps/dappreg/Card/card.css | 4 ++++ js/src/dapps/dappreg/Card/card.js | 12 ++++++++++-- .../dapps/dappreg/CreateDappCard/createDappCard.js | 1 + js/src/dapps/dappreg/DappCard/dappCard.css | 4 ---- js/src/dapps/dappreg/DappCard/dappCard.js | 1 - 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/js/src/dapps/dappreg/Card/card.css b/js/src/dapps/dappreg/Card/card.css index c6c650d5d50..05f9710a763 100644 --- a/js/src/dapps/dappreg/Card/card.css +++ b/js/src/dapps/dappreg/Card/card.css @@ -41,6 +41,10 @@ $imgSize: 6rem; } } +.dashed { + border: 1px dashed black; +} + .icon { margin-bottom: 0.75rem; overflow: hidden; diff --git a/js/src/dapps/dappreg/Card/card.js b/js/src/dapps/dappreg/Card/card.js index f49a5336579..d3201425c47 100644 --- a/js/src/dapps/dappreg/Card/card.js +++ b/js/src/dapps/dappreg/Card/card.js @@ -23,6 +23,7 @@ import styles from './card.css'; export default class Card extends Component { static propTypes = { children: PropTypes.any, + dashed: PropTypes.bool, focus: PropTypes.bool, icon: PropTypes.object, name: PropTypes.object, @@ -30,6 +31,7 @@ export default class Card extends Component { }; static defaultProps = { + dashed: false, focus: false, name: { value: '' } }; @@ -41,12 +43,18 @@ export default class Card extends Component { } render () { - const { children, icon, name } = this.props; + const { children, dashed, icon, name } = this.props; + + const cardClasses = [ styles.card ]; + + if (dashed) { + cardClasses.push(styles.dashed); + } return (
) } name={ { value: 'Register a dapp' } } diff --git a/js/src/dapps/dappreg/DappCard/dappCard.css b/js/src/dapps/dappreg/DappCard/dappCard.css index 9ecfa529484..ed4b483ae52 100644 --- a/js/src/dapps/dappreg/DappCard/dappCard.css +++ b/js/src/dapps/dappreg/DappCard/dappCard.css @@ -15,10 +15,6 @@ /* along with Parity. If not, see . */ -.register { - border: 1px dashed black; -} - .author, .version { font-size: 0.75rem; diff --git a/js/src/dapps/dappreg/DappCard/dappCard.js b/js/src/dapps/dappreg/DappCard/dappCard.js index 3b001276b17..f215e66f3e2 100644 --- a/js/src/dapps/dappreg/DappCard/dappCard.js +++ b/js/src/dapps/dappreg/DappCard/dappCard.js @@ -15,7 +15,6 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; -import ReactDOM from 'react-dom'; import Card from '../Card'; import DappsStore from '../dappsStore'; From 2c8a45d0eedadb9539d1aa2268326dd18f44d56e Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 8 Mar 2017 19:27:11 +0100 Subject: [PATCH 23/34] Cleanups --- js/src/dapps/dappreg/Modal/modal.css | 4 ---- js/src/dapps/dappreg/Modal/modal.js | 22 +++------------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/js/src/dapps/dappreg/Modal/modal.css b/js/src/dapps/dappreg/Modal/modal.css index e70538d987a..7375badaba8 100644 --- a/js/src/dapps/dappreg/Modal/modal.css +++ b/js/src/dapps/dappreg/Modal/modal.css @@ -68,10 +68,6 @@ color: #fff; opacity: 0.85; padding: 1em; - - &.error { - background: #e44; - } } } } diff --git a/js/src/dapps/dappreg/Modal/modal.js b/js/src/dapps/dappreg/Modal/modal.js index d8c8c166bcd..c3998cd29cf 100644 --- a/js/src/dapps/dappreg/Modal/modal.js +++ b/js/src/dapps/dappreg/Modal/modal.js @@ -22,23 +22,22 @@ export default class Modal extends Component { static propTypes = { buttons: PropTypes.node, children: PropTypes.node, - error: PropTypes.object, header: PropTypes.string } render () { - const { children, buttons, error, header } = this.props; + const { children, buttons, header } = this.props; return (
-
+
{ header }
- { error ? this.renderError() : children } + { children }
{ buttons } @@ -48,19 +47,4 @@ export default class Modal extends Component {
); } - - renderError () { - const { error } = this.props; - - return ( -
-
- Your operation failed to complete sucessfully. The following error was returned: -
-
- { error.toString() } -
-
- ); - } } From caf4e2c4c9eb8bd7de97050d8af6865b6d60d150 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 9 Mar 2017 15:29:07 +0100 Subject: [PATCH 24/34] Cleanups --- js/src/dapps/dappreg/DappModal/dappModal.css | 66 -------- js/src/dapps/dappreg/DappModal/dappModal.js | 87 ++-------- js/src/dapps/dappreg/Modal/modal.css | 160 ++++++++++-------- js/src/dapps/dappreg/Modal/modal.js | 107 ++++++++++-- .../dapps/dappreg/ModalDelete/modalDelete.js | 2 + .../dappreg/ModalRegister/modalRegister.js | 2 + .../dapps/dappreg/ModalUpdate/modalUpdate.js | 2 + 7 files changed, 195 insertions(+), 231 deletions(-) diff --git a/js/src/dapps/dappreg/DappModal/dappModal.css b/js/src/dapps/dappreg/DappModal/dappModal.css index c2610561f0b..8d819948c6c 100644 --- a/js/src/dapps/dappreg/DappModal/dappModal.css +++ b/js/src/dapps/dappreg/DappModal/dappModal.css @@ -45,58 +45,6 @@ $imgSize: 5rem; } } -.modal { - align-items: center; - background-color: rgba(40, 40, 40, 0.75); - bottom: 0; - display: none; - justify-content: center; - left: 0; - opacity: 0; - position: fixed; - right: 0; - top: 0; - z-index: -1; - - &.open { - display: flex; - opacity: 1; - z-index: 100; - } -} - -.container { - background-color: rgba(255, 255, 255, 0.95); - display: flex; - flex-direction: column; - max-height: 90vh; - overflow: hidden; - position: relative; - width: 50rem; - - > * { - padding: 0.5rem 1rem; - } -} - -.close { - composes: bezier-transform; - - color: #ddd; - display: inline-block; - font-family: 'Roboto Mono', monospace; - font-size: 2rem; - padding: 0; - position: absolute; - right: 1rem; - top: 0.5rem; - - &:hover { - cursor: pointer; - transform: scale(1.1); - } -} - .actions { height: 0.5rem; position: relative; @@ -110,20 +58,6 @@ $imgSize: 5rem; } } -.header { - align-items: center; - background-color: $blue; - color: white; - display: flex; - flex: 0 0 auto; - flex-direction: row; -} - -.content { - flex: 1 1 auto; - overflow: auto; -} - .icon { margin-right: 1.5rem; overflow: hidden; diff --git a/js/src/dapps/dappreg/DappModal/dappModal.js b/js/src/dapps/dappreg/DappModal/dappModal.js index e8b911a4e21..21da07b147f 100644 --- a/js/src/dapps/dappreg/DappModal/dappModal.js +++ b/js/src/dapps/dappreg/DappModal/dappModal.js @@ -14,15 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import keycode from 'keycode'; import { observer } from 'mobx-react'; import React, { Component, PropTypes } from 'react'; -import ReactDOM from 'react-dom'; import { api } from '../parity'; import DappsStore from '../dappsStore'; import Button from '../Button'; import Input from '../Input'; +import Modal from '../Modal'; import ModalDelete from '../ModalDelete'; import ModalUpdate from '../ModalUpdate'; import SelectAccount from '../SelectAccount'; @@ -46,28 +45,16 @@ export default class DappModal extends Component { dappsStore = DappsStore.instance(); - componentWillReceiveProps (nextProps) { - if (nextProps.open && !this.props.open) { - this.handleOpen(); - } - } - render () { const { dapp, open } = this.props; const { showDelete, showUpdate, updates } = this.state; - const classes = [ styles.modal ]; - - if (open) { - classes.push(styles.open); + if (!open) { + return null; } return ( -
+
{ showDelete ? ( @@ -91,25 +78,13 @@ export default class DappModal extends Component { ) : null } -
-
- ❌ -
- { this.renderHeader(dapp) } + { this.renderContent(dapp) } -
+
); } @@ -118,7 +93,7 @@ export default class DappModal extends Component { const manifest = dapp.manifest.content || {}; return ( -
+
{ this.renderInputs(dapp) }
@@ -206,7 +181,7 @@ export default class DappModal extends Component { } return ( -
+
@@ -339,46 +314,6 @@ export default class DappModal extends Component { ); } - stopEvent = (event) => { - event.stopPropagation(); - event.preventDefault(); - - return false; - } - - handleKeyPress = (event) => { - const codeName = keycode(event); - - if (codeName === 'esc') { - return this.handleClose(); - } - - return event; - } - - handleCloseKeyPress = (event) => { - const codeName = keycode(event); - - if (codeName === 'enter') { - return this.handleClose(); - } - - return event; - } - - handleOpen = () => { - if (!this.refs.container) { - return false; - } - - // Focus after the modal is open - setTimeout(() => { - const element = ReactDOM.findDOMNode(this.refs.container); - - element && element.focus(); - }, 50); - } - handleClose = () => { this.handleCancel(); this.props.onClose(); diff --git a/js/src/dapps/dappreg/Modal/modal.css b/js/src/dapps/dappreg/Modal/modal.css index 7375badaba8..fb7a7f494ea 100644 --- a/js/src/dapps/dappreg/Modal/modal.css +++ b/js/src/dapps/dappreg/Modal/modal.css @@ -16,97 +16,111 @@ */ @import '../_colors.css'; +@import '../_utils.css'; .modal { - .body { - bottom: 0; - left: 0; - position: fixed; - right: 0; - top: 0; - text-align: center; - z-index: 500; + align-items: center; + background-color: rgba(40, 40, 40, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 150; + + &.secondary { + align-items: flex-start; + z-index: 200; + + .content { + line-height: 1.5rem; + padding: 2rem; + text-align: center; + } .dialog { - background: #fff; - border-radius: 0 0 0.25em 0.25em; - margin: 0 auto; max-width: 840px; - text-align: left; - - .content { - line-height: 1.5em; - padding: 2em; - text-align: center; - - .section { - margin: 0; - padding: 0; - - &.error { - color: #f44; - } - - * { - overflow-x: hidden; - text-overflow: ellipsis; - } - } - - .section+.section { - margin-top: 1em; - } - } - - .footer { - padding: 0.5em 1.625em; - text-align: right; - } - - .header { - background: $blue; - color: #fff; - opacity: 0.85; - padding: 1em; - } + width: 85vw; } } +} + +.close { + composes: bezier-transform; + + color: #ddd; + display: inline-block; + font-family: 'Roboto Mono', monospace; + font-size: 2rem; + opacity: 0.75; + padding: 0; + position: absolute; + right: 1rem; + top: 0.25rem; + + &:hover { + cursor: pointer; + opacity: 1; + } + + &::before { + content: '❌'; + } +} + +.dialog { + background-color: rgba(255, 255, 255, 0.95); + display: flex; + flex-direction: column; + max-height: 90vh; + overflow: hidden; + position: relative; + max-width: 740px; + width: 75vw; - .overlay { - background: rgba(204, 204, 204, 0.7); - bottom: 0; - left: 0; - position: fixed; - right: 0; - top: 0; - z-index: 450; + > * { + padding: 0.5rem 1rem; } } -.account { - div { - display: inline-block; - vertical-align: top; +.content { + flex: 1 1 auto; + overflow: auto; + + .section { + margin: 0; + padding: 0; + + * { + overflow-x: hidden; + text-overflow: ellipsis; + } } - img { - border-radius: 50%; - margin-right: 0.5em; + .section + .section { + margin-top: 1em; } } -.hint { - display: block !important; - color: #888; - font-size: 0.75em; - margin-top: -0.5em; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; +.footer { + padding: 0.5em 1.625em; + text-align: right; } -.center { - text-align: center; +.header { + background-color: $blue; + color: white; + min-height: 3rem; + + &, + & > * { + align-items: center; + display: flex; + flex: 0 0 auto; + flex-direction: row; + } } .heading { diff --git a/js/src/dapps/dappreg/Modal/modal.js b/js/src/dapps/dappreg/Modal/modal.js index c3998cd29cf..7fe6d51705c 100644 --- a/js/src/dapps/dappreg/Modal/modal.js +++ b/js/src/dapps/dappreg/Modal/modal.js @@ -14,7 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import keycode from 'keycode'; import React, { Component, PropTypes } from 'react'; +import ReactDOM from 'react-dom'; import styles from './modal.css'; @@ -22,29 +24,102 @@ export default class Modal extends Component { static propTypes = { buttons: PropTypes.node, children: PropTypes.node, - header: PropTypes.string - } + header: PropTypes.node, + secondary: PropTypes.bool, + onClose: PropTypes.func.isRequired + }; + + static defaultProps = { + secondary: false + }; render () { - const { children, buttons, header } = this.props; + const { children, buttons, header, secondary } = this.props; + + const modalClasses = [ styles.modal ]; + + if (secondary) { + modalClasses.push(styles.secondary); + } return ( -
-
-
-
-
- { header } -
-
- { children } -
-
- { buttons } -
+
+
+
+ { header } +
+
+ +
+ { children }
+ + { + buttons + ? ( +
+ { buttons } +
+ ) + : null + }
); } + + stopEvent = (event) => { + event.stopPropagation(); + event.preventDefault(); + + return false; + } + + handleKeyPress = (event) => { + const codeName = keycode(event); + + if (codeName === 'esc') { + return this.handleClose(); + } + + return event; + } + + handleCloseKeyPress = (event) => { + const codeName = keycode(event); + + if (codeName === 'enter') { + return this.handleClose(); + } + + return event; + } + + handleSetRef = (containerRef) => { + // Focus after the modal is open + setTimeout(() => { + const element = ReactDOM.findDOMNode(containerRef); + + element && element.focus(); + }, 100); + } + + handleClose = () => { + this.props.onClose(); + } } diff --git a/js/src/dapps/dappreg/ModalDelete/modalDelete.js b/js/src/dapps/dappreg/ModalDelete/modalDelete.js index ce1976e8122..b4e3b06d42f 100644 --- a/js/src/dapps/dappreg/ModalDelete/modalDelete.js +++ b/js/src/dapps/dappreg/ModalDelete/modalDelete.js @@ -33,6 +33,8 @@ export default class ModalDelete extends Component { { this.renderConfirm() } diff --git a/js/src/dapps/dappreg/ModalRegister/modalRegister.js b/js/src/dapps/dappreg/ModalRegister/modalRegister.js index 363940fe4fd..7204d0c8ae3 100644 --- a/js/src/dapps/dappreg/ModalRegister/modalRegister.js +++ b/js/src/dapps/dappreg/ModalRegister/modalRegister.js @@ -40,6 +40,8 @@ export default class ModalRegister extends Component { { this.renderConfirm() } diff --git a/js/src/dapps/dappreg/ModalUpdate/modalUpdate.js b/js/src/dapps/dappreg/ModalUpdate/modalUpdate.js index 84d3f8c81ff..9f8888e89ec 100644 --- a/js/src/dapps/dappreg/ModalUpdate/modalUpdate.js +++ b/js/src/dapps/dappreg/ModalUpdate/modalUpdate.js @@ -34,6 +34,8 @@ export default class ModalUpdate extends Component { { this.renderConfirm() } From bc8d695534171d46873647b871e66139036a61f4 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 9 Mar 2017 15:44:40 +0100 Subject: [PATCH 25/34] Add Actions to Modal --- js/src/dapps/dappreg/Modal/modal.js | 53 ++++++++++++++----- .../dapps/dappreg/ModalDelete/modalDelete.js | 25 +++------ .../dappreg/ModalRegister/modalRegister.js | 25 +++------ .../dapps/dappreg/ModalUpdate/modalUpdate.js | 25 +++------ 4 files changed, 62 insertions(+), 66 deletions(-) diff --git a/js/src/dapps/dappreg/Modal/modal.js b/js/src/dapps/dappreg/Modal/modal.js index 7fe6d51705c..451950a4585 100644 --- a/js/src/dapps/dappreg/Modal/modal.js +++ b/js/src/dapps/dappreg/Modal/modal.js @@ -18,23 +18,27 @@ import keycode from 'keycode'; import React, { Component, PropTypes } from 'react'; import ReactDOM from 'react-dom'; +import Button from '../Button'; + import styles from './modal.css'; export default class Modal extends Component { static propTypes = { - buttons: PropTypes.node, + actions: PropTypes.array, children: PropTypes.node, header: PropTypes.node, secondary: PropTypes.bool, - onClose: PropTypes.func.isRequired + onClose: PropTypes.func.isRequired, + onConfirm: PropTypes.func }; static defaultProps = { + actions: null, secondary: false }; render () { - const { children, buttons, header, secondary } = this.props; + const { children, actions, header, secondary } = this.props; const modalClasses = [ styles.modal ]; @@ -69,20 +73,41 @@ export default class Modal extends Component { { children }
- { - buttons - ? ( -
- { buttons } -
- ) - : null - } + { actions ? this.renderActions(actions) : null }
); } + renderActions (actions) { + return ( +
+ { actions.map((action) => { + let onClick = () => {}; + + switch (action.type) { + case 'confirm': + onClick = this.handleConfirm; + break; + + case 'close': + onClick = this.handleClose; + break; + } + + return ( +
+ ); + } + stopEvent = (event) => { event.stopPropagation(); event.preventDefault(); @@ -119,6 +144,10 @@ export default class Modal extends Component { }, 100); } + handleConfirm = () => { + this.props.onConfirm && this.props.onConfirm(); + } + handleClose = () => { this.props.onClose(); } diff --git a/js/src/dapps/dappreg/ModalDelete/modalDelete.js b/js/src/dapps/dappreg/ModalDelete/modalDelete.js index b4e3b06d42f..d9672134bca 100644 --- a/js/src/dapps/dappreg/ModalDelete/modalDelete.js +++ b/js/src/dapps/dappreg/ModalDelete/modalDelete.js @@ -16,7 +16,6 @@ import React, { Component, PropTypes } from 'react'; -import Button from '../Button'; import Modal from '../Modal'; import styles from '../Modal/modal.css'; @@ -29,11 +28,17 @@ export default class ModalDelete extends Component { }; render () { + const actions = [ + { type: 'close', label: 'No, Cancel' }, + { type: 'confirm', label: 'Yes, Delete', warning: true } + ]; + return ( { this.renderConfirm() } @@ -41,22 +46,6 @@ export default class ModalDelete extends Component { ); } - renderButtons () { - return [ -
+ ); } - - handleClose = () => { - this.props.onClose(); - } - - handleDelete = () => { - const { dappId } = this.props; - - this.props.onDelete(dappId); - } } diff --git a/js/src/dapps/dappreg/ModalRegister/modalRegister.js b/js/src/dapps/dappreg/ModalRegister/modalRegister.js index 70ca64f9169..6b18cfeda3e 100644 --- a/js/src/dapps/dappreg/ModalRegister/modalRegister.js +++ b/js/src/dapps/dappreg/ModalRegister/modalRegister.js @@ -35,6 +35,7 @@ export default class ModalRegister extends Component { dappsStore = DappsStore.instance(); render () { + const { onClose, onRegister } = this.props; const actions = [ { type: 'close', label: 'No, Cancel' }, { type: 'confirm', label: 'Yes, Register', warning: true } @@ -44,18 +45,10 @@ export default class ModalRegister extends Component { - { this.renderConfirm() } - - ); - } - - renderConfirm () { - return ( -
You are about to register a new distributed application on the network, the details of this application is given below. This will require a non-refundable fee @@ -69,15 +62,7 @@ export default class ModalRegister extends Component { { this.props.dappId }
-
+ ); } - - handleCancel = () => { - this.props.onClose(); - } - - handleRegister = () => { - this.props.onRegister(); - } } diff --git a/js/src/dapps/dappreg/ModalUpdate/modalUpdate.js b/js/src/dapps/dappreg/ModalUpdate/modalUpdate.js index 25ca4da790e..051e56ddc51 100644 --- a/js/src/dapps/dappreg/ModalUpdate/modalUpdate.js +++ b/js/src/dapps/dappreg/ModalUpdate/modalUpdate.js @@ -29,6 +29,7 @@ export default class ModalUpdate extends Component { }; render () { + const { dappId, onClose, onConfirm } = this.props; const actions = [ { type: 'close', label: 'No, Cancel' }, { type: 'confirm', label: 'Yes, Update', warning: true } @@ -38,20 +39,10 @@ export default class ModalUpdate extends Component { - { this.renderConfirm() } - - ); - } - - renderConfirm () { - const { dappId } = this.props; - - return ( -
You are about to update the application details in the registry, the details of these updates are given below. Please note that each @@ -66,7 +57,7 @@ export default class ModalUpdate extends Component {
{ this.renderChanges() } -
+ ); } @@ -90,12 +81,4 @@ export default class ModalUpdate extends Component { ); }); } - - handleClose = () => { - this.props.onClose(); - } - - handleConfirm = () => { - this.props.onConfirm(); - } } From f86bc7f48e20eb5d0e810706a963851370cd80f9 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 9 Mar 2017 16:12:54 +0100 Subject: [PATCH 27/34] Better Close Icon --- js/assets/images/dapps/close.svg | 12 ++++++++++++ js/src/dapps/dappreg/Modal/modal.css | 20 ++++++++++++++------ js/src/dapps/dappreg/Modal/modal.js | 8 +++++++- 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 js/assets/images/dapps/close.svg diff --git a/js/assets/images/dapps/close.svg b/js/assets/images/dapps/close.svg new file mode 100644 index 00000000000..d46acd87298 --- /dev/null +++ b/js/assets/images/dapps/close.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/js/src/dapps/dappreg/Modal/modal.css b/js/src/dapps/dappreg/Modal/modal.css index fb7a7f494ea..6d70381d194 100644 --- a/js/src/dapps/dappreg/Modal/modal.css +++ b/js/src/dapps/dappreg/Modal/modal.css @@ -50,26 +50,34 @@ .close { composes: bezier-transform; - color: #ddd; + color: #fff; display: inline-block; font-family: 'Roboto Mono', monospace; - font-size: 2rem; + font-size: 4rem; opacity: 0.75; padding: 0; - position: absolute; + position: fixed; right: 1rem; top: 0.25rem; &:hover { cursor: pointer; opacity: 1; - } - &::before { - content: '❌'; + .closeIcon { + transform: rotate(135deg); + } } } +.closeIcon { + composes: bezier-transform; + + height: 3rem; + width: 3rem; + transform: rotate(45deg); +} + .dialog { background-color: rgba(255, 255, 255, 0.95); display: flex; diff --git a/js/src/dapps/dappreg/Modal/modal.js b/js/src/dapps/dappreg/Modal/modal.js index 451950a4585..d70ac1090c2 100644 --- a/js/src/dapps/dappreg/Modal/modal.js +++ b/js/src/dapps/dappreg/Modal/modal.js @@ -21,6 +21,7 @@ import ReactDOM from 'react-dom'; import Button from '../Button'; import styles from './modal.css'; +import CloseImage from '~/../assets/images/dapps/close.svg'; export default class Modal extends Component { static propTypes = { @@ -66,7 +67,12 @@ export default class Modal extends Component { onKeyPress={ this.handleCloseKeyPress } tabIndex={ open ? 0 : null } title='close' - /> + > + +
From 94a754559d3261fbf1f66bf83a9d9a5a3e77378d Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 9 Mar 2017 17:52:22 +0100 Subject: [PATCH 28/34] Single place for Registry version // Fetch meta-data from Registry --- js/src/contracts/registry.js | 55 +++++++++++++++++++-- js/src/dapps/dappreg/DappModal/dappModal.js | 9 ++++ js/src/dapps/dappreg/dappStore.js | 15 ++++++ js/src/dapps/dappreg/dappsStore.js | 44 +++++++++++++++-- js/src/dapps/registry/actions.js | 45 +++++------------ 5 files changed, 125 insertions(+), 43 deletions(-) diff --git a/js/src/contracts/registry.js b/js/src/contracts/registry.js index 80f54ea03df..cef31785e06 100644 --- a/js/src/contracts/registry.js +++ b/js/src/contracts/registry.js @@ -16,7 +16,14 @@ import * as abis from './abi'; +const REGISTRY_V1_HASHES = [ + '0x34f7c51bbb1b1902fbdabfdf04811100f5c9f998f26dd535d2f6f977492c748e', // ropsten + '0x64c3ee34851517a9faecd995c102b339f03e564ad6772dc43a26f993238b20ec' // homestead +]; + export default class Registry { + _registryContract = null; + constructor (api) { this._api = api; @@ -43,11 +50,10 @@ export default class Registry { this._fetching = true; - return this._api.parity - .registryAddress() - .then((address) => { + return this.fetchContract() + .then((contract) => { this._fetching = false; - this._instance = this._api.newContract(abis.registry, address).instance; + this._instance = contract.instance; this._queue.forEach((queued) => { queued.resolve(this._instance); @@ -89,6 +95,47 @@ export default class Registry { .then((contract) => contract.instance); } + fetchContract () { + if (this._registryContract) { + return Promise.resolve(this._registryContract); + } + + return this._api.parity + .registryAddress() + .then((address) => Promise.all([ address, this._api.eth.getCode(address) ])) + .then(([ address, code ]) => { + const codeHash = this._api.util.sha3(code); + const version = REGISTRY_V1_HASHES.includes(codeHash) + ? 1 + : 2; + const abi = version === 1 + ? abis.registry + : abis.registry2; + const contract = this._api.newContract(abi, address); + + // Add support for previous `set` and `get` methods + if (!contract.instance.get && contract.instance.getData) { + contract.instance.get = contract.instance.getData; + } + + if (contract.instance.get && !contract.instance.getData) { + contract.instance.getData = contract.instance.get; + } + + if (!contract.instance.set && contract.instance.setData) { + contract.instance.set = contract.instance.setData; + } + + if (contract.instance.set && !contract.instance.setData) { + contract.instance.setData = contract.instance.set; + } + + console.log(`registry at ${address}, code ${codeHash}, version ${version}`); + this._registryContract = contract; + return this._registryContract; + }); + } + _createGetParams (_name, key) { const name = _name.toLowerCase(); const sha3 = this._api.util.sha3.text(name); diff --git a/js/src/dapps/dappreg/DappModal/dappModal.js b/js/src/dapps/dappreg/DappModal/dappModal.js index 21da07b147f..cc5f14731de 100644 --- a/js/src/dapps/dappreg/DappModal/dappModal.js +++ b/js/src/dapps/dappreg/DappModal/dappModal.js @@ -139,6 +139,11 @@ export default class DappModal extends Component { label='Save' onClick={ this.handleSave } /> +
+ ); + } + const { isEditing } = dapp; const { updating } = this.state; @@ -375,9 +388,7 @@ export default class DappModal extends Component { } handleDeleteConfirm = () => { - const { id, owner } = this.props.dapp; - - this.dappsStore.delete(id, owner.address); + this.dappsStore.delete(this.props.dapp); this.handleDeleteClose(); this.handleClose(); } diff --git a/js/src/dapps/dappreg/dappStore.js b/js/src/dapps/dappreg/dappStore.js index 81af8932af1..bef02729d03 100644 --- a/js/src/dapps/dappreg/dappStore.js +++ b/js/src/dapps/dappreg/dappStore.js @@ -27,8 +27,11 @@ export default class DappStore { @observable isEditing = false; @observable wip = null; + contractOwner = ''; + isContractOwner = false; + constructor (data) { - const { id, content = {}, image = {}, manifest = {}, owner = {}, isOwner } = data; + const { id, content = {}, image = {}, manifest = {}, owner = {}, isOwner = false, contractOwner = '', isContractOwner = false } = data; transaction(() => { this.id = id; @@ -40,6 +43,9 @@ export default class DappStore { this.copyToWip(); }); + + this.contractOwner = contractOwner; + this.isContractOwner = isContractOwner; } @computed get canSave () { diff --git a/js/src/dapps/dappreg/dappsStore.js b/js/src/dapps/dappreg/dappsStore.js index d1f045e666a..ea2e6f05428 100644 --- a/js/src/dapps/dappreg/dappsStore.js +++ b/js/src/dapps/dappreg/dappsStore.js @@ -214,11 +214,11 @@ export default class DappsStore { .then(() => this._loadDapps()); } - delete (dappId, dappOwner) { + delete (dapp) { const dappRegInstance = this._instanceReg; - return deleteDapp(dappId, dappOwner, dappRegInstance) - .then((request) => this.trackRequest(request, `Deleting ${dappId}`)) + return deleteDapp(dapp, dappRegInstance) + .then((request) => this.trackRequest(request, `Deleting ${dapp.id}`)) .then(() => this._loadDapps()); } @@ -393,6 +393,8 @@ export default class DappsStore { const { content, image, manifest } = data; const dapp = new Dapp({ + contractOwner: this.contractOwner, + isContractOwner: this.isContractOwner, id, content, image, diff --git a/js/src/dapps/dappreg/utils.js b/js/src/dapps/dappreg/utils.js index 037dbde8b7d..4e13373e183 100644 --- a/js/src/dapps/dappreg/utils.js +++ b/js/src/dapps/dappreg/utils.js @@ -91,10 +91,16 @@ export const registerDapp = (dappId, dappRegInstance) => { }); }; -export const deleteDapp = (dappId, dappOwner, dappRegInstance) => { - const values = [ dappId ]; +export const deleteDapp = (dapp, dappRegInstance) => { + const { id, owner } = dapp; + + const fromAddress = dapp.isOwner + ? owner.address + : dapp.contractOwner; + + const values = [ id ]; const options = { - from: dappOwner + from: fromAddress }; return dappRegInstance