72 lines
1.6 KiB
Vue
72 lines
1.6 KiB
Vue
<script setup lang="ts">
|
|
import { translate } from '@/i18n'
|
|
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
|
|
const DEFAULT_MESSAGE =
|
|
"You're offline. You can keep writing, but saving and publishing will wait until you're back online."
|
|
|
|
const ROOMY_BLEED_ROOT = 'w-auto -mx-4 -mt-5 mb-5 lg:-mx-8 lg:-mt-8 lg:mb-8'
|
|
|
|
const BLEED_UI = {
|
|
root: 'w-auto -mx-4 -mt-4 mb-4 lg:-mx-6 lg:-mt-6 lg:mb-6',
|
|
container: 'h-auto min-h-10 max-w-none justify-start gap-2.5 px-4 py-2.5 sm:px-4 lg:px-4',
|
|
left: 'hidden lg:hidden',
|
|
icon: 'size-4',
|
|
title: 'whitespace-normal font-normal text-wrap',
|
|
}
|
|
|
|
const FLUSH_UI = { ...BLEED_UI, root: 'w-auto' }
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
message?: string
|
|
icon?: string
|
|
bleed?: boolean
|
|
roomy?: boolean
|
|
flush?: boolean
|
|
}>(),
|
|
{
|
|
message: DEFAULT_MESSAGE,
|
|
icon: undefined,
|
|
bleed: false,
|
|
roomy: false,
|
|
flush: false,
|
|
},
|
|
)
|
|
|
|
const bleedUi = computed(() => (props.roomy ? { ...BLEED_UI, root: ROOMY_BLEED_ROOT } : BLEED_UI))
|
|
const bannerUi = computed(() => {
|
|
if (props.flush) {
|
|
return FLUSH_UI
|
|
}
|
|
return props.bleed ? bleedUi.value : undefined
|
|
})
|
|
|
|
const isOffline = ref(!navigator.onLine)
|
|
|
|
function updateOnlineStatus() {
|
|
isOffline.value = !navigator.onLine
|
|
}
|
|
|
|
onMounted(() => {
|
|
window.addEventListener('online', updateOnlineStatus)
|
|
window.addEventListener('offline', updateOnlineStatus)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
window.removeEventListener('online', updateOnlineStatus)
|
|
window.removeEventListener('offline', updateOnlineStatus)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<UBanner
|
|
v-if="isOffline"
|
|
color="neutral"
|
|
:icon="icon"
|
|
:title="translate(message)"
|
|
:ui="bannerUi"
|
|
/>
|
|
</template>
|