mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
made mobile HUD smaller
This commit is contained in:
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
@@ -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
@@ -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