feat: add loading spinner splash screen while loading

This commit is contained in:
kolaente 2021-10-31 20:42:09 +01:00
parent 14472a45ed
commit eef2a3d7cc
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
6 changed files with 105 additions and 57 deletions

View File

@ -1,5 +1,5 @@
<template> <template>
<div :class="{'is-touch': isTouch}"> <div :class="{'is-touch': isTouch}" v-if="ready">
<div :class="{'is-hidden': !online}"> <div :class="{'is-hidden': !online}">
<!-- This is a workaround to get the sw to "see" the to-be-cached version of the offline background image --> <!-- This is a workaround to get the sw to "see" the to-be-cached version of the offline background image -->
<div class="offline" style="height: 0;width: 0;"></div> <div class="offline" style="height: 0;width: 0;"></div>
@ -20,6 +20,7 @@
<keyboard-shortcuts v-if="keyboardShortcutsActive"/> <keyboard-shortcuts v-if="keyboardShortcutsActive"/>
</transition> </transition>
</div> </div>
<vikunja-loading v-else/>
</template> </template>
<script> <script>
@ -36,10 +37,12 @@ import ContentLinkShare from './components/home/contentLinkShare'
import ContentNoAuth from './components/home/contentNoAuth' import ContentNoAuth from './components/home/contentNoAuth'
import {setLanguage} from './i18n' import {setLanguage} from './i18n'
import AccountDeleteService from '@/services/accountDelete' import AccountDeleteService from '@/services/accountDelete'
import VikunjaLoading from '@/components/misc/vikunja-loading'
export default defineComponent({ export default defineComponent({
name: 'app', name: 'app',
components: { components: {
VikunjaLoading,
ContentNoAuth, ContentNoAuth,
ContentLinkShare, ContentLinkShare,
ContentAuth, ContentAuth,
@ -54,13 +57,7 @@ export default defineComponent({
this.setupAccountDeletionVerification() this.setupAccountDeletionVerification()
}, },
beforeCreate() { beforeCreate() {
// FIXME: async action in beforeCreate, might be not finished when component mounts this.$store.dispatch('loadApp')
this.$store.dispatch('config/update')
.then(() => {
this.$store.dispatch('auth/checkAuth')
})
this.$store.dispatch('auth/checkAuth')
setLanguage() setLanguage()
}, },
created() { created() {
@ -76,6 +73,7 @@ export default defineComponent({
...mapState({ ...mapState({
online: ONLINE, online: ONLINE,
keyboardShortcutsActive: KEYBOARD_SHORTCUTS_ACTIVE, keyboardShortcutsActive: KEYBOARD_SHORTCUTS_ACTIVE,
ready: 'vikunjaReady',
}), }),
...mapGetters('auth', [ ...mapGetters('auth', [
'authUser', 'authUser',
@ -124,26 +122,26 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.offline { .offline {
background: url('@/assets/llama-nightscape.jpg') no-repeat center; background: url('@/assets/llama-nightscape.jpg') no-repeat center;
background-size: cover; background-size: cover;
height: 100vh; height: 100vh;
.offline-message { .offline-message {
text-align: center; text-align: center;
position: absolute; position: absolute;
width: 100vw; width: 100vw;
bottom: 5vh; bottom: 5vh;
color: $white; color: $white;
padding: 0 1rem; padding: 0 1rem;
h1 { h1 {
font-weight: bold; font-weight: bold;
font-size: 1.5rem; font-size: 1.5rem;
text-align: center; text-align: center;
color: $white; color: $white;
font-weight: 700 !important; font-weight: 700 !important;
font-size: 1.5rem; font-size: 1.5rem;
} }
} }
} }
</style> </style>

View File

@ -48,7 +48,7 @@
</ul> </ul>
</div> </div>
<aside class="menu namespaces-lists loader-container" :class="{'is-loading': loading}"> <aside class="menu namespaces-lists loader-container is-loading-small" :class="{'is-loading': loading}">
<template v-for="(n, nk) in namespaces" :key="n.id" > <template v-for="(n, nk) in namespaces" :key="n.id" >
<div class="namespace-title" :class="{'has-menu': n.id > 0}"> <div class="namespace-title" :class="{'has-menu': n.id > 0}">
<span <span
@ -105,7 +105,7 @@
> >
<template #item="{element: l}"> <template #item="{element: l}">
<li <li
class="loader-container" class="loader-container is-loading-small"
:class="{'is-loading': listUpdating[l.id]}" :class="{'is-loading': listUpdating[l.id]}"
> >
<router-link <router-link
@ -449,14 +449,6 @@ $vikunja-nav-selected-width: 0.4rem;
&:hover :deep(.dropdown-trigger) { &:hover :deep(.dropdown-trigger) {
opacity: 1; opacity: 1;
} }
&.loader-container.is-loading:after {
width: 1.5rem;
height: 1.5rem;
top: calc(50% - .75rem);
left: calc(50% - .75rem);
border-width: 2px;
}
} }
.flip-list-move { .flip-list-move {
@ -530,14 +522,6 @@ $vikunja-nav-selected-width: 0.4rem;
padding-top: math.div($navbar-padding, 2); padding-top: math.div($navbar-padding, 2);
} }
&.loader-container.is-loading:after {
width: 1.5rem;
height: 1.5rem;
top: calc(50% - .75rem);
left: calc(50% - .75rem);
border-width: 2px;
}
.icon { .icon {
color: $grey-400 !important; color: $grey-400 !important;
} }

View File

@ -0,0 +1,46 @@
<template>
<section class="vikunja-loading">
<img alt="Vikunja" :src="logoUrl" width="100" height="100"/>
<p>
<span class="loader-container is-loading-small is-loading"></span>
{{ $t('home.vikunjaLoading') }}
</p>
</section>
</template>
<script>
import logoUrl from '@/assets/logo.svg'
export default {
name: 'vikunja-loading',
data() {
return {
logoUrl,
}
},
}
</script>
<style lang="scss" scoped>
.vikunja-loading {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
flex-direction: column;
img {
margin-bottom: 1rem;
}
.loader-container {
margin-right: 1rem;
&.is-loading:after {
border-left-color: $grey-400;
border-bottom-color: $grey-400;
}
}
}
</style>

View File

@ -1,5 +1,6 @@
{ {
"home": { "home": {
"vikunjaLoading": "Vikunja is loading…",
"welcomeNight": "Good Night {username}", "welcomeNight": "Good Night {username}",
"welcomeMorning": "Good Morning {username}", "welcomeMorning": "Good Morning {username}",
"welcomeDay": "Hi {username}", "welcomeDay": "Hi {username}",

View File

@ -43,6 +43,7 @@ export const store = createStore({
menuActive: true, menuActive: true,
keyboardShortcutsActive: false, keyboardShortcutsActive: false,
quickActionsActive: false, quickActionsActive: false,
vikunjaReady: false,
}, },
mutations: { mutations: {
[LOADING](state, loading) { [LOADING](state, loading) {
@ -84,6 +85,9 @@ export const store = createStore({
[BACKGROUND](state, background) { [BACKGROUND](state, background) {
state.background = background state.background = background
}, },
vikunjaReady(state, ready) {
state.vikunjaReady = ready
}
}, },
actions: { actions: {
async [CURRENT_LIST]({state, commit}, currentList) { async [CURRENT_LIST]({state, commit}, currentList) {
@ -138,5 +142,10 @@ export const store = createStore({
commit(CURRENT_LIST, currentList) commit(CURRENT_LIST, currentList)
}, },
async loadApp({commit, dispatch}) {
await dispatch('config/update')
await dispatch('auth/checkAuth')
commit('vikunjaReady', true)
},
}, },
}) })

View File

@ -1,17 +1,27 @@
// FIXME: move to loading.vue // FIXME: move to loading.vue
.loader-container.is-loading { .loader-container {
position: relative; &.is-loading {
pointer-events: none; position: relative;
opacity: 0.5; pointer-events: none;
opacity: 0.5;
&::after { &::after {
@include loader; @include loader;
position: absolute; position: absolute;
top: calc(50% - 2.5rem); top: calc(50% - 2.5rem);
left: calc(50% - 2.5rem); left: calc(50% - 2.5rem);
width: 5rem; width: 5rem;
height: 5rem; height: 5rem;
border-width: 0.25rem; border-width: 0.25rem;
}
}
&.is-loading-small.is-loading::after {
width: 1.5rem;
height: 1.5rem;
top: calc(50% - .75rem);
left: calc(50% - .75rem);
border-width: 2px;
} }
} }