mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
feat: add loading animation on load more matches button
This commit is contained in:
parent
e09c7d59b5
commit
a7561a82b8
4 changed files with 136 additions and 5 deletions
117
client/src/components/LoadingButton.vue
Normal file
117
client/src/components/LoadingButton.vue
Normal 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>
|
||||||
|
|
@ -11,11 +11,17 @@ export const state = {
|
||||||
matches: [],
|
matches: [],
|
||||||
soloQ: {}
|
soloQ: {}
|
||||||
},
|
},
|
||||||
|
matchesLoading: false,
|
||||||
status: '',
|
status: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
|
MATCHES_LOADING(state) {
|
||||||
|
state.matchesLoading = true
|
||||||
|
},
|
||||||
MATCHES_FOUND(state, newMatches) {
|
MATCHES_FOUND(state, newMatches) {
|
||||||
|
state.matchesLoading = false
|
||||||
|
|
||||||
state.infos.matches = [...state.infos.matches, ...newMatches]
|
state.infos.matches = [...state.infos.matches, ...newMatches]
|
||||||
|
|
||||||
state.infos.matchIndex += newMatches.length
|
state.infos.matchIndex += newMatches.length
|
||||||
|
|
@ -38,6 +44,8 @@ export const mutations = {
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
async moreMatches({ commit }) {
|
async moreMatches({ commit }) {
|
||||||
|
commit('MATCHES_LOADING')
|
||||||
|
|
||||||
const account = state.infos.account
|
const account = state.infos.account
|
||||||
const gameIds = state.infos.matchList.slice(state.infos.matchIndex, state.infos.matchIndex + 10).map(({ gameId }) => gameId)
|
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 = {
|
export const getters = {
|
||||||
|
matchesLoading: state => state.matchesLoading,
|
||||||
moreMatchesToFetch: state => state.infos.matchIndex < state.infos.matchList.length,
|
moreMatchesToFetch: state => state.infos.matchIndex < state.infos.matchList.length,
|
||||||
summonerFound: state => state.status === 'found',
|
summonerFound: state => state.status === 'found',
|
||||||
summonerNotFound: state => state.status === 'error',
|
summonerNotFound: state => state.status === 'error',
|
||||||
|
|
|
||||||
|
|
@ -87,11 +87,13 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<LoadingButton
|
||||||
v-if="moreMatchesToFetch"
|
v-if="moreMatchesToFetch"
|
||||||
@click="moreMatches"
|
@clicked="moreMatches"
|
||||||
class="mt-4 block mx-auto bg-blue-800 px-4 py-2 rounded-md font-semibold hover:bg-blue-1000 shadow-lg"
|
:loading="matchesLoading"
|
||||||
>More matches</button>
|
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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -113,6 +115,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapActions, mapGetters } from 'vuex'
|
import { mapState, mapActions, mapGetters } from 'vuex'
|
||||||
import LazyBackground from '@/components/LazyBackgroundImage.vue'
|
import LazyBackground from '@/components/LazyBackgroundImage.vue'
|
||||||
|
import LoadingButton from '@/components/LoadingButton.vue'
|
||||||
import RecentActivity from '@/components/RecentActivity.vue'
|
import RecentActivity from '@/components/RecentActivity.vue'
|
||||||
import Match from '@/components/Match.vue'
|
import Match from '@/components/Match.vue'
|
||||||
import SearchForm from '@/components/SearchForm.vue'
|
import SearchForm from '@/components/SearchForm.vue'
|
||||||
|
|
@ -120,6 +123,7 @@ import SearchForm from '@/components/SearchForm.vue'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
LazyBackground,
|
LazyBackground,
|
||||||
|
LoadingButton,
|
||||||
Match,
|
Match,
|
||||||
RecentActivity,
|
RecentActivity,
|
||||||
SearchForm
|
SearchForm
|
||||||
|
|
@ -138,7 +142,7 @@ export default {
|
||||||
...mapState({
|
...mapState({
|
||||||
summonerInfos: state => state.summoner.infos
|
summonerInfos: state => state.summoner.infos
|
||||||
}),
|
}),
|
||||||
...mapGetters('summoner', ['moreMatchesToFetch', 'summonerFound', 'summonerNotFound', 'summonerLoading'])
|
...mapGetters('summoner', ['matchesLoading', 'moreMatchesToFetch', 'summonerFound', 'summonerNotFound', 'summonerLoading'])
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,7 @@ module.exports = {
|
||||||
default: '1px',
|
default: '1px',
|
||||||
'0': '0',
|
'0': '0',
|
||||||
'2': '2px',
|
'2': '2px',
|
||||||
|
'3': '3px',
|
||||||
'4': '4px',
|
'4': '4px',
|
||||||
'8': '8px',
|
'8': '8px',
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue