Spaces:
Running
Running
| <script lang="ts"> | |
| import { Button } from "@/components/ui/button"; | |
| import { Badge } from "@/components/ui/badge"; | |
| import * as DropdownMenu from "@/components/ui/dropdown-menu"; | |
| import { toast } from "svelte-sonner"; | |
| import { cn } from "$lib/utils"; | |
| import { videoManager } from "$lib/elements/video/VideoManager.svelte"; | |
| interface Props { | |
| open: boolean; | |
| } | |
| let { open = $bindable() }: Props = $props(); | |
| interface SensorConfig { | |
| id: string; | |
| label: string; | |
| description: string; | |
| icon: string; | |
| enabled: boolean; | |
| isDefault?: boolean; | |
| } | |
| const sensorConfigs: SensorConfig[] = [ | |
| { | |
| id: "camera", | |
| label: "Camera", | |
| description: "Video Camera Sensor", | |
| icon: "icon-[mdi--camera]", | |
| enabled: true, | |
| isDefault: true | |
| }, | |
| { | |
| id: "depth-camera", | |
| label: "Depth Camera", | |
| description: "Depth Camera Sensor", | |
| icon: "icon-[mdi--camera]", | |
| enabled: false | |
| }, | |
| { | |
| id: "lidar", | |
| label: "Lidar", | |
| description: "Distance Sensor", | |
| icon: "icon-[mdi--radar]", | |
| enabled: false | |
| }, | |
| { | |
| id: "imu", | |
| label: "IMU", | |
| description: "Motion Sensor", | |
| icon: "icon-[mdi--radar]", | |
| enabled: false | |
| } | |
| ]; | |
| async function addSensor(sensorType: string) { | |
| try { | |
| // Basic validation | |
| if (!sensorType) return; | |
| const sensorId = `${sensorType}_${Date.now()}`; | |
| if (sensorType === "camera") { | |
| // Create video camera | |
| const video = videoManager.createVideo(sensorId); | |
| toast.success("Video Camera Added", { | |
| description: `Video camera ${sensorId.slice(0, 12)}... created successfully.` | |
| }); | |
| } else { | |
| // Placeholder for other sensor types | |
| const config = sensorConfigs.find((c) => c.id === sensorType); | |
| toast.success("Sensor Added", { | |
| description: `${config?.label || sensorType} sensor ${sensorId.slice(0, 12)}... created successfully.` | |
| }); | |
| } | |
| open = false; // Close dropdown on success | |
| } catch (error) { | |
| console.error("Sensor creation failed:", error); | |
| toast.error("Failed to Add Sensor", { | |
| description: `Could not create ${sensorType} sensor: ${error}` | |
| }); | |
| } | |
| } | |
| async function quickAddCamera() { | |
| await addSensor("camera"); | |
| } | |
| </script> | |
| <!-- Main Add Button (Camera) --> | |
| <Button | |
| variant="default" | |
| size="sm" | |
| onclick={quickAddCamera} | |
| class="group rounded-r-none border-0 bg-blue-500 text-white transition-all duration-200 hover:bg-blue-400 dark:bg-blue-600 dark:hover:bg-blue-500" | |
| > | |
| <span | |
| class={[ | |
| "mr-2 size-4 transition-transform duration-200", | |
| "icon-[mdi--plus] group-hover:rotate-90" | |
| ]} | |
| ></span> | |
| Add Sensor | |
| </Button> | |
| <!-- Dropdown Menu Button --> | |
| <DropdownMenu.Root bind:open> | |
| <DropdownMenu.Trigger> | |
| {#snippet child({ props })} | |
| <Button | |
| {...props} | |
| variant="default" | |
| size="sm" | |
| class={cn( | |
| "rounded-l-none border-0 border-l border-blue-400/30 bg-blue-500 px-2 text-white transition-all duration-200 hover:bg-blue-400", | |
| "dark:border-blue-500/30 dark:bg-blue-600 dark:hover:bg-blue-500", | |
| open && "bg-blue-600 shadow-inner dark:bg-blue-700" | |
| )} | |
| > | |
| <span | |
| class={cn( | |
| "size-4 transition-transform duration-200", | |
| "icon-[mdi--chevron-down]", | |
| open && "rotate-180" | |
| )} | |
| ></span> | |
| </Button> | |
| {/snippet} | |
| </DropdownMenu.Trigger> | |
| <DropdownMenu.Content | |
| class="w-56 border-blue-400/30 bg-blue-500 backdrop-blur-sm dark:border-blue-500/30 dark:bg-blue-600" | |
| align="center" | |
| > | |
| <DropdownMenu.Group> | |
| <DropdownMenu.GroupHeading | |
| class="text-xs font-semibold tracking-wider text-blue-100 uppercase dark:text-blue-200" | |
| > | |
| Sensor Types | |
| </DropdownMenu.GroupHeading> | |
| {#each sensorConfigs as sensor} | |
| <DropdownMenu.Item | |
| class={[ | |
| "group group cursor-pointer bg-blue-500 text-white transition-all duration-200", | |
| "data-highlighted:bg-blue-600 dark:bg-blue-600 dark:data-highlighted:bg-blue-700" | |
| ]} | |
| disabled={!sensor.enabled} | |
| onclick={async () => await addSensor(sensor.id)} | |
| > | |
| <span | |
| class={[ | |
| sensor.icon, | |
| "mr-3 size-4 text-blue-100 transition-colors duration-200 dark:text-blue-200" | |
| ]} | |
| ></span> | |
| <div class="flex flex-1 flex-col"> | |
| <span class="font-medium text-white transition-colors duration-200">{sensor.label}</span | |
| > | |
| <span class="text-xs text-blue-100 transition-colors duration-200 dark:text-blue-200"> | |
| {sensor.description} | |
| </span> | |
| </div> | |
| {#if sensor.isDefault} | |
| <Badge | |
| variant="secondary" | |
| class="ml-2 bg-blue-600 text-xs text-blue-100 group-data-highlighted:bg-blue-300 group-data-highlighted:text-blue-900 dark:bg-blue-700 dark:text-blue-100 dark:group-data-highlighted:bg-blue-400 dark:group-data-highlighted:text-blue-900" | |
| > | |
| Default | |
| </Badge> | |
| {/if} | |
| </DropdownMenu.Item> | |
| {/each} | |
| </DropdownMenu.Group> | |
| </DropdownMenu.Content> | |
| </DropdownMenu.Root> | |