1import type { ReactNode } from "react";
2import { Smartphone } from "lucide-react";
3
4import { Spinner } from "~/components/ui/spinner";
5
6export function DeviceLoadingView(props: {
7 readonly name: string;
8 readonly description?: string;
9 readonly stage: "opening" | "stream";
10 readonly message: string;
11 readonly error?: boolean;
12 readonly children?: ReactNode;
13}) {
14 return (
15 <div
16 role={props.error ? "alert" : "status"}
17 className="flex size-full items-center justify-center bg-background px-6 py-10"
18 >
19 <div className="flex max-w-sm flex-col items-center gap-3 text-center">
20 <div className="grid size-12 place-items-center rounded-xl border bg-muted/30">
21 <Smartphone className="size-6 text-muted-foreground" />
22 </div>
23 <div className="space-y-1">
24 <p className="text-sm font-medium">{props.name}</p>
25 {props.description ? (
26 <p className="text-xs text-muted-foreground">{props.description}</p>
27 ) : null}
28 </div>
29 <div className="flex items-center gap-2 text-xs text-muted-foreground">
30 {!props.error ? <Spinner size="xs" /> : null}
31 <span>{props.message}</span>
32 </div>
33 {props.children}
34 {!props.error ? (
35 <div
36 className="flex w-24 gap-1"
37 aria-label={
38 props.stage === "opening" ? "Step 1 of 2: open device" : "Step 2 of 2: connect video"
39 }
40 >
41 <span className="h-1 flex-1 rounded-full bg-foreground/60" />
42 <span
43 className={`h-1 flex-1 rounded-full ${props.stage === "stream" ? "bg-foreground/60" : "bg-muted"}`}
44 />
45 </div>
46 ) : null}
47 </div>
48 </div>
49 );
50}