Use shadcn Alert for the "no devices connected" hints

Replaces the ad-hoc bp-glass Card used for the "No devices connected
yet." placeholder in ButtplugConsole and ReplayPlayer with the shadcn
Alert component (newly installed).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-01 19:02:32 +02:00
co-authored by Claude Sonnet 5
parent 27d0db0f72
commit ea320548b6
3 changed files with 90 additions and 9 deletions
+7 -4
View File
@@ -22,6 +22,8 @@ import { DeviceCard } from "./DeviceCard";
import { RecordControls } from "./RecordControls";
import { NameSessionDialog } from "./NameSessionDialog";
import { Card, CardContent } from "@/components/ui/card";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Info } from "lucide-react";
interface ActiveSession {
id: number;
@@ -240,12 +242,13 @@ export function ButtplugConsole() {
{storeError && <p className="text-sm text-destructive">{storeError}</p>}
{Object.keys(devices).length === 0 ? (
<Card className="bp-glass">
<CardContent className="text-sm text-muted-foreground">
<Alert className="bp-glass">
<Info />
<AlertDescription>
No devices connected yet. Scan to discover nearby toys, then select one from your browser&apos;s
pairing prompt.
</CardContent>
</Card>
</AlertDescription>
</Alert>
) : (
<div className="grid gap-4 sm:grid-cols-2">
{Object.values(devices).map((device) => (
+7 -5
View File
@@ -11,7 +11,8 @@ import { disconnectAll, getButtplugClientHandle, getDevice, startScanning, stopS
import { SessionPlayer, type SessionEventRow } from "@/lib/buttplug/player";
import { useButtplugStore } from "@/lib/buttplug/store";
import type { ActuatorInfo, ReplayDeviceSlot } from "@/lib/buttplug/types";
import { Pause, Play } from "lucide-react";
import { Info, Pause, Play } from "lucide-react";
import { Alert, AlertDescription } from "@/components/ui/alert";
interface ReplayDataResponse {
session: {
@@ -163,12 +164,13 @@ export function ReplayPlayer({ sessionId }: { sessionId: number }) {
</div>
{connectedDevices.length === 0 && (
<Card className="bp-glass">
<CardContent className="text-sm text-muted-foreground">
<Alert className="bp-glass">
<Info />
<AlertDescription>
No devices connected yet. Scan to discover nearby toys, then match them to this session&apos;s
original device slots.
</CardContent>
</Card>
</AlertDescription>
</Alert>
)}
</>
) : (
+76
View File
@@ -0,0 +1,76 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const alertVariants = cva(
"group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4",
{
variants: {
variant: {
default: "bg-card text-card-foreground",
destructive:
"bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Alert({
className,
variant,
...props
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
return (
<div
data-slot="alert"
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
)
}
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-title"
className={cn(
"font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground",
className
)}
{...props}
/>
)
}
function AlertDescription({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-description"
className={cn(
"text-sm text-balance text-muted-foreground md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
className
)}
{...props}
/>
)
}
function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-action"
className={cn("absolute top-2 right-2", className)}
{...props}
/>
)
}
export { Alert, AlertTitle, AlertDescription, AlertAction }