blanchon's picture
Update
6ce4ca6
raw
history blame
13.7 kB
<script lang="ts">
import * as Sheet from "@/components/ui/sheet";
import { Separator } from "@/components/ui/separator";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { settings } from "$lib/runes/settings.svelte";
import { remoteComputeManager } from "$lib/elements/compute/RemoteComputeManager.svelte";
import { toast } from "svelte-sonner";
interface Props {
open?: boolean;
}
let { open = $bindable(false) }: Props = $props();
interface LocalSettings {
darkMode: boolean;
showFPS: boolean;
renderQuality: number;
animationSpeed: number;
}
let localSettings = $state<LocalSettings>({
darkMode: true,
showFPS: false,
renderQuality: 75,
animationSpeed: 1
});
let isCheckingInferenceConnection = $state(false);
let inferenceConnectionStatus = $state<'unknown' | 'connected' | 'disconnected'>('unknown');
let isCheckingTransportConnection = $state(false);
let transportConnectionStatus = $state<'unknown' | 'connected' | 'disconnected'>('unknown');
async function checkInferenceServerConnection() {
isCheckingInferenceConnection = true;
try {
const result = await remoteComputeManager.checkServerHealth();
if (result.success) {
inferenceConnectionStatus = 'connected';
toast.success('Inference server is connected');
} else {
inferenceConnectionStatus = 'disconnected';
toast.error(`Connection failed: ${result.error}`);
}
} catch (error) {
inferenceConnectionStatus = 'disconnected';
toast.error('Failed to connect to inference server');
} finally {
isCheckingInferenceConnection = false;
}
}
async function checkTransportServerConnection() {
isCheckingTransportConnection = true;
try {
// Test transport server health by making a simple HTTP request
const response = await fetch(`${settings.transportServerUrl}/health`, {
method: 'GET',
headers: {
'Accept': 'application/json',
},
});
if (response.ok) {
transportConnectionStatus = 'connected';
toast.success('Transport server is connected');
} else {
transportConnectionStatus = 'disconnected';
toast.error(`Transport server returned status: ${response.status}`);
}
} catch (error) {
transportConnectionStatus = 'disconnected';
toast.error('Failed to connect to transport server');
} finally {
isCheckingTransportConnection = false;
}
}
$effect(() => {
console.log("render_interface");
});
</script>
<!-- Settings Sheet -->
<Sheet.Root bind:open>
<Sheet.Content
side="left"
class="w-80 gap-0 border-r border-slate-600 bg-gradient-to-b from-slate-700 to-slate-800 p-0 text-white sm:w-96"
>
<!-- Header -->
<Sheet.Header class="border-b border-slate-600 bg-slate-700/80 p-6 backdrop-blur-sm">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<span class="icon-[mdi--cog] size-6 text-orange-400"></span>
<div>
<Sheet.Title class="text-xl font-semibold text-slate-100">Robot Settings</Sheet.Title>
<p class="mt-1 text-sm text-slate-400">Configure application preferences</p>
</div>
</div>
</div>
</Sheet.Header>
<!-- Content -->
<div
class="scrollbar-thin scrollbar-track-slate-700 scrollbar-thumb-slate-500 flex-1 overflow-y-auto px-4"
>
<div class="space-y-6 py-4">
<!-- Server Configuration -->
<div class="space-y-4">
<div class="mb-3 flex items-center gap-3">
<span class="icon-[mdi--server] size-5 text-blue-400"></span>
<h3 class="text-lg font-medium text-slate-100">Server Configuration</h3>
</div>
<div class="space-y-4">
<div class="space-y-3">
<div class="space-y-1">
<Label class="text-sm font-medium text-slate-200">Inference Server URL</Label>
<p class="text-xs text-slate-400">
URL for the remote AI inference server that runs ACT models and manages robot sessions
</p>
</div>
<div class="flex gap-2">
<Input
bind:value={settings.inferenceServerUrl}
placeholder="http://localhost:8001"
class="flex-1 bg-slate-800 border-slate-600 text-slate-100"
/>
<Button
variant="outline"
size="sm"
onclick={checkInferenceServerConnection}
disabled={isCheckingInferenceConnection}
class="border-slate-600 text-slate-200 hover:bg-slate-700"
>
{#if isCheckingInferenceConnection}
<span class="icon-[mdi--loading] animate-spin mr-1 size-4"></span>
Testing...
{:else}
<span class="icon-[mdi--connection] mr-1 size-4"></span>
Test
{/if}
</Button>
</div>
<div class="flex items-center gap-2">
{#if inferenceConnectionStatus === 'connected'}
<span class="icon-[mdi--check-circle] size-4 text-green-400"></span>
<span class="text-xs text-green-400">Connected to inference server</span>
{:else if inferenceConnectionStatus === 'disconnected'}
<span class="icon-[mdi--close-circle] size-4 text-red-400"></span>
<span class="text-xs text-red-400">Cannot connect to inference server</span>
{:else}
<span class="icon-[mdi--help-circle] size-4 text-slate-400"></span>
<span class="text-xs text-slate-400">Connection status unknown</span>
{/if}
</div>
</div>
<div class="space-y-3">
<div class="space-y-1">
<Label class="text-sm font-medium text-slate-200">Transport Server URL</Label>
<p class="text-xs text-slate-400">
URL for the transport server that manages communication rooms and routes video streams and robot data using consumer/producer system
</p>
</div>
<div class="flex gap-2">
<Input
bind:value={settings.transportServerUrl}
placeholder="http://localhost:8000"
class="flex-1 bg-slate-800 border-slate-600 text-slate-100"
/>
<Button
variant="outline"
size="sm"
onclick={checkTransportServerConnection}
disabled={isCheckingTransportConnection}
class="border-slate-600 text-slate-200 hover:bg-slate-700"
>
{#if isCheckingTransportConnection}
<span class="icon-[mdi--loading] animate-spin mr-1 size-4"></span>
Testing...
{:else}
<span class="icon-[mdi--connection] mr-1 size-4"></span>
Test
{/if}
</Button>
</div>
<div class="flex items-center gap-2">
{#if transportConnectionStatus === 'connected'}
<span class="icon-[mdi--check-circle] size-4 text-green-400"></span>
<span class="text-xs text-green-400">Connected to transport server</span>
{:else if transportConnectionStatus === 'disconnected'}
<span class="icon-[mdi--close-circle] size-4 text-red-400"></span>
<span class="text-xs text-red-400">Cannot connect to transport server</span>
{:else}
<span class="icon-[mdi--help-circle] size-4 text-slate-400"></span>
<span class="text-xs text-slate-400">Connection status unknown</span>
{/if}
</div>
</div>
</div>
</div>
<Separator class="bg-slate-600" />
<!-- Application Settings -->
<div class="space-y-4">
<div class="mb-3 flex items-center gap-3">
<span class="icon-[mdi--tune] size-5 text-orange-400"></span>
<h3 class="text-lg font-medium text-slate-100">Application Settings</h3>
</div>
<!-- <div class="space-y-4">
<div class="flex items-center justify-between">
<div class="space-y-1">
<Label class="text-sm font-medium text-slate-200">Dark Mode</Label>
<p class="text-xs text-slate-400">Use dark theme for the interface</p>
</div>
<Switch bind:checked={localSettings.darkMode} />
</div>
<div class="flex items-center justify-between">
<div class="space-y-1">
<Label class="text-sm font-medium text-slate-200">Show FPS</Label>
<p class="text-xs text-slate-400">Display frame rate counter</p>
</div>
<Switch bind:checked={localSettings.showFPS} />
</div>
<div class="space-y-3">
<div class="space-y-1">
<Label class="text-sm font-medium text-slate-200">Render Quality</Label>
<p class="text-xs text-slate-400">
Adjust 3D rendering quality ({localSettings.renderQuality}%)
</p>
</div>
<input
type="range"
min="25"
max="100"
step="5"
bind:value={localSettings.renderQuality}
class="slider h-2 w-full cursor-pointer appearance-none rounded-lg bg-slate-600"
/>
<div class="flex justify-between text-xs text-slate-500">
<span>25%</span>
<span>100%</span>
</div>
</div>
<div class="space-y-3">
<div class="space-y-1">
<Label class="text-sm font-medium text-slate-200">Animation Speed</Label>
<p class="text-xs text-slate-400">
Robot movement animation speed ({localSettings.animationSpeed}x)
</p>
</div>
<input
type="range"
min="0.1"
max="3"
step="0.1"
bind:value={localSettings.animationSpeed}
class="slider h-2 w-full cursor-pointer appearance-none rounded-lg bg-slate-600"
/>
<div class="flex justify-between text-xs text-slate-500">
<span>0.1x</span>
<span>3x</span>
</div>
</div>
</div> -->
</div>
<Separator class="bg-slate-600" />
<!-- About Section -->
<div class="space-y-4">
<div class="mb-3 flex items-center gap-3">
<span class="icon-[mdi--information-outline] size-5 text-blue-400"></span>
<h3 class="text-lg font-medium text-slate-100">About</h3>
</div>
<div class="space-y-4">
<div class="space-y-2">
<h4 class="text-sm font-medium text-slate-200">Acknowledgements</h4>
<p class="text-xs leading-relaxed text-slate-400">
This application is built with amazing open-source technologies and communities.
</p>
</div>
<div class="space-y-3">
<!-- Hugging Face LeRobot -->
<a
href="https://github.com/huggingface/lerobot"
target="_blank"
rel="noopener noreferrer"
class="flex items-center gap-3 rounded-lg border border-slate-600 bg-slate-800/50 p-3 transition-colors duration-200 hover:bg-slate-700/50"
>
<span class="icon-[mdi--robot] size-5 text-yellow-400"></span>
<div class="flex-1">
<div class="text-sm font-medium text-slate-200">Hugging Face LeRobot</div>
<p class="text-xs text-slate-400">Robotics AI framework and models</p>
</div>
</a>
<!-- Threlte -->
<a
href="https://threlte.xyz"
target="_blank"
rel="noopener noreferrer"
class="flex items-center gap-3 rounded-lg border border-slate-600 bg-slate-800/50 p-3 transition-colors duration-200 hover:bg-slate-700/50"
>
<span class="icon-[mdi--cube-outline] size-5 text-orange-400"></span>
<div class="flex-1">
<div class="text-sm font-medium text-slate-200">Threlte</div>
<p class="text-xs text-slate-400">3D graphics library for Svelte</p>
</div>
</a>
<!-- feetech.js -->
<a
href="https://bambot.org"
target="_blank"
rel="noopener noreferrer"
class="flex items-center gap-3 rounded-lg border border-slate-600 bg-slate-800/50 p-3 transition-colors duration-200 hover:bg-slate-700/50"
>
<span class="icon-[mdi--memory] size-5 text-green-400"></span>
<div class="flex-1">
<div class="text-sm font-medium text-slate-200">bambot.org feetech.js</div>
<p class="text-xs text-slate-400">Servo motor control library</p>
</div>
</a>
<!-- URDF Viewer -->
<a
href="https://github.com/brean/urdf-viewer"
target="_blank"
rel="noopener noreferrer"
class="flex items-center gap-3 rounded-lg border border-slate-600 bg-slate-800/50 p-3 transition-colors duration-200 hover:bg-slate-700/50"
>
<span class="icon-[mdi--cube-outline] size-5 text-orange-400"></span>
<div class="flex-1">
<div class="text-sm font-medium text-slate-200">URDF Viewer</div>
<p class="text-xs text-slate-400">
Nice component for viewing URDF models with Threlte
</p>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</Sheet.Content>
</Sheet.Root>
<style>
:global(.slider::-webkit-slider-thumb) {
appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: #f97316; /* orange-500 */
cursor: pointer;
border: 2px solid #1e293b;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: all 0.15s ease;
}
:global(.slider::-webkit-slider-thumb:hover) {
background: #ea580c; /* orange-600 */
transform: scale(1.1);
}
:global(.slider::-moz-range-thumb) {
width: 18px;
height: 18px;
border-radius: 50%;
background: #f97316; /* orange-500 */
cursor: pointer;
border: 2px solid #1e293b;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: all 0.15s ease;
}
:global(.slider::-moz-range-track) {
height: 6px;
background: #374151;
border-radius: 3px;
border: none;
}
:global(.slider:focus) {
box-shadow: 0 0 0 2px rgba(249, 115, 22, 0.5);
}
</style>