fix: move audience pairing above deck
This commit is contained in:
@@ -2,20 +2,10 @@ import { cleanup, render, screen, within } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { EvidenceRecord } from "../app/state.js";
|
||||
import type { DemoChromePresentation } from "./presentation-demo-chrome.js";
|
||||
import type { PresentationSyncController } from "./sync/presentation-sync-state.js";
|
||||
import { PresentationFooter } from "./PresentationFooter.js";
|
||||
|
||||
afterEach(() => cleanup());
|
||||
|
||||
const standaloneSyncController = (): PresentationSyncController => ({
|
||||
state: { kind: "standalone" },
|
||||
startSession: vi.fn(async () => {}),
|
||||
joinSession: vi.fn(async () => {}),
|
||||
retry: vi.fn(),
|
||||
leaveSession: vi.fn(),
|
||||
endSession: vi.fn(),
|
||||
});
|
||||
|
||||
describe("PresentationFooter", () => {
|
||||
it("combines scene progress and evidence provenance", () => {
|
||||
const evidence: EvidenceRecord = {
|
||||
@@ -40,7 +30,6 @@ describe("PresentationFooter", () => {
|
||||
}}
|
||||
evidence={[evidence]}
|
||||
demoRail={hiddenRail}
|
||||
syncController={standaloneSyncController()}
|
||||
retryHealth={vi.fn()}
|
||||
showEvidenceReceipt
|
||||
inspectEvidence={vi.fn()}
|
||||
@@ -63,7 +52,6 @@ describe("PresentationFooter", () => {
|
||||
}}
|
||||
evidence={[]}
|
||||
demoRail={{ kind: "hidden" }}
|
||||
syncController={standaloneSyncController()}
|
||||
retryHealth={vi.fn()}
|
||||
showEvidenceReceipt={false}
|
||||
inspectEvidence={vi.fn()}
|
||||
@@ -92,7 +80,6 @@ describe("PresentationFooter", () => {
|
||||
canRun: true,
|
||||
canRetry: true,
|
||||
}}
|
||||
syncController={standaloneSyncController()}
|
||||
retryHealth={vi.fn()}
|
||||
showEvidenceReceipt={false}
|
||||
inspectEvidence={vi.fn()}
|
||||
@@ -103,7 +90,7 @@ describe("PresentationFooter", () => {
|
||||
expect(screen.getByText("Live target ready")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps audience pairing in the non-demo utility area beside one demo rail", () => {
|
||||
it("keeps the footer focused on one demo rail without the pairing surface", () => {
|
||||
render(
|
||||
<PresentationFooter
|
||||
location={{ kind: "main", sceneId: "agent-handoff", beatId: "request", focusPath: [] }}
|
||||
@@ -121,7 +108,6 @@ describe("PresentationFooter", () => {
|
||||
canRun: true,
|
||||
canRetry: true,
|
||||
}}
|
||||
syncController={standaloneSyncController()}
|
||||
retryHealth={vi.fn()}
|
||||
showEvidenceReceipt={false}
|
||||
inspectEvidence={vi.fn()}
|
||||
@@ -132,8 +118,8 @@ describe("PresentationFooter", () => {
|
||||
const utility = footer.querySelector<HTMLElement>(".presentation-footer__utility");
|
||||
expect(utility).not.toBeNull();
|
||||
if (utility === null) throw new Error("presentation utility area is missing");
|
||||
expect(within(utility).getByRole("complementary", { name: "Presentation pairing" }))
|
||||
.toHaveAttribute("data-role", "audience");
|
||||
expect(within(utility).queryByRole("complementary", { name: "Presentation pairing" }))
|
||||
.not.toBeInTheDocument();
|
||||
expect(screen.getAllByTestId("presentation-demo-rail")).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,8 +5,6 @@ import { EvidenceReceipt } from "./evidence/EvidenceReceipt.js";
|
||||
import type { DemoChromePresentation } from "./presentation-demo-chrome.js";
|
||||
import { PresentationDemoRail } from "./PresentationDemoRail.js";
|
||||
import type { MainLocation } from "./storyboard.js";
|
||||
import { PresentationPairingPanel } from "./sync/PresentationPairingPanel.js";
|
||||
import type { PresentationSyncController } from "./sync/presentation-sync-state.js";
|
||||
|
||||
type PresentationFooterProps = {
|
||||
readonly location: MainLocation;
|
||||
@@ -16,7 +14,6 @@ type PresentationFooterProps = {
|
||||
readonly retryHealth: () => void;
|
||||
readonly showEvidenceReceipt: boolean;
|
||||
readonly inspectEvidence: () => void;
|
||||
readonly syncController: PresentationSyncController;
|
||||
};
|
||||
|
||||
export const PresentationFooter = ({
|
||||
@@ -27,7 +24,6 @@ export const PresentationFooter = ({
|
||||
retryHealth,
|
||||
showEvidenceReceipt,
|
||||
inspectEvidence,
|
||||
syncController,
|
||||
}: PresentationFooterProps) => (
|
||||
<footer className="presentation-footer" aria-label="presentation footer">
|
||||
<SceneProgress location={location} />
|
||||
@@ -37,7 +33,6 @@ export const PresentationFooter = ({
|
||||
retryHealth={retryHealth}
|
||||
/>
|
||||
<div className="presentation-footer__utility">
|
||||
<PresentationPairingPanel role="audience" controller={syncController} />
|
||||
<EvidenceReceipt
|
||||
records={evidence}
|
||||
visible={showEvidenceReceipt}
|
||||
|
||||
@@ -178,6 +178,8 @@ describe("PresentationRoute", () => {
|
||||
|
||||
const panel = screen.getByRole("complementary", { name: "Presentation pairing" });
|
||||
expect(panel).toHaveAttribute("data-role", "audience");
|
||||
expect(panel.closest(".presentation-stage__sync")).not.toBeNull();
|
||||
expect(panel.closest(".presentation-footer")).toBeNull();
|
||||
expect(within(panel).getByRole("button", { name: "Pair presentation" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { PresentationState } from "./presentation-state.js";
|
||||
import { compositionForState } from "./presentation-state.js";
|
||||
import type { PresentationTargetHealth } from "./presentation-target-status.js";
|
||||
import type { PresentationSyncController } from "./sync/presentation-sync-state.js";
|
||||
import { PresentationPairingPanel } from "./sync/PresentationPairingPanel.js";
|
||||
import { demoChromeFor } from "./presentation-demo-chrome.js";
|
||||
import type { DemoTimelineController } from "../demo/useDemoTimeline.js";
|
||||
import { findScene, type MainLocation } from "./storyboard.js";
|
||||
@@ -89,6 +90,9 @@ export const PresentationStage = ({
|
||||
data-evidence-presentation={composition.evidencePresentation}
|
||||
data-scene-view={activeSceneView}
|
||||
>
|
||||
<div className="presentation-stage__sync">
|
||||
<PresentationPairingPanel role="audience" controller={syncController} />
|
||||
</div>
|
||||
<aside className="presentation-stage__chat" aria-label="agent chat region">
|
||||
<OperatorChat state={state} messages={messages} timelineAgent={timelineAgent} onApprove={onApprove} onRequestRevision={onRequestRevision} />
|
||||
</aside>
|
||||
@@ -129,7 +133,6 @@ export const PresentationStage = ({
|
||||
retryHealth={retryHealth}
|
||||
showEvidenceReceipt={composition.evidencePresentation !== "hidden"}
|
||||
inspectEvidence={openEvidence}
|
||||
syncController={syncController}
|
||||
/>
|
||||
)}
|
||||
<EvidenceInspector
|
||||
|
||||
@@ -1077,6 +1077,12 @@
|
||||
.presentation-stage__chat { grid-area: chat; }
|
||||
.presentation-stage__primary { grid-area: primary; }
|
||||
|
||||
/* The audience pairing control floats above the deck instead of competing with demo footer controls. */
|
||||
.presentation-stage__sync .presentation-pairing {
|
||||
top: 1rem;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
.presentation-footer {
|
||||
grid-area: footer;
|
||||
min-height: var(--presentation-footer-height);
|
||||
@@ -1225,6 +1231,10 @@
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.presentation-stage__sync .presentation-pairing {
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
.presentation-footer__utility {
|
||||
flex: 0 1 auto;
|
||||
max-width: 52%;
|
||||
|
||||
Reference in New Issue
Block a user