This commit is contained in:
legop3
2025-11-15 23:50:21 -05:00
parent 57dc40dfd3
commit 8c25114c50
12 changed files with 41 additions and 41 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -5,8 +5,8 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webui</title>
<script type="module" crossorigin src="/assets/index-XP4uegUE.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D4wUVUN4.css">
<script type="module" crossorigin src="/assets/index-CIkC6ML4.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DbekZdBV.css">
</head>
<body>
<div id="root"></div>
+7 -7
View File
@@ -57,13 +57,13 @@ export default function AdminPanel() {
if (!isAdmin) return null;
return (
<section className="rounded-sm bg-[#242a32] p-2 text-base text-slate-100">
<div className="flex items-center justify-between gap-2 text-sm">
<section className="rounded-sm bg-[#242a32] p-1 text-base text-slate-100">
<div className="flex items-center justify-between gap-1 text-sm">
<span>Admin controls</span>
<select
value={currentMode}
onChange={handleModeChange}
className="rounded-sm bg-black/40 px-2 py-1 text-sm text-slate-100"
className="rounded-sm bg-black/40 px-1 py-1 text-sm text-slate-100"
>
{MODES.map((mode) => (
<option key={mode.key} value={mode.key}>
@@ -73,9 +73,9 @@ export default function AdminPanel() {
</select>
</div>
<div className="mt-2 space-y-2 text-sm">
<div className="mt-1 space-y-1 text-sm">
{roster.map((rover) => (
<div key={rover.id} className="flex flex-wrap items-center justify-between gap-2 rounded-sm bg-black/30 px-2 py-2">
<div key={rover.id} className="flex flex-wrap items-center justify-between gap-1 rounded-sm bg-black/30 px-1 py-1">
<div>
<p className="text-slate-100">{rover.name}</p>
<p className="text-xs text-slate-400">{lockMap[rover.id] ? 'locked' : 'unlocked'}</p>
@@ -84,14 +84,14 @@ export default function AdminPanel() {
<button
type="button"
onClick={() => handleLockToggle(rover.id, !lockMap[rover.id])}
className="rounded-sm bg-black/50 px-2 py-1 text-slate-100"
className="rounded-sm bg-black/50 px-1 py-1 text-slate-100"
>
{lockMap[rover.id] ? 'Unlock' : 'Lock'}
</button>
<button
type="button"
onClick={() => handleForceControl(rover.id)}
className="rounded-sm bg-black/50 px-2 py-1 text-slate-100"
className="rounded-sm bg-black/50 px-1 py-1 text-slate-100"
>
Force
</button>
+1 -1
View File
@@ -46,7 +46,7 @@ function AlertToast({ alert }) {
? 'bg-amber-500/30 text-amber-100'
: 'bg-emerald-500/30 text-emerald-100';
return (
<div className={`pointer-events-auto rounded-sm px-2 py-1 text-[0.75rem] shadow-lg shadow-black/60 ${colorClasses}`}>
<div className={`pointer-events-auto rounded-sm px-1 py-1 text-[0.75rem] shadow-lg shadow-black/60 ${colorClasses}`}>
<p className="text-[0.65rem] text-slate-300">{alert.title || 'Alert'}</p>
<p className="text-sm text-white">{alert.message}</p>
</div>
+8 -8
View File
@@ -22,17 +22,17 @@ export default function AuthPanel() {
}
return (
<div className="rounded-sm bg-[#242a32] p-2 text-base text-slate-100">
<div className="rounded-sm bg-[#242a32] p-1 text-base text-slate-100">
<p className="text-sm text-slate-400">Admin login</p>
<form className="mt-2 flex flex-col gap-2" onSubmit={handleLogin}>
<form className="mt-1 flex flex-col gap-1" onSubmit={handleLogin}>
<input
className="rounded-sm bg-black/50 px-2 py-1 text-slate-100"
className="rounded-sm bg-black/50 px-1 py-1 text-slate-100"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
className="rounded-sm bg-black/50 px-2 py-1 text-slate-100"
className="rounded-sm bg-black/50 px-1 py-1 text-slate-100"
placeholder="Password"
type="password"
value={password}
@@ -41,23 +41,23 @@ export default function AuthPanel() {
<button
type="submit"
disabled={loading}
className="rounded-sm bg-slate-200 px-2 py-1 text-sm font-semibold text-black disabled:opacity-50"
className="rounded-sm bg-slate-200 px-1 py-1 text-sm font-semibold text-black disabled:opacity-50"
>
{loading ? 'Logging in…' : 'Login'}
</button>
</form>
<div className="mt-2 flex gap-2 text-sm">
<div className="mt-1 flex gap-1 text-sm">
<button
type="button"
onClick={() => setRole('user')}
className="flex-1 rounded-sm bg-black/40 px-2 py-1 text-slate-200"
className="flex-1 rounded-sm bg-black/40 px-1 py-1 text-slate-200"
>
Driver
</button>
<button
type="button"
onClick={() => setRole('spectator')}
className="flex-1 rounded-sm bg-black/40 px-2 py-1 text-slate-200"
className="flex-1 rounded-sm bg-black/40 px-1 py-1 text-slate-200"
>
Spectator
</button>
+10 -10
View File
@@ -19,12 +19,12 @@ export default function DrivePanel() {
const updated = frame?.receivedAt ? new Date(frame.receivedAt).toLocaleTimeString() : null;
return (
<section className="rounded-sm bg-[#242a32] p-2 text-base text-slate-100">
<section className="rounded-sm bg-[#242a32] p-1 text-base text-slate-100">
<div className="flex items-center justify-between text-sm text-slate-300">
<span>Drive control</span>
<span>{roverId ? `Rover ${roverId}` : 'unassigned'}</span>
</div>
<div className="mt-2 space-y-2">
<div className="mt-1 space-y-1">
<ActionCard
title="Start Driving"
description="Press to enable driving mode, then start moving. The headlamps should illuminate."
@@ -55,7 +55,7 @@ export default function DrivePanel() {
type="button"
onClick={() => sendOiCommand(btn.key)}
disabled={!roverId}
className="rounded-sm bg-black/40 px-2 py-0.5 text-sm text-slate-200 disabled:opacity-30"
className="rounded-sm bg-black/40 px-1 py-0.5 text-sm text-slate-200 disabled:opacity-30"
>
{btn.label}
</button>
@@ -67,13 +67,13 @@ export default function DrivePanel() {
type="button"
onClick={stopMotors}
disabled={!roverId}
className="flex-1 rounded-sm bg-red-600/70 px-2 py-1 text-sm text-white disabled:opacity-40"
className="flex-1 rounded-sm bg-red-600/70 px-1 py-1 text-sm text-white disabled:opacity-40"
>
Stop motors
</button>
</div>
</div>
<p className="mt-2 text-sm text-slate-400">Sensor streaming auto-starts after each OI change.</p>
<p className="mt-1 text-sm text-slate-400">Sensor streaming auto-starts after each OI change.</p>
</section>
);
}
@@ -85,15 +85,15 @@ function ActionCard({ title, description, statuses, tone, onClick, disabled, foo
type="button"
onClick={onClick}
disabled={disabled}
className={`w-full rounded-lg ${baseColor} px-3 py-2 text-left text-white disabled:opacity-40`}
className={`w-full rounded-lg ${baseColor} px-1 py-1 text-left text-white disabled:opacity-40`}
>
<p className="text-base font-semibold">{title}</p>
<p className="text-sm text-white/90">{description}</p>
<div className="mt-2 flex flex-wrap gap-1">
<div className="mt-1 flex flex-wrap gap-1">
{statuses.map((status) => (
<span
key={status.label}
className={`rounded-full px-3 py-0.5 text-xs font-semibold ${
className={`rounded-full px-1 py-0.5 text-xs font-semibold ${
status.active ? 'bg-lime-300 text-emerald-900' : 'bg-emerald-900 text-emerald-100'
}`}
>
@@ -108,7 +108,7 @@ function ActionCard({ title, description, statuses, tone, onClick, disabled, foo
function SpeedRow({ left, right }) {
return (
<div className="grid grid-cols-2 gap-1 rounded-sm bg-black/40 p-2 text-base">
<div className="grid grid-cols-2 gap-1 rounded-sm bg-black/40 p-1 text-base">
<div>
<p className="text-sm text-slate-300">Left</p>
<p className="font-semibold text-slate-100">{left}</p>
@@ -124,7 +124,7 @@ function SpeedRow({ left, right }) {
function StatusPill({ label, active }) {
return (
<span
className={`rounded-sm px-2 py-0.5 text-xs ${
className={`rounded-sm px-1 py-0.5 text-xs ${
active ? 'bg-emerald-500/30 text-emerald-100' : 'bg-black/40 text-slate-500'
}`}
>
+2 -2
View File
@@ -3,12 +3,12 @@ import { useSession } from '../context/SessionContext.jsx';
export default function LogPanel() {
const { logs } = useSession();
return (
<div className="rounded-sm bg-[#242a32] p-2 text-base text-slate-100">
<div className="rounded-sm bg-[#242a32] p-1 text-base text-slate-100">
<div className="flex items-center justify-between text-sm text-slate-400">
<span>Server logs</span>
<span>{logs.length}</span>
</div>
<div className="mt-2 h-48 overflow-y-auto rounded-sm bg-black/40 p-2 font-mono text-sm text-slate-300">
<div className="mt-1 h-48 overflow-y-auto rounded-sm bg-black/40 p-1 font-mono text-sm text-slate-300">
{logs.length === 0 ? (
<p>No logs yet.</p>
) : (
+1 -1
View File
@@ -1,6 +1,6 @@
export default function RoomCameraPanel() {
return (
<div className="min-h-[8rem] rounded-sm bg-[#242a32] p-2 text-base text-slate-100">
<div className="min-h-[8rem] rounded-sm bg-[#242a32] p-1 text-base text-slate-100">
<p className="text-center text-sm text-slate-400">Room camera</p>
<p className="mt-1 text-center">Feed placeholder. Wire upcoming room cam here.</p>
</div>
+6 -6
View File
@@ -38,7 +38,7 @@ export default function TelemetryPanel() {
}
return (
<section className="rounded-sm bg-[#242a32] p-2 text-base text-slate-100">
<section className="rounded-sm bg-[#242a32] p-1 text-base text-slate-100">
<div className="text-sm text-slate-400">
<span>{connected ? 'online' : 'offline'}</span>
<span> · role {session?.role || 'unknown'}</span>
@@ -50,7 +50,7 @@ export default function TelemetryPanel() {
) : !frame ? (
<p className="mt-1 text-[0.75rem] text-slate-400">Waiting for sensor frames</p>
) : (
<div className="mt-2 space-y-1 text-base">
<div className="mt-1 space-y-1 text-base">
<Metric label="Charge" value={formatMetric(charge != null && capacity != null ? `${charge}/${capacity} mAh` : null)} />
<Metric label="Charging" value={formatMetric(sensors.chargingState?.label)} />
<Metric label="OI mode" value={formatMetric(sensors.oiMode?.label)} />
@@ -59,16 +59,16 @@ export default function TelemetryPanel() {
</div>
)}
{rawSnippet && (
<pre className="mt-2 overflow-hidden rounded-sm bg-black/60 p-2 text-sm text-lime-300">
<pre className="mt-1 overflow-hidden rounded-sm bg-black/60 p-1 text-sm text-lime-300">
{rawSnippet}
</pre>
)}
<div className="mt-2">
<div className="mt-1">
<p className="text-sm text-slate-400">Rovers</p>
{roster.length === 0 ? (
<p className="text-sm text-slate-500">No roster data.</p>
) : (
<ul className="mt-2 space-y-1 text-sm">
<ul className="mt-1 space-y-1 text-sm">
{roster.map((rover) => (
<li key={rover.id} className="flex items-center justify-between gap-1">
<div>
@@ -82,7 +82,7 @@ export default function TelemetryPanel() {
type="button"
onClick={() => handleRequest(rover.id)}
disabled={pending[rover.id]}
className="rounded-sm bg-black/40 px-2 py-0.5 text-xs text-slate-200 disabled:opacity-40"
className="rounded-sm bg-black/40 px-1 py-0.5 text-xs text-slate-200 disabled:opacity-40"
>
{pending[rover.id] ? '...' : 'request'}
</button>
+2 -2
View File
@@ -153,7 +153,7 @@ function BatteryBar({ charge, config, label, status }) {
const urgent = config?.Urgent ?? null;
if (charge == null || full == null || warn == null) {
return (
<div className="rounded-sm bg-[#1e1e1e] px-2 py-1 text-sm text-slate-200">
<div className="rounded-sm bg-[#1e1e1e] px-1 py-1 text-sm text-slate-200">
<div className="flex items-center justify-between text-xs text-slate-400">
<span>{label}</span>
<span>{status}</span>
@@ -173,7 +173,7 @@ function BatteryBar({ charge, config, label, status }) {
const warnTriggered = urgent != null && charge <= urgent;
const barClass = depleted ? 'bg-red-500 animate-pulse' : warnTriggered ? 'bg-amber-400' : 'bg-emerald-500';
return (
<div className="space-y-2 rounded-sm bg-[#1e1e1e] px-2 py-2 text-sm text-slate-200">
<div className="space-y-2 rounded-sm bg-[#1e1e1e] px-1 py-1 text-sm text-slate-200">
<div className="flex items-center justify-between text-xs text-slate-400">
<span>{label}</span>
<span>{status}</span>