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 untrusted user: konrad
GPG Key ID: F40E70337AB24C9B
6 changed files with 105 additions and 57 deletions

View File

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

View File

@ -48,7 +48,7 @@
</ul>
</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" >
<div class="namespace-title" :class="{'has-menu': n.id > 0}">
<span
@ -105,7 +105,7 @@
>
<template #item="{element: l}">
<li
class="loader-container"
class="loader-container is-loading-small"
:class="{'is-loading': listUpdating[l.id]}"
>
<router-link
@ -449,14 +449,6 @@ $vikunja-nav-selected-width: 0.4rem;
&:hover :deep(.dropdown-trigger) {
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 {
@ -530,14 +522,6 @@ $vikunja-nav-selected-width: 0.4rem;
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 {
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": {
"vikunjaLoading": "Vikunja is loading…",
"welcomeNight": "Good Night {username}",
"welcomeMorning": "Good Morning {username}",
"welcomeDay": "Hi {username}",

View File

@ -43,6 +43,7 @@ export const store = createStore({
menuActive: true,
keyboardShortcutsActive: false,
quickActionsActive: false,
vikunjaReady: false,
},
mutations: {
[LOADING](state, loading) {
@ -84,6 +85,9 @@ export const store = createStore({
[BACKGROUND](state, background) {
state.background = background
},
vikunjaReady(state, ready) {
state.vikunjaReady = ready
}
},
actions: {
async [CURRENT_LIST]({state, commit}, currentList) {
@ -138,5 +142,10 @@ export const store = createStore({
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
.loader-container.is-loading {
position: relative;
pointer-events: none;
opacity: 0.5;
.loader-container {
&.is-loading {
position: relative;
pointer-events: none;
opacity: 0.5;
&::after {
@include loader;
position: absolute;
top: calc(50% - 2.5rem);
left: calc(50% - 2.5rem);
width: 5rem;
height: 5rem;
border-width: 0.25rem;
&::after {
@include loader;
position: absolute;
top: calc(50% - 2.5rem);
left: calc(50% - 2.5rem);
width: 5rem;
height: 5rem;
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;
}
}