fix: stabilize conclusion map layout

This commit is contained in:
lda
2026-07-10 18:48:03 +07:00 Verified
parent 20b12c346f
commit 966837713b
5 changed files with 121 additions and 3 deletions
@@ -76,4 +76,24 @@ describe("ConclusionScene", () => {
expect(screen.getByText("Planner proposes; runtime executes.")).toBeInTheDocument();
expect(screen.getByRole("list", { name: "future work layers" })).toHaveAttribute("data-state", "receded");
});
it("keeps evidence as a separately identified node after the runtime", () => {
render(<ConclusionScene scene={scene} beat={beat("future")} />);
const nodes = [...screen.getByLabelText("contribution flow").children];
expect(nodes.map((node) => node.getAttribute("data-node-id"))).toEqual([
"planner",
"substrate",
"runtime",
"evidence",
]);
expect(nodes[2]).toHaveAttribute("data-node-id", "runtime");
expect(nodes[3]).toHaveAttribute("data-node-id", "evidence");
});
it("marks every future-work icon neutral while substrate stays the sole emphasis", () => {
render(<ConclusionScene scene={scene} beat={beat("future")} />);
const map = screen.getByRole("region", { name: "thesis contribution boundary" });
expect(map.querySelector('[data-node-id="substrate"]')).toHaveAttribute("data-emphasis", "substrate");
expect([...map.querySelectorAll(".conclusion-map__future svg")].every((icon) => icon.getAttribute("data-emphasis") === "neutral")).toBe(true);
});
});
@@ -61,7 +61,7 @@ export const ConclusionScene: FC<ConclusionSceneProps> = ({ scene, beat }) => {
const Icon = futureWorkIcons[branch.icon];
return (
<li key={branch.id} data-future-work-id={branch.id}>
<Icon aria-hidden="true" />
<Icon aria-hidden="true" data-emphasis="neutral" />
<span>
<strong>{branch.label}</strong>
<small>{branch.example}</small>
@@ -21,4 +21,17 @@ describe("presentation.css", () => {
expect(breakpointBlock).toMatch(/\.evaluation-board__audit-row\s*\{\s*grid-template-columns: 1fr;/);
});
it("places the conclusion evidence beneath substrate at the 1080px breakpoint", () => {
expect(css).toMatch(/\.conclusion-map__node--planner\s*\{\s*grid-column: 1;\s*grid-row: 1;/);
expect(css).toMatch(/\.conclusion-map__node--substrate\s*\{\s*grid-column: 2;\s*grid-row: 1;/);
expect(css).toMatch(/\.conclusion-map__node--runtime\s*\{\s*grid-column: 3;\s*grid-row: 1;/);
expect(css).toMatch(/\.conclusion-map__node--evidence\s*\{\s*grid-column: 2;\s*grid-row: 2;/);
expect(css).not.toMatch(/\.conclusion-map__node--runtime::after/);
});
it("keeps future-work icons neutral by default", () => {
expect(css).toMatch(/\.conclusion-map__future svg\s*\{[^}]*color: var\(--text-secondary\);/s);
expect(css).not.toMatch(/\.conclusion-map__future svg\s*\{[^}]*color: var\(--accent-cyan\);/s);
});
});
@@ -287,7 +287,8 @@
background: oklch(0.19 0.03 250 / 88%);
}
.conclusion-map__node:not(:last-child)::after {
.conclusion-map__node--planner::after,
.conclusion-map__node--substrate::after {
position: absolute;
top: 50%;
right: -0.85rem;
@@ -352,7 +353,12 @@
transition: opacity 180ms ease, transform 180ms ease;
}
.conclusion-map__future svg { flex: 0 0 auto; width: 1.1rem; height: 1.1rem; color: var(--accent-cyan); }
.conclusion-map__future svg {
flex: 0 0 auto;
width: 1.1rem;
height: 1.1rem;
color: var(--text-secondary);
}
.conclusion-map__future span { display: grid; gap: 0.2rem; }
.conclusion-map__future strong { font-size: 0.8rem; }
.conclusion-map__future small { color: var(--text-secondary); font-family: "Source Sans 3", sans-serif; font-size: 0.76rem; }
@@ -371,6 +377,19 @@
.conclusion-map__future { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 1080px) {
.conclusion-map__flow {
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-template-rows: auto auto;
gap: 0.8rem 1.7rem;
}
.conclusion-map__node--planner { grid-column: 1; grid-row: 1; }
.conclusion-map__node--substrate { grid-column: 2; grid-row: 1; }
.conclusion-map__node--runtime { grid-column: 3; grid-row: 1; }
.conclusion-map__node--evidence { grid-column: 2; grid-row: 2; }
}
@media (max-width: 640px) {
.conclusion-map__flow { grid-template-columns: 1fr; gap: 0.85rem; }
.conclusion-map__node:not(:last-child)::after {