feat: add loading animation on load more matches button

This commit is contained in:
Valentin Kaelin 2019-10-06 15:08:24 +02:00
parent e09c7d59b5
commit a7561a82b8
4 changed files with 136 additions and 5 deletions

View file

@ -0,0 +1,117 @@
<template>
<button
@click="btnClicked"
:class="[btnClass, {'loading': loading}, {'pr-12': loading}]"
:disabled="loading"
class="relative"
type="button"
>
<slot>Send</slot>
<span class="spinner absolute opacity-0 left-auto">
<span
class="inline-block absolute right-0 w-4 h-4 opacity-100 border-3 border-white rounded-full"
></span>
<span
class="inline-block absolute right-0 w-4 h-4 opacity-100 border-3 border-white rounded-full"
></span>
<span
class="inline-block absolute right-0 w-4 h-4 opacity-100 border-3 border-white rounded-full"
></span>
<span
class="inline-block absolute right-0 w-4 h-4 opacity-100 border-3 border-white rounded-full"
></span>
</span>
</button>
</template>
<script>
export default {
props: {
btnClass: {
type: String,
required: false,
default: ''
},
loading: {
type: Boolean,
required: false,
default: false
}
},
methods: {
btnClicked() {
this.$emit('clicked')
}
}
}
</script>
<style scoped>
button {
transition: all 0.2s;
transition-timing-function: ease-in;
}
.spinner {
top: 50%;
right: 1.7rem;
margin: -0.5rem;
transition-property: padding, opacity;
transition-duration: 0.2s, 0.2s;
transition-timing-function: ease-in, ease;
transition-delay: 0s, 0.2s;
}
.spinner span {
animation: spinner 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: #fff transparent transparent transparent;
}
.spinner span:nth-child(1) {
animation-delay: 0.45s;
}
.spinner span:nth-child(2) {
animation-delay: 0.3s;
}
.spinner span:nth-child(3) {
animation-delay: 0.15s;
}
.loading .spinner {
opacity: 1;
}
button:not(:disabled) .spinner span {
box-shadow: 0 0 0 0.2rem #4fd1c5 inset;
border: 7.4px solid transparent;
transition: all 0.4s;
}
button:not(:disabled) .spinner span:nth-child(1) {
transform: rotate(0deg);
}
button:not(:disabled) .spinner span:nth-child(2) {
transform: rotate(90deg);
}
button:not(:disabled) .spinner span:nth-child(3) {
transform: rotate(180deg);
}
button:not(:disabled) .spinner span:nth-child(4) {
transform: rotate(270deg);
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>

View file

@ -11,11 +11,17 @@ export const state = {
matches: [],
soloQ: {}
},
matchesLoading: false,
status: '',
}
export const mutations = {
MATCHES_LOADING(state) {
state.matchesLoading = true
},
MATCHES_FOUND(state, newMatches) {
state.matchesLoading = false
state.infos.matches = [...state.infos.matches, ...newMatches]
state.infos.matchIndex += newMatches.length
@ -38,6 +44,8 @@ export const mutations = {
export const actions = {
async moreMatches({ commit }) {
commit('MATCHES_LOADING')
const account = state.infos.account
const gameIds = state.infos.matchList.slice(state.infos.matchIndex, state.infos.matchIndex + 10).map(({ gameId }) => gameId)
@ -69,6 +77,7 @@ export const actions = {
}
export const getters = {
matchesLoading: state => state.matchesLoading,
moreMatchesToFetch: state => state.infos.matchIndex < state.infos.matchList.length,
summonerFound: state => state.status === 'found',
summonerNotFound: state => state.status === 'error',

View file

@ -87,11 +87,13 @@
</ul>
</div>
<button
<LoadingButton
v-if="moreMatchesToFetch"
@click="moreMatches"
class="mt-4 block mx-auto bg-blue-800 px-4 py-2 rounded-md font-semibold hover:bg-blue-1000 shadow-lg"
>More matches</button>
@clicked="moreMatches"
:loading="matchesLoading"
btn-class="mt-4 block mx-auto bg-blue-800 px-4 py-2 rounded-md font-semibold hover:bg-blue-1000 shadow-lg"
>More matches</LoadingButton>
</div>
</template>
@ -113,6 +115,7 @@
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
import LazyBackground from '@/components/LazyBackgroundImage.vue'
import LoadingButton from '@/components/LoadingButton.vue'
import RecentActivity from '@/components/RecentActivity.vue'
import Match from '@/components/Match.vue'
import SearchForm from '@/components/SearchForm.vue'
@ -120,6 +123,7 @@ import SearchForm from '@/components/SearchForm.vue'
export default {
components: {
LazyBackground,
LoadingButton,
Match,
RecentActivity,
SearchForm
@ -138,7 +142,7 @@ export default {
...mapState({
summonerInfos: state => state.summoner.infos
}),
...mapGetters('summoner', ['moreMatchesToFetch', 'summonerFound', 'summonerNotFound', 'summonerLoading'])
...mapGetters('summoner', ['matchesLoading', 'moreMatchesToFetch', 'summonerFound', 'summonerNotFound', 'summonerLoading'])
},
watch: {

View file

@ -183,6 +183,7 @@ module.exports = {
default: '1px',
'0': '0',
'2': '2px',
'3': '3px',
'4': '4px',
'8': '8px',
},