ptz operator in /display

This commit is contained in:
legop3
2026-07-14 14:32:25 -04:00
parent f667bbce53
commit f6b9fa798e
7 changed files with 52 additions and 6 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
@@ -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>
);
}