Openstatus
www.openstatus.dev
1import { statusDictionary } from "./utils";
2
3export type Status =
4 | "operational"
5 | "degraded_performance"
6 | "partial_outage"
7 | "major_outage"
8 | "under_maintenance"
9 | "unknown"
10 | "incident";
11
12export type StatusResponse = { status: Status };
13
14export async function getStatus(slug: string): Promise<StatusResponse> {
15 const res = await fetch(`https://api.openstatus.dev/public/status/${slug}`, {
16 cache: "no-cache",
17 });
18
19 if (res.ok) {
20 const data = (await res.json()) as StatusResponse;
21 return data;
22 }
23
24 return { status: "unknown" };
25}
26
27export type StatusWidgetProps = {
28 slug: string;
29 href?: string;
30};
31
32export async function StatusWidget({ slug, href }: StatusWidgetProps) {
33 const { status } = await getStatus(slug);
34
35 const { label, color } = statusDictionary[status];
36
37 return (
38 <a
39 className="inline-flex max-w-fit items-center gap-2 rounded-md border border-gray-200 px-3 py-1 text-gray-700 text-sm hover:bg-gray-100 hover:text-black dark:border-gray-800 dark:text-gray-300 dark:hover:bg-gray-900 dark:hover:text-white"
40 href={href || `https://${slug}.openstatus.dev`}
41 target="_blank"
42 rel="noreferrer"
43 >
44 {label}
45 <span className="relative flex h-2 w-2">
46 {status === "operational" ? (
47 <span
48 className={`absolute inline-flex h-full w-full animate-ping rounded-full ${color} opacity-75 duration-1000`}
49 />
50 ) : null}
51 <span
52 className={`relative inline-flex h-2 w-2 rounded-full ${color}`}
53 />
54 </span>
55 </a>
56 );
57}