refactor: use one editorial presentation canvas
This commit is contained in:
@@ -17,17 +17,11 @@ describe("PresentationCanvas", () => {
|
||||
const canvas = screen.getByTestId("presentation-canvas");
|
||||
|
||||
expect(canvas).toHaveClass("presentation-canvas");
|
||||
expect(canvas).toHaveAttribute("data-stage-theme", "paper");
|
||||
expect(canvas).not.toHaveAttribute("data-stage-theme");
|
||||
expect(canvas.style.transform).toBe("");
|
||||
expect(canvas).toHaveTextContent("Scene");
|
||||
});
|
||||
|
||||
it("applies the authored night stage theme without changing canvas geometry", () => {
|
||||
render(<PresentationCanvas stageTheme="night"><div>Scene</div></PresentationCanvas>);
|
||||
|
||||
expect(screen.getByTestId("presentation-canvas")).toHaveAttribute("data-stage-theme", "night");
|
||||
});
|
||||
|
||||
it("uses CSS ratio bounds instead of JavaScript scale calculations", () => {
|
||||
expect(editorialCss).toContain("width: min(100dvw, calc(100dvh * 16 / 9))");
|
||||
expect(editorialCss).toContain("height: min(100dvh, calc(100dvw * 9 / 12))");
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import type { ReactNode } from "react";
|
||||
import type { StageTheme } from "./storyboard.js";
|
||||
|
||||
type PresentationCanvasProps = {
|
||||
readonly children: ReactNode;
|
||||
readonly stageTheme?: StageTheme;
|
||||
};
|
||||
|
||||
export const PresentationCanvas = ({ children, stageTheme = "paper" }: PresentationCanvasProps) => (
|
||||
export const PresentationCanvas = ({ children }: PresentationCanvasProps) => (
|
||||
<div className="presentation-viewport">
|
||||
{/*
|
||||
Keep the presentation as normal responsive DOM instead of scaling the
|
||||
@@ -17,7 +15,6 @@ export const PresentationCanvas = ({ children, stageTheme = "paper" }: Presentat
|
||||
<div
|
||||
className="presentation-canvas"
|
||||
data-testid="presentation-canvas"
|
||||
data-stage-theme={stageTheme}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
presentationReducer,
|
||||
} from "./presentation-state.js";
|
||||
import { hashForLocation } from "./storyboard-navigation.js";
|
||||
import { findScene, type MainLocation } from "./storyboard.js";
|
||||
import type { MainLocation } from "./storyboard.js";
|
||||
import type { DemoApprovalActions, DemoApprovalUiState } from "./demo-approval-actions.js";
|
||||
import "./presentation.css";
|
||||
import "./styles/demo-workflow.css";
|
||||
@@ -224,13 +224,9 @@ export const PresentationRoute = () => {
|
||||
[],
|
||||
);
|
||||
|
||||
const stageTheme = state.location.kind === "main"
|
||||
? findScene(state.location.sceneId)?.stageTheme ?? "paper"
|
||||
: "paper";
|
||||
|
||||
return (
|
||||
<main className="presentation-route" aria-label="lda.chat presentation" data-motion={state.motionDisabled ? "disabled" : "enabled"}>
|
||||
<PresentationCanvas stageTheme={stageTheme}>
|
||||
<PresentationCanvas>
|
||||
<PresentationStage
|
||||
state={state}
|
||||
demo={demo}
|
||||
|
||||
@@ -62,9 +62,16 @@ const DiscussionLinks = ({
|
||||
);
|
||||
};
|
||||
|
||||
const actForSceneNumber = (sceneNumber: number): string => {
|
||||
if (sceneNumber <= 3) return "I";
|
||||
if (sceneNumber <= 12) return "II";
|
||||
if (sceneNumber === 13) return "III";
|
||||
return "IV";
|
||||
};
|
||||
|
||||
const NarrativeScene = ({ scene, beat }: { scene: SceneDefinition; beat: SceneBeatDefinition }) => (
|
||||
<>
|
||||
<StageCaption eyebrow={`Act ${scene.stageTheme === "paper" ? "I" : "II"} · ${scene.claimClass}`} title={scene.title}>
|
||||
<StageCaption eyebrow={`Act ${actForSceneNumber(scene.number)} · ${scene.claimClass}`} title={scene.title}>
|
||||
<p>{beat.caption}</p>
|
||||
</StageCaption>
|
||||
<p className="scene-body__evidence">{scene.evidencePointer}</p>
|
||||
|
||||
@@ -8,7 +8,6 @@ const scene = {
|
||||
title: "Contribution and future work",
|
||||
claimClass: "future-work" as const,
|
||||
evidencePointer: "Thesis conclusion",
|
||||
stageTheme: "night" as const,
|
||||
view: "conclusion" as const,
|
||||
beats: [],
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@ const scene = {
|
||||
title: "Evaluation",
|
||||
claimClass: "evaluated" as const,
|
||||
evidencePointer: "Thesis Evaluation and Appendix C",
|
||||
stageTheme: "paper" as const,
|
||||
view: "evaluation" as const,
|
||||
beats: [],
|
||||
};
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
/* Semantic kind colors */
|
||||
.figure-node[data-figure-node-kind="actor"],
|
||||
.figure-node[data-figure-node-kind="operation"] {
|
||||
border-color: var(--color-intent, oklch(0.53 0.17 250));
|
||||
border-color: var(--color-editorial-ink, oklch(0.19 0.015 65));
|
||||
}
|
||||
|
||||
.figure-node[data-figure-node-kind="runtime"] {
|
||||
@@ -245,14 +245,6 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.presentation-canvas[data-stage-theme="night"] .figure-breadcrumbs {
|
||||
color: var(--text-secondary, oklch(0.78 0.035 250));
|
||||
}
|
||||
|
||||
.presentation-canvas[data-stage-theme="night"] .figure-breadcrumbs__crumb[aria-current="page"] {
|
||||
color: var(--text-primary, oklch(0.96 0.01 250));
|
||||
}
|
||||
|
||||
.figure-breadcrumbs__crumb + .figure-breadcrumbs__crumb::before {
|
||||
content: "\203A";
|
||||
margin-right: 4px;
|
||||
|
||||
@@ -19,31 +19,20 @@
|
||||
--chat-width: 18rem;
|
||||
}
|
||||
|
||||
.presentation-canvas[data-stage-theme="night"] .presentation-stage__primary {
|
||||
background: var(--stage-canvas);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.presentation-canvas[data-stage-theme="paper"] .presentation-stage__primary {
|
||||
.presentation-stage__primary {
|
||||
background: var(--color-editorial-paper, oklch(0.975 0.012 82));
|
||||
color: var(--color-editorial-ink, oklch(0.19 0.015 65));
|
||||
}
|
||||
|
||||
/* The console's global section rule must not turn night-mode slide roots white. */
|
||||
.presentation-canvas[data-stage-theme="night"] .presentation-stage__primary > .stage-caption,
|
||||
.presentation-canvas[data-stage-theme="night"] .architecture-scene > .stage-caption,
|
||||
.presentation-canvas[data-stage-theme="night"] .presentation-stage__primary > .architecture-scene,
|
||||
.presentation-canvas[data-stage-theme="night"] .presentation-stage__primary > .scene-body__authoring-composition {
|
||||
/* Presentation roots own their visual surfaces; do not inherit console cards. */
|
||||
.presentation-stage__primary > .architecture-scene,
|
||||
.presentation-stage__primary > .scene-body__authoring-composition,
|
||||
.presentation-stage__primary > .prepared-lifecycle-scene {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: var(--text-primary);
|
||||
border-color: var(--stage-line);
|
||||
}
|
||||
|
||||
.presentation-canvas[data-stage-theme="night"] .presentation-stage__primary > .prepared-lifecycle-scene {
|
||||
background: var(--stage-canvas);
|
||||
color: var(--text-primary);
|
||||
border-color: var(--stage-line);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.presentation-stage {
|
||||
@@ -295,7 +284,7 @@
|
||||
}
|
||||
|
||||
.stage-caption__eyebrow {
|
||||
color: oklch(0.78 0.035 250);
|
||||
color: var(--color-editorial-muted, oklch(0.48 0.025 65));
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
@@ -326,7 +315,7 @@
|
||||
.scene-body__evidence {
|
||||
flex-shrink: 0;
|
||||
margin: 0.55rem 0 0;
|
||||
color: oklch(0.62 0.05 250);
|
||||
color: var(--color-editorial-muted, oklch(0.48 0.025 65));
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ const mockScene = {
|
||||
title: "Architecture Zoom",
|
||||
claimClass: "implemented" as const,
|
||||
evidencePointer: "Thesis System Architecture",
|
||||
stageTheme: "night" as const,
|
||||
view: "architecture" as const,
|
||||
beats: [],
|
||||
};
|
||||
|
||||
@@ -42,10 +42,7 @@ describe("defense storyboard catalog", () => {
|
||||
expect(findBeat("conclusion", "questions")?.chatMode).toBe("hidden");
|
||||
});
|
||||
|
||||
it("uses act-level stage themes and independent chat composition", () => {
|
||||
expect(mainScenes.slice(0, 3).every((scene) => scene.stageTheme === "paper")).toBe(true);
|
||||
expect(mainScenes.slice(3, 12).every((scene) => scene.stageTheme === "night")).toBe(true);
|
||||
expect(mainScenes.slice(12).every((scene) => scene.stageTheme === "paper")).toBe(true);
|
||||
it("uses one editorial canvas theme and independent chat composition", () => {
|
||||
expect(findBeat("agent-handoff", "request")?.chatMode).toBe("hidden");
|
||||
expect(findBeat("resume-output-evidence", "trace")?.chatMode).toBe("hidden");
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export type ClaimClass = "motivation" | "implemented" | "evaluated" | "external-context" | "future-work";
|
||||
export type StageTheme = "paper" | "night";
|
||||
export type ChatTheme = "light" | "dark";
|
||||
export type ChatMode = "hidden" | "full" | "rail" | "dock";
|
||||
export type EvidencePresentation = "hidden" | "receipt" | "inspector";
|
||||
@@ -39,7 +38,6 @@ export type SceneDefinition = {
|
||||
readonly title: string;
|
||||
readonly claimClass: ClaimClass;
|
||||
readonly evidencePointer: string;
|
||||
readonly stageTheme: StageTheme;
|
||||
readonly view: SceneView;
|
||||
readonly beats: readonly SceneBeatDefinition[];
|
||||
};
|
||||
@@ -68,7 +66,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Thesis",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "Thesis Abstract and Introduction",
|
||||
stageTheme: "paper",
|
||||
view: "narrative",
|
||||
beats: [
|
||||
sceneBeat("title", "Design and Implementation of lda.chat", "The project began as a pursuit of an AI agent for workspace automation."),
|
||||
@@ -81,7 +78,6 @@ export const mainScenes = defineScenes([
|
||||
title: "The Problem",
|
||||
claimClass: "motivation",
|
||||
evidencePointer: "Thesis Problem Statement and Requirements",
|
||||
stageTheme: "paper",
|
||||
view: "narrative",
|
||||
beats: [
|
||||
sceneBeat("direct-actions", "Direct actions are not reusable automation", "A tool loop can act without owning durable lifecycle records."),
|
||||
@@ -94,7 +90,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Positioning and Related Systems",
|
||||
claimClass: "motivation",
|
||||
evidencePointer: "Thesis Positioning and Related Systems",
|
||||
stageTheme: "paper",
|
||||
view: "positioning",
|
||||
beats: [
|
||||
sceneBeat("landscape", "Different centers of gravity", "Tool loops, scripts, hosted automation, agent graphs, and MCP solve different parts of the problem."),
|
||||
@@ -107,7 +102,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Planner and Runtime",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "Thesis Architecture Overview",
|
||||
stageTheme: "night",
|
||||
view: "boundary",
|
||||
beats: [
|
||||
sceneBeat("planner", "External planner", "The planner proposes and revises workflow structure."),
|
||||
@@ -121,7 +115,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Workflow Lifecycle",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "Thesis Workflow Lifecycle",
|
||||
stageTheme: "night",
|
||||
view: "lifecycle",
|
||||
beats: [
|
||||
sceneBeat("draft", "Draft", "Mutable iterative authoring state."),
|
||||
@@ -136,7 +129,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Architecture Zoom",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "Thesis System Architecture; docs/project_map.md; docs/source_architecture.md",
|
||||
stageTheme: "night",
|
||||
view: "architecture",
|
||||
beats: [
|
||||
sceneBeat("client", "Client operations", "Human and agent clients use the same public lifecycle surface.", { figure: { catalogId: "system-architecture", focusPath: [], activeNodeId: "client-operations" } }),
|
||||
@@ -151,7 +143,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Author, Validate, Repair",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "CLI documentation; draft authoring API; challenge UX findings",
|
||||
stageTheme: "night",
|
||||
view: "authoring",
|
||||
beats: [
|
||||
sceneBeat("discover", "Discover", "Inspect capabilities and schemas before authoring."),
|
||||
@@ -166,7 +157,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Agent Handoff",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "Constrained demo agent and prepared replay recipe",
|
||||
stageTheme: "night",
|
||||
view: "agent",
|
||||
beats: [
|
||||
// Scene 8 renders its own full-screen prepared transcript in the primary
|
||||
@@ -181,7 +171,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Prepared Workflow Lifecycle",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "examples/lda_report_workflow; deployment inspect replay evidence",
|
||||
stageTheme: "night",
|
||||
view: "demo-lifecycle",
|
||||
beats: [
|
||||
sceneBeat("discover", "Discover capabilities", "Inspect available sources, capabilities, and schemas before authoring.", { chatMode: "hidden", chatTheme: "light" }),
|
||||
@@ -197,7 +186,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Run From Deployment",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "workflow.runs.start replay evidence",
|
||||
stageTheme: "night",
|
||||
view: "demo",
|
||||
beats: [
|
||||
sceneBeat("input", "Workflow input", "The run starts from selected documents and an issue board path.", { chatMode: "hidden", chatTheme: "light" }),
|
||||
@@ -211,7 +199,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Typed Human Boundary",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "typed interrupt payload and resume contract",
|
||||
stageTheme: "night",
|
||||
view: "demo",
|
||||
beats: [
|
||||
sceneBeat("interrupt", "Interrupt payload", "Execution reaches a declared issue-review boundary.", { chatMode: "hidden", chatTheme: "light" }),
|
||||
@@ -225,7 +212,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Resume, Output, Evidence",
|
||||
claimClass: "implemented",
|
||||
evidencePointer: "workflow.runs.resume, workflow output, and trace replay evidence",
|
||||
stageTheme: "night",
|
||||
view: "demo",
|
||||
beats: [
|
||||
sceneBeat("resume", "Resume", "The submitted payload resumes the same persisted run.", { chatMode: "hidden", chatTheme: "light" }),
|
||||
@@ -239,7 +225,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Evaluation",
|
||||
claimClass: "evaluated",
|
||||
evidencePointer: "Thesis Evaluation and Appendix C",
|
||||
stageTheme: "paper",
|
||||
view: "evaluation",
|
||||
beats: [
|
||||
sceneBeat("cohort", "36-trial cohort", "Two challenges, two hosted models, three profiles, and three waves.", { chatMode: "hidden" }),
|
||||
@@ -253,7 +238,6 @@ export const mainScenes = defineScenes([
|
||||
title: "Limits and Conclusion",
|
||||
claimClass: "future-work",
|
||||
evidencePointer: "Thesis Limitations, Future Work, and Conclusion",
|
||||
stageTheme: "paper",
|
||||
view: "conclusion",
|
||||
beats: [
|
||||
sceneBeat("limits", "Implemented boundary", "The prototype is not a production sandbox, scheduler, or broad agent benchmark.", { chatMode: "hidden" }),
|
||||
|
||||
@@ -40,8 +40,3 @@
|
||||
container-name: presentation-canvas;
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.presentation-canvas[data-stage-theme="night"] {
|
||||
background: oklch(0.12 0.025 250);
|
||||
color: oklch(0.96 0.01 250);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user