feat: add fade in for background images
continuous-integration/drone/pr Build is failing Details

This commit is contained in:
kolaente 2021-12-20 21:36:33 +01:00
parent af177071d6
commit daf3212902
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
5 changed files with 117 additions and 83 deletions

View File

@ -1,13 +1,17 @@
<template> <template>
<div> <div>
<a @click="$store.commit('menuActive', false)" class="menu-hide-button" v-if="menuActive"> <a @click="$store.commit('menuActive', false)" class="menu-hide-button" v-if="menuActive">
<icon icon="times" /> <icon icon="times"/>
</a> </a>
<div <div
:class="{'has-background': background}" :class="{'has-background': background || blurHash}"
:style="{'background-image': background && `url(${background})`}" :style="{'background-image': blurHash && `url(${blurHash})`}"
class="app-container" class="app-container"
> >
<div
:class="{'is-visible': background}"
class="app-container-background"
:style="{'background-image': background && `url(${background})`}"></div>
<navigation/> <navigation/>
<div <div
:class="[ :class="[
@ -24,7 +28,7 @@
<router-view name="popup" v-slot="{ Component }"> <router-view name="popup" v-slot="{ Component }">
<transition name="modal"> <transition name="modal">
<component :is="Component" /> <component :is="Component"/>
</transition> </transition>
</router-view> </router-view>
@ -53,6 +57,7 @@ import QuickActions from '@/components/quick-actions/quick-actions.vue'
const store = useStore() const store = useStore()
const background = computed(() => store.state.background) const background = computed(() => store.state.background)
const blurHash = computed(() => store.state.blurHash)
const menuActive = computed(() => store.state.menuActive) const menuActive = computed(() => store.state.menuActive)
function showKeyboardShortcuts() { function showKeyboardShortcuts() {
@ -77,7 +82,7 @@ watch(() => route.fullPath, () => {
'migrate.start', 'migrate.start',
'migrate.wunderlist', 'migrate.wunderlist',
'namespaces.index', 'namespaces.index',
].includes(route.name) || ].includes(route.name) ||
route.name.startsWith('user.settings') route.name.startsWith('user.settings')
) { ) {
store.dispatch(CURRENT_LIST, null) store.dispatch(CURRENT_LIST, null)
@ -88,7 +93,7 @@ watch(() => route.fullPath, () => {
function useRenewTokenOnFocus() { function useRenewTokenOnFocus() {
const router = useRouter() const router = useRouter()
const userInfo = computed(() => store.state.auth.info) const userInfo = computed(() => store.state.auth.info)
const authenticated = computed(() => store.state.auth.authenticated) const authenticated = computed(() => store.state.auth.authenticated)
@ -152,40 +157,41 @@ store.dispatch('labels/loadAllLabels')
} }
.app-container { .app-container {
min-height: calc(100vh - 65px); min-height: calc(100vh - 65px);
@media screen and (max-width: $tablet) { @media screen and (max-width: $tablet) {
padding-top: $navbar-height; padding-top: $navbar-height;
}
.app-content {
padding: $navbar-height + 1.5rem 1.5rem 1rem 1.5rem;
z-index: 2;
@media screen and (max-width: $tablet) {
margin-left: 0;
padding-top: 1.5rem;
min-height: calc(100vh - 4rem);
}
&.is-menu-enabled {
margin-left: $navbar-width;
@media screen and (max-width: $tablet) {
min-width: 100%;
margin-left: 0;
}
}
&.task\.detail {
padding-left: 0;
padding-right: 0;
} }
.card { .app-content {
background: var(--white); padding: $navbar-height + 1.5rem 1.5rem 1rem 1.5rem;
} z-index: 10;
} position: relative;
@media screen and (max-width: $tablet) {
margin-left: 0;
padding-top: 1.5rem;
min-height: calc(100vh - 4rem);
}
&.is-menu-enabled {
margin-left: $navbar-width;
@media screen and (max-width: $tablet) {
min-width: 100%;
margin-left: 0;
}
}
&.task\.detail {
padding-left: 0;
padding-right: 0;
}
.card {
background: var(--white);
}
}
} }
.mobile-overlay { .mobile-overlay {
@ -214,7 +220,7 @@ store.dispatch('labels/loadAllLabels')
color: var(--grey-500); color: var(--grey-500);
transition: color $transition; transition: color $transition;
@media screen and (max-width: $tablet) { @media screen and (max-width: $tablet) {
display: none; display: none;
} }

View File

@ -2,6 +2,7 @@ import {createStore} from 'vuex'
import {getBlobFromBlurHash} from '../helpers/getBlobFromBlurHash' import {getBlobFromBlurHash} from '../helpers/getBlobFromBlurHash'
import { import {
BACKGROUND, BACKGROUND,
BLUR_HASH,
CURRENT_LIST, CURRENT_LIST,
HAS_TASKS, HAS_TASKS,
KEYBOARD_SHORTCUTS_ACTIVE, KEYBOARD_SHORTCUTS_ACTIVE,
@ -41,6 +42,7 @@ export const store = createStore({
// This is used to highlight the current list in menu for all list related views // This is used to highlight the current list in menu for all list related views
currentList: {id: 0}, currentList: {id: 0},
background: '', background: '',
blurHash: '',
hasTasks: false, hasTasks: false,
menuActive: true, menuActive: true,
keyboardShortcutsActive: false, keyboardShortcutsActive: false,
@ -87,6 +89,9 @@ export const store = createStore({
[BACKGROUND](state, background) { [BACKGROUND](state, background) {
state.background = background state.background = background
}, },
[BLUR_HASH](state, blurHash) {
state.blurHash = blurHash
},
vikunjaReady(state, ready) { vikunjaReady(state, ready) {
state.vikunjaReady = ready state.vikunjaReady = ready
}, },
@ -97,6 +102,7 @@ export const store = createStore({
if (currentList === null) { if (currentList === null) {
commit(CURRENT_LIST, {}) commit(CURRENT_LIST, {})
commit(BACKGROUND, null) commit(BACKGROUND, null)
commit(BLUR_HASH, null)
return return
} }
@ -130,8 +136,8 @@ export const store = createStore({
if (currentList.backgroundInformation) { if (currentList.backgroundInformation) {
try { try {
const blurHash = await getBlobFromBlurHash(currentList.backgroundBlurHash) const blurHash = await getBlobFromBlurHash(currentList.backgroundBlurHash)
if(blurHash) { if (blurHash) {
commit(BACKGROUND, window.URL.createObjectURL(blurHash)) commit(BLUR_HASH, window.URL.createObjectURL(blurHash))
} }
const listService = new ListService() const listService = new ListService()
@ -145,6 +151,7 @@ export const store = createStore({
if (typeof currentList.backgroundInformation === 'undefined' || currentList.backgroundInformation === null) { if (typeof currentList.backgroundInformation === 'undefined' || currentList.backgroundInformation === null) {
commit(BACKGROUND, null) commit(BACKGROUND, null)
commit(BLUR_HASH, null)
} }
commit(CURRENT_LIST, currentList) commit(CURRENT_LIST, currentList)

View File

@ -7,6 +7,7 @@ export const MENU_ACTIVE = 'menuActive'
export const KEYBOARD_SHORTCUTS_ACTIVE = 'keyboardShortcutsActive' export const KEYBOARD_SHORTCUTS_ACTIVE = 'keyboardShortcutsActive'
export const QUICK_ACTIONS_ACTIVE = 'quickActionsActive' export const QUICK_ACTIONS_ACTIVE = 'quickActionsActive'
export const BACKGROUND = 'background' export const BACKGROUND = 'background'
export const BLUR_HASH = 'blurHash'
export const CONFIG = 'config' export const CONFIG = 'config'
export const AUTH = 'auth' export const AUTH = 'auth'

View File

@ -1,12 +1,16 @@
.app-container.has-background, .app-container.has-background,
.link-share-container.has-background { .link-share-container.has-background {
background-position: center; position: relative;
background-size: cover;
background-repeat: no-repeat;
background-attachment: fixed;
min-height: 100vh;
// FIXME: move to pagination component &, .app-container-background {
background-position: center;
background-size: cover;
background-repeat: no-repeat;
background-attachment: fixed;
min-height: 100vh;
}
// FIXME: move to pagination component
.pagination-link:not(.is-current) { .pagination-link:not(.is-current) {
background: var(--grey-100); background: var(--grey-100);
} }
@ -32,4 +36,18 @@
border-radius: $radius !important; border-radius: $radius !important;
} }
} }
} }
.app-container-background {
width: 100vw;
height: 100vh;
position: fixed;
z-index: 0;
opacity: 0;
transition: opacity $transition;
transition-delay: $transition-duration * 2; // To fake an appearing background
&.is-visible {
opacity: 1;
}
}

View File

@ -71,7 +71,7 @@ export default {
computed: { computed: {
// Computed property to let "listId" always have a value // Computed property to let "listId" always have a value
listId() { listId() {
return typeof this.$route.params.listId === 'undefined' ? 0 : this.$route.params.listId return typeof this.$route.params.listId === 'undefined' ? 0 : parseInt(this.$route.params.listId)
}, },
background() { background() {
return this.$store.state.background return this.$store.state.background
@ -99,9 +99,11 @@ export default {
const listData = {id: parseInt(this.$route.params.listId)} const listData = {id: parseInt(this.$route.params.listId)}
saveListToHistory(listData) saveListToHistory(listData)
this.setTitle(this.currentList.id ? this.getListTitle(this.currentList) : '') this.setTitle(this.currentList.id ? this.getListTitle(this.currentList) : '')
const listFromStore = this.$store.getters['lists/getListById'](this.listId)
await this.$store.dispatch(CURRENT_LIST, listFromStore)
// This invalidates the loaded list at the kanban board which lets it reload its content when // This invalidates the loaded list at the kanban board which lets it reload its content when
// switched to it. This ensures updates done to tasks in the gantt or list views are consistently // switched to it. This ensures updates done to tasks in the gantt or list views are consistently
// shown in all views while preventing reloads when closing a task popup. // shown in all views while preventing reloads when closing a task popup.
@ -161,51 +163,51 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.switch-view-container { .switch-view-container {
@media screen and (max-width: $tablet) { @media screen and (max-width: $tablet) {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
} }
.switch-view { .switch-view {
background: var(--white); background: var(--white);
display: inline-flex; display: inline-flex;
border-radius: $radius; border-radius: $radius;
font-size: .75rem; font-size: .75rem;
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-sm);
height: $switch-view-height; height: $switch-view-height;
margin-bottom: 1rem; margin-bottom: 1rem;
padding: .5rem; padding: .5rem;
a { a {
padding: .25rem .5rem; padding: .25rem .5rem;
display: block; display: block;
border-radius: $radius; border-radius: $radius;
transition: all 100ms; transition: all 100ms;
&:not(:last-child) { &:not(:last-child) {
margin-right: .5rem; margin-right: .5rem;
} }
&.is-active, &.is-active,
&:hover { &:hover {
color: var(--switch-view-color); color: var(--switch-view-color);
} }
&.is-active { &.is-active {
background: var(--primary); background: var(--primary);
font-weight: bold; font-weight: bold;
box-shadow: var(--shadow-xs); box-shadow: var(--shadow-xs);
} }
&:hover { &:hover {
background: var(--primary); background: var(--primary);
} }
} }
} }
.is-archived .notification.is-warning { .is-archived .notification.is-warning {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
</style> </style>