import { type Signal, useComputed, useSignal } from '@preact/signals' import { useEffect } from 'preact/hooks' import { getStyleScope, useSmartStylesheet, } from ':plugins/SmartStylesheetIsland.tsx' type NetworkConnection = { addEventListener: ( type: 'change', listener: (event: Event) => void | Promise, ) => void } declare global { interface Navigator { connection?: NetworkConnection } } const scope = getStyleScope(IsOnline) export default function IsOnline( { online, offline }: { online?: string; offline: string }, ) { useSmartStylesheet(import.meta, { scope }) const status = useSignal(true) const displayed = useComputed(() => { if (status.value && online) { return {online} } if (status.value) { return } return {offline} }) useEffect(() => { openSocket(status) navigator.connection?.addEventListener('change', () => { fetch('/api/serviceworker/is-online') .then(() => status.value = true) .catch(() => status.value = false) }) }, []) return <>{displayed} } function openSocket(status: Signal, timeout = 5_000) { const socket = new WebSocket( `wss://${location.host}/api/serviceworker/is-online`, ) setTimeout(() => { if (socket.OPEN || socket.CONNECTING) return socket.close() }, timeout) socket.addEventListener('open', () => status.value = true) socket.addEventListener('close', () => { status.value = false setTimeout(() => openSocket(status), timeout) }) }