mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
ptz operator in /display
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
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -78,8 +78,8 @@
|
|||||||
<script defer src="https://analytics.otter.land/script.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land"></script>
|
<script defer src="https://analytics.otter.land/script.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land"></script>
|
||||||
<script defer src="https://analytics.otter.land/recorder.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land" data-sample-rate="0.15" data-mask-level="moderate" data-max-duration="300000"></script>
|
<script defer src="https://analytics.otter.land/recorder.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land" data-sample-rate="0.15" data-mask-level="moderate" data-max-duration="300000"></script>
|
||||||
<title>Roomba Rover</title>
|
<title>Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-H6WndPjR.js"></script>
|
<script type="module" crossorigin src="/assets/index-CnPRqSSv.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-tRV3nWgE.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-BCPTvUH6.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import OnlinePeopleStrip from './components/OnlinePeopleStrip.jsx';
|
|||||||
import DisplayRoverGrid from './components/DisplayRoverGrid.jsx';
|
import DisplayRoverGrid from './components/DisplayRoverGrid.jsx';
|
||||||
import DisplayChatFeed from './components/DisplayChatFeed.jsx';
|
import DisplayChatFeed from './components/DisplayChatFeed.jsx';
|
||||||
import DisplayNoticeOverlay from './components/DisplayNoticeOverlay.jsx';
|
import DisplayNoticeOverlay from './components/DisplayNoticeOverlay.jsx';
|
||||||
|
import DisplayPtzOperatorBadge from './components/DisplayPtzOperatorBadge.jsx';
|
||||||
|
|
||||||
export default function ServerDisplayContent() {
|
export default function ServerDisplayContent() {
|
||||||
const { session } = useSession();
|
const { session } = useSession();
|
||||||
@@ -44,6 +45,11 @@ export default function ServerDisplayContent() {
|
|||||||
<div className="min-h-0 flex-[1.28]">
|
<div className="min-h-0 flex-[1.28]">
|
||||||
<DisplayChatFeed />
|
<DisplayChatFeed />
|
||||||
</div>
|
</div>
|
||||||
|
{/* Keep the PTZ operator visible on the room board without changing the
|
||||||
|
existing rover/chat layout. The badge is self-hiding when nobody owns
|
||||||
|
the camera, so the display remains exactly as sparse as before between
|
||||||
|
PTZ turns. */}
|
||||||
|
<DisplayPtzOperatorBadge />
|
||||||
<DisplayNoticeOverlay />
|
<DisplayNoticeOverlay />
|
||||||
<RewardRunOverlay />
|
<RewardRunOverlay />
|
||||||
{/* Display is spectator-like: every Discord-hosted replay should take over
|
{/* Display is spectator-like: every Discord-hosted replay should take over
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// Display PTZ Operator Badge
|
||||||
|
// Purpose: Gives the physical /display page a simple, always-readable indicator
|
||||||
|
// for who currently owns the single PTZ camera turn.
|
||||||
|
// Scope: This is intentionally display-only chrome; PTZ ownership, naming, and
|
||||||
|
// permission rules stay in the server session state that every client already receives.
|
||||||
|
import { useSessionSelector } from '../../../context/SessionContext.jsx';
|
||||||
|
|
||||||
|
export default function DisplayPtzOperatorBadge() {
|
||||||
|
const ptz = useSessionSelector((state) => state.session?.ptzCamera || null);
|
||||||
|
const operatorLabel = String(ptz?.operatorLabel || '').trim();
|
||||||
|
|
||||||
|
if (!ptz?.enabled || !operatorLabel) {
|
||||||
|
/*
|
||||||
|
The display should stay clean when nobody has the camera. Returning null
|
||||||
|
instead of showing "none" makes the badge behave like a popup: it appears
|
||||||
|
only for an active PTZ operator and disappears as soon as the turn ends.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<aside
|
||||||
|
className="pointer-events-none fixed bottom-[2vh] right-[2vw] z-[90] max-w-[42vw] border-4 border-sky-200 bg-sky-700 px-[1.4vw] py-[1vh] text-center shadow-[0_0_2rem_rgba(14,165,233,0.45)]"
|
||||||
|
aria-label={`PTZ operator ${operatorLabel}`}
|
||||||
|
>
|
||||||
|
{/*
|
||||||
|
The label is deliberately short because /display is a room board, not a
|
||||||
|
control panel. The large name is the useful information from across the
|
||||||
|
room, while the smaller prefix prevents the blue box from being mistaken
|
||||||
|
for a rover driver or chat message.
|
||||||
|
*/}
|
||||||
|
<div className="text-[clamp(0.9rem,2.2vh,2rem)] font-black tracking-normal text-sky-100">
|
||||||
|
Ptz camera
|
||||||
|
</div>
|
||||||
|
<div className="truncate text-[clamp(1.8rem,5vh,5rem)] font-black leading-none text-white">
|
||||||
|
{operatorLabel}
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user