diff --git a/.gitignore b/.gitignore index e77c88ec..c32ac8f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,12 @@ server/public/js -server/public/index.html +server/public/index.html node_modules/ babel_cache/ .DS_Store \#*\# -.\#* +.\#* *.log *~ *.swp *.swo - \ No newline at end of file +.tern-port \ No newline at end of file diff --git a/client/assets/bucket.svg b/client/assets/bucket.svg new file mode 100644 index 00000000..8380a9bb --- /dev/null +++ b/client/assets/bucket.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/client/assets/delete.svg b/client/assets/delete.svg new file mode 100644 index 00000000..f7358b02 --- /dev/null +++ b/client/assets/delete.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/assets/download.svg b/client/assets/download.svg new file mode 100644 index 00000000..ee148bd4 --- /dev/null +++ b/client/assets/download.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/client/assets/dropbox.png b/client/assets/dropbox.png new file mode 100644 index 00000000..19515de3 Binary files /dev/null and b/client/assets/dropbox.png differ diff --git a/client/assets/edit.svg b/client/assets/edit.svg new file mode 100644 index 00000000..463b377e --- /dev/null +++ b/client/assets/edit.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/client/assets/error.svg b/client/assets/error.svg new file mode 100644 index 00000000..e5bcec14 --- /dev/null +++ b/client/assets/error.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/assets/file.svg b/client/assets/file.svg new file mode 100644 index 00000000..3803ac02 --- /dev/null +++ b/client/assets/file.svg @@ -0,0 +1,4 @@ + + + + diff --git a/client/assets/folder copy.svg b/client/assets/folder copy.svg new file mode 100644 index 00000000..f1b08731 --- /dev/null +++ b/client/assets/folder copy.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/client/assets/folder.svg b/client/assets/folder.svg new file mode 100644 index 00000000..f1b08731 --- /dev/null +++ b/client/assets/folder.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/client/assets/google-drive.png b/client/assets/google-drive.png new file mode 100644 index 00000000..7d0135b0 Binary files /dev/null and b/client/assets/google-drive.png differ diff --git a/client/assets/link.svg b/client/assets/link.svg new file mode 100644 index 00000000..f1b08731 --- /dev/null +++ b/client/assets/link.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/client/assets/loader.svg b/client/assets/loader.svg new file mode 100644 index 00000000..f997200a --- /dev/null +++ b/client/assets/loader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/assets/loader_white.svg b/client/assets/loader_white.svg new file mode 100644 index 00000000..ad3b741a --- /dev/null +++ b/client/assets/loader_white.svg @@ -0,0 +1 @@ + diff --git a/client/assets/pause.svg b/client/assets/pause.svg new file mode 100644 index 00000000..7c8b0090 --- /dev/null +++ b/client/assets/pause.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/assets/play.svg b/client/assets/play.svg new file mode 100644 index 00000000..f22527cf --- /dev/null +++ b/client/assets/play.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/assets/power.svg b/client/assets/power.svg new file mode 100644 index 00000000..06e7e0ba --- /dev/null +++ b/client/assets/power.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/assets/save.svg b/client/assets/save.svg new file mode 100644 index 00000000..6cec20d4 --- /dev/null +++ b/client/assets/save.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/pages/connectpage.js b/client/pages/connectpage.js index 8a714f41..d388e177 100644 --- a/client/pages/connectpage.js +++ b/client/pages/connectpage.js @@ -17,9 +17,11 @@ export class ConnectPage extends React.Component { remember_me: window.localStorage.hasOwnProperty('credentials') ? true : false, loading: false, error: null, - marginTop: this._marginTop() + doing_a_third_party_login: false }; + } + componentDidMount(){ // adapted from: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript function getParam(name) { const regex = new RegExp("[?&#]" + name.replace(/[\[\]]/g, "\\$&") + "(=([^&#]*)|&|#|$)"); @@ -31,76 +33,54 @@ export class ConnectPage extends React.Component { // dropbox login if(getParam('state') === 'dropbox'){ - this.state.loading = true; this.authenticate({bearer: getParam('access_token'), type: 'dropbox'}); + this.setState({doing_a_third_party_login: true}); } // google drive login if(getParam('code')){ - this.state.loading = true; this.authenticate({code: getParam('code'), type: 'gdrive'}); + this.setState({doing_a_third_party_login: true}); } } - componentWillMount(){ - window.onresize = () => { - this.setState({marginTop: this._marginTop()}); - }; - } - _marginTop(){ - let size = Math.round(Math.abs((document.body.offsetHeight - 300) / 2)); - return size > 150? 150 : size; - } - authenticate(params){ - if(params.type === 'dropbox') return this.login_dropbox(); - else if(params.type === 'gdrive') return this.login_google(); - this.setState({loading: true}); Session.authenticate(params) .then((ok) => { - this.setState({loading: false}); invalidate(); const path = params.path && /^\//.test(params.path)? /\/$/.test(params.path) ? params.path : params.path+'/' : '/'; this.props.history.push('/files'+path); }) .catch(err => { - if(err && err.code === 'CANCELLED'){ return; } this.setState({loading: false, error: err}); - window.setTimeout(() => { - this.setState({error: null}); - }, 1000); + window.setTimeout(() => this.setState({error: null}), 1000); }); } - login_dropbox(e){ - this.setState({loading: true}); - Session.url('dropbox').then((url) => { - window.location.href = url; - }).catch((err) => { - if(err && err.code === 'CANCELLED'){ return; } - this.setState({loading: false, error: err}); - window.setTimeout(() => { - this.setState({error: null}); - }, 1000); - }); - } - - login_google(e){ - this.setState({loading: true}); - Session.url('gdrive').then((url) => { - window.location.href = url; - }).catch((err) => { - if(err && err.code === 'CANCELLED'){ return } - this.setState({loading: false, error: err}); - window.setTimeout(() => { - this.setState({error: null}); - }, 1000); - }); + initiateAuthToThirdParty(source){ + if(source === 'dropbox'){ + this.setState({loading: true}); + Session.url('dropbox').then((url) => { + window.location.href = url; + }).catch((err) => { + this.setState({loading: false, error: err}); + window.setTimeout(() => this.setState({error: null}), 1000); + }); + }else if(source === 'google'){ + this.setState({loading: true}); + Session.url('gdrive').then((url) => { + window.location.href = url; + }).catch((err) => { + this.setState({loading: false, error: err}); + window.setTimeout(() => this.setState({error: null}), 1000); + }); + } } onFormSubmit(data, credentials){ - this.setState({credentials: credentials}); - this.authenticate(data); + this.setState({credentials: credentials}, () => { + this.authenticate(data); + }); } setRemember(state){ @@ -122,23 +102,22 @@ export class ConnectPage extends React.Component { - - -
+ + + + + - - - + + + + + diff --git a/client/pages/connectpage/credentials.js b/client/pages/connectpage/credentials.js index 88da5067..539a2edd 100644 --- a/client/pages/connectpage/credentials.js +++ b/client/pages/connectpage/credentials.js @@ -36,7 +36,7 @@ export class Credentials extends React.Component { } } - componentWillMount(){ + componentDidMount(){ this.init(); if(this.state.key) this.onSubmit(); } @@ -91,8 +91,8 @@ export class Credentials extends React.Component { } }else{ this.setState({error: 'Password can\'t be empty'}); + window.setTimeout(() => this.setState({error: null}), 1500); } - window.setTimeout(() => this.setState({error: null}), 1500); } render() { diff --git a/client/pages/connectpage/form.js b/client/pages/connectpage/form.js index 95ce831a..e0c13750 100644 --- a/client/pages/connectpage/form.js +++ b/client/pages/connectpage/form.js @@ -3,6 +3,8 @@ import { Container, Card, NgIf, Input, Button, Textarea, Loader, Notification, e import { Session, invalidate, password } from '../../data'; import './form.scss'; +import img_drive from '../../assets/google-drive.png'; +import img_dropbox from '../../assets/dropbox.png'; export class Form extends React.Component { constructor(props){ @@ -14,24 +16,14 @@ export class Form extends React.Component { advanced_sftp: false, advanced_webdav: false, advanced_s3: false, - advanced_git: false + advanced_git: false, + dummy: true }; } - - _marginTop(){ - let size = 300; - const $screen = document.querySelector('.login-form'); - if($screen) size = $screen.offsetHeight; - - size = Math.round((document.body.offsetHeight - size) / 2); - if(size < 0) return 0; - if(size > 150) return 150; - return size; - } - componentDidMount(){ this.publishState(this.props.credentials); + window.addEventListener('resize', this.rerender.bind(this)); } componentWillReceiveProps(props){ @@ -40,6 +32,9 @@ export class Form extends React.Component { } } + componentWillUnmount(){ + window.removeEventListener('resize', this.rerender.bind(this)); + } publishState(_credentials){ const pushDOM = (credentials) => { @@ -102,10 +97,33 @@ export class Form extends React.Component { this.props.onSubmit(auth_data, credentials); } + redirect_dropbox(e){ + this.props.onThirdPartyLogin('dropbox'); + } + + redirect_google(e){ + this.props.onThirdPartyLogin('google'); + } + onTypeChange(type){ this.setState({type: type}, () => this.publishState(this.props.credentials)); } + rerender(){ + this.setState({dummy: !this.state.dummy}); + } + + _marginTop(){ + let size = 300; + const $screen = document.querySelector('.login-form'); + if($screen) size = $screen.offsetHeight; + + size = Math.round((document.body.offsetHeight - size) / 2); + if(size < 0) return 0; + if(size > 150) return 150; + return size; + } + render() { let className = (window.innerWidth < 600) ? 'scroll-x' : ''; return ( @@ -122,9 +140,9 @@ export class Form extends React.Component {
- {this.state.refs.webdav_url = input; }} autoComplete="new-password" /> - {this.state.refs.webdav_username = input; }} autoComplete="new-password" /> - {this.state.refs.webdav_password = input; }} autoComplete="new-password" /> + { this.state.refs.webdav_url = input; }} autoComplete="new-password" /> + { this.state.refs.webdav_username = input; }} autoComplete="new-password" /> + { this.state.refs.webdav_password = input; }} autoComplete="new-password" /> @@ -196,23 +214,23 @@ export class Form extends React.Component { -
- +
+
- +
-
- +
+
- +
- + ); } } diff --git a/client/pages/connectpage/form.scss b/client/pages/connectpage/form.scss index 99cbb5b3..58359b57 100644 --- a/client/pages/connectpage/form.scss +++ b/client/pages/connectpage/form.scss @@ -42,3 +42,23 @@ } } } + +.component_page_connection_form.form-appear{ + opacity: 0; +} +.component_page_connection_form.form-appear.form-appear-active{ + opacity: 1; + transition: opacity 0.5s ease-out; +} + + +.component_rememberme.remember-appear{ + opacity: 0; + transform: translateX(40px); +} +.component_rememberme.remember-appear.remember-appear-active{ + opacity: 1; + transform: translateX(0px); + transition: all 0.3s ease-out; + transition-delay: 0.5s; +} diff --git a/package-lock.json b/package-lock.json index b3cb7fc7..9b06de26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11149,6 +11149,34 @@ "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.0.tgz", "integrity": "sha1-TTNA6AfTdzvamZH4MFrNzCpmXSo=" }, + "url-loader": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz", + "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "mime": "1.6.0", + "schema-utils": "0.3.0" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "5.5.2" + } + } + } + }, "url-parse": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.2.0.tgz", diff --git a/package.json b/package.json index 182a4703..0443bbba 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "sass-loader": "^6.0.6", "sass-variable-loader": "^0.1.2", "style-loader": "^0.20.2", + "url-loader": "^0.6.2", "webpack-bundle-analyzer": "^2.8.2", "webpack-dev-server": "^2.4.5" } diff --git a/server/model/backend/dropbox.js b/server/model/backend/dropbox.js index 8266366f..b08ae48a 100644 --- a/server/model/backend/dropbox.js +++ b/server/model/backend/dropbox.js @@ -43,7 +43,7 @@ module.exports = { test: function(params){ return query(params, "https://api.dropboxapi.com/2/users/get_current_account", "POST") .then((opts) => Promise.resolve(params)) - .catch((err) => Promise.reject({message: err && err.message || err, code: "NOT_AUTHENTICATED"})) + .catch((err) => Promise.reject({message: 'Dropbox didn\'t gave us access to your account', code: "NOT_AUTHENTICATED"})) }, cat: function(path, params){ return query_stream(params, "https://content.dropboxapi.com/2/files/download", "POST", null, { diff --git a/webpack.config.js b/webpack.config.js index bb157374..550f7167 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -28,6 +28,10 @@ let config = { { test: /\.scss$/, loaders: ['style-loader', 'css-loader', 'sass-loader'] + }, + { + test: /\.(pdf|jpg|png|gif|svg|ico)$/, + loader: "url-loader?mimetype=image/png" } ] },