Improve live indications (Smaller, but maybe marginally less user friendly?) Shorten poll interval for boards due to backend optimizations.

ensure data is reloaded when tab/page becomes visible.
This commit is contained in:
2026-05-21 20:06:33 +01:00
parent f30a2745d4
commit 22aee0b915
2 changed files with 47 additions and 61 deletions

View File

@@ -1,49 +0,0 @@
<div class="cont">
<div class="flash"></div>
<span class="txt">Live</span>
</div>
<style>
.cont {
display: inline-flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
font-family: 'URW Gothic', sans-serif;
font-weight: 600;
letter-spacing: 0.15ch;
}
.flash {
height: 0.6rem;
width: 0.6rem;
margin: 0 0.35rem;
border-radius: 50%;
background-color: forestgreen;
animation: live-pulse 1s ease-in-out infinite;
}
.txt {
animation: live-text-pulse 1s ease-in-out infinite;
}
@keyframes live-pulse {
0%, 100% {
box-shadow: 0 0 14px forestgreen;
filter: opacity(1) saturate(1);
}
50% {
box-shadow: 0 0 2px forestgreen;
filter: opacity(0.2) saturate(0.95);
}
}
@keyframes live-text-pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.65;
}
}
</style>

View File

@@ -6,12 +6,14 @@
import { formatUkDateTime, formatUkTime } from '$lib/utils/time'; import { formatUkDateTime, formatUkTime } from '$lib/utils/time';
import StaffServicesTable from '$lib/components/ui/station-board/StaffServicesTable.svelte'; import StaffServicesTable from '$lib/components/ui/station-board/StaffServicesTable.svelte';
import LiveIndicator from '$lib/components/ui/LiveIndicator.svelte';
import StaffServicesGrid from '$lib/components/ui/station-board/StaffServicesGrid.svelte'; import StaffServicesGrid from '$lib/components/ui/station-board/StaffServicesGrid.svelte';
let { data } = $props(); let { data } = $props();
let now = $state(new Date()); let now = $state(new Date());
let live = $state(false); let dataAgeInSeconds = $derived(
Math.floor((now.getTime() - new Date(data.boardData.producedAt).getTime()) / 1000)
);
let live = $derived(dataAgeInSeconds < 45);
// Handle auto-refreshing & Wake-lock // Handle auto-refreshing & Wake-lock
$effect(() => { $effect(() => {
@@ -50,10 +52,8 @@
await invalidateAll(); await invalidateAll();
} catch (error) { } catch (error) {
console.error("Background data fetch failed: ", error) console.error("Background data fetch failed: ", error)
live = false;
} }
}, 60100); }, 20000);
live = true;
console.log("Polling started") console.log("Polling started")
}; };
@@ -66,11 +66,12 @@
await releaseWakeLock(); await releaseWakeLock();
}; };
const handleVisibilityChange = () => { const handleVisibilityChange = async () => {
if (document.hidden) { if (document.hidden) {
stopPolling(); stopPolling();
} else { } else {
startPolling(); startPolling();
await invalidateAll();
} }
}; };
@@ -115,17 +116,15 @@ $effect(() => {
</script> </script>
<section class="board-wrapper"> <section class="board-wrapper">
<div class="time-data"> <div class="time-data">
<div class="loadedlive">
<div class="liveflash {live ? 'isLive' : 'notLive'}"></div>
<span class="time-loaded">Updated: {formatUkDateTime(data.boardData.producedAt, true)}</span> <span class="time-loaded">Updated: {formatUkDateTime(data.boardData.producedAt, true)}</span>
</div>
<span class="time-now">{formatUkTime(now, true)}</span> <span class="time-now">{formatUkTime(now, true)}</span>
</div> </div>
{#if data.boardData.data.m?.length} {#if data.boardData.data.m?.length}
<StationAlertCard messages={data.boardData.data.m} /> <StationAlertCard messages={data.boardData.data.m} />
{/if} {/if}
{#if live}
<div class="live-indicator">
<LiveIndicator />
</div>
{/if}
{#if data.boardData.data.s?.length} {#if data.boardData.data.s?.length}
<div class="service-list-wrapper"> <div class="service-list-wrapper">
<StaffServicesGrid services={data.boardData.data.s} /> <StaffServicesGrid services={data.boardData.data.s} />
@@ -155,6 +154,42 @@ $effect(() => {
font-family: 'URW Gothic', sans-serif; font-family: 'URW Gothic', sans-serif;
} }
.loadedlive {
display: inline-flex;
justify-content: center;
align-items: center;
gap: 1rem;
}
.liveflash {
width: 12px;
height: 12px;
border-radius: 50%;
transition: all 0.3s ease;
}
div.notLive {
background-color: #ef4444;
animation:
led-blink 1s steps(1, start) infinite,
led-halo-expand 1s steps(1, start) infinite;
}
div.isLive {
background-color: #10b981;
animation:
led-pulse 2.5s infinite ease-in-out;
}
@keyframes led-blink {
0%,100%{opacity:1;}
50%{opacity:0.2;filter:saturate(0.2)}
}
@keyframes led-pulse{
0%,100%{opacity: 1;filter:saturate(1);box-shadow: 0 0 6px 1px rgba(16,185,129,0.4)}
50%{opacity: 0.2;filter:saturate(0.2);box-shadow:0 0 2px 0px rgba(16,185,129,0.1)}
}
.time-loaded, .time-loaded,
.time-now { .time-now {
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;