spectate pages have been upgraded
Container image / image (push) Failing after 55s

This commit is contained in:
legop3
2026-09-23 13:54:41 -04:00
parent e750712a39
commit aeeff6fe1b
42 changed files with 270 additions and 238 deletions
@@ -1,11 +1,13 @@
// Server Display Content
// Purpose: Composes the passive room display route used as a third spectator-style page.
// Scope: Shows online names, rover driver/battery status, chat, replay overlays, reward overlays, and hidden audio.
import { useSession, useSessionActions, useSessionSelector } from '../../context/SessionContext.jsx';
import { useSettingsNamespace } from '../../settings/index.js';
import SpectatorSettings from '../../components/SpectatorSettings/index.jsx';
import SpectatorReplayPopup from '../../components/SpectatorSettings/ReplayPopup.jsx';
import { useSession } from '../../context/SessionContext.jsx';
import { useSpectatorMode } from '../../hooks/useSpectatorMode.js';
import useDefaultNickname from '../../hooks/useDefaultNickname.js';
import useUserIdentitySync from '../../hooks/useUserIdentitySync.js';
import ReplayReadyPopup from '../../components/ReplaySourcesPanel/ReplayReadyPopup.jsx';
import RewardRunOverlay from '../../components/RewardRunOverlay/index.jsx';
import OnlinePeopleStrip from './components/OnlinePeopleStrip.jsx';
import DisplayRoverGrid from './components/DisplayRoverGrid.jsx';
@@ -14,10 +16,15 @@ import DisplayNoticeOverlay from './components/DisplayNoticeOverlay.jsx';
import DisplayPtzOperatorBadge from './components/DisplayPtzOperatorBadge.jsx';
import AlertFeed from '../../components/AlertFeed/index.jsx';
const VIEW_OPTIONS = [{ key: 'showReplayPopups', label: 'Replay popups' }];
export default function ServerDisplayContent() {
const { session } = useSession();
const latestReplay = useSessionSelector((state) => state.latestReplay);
const { clearLatestReplay } = useSessionActions();
const { value: viewPreferences, save: saveViewPreferences, status: settingsStatus } = useSettingsNamespace(
'displayPage',
{ showReplayPopups: true },
);
const updateViewPreference = (key, enabled) => saveViewPreferences({ [key]: enabled });
const inLockdown = session?.mode === 'lockdown';
useDefaultNickname();
@@ -37,20 +44,21 @@ export default function ServerDisplayContent() {
return (
<div className="display-page flex h-screen w-screen flex-col overflow-hidden bg-black text-slate-100">
<div className="flex h-[8vh] min-h-16 shrink-0 overflow-hidden">
<div className="flex h-[clamp(4rem,7.5vmin,6.5rem)] shrink-0 overflow-hidden pr-10">
<OnlinePeopleStrip users={session?.users || []} />
<DisplayPtzOperatorBadge />
</div>
<div className="min-h-0 flex-[0.72]">
<div className="max-h-[65%] shrink-0 overflow-y-auto">
<DisplayRoverGrid roster={session?.roster || []} session={session} />
</div>
<div className="min-h-0 flex-[1.28]">
<div className="min-h-0 flex-1">
<DisplayChatFeed />
</div>
<DisplayNoticeOverlay />
<RewardRunOverlay />
<ReplayReadyPopup replay={latestReplay} onClose={clearLatestReplay} />
<AlertFeed scale={2} opacity={1}/>
<SpectatorSettings options={VIEW_OPTIONS} preferences={viewPreferences} onToggle={updateViewPreference} />
<SpectatorReplayPopup enabled={viewPreferences?.showReplayPopups !== false} ready={settingsStatus !== 'loading'} />
</div>
);
}
@@ -4,7 +4,7 @@
import ChatPanel from '../../../components/ChatPanel/index.jsx';
export default function DisplayChatFeed() {
const displayChatScale = 4.6;
const displayChatScale = 4;
return (
<section className="h-full min-h-0 overflow-hidden border-t border-slate-800 bg-black">
@@ -24,7 +24,7 @@ export default function DisplayPtzOperatorBadge() {
like it enters from the right edge of the top bar while avoiding the
previous problem where it covered content in the bottom-right corner.
*/}
<div className="flex h-full min-w-0 items-center justify-center gap-[1vw] px-[1.2vw] text-[clamp(2.1rem,5.1vh,5.6rem)] font-black leading-none tracking-normal text-white">
<div className="flex h-full min-w-0 items-center justify-center gap-[1vw] px-[1.2vw] text-[clamp(1.25rem,3.2vmin,2.75rem)] font-black leading-none tracking-normal text-white">
{/*
The user explicitly requested uppercase "PTZ" here because the room
display needs a terse, instantly recognizable camera marker. The name
@@ -45,7 +45,7 @@ export default function DisplayRoverCell({ rover, session }) {
>
<RoverHelpOverlay active={Boolean(rover?.needsHelp)} />
<BatteryBar visual={visual} variant="background" orientation="vertical" />
<div className="relative z-10 grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] gap-[0.55vh] p-[0.85vw] text-center">
<div className="relative z-10 grid min-w-0 gap-[0.55vh] p-[0.85vw] text-center">
<div className="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-[0.8vw]">
<div className="min-w-0">
<RoverLabel
@@ -71,8 +71,8 @@ export default function DisplayRoverCell({ rover, session }) {
</div>
) : null}
</div>
<div className="grid min-h-0 min-w-0 grid-cols-[minmax(0,1.45fr)_minmax(0,0.85fr)] items-center gap-[1vw]">
<div className="min-w-0">
<div className="flex min-w-0 flex-wrap items-center justify-center gap-[1vw]">
<div className="min-w-0 flex-[1.45_1_12rem]">
<AutoFitText
className={classNames(
'font-black leading-none',
@@ -84,7 +84,7 @@ export default function DisplayRoverCell({ rover, session }) {
{driver?.label || 'Idle'}
</AutoFitText>
</div>
<div className="min-w-0 bg-black/50 rounded-sm">
<div className="min-w-0 max-w-[18rem] flex-[0.85_1_9rem] bg-black/50 rounded-sm text-center">
<AutoFitText
className={classNames(
'font-black leading-none',
@@ -1,5 +1,5 @@
// Display Rover Grid
// Purpose: Fills the central 16:10 display band with rover driver/battery cells.
// Purpose: Renders content-sized rows with rover driver/battery cells.
// Scope: Keeps rover status presentation dense and label-free for room readability.
import DisplayRoverCell from './DisplayRoverCell.jsx';
import { gridClassForRoverCount } from '../utils.js';
@@ -7,14 +7,14 @@ import { gridClassForRoverCount } from '../utils.js';
export default function DisplayRoverGrid({ roster = [], session }) {
if (!roster.length) {
return (
<section className="flex h-full min-h-0 items-center justify-center border-b border-slate-800 bg-black text-[clamp(2.5rem,7vh,7rem)] font-black text-slate-500">
<section className="flex min-h-24 items-center justify-center border-b border-slate-800 bg-black text-[clamp(2.5rem,7vh,7rem)] font-black text-slate-500">
No rovers
</section>
);
}
return (
<section className={`grid h-full min-h-0 ${gridClassForRoverCount(roster.length)} auto-rows-fr gap-0.5 bg-slate-950 p-0.5`}>
<section className={`grid items-stretch ${gridClassForRoverCount(roster.length)} auto-rows-fr gap-0.5 bg-slate-950 p-0.5`}>
{roster.map((rover) => (
<DisplayRoverCell key={rover.id} rover={rover} session={session} />
))}
@@ -75,7 +75,7 @@ export default function OnlinePeopleStrip({ users = [] }) {
<div
ref={trackRef}
className={classNames(
'flex h-full w-max items-center whitespace-nowrap text-[clamp(2.5rem,5.3vh,5.8rem)] leading-none',
'flex h-full w-max items-center whitespace-nowrap text-[clamp(2.25rem,5.5vmin,4.5rem)] leading-none',
)}
>
<div ref={contentRef} className="flex h-full items-center">