mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
new /mini stuff
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
@@ -11,8 +11,8 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
||||||
<title>Multi Roomba Rover</title>
|
<title>Multi Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-BJNBFmS4.js"></script>
|
<script type="module" crossorigin src="/assets/index-Sryc1K8v.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-5vqbgc7L.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CwxAi21V.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { useVideoRequests } from '../hooks/useVideoRequests.js';
|
|||||||
import { useRoverSnapshots } from '../hooks/useRoverSnapshots.js';
|
import { useRoverSnapshots } from '../hooks/useRoverSnapshots.js';
|
||||||
import { useSpectatorMode } from '../hooks/useSpectatorMode.js';
|
import { useSpectatorMode } from '../hooks/useSpectatorMode.js';
|
||||||
import VideoTile from '../components/VideoTile.jsx';
|
import VideoTile from '../components/VideoTile.jsx';
|
||||||
import ChatPanel from '../components/ChatPanel.jsx';
|
|
||||||
import AlertFeed from '../components/AlertFeed.jsx';
|
import AlertFeed from '../components/AlertFeed.jsx';
|
||||||
import useDefaultNickname from '../hooks/useDefaultNickname.js';
|
import useDefaultNickname from '../hooks/useDefaultNickname.js';
|
||||||
|
|
||||||
@@ -19,7 +18,40 @@ function formatDriverLabel({ roverId, session }) {
|
|||||||
const label = user?.nickname || (activeDriverId ? activeDriverId.slice(0, 6) : 'No driver');
|
const label = user?.nickname || (activeDriverId ? activeDriverId.slice(0, 6) : 'No driver');
|
||||||
const mode = session?.mode;
|
const mode = session?.mode;
|
||||||
const turnInfo = session?.turnQueues?.[roverId];
|
const turnInfo = session?.turnQueues?.[roverId];
|
||||||
return mode === 'turns' && turnInfo?.current ? `${label} (turns)` : label;
|
return mode === 'turns' && turnInfo?.current ? `${label}` : label;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBatteryVisual({ rover, frame }) {
|
||||||
|
const percentDisplay = rover?.batteryState?.percentDisplay;
|
||||||
|
const urgentActive = rover?.batteryState?.urgentActive ?? false;
|
||||||
|
const warnActive = rover?.batteryState?.warnActive ?? false;
|
||||||
|
const config = rover?.battery ?? null;
|
||||||
|
const charge = frame?.sensors?.batteryChargeMah ?? null;
|
||||||
|
const full = config?.Full ?? null;
|
||||||
|
const warn = config?.Warn ?? null;
|
||||||
|
const urgent = config?.Urgent ?? null;
|
||||||
|
|
||||||
|
if (percentDisplay != null && Number.isFinite(percentDisplay)) {
|
||||||
|
const percent = Math.max(0, Math.min(1, percentDisplay / 100));
|
||||||
|
const barClass = urgentActive ? 'bg-red-500/40' : warnActive ? 'bg-amber-400/40' : 'bg-emerald-400/40';
|
||||||
|
return { percent, barClass };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charge == null || full == null || warn == null) {
|
||||||
|
return { percent: 0, barClass: 'bg-slate-700/40' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const span = full - warn;
|
||||||
|
if (span <= 0) {
|
||||||
|
return { percent: 0, barClass: 'bg-slate-700/40' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = (charge - warn) / span;
|
||||||
|
const percent = Math.max(0, Math.min(1, normalized));
|
||||||
|
const depleted = normalized <= 0;
|
||||||
|
const warnTriggered = urgent != null && charge <= urgent;
|
||||||
|
const barClass = depleted ? 'bg-red-500/40' : warnTriggered ? 'bg-amber-400/40' : 'bg-emerald-400/40';
|
||||||
|
return { percent, barClass };
|
||||||
}
|
}
|
||||||
|
|
||||||
function MiniSummaryContent() {
|
function MiniSummaryContent() {
|
||||||
@@ -101,9 +133,11 @@ function MiniSummaryContent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative h-screen w-screen overflow-hidden bg-black p-0 text-slate-100 flex flex-col gap-0.5">
|
<div className="relative flex h-screen w-screen overflow-hidden bg-black text-slate-100">
|
||||||
<ChatOverlay />
|
<section
|
||||||
<section className="panel relative flex min-h-0 flex-1 overflow-hidden">
|
className="relative flex h-full shrink-0 items-center justify-start overflow-hidden bg-black"
|
||||||
|
style={{ width: 'min(100vw, calc(100vh * 4 / 3))' }}
|
||||||
|
>
|
||||||
{!spectatorReady ? (
|
{!spectatorReady ? (
|
||||||
<div className="flex h-full w-full items-center justify-center text-sm text-slate-500">
|
<div className="flex h-full w-full items-center justify-center text-sm text-slate-500">
|
||||||
Switching to spectator…
|
Switching to spectator…
|
||||||
@@ -121,7 +155,7 @@ function MiniSummaryContent() {
|
|||||||
layoutFormat="mobile"
|
layoutFormat="mobile"
|
||||||
hudVariant="spectator"
|
hudVariant="spectator"
|
||||||
driverLabel={driverLabel}
|
driverLabel={driverLabel}
|
||||||
hudLabelScale={5}
|
hudLabelScale={7}
|
||||||
hudForceMap
|
hudForceMap
|
||||||
hudMapPosition="bottom-left"
|
hudMapPosition="bottom-left"
|
||||||
fitParent
|
fitParent
|
||||||
@@ -133,6 +167,41 @@ function MiniSummaryContent() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
<aside className="flex h-full min-w-0 flex-1 flex-col border-l border-slate-800/60 bg-slate-950/90">
|
||||||
|
{roster.length ? (
|
||||||
|
roster.map((rover) => {
|
||||||
|
const frame = frames[rover.id] || null;
|
||||||
|
const driverText = formatDriverLabel({ roverId: rover.id, session });
|
||||||
|
const batteryVisual = getBatteryVisual({ rover, frame });
|
||||||
|
const isActive = activeRover?.id === rover.id;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={rover.id}
|
||||||
|
className={`relative flex min-h-0 flex-1 flex-col justify-center gap-2 overflow-hidden px-6 py-4 ${
|
||||||
|
isActive ? 'border-4 border-emerald-300/90 bg-emerald-300/10' : 'opacity-60'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`absolute inset-y-0 left-0 ${batteryVisual.barClass}`}
|
||||||
|
style={{ width: `${batteryVisual.percent * 100}%` }}
|
||||||
|
/>
|
||||||
|
<div className="relative flex flex-col gap-1">
|
||||||
|
<div className={`text-6xl font-semibold tracking-wide ${isActive ? 'text-white' : 'text-slate-200'}`}>
|
||||||
|
{rover.name || rover.id}
|
||||||
|
</div>
|
||||||
|
<div className={`text-5xl font-semibold ${isActive ? 'text-white' : 'text-slate-300'}`}>
|
||||||
|
{driverText}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<div className="flex h-full w-full items-center justify-center text-sm text-slate-500">
|
||||||
|
No rovers available.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -158,25 +227,9 @@ export default function MiniSummaryApp() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChatOverlay() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="pointer-events-none absolute left-1/2 top-1 z-30"
|
|
||||||
style={{ transform: 'translate(-50%, 0) scale(0.7)', transformOrigin: 'top center' }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="pointer-events-none overflow-hidden rounded-md"
|
|
||||||
style={{ width: '50vw', minWidth: '16rem', maxWidth: '24rem', opacity: 0.55, maxHeight: '12rem' }}
|
|
||||||
>
|
|
||||||
<ChatPanel hideInput hideSpectatorNotice />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function FitViewportFrame({ children }) {
|
function FitViewportFrame({ children }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full items-center justify-center overflow-hidden bg-black">
|
<div className="flex h-full w-full items-center justify-start overflow-hidden bg-black">
|
||||||
<div
|
<div
|
||||||
className="relative flex items-center justify-center overflow-hidden bg-black"
|
className="relative flex items-center justify-center overflow-hidden bg-black"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
Reference in New Issue
Block a user