import { Activity } from "lucide-react" import { AnimatePresence, motion } from "motion/react" import { useEffect, useState, useSyncExternalStore } from "react" import { useLiveConnection } from "@/components/Flow/liveStore" import { connectionStore } from "@/lib/connectionStore" import { fadeIn } from "@/lib/motion" /** * How long the socket may be down before it is worth saying so. * * The first reconnect attempt is a second away, so a dropped frame is back * before this elapses and nothing appears. Long enough to cover the opening * handshake too: a page that has just loaded is connecting, not disconnected. */ const GRACE = 3000 /** * Says when live values have stopped arriving. * * Everything else on Home is polled over HTTP, so a dead socket leaves the page * looking perfectly current while nothing on it moves any more — the neurons * stop pulsing and the values stop changing, with nothing to say why. Nothing * at all while the socket is up: a page that works needs no chip saying so. * * Quiet too while the offline notification is up, since an instance that cannot * be reached has no socket either and one explanation of that is enough. Named * in words rather than coloured, and deliberately not terracotta: the brain * graph above it already owns that accent for a flow that cannot run. */ export function LiveIndicator() { const connected = useLiveConnection() const { offline } = useSyncExternalStore( connectionStore.subscribe, connectionStore.snapshot, connectionStore.snapshot, ) const [down, setDown] = useState(false) useEffect(() => { if (connected) { setDown(false) return } const timer = setTimeout(() => setDown(true), GRACE) return () => clearTimeout(timer) }, [connected]) return ( {down && !offline ? ( Live updates disconnected values and activity are frozen — reconnecting… ) : null} ) }