feat: add contribution closing map

This commit is contained in:
lda
2026-07-10 18:42:54 +07:00 Verified
parent 7ddb67486e
commit 3e2cf41b65
5 changed files with 337 additions and 0 deletions
@@ -0,0 +1,79 @@
import type { FC } from "react";
import { Bot, CalendarClock, ChartNoAxesCombined, ShieldCheck, Workflow, type LucideProps } from "lucide-react";
import { StageCaption } from "../StageCaption.js";
import type { SceneBeatDefinition, SceneDefinition } from "../storyboard.js";
import {
contributionNodes,
futureWorkBranches,
isConclusionBeatId,
nonClaims,
type FutureWorkIcon,
} from "./conclusion-model.js";
type ConclusionSceneProps = {
readonly scene: SceneDefinition;
readonly beat: SceneBeatDefinition;
};
const futureWorkIcons: Record<FutureWorkIcon, FC<LucideProps>> = {
agent: Bot,
security: ShieldCheck,
schedule: CalendarClock,
evaluation: ChartNoAxesCombined,
runtime: Workflow,
};
export const ConclusionScene: FC<ConclusionSceneProps> = ({ scene, beat }) => {
const beatId = isConclusionBeatId(beat.id) ? beat.id : "conclusion";
const futureState = beatId === "conclusion" ? "receded" : "visible";
return (
<>
<StageCaption eyebrow={`Act IV · ${scene.claimClass}`} title={scene.title}>
<p>{beat.caption}</p>
</StageCaption>
<section className="conclusion-map" aria-label="thesis contribution boundary" data-conclusion-beat={beatId}>
<div className="conclusion-map__flow" aria-label="contribution flow">
{contributionNodes.map((node, index) => (
<div
className={`conclusion-map__node conclusion-map__node--${node.id}`}
data-node-id={node.id}
data-emphasis={node.id === "substrate" ? "substrate" : "neutral"}
key={node.id}
>
<span className="conclusion-map__node-index">0{index + 1}</span>
<strong>{node.label}</strong>
{node.id === "evidence" && <small>saved traces and receipts</small>}
</div>
))}
</div>
<ul
className="conclusion-map__non-claims"
aria-label="explicit non-claims"
data-emphasis={beatId === "limits" ? "limits" : "neutral"}
>
{nonClaims.map((claim) => <li key={claim}>{claim}</li>)}
</ul>
<ul className="conclusion-map__future" aria-label="future work layers" data-state={futureState}>
{futureWorkBranches.map((branch) => {
const Icon = futureWorkIcons[branch.icon];
return (
<li key={branch.id} data-future-work-id={branch.id}>
<Icon aria-hidden="true" />
<span>
<strong>{branch.label}</strong>
<small>{branch.example}</small>
</span>
</li>
);
})}
</ul>
<p className="conclusion-map__statement">Planner proposes; runtime executes.</p>
</section>
<p className="scene-body__evidence">{scene.evidencePointer}</p>
</>
);
};