47 lines
1.3 KiB
Svelte
47 lines
1.3 KiB
Svelte
|
|
<script>
|
||
|
|
import { onMount, onDestroy } from 'svelte'
|
||
|
|
import { getLastSync } from '../db.js'
|
||
|
|
import { syncPull } from '../sync.js'
|
||
|
|
|
||
|
|
let online = $state(navigator.onLine)
|
||
|
|
let syncing = $state(false)
|
||
|
|
let lastSync = $state('')
|
||
|
|
|
||
|
|
async function refresh() {
|
||
|
|
lastSync = await getLastSync()
|
||
|
|
}
|
||
|
|
|
||
|
|
async function manualSync() {
|
||
|
|
syncing = true
|
||
|
|
await syncPull()
|
||
|
|
await refresh()
|
||
|
|
syncing = false
|
||
|
|
}
|
||
|
|
|
||
|
|
function onOnline() { online = true; manualSync() }
|
||
|
|
function onOffline() { online = false }
|
||
|
|
|
||
|
|
onMount(() => {
|
||
|
|
refresh()
|
||
|
|
window.addEventListener('online', onOnline)
|
||
|
|
window.addEventListener('offline', onOffline)
|
||
|
|
})
|
||
|
|
onDestroy(() => {
|
||
|
|
window.removeEventListener('online', onOnline)
|
||
|
|
window.removeEventListener('offline', onOffline)
|
||
|
|
})
|
||
|
|
|
||
|
|
const dotClass = $derived(syncing ? 'syncing' : online ? 'online' : 'offline')
|
||
|
|
const label = $derived(syncing ? 'Syncing…' : online ? 'Online' : 'Offline')
|
||
|
|
const lastSyncLabel = $derived(lastSync ? new Date(lastSync).toLocaleTimeString() : 'Never')
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<div class="sync-bar">
|
||
|
|
<div class="sync-dot {dotClass}"></div>
|
||
|
|
<span>{label}</span>
|
||
|
|
<span class="text-muted" style="margin-left:auto;font-size:0.72rem">Last sync: {lastSyncLabel}</span>
|
||
|
|
{#if online && !syncing}
|
||
|
|
<button class="btn btn-ghost btn-sm" onclick={manualSync}>↻</button>
|
||
|
|
{/if}
|
||
|
|
</div>
|