feat(pwa): ✨ add network status banner
This commit is contained in:
parent
5716284c73
commit
00c40f2569
13
islands/IsOnline.css
Normal file
13
islands/IsOnline.css
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
.island__is_online {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
padding: var(--_gap-half);
|
||||||
|
/* invert accent color */
|
||||||
|
background: hsl(from #82c91e calc(h + 180) s l / 1);
|
||||||
|
font-family: var(--_font-family-accent);
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
52
islands/IsOnline.tsx
Normal file
52
islands/IsOnline.tsx
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { type Signal, useSignal } from '@preact/signals'
|
||||||
|
import { useEffect } from 'preact/hooks'
|
||||||
|
import { JSX } from 'preact'
|
||||||
|
import { requestApi } from ':src/utils.ts'
|
||||||
|
|
||||||
|
type NetworkConnection = {
|
||||||
|
addEventListener: (
|
||||||
|
type: 'change',
|
||||||
|
listener: (event: Event) => void | Promise<void>,
|
||||||
|
) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function IsOnline(
|
||||||
|
{ online, offline }: { online?: string; offline: string },
|
||||||
|
) {
|
||||||
|
const status = useSignal(offline)
|
||||||
|
const connection = 'connection' in navigator
|
||||||
|
? navigator.connection as NetworkConnection
|
||||||
|
: null
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Update connection status on network changes
|
||||||
|
connection?.addEventListener('change', () => {
|
||||||
|
updateNetworkStatus(status, online, offline)
|
||||||
|
})
|
||||||
|
// Update connection status on 1st load
|
||||||
|
updateNetworkStatus(status, online, offline)
|
||||||
|
// Update connection status on interval (10s)
|
||||||
|
setInterval(() => updateNetworkStatus(status, online, offline), 10_000)
|
||||||
|
})
|
||||||
|
|
||||||
|
return <>{status}</>
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateNetworkStatus(
|
||||||
|
status: Signal<JSX.Element>,
|
||||||
|
online: string | undefined,
|
||||||
|
offline: string,
|
||||||
|
) {
|
||||||
|
const isOnline = await requestApi<void, boolean>(
|
||||||
|
'/serviceworker/is-online',
|
||||||
|
'POST',
|
||||||
|
).catch(() => false)
|
||||||
|
|
||||||
|
if (isOnline) {
|
||||||
|
status.value = online === undefined
|
||||||
|
? <span style={{ display: 'none' }}></span>
|
||||||
|
: <span>{online}</span>
|
||||||
|
} else {
|
||||||
|
status.value = <span class={'island__is_online'}>{offline}</span>
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import { type PageProps } from '$fresh/server.ts'
|
||||||
import { Footer } from ':components/Footer.tsx'
|
import { Footer } from ':components/Footer.tsx'
|
||||||
import { Header } from ':components/Header.tsx'
|
import { Header } from ':components/Header.tsx'
|
||||||
import { ProgressiveWebApp } from ':components/ProgressiveWebApp.tsx'
|
import { ProgressiveWebApp } from ':components/ProgressiveWebApp.tsx'
|
||||||
|
import IsOnline from ':islands/IsOnline.tsx'
|
||||||
|
|
||||||
export default function App({ Component }: PageProps) {
|
export default function App({ Component }: PageProps) {
|
||||||
return (
|
return (
|
||||||
|
@ -42,6 +43,9 @@ export default function App({ Component }: PageProps) {
|
||||||
</Head>
|
</Head>
|
||||||
<body>
|
<body>
|
||||||
<Header />
|
<Header />
|
||||||
|
<IsOnline
|
||||||
|
offline={'Vous êtes hors ligne / Serveur inaccessible'}
|
||||||
|
/>
|
||||||
<main f-client-nav>
|
<main f-client-nav>
|
||||||
<Partial name='main'>
|
<Partial name='main'>
|
||||||
<Component />
|
<Component />
|
||||||
|
|
9
routes/api/serviceworker/is-online.tsx
Normal file
9
routes/api/serviceworker/is-online.tsx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { SessionHandlers } from ':src/session/mod.ts'
|
||||||
|
import { respondApi } from ':src/utils.ts'
|
||||||
|
|
||||||
|
export const handler: SessionHandlers = {
|
||||||
|
POST() {
|
||||||
|
// Check if server is online
|
||||||
|
return respondApi<'success', true>('success', true)
|
||||||
|
},
|
||||||
|
}
|
|
@ -13,3 +13,4 @@
|
||||||
@import url('../../islands/MoreBox.css');
|
@import url('../../islands/MoreBox.css');
|
||||||
@import url('../../islands/AiChatBox.css');
|
@import url('../../islands/AiChatBox.css');
|
||||||
@import url('../../islands/LoginForm.css');
|
@import url('../../islands/LoginForm.css');
|
||||||
|
@import url('../../islands/IsOnline.css');
|
||||||
|
|
Loading…
Reference in a new issue