fix: clarify defense qna modal hierarchy

This commit is contained in:
lda
2026-07-09 04:51:11 +07:00 Verified
parent fe1f3f90e1
commit 645e4ffbf1
3 changed files with 123 additions and 51 deletions
@@ -93,6 +93,26 @@ describe("DiscussionPanel", () => {
expect(note).toHaveClass("discussion-panel__presenter-note"); expect(note).toHaveClass("discussion-panel__presenter-note");
}); });
it("separates Q&A answer, provenance, and presenter note regions", () => {
render(<DiscussionPanel branchId="where-is-ai-agent" onClose={onClose} />);
const dialog = screen.getByRole("dialog");
expect(dialog).toHaveAttribute("data-discussion-layout", "qna");
expect(screen.getByLabelText("short defense answer")).toHaveTextContent(/workflow substrate/i);
expect(screen.getByLabelText("answer expansion")).toHaveTextContent(/planning algorithm/i);
expect(screen.getByLabelText("answer provenance")).toHaveTextContent(/Abstract/i);
expect(screen.getByLabelText("presenter note")).toHaveTextContent(/Answer directly first/i);
});
it("uses context layout for non-Q&A discussion branches", () => {
render(<DiscussionPanel branchId="hosted-automation" onClose={onClose} />);
const dialog = screen.getByRole("dialog");
expect(dialog).toHaveAttribute("data-discussion-layout", "context");
expect(screen.queryByLabelText("short defense answer")).not.toBeInTheDocument();
expect(screen.getByLabelText("answer provenance")).toHaveTextContent(/Workflow Automation Platforms/i);
});
it("shows mcp-agent-scale links to Anthropic and Cloudflare", () => { it("shows mcp-agent-scale links to Anthropic and Cloudflare", () => {
render(<DiscussionPanel branchId="mcp-agent-scale" onClose={onClose} />); render(<DiscussionPanel branchId="mcp-agent-scale" onClose={onClose} />);
const anthropic = screen.getByText("Anthropic MCP"); const anthropic = screen.getByText("Anthropic MCP");
@@ -22,6 +22,8 @@ export const DiscussionPanel = ({ branchId, onClose }: DiscussionPanelProps) =>
if (!branch) return null; if (!branch) return null;
const hasQuestion = branch.question !== undefined;
const parentScene = findScene(branch.parentSceneId); const parentScene = findScene(branch.parentSceneId);
const trapKeyboardWithinDialog = (event: KeyboardEvent<HTMLDivElement>) => { const trapKeyboardWithinDialog = (event: KeyboardEvent<HTMLDivElement>) => {
@@ -51,6 +53,7 @@ export const DiscussionPanel = ({ branchId, onClose }: DiscussionPanelProps) =>
ref={dialogRef} ref={dialogRef}
className="discussion-panel" className="discussion-panel"
data-presentation-surface="editorial" data-presentation-surface="editorial"
data-discussion-layout={hasQuestion ? "qna" : "context"}
role="dialog" role="dialog"
aria-modal="true" aria-modal="true"
aria-label={branch.title} aria-label={branch.title}
@@ -60,36 +63,47 @@ export const DiscussionPanel = ({ branchId, onClose }: DiscussionPanelProps) =>
<h2>{branch.title}</h2> <h2>{branch.title}</h2>
<span className="discussion-panel__badge">{branch.claimClass}</span> <span className="discussion-panel__badge">{branch.claimClass}</span>
</header> </header>
<p className="discussion-panel__evidence">{branch.evidencePointer}</p> <section className="discussion-panel__provenance" aria-label="answer provenance">
<span>Evidence</span>
<p>{branch.evidencePointer}</p>
</section>
<p className="discussion-panel__summary">{branch.summary}</p> <p className="discussion-panel__summary">{branch.summary}</p>
{branch.question && ( {hasQuestion && (
<section className="discussion-panel__qna" aria-label="defense question"> <section className="discussion-panel__qna" aria-label="defense question">
<p className="discussion-panel__question">{branch.question}</p> <p className="discussion-panel__question">{branch.question}</p>
{branch.shortAnswer && ( {branch.shortAnswer && (
<p className="discussion-panel__short-answer">{branch.shortAnswer}</p> <article className="discussion-panel__answer-card" aria-label="short defense answer">
<span>Short answer</span>
<p>{branch.shortAnswer}</p>
</article>
)} )}
{branch.expandedAnswer && ( {branch.expandedAnswer && (
<p className="discussion-panel__expanded-answer">{branch.expandedAnswer}</p> <article className="discussion-panel__answer-card discussion-panel__answer-card--expanded" aria-label="answer expansion">
<span>Expanded answer</span>
<p>{branch.expandedAnswer}</p>
</article>
)} )}
{branch.speakerHint && ( {branch.speakerHint && (
<p className="discussion-panel__presenter-note" aria-label="presenter note"> <aside className="discussion-panel__presenter-note" aria-label="presenter note">
<span>Presenter note</span> <span>Presenter note</span>
{branch.speakerHint} <p>{branch.speakerHint}</p>
</p> </aside>
)} )}
</section> </section>
)} )}
{branch.detail && ( {branch.detail && (
<p className="discussion-panel__detail"> <section className="discussion-panel__detail" aria-label="additional context">
{branch.detail.links?.map((link, index) => ( <p>
<span key={link.href}> {branch.detail.links?.map((link, index) => (
{index > 0 && " · "} <span key={link.href}>
<a href={link.href} target="_blank" rel="noopener noreferrer">{link.label}</a> {index > 0 && " · "}
</span> <a href={link.href} target="_blank" rel="noopener noreferrer">{link.label}</a>
))} </span>
{branch.detail.links && branch.detail.links.length > 0 ? " — " : ""} ))}
{branch.detail.text} {branch.detail.links && branch.detail.links.length > 0 ? " — " : ""}
</p> {branch.detail.text}
</p>
</section>
)} )}
<button ref={returnButtonRef} type="button" onClick={onClose} className="discussion-panel__return"> <button ref={returnButtonRef} type="button" onClick={onClose} className="discussion-panel__return">
Return to {parentScene?.title ?? "scene"} Return to {parentScene?.title ?? "scene"}
@@ -593,9 +593,26 @@
letter-spacing: 0.05em; letter-spacing: 0.05em;
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__evidence { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__provenance {
font-size: 0.8rem; display: grid;
color: var(--color-editorial-muted, oklch(0.48 0.025 65)); gap: 0.2rem;
margin: 0.55rem 0 0;
border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 24%, transparent);
border-radius: 0.6rem;
padding: 0.5rem 0.6rem;
background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 82%, white);
}
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__provenance span,
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__answer-card span {
color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 68%, var(--color-editorial-muted, oklch(0.48 0.025 65)));
font: 700 0.68rem/1 var(--font-interface);
}
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__provenance p {
margin: 0;
color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 84%, var(--color-editorial-muted, oklch(0.48 0.025 65)));
font-size: 0.82rem;
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__summary { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__summary {
@@ -605,58 +622,79 @@
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__qna { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__qna {
display: grid; display: grid;
gap: 0.6rem; grid-template-columns: minmax(0, 1.1fr) minmax(14rem, 0.9fr);
margin: 0.75rem 0; gap: 0.7rem;
padding: 0.85rem; margin: 0.85rem 0;
border: 1px solid color-mix(in oklch, var(--color-intent, oklch(0.53 0.17 250)) 28%, transparent);
border-radius: 1rem;
background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 74%, white);
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__question, .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__question {
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__short-answer { grid-column: 1 / -1;
margin: 0; margin: 0;
font-size: 1.02rem;
font-weight: 750;
color: var(--color-editorial-ink, oklch(0.19 0.015 65)); color: var(--color-editorial-ink, oklch(0.19 0.015 65));
font-size: 1.15rem;
font-weight: 760;
line-height: 1.15;
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__short-answer { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__answer-card {
font-weight: 400; display: grid;
gap: 0.35rem;
border: 1px solid color-mix(in oklch, var(--color-intent, oklch(0.53 0.17 250)) 26%, transparent);
border-radius: 0.75rem;
padding: 0.7rem;
background: color-mix(in oklch, var(--color-intent, oklch(0.53 0.17 250)) 6%, var(--color-editorial-paper, oklch(0.975 0.012 82)));
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__expanded-answer { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__answer-card--expanded {
border-color: color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 28%, transparent);
background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 90%, white);
}
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__answer-card p {
margin: 0; margin: 0;
color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 82%, var(--color-editorial-muted, oklch(0.48 0.025 65))); color: var(--color-editorial-ink, oklch(0.19 0.015 65));
line-height: 1.45; line-height: 1.42;
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note {
display: grid;
gap: 0.3rem;
margin: 0; margin: 0;
padding: 0.55rem 0.65rem; border: 1px dashed color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 42%, transparent);
border: 1px dashed color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 38%, transparent); border-radius: 0.75rem;
border-radius: 0.55rem; padding: 0.7rem;
background: color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 10%, var(--color-editorial-paper, oklch(0.975 0.012 82))); background: color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 9%, var(--color-editorial-paper, oklch(0.975 0.012 82)));
color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 76%, var(--color-editorial-muted, oklch(0.48 0.025 65)));
font-size: 0.82rem;
line-height: 1.35;
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note span { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note span {
display: block;
margin-bottom: 0.2rem;
color: color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 70%, var(--color-editorial-ink, oklch(0.19 0.015 65))); color: color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 70%, var(--color-editorial-ink, oklch(0.19 0.015 65)));
font: 750 0.64rem/1 var(--font-mono, monospace); font: 700 0.68rem/1 var(--font-interface);
letter-spacing: 0.08em; }
text-transform: uppercase;
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note p {
margin: 0;
color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 84%, var(--color-editorial-muted, oklch(0.48 0.025 65)));
font-size: 0.84rem;
line-height: 1.35;
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__detail { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__detail {
font-size: 0.85rem; margin: 0.65rem 0 0;
border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 24%, transparent);
border-radius: 0.65rem;
padding: 0.6rem;
color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 82%, var(--color-editorial-muted, oklch(0.48 0.025 65))); color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 82%, var(--color-editorial-muted, oklch(0.48 0.025 65)));
border-left: 2px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 42%, transparent); font-size: 0.85rem;
padding-left: 0.65rem; }
margin: 0.5rem 0;
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__detail p {
margin: 0;
}
@media (max-height: 760px) {
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__qna {
grid-template-columns: minmax(0, 1fr);
}
} }
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__return { .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__return {