diff --git a/web/src/components/PublicView.tsx b/web/src/components/PublicView.tsx new file mode 100644 index 0000000..dc7f553 --- /dev/null +++ b/web/src/components/PublicView.tsx @@ -0,0 +1,98 @@ +import { motion } from "motion/react"; +import type { MonitorState } from "../hooks/useMonitor"; +import { StatusRing } from "./StatusRing"; +import { IncidentList } from "./IncidentList"; +import { fmtUptime, pctSign } from "../lib/format"; +import { springs, STATE_COLOR, useUI } from "../lib/ui"; + +/** + * The shareable status page: the same instruments, stripped to their + * quietest form. One headline, one ring per service, the incident log. + */ +export function PublicView({ monitor }: { monitor: MonitorState }) { + const { t, lang, reduced } = useUI(); + const { targets, incidents } = monitor; + + const anyDown = targets.some((x) => x.state === "down"); + const anyDegraded = targets.some((x) => x.state === "degraded"); + const allUnknown = targets.every((x) => x.state === "unknown"); + const headline = anyDown + ? t.outage + : anyDegraded + ? t.someDegraded + : allUnknown + ? t.pending + : t.allOperational; + const headlineState = anyDown + ? "down" + : anyDegraded + ? "degraded" + : allUnknown + ? "unknown" + : "up"; + + return ( +
+ + +

+ {headline} +

+
+ +
+ +
+ {targets.map((target, i) => ( + + +
+

{target.name}

+

+ {t.state[target.state]} +

+
+
+

+ {target.uptime_24h !== undefined + ? `${fmtUptime(lang, target.uptime_24h)}${pctSign(lang)}` + : "—"} +

+

{t.uptime}

+
+
+ ))} +
+ +
+
+ {t.incidents} + +
+ +
+
+ ); +}