1import type { EnvironmentConnectionPhase } from "@t3tools/client-runtime/connection";
2
3import { cn } from "~/lib/utils";
4import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip";
5
6export function connectionPhaseDotClassName(phase: EnvironmentConnectionPhase): string {
7 switch (phase) {
8 case "connected":
9 return "bg-success";
10 case "connecting":
11 case "reconnecting":
12 return "bg-warning";
13 case "error":
14 return "bg-destructive";
15 default:
16 return "bg-muted-foreground/40";
17 }
18}
19
20export function connectionPhasePingClassName(phase: EnvironmentConnectionPhase): string | null {
21 return phase === "connecting" || phase === "reconnecting" ? "bg-warning/60 duration-2000" : null;
22}
23
24type ConnectionStatusDotProps = {
25 tooltipText?: string | null;
26 dotClassName: string;
27 pingClassName?: string | null;
28};
29
30export function ConnectionStatusDot({
31 tooltipText,
32 dotClassName,
33 pingClassName,
34}: ConnectionStatusDotProps) {
35 const dotContent = (
36 <>
37 {pingClassName ? (
38 <span
39 className={cn(
40 "absolute inline-flex h-full w-full motion-safe:animate-status-ping rounded-full",
41 pingClassName,
42 )}
43 />
44 ) : null}
45 <span className={cn("relative inline-flex size-2 rounded-full", dotClassName)} />
46 </>
47 );
48
49 if (!tooltipText) {
50 return (
51 <span className="relative flex size-3 shrink-0 items-center justify-center">
52 {dotContent}
53 </span>
54 );
55 }
56
57 const dot = (
58 <button
59 type="button"
60 aria-label={tooltipText}
61 className="relative flex size-3 shrink-0 cursor-help items-center justify-center rounded-full outline-hidden"
62 >
63 {dotContent}
64 </button>
65 );
66
67 return (
68 <Tooltip>
69 <TooltipTrigger render={dot} />
70 <TooltipPopup side="top" className="whitespace-pre-wrap">
71 {tooltipText}
72 </TooltipPopup>
73 </Tooltip>
74 );
75}