返回 JoyAI-Echo
ConnectionBadge.tsx
根目录 / echo_longvideo / Director_Agent / webui / src / components / ConnectionBadge.tsx
1 import { useEffect, useState } from "react";
2 import { useTranslation } from "react-i18next";
3
4 import { cn } from "@/lib/utils";
5 import { useClient } from "@/providers/ClientProvider";
6 import type { ConnectionStatus } from "@/lib/types";
7
8 const COPY: Record<ConnectionStatus, { color: string }> = {
9 idle: { color: "bg-card/40 text-muted-foreground" },
10 connecting: {
11 color: "bg-amber-500/10 text-amber-700 dark:text-amber-300",
12 },
13 open: {
14 color: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-400",
15 },
16 reconnecting: {
17 color: "bg-amber-500/10 text-amber-700 dark:text-amber-300",
18 },
19 closed: {
20 color: "bg-card/40 text-muted-foreground",
21 },
22 error: {
23 color: "bg-destructive/10 text-destructive",
24 },
25 };
26
27 export function ConnectionBadge() {
28 const { t } = useTranslation();
29 const { client } = useClient();
30 const [status, setStatus] = useState<ConnectionStatus>(client.status);
31
32 useEffect(() => client.onStatus(setStatus), [client]);
33
34 const meta = COPY[status];
35 const pulsing =
36 status === "connecting" ||
37 status === "reconnecting" ||
38 status === "error";
39 return (
40 <span
41 className={cn(
42 "inline-flex items-center gap-1.5 rounded-md border border-border/60 px-2 py-1 text-[11px] font-medium transition-colors",
43 meta.color,
44 )}
45 aria-live="polite"
46 >
47 <span className="relative flex h-1.5 w-1.5" aria-hidden>
48 {pulsing && (
49 <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-current opacity-75" />
50 )}
51 <span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-current" />
52 </span>
53 {t(`connection.${status}`)}
54 </span>
55 );
56 }
57
57 lines Plain Text