feat: use blurHash when loading list backgrounds #1188
|
@ -1,13 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<a @click="$store.commit('menuActive', false)" class="menu-hide-button" v-if="menuActive">
|
||||
<icon icon="times" />
|
||||
<icon icon="times"/>
|
||||
</a>
|
||||
<div
|
||||
:class="{'has-background': background}"
|
||||
:style="{'background-image': background && `url(${background})`}"
|
||||
:class="{'has-background': background || blurHash}"
|
||||
:style="{'background-image': blurHash && `url(${blurHash})`}"
|
||||
class="app-container"
|
||||
>
|
||||
<div
|
||||
:class="{'is-visible': background}"
|
||||
class="app-container-background"
|
||||
:style="{'background-image': background && `url(${background})`}"></div>
|
||||
<navigation/>
|
||||
<div
|
||||
:class="[
|
||||
|
@ -24,7 +28,7 @@
|
|||
|
||||
<router-view name="popup" v-slot="{ Component }">
|
||||
<transition name="modal">
|
||||
<component :is="Component" />
|
||||
<component :is="Component"/>
|
||||
</transition>
|
||||
</router-view>
|
||||
|
||||
|
@ -53,6 +57,7 @@ import QuickActions from '@/components/quick-actions/quick-actions.vue'
|
|||
const store = useStore()
|
||||
|
||||
const background = computed(() => store.state.background)
|
||||
const blurHash = computed(() => store.state.blurHash)
|
||||
const menuActive = computed(() => store.state.menuActive)
|
||||
|
||||
function showKeyboardShortcuts() {
|
||||
|
@ -77,7 +82,7 @@ watch(() => route.fullPath, () => {
|
|||
'migrate.start',
|
||||
'migrate.wunderlist',
|
||||
'namespaces.index',
|
||||
].includes(route.name) ||
|
||||
].includes(route.name) ||
|
||||
route.name.startsWith('user.settings')
|
||||
) {
|
||||
store.dispatch(CURRENT_LIST, null)
|
||||
|
@ -88,7 +93,7 @@ watch(() => route.fullPath, () => {
|
|||
|
||||
function useRenewTokenOnFocus() {
|
||||
const router = useRouter()
|
||||
|
||||
|
||||
const userInfo = computed(() => store.state.auth.info)
|
||||
const authenticated = computed(() => store.state.auth.authenticated)
|
||||
|
||||
|
@ -152,40 +157,41 @@ store.dispatch('labels/loadAllLabels')
|
|||
}
|
||||
|
||||
.app-container {
|
||||
min-height: calc(100vh - 65px);
|
||||
min-height: calc(100vh - 65px);
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
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;
|
||||
@media screen and (max-width: $tablet) {
|
||||
padding-top: $navbar-height;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--white);
|
||||
}
|
||||
}
|
||||
.app-content {
|
||||
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 {
|
||||
|
@ -214,7 +220,7 @@ store.dispatch('labels/loadAllLabels')
|
|||
|
||||
color: var(--grey-500);
|
||||
transition: color $transition;
|
||||
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import {createStore} from 'vuex'
|
|||
import {getBlobFromBlurHash} from '../helpers/getBlobFromBlurHash'
|
||||
import {
|
||||
BACKGROUND,
|
||||
BLUR_HASH,
|
||||
CURRENT_LIST,
|
||||
HAS_TASKS,
|
||||
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
|
||||
currentList: {id: 0},
|
||||
background: '',
|
||||
blurHash: '',
|
||||
hasTasks: false,
|
||||
menuActive: true,
|
||||
keyboardShortcutsActive: false,
|
||||
|
@ -87,6 +89,9 @@ export const store = createStore({
|
|||
[BACKGROUND](state, background) {
|
||||
state.background = background
|
||||
},
|
||||
[BLUR_HASH](state, blurHash) {
|
||||
state.blurHash = blurHash
|
||||
},
|
||||
vikunjaReady(state, ready) {
|
||||
state.vikunjaReady = ready
|
||||
},
|
||||
|
@ -97,6 +102,7 @@ export const store = createStore({
|
|||
if (currentList === null) {
|
||||
commit(CURRENT_LIST, {})
|
||||
commit(BACKGROUND, null)
|
||||
commit(BLUR_HASH, null)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -130,8 +136,8 @@ export const store = createStore({
|
|||
if (currentList.backgroundInformation) {
|
||||
try {
|
||||
const blurHash = await getBlobFromBlurHash(currentList.backgroundBlurHash)
|
||||
if(blurHash) {
|
||||
commit(BACKGROUND, window.URL.createObjectURL(blurHash))
|
||||
if (blurHash) {
|
||||
commit(BLUR_HASH, window.URL.createObjectURL(blurHash))
|
||||
}
|
||||
|
||||
const listService = new ListService()
|
||||
|
@ -145,6 +151,7 @@ export const store = createStore({
|
|||
|
||||
if (typeof currentList.backgroundInformation === 'undefined' || currentList.backgroundInformation === null) {
|
||||
commit(BACKGROUND, null)
|
||||
commit(BLUR_HASH, null)
|
||||
}
|
||||
|
||||
commit(CURRENT_LIST, currentList)
|
||||
|
|
|
@ -7,6 +7,7 @@ export const MENU_ACTIVE = 'menuActive'
|
|||
export const KEYBOARD_SHORTCUTS_ACTIVE = 'keyboardShortcutsActive'
|
||||
export const QUICK_ACTIONS_ACTIVE = 'quickActionsActive'
|
||||
export const BACKGROUND = 'background'
|
||||
export const BLUR_HASH = 'blurHash'
|
||||
|
||||
export const CONFIG = 'config'
|
||||
export const AUTH = 'auth'
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
.app-container.has-background,
|
||||
.link-share-container.has-background {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
|
||||
// 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) {
|
||||
background: var(--grey-100);
|
||||
}
|
||||
|
@ -32,4 +36,18 @@
|
|||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ export default {
|
|||
computed: {
|
||||
// Computed property to let "listId" always have a value
|
||||
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() {
|
||||
return this.$store.state.background
|
||||
|
@ -99,9 +99,11 @@ export default {
|
|||
const listData = {id: parseInt(this.$route.params.listId)}
|
||||
|
||||
saveListToHistory(listData)
|
||||
|
||||
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
|
||||
// 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.
|
||||
|
@ -161,51 +163,51 @@ export default {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
.switch-view-container {
|
||||
@media screen and (max-width: $tablet) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
@media screen and (max-width: $tablet) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.switch-view {
|
||||
background: var(--white);
|
||||
display: inline-flex;
|
||||
border-radius: $radius;
|
||||
font-size: .75rem;
|
||||
box-shadow: var(--shadow-sm);
|
||||
height: $switch-view-height;
|
||||
margin-bottom: 1rem;
|
||||
padding: .5rem;
|
||||
background: var(--white);
|
||||
display: inline-flex;
|
||||
border-radius: $radius;
|
||||
font-size: .75rem;
|
||||
box-shadow: var(--shadow-sm);
|
||||
height: $switch-view-height;
|
||||
margin-bottom: 1rem;
|
||||
padding: .5rem;
|
||||
|
||||
a {
|
||||
padding: .25rem .5rem;
|
||||
display: block;
|
||||
border-radius: $radius;
|
||||
a {
|
||||
padding: .25rem .5rem;
|
||||
display: block;
|
||||
border-radius: $radius;
|
||||
|
||||
transition: all 100ms;
|
||||
transition: all 100ms;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
&:not(:last-child) {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
&.is-active,
|
||||
&:hover {
|
||||
color: var(--switch-view-color);
|
||||
}
|
||||
&.is-active,
|
||||
&:hover {
|
||||
color: var(--switch-view-color);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: var(--primary);
|
||||
font-weight: bold;
|
||||
box-shadow: var(--shadow-xs);
|
||||
}
|
||||
&.is-active {
|
||||
background: var(--primary);
|
||||
font-weight: bold;
|
||||
box-shadow: var(--shadow-xs);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--primary);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-archived .notification.is-warning {
|
||||
margin-bottom: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user
I'm not quite sure why
<transition>
did not work here.