feat: move update from navigation to app #2997

Merged
dpschen merged 3 commits from dpschen/frontend:feature/move-update-to-app into main 2023-02-03 16:34:49 +00:00
7 changed files with 56 additions and 62 deletions

View File

@ -8,9 +8,13 @@
<no-auth-wrapper v-else> <no-auth-wrapper v-else>
<router-view/> <router-view/>
</no-auth-wrapper> </no-auth-wrapper>
<Notification/>
<keyboard-shortcuts v-if="keyboardShortcutsActive"/> <keyboard-shortcuts v-if="keyboardShortcutsActive"/>
<Teleport to="body">
<UpdateNotification/>
<Notification/>
</Teleport>
</ready> </ready>
</template> </template>
@ -19,23 +23,26 @@ import {computed, watch} from 'vue'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import isTouchDevice from 'is-touch-device' import isTouchDevice from 'is-touch-device'
import {success} from '@/message'
import Notification from '@/components/misc/notification.vue' import Notification from '@/components/misc/notification.vue'
import KeyboardShortcuts from './components/misc/keyboard-shortcuts/index.vue' import UpdateNotification from '@/components/home/UpdateNotification.vue'
import KeyboardShortcuts from '@/components/misc/keyboard-shortcuts/index.vue'
import TheNavigation from '@/components/home/TheNavigation.vue' import TheNavigation from '@/components/home/TheNavigation.vue'
import ContentAuth from './components/home/contentAuth.vue' import ContentAuth from '@/components/home/contentAuth.vue'
import ContentLinkShare from './components/home/contentLinkShare.vue' import ContentLinkShare from '@/components/home/contentLinkShare.vue'
import NoAuthWrapper from '@/components/misc/no-auth-wrapper.vue' import NoAuthWrapper from '@/components/misc/no-auth-wrapper.vue'
import Ready from '@/components/misc/ready.vue' import Ready from '@/components/misc/ready.vue'
import {setLanguage} from './i18n' import {setLanguage} from '@/i18n'
import AccountDeleteService from '@/services/accountDelete' import AccountDeleteService from '@/services/accountDelete'
import {success} from '@/message'
import {useAuthStore} from '@/stores/auth'
import {useBaseStore} from '@/stores/base' import {useBaseStore} from '@/stores/base'
import {useColorScheme} from '@/composables/useColorScheme' import {useColorScheme} from '@/composables/useColorScheme'
import {useBodyClass} from '@/composables/useBodyClass' import {useBodyClass} from '@/composables/useBodyClass'
import {useAuthStore} from './stores/auth'
const baseStore = useBaseStore() const baseStore = useBaseStore()
const authStore = useAuthStore() const authStore = useAuthStore()

View File

@ -25,7 +25,6 @@
</div> </div>
<div class="navbar-end"> <div class="navbar-end">
<update/>
<BaseButton <BaseButton
@click="openQuickActions" @click="openQuickActions"
class="trigger-button pr-0" class="trigger-button pr-0"
@ -95,7 +94,6 @@ import {ref, computed, onMounted, nextTick} from 'vue'
import {RIGHTS as Rights} from '@/constants/rights' import {RIGHTS as Rights} from '@/constants/rights'
import Update from '@/components/home/update.vue'
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue' import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
import Dropdown from '@/components/misc/dropdown.vue' import Dropdown from '@/components/misc/dropdown.vue'
import DropdownItem from '@/components/misc/dropdown-item.vue' import DropdownItem from '@/components/misc/dropdown-item.vue'

View File

@ -1,7 +1,11 @@
<template> <template>
<div class="update-notification" v-if="updateAvailable"> <div class="update-notification" v-if="updateAvailable">
<p>{{ $t('update.available') }}</p> <p class="update-notification__message">{{ $t('update.available') }}</p>
<x-button @click="refreshApp()" :shadow="false" class="has-no-text-wrap"> <x-button
@click="refreshApp()"
:shadow="false"
:wrap="false"
>
{{ $t('update.do') }} {{ $t('update.do') }}
</x-button> </x-button>
</div> </div>
@ -16,15 +20,13 @@ const refreshing = ref(false)
document.addEventListener('swUpdated', showRefreshUI, {once: true}) document.addEventListener('swUpdated', showRefreshUI, {once: true})
if (navigator && navigator.serviceWorker) { navigator?.serviceWorker?.addEventListener(
navigator.serviceWorker.addEventListener( 'controllerchange', () => {
'controllerchange', () => { if (refreshing.value) return
if (refreshing.value) return refreshing.value = true
refreshing.value = true window.location.reload()
window.location.reload() },
}, )
)
}
function showRefreshUI(e: Event) { function showRefreshUI(e: Event) {
console.log('recieved refresh event', e) console.log('recieved refresh event', e)
@ -33,6 +35,7 @@ function showRefreshUI(e: Event) {
} }
function refreshApp() { function refreshApp() {
updateAvailable.value = false
if (!registration.value || !registration.value.waiting) { if (!registration.value || !registration.value.waiting) {
return return
} }
@ -43,39 +46,30 @@ function refreshApp() {
<style lang="scss" scoped> <style lang="scss" scoped>
.update-notification { .update-notification {
position: fixed;
// FIXME: We should prevent usage of z-index or
// at least define it centrally
// the highest z-index of a modal is .hint-modal with 4500
z-index: 5000;
bottom: 1rem;
inset-inline: 1rem;
max-width: max-content;
margin-inline: auto;
display: flex; display: flex;
align-items: center; align-items: center;
background: $warning; justify-content: space-between;
gap: 1rem;
padding: .5rem; padding: .5rem;
background: $warning;
border-radius: $radius; border-radius: $radius;
font-size: .9rem; font-size: .9rem;
color: var(--grey-900); color: var(--grey-900);
justify-content: space-between;
position: fixed;
bottom: 1rem;
width: 450px;
left: calc(50vw - 225px);
@media screen and (max-width: $tablet) {
position: fixed;
left: 1rem;
right: 1rem;
bottom: 1rem;
width: auto;
}
p {
text-align: center;
width: 100%;
}
> * + * {
margin-left: .5rem;
}
} }
.dark .update-notification { .update-notification__message {
color: var(--grey-200); width: 100%;
text-align: center;
} }
</style> </style>

View File

@ -224,9 +224,4 @@ labelStore.loadAllLabels()
position: relative; position: relative;
z-index: 1; z-index: 1;
} }
.is-touch .content-auth,
.content-auth.z-unset {
z-index: unset;
}
</style> </style>

View File

@ -8,17 +8,20 @@
'has-no-shadow': !shadow || variant === 'tertiary', 'has-no-shadow': !shadow || variant === 'tertiary',
} }
]" ]"
:style="{
'--button-white-space': wrap ? 'break-spaces' : 'nowrap',
}"
> >
<template v-if="icon"> <template v-if="icon">
<icon <icon
v-if="showIconOnly" v-if="showIconOnly"
:icon="icon" :icon="icon"
:style="{'color': iconColor !== '' ? iconColor : false}" :style="{'color': iconColor !== '' ? iconColor : undefined}"
/> />
<span class="icon is-small" v-else> <span class="icon is-small" v-else>
<icon <icon
:icon="icon" :icon="icon"
:style="{'color': iconColor !== '' ? iconColor : false}" :style="{'color': iconColor !== '' ? iconColor : undefined}"
/> />
</span> </span>
</template> </template>
@ -50,6 +53,7 @@ export interface ButtonProps extends BaseButtonProps {
iconColor?: string iconColor?: string
loading?: boolean loading?: boolean
shadow?: boolean shadow?: boolean
wrap?: boolean
} }
const { const {
@ -58,6 +62,7 @@ const {
iconColor = '', iconColor = '',
loading = false, loading = false,
shadow = true, shadow = true,
wrap = true,
} = defineProps<ButtonProps>() } = defineProps<ButtonProps>()
const variantClass = computed(() => BUTTON_TYPES_MAP[variant]) const variantClass = computed(() => BUTTON_TYPES_MAP[variant])
@ -67,7 +72,7 @@ const showIconOnly = computed(() => icon !== '' && typeof slots.default === 'und
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.button { :where(.button) {
transition: all $transition; transition: all $transition;
border: 0; border: 0;
text-transform: uppercase; text-transform: uppercase;
@ -77,7 +82,7 @@ const showIconOnly = computed(() => icon !== '' && typeof slots.default === 'und
min-height: $button-height; min-height: $button-height;
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-sm);
display: inline-flex; display: inline-flex;
white-space: break-spaces; white-space: var(--button-white-space);
&:hover { &:hover {
box-shadow: var(--shadow-md); box-shadow: var(--shadow-md);
@ -99,7 +104,6 @@ const showIconOnly = computed(() => icon !== '' && typeof slots.default === 'und
&.is-primary.is-outlined:hover { &.is-primary.is-outlined:hover {
color: var(--white); color: var(--white);
} }
} }
.is-small { .is-small {

View File

@ -915,7 +915,7 @@
} }
}, },
"update": { "update": {
"available": "There is an update for Vikunja available!", "available": "There is an update available!",
"do": "Update Now" "do": "Update Now"
}, },
"menu": { "menu": {

View File

@ -2,8 +2,4 @@
@media print { @media print {
display: none !important; display: none !important;
} }
} }
.has-no-text-wrap {
white-space: nowrap !important;
}