mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
made mobile HUD smaller
This commit is contained in:
+63
-30
@@ -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],
|
||||
);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user