Spaces:
Running
Running
| <script lang="ts"> | |
| import type { Robot } from "../Robot.svelte.js"; | |
| interface Props { | |
| robot: Robot; | |
| } | |
| let { robot }: Props = $props(); | |
| const joints = $derived(robot.jointArray); | |
| const isManualControlEnabled = $derived(robot.isManualControlEnabled); | |
| function updateJoint(name: string, value: number) { | |
| if (!isManualControlEnabled) return; | |
| robot.updateJoint(name, value); | |
| } | |
| </script> | |
| <div class="space-y-4 rounded-lg border border-slate-600 bg-slate-800 p-4"> | |
| <div class="flex items-center justify-between"> | |
| <h3 class="text-lg font-semibold text-slate-100"> | |
| Robot Controls - {robot.id} | |
| </h3> | |
| <div class="flex items-center gap-2"> | |
| {#if isManualControlEnabled} | |
| <span class="text-sm text-green-400">Manual Control</span> | |
| {:else} | |
| <span class="text-sm text-orange-400">External Control</span> | |
| {/if} | |
| </div> | |
| </div> | |
| <div class="space-y-4"> | |
| {#each joints as joint} | |
| <div class="space-y-2"> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-slate-200">{joint.name}</span> | |
| <span class="text-sm text-slate-400"> | |
| {joint.value.toFixed(1)}% | |
| </span> | |
| </div> | |
| <div class="flex items-center gap-4"> | |
| {#if joint.name.toLowerCase() === "jaw" || joint.name.toLowerCase() === "gripper"} | |
| <span class="w-12 text-xs text-slate-400">0% (closed)</span> | |
| <input | |
| type="range" | |
| min="0" | |
| max="100" | |
| step="1" | |
| value={joint.value} | |
| disabled={!isManualControlEnabled} | |
| oninput={(e) => updateJoint(joint.name, parseFloat(e.currentTarget.value))} | |
| class="h-2 flex-1 cursor-pointer appearance-none rounded-lg bg-slate-700 disabled:cursor-not-allowed disabled:opacity-50" | |
| /> | |
| <span class="w-12 text-xs text-slate-400">100% (open)</span> | |
| {:else} | |
| <span class="w-8 text-xs text-slate-400">-100%</span> | |
| <input | |
| type="range" | |
| min="-100" | |
| max="100" | |
| step="1" | |
| value={joint.value} | |
| disabled={!isManualControlEnabled} | |
| oninput={(e) => updateJoint(joint.name, parseFloat(e.currentTarget.value))} | |
| class="h-2 flex-1 cursor-pointer appearance-none rounded-lg bg-slate-700 disabled:cursor-not-allowed disabled:opacity-50" | |
| /> | |
| <span class="w-8 text-xs text-slate-400">+100%</span> | |
| {/if} | |
| </div> | |
| {#if joint.limits} | |
| <div class="text-xs text-slate-500"> | |
| URDF limits: {joint.limits.lower}° to {joint.limits.upper}° | |
| </div> | |
| {/if} | |
| </div> | |
| {/each} | |
| </div> | |
| </div> | |