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:
2026-08-22 19:01:45 +01:00
parent 517d780e2c
commit 96ad0e7915
+107 -38
View File
@@ -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}
/>
)}