mirror of
https://github.com/koel/koel
synced 2024-12-01 00:09:17 +00:00
feat: notify when app comes offline (#1561)
This commit is contained in:
parent
cadc2d1d92
commit
260152b417
5 changed files with 69 additions and 1 deletions
|
@ -3,6 +3,7 @@
|
||||||
<DialogBox ref="dialog"/>
|
<DialogBox ref="dialog"/>
|
||||||
<MessageToaster ref="toaster"/>
|
<MessageToaster ref="toaster"/>
|
||||||
<GlobalEventListeners/>
|
<GlobalEventListeners/>
|
||||||
|
<OfflineNotification v-if="offline"/>
|
||||||
|
|
||||||
<div v-if="authenticated" id="main" @dragend="onDragEnd" @dragover="onDragOver" @drop="onDrop">
|
<div v-if="authenticated" id="main" @dragend="onDragEnd" @dragover="onDragOver" @drop="onDrop">
|
||||||
<Hotkeys/>
|
<Hotkeys/>
|
||||||
|
@ -29,10 +30,12 @@ import { eventBus, hideOverlay, requireInjection, showOverlay } from '@/utils'
|
||||||
import { commonStore, preferenceStore as preferences, queueStore } from '@/stores'
|
import { commonStore, preferenceStore as preferences, queueStore } from '@/stores'
|
||||||
import { authService, playbackService, socketListener, socketService, uploadService } from '@/services'
|
import { authService, playbackService, socketListener, socketService, uploadService } from '@/services'
|
||||||
import { CurrentSongKey, DialogBoxKey, MessageToasterKey, RouterKey } from '@/symbols'
|
import { CurrentSongKey, DialogBoxKey, MessageToasterKey, RouterKey } from '@/symbols'
|
||||||
|
import { useNetworkStatus } from '@/composables'
|
||||||
|
|
||||||
import DialogBox from '@/components/ui/DialogBox.vue'
|
import DialogBox from '@/components/ui/DialogBox.vue'
|
||||||
import MessageToaster from '@/components/ui/MessageToaster.vue'
|
import MessageToaster from '@/components/ui/MessageToaster.vue'
|
||||||
import Overlay from '@/components/ui/Overlay.vue'
|
import Overlay from '@/components/ui/Overlay.vue'
|
||||||
|
import OfflineNotification from '@/components/ui/OfflineNotification.vue'
|
||||||
|
|
||||||
// Do not dynamic-import app footer, as it contains the <audio> element
|
// Do not dynamic-import app footer, as it contains the <audio> element
|
||||||
// that is necessary to properly initialize the playService and equalizer.
|
// that is necessary to properly initialize the playService and equalizer.
|
||||||
|
@ -59,6 +62,8 @@ const currentSong = ref<Song | null>(null)
|
||||||
const authenticated = ref(false)
|
const authenticated = ref(false)
|
||||||
const showDropZone = ref(false)
|
const showDropZone = ref(false)
|
||||||
|
|
||||||
|
const { offline } = useNetworkStatus()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request for notification permission if it's not provided and the user is OK with notifications.
|
* Request for notification permission if it's not provided and the user is OK with notifications.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { clickaway, focus, tooltip } from '@/directives'
|
import { clickaway, focus, tooltip } from '@/directives'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
|
||||||
import { RouterKey } from '@/symbols'
|
import { RouterKey } from '@/symbols'
|
||||||
import { routes } from '@/config'
|
import { routes } from '@/config'
|
||||||
import Router from '@/router'
|
import Router from '@/router'
|
||||||
|
@ -9,6 +9,7 @@ import App from './App.vue'
|
||||||
createApp(App)
|
createApp(App)
|
||||||
.provide(RouterKey, new Router(routes))
|
.provide(RouterKey, new Router(routes))
|
||||||
.component('icon', FontAwesomeIcon)
|
.component('icon', FontAwesomeIcon)
|
||||||
|
.component('icon-layers', FontAwesomeLayers)
|
||||||
.directive('koel-focus', focus)
|
.directive('koel-focus', focus)
|
||||||
.directive('koel-clickaway', clickaway)
|
.directive('koel-clickaway', clickaway)
|
||||||
.directive('koel-tooltip', tooltip)
|
.directive('koel-tooltip', tooltip)
|
||||||
|
|
40
resources/assets/js/components/ui/OfflineNotification.vue
Normal file
40
resources/assets/js/components/ui/OfflineNotification.vue
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<template>
|
||||||
|
<div class="offline">
|
||||||
|
<icon-layers fixed-width>
|
||||||
|
<icon :icon="faWifi" fixed-width size="xl"/>
|
||||||
|
<icon :icon="faSlash" fixed-width size="lg" transform="up-2"/>
|
||||||
|
</icon-layers>
|
||||||
|
<span class="text">You’re offline.</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { faSlash, faWifi } from '@fortawesome/free-solid-svg-icons'</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.offline {
|
||||||
|
color: #ed5135;
|
||||||
|
width: 144px;
|
||||||
|
height: 42px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10000;
|
||||||
|
left: 1.6rem;
|
||||||
|
|
||||||
|
bottom: calc(var(--footer-height) + 1.2rem);
|
||||||
|
box-shadow: 0 2px 30px rgba(0, 0, 0, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-slash {
|
||||||
|
filter: drop-shadow(0 2px 0 #fff);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -9,3 +9,4 @@ export * from './useDragAndDrop'
|
||||||
export * from './useUpload'
|
export * from './useUpload'
|
||||||
export * from './useScreen'
|
export * from './useScreen'
|
||||||
export * from './usePlaylistManagement'
|
export * from './usePlaylistManagement'
|
||||||
|
export * from './useNetworkStatus'
|
||||||
|
|
21
resources/assets/js/composables/useNetworkStatus.ts
Normal file
21
resources/assets/js/composables/useNetworkStatus.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { computed, onUnmounted, ref } from 'vue'
|
||||||
|
|
||||||
|
export const useNetworkStatus = () => {
|
||||||
|
const online = ref(navigator.onLine)
|
||||||
|
const offline = computed(() => !online.value)
|
||||||
|
|
||||||
|
const updateOnlineStatus = () => (online.value = navigator.onLine)
|
||||||
|
|
||||||
|
window.addEventListener('online', updateOnlineStatus)
|
||||||
|
window.addEventListener('offline', updateOnlineStatus)
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('online', updateOnlineStatus)
|
||||||
|
window.removeEventListener('offline', updateOnlineStatus)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
online,
|
||||||
|
offline
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue