updated mobile page

This commit is contained in:
legop3
2026-01-08 20:32:47 -05:00
parent 008cf96c7e
commit d3f2f15370
5 changed files with 51 additions and 41 deletions
+6 -4
View File
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import TelemetryPanel from './components/TelemetryPanel.jsx';
import ControlSummary from './components/ControlSummary.jsx';
import ControlSummary, { RoverRosterPanel } from './components/ControlSummary.jsx';
import AlertFeed from './components/AlertFeed.jsx';
import MobileControls, {
MobileLandscapeAuxColumn,
@@ -125,8 +125,9 @@ function MobileFeatureTabs({
function MobilePortraitLayout({ onOpenHelpOverlay }) {
return (
<div className="flex flex-col gap-0.5">
<DriverVideoPanel layoutFormat='mobile'/>
<DriverVideoPanel layoutFormat="mobile-portrait" />
<MobileControls />
<RoverRosterPanel />
{/* <ControlSummary /> */}
<MobileFeatureTabs
layout="mobile-portrait"
@@ -143,8 +144,9 @@ function MobileLandscapeLayout({ onOpenHelpOverlay }) {
<section className="grid min-h-screen grid-cols-[minmax(0,0.7fr)_minmax(0,2.1fr)_minmax(0,0.7fr)] gap-0.5">
<MobileLandscapeAuxColumn />
<div>
<DriverVideoPanel layoutFormat='mobile'/>
<TelemetryPanel />
<DriverVideoPanel layoutFormat="mobile-landscape" />
<RoverRosterPanel />
{/* <TelemetryPanel /> */}
</div>
<MobileLandscapeControlColumn />
</section>
+31 -26
View File
@@ -7,21 +7,12 @@ import TopDownMap from './TopDownMap.jsx';
import RoverRoster from './RoverRoster.jsx';
import DriveDockAction, { useDriveDockState } from './DriveDockAction.jsx';
export default function ControlSummary() {
export function RoverRosterPanel({ title = 'Rovers' }) {
const { session, requestControl } = useSession();
const {
state: { roverId, keymap },
} = useControlSystem();
const frame = useTelemetryFrame(roverId);
const sensors = frame?.sensors || {};
const driveDockState = useDriveDockState(roverId);
const roster = session?.roster ?? [];
const [pending, setPending] = useState({});
const canRequest = useMemo(() => session?.role && session.role !== 'spectator', [session?.role]);
const hideInlineControls = driveDockState.docked && !driveDockState.driving;
async function handleRequest(targetRoverId) {
if (!targetRoverId) return;
setPending((prev) => ({ ...prev, [targetRoverId]: true }));
@@ -34,6 +25,35 @@ export default function ControlSummary() {
}
}
return (
<RoverRoster
title={title}
roster={session?.roster ?? []}
renderActions={(rover) =>
canRequest ? (
<button
type="button"
onClick={() => handleRequest(rover.id)}
disabled={pending[rover.id]}
className="button-dark disabled:opacity-40"
>
{pending[rover.id] ? '...' : 'request'}
</button>
) : null
}
/>
);
}
export default function ControlSummary({ showRoster = true }) {
const {
state: { roverId, keymap },
} = useControlSystem();
const frame = useTelemetryFrame(roverId);
const sensors = frame?.sensors || {};
const driveDockState = useDriveDockState(roverId);
const hideInlineControls = driveDockState.docked && !driveDockState.driving;
return (
<section className="panel-section">
<div className="grid items-stretch gap-1 md:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] md:min-h-[22rem]">
@@ -49,22 +69,7 @@ export default function ControlSummary() {
{!hideInlineControls ? <InlineCameraTilt keymap={keymap} /> : null}
</div>
</div>
<RoverRoster
title="Rovers"
roster={roster}
renderActions={(rover) =>
canRequest ? (
<button
type="button"
onClick={() => handleRequest(rover.id)}
disabled={pending[rover.id]}
className="button-dark disabled:opacity-40"
>
{pending[rover.id] ? '...' : 'request'}
</button>
) : null
}
/>
{showRoster ? <RoverRosterPanel /> : null}
</section>
);
}
+5 -2
View File
@@ -368,6 +368,7 @@ export default function VideoTile({
status={renderedStatus}
audioStatus={renderedAudioStatus}
desktopLayout={desktopLayout}
layoutFormat={layoutFormat}
variant={hudVariant}
driverLabel={driverLabel}
battery={batteryVisual}
@@ -484,6 +485,7 @@ function HudOverlay({
status,
audioStatus,
desktopLayout = true,
layoutFormat = 'desktop',
variant = 'default',
driverLabel = null,
battery,
@@ -502,12 +504,13 @@ function HudOverlay({
const pulse = frame?.receivedAt ? now - frame.receivedAt < 200 : false;
const isMobile = mobileHud;
const portraitMobile = layoutFormat === 'mobile-portrait';
const statusTextClass = isMobile ? 'text-[0.55rem]' : 'text-[0.65rem]';
const statusPadClass = isMobile ? 'px-0.5 py-0.25' : 'px-1 py-0.5';
const labelPadClass = isMobile ? 'px-0.5 py-0.25' : 'px-0.5 py-0.5';
const labelTextClass = isMobile ? 'text-[0.7rem]' : 'text-[0.8rem]';
const mapSize = isMobile ? '240px' : '240px';
const mapScale = isMobile ? 0.45 : 0.7;
const mapSize = '240px';
const mapScale = portraitMobile ? 0.36 : isMobile ? 0.45 : 0.7;
const mapOpacity = isMobile ? 0.85 : 0.7;
const mapStyle = {
width: mapSize,