refine(ui): restore visual hierarchy and Situation context in initial workspace
- Enhance Current Understanding prominence with subtle teal/teal border gradient, stronger heading, larger body text, more internal spacing - Restore Situation panel as right-hand column in initial reflection view; uses OriginalSituation when graph exists, scenario text fallback otherwise - Stacks layout on narrow screens via grid-cols-1/gap-6/lg:grid-cols-3 - Apply teal styling to normal-state CurrentUnderstandingCard and PlainLanguageCard (was flat gray border with bg-transparent) - Surface assumption nodes alongside unknowns in Open Questions; add Unclear / Plausible interpretation tags - Wire up follow-up question buttons in deconstructed results
This commit is contained in:
@@ -512,11 +512,11 @@ function CurrentUnderstandingCard({ currentSummary, plainLanguage }) {
|
||||
if (!summary) return null;
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-gray-100/80 bg-transparent px-6 pt-5 pb-6">
|
||||
<h2 className="mb-3 text-[11px] font-semibold tracking-widest uppercase text-gray-500">
|
||||
<div className="rounded-lg border-[2.5px] border-teal-300/60 bg-gradient-to-b from-teal-50/40 to-white px-7 pt-6 pb-7">
|
||||
<h2 className="mb-3 text-[11px] font-bold tracking-widest uppercase text-teal-700/60">
|
||||
Understanding
|
||||
</h2>
|
||||
<p className="text-sm leading-relaxed text-gray-600">{summary}</p>
|
||||
<p className="text-base leading-relaxed text-gray-800">{summary}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -526,11 +526,11 @@ function PlainLanguageCard({ summary }) {
|
||||
if (!summary) return null;
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-gray-100/80 bg-transparent px-6 pt-5 pb-6">
|
||||
<h2 className="mb-3 text-[11px] font-semibold tracking-widest uppercase text-gray-500">
|
||||
<div className="rounded-lg border-[2.5px] border-teal-300/60 bg-gradient-to-b from-teal-50/40 to-white px-7 pt-6 pb-7">
|
||||
<h2 className="mb-3 text-[11px] font-bold tracking-widest uppercase text-teal-700/60">
|
||||
Understanding
|
||||
</h2>
|
||||
<p className="text-sm leading-relaxed text-gray-600">{summary}</p>
|
||||
<p className="text-base leading-relaxed text-gray-800">{summary}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -710,6 +710,7 @@ function OpenQuestionsPanel({
|
||||
focused, formulationStep, formulateMsg, processingStep, deconstructMsg, doneForNowIds,
|
||||
startFocused, handleDeconstructSubmit, retryFormulation, setSelectedPresentationItemId,
|
||||
setFocusedPresentationItemId, setFocusedAnswer, focusedAnswer, setDoneForNowIds,
|
||||
setFollowUpQuestion,
|
||||
}) {
|
||||
const openNodes = (graph?.nodes || []).filter(
|
||||
(n) => n.kind === "unknown" && n.status !== "resolved" && !doneForNowIds.includes(n.id),
|
||||
@@ -785,11 +786,29 @@ function OpenQuestionsPanel({
|
||||
|
||||
{focused?.result && (
|
||||
<>
|
||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">What we learned</h3><ul className="list-disc pl-5 space-y-1">{focused.result.observations.map((o, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{o}</li>))}</ul></div>
|
||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Still unclear</h3><ul className="list-disc pl-5 space-y-1">{focused.result.uncertainties.map((u, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{u}</li>))}</ul></div>
|
||||
{focused.result.assumptions?.length > 0 && <div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Assumptions in this response</h3><ul className="list-disc pl-5 space-y-1">{focused.result.assumptions.map((a, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{a}</li>))}</ul></div>}
|
||||
{focused.result.relationships?.length > 0 && <div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Connections</h3><ul className="list-disc pl-5 space-y-1">{focused.result.relationships.map((r, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{r.from} → {r.to} ({r.type})</li>))}</ul></div>}
|
||||
{focused.result.possibleFollowUpQuestions?.length > 0 && <div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Questions this raises</h3><ul className="list-disc pl-5 space-y-1">{focused.result.possibleFollowUpQuestions.map((q, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{q}</li>))}</ul></div>}
|
||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h3><ul className="list-disc pl-5 space-y-1">{(focused.result.observations || []).map((o, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{o}</li>))}</ul></div>
|
||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Still unclear</h3><ul className="list-disc pl-5 space-y-1">{(focused.result.uncertainties || []).map((u, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{u}</li>))}</ul></div>
|
||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Assumptions</h3><ul className="list-disc pl-5 space-y-1">{(focused.result.assumptions || []).map((a, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{a}</li>))}</ul></div>
|
||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Connections</h3><ul className="list-disc pl-5 space-y-1">{(focused.result.relationships || []).map((r, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{r.from} → {r.to} ({r.type})</li>))}</ul></div>
|
||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Questions this raises</h3>
|
||||
{(focused.result.possibleFollowUpQuestions || []).length > 0 ? (
|
||||
<div className="space-y-1 mt-1">
|
||||
{focused.result.possibleFollowUpQuestions.map((q, i) => (
|
||||
<button
|
||||
key={i}
|
||||
onClick={(e) => { e.stopPropagation(); setFollowUpQuestion(q); }}
|
||||
style={{ cursor: "pointer" }}
|
||||
className="w-full text-left rounded-lg border border-blue-200/60 bg-blue-50/40 px-3 py-2.5 text-sm leading-relaxed text-gray-800 hover:border-blue-300 hover:bg-blue-100/60 transition"
|
||||
data-testid="follow-up-question"
|
||||
>
|
||||
{q} → pick this question
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-xs text-gray-400">None yet</p>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1113,6 +1132,16 @@ export default function ReasoningWorkspace({
|
||||
doFormulate(target);
|
||||
}
|
||||
|
||||
function setFollowUpQuestion(followUpText) {
|
||||
const target = focusedPresentationItemId;
|
||||
if (!target || !followUpText?.trim()) return;
|
||||
setFocusedInvestigations((prev) => ({
|
||||
...prev,
|
||||
[target]: { ...prev[target], question: followUpText.trim(), answer: null },
|
||||
}));
|
||||
setFocusedAnswer("");
|
||||
}
|
||||
|
||||
function hasFocusedContent() {
|
||||
if (!focused) return false;
|
||||
const q = focused.question;
|
||||
@@ -1201,40 +1230,79 @@ export default function ReasoningWorkspace({
|
||||
{/* ── RTO.29D — initial post-Analyse reflection ──────── */}
|
||||
{postAnalyseStatus === "success" && (
|
||||
<div className="space-y-6" data-testid="initial-reflection-surface">
|
||||
{/* What I understood */}
|
||||
<div className="rounded-lg border border-blue-200/60 bg-blue-50/40 px-6 pt-5 pb-6">
|
||||
<h2 className="mb-3 text-[11px] font-semibold tracking-widest uppercase text-gray-500">
|
||||
What I understood
|
||||
</h2>
|
||||
<p className="text-sm leading-relaxed text-gray-700">{propUnderstanding}</p>
|
||||
</div>
|
||||
{/* Current Understanding + Situation — prominent two-column orienting surface */}
|
||||
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
||||
<div className={`space-y-6 ${hasGraph ? 'lg:col-span-2' : 'lg:col-span-full'}`}>
|
||||
{/* Current Understanding — prominent orienting surface */}
|
||||
<div className="rounded-xl border-[2.5px] border-teal-300/70 bg-gradient-to-b from-teal-50/60 to-white px-8 pt-7 pb-8 shadow-sm">
|
||||
<h2 className="mb-4 text-[11px] font-bold tracking-[.18em] uppercase text-teal-700/60">
|
||||
Current Understanding
|
||||
</h2>
|
||||
<p className="text-lg leading-relaxed text-gray-800">{propUnderstanding}</p>
|
||||
</div>
|
||||
|
||||
{/* Initial proposed findings */}
|
||||
<div className="space-y-3" data-testid="initial-proposed-findings">
|
||||
<h2 className="text-[11px] font-semibold tracking-widest uppercase text-gray-500">
|
||||
Initial proposed findings
|
||||
</h2>
|
||||
{/* Initial proposed findings — unknowns + plausible interpretations from reconstruction */}
|
||||
<div className="space-y-3" data-testid="initial-proposed-findings">
|
||||
<h2 className="text-[11px] font-semibold tracking-widest uppercase text-gray-500">
|
||||
Open Questions
|
||||
</h2>
|
||||
{(() => {
|
||||
const resolvedIds = new Set(graph?.resolvedNodeIds || []);
|
||||
// Surface only candidate items from the semantic reconstruction that are worth investigating:
|
||||
// — unknowns (importantUnknowns from the LLM's reconstruction)
|
||||
// — assumptions (plausibleInterpretations from the LLM's reconstruction)
|
||||
// Skips observations, states, relationships, transitions — these are already established facts/context.
|
||||
// Both kinds check status !== "resolved" and excluded resolvedIds to mirror OpenQuestionsPanel logic.
|
||||
const candidateKinds = ["unknown", "assumption"];
|
||||
return (
|
||||
graph?.nodes?.map((node) =>
|
||||
node.kind === "unknown" && node.status !== "resolved" && !resolvedIds.has(node.id) ? (
|
||||
<button
|
||||
key={node.id}
|
||||
onClick={() => startFocused(node.id)}
|
||||
style={{ cursor: "pointer" }}
|
||||
className="w-full text-left rounded-lg border border-gray-200 bg-white px-5 py-4 transition hover:border-gray-300 hover:bg-gray-50"
|
||||
>
|
||||
<span className="block text-sm leading-relaxed text-gray-900">{node.label}</span>
|
||||
{node.description && node.description !== node.label && (
|
||||
<p className="mt-1.5 text-xs leading-snug text-gray-500">{node.description}</p>
|
||||
)}
|
||||
</button>
|
||||
) : null,
|
||||
) || []
|
||||
(graph?.nodes || [])
|
||||
.filter(
|
||||
(n) =>
|
||||
candidateKinds.includes(n.kind) &&
|
||||
n.status !== "resolved" &&
|
||||
!resolvedIds.has(n.id),
|
||||
)
|
||||
.map((node) => {
|
||||
const tag = node.kind === "assumption" ? "Plausible interpretation" : "Unclear";
|
||||
return (
|
||||
<button
|
||||
key={node.id}
|
||||
onClick={() => startFocused(node.id)}
|
||||
style={{ cursor: "pointer" }}
|
||||
className="w-full text-left rounded-lg border border-gray-200 bg-white px-5 py-4 transition hover:border-gray-300 hover:bg-gray-50"
|
||||
>
|
||||
<span className="block text-sm leading-relaxed text-gray-900">{node.label}</span>
|
||||
{node.description && node.description !== node.label && (
|
||||
<p className="mt-1.5 text-xs leading-snug text-gray-500">{node.description}</p>
|
||||
)}
|
||||
<span className="mt-2 block text-[10px] uppercase tracking-wider text-gray-400">{tag}</span>
|
||||
</button>
|
||||
);
|
||||
})
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Situation panel during initial reflection */}
|
||||
{hasGraph && (
|
||||
<div className="space-y-6 lg:col-span-1">
|
||||
<OriginalSituation scenario={scenario} centralStatement={graph?.centralStatement} />
|
||||
</div>
|
||||
)}
|
||||
{!hasGraph && scenario && (
|
||||
<div className="space-y-6 lg:col-span-1">
|
||||
<div className="rounded-lg border border-gray-200/60 bg-gray-50/40 px-5 py-4">
|
||||
<h2 className="mb-2 text-[11px] font-semibold tracking-widest uppercase text-gray-500">
|
||||
Situation
|
||||
</h2>
|
||||
<p className="whitespace-pre-wrap text-sm leading-relaxed text-gray-600">
|
||||
{scenario}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1269,6 +1337,7 @@ export default function ReasoningWorkspace({
|
||||
setFocusedAnswer={setFocusedAnswer}
|
||||
focusedAnswer={focusedAnswer}
|
||||
setDoneForNowIds={setDoneForNowIds}
|
||||
setFollowUpQuestion={setFollowUpQuestion}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user