diff --git a/app.js b/app.js index 62d4fb75..99a879e5 100644 --- a/app.js +++ b/app.js @@ -29,6 +29,7 @@ app.use(require('./models/inspect')) app.use(require('./models/download')) app.use(require('./models/drag-drop')) app.use(require('./models/dats')) +app.use(require('./models/user')) app.use(require('./models/error')) app.route('/', require('./pages/main')) diff --git a/elements/header.js b/elements/header.js index 91c6888e..5b3353eb 100644 --- a/elements/header.js +++ b/elements/header.js @@ -1,10 +1,11 @@ 'use strict' +const version = require('../package.json').version const microcomponent = require('microcomponent') +const gravatar = require('gravatar') const html = require('choo/html') const assert = require('assert') const css = require('sheetify') -const version = require('../package.json').version const button = require('./button') const DatImport = require('./dat-import') @@ -30,7 +31,49 @@ const shareButtonIcon = css` const menuButtonIcon = css` :host { - width: 1.75em; + width: 1em; + } +` + +const avatarButtonStyles = css` + :host { + border: 2px solid var(--color-neutral-40); + vertical-align: middle; + background-color: var(--color-pink); + &:hover, &:focus { + border-color: var(--color-white); + } + } +` + +const menuStyles = css` + :host { + width: 14rem; + padding-left: 1rem; + padding-right: 1rem; + position: absolute; + z-index: 2; + top: 3rem; + right: 0; + border: 1px solid var(--color-neutral-20); + border-radius: .25rem; + background-color: var(--color-white); + color: var(--color-neutral-60); + box-shadow: 0 0 4px 2px rgba( 0, 0, 0, .1); + section { + padding-top: 1rem; + padding-bottom: 1rem; + &:first-child { + border-bottom: 1px solid var(--color-neutral-20); + } + } + a { + text-decoration: none; + color: var(--color-neutral-80); + &:hover, &:focus { + color: var(--color-blue-hover); + } + } } ` @@ -42,7 +85,7 @@ function HeaderElement () { return component function render () { - var { isReady, onimport, oncreate, onreport } = this.props + var { isReady, session, onimport, oncreate, onreport, onlogin, onlogout, onprofile, onhomepage } = this.props var { showMenu, willShowMenu } = this.state if (typeof willShowMenu === 'boolean') { @@ -65,16 +108,37 @@ function HeaderElement () { onclick: oncreate }) - var loginButton = button.header('Log In', { - class: 'ml3 v-mid color-neutral-30 hover-color-white f7 f6-l dn' + var loginButton = button.green('Log In', { + class: 'ml3 v-mid color-neutral-30 hover-color-white f7 f6-l', + onclick: onlogin }) var menuButton = button.icon('Open Menu', { - icon: icon('menu', { class: menuButtonIcon }), + icon: icon('info', { class: menuButtonIcon }), class: 'ml3 v-mid color-neutral-20 hover-color-white pointer', onclick: toggle }) + var avatar = { + size: 26 + } + if (session) { + avatar.url = gravatar.url(session.email, { + s: avatar.size * 2, + r: 'pg', + d: '404', + protocol: 'https' + }) + } + + var avatarButton = html` + + ` + function toggle () { if (component.state.showMenu) hide() else show() @@ -96,6 +160,11 @@ function HeaderElement () { if (!component._element.contains(e.target)) hide() } + function onclicklogout () { + component.state.willShowMenu = false + onlogout() + } + return html`
@@ -103,20 +172,47 @@ function HeaderElement () { onsubmit: onimport })} ${createButton} - ${loginButton} - ${menuButton} + ${session + ? html` + ${avatarButton} + ` + : html` + + ${menuButton} + ${loginButton} + + `} ${showMenu ? html` -
-

- Dat Desktop ${version} -

-

- Dat Desktop is a peer to peer sharing app built for humans by humans. -

-

- Report Bug -

+
+ ${session + ? html` +
+ ${session.email} +
+ ` + : html` +
+ Dat Desktop is a peer to peer sharing app built for humans by humans. +
+ `} +
+ ${session + ? html` + Profile + ` + : ''} + Report Bug + ${session + ? html` + Log out + ` + : ''} +
+
+ Version ${version} | Built by + datproject.org +
` : ''} @@ -127,6 +223,7 @@ function HeaderElement () { function update (props) { return props.isReady !== this.props.isReady || - typeof this.state.willShowMenu === 'boolean' + typeof this.state.willShowMenu === 'boolean' || + props.session !== this.props.session } } diff --git a/elements/input.js b/elements/input.js new file mode 100644 index 00000000..08f6c007 --- /dev/null +++ b/elements/input.js @@ -0,0 +1,82 @@ +'use strict' + +const microcomponent = require('microcomponent') +const html = require('choo/html') +const css = require('sheetify') +const icon = require('./icon') + +var baseStyles = css` + :host { + --input-height: 2.75rem; + --icon-height: 1.2rem; + height: var(--input-height); + border: 0; + svg { + position: absolute; + top: 0; + bottom: 0; + left: 0; + padding-top: calc(var(--icon-height) - .35rem); + padding-left: .75rem; + pointer-events: none; + display: block; + width: var(--icon-height); + height: var(--icon-height); + transition: color .025s ease-out; + color: var(--color-neutral-30); + } + input { + width: 100%; + height: var(--input-height); + position: relative; + padding-top: 0; + padding-right: .5rem; + padding-bottom: 0; + padding-left: 2.5rem; + font-size: 1rem; + font-weight: 600; + border: 1px solid var(--color-neutral-20); + background-color: var(--color-white); + color: var(--color-green-hover); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + &:hover, + &:focus { + outline: none; + } + } + } +` + +module.exports = inputElement + +function inputElement (name) { + var component = microcomponent(`input-${name}`) + component.on('render', render) + component.on('update', update) + return component + + function render () { + var { name, type, placeholder, value, icon: inputIcon } = this.props + var classNames = baseStyles + if (this.props.class) classNames += ' ' + this.props.class + + return html` + + ` + } + + function update () { + return false + } +} diff --git a/elements/login.js b/elements/login.js new file mode 100644 index 00000000..9daf27e2 --- /dev/null +++ b/elements/login.js @@ -0,0 +1,93 @@ +var microcomponent = require('microcomponent') +var html = require('choo/html') +var input = require('./input') +var button = require('./button') +var FormData = window.FormData + +module.exports = function () { + var component = microcomponent({ + name: 'login', + state: { + email: '', + password: '', + inputs: { + email: input('email'), + password: input('password') + } + } + }) + component.on('render', render) + component.on('update', update) + return component + + function render () { + var { onlogin, onregister, onresetpassword, onexit, error } = this.props + var { email, password, inputs } = this.state + + function onsubmit (ev) { + ev.preventDefault() + var data = new FormData(ev.target) + var email = data.get('email') + var password = data.get('password') + onlogin({ email, password }) + Object.assign(component.state, { email, password }) + } + + function onclickresetpassword (ev) { + ev.preventDefault() + onresetpassword() + } + + function onclickregister (ev) { + ev.preventDefault() + onregister() + } + + return html` +
+
+

Log In

+
+ + ${inputs.email.render({ + type: 'email', + name: 'email', + placeholder: 'E-Mail', + icon: 'letter', + value: email + })} + + ${inputs.password.render({ + type: 'password', + name: 'password', + placeholder: 'Password', + icon: 'lock', + value: password + })} + + ${button.green('Log In', { + class: 'w-100 mb3' + })} + +

+ + +

+
+ ${error + ? html` +

+ Oops. ${error.message} +

+ ` + : ''} + +
+
+ ` + } + + function update (props) { + return props.error !== this.props.error + } +} diff --git a/elements/modal.js b/elements/modal.js index a2cbafe9..d49c8e99 100644 --- a/elements/modal.js +++ b/elements/modal.js @@ -137,7 +137,7 @@ function confirmModal () { return Modal({ render: render, onexit: onexit, - class: 'modal' + class: 'modal bg-black-20' }) function onexit () { @@ -256,7 +256,7 @@ function errorModal () { return Modal({ render: render, onexit: onexit, - class: 'modal' + class: 'modal bg-black-20' }) function render (message) { @@ -293,7 +293,7 @@ function warningModal () { return Modal({ render: render, onexit: onexit, - class: 'modal' + class: 'modal bg-black-20' }) function render (message) { @@ -335,7 +335,7 @@ function linkModal () { onunload: onunload, onexit: onexit, render: render, - class: 'modal' + class: 'modal bg-black-20' }) return modal diff --git a/elements/register.js b/elements/register.js new file mode 100644 index 00000000..492dd2ff --- /dev/null +++ b/elements/register.js @@ -0,0 +1,96 @@ +var microcomponent = require('microcomponent') +var html = require('choo/html') +var input = require('./input') +var button = require('./button') +var FormData = window.FormData + +module.exports = function () { + var component = microcomponent({ + name: 'register', + state: { + username: '', + email: '', + password: '', + inputs: { + username: input('username'), + email: input('email'), + password: input('password') + } + } + }) + component.on('render', render) + component.on('update', update) + return component + + function render () { + var { onregister, onlogin, error } = this.props + var { username, email, password, inputs } = this.state + + function onsubmit (ev) { + ev.preventDefault() + var data = new FormData(ev.target) + var username = data.get('username') + var email = data.get('email') + var password = data.get('password') + onregister({ username, email, password }) + Object.assign(component.state, { username, email, password }) + } + + function onclicklogin (ev) { + ev.preventDefault() + onlogin() + } + + return html` +
+
+

Create A New Account

+
+ + ${inputs.username.render({ + type: 'text', + name: 'username', + placeholder: 'Username', + icon: 'happy-dat', + value: username + })} + + ${inputs.email.render({ + type: 'email', + name: 'email', + placeholder: 'E-Mail', + icon: 'letter', + value: email + })} + + ${inputs.password.render({ + type: 'password', + name: 'password', + placeholder: 'Password', + icon: 'lock', + value: password + })} + + ${button.green('Register', { + class: 'w-100 mb3' + })} +

+ +

+
+ ${error + ? html` +

+ Oops. ${error.message} +

+ ` + : ''} +
+
+ ` + } + + function update (props) { + return props.error !== this.props.error + } +} diff --git a/elements/reset-password.js b/elements/reset-password.js new file mode 100644 index 00000000..80d7337e --- /dev/null +++ b/elements/reset-password.js @@ -0,0 +1,46 @@ +var microcomponent = require('microcomponent') +var html = require('choo/html') +var FormData = window.FormData + +module.exports = function () { + var component = microcomponent({ + name: 'reset-password', + state: { + email: '' + } + }) + component.on('render', render) + component.on('update', update) + return component + + function render () { + var { onreset, error } = this.props + var { email } = this.state + + function onsubmit (ev) { + ev.preventDefault() + var data = new FormData(ev.target) + var email = data.get('email') + onreset({ email }) + Object.assign(component.state, { email }) + } + + return html` +
+
+ + +
+ ${error + ? html` +
Error! ${error.message}
+ ` + : ''} +
+ ` + } + + function update (props) { + return props.error !== this.props.error + } +} diff --git a/models/user.js b/models/user.js new file mode 100644 index 00000000..b76a9a2b --- /dev/null +++ b/models/user.js @@ -0,0 +1,76 @@ +var Registry = require('dat-registry') +var xtend = Object.assign + +var registry = Registry() + +module.exports = userModel + +function userModel (state, bus) { + state.user = state.user || {} + state.user = xtend(state.user, { + show: null, + loginError: null, + registerError: null, + session: state.user.session + }) + + bus.on('user:login', function () { + state.user.show = 'login' + bus.emit('render') + }) + + bus.on('user:login!', function (data) { + if (!data) { + state.user.show = null + bus.emit('render') + } + registry.login(data, function (err, res, session) { + if (err) { + state.user.loginError = err + bus.emit('render') + return + } + state.user.show = null + state.user.session = session + bus.emit('render') + }) + }) + + bus.on('user:register', function () { + state.user.show = 'register' + bus.emit('render') + }) + + bus.on('user:register!', function (data) { + registry.register(data, function (err, res, session) { + if (err) { + state.user.registerError = err + bus.emit('render') + return + } + state.user.show = null + state.user.session = session + bus.emit('render') + }) + }) + + bus.on('user:logout', function () { + registry.logout(function (err) { + if (err) console.error(err) + state.user.session = null + bus.emit('render') + }) + }) + + bus.on('user:reset-password', function () { + state.user.show = 'reset password' + bus.emit('render') + }) + + bus.on('user:reset-password!', function (data) { + registry.users.resetPassword(data, function (err) { + if (err) console.error(err) + bus.emit('render') + }) + }) +} diff --git a/package-lock.json b/package-lock.json index 1c9ef1db..22834854 100644 --- a/package-lock.json +++ b/package-lock.json @@ -394,6 +394,11 @@ "resolved": "https://registry.npmjs.org/bluebird-lst-c/-/bluebird-lst-c-1.0.6.tgz", "integrity": "sha1-gfiB0T+d9wD2fVd/E0gLwy2Eu6k=" }, + "blueimp-md5": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.7.0.tgz", + "integrity": "sha1-f1GODdcEZ/7+KOy6OYkWCS8qAqk=" + }, "bn.js": { "version": "4.11.7", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.7.tgz", @@ -585,8 +590,7 @@ "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, "builtin-status-codes": { "version": "3.0.0", @@ -670,14 +674,29 @@ "dev": true }, "choo": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/choo/-/choo-5.6.2.tgz", - "integrity": "sha1-WWn6CiyN0Ne0v233vUR9HlmGL+A=", + "version": "6.0.0-2", + "resolved": "https://registry.npmjs.org/choo/-/choo-6.0.0-2.tgz", + "integrity": "sha1-xAFwwYorYvtups/szzqxxbVm2S4=", "dependencies": { - "nanomorph": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/nanomorph/-/nanomorph-4.0.5.tgz", - "integrity": "sha1-fifMXiigXfDCePU7pDDyU/OsP6w=" + "bel": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/bel/-/bel-5.0.2.tgz", + "integrity": "sha1-VMALa7D5m24o/d37iIQhmr4AjKs=" + }, + "nanobus": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/nanobus/-/nanobus-4.2.0.tgz", + "integrity": "sha1-T/6wNlsDPXp8xPDI7lyMGqmzK6w=" + }, + "nanohref": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/nanohref/-/nanohref-3.0.0.tgz", + "integrity": "sha1-wysD4KJY+1/pELtqT+yoESC5RHI=" + }, + "nanotiming": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/nanotiming/-/nanotiming-6.1.0.tgz", + "integrity": "sha1-HWckoYn8LaLvDV6BKMXLEwP7vFI=" } } }, @@ -747,8 +766,7 @@ "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=" }, "clone": { "version": "1.0.2", @@ -764,8 +782,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "codecs": { "version": "1.2.0", @@ -1099,6 +1116,11 @@ "resolved": "https://registry.npmjs.org/dat-node/-/dat-node-3.5.1.tgz", "integrity": "sha512-z1kUQ823PVqZuemP3YWDPIvbQpLaaWGaKcf6MOVBZr3HHVvRRydxTqnidP0sQg3FhbOnxldSRNCO4ZvQ7swPdQ==" }, + "dat-registry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dat-registry/-/dat-registry-3.0.3.tgz", + "integrity": "sha512-BWxQlSFQWc5BsIepOw9ZvbzsKkb2h+3lfCFC5pisNjzLdRbvyRuCQn0MicsBYeyCxAe/bNah21KgVPYbp6G1Ng==" + }, "dat-secret-storage": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/dat-secret-storage/-/dat-secret-storage-4.0.0.tgz", @@ -1152,8 +1174,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "deep-equal": { "version": "1.0.1", @@ -1522,6 +1543,11 @@ "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", "dev": true }, + "email-validator": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/email-validator/-/email-validator-1.0.7.tgz", + "integrity": "sha1-RiHKMvx0HrgzrJjV+1VnC34FbJU=" + }, "end-of-stream": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", @@ -1567,8 +1593,7 @@ "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=" }, "es-abstract": { "version": "1.7.0", @@ -1946,8 +1971,7 @@ "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=" }, "flat-cache": { "version": "1.2.2", @@ -2734,8 +2758,7 @@ "get-caller-file": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", - "dev": true + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" }, "get-stdin": { "version": "4.0.1", @@ -2818,6 +2841,11 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, + "gravatar": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/gravatar/-/gravatar-1.6.0.tgz", + "integrity": "sha1-i9ybeGynJajnB2QW0XMfjTMxyXY=" + }, "har-schema": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", @@ -2880,8 +2908,7 @@ "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", - "dev": true + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" }, "htmlescape": { "version": "1.1.1", @@ -3131,8 +3158,7 @@ "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, "ip": { "version": "1.1.5", @@ -3142,8 +3168,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-binary-path": { "version": "1.0.1", @@ -3159,8 +3184,7 @@ "is-builtin-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=" }, "is-callable": { "version": "1.1.3", @@ -3184,6 +3208,11 @@ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" }, + "is-electron": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.0.0.tgz", + "integrity": "sha1-yC01mWQPffkchOqu52vFZxPGrHk=" + }, "is-electron-renderer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-electron-renderer/-/is-electron-renderer-2.0.1.tgz", @@ -3213,8 +3242,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=" }, "is-function": { "version": "1.0.1", @@ -3324,6 +3352,11 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-string": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.4.tgz", + "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=" + }, "is-symbol": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", @@ -3344,8 +3377,7 @@ "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" }, "isarray": { "version": "0.0.1", @@ -3551,8 +3583,7 @@ "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=" }, "lcov-parse": { "version": "0.0.10", @@ -3579,8 +3610,7 @@ "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=" }, "localenv": { "version": "0.2.2", @@ -3955,25 +3985,15 @@ "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.0.0.tgz", "integrity": "sha1-VVoRIL8mXh0zMy73tYA3ENXiCv8=" }, - "nanobus": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/nanobus/-/nanobus-3.3.0.tgz", - "integrity": "sha1-vOXV1DWlNix9rX+ekM0hlZWJvoY=" - }, "nanocomponent": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/nanocomponent/-/nanocomponent-2.0.3.tgz", "integrity": "sha1-yupqOad9l+T3HanCo15hl8cLcus=" }, - "nanohistory": { + "nanolocation": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/nanohistory/-/nanohistory-1.0.0.tgz", - "integrity": "sha1-ZaPSm8X0D2MF7GfRILi+OOlXGeg=" - }, - "nanohref": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/nanohref/-/nanohref-1.0.0.tgz", - "integrity": "sha1-Eu1e6ZDZgRE0SgTYFlDRZ60mRCE=" + "resolved": "https://registry.npmjs.org/nanolocation/-/nanolocation-1.0.0.tgz", + "integrity": "sha1-FbXHrwWJXRqfIfDRNkldmURQaGs=" }, "nanologger": { "version": "1.1.0", @@ -3985,17 +4005,10 @@ "resolved": "https://registry.npmjs.org/nanomorph/-/nanomorph-5.1.2.tgz", "integrity": "sha1-ZtElCYco5UsOyqDISYA205XT8l0=" }, - "nanomount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nanomount/-/nanomount-1.0.1.tgz", - "integrity": "sha1-2m5MRG8EaiDVqHv8OmFSvimJDTU=", - "dependencies": { - "nanomorph": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/nanomorph/-/nanomorph-4.0.5.tgz", - "integrity": "sha1-fifMXiigXfDCePU7pDDyU/OsP6w=" - } - } + "nanoquery": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nanoquery/-/nanoquery-1.1.0.tgz", + "integrity": "sha1-g6giCTNAygU9aW7IYKEKWsTDtEI=" }, "nanoraf": { "version": "3.0.1", @@ -4007,11 +4020,6 @@ "resolved": "https://registry.npmjs.org/nanorouter/-/nanorouter-2.1.0.tgz", "integrity": "sha1-T8r5YgOgCJjaiRiLG/9aj8Bu9P8=" }, - "nanotiming": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nanotiming/-/nanotiming-1.0.1.tgz", - "integrity": "sha1-E+ei4nZ5Z5dP7f/wce3Tkyf0TsM=" - }, "nested-error-stacks": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", @@ -4125,8 +4133,7 @@ "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==" }, "normalize-path": { "version": "2.1.1", @@ -4154,8 +4161,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nyc": { "version": "11.0.3", @@ -5349,8 +5355,7 @@ "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=" }, "os-tmpdir": { "version": "1.0.2", @@ -5431,8 +5436,7 @@ "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=" }, "parse-ms": { "version": "1.0.1", @@ -5449,8 +5453,7 @@ "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=" }, "path-is-absolute": { "version": "1.0.1", @@ -5483,8 +5486,7 @@ "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=" }, "pause-stream": { "version": "0.0.11", @@ -5498,6 +5500,11 @@ "integrity": "sha1-vjZ4XFBn6kjYBv+SMojF91C2uKI=", "dev": true }, + "pelo": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/pelo/-/pelo-0.0.2.tgz", + "integrity": "sha1-pdQHrT+SGpG40bNF+zigMM9YeW8=" + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -5512,20 +5519,17 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=" }, "pkg-config": { "version": "1.1.1", @@ -5749,8 +5753,7 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, "querystring-es3": { "version": "0.2.1", @@ -5846,14 +5849,12 @@ "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=" }, "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=" }, "readable-stream": { "version": "2.3.3", @@ -5961,14 +5962,12 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, "require-uncached": { "version": "1.0.3", @@ -6062,6 +6061,11 @@ "integrity": "sha1-YS2hyWRz+gLczaktzVtKsWSmdyo=", "dev": true }, + "scroll-to-anchor": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/scroll-to-anchor/-/scroll-to-anchor-1.1.0.tgz", + "integrity": "sha1-yZuNLl2VBWdSeHyngJWrdbUgs/0=" + }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", @@ -6076,8 +6080,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-immediate-shim": { "version": "1.0.1", @@ -6264,20 +6267,17 @@ "spdx-correct": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "dev": true + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=" }, "spdx-expression-parse": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", - "dev": true + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" }, "spdx-license-ids": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", - "dev": true + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" }, "spectron": { "version": "3.7.2", @@ -6532,8 +6532,7 @@ "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=" }, "string.prototype.codepointat": { "version": "0.2.0", @@ -6560,8 +6559,7 @@ "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=" }, "strip-eof": { "version": "1.0.0", @@ -6833,6 +6831,11 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=" }, + "township-client": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/township-client/-/township-client-1.3.1.tgz", + "integrity": "sha1-wBY7DLXZl/6NDWDrH1Uqj70VI9A=" + }, "trim": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", @@ -7048,8 +7051,7 @@ "validate-npm-package-license": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "dev": true + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=" }, "validator": { "version": "7.0.0", @@ -7177,8 +7179,7 @@ "which-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" }, "widest-line": { "version": "1.0.0", @@ -7194,8 +7195,7 @@ "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=" }, "wrappy": { "version": "1.0.2", @@ -7250,8 +7250,7 @@ "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" }, "yallist": { "version": "2.1.2", @@ -7269,13 +7268,11 @@ "version": "6.6.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", - "dev": true, "dependencies": { "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" } } }, @@ -7283,13 +7280,11 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", - "dev": true, "dependencies": { "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" } } }, diff --git a/package.json b/package.json index edd9a3af..31de208a 100644 --- a/package.json +++ b/package.json @@ -8,21 +8,23 @@ "author": "Dat Team", "dependencies": { "base-elements": "^2.2.1", - "choo": "^5.1.0", + "choo": "^6.0.0-2", "choo-expose": "^1.0.0", "choo-log": "^6.0.0", "choo-persist": "^3.0.0", "dat-colors": "^3.5.0", "dat-doctor": "^1.2.2", "dat-encoding": "^4.0.1", - "dat-icons": "^2.2.0", + "dat-icons": "^2.5.1", "dat-node": "^3.2.3", + "dat-registry": "^3.0.3", "delegate-electron-events": "^1.0.1", "electron-auto-updater": "^0.9.2", "electron-default-menu": "^1.0.0", "electron-window": "^0.8.1", "envobj": "^1.0.2", "explain-error": "^1.0.3", + "gravatar": "^1.6.0", "microcomponent": "^3.1.6", "minimist": "^1.2.0", "mirror-folder": "^2.1.0", @@ -30,7 +32,7 @@ "ms": "^0.7.2", "multidat": "^5.0.1", "nanologger": "^1.0.2", - "nanomorph": "^5.0.0", + "nanomorph": "^5.1.2", "prettier-bytes": "^1.0.3", "rimraf": "^2.5.4", "run-waterfall": "^1.1.3", diff --git a/pages/main.js b/pages/main.js index 6434a2a8..f322c51b 100644 --- a/pages/main.js +++ b/pages/main.js @@ -3,23 +3,29 @@ const html = require('choo/html') const shell = require('electron').shell +const ResetPassword = require('../elements/reset-password') const StatusBar = require('../elements/status-bar') const Download = require('../elements/download') +const Register = require('../elements/register') const Inspect = require('../elements/inspect') const Header = require('../elements/header') const Sprite = require('../elements/sprite') const Table = require('../elements/table') const Intro = require('../elements/intro') const Empty = require('../elements/empty') +const Login = require('../elements/login') module.exports = mainView +const resetPassword = ResetPassword() const statusBar = StatusBar() const download = Download() +const register = Register() const inspect = Inspect() const header = Header() const sprite = Sprite() const intro = Intro() +const login = Login() // render the main view // (obj, obj, fn) -> html @@ -31,9 +37,14 @@ function mainView (state, emit) { const isReady = state.dats.ready const headerProps = { isReady: isReady, + session: state.user.session, oncreate: () => emit('dats:create'), onimport: (link) => emit('dats:download', link), - onreport: () => shell.openExternal('https://github.com/datproject/dat-desktop/issues') + onreport: () => shell.openExternal('https://github.com/datproject/dat-desktop/issues'), + onhomepage: () => shell.openExternal('https://datproject.org/'), + onprofile: () => shell.openExternal(`https://datproject.org/profile/${state.user.session.username}`), + onlogin: () => emit('user:login'), + onlogout: () => emit('user:logout') } document.title = 'Dat Desktop' @@ -90,6 +101,57 @@ function mainView (state, emit) { ` } + if (state.user.show === 'login') { + return html` +
+ ${sprite.render()} + ${header.render(headerProps)} + ${login.render({ + onlogin: data => emit('user:login!', data), + onregister: () => emit('user:register'), + onresetpassword: () => emit('user:reset-password'), + onexit: () => emit('user:login!', false), + error: state.user.loginError + })} + ${statusBar.render(state.dats.speed)} +
+ ` + } + + if (state.user.show === 'register') { + return html` +
+ ${sprite.render()} + ${header.render(headerProps)} + ${register.render({ + onregister: data => { + emit('user:register!', data) + }, + onlogin: () => { + emit('user:login') + }, + error: state.user.registerError + })} + ${statusBar.render(state.dats.speed)} +
+ ` + } + + if (state.user.show === 'reset password') { + return html` +
+ ${sprite.render()} + ${header.render(headerProps)} + ${resetPassword.render({ + onreset: data => { + emit('user:reset-password!', data) + } + })} + ${statusBar.render(state.dats.speed)} +
+ ` + } + if (!dats.length) { return html`