From 7d522583780cae5746112f204b3f8c604d5a87bd Mon Sep 17 00:00:00 2001 From: wakarimasen <wakarimasen@airmail.cc> Date: Tue, 7 Mar 2017 21:38:55 +0100 Subject: [PATCH 01/12] Move rejection handler --- src/services/timeline_fetcher/timeline_fetcher.service.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js index 40f568c3..e684a170 100644 --- a/src/services/timeline_fetcher/timeline_fetcher.service.js +++ b/src/services/timeline_fetcher/timeline_fetcher.service.js @@ -5,6 +5,8 @@ import apiService from '../api/api.service.js' const update = ({store, statuses, timeline, showImmediately}) => { const ccTimeline = camelCase(timeline) + setError({store, timeline, value: false}) + store.dispatch('addNewStatuses', { timeline: ccTimeline, statuses, @@ -33,9 +35,8 @@ const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false } return apiService.fetchTimeline(args) - .then((statuses) => update({store, statuses, timeline, showImmediately})) - .then(() => setError({store, timeline, value: false})) - .catch(() => setError({store, timeline, value: true})) + .then((statuses) => update({store, statuses, timeline, showImmediately}), + () => setError({store, timeline, value: true})) } const startFetching = ({ timeline = 'friends', credentials, store }) => { From a6b6fe95c0fe2aa60ebbfca87fde47e629035c49 Mon Sep 17 00:00:00 2001 From: wakarimasen <wakarimasen@airmail.cc> Date: Wed, 8 Mar 2017 18:28:41 +0100 Subject: [PATCH 02/12] Show visual feedback on login error, redirect on success --- src/components/login_form/login_form.js | 8 ++- src/components/login_form/login_form.vue | 9 ++++ src/modules/users.js | 68 +++++++++++++----------- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index 827c704c..2ad5b0b5 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -1,13 +1,17 @@ const LoginForm = { data: () => ({ - user: {} + user: {}, + authError: false }), computed: { loggingIn () { return this.$store.state.users.loggingIn } }, methods: { submit () { - this.$store.dispatch('loginUser', this.user) + this.$store.dispatch('loginUser', this.user).then( + () => { this.$router.push('/main/friends')}, + () => { this.authError = true } + ) } } } diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue index c0273bae..279469ee 100644 --- a/src/components/login_form/login_form.vue +++ b/src/components/login_form/login_form.vue @@ -17,6 +17,9 @@ <div class='form-group'> <button :disabled="loggingIn" type='submit' class='btn btn-default base05 base01-background'>Submit</button> </div> + <div v-if="authError" class='form-group'> + <button disabled='true' class='btn btn-default base05 error'>Error logging in, try again</button> + </div> </form> </div> </div> @@ -39,6 +42,12 @@ margin-top: 1.0em; min-height: 28px; } + + .error { + margin-top: 0em; + margin-bottom: 0em; + background-color: rgba(255, 48, 16, 0.65); + } } </style> diff --git a/src/modules/users.js b/src/modules/users.js index 31731880..a5274480 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -65,40 +65,48 @@ const users = { }) }, loginUser (store, userCredentials) { - const commit = store.commit - commit('beginLogin') - store.rootState.api.backendInteractor.verifyCredentials(userCredentials) - .then((response) => { - if (response.ok) { - response.json() - .then((user) => { - user.credentials = userCredentials - commit('setCurrentUser', user) - commit('addNewUsers', [user]) + return new Promise((resolve, reject) => { + const commit = store.commit + commit('beginLogin') + store.rootState.api.backendInteractor.verifyCredentials(userCredentials) + .then((response) => { + if (response.ok) { + response.json() + .then((user) => { + user.credentials = userCredentials + commit('setCurrentUser', user) + commit('addNewUsers', [user]) - // Set our new backend interactor - commit('setBackendInteractor', backendInteractorService(userCredentials)) + // Set our new backend interactor + commit('setBackendInteractor', backendInteractorService(userCredentials)) - // Start getting fresh tweets. - store.dispatch('startFetching', 'friends') + // Start getting fresh tweets. + store.dispatch('startFetching', 'friends') - // Get user mutes and follower info - store.rootState.api.backendInteractor.fetchMutes().then((mutedUsers) => { - each(mutedUsers, (user) => { user.muted = true }) - store.commit('addNewUsers', mutedUsers) + // Get user mutes and follower info + store.rootState.api.backendInteractor.fetchMutes().then((mutedUsers) => { + each(mutedUsers, (user) => { user.muted = true }) + store.commit('addNewUsers', mutedUsers) + }) + + // Fetch our friends + store.rootState.api.backendInteractor.fetchFriends() + .then((friends) => commit('addNewUsers', friends)) }) - - // Fetch our friends - store.rootState.api.backendInteractor.fetchFriends() - .then((friends) => commit('addNewUsers', friends)) - }) - } - commit('endLogin') - }) - .catch((error) => { - console.log(error) - commit('endLogin') - }) + } else { + // Authentication failed + commit('endLogin') + reject() + } + commit('endLogin') + resolve() + }) + .catch((error) => { + console.log(error) + commit('endLogin') + reject() + }) + }) } } } From c0e8111d642ca9f85fbb4091f2ac9e86f4238a58 Mon Sep 17 00:00:00 2001 From: wakarimasen <wakarimasen@airmail.cc> Date: Wed, 8 Mar 2017 19:08:01 +0100 Subject: [PATCH 03/12] Clear username and password field on failed login --- src/components/login_form/login_form.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index 2ad5b0b5..e489f381 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -10,7 +10,11 @@ const LoginForm = { submit () { this.$store.dispatch('loginUser', this.user).then( () => { this.$router.push('/main/friends')}, - () => { this.authError = true } + () => { + this.authError = true + this.user.username = '' + this.user.password = '' + } ) } } From ccc460bb5ed1c8b7338f8a26bdb3029c74b26024 Mon Sep 17 00:00:00 2001 From: wakarimasen <wakarimasen@airmail.cc> Date: Wed, 8 Mar 2017 19:22:56 +0100 Subject: [PATCH 04/12] Give more specific reason for failed login --- src/components/login_form/login_form.js | 4 ++-- src/components/login_form/login_form.vue | 2 +- src/modules/users.js | 8 ++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index e489f381..bc801397 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -10,8 +10,8 @@ const LoginForm = { submit () { this.$store.dispatch('loginUser', this.user).then( () => { this.$router.push('/main/friends')}, - () => { - this.authError = true + (error) => { + this.authError = error this.user.username = '' this.user.password = '' } diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue index 279469ee..8a32e064 100644 --- a/src/components/login_form/login_form.vue +++ b/src/components/login_form/login_form.vue @@ -18,7 +18,7 @@ <button :disabled="loggingIn" type='submit' class='btn btn-default base05 base01-background'>Submit</button> </div> <div v-if="authError" class='form-group'> - <button disabled='true' class='btn btn-default base05 error'>Error logging in, try again</button> + <button disabled='true' class='btn btn-default base05 error'>{{authError}}</button> </div> </form> </div> diff --git a/src/modules/users.js b/src/modules/users.js index a5274480..482c3b14 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -96,7 +96,11 @@ const users = { } else { // Authentication failed commit('endLogin') - reject() + if (response.status === 401) { + reject('Wrong username or password') + } else { + reject('An error occured, please try again') + } } commit('endLogin') resolve() @@ -104,7 +108,7 @@ const users = { .catch((error) => { console.log(error) commit('endLogin') - reject() + reject('Failed to connect to server, try again') }) }) } From 0810b2d51a6f0fbbfe1604f6d1954cde8ed08290 Mon Sep 17 00:00:00 2001 From: wakarimasen <wakarimasen@airmail.cc> Date: Wed, 8 Mar 2017 19:31:39 +0100 Subject: [PATCH 05/12] Fix typo --- src/modules/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/users.js b/src/modules/users.js index 482c3b14..51643bd1 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -99,7 +99,7 @@ const users = { if (response.status === 401) { reject('Wrong username or password') } else { - reject('An error occured, please try again') + reject('An error occurred, please try again') } } commit('endLogin') From 9511691c9467e26c3237b4a2c936e8a757b3e515 Mon Sep 17 00:00:00 2001 From: shpuld <shpuld@gmail.com> Date: Thu, 9 Mar 2017 02:21:23 +0200 Subject: [PATCH 06/12] Make the error into a div instead of a button to get rid of the hover effects. --- src/components/login_form/login_form.vue | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue index 8a32e064..b2fa5341 100644 --- a/src/components/login_form/login_form.vue +++ b/src/components/login_form/login_form.vue @@ -18,7 +18,7 @@ <button :disabled="loggingIn" type='submit' class='btn btn-default base05 base01-background'>Submit</button> </div> <div v-if="authError" class='form-group'> - <button disabled='true' class='btn btn-default base05 error'>{{authError}}</button> + <div class='error base05'>{{authError}}</div> </div> </form> </div> @@ -44,9 +44,11 @@ } .error { - margin-top: 0em; - margin-bottom: 0em; + border-radius: 5px; + text-align: center; background-color: rgba(255, 48, 16, 0.65); + min-height: 28px; + line-height: 28px; } } From 502757da28d573641a48197c284b7e40dfc8154e Mon Sep 17 00:00:00 2001 From: xj9 <xj9@heropunch.io> Date: Wed, 8 Mar 2017 20:23:10 -0700 Subject: [PATCH 07/12] improvements on fature/better-nsfw-image-loading - loading indicator - avoid hitting the cache if we already know the image was loaded - more responsive toggle --- src/components/attachment/attachment.js | 24 +++++++++++++++++++----- src/components/attachment/attachment.vue | 18 ++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js index c3f52f57..7715add5 100644 --- a/src/components/attachment/attachment.js +++ b/src/components/attachment/attachment.js @@ -11,7 +11,9 @@ const Attachment = { return { nsfwImage, hideNsfwLocal: this.$store.state.config.hideNsfw, - showHidden: false + showHidden: false, + loading: false, + img: document.createElement('img') } }, computed: { @@ -20,6 +22,13 @@ const Attachment = { }, hidden () { return this.nsfw && this.hideNsfwLocal && !this.showHidden + }, + autoHeight () { + if (this.type === 'image' && this.nsfw) { + return { + 'min-height': '311px' + } + } } }, methods: { @@ -29,10 +38,15 @@ const Attachment = { } }, toggleHidden () { - let img = document.createElement('img') - img.src = this.attachment.url - img.onload = () => { - this.showHidden = !this.showHidden + if (this.img.onload) { + this.img.onload() + } else { + this.loading = true + this.img.src = this.attachment.url + this.img.onload = () => { + this.loading = false + this.showHidden = !this.showHidden + } } } } diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue index ad60acf9..8f51b891 100644 --- a/src/components/attachment/attachment.vue +++ b/src/components/attachment/attachment.vue @@ -1,15 +1,14 @@ <template> - <div class="attachment" :class="type"> - <a class="image-attachment" v-if="hidden" v-on:click.prevent="toggleHidden()"> - <img :key="nsfwImage" :src="nsfwImage"></img> + <div class="attachment" :class="{[type]: true, loading}" :style="autoHeight"> + <a class="image-attachment" v-if="hidden" @click.prevent="toggleHidden()"> + <img :key="nsfwImage" :src="nsfwImage"/> </a> <div class="hider" v-if="nsfw && hideNsfwLocal && !hidden"> <a href="#" @click.prevent="toggleHidden()">Hide</a> </div> - <a class="image-attachment" v-if="type === 'image' && !hidden" - :href="attachment.url" target="_blank"> - <img class="base05-border" referrerpolicy="no-referrer" :src="attachment.large_thumb_url || attachment.url"></img> + <a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank"> + <img class="base05-border" referrerpolicy="no-referrer" :src="attachment.large_thumb_url || attachment.url"/> </a> <video v-if="type === 'video' && !hidden" :src="attachment.url" controls></video> @@ -18,7 +17,7 @@ <div @click.prevent="linkClicked" v-if="type === 'html' && attachment.oembed" class="oembed"> <div v-if="attachment.thumb_url" class="image"> - <img :src="attachment.thumb_url"></img> + <img :src="attachment.thumb_url"/> </div> <div class="text"> <h1><a :href="attachment.url">{{attachment.oembed.title}}</a></h1> @@ -45,6 +44,10 @@ display: flex; } + &.loading { + cursor: progress; + } + .hider { position: absolute; margin: 10px; @@ -111,7 +114,6 @@ flex: 1; img { - width: 100%; border-style: solid; border-width: 1px; border-radius: 5px; From 459fdaf10fcc55248ec2868963edcba51114c877 Mon Sep 17 00:00:00 2001 From: xj9 <xj9@heropunch.io> Date: Wed, 8 Mar 2017 21:45:40 -0700 Subject: [PATCH 08/12] add a spin animation to favorite and boost actions --- src/components/favorite_button/favorite_button.js | 14 ++++++++++++-- src/components/favorite_button/favorite_button.vue | 4 +++- src/components/retweet_button/retweet_button.js | 14 ++++++++++++-- src/components/retweet_button/retweet_button.vue | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/components/favorite_button/favorite_button.js b/src/components/favorite_button/favorite_button.js index 4ee3890f..466e9b84 100644 --- a/src/components/favorite_button/favorite_button.js +++ b/src/components/favorite_button/favorite_button.js @@ -1,5 +1,10 @@ const FavoriteButton = { - props: [ 'status' ], + props: ['status'], + data () { + return { + animated: false + } + }, methods: { favorite () { if (!this.status.favorited) { @@ -7,13 +12,18 @@ const FavoriteButton = { } else { this.$store.dispatch('unfavorite', {id: this.status.id}) } + this.animated = true + setTimeout(() => { + this.animated = false + }, 500) } }, computed: { classes () { return { 'icon-star-empty': !this.status.favorited, - 'icon-star': this.status.favorited + 'icon-star': this.status.favorited, + 'animate-spin': this.animated } } } diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue index fd53b505..0abece31 100644 --- a/src/components/favorite_button/favorite_button.vue +++ b/src/components/favorite_button/favorite_button.vue @@ -1,6 +1,6 @@ <template> <div> - <i :class='classes' class='favorite-button fa' v-on:click.prevent='favorite()'></i> + <i :class='classes' class='favorite-button fa' @click.prevent='favorite()'/> <span v-if='status.fave_num > 0'>{{status.fave_num}}</span> </div> </template> @@ -10,6 +10,7 @@ <style lang='scss'> .favorite-button { cursor: pointer; + animation-duration: 0.6s; &:hover { color: orange; } @@ -17,4 +18,5 @@ .icon-star { color: orange; } + </style> diff --git a/src/components/retweet_button/retweet_button.js b/src/components/retweet_button/retweet_button.js index e7318dc5..2280f315 100644 --- a/src/components/retweet_button/retweet_button.js +++ b/src/components/retweet_button/retweet_button.js @@ -1,16 +1,26 @@ const RetweetButton = { - props: [ 'status' ], + props: ['status'], + data () { + return { + animated: false + } + }, methods: { retweet () { if (!this.status.repeated) { this.$store.dispatch('retweet', {id: this.status.id}) } + this.animated = true + setTimeout(() => { + this.animated = false + }, 500) } }, computed: { classes () { return { - 'retweeted': this.status.repeated + 'retweeted': this.status.repeated, + 'animate-spin': this.animated } } } diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue index 9b2f5c7b..5ec85fcf 100644 --- a/src/components/retweet_button/retweet_button.vue +++ b/src/components/retweet_button/retweet_button.vue @@ -11,6 +11,7 @@ @import '../../_variables.scss'; .icon-retweet { cursor: pointer; + animation-duration: 0.6s; &:hover { color: $green; } From aff432a572c9c3368c8822a5aa5d5827eeb3b39f Mon Sep 17 00:00:00 2001 From: xj9 <xj9@heropunch.io> Date: Wed, 8 Mar 2017 22:36:03 -0700 Subject: [PATCH 09/12] themeable hover states for nav-panel --- src/components/nav_panel/nav_panel.vue | 33 ++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue index 85ed163c..1d96f4d6 100644 --- a/src/components/nav_panel/nav_panel.vue +++ b/src/components/nav_panel/nav_panel.vue @@ -1,24 +1,24 @@ <template> <div class="nav-panel"> - <div class="panel panel-default base01-background"> + <div class="panel panel-default base02-background"> <ul> <li v-if='currentUser'> - <router-link to='/main/friends'> + <router-link class="base01-background" to='/main/friends'> Timeline </router-link> </li> <li v-if='currentUser'> - <router-link :to="{ name: 'mentions', params: { username: currentUser.screen_name } }"> + <router-link class="base01-background" :to="{ name: 'mentions', params: { username: currentUser.screen_name } }"> Mentions </router-link> </li> <li> - <router-link to='/main/public'> + <router-link class="base01-background" to='/main/public'> Public Timeline </router-link> </li> <li> - <router-link to='/main/all'> + <router-link class="base01-background" to='/main/all'> The Whole Known Network </router-link> </li> @@ -30,7 +30,6 @@ <script src="./nav_panel.js" ></script> <style lang="scss"> - .nav-panel ul { list-style: none; margin: 0; @@ -39,7 +38,15 @@ .nav-panel li { border-bottom: 1px solid; - padding: 0.8em 0.85em; + padding: 0; + &:first-child a { + border-top-right-radius: 10px; + border-top-left-radius: 10px; + } + &:last-child a { + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; + } } .nav-panel li:last-child { @@ -48,10 +55,16 @@ .nav-panel a { display: block; - width: 100%; - + padding: 0.8em 0.85em; + &:hover { + background-color: transparent; + } &.router-link-active { - font-weight: bold + font-weight: bolder; + background-color: transparent; + &:hover { + text-decoration: underline; + } } } From d94cd15467d53b8f5b87381de34fd9e3d3536b45 Mon Sep 17 00:00:00 2001 From: xj9 <xj9@heropunch.io> Date: Wed, 8 Mar 2017 22:38:14 -0700 Subject: [PATCH 10/12] fix cursor style --- src/components/retweet_button/retweet_button.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue index 5ec85fcf..d923c5c4 100644 --- a/src/components/retweet_button/retweet_button.vue +++ b/src/components/retweet_button/retweet_button.vue @@ -17,7 +17,6 @@ } } .retweeted { - cursor: auto; color: $green; } </style> From 08297ea83e91418293c09e265bc87ae77d867d2a Mon Sep 17 00:00:00 2001 From: Roger Braun <roger@rogerbraun.net> Date: Thu, 9 Mar 2017 08:51:33 +0100 Subject: [PATCH 11/12] Remove redirect on login This is to enable this workflow: 1. Open conversation in new tab 2. Login 3. Interact with the conversation We can add this again once we have persistent logins. --- src/components/login_form/login_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index bc801397..1a6f6015 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -9,7 +9,7 @@ const LoginForm = { methods: { submit () { this.$store.dispatch('loginUser', this.user).then( - () => { this.$router.push('/main/friends')}, + () => {}, (error) => { this.authError = error this.user.username = '' From d954909134325ef9bf0593a05117aa2787932e59 Mon Sep 17 00:00:00 2001 From: Roger Braun <roger@rogerbraun.net> Date: Thu, 9 Mar 2017 08:58:17 +0100 Subject: [PATCH 12/12] Add linter. --- .gitlab-ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c31d2d31..296d6839 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,10 +28,17 @@ before_script: # - node_modules/ stages: + - lint - build - test - deploy +lint: + stage: lint + script: + - yarn + - npm run lint + test: stage: test script: