fixing up mobile layouts

This commit is contained in:
legop3
2025-11-22 19:10:50 -05:00
parent 3be9e17ecc
commit 930f411549
10 changed files with 62 additions and 53 deletions
+4 -4
View File
@@ -14,14 +14,14 @@
<!-- 2. pi-side sensor throttle (1/5th) -->
<!-- 3. convert rover roster to a reusable component, unbake it from telemetry and admin panels -->
<!-- 4. room cameras -->
4. fix gamepad input - add manual inversions?
4. fix gamepad input - more complex axis assignment? division, combined axes?
<!-- 5. home assistant controls -->
<!-- 6. nicknames -->
<!-- 7. discord bot -->
8. turns mode display
<!-- 8. turns mode display -->
<!-- 9. online user list -->
<!-- 10. chat -->
9. discord invite button
<!-- 9. discord invite button -->
10. redo both mobile layouts
11. redo spectator view (last)
21. finally.. set the favicon
21. finally.. set the favicon and title
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
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-D4k56rvM.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DUduiIaK.css">
<script type="module" crossorigin src="/assets/index-CoT66lYm.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DQGzoV_h.css">
</head>
<body>
<div id="root"></div>
+15 -9
View File
@@ -72,8 +72,10 @@ function DesktopLayout({ layout }) {
function MobilePortraitLayout() {
return (
<div className="flex flex-col gap-0.5">
<DriverVideoPanel />
<DriverVideoPanel layoutFormat='mobile'/>
<MobileControls />
<ChatPanel />
<UserListPanel />
<DrivePanel />
<TelemetryPanel />
<AuthPanel />
@@ -90,23 +92,27 @@ function MobileLandscapeLayout() {
<div className="flex flex-col gap-0.5">
<section className="grid min-h-screen grid-cols-[minmax(0,0.7fr)_minmax(0,2.1fr)_minmax(0,0.7fr)] gap-0.5">
<MobileLandscapeAuxColumn />
<DriverVideoPanel />
<div>
<DriverVideoPanel layoutFormat='mobile'/>
<TelemetryPanel />
</div>
<MobileLandscapeControlColumn />
</section>
<div className="flex flex-col gap-0.5 pb-0.5">
<RoomCameraPanel />
<HomeAssistantControls />
<DrivePanel />
<section className="grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] gap-0.5">
<div className="flex flex-col gap-0.5">
<AuthPanel />
<AdminPanel />
{/* <AuthPanel /> */}
{/* <AdminPanel /> */}
<UserListPanel />
</div>
<div className="flex flex-col gap-0.5">
<LogPanel />
<TelemetryPanel />
{/* <LogPanel /> */}
<ChatPanel />
</div>
</section>
<RoomCameraPanel />
<HomeAssistantControls />
{/* <DrivePanel /> */}
</div>
</div>
);
+2 -2
View File
@@ -3,7 +3,7 @@ import { useTelemetryFrame } from '../context/TelemetryContext.jsx';
import { useVideoRequests } from '../hooks/useVideoRequests.js';
import VideoTile from './VideoTile.jsx';
export default function DriverVideoPanel() {
export default function DriverVideoPanel({layoutFormat = 'desktop'}) {
const { session } = useSession();
const roverId = session?.assignment?.roverId;
const sources = useVideoRequests(roverId ? [roverId] : []);
@@ -20,7 +20,7 @@ export default function DriverVideoPanel() {
return (
<section className="panel">
{roverId ? (
<VideoTile sessionInfo={info} label={roverLabel} telemetryFrame={frame} batteryConfig={batteryConfig} />
<VideoTile sessionInfo={info} label={roverLabel} telemetryFrame={frame} batteryConfig={batteryConfig} layoutFormat={layoutFormat}/>
) : (
<div className="panel-muted content-center text-center text-sm text-slate-400 aspect-video">
<p>You are not assigned to a rover.</p>
+18 -16
View File
@@ -7,13 +7,13 @@ const SOURCE = 'mobile-joystick';
const JOYSTICK_RADIUS = 80;
const JOYSTICK_SMOOTHING = 0.15;
const AUX_BUTTONS = [
{ id: 'main-forward', label: 'Main +', values: { main: 127 }, hold: true, color: 'bg-emerald-600' },
{ id: 'main-reverse', label: 'Main -', values: { main: -127 }, hold: true, color: 'bg-emerald-800' },
{ id: 'side-forward', label: 'Side +', values: { side: 127 }, hold: true, color: 'bg-cyan-600' },
{ id: 'side-reverse', label: 'Side -', values: { side: -70 }, hold: true, color: 'bg-cyan-800' },
{ id: 'main-forward', label: 'Main Brush +', values: { main: 127 }, hold: true, color: 'bg-emerald-600' },
{ id: 'main-reverse', label: 'Main Brush -', values: { main: -127 }, hold: true, color: 'bg-emerald-800' },
{ id: 'all-forward', label: 'All Motors +', values: { main: 127, side: 127, vacuum: 127 }, hold: true, color: 'bg-fuchsia-600' },
{ id: 'side-forward', label: 'Side Brush +', values: { side: 127 }, hold: true, color: 'bg-cyan-600' },
{ id: 'side-reverse', label: 'Side Brush -', values: { side: -70 }, hold: true, color: 'bg-cyan-800' },
{ id: 'vacuum-fast', label: 'Vacuum Max', values: { vacuum: 127 }, hold: true, color: 'bg-amber-500 text-amber-950' },
{ id: 'vacuum-slow', label: 'Vacuum Low', values: { vacuum: 50 }, hold: true, color: 'bg-amber-700' },
{ id: 'all-forward', label: 'All +', values: { main: 127, side: 127, vacuum: 127 }, hold: true, color: 'bg-fuchsia-600' },
{ id: 'stop-all', label: 'Stop', values: { main: 0, side: 0, vacuum: 0 }, hold: false, color: 'bg-slate-900' },
];
@@ -196,17 +196,8 @@ function MobileJoystickPanel({ layout }) {
return (
<div className="flex flex-col gap-0.5 text-slate-100">
<DriveModeToggle size="compact" />
<FloatingJoystick
disabled={disabled}
layout={layout}
radius={joystickRadius}
onMove={handleMove}
onStop={handleStop}
/>
<button type="button" onClick={stopAllMotion} disabled={disabled} className="button-danger w-full disabled:opacity-40">
Panic Stop
</button>
{cameraEnabled && (
<div className="bg-zinc-950 p-0.5 text-xs">
<div className="flex items-center justify-between text-[0.75rem] text-slate-400">
@@ -224,6 +215,17 @@ function MobileJoystickPanel({ layout }) {
/>
</div>
)}
<FloatingJoystick
disabled={disabled}
layout={layout}
radius={joystickRadius}
onMove={handleMove}
onStop={handleStop}
/>
<button type="button" onClick={stopAllMotion} disabled={disabled} className="button-danger w-full disabled:opacity-40">
Panic Stop
</button>
</div>
);
}
@@ -280,7 +282,7 @@ function AuxMotorPanel({ orientation }) {
onPointerLeave={() => handleRelease(button)}
onPointerCancel={() => handleRelease(button)}
onContextMenu={(event) => event.preventDefault()}
className={`px-0.5 py-0.5 text-left text-sm font-semibold text-white transition ${button.color} hover:brightness-110 disabled:opacity-30`}
className={`px-0.5 py-0.5 text-left text-sm font-semibold text-white transition ${button.color} hover:brightness-110 disabled:opacity-30 h-10`}
>
{button.label}
</button>
+9 -8
View File
@@ -4,7 +4,7 @@ import { WhepPlayer } from '../lib/whepPlayer.js';
const RESTART_DELAY_MS = 2000;
const UNMUTE_RETRY_MS = 3000;
export default function VideoTile({ sessionInfo, label, forceMute = false, telemetryFrame, batteryConfig }) {
export default function VideoTile({ sessionInfo, label, forceMute = false, telemetryFrame, batteryConfig, layoutFormat = 'desktop' }) {
const videoRef = useRef(null);
const restartTimer = useRef(null);
const unmuteTimer = useRef(null);
@@ -14,6 +14,7 @@ export default function VideoTile({ sessionInfo, label, forceMute = false, telem
const [muted, setMuted] = useState(true);
const sensors = telemetryFrame?.sensors;
const batteryCharge = sensors?.batteryChargeMah ?? null;
const desktopLayout = layoutFormat === 'desktop';
// console.log('[BatteryBarDebug]', {
// frameSensors: sensors,
// batteryCharge,
@@ -157,7 +158,7 @@ export default function VideoTile({ sessionInfo, label, forceMute = false, telem
controls={false}
className="h-full w-full object-contain"
/>
<HudOverlay frame={telemetryFrame} label={label} status={renderedStatus} />
<HudOverlay frame={telemetryFrame} label={label} status={renderedStatus} desktopLayout={desktopLayout}/>
<OvercurrentOverlay motors={overcurrentMotors} />
<LowBatteryOverlay charge={batteryCharge} config={batteryConfig} />
</div>
@@ -200,7 +201,7 @@ function BatteryBar({ charge, config }) {
);
}
function HudOverlay({ frame, label, status }) {
function HudOverlay({ frame, label, status, desktopLayout = true }) {
const sensors = frame?.sensors;
const bumps = sensors?.bumpsAndWheelDrops || {};
const [now, setNow] = useState(() => Date.now());
@@ -224,11 +225,11 @@ function HudOverlay({ frame, label, status }) {
{/* bump and wheel drops bar */}
<div className="absolute top-0.5 left-1/2 flex -translate-x-1/2 gap-1 bg-black/70 px-0.5 py-0.5 text-[0.6rem] font-medium text-slate-200">
<div className={`px-1 py-0.5 ${bumps.bumpLeft ? 'bg-red-600 text-white animate-pulse' : 'text-slate-500'}`}>Left bump</div>
<div className={`px-1 py-0.5 ${bumps.wheelDropLeft ? 'bg-red-600 text-white animate-pulse' : 'text-slate-500'}`}>Left wheel drop</div>
<div className={`px-1 py-0.5 ${bumps.wheelDropRight ? 'bg-red-600 text-white animate-pulse' : 'text-slate-500'}`}>Right wheel drop</div>
<div className={`px-1 py-0.5 ${bumps.bumpRight ? 'bg-red-600 text-white animate-pulse' : 'text-slate-500'}`}>Right bump</div>
<div className="absolute top-0.5 left-1/2 flex -translate-x-1/2 gap-1 bg-black/70 text-[0.6rem] font-medium text-slate-200">
<div className={`${desktopLayout ? 'px-1 py-0.5':'px-0.5 py-0 text-nowrap'} ${bumps.bumpLeft ? 'bg-red-600 text-white animate-pulse' : 'text-slate-500'}`}>Left bump</div>
<div className={`${desktopLayout ? 'px-1 py-0.5':'px-0.5 py-0 text-nowrap'} ${bumps.wheelDropLeft ? 'bg-red-600 text-white animate-pulse' : 'text-slate-500'}`}>Left wheel drop</div>
<div className={`${desktopLayout ? 'px-1 py-0.5':'px-0.5 py-0 text-nowrap'} ${bumps.wheelDropRight ? 'bg-red-600 text-white animate-pulse' : 'text-slate-500'}`}>Right wheel drop</div>
<div className={`${desktopLayout ? 'px-1 py-0.5':'px-0.5 py-0 text-nowrap'} ${bumps.bumpRight ? 'bg-red-600 text-white animate-pulse' : 'text-slate-500'}`}>Right bump</div>
</div>
</div>
);