made mobile HUD smaller

This commit is contained in:
legop3
2026-01-07 22:46:17 -05:00
parent 4005ced6f9
commit dc9f93ca60
7 changed files with 119 additions and 62 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
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -11,8 +11,8 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
<title>Multi Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-D6SoVC4Y.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Blc6K3HE.css">
<script type="module" crossorigin src="/assets/index-IngetVG6.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DCrU2sZz.css">
</head>
<body>
<div id="root"></div>
+63 -30
View File
@@ -2,7 +2,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import TelemetryPanel from './components/TelemetryPanel.jsx';
import ControlSummary from './components/ControlSummary.jsx';
import AlertFeed from './components/AlertFeed.jsx';
import AdminPanel from './components/AdminPanel.jsx';
import MobileControls, {
MobileLandscapeAuxColumn,
MobileLandscapeControlColumn,
@@ -11,11 +10,9 @@ import { ControlSystemProvider, KeyboardInputManager, GamepadInputManager } from
import { SettingsProvider } from './settings/index.js';
import RoomCameraPanel from './components/RoomCameraPanel.jsx';
import LogPanel from './components/LogPanel.jsx';
import AuthPanel from './components/AuthPanel.jsx';
import DriverVideoPanel from './components/DriverVideoPanel.jsx';
import RightPaneTabs from './components/RightPaneTabs.jsx';
import ModeGateOverlay from './components/ModeGateOverlay.jsx';
import SessionSnapshot from './components/SessionSnapshot.jsx';
import HomeAssistantControls from './components/HomeAssistantControls.jsx';
import TurnAlertListener from './components/TurnAlertListener.jsx';
import UserListPanel from './components/UserListPanel.jsx';
@@ -24,6 +21,9 @@ import FullscreenPrompt from './components/FullscreenPrompt.jsx';
import { useFullscreenPrompt } from './hooks/useFullscreenPrompt.js';
import { useSettingsNamespace } from './settings/index.js';
import HelpOverlay from './components/HelpOverlay.jsx';
import HelpPanel from './components/HelpPanel.jsx';
import SettingsPanel from './components/SettingsPanel.jsx';
import Tabs, { Tab, TabList, TabPanel, TabPanels } from './components/Tabs.jsx';
function useLayoutMode() {
const [mode, setMode] = useState(() => {
@@ -78,25 +78,66 @@ function DesktopLayout({ layout, onOpenHelpOverlay }) {
);
}
function MobilePortraitLayout() {
function MobileFeatureTabs({
layout,
onOpenHelpOverlay,
roomPanelId,
showTelemetry = true,
}) {
return (
<section className="panel text-base">
<Tabs defaultTab="chat">
<TabList>
<Tab id="chat">Chat</Tab>
<Tab id="roomcontrols">Room Controls</Tab>
<Tab id="help">Help</Tab>
<Tab id="settings">Settings</Tab>
</TabList>
<TabPanels>
<TabPanel id="chat">
<div className="space-y-0.5">
<ChatPanel />
<UserListPanel />
</div>
</TabPanel>
<TabPanel id="roomcontrols">
<div className="space-y-0.5">
{showTelemetry ? <TelemetryPanel /> : null}
<HomeAssistantControls />
<RoomCameraPanel panelId={roomPanelId} />
</div>
</TabPanel>
<TabPanel id="help">
<HelpPanel layout={layout} onOpenOverlay={onOpenHelpOverlay} />
</TabPanel>
<TabPanel id="settings">
<div className="space-y-0.5">
<SettingsPanel />
<LogPanel />
</div>
</TabPanel>
</TabPanels>
</Tabs>
</section>
);
}
function MobilePortraitLayout({ onOpenHelpOverlay }) {
return (
<div className="flex flex-col gap-0.5">
<DriverVideoPanel layoutFormat='mobile'/>
<MobileControls />
<ControlSummary />
<ChatPanel />
<UserListPanel />
<TelemetryPanel />
<AuthPanel />
<AdminPanel />
<HomeAssistantControls />
<RoomCameraPanel panelId="mobile-portrait-room" />
<LogPanel />
{/* <ControlSummary /> */}
<MobileFeatureTabs
layout="mobile-portrait"
onOpenHelpOverlay={onOpenHelpOverlay}
roomPanelId="mobile-portrait-room"
/>
</div>
);
}
function MobileLandscapeLayout() {
function MobileLandscapeLayout({ onOpenHelpOverlay }) {
return (
<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">
@@ -108,20 +149,12 @@ function MobileLandscapeLayout() {
<MobileLandscapeControlColumn />
</section>
<div className="flex flex-col gap-0.5 pb-0.5">
<section className="grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] gap-0.5">
<div className="flex flex-col gap-0.5">
{/* <AuthPanel /> */}
{/* <AdminPanel /> */}
<UserListPanel />
</div>
<div className="flex flex-col gap-0.5">
{/* <LogPanel /> */}
<ChatPanel />
</div>
</section>
<HomeAssistantControls />
<RoomCameraPanel panelId="mobile-landscape-room" />
{/* <DrivePanel /> */}
<MobileFeatureTabs
layout="mobile-landscape"
onOpenHelpOverlay={onOpenHelpOverlay}
roomPanelId="mobile-landscape-room"
showTelemetry={false}
/>
</div>
</div>
);
@@ -180,8 +213,8 @@ function AppWithProviders({ layout, isDesktop, fullscreen }) {
isDesktop
? <DesktopLayout layout={layout} onOpenHelpOverlay={openHelp} />
: layout === 'mobile-landscape'
? <MobileLandscapeLayout />
: <MobilePortraitLayout />,
? <MobileLandscapeLayout onOpenHelpOverlay={openHelp} />
: <MobilePortraitLayout onOpenHelpOverlay={openHelp} />,
[isDesktop, layout, openHelp],
);
+41 -17
View File
@@ -501,11 +501,19 @@ function HudOverlay({
}, []);
const pulse = frame?.receivedAt ? now - frame.receivedAt < 200 : false;
const isMobile = mobileHud;
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 mapOpacity = isMobile ? 0.85 : 0.7;
const mapStyle = {
width: '240px',
height: '240px',
opacity: 0.7,
transform: `scale(${mobileHud ? 0.55 : 0.7})`,
width: mapSize,
height: mapSize,
opacity: mapOpacity,
transform: `scale(${mapScale})`,
transformOrigin: mapPosition === 'bottom-left' ? 'bottom left' : 'top right',
...(mapPosition === 'bottom-left'
? { left: '0.25rem', bottom: '0.25rem' }
@@ -521,19 +529,27 @@ function HudOverlay({
];
return (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="absolute left-1 top-1 bg-black/70 px-1 py-0.5 text-[0.65rem] font-medium text-slate-100">
<div
className={`absolute left-1 top-1 bg-black/70 font-medium text-slate-100 ${statusTextClass} ${statusPadClass}`}
>
<span>Status: {status}</span>
{audioStatus ? <div>Audio: {audioStatus}</div> : null}
</div>
{songNote != null ? (
<div className="absolute right-1 top-1 rounded bg-black/70 px-1 py-0.25 text-[0.65rem] font-semibold text-emerald-200">
<div
className={`absolute right-1 top-1 rounded bg-black/70 font-semibold text-emerald-200 ${statusTextClass} ${statusPadClass}`}
>
Song {formatNoteLabel(songNote)} <span className="text-slate-400">({songNote})</span>
</div>
) : null}
<div className="absolute left-1 top-1/2 flex -translate-y-1/2 flex-col gap-0.35 bg-black/70 px-1 py-0.35 text-[0.65rem] text-slate-100">
<div
className={`absolute left-1 top-1/2 flex -translate-y-1/2 flex-col gap-0.35 bg-black/70 text-slate-100 ${statusTextClass} ${statusPadClass}`}
>
<div className="space-y-0.1 leading-tight">
<span className="text-[0.6rem] uppercase tracking-wide text-slate-400">Telemetry</span>
<span className={`${isMobile ? 'text-[0.55rem]' : 'text-[0.6rem]'} uppercase tracking-wide text-slate-400`}>
Telemetry
</span>
{telemetryEntries.map(([labelText, value]) => (
<span key={labelText} className="flex items-center justify-between gap-0.5">
<span className="text-slate-400">{labelText}</span>
@@ -546,20 +562,22 @@ function HudOverlay({
<div
className="pointer-events-none rounded"
style={{
width: '130px',
height: '130px',
opacity: 0.9,
transform: 'scale(0.85)',
width: isMobile ? '110px' : '130px',
height: isMobile ? '110px' : '130px',
opacity: isMobile ? 0.85 : 0.9,
transform: isMobile ? 'scale(0.7)' : 'scale(0.85)',
transformOrigin: 'top left',
}}
>
<TopDownMap sensors={sensors} size={160} overlay />
<TopDownMap sensors={sensors} size={isMobile ? 160 : 160} overlay />
</div>
</div>
) : null}
</div>
<div className="absolute bottom-0.5 left-1/2 flex -translate-x-1/2 items-center gap-1 bg-black/80 px-1 py-0.5 text-[0.8rem] text-slate-100">
<div
className={`absolute bottom-0.5 left-1/2 flex -translate-x-1/2 items-center gap-1 bg-black/80 text-slate-100 ${labelPadClass} ${labelTextClass}`}
>
<span className="font-semibold text-white">{label || 'Unnamed Rover'}</span>
{driverLabel ? <span className="text-slate-300"> {driverLabel}</span> : null}
</div>
@@ -569,17 +587,23 @@ function HudOverlay({
return (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="absolute left-1 top-1 bg-black/70 px-1 py-0.5 text-[0.65rem] font-medium text-slate-100">
<div
className={`absolute left-1 top-1 bg-black/70 font-medium text-slate-100 ${statusTextClass} ${statusPadClass}`}
>
<span>Status: {status}</span>
{audioStatus ? <div>Audio: {audioStatus}</div> : null}
</div>
{songNote != null ? (
<div className="absolute bottom-1 right-1 rounded bg-black/70 px-1 py-0.25 text-[0.65rem] font-semibold text-emerald-200">
<div
className={`absolute bottom-1 right-1 rounded bg-black/70 font-semibold text-emerald-200 ${statusTextClass} ${statusPadClass}`}
>
Song {formatNoteLabel(songNote)} <span className="text-slate-400">({songNote})</span>
</div>
) : null}
<div className="absolute bottom-0.5 left-1/2 flex -translate-x-1/2 gap-0.5 bg-black/80 px-0.5 py-0.5 text-slate-100">
<div
className={`absolute bottom-0.5 left-1/2 flex -translate-x-1/2 gap-0.5 bg-black/80 text-slate-100 ${labelPadClass} ${labelTextClass}`}
>
<span>Rover: "{label || 'Unnamed Rover'}"</span>
{/* <span>{pulse ? 'Sensors active' : 'No recent sensors'}</span> */}
</div>