style: polish investigation workspace

- Summary panel: hide meaningless metrics (questions answered/remaining) until genuinely in progress; remove placeholder timestamps
- Understanding card: increased visual importance via larger heading, lighter border, more padding
- History section: reduced labels to brief forms ('History', 'Situation'), removed uppercase decorative labels from headings
- Investigation Map Preview: lighter borders, muted text, subtle background to signal provisional state
- Turn history cards: removed redundant subheadings ('Your answer', 'What changed') and divider lines
- Button label: 'Update situation' → 'Update'; padding consistent with design tokens
- Condition clarity fix: '!hasSelectedQuestion === false' → 'hasSelectedQuestion'
- Workspace polish section added to UX guidelines
This commit is contained in:
2026-08-05 10:30:22 +01:00
parent 86d9bc3f48
commit 2f87cca88d
4 changed files with 58 additions and 69 deletions
+20
View File
@@ -242,3 +242,23 @@ Updated workspace returns
The interaction is consistent in intent — both modes confirm input acceptance and pause the active response area — but the page-level behaviour differs because one constructs from nothing while the other refines existing context.
Users should never wonder whether their input has been accepted or whether the engine is still reasoning.
## Workspace Polish (v0.7)
The workspace should feel calm. Every visible element must justify its presence.
Unknown values should usually be hidden rather than represented with placeholders.
Whitespace is preferred over decorative UI.
Prefer removing over adding. Prefer consistency over cleverness.
Every section group should feel visually connected — spacing within a group is tighter than between groups.
Labels should be brief. "Investigation History" → "History". "Your response" → "Response". The context already makes the meaning clear.
Headings should be clean. Remove unnecessary subheadings that duplicate context. Remove uppercase labels from headings where they add visual noise without adding information.
Cards should have consistent border radius, padding, and heading treatment across the workspace.
An Investigation Map Preview should look provisional — lighter borders, muted text, subtle background — so the user knows it is a preview rather than completed content.
+2 -2
View File
@@ -82,8 +82,8 @@ export default function InvestigationMap({ turnCount = 0 }) {
if (!hasActiveTopics && groups.established.length === 0) return null;
return (
<div className="rounded-lg border border-gray-200 bg-white p-5" role="region" aria-label="Investigation map preview">
<h2 className="mb-1 text-sm font-semibold uppercase tracking-wide text-gray-500">
<div className="rounded-lg border border-gray-100 bg-gray-50/50 p-4" role="region" aria-label="Investigation map preview">
<h2 className="mb-1 text-sm font-semibold tracking-tight text-gray-400">
Investigation Map Preview
</h2>
<p className="mb-3 text-xs text-gray-400">
+12 -33
View File
@@ -132,40 +132,19 @@ function InvestigationSummaryPanel({ graph, selectedQuestion, result, updateStat
</div>
)}
{/* Questions */}
<div className="grid grid-cols-2 gap-4">
<div>
<span className="block text-xs text-gray-400">Questions answered</span>
<span className={`text-lg font-semibold ${colors.text}`}>{questionsAnswered}</span>
</div>
<div>
<span className="block text-xs text-gray-400">Still working on</span>
{/* TODO: avoid implying 1 unknown = 1 remaining question */}
{isInvestigating ? (
<span className={`text-lg font-semibold ${colors.text}`}>{questionsRemaining > 0 ? questionsRemaining + " items" : "—"}</span>
) : (
<span className={`text-lg font-semibold ${colors.text}`}></span>
)}
</div>
</div>
{/* Timestamps */}
<div className="space-y-1 text-xs text-gray-400">
<div className="flex justify-between">
<span>Investigation started</span>
<span>{formatTimestamp(investigationStartTime)}</span>
</div>
<div className="flex justify-between">
<span>Last updated</span>
<span>{formatTimestamp(lastUpdatedAt)}</span>
</div>
{elapsedSeconds > 0 && (
<div className="flex justify-between">
<span>Elapsed since last update</span>
<span>{humaniseDuration(elapsedSeconds)}</span>
{/* Questions — hidden when no meaningful value to show */}
{isInvestigating && questionsRemaining > 0 && (
<div className="grid grid-cols-2 gap-4">
<div>
<span className="block text-xs text-gray-400">Questions answered</span>
<span className={`text-lg font-semibold ${colors.text}`}>{questionsAnswered}</span>
</div>
)}
</div>
<div>
<span className="block text-xs text-gray-400">Still working on</span>
<span className={`text-lg font-semibold ${colors.text}`}>{questionsRemaining + " items"}</span>
</div>
</div>
)}
</div>
);
}
+24 -34
View File
@@ -249,15 +249,14 @@ function CurrentInvestigationCard({ selectedQuestion, graph }) {
return (
<div className="investigation-card rounded-lg border-2 border-green-300 bg-green-50 p-6">
<h2 className="mb-2 text-sm font-bold uppercase tracking-wide text-green-700">
Current investigation
<h2 className="mb-2 text-sm font-bold tracking-wide text-green-700">
Investigation
</h2>
<p className="text-xl font-semibold leading-snug text-gray-900">{q}</p>
{whyMattersText && (
<div className="mt-4 space-y-1">
<h3 className="text-xs font-bold uppercase tracking-wide text-green-800">Why this matters</h3>
<p className="text-sm text-gray-700">{whyMattersText}</p>
</div>
<p className="mt-4 text-sm leading-relaxed text-green-800">
{whyMattersText}
</p>
)}
</div>
);
@@ -318,9 +317,9 @@ function CurrentUnderstandingCard({ currentSummary, plainLanguage }) {
if (!summary) return null;
return (
<div className="rounded-lg border border-gray-200 bg-white p-5">
<h2 className="mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500">
Current understanding
<div className="rounded-lg border border-gray-100 bg-white px-6 pt-5 pb-6">
<h2 className="mb-4 text-xl font-semibold tracking-tight text-gray-800">
Understanding
</h2>
<p className="text-sm leading-relaxed text-gray-700">{summary}</p>
</div>
@@ -332,9 +331,9 @@ function PlainLanguageCard({ summary }) {
if (!summary) return null;
return (
<div className="rounded-lg border border-gray-200 bg-white p-5">
<h2 className="mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500">
Current understanding
<div className="rounded-lg border border-gray-100 bg-white px-6 pt-5 pb-6">
<h2 className="mb-4 text-xl font-semibold tracking-tight text-gray-800">
Understanding
</h2>
<p className="text-sm leading-relaxed text-gray-700">{summary}</p>
</div>
@@ -363,22 +362,13 @@ function InvestigationHistoryCard({ turn }) {
{displayedQuestion}
</summary>
<div className="space-y-2 px-4 pb-3 pt-1">
<p>
<strong>Your answer</strong>
</p>
<div className="space-y-2 px-4 pb-4 pt-2">
<p className="text-gray-700">{turn.answer}</p>
{turn.acknowledgement && (
<>
<hr className="border-gray-200" />
<p>
<strong>What changed</strong>
</p>
<p className="italic text-gray-500">
{turn.acknowledgement}
</p>
</>
<p className="italic text-gray-500">
{turn.acknowledgement}
</p>
)}
</div>
</details>
@@ -393,8 +383,8 @@ function InvestigationHistory({ turns }) {
return (
<div className="space-y-3" data-testid="investigation-history">
<h2 className="text-xs font-bold uppercase tracking-wider text-gray-400">
Investigation history
<h2 className="text-xs font-semibold tracking-wider text-gray-400">
History
</h2>
<div className="space-y-2">
{turns.map((turn) => (
@@ -412,9 +402,9 @@ function OriginalSituation({ scenario, centralStatement }) {
if (!text) return null;
return (
<div className="rounded-lg border border-gray-200 bg-gray-50/70 px-5 py-4">
<h2 className="mb-2 text-xs font-bold uppercase tracking-widest text-gray-400">
Original situation
<div className="rounded-lg border border-gray-100 bg-gray-50/70 px-5 py-4">
<h2 className="mb-2 text-xs font-semibold tracking-wider text-gray-400">
Situation
</h2>
<p className="whitespace-pre-wrap text-sm leading-relaxed text-gray-700">
@@ -694,7 +684,7 @@ export default function ReasoningWorkspace({
<form onSubmit={handleUpdateCaptureAndSubmit} className="space-y-4 rounded-lg border border-gray-200 bg-white p-5">
<div>
<label htmlFor="rw-answer" className="mb-2 block text-sm font-medium text-gray-700">
Your response
Response
</label>
<textarea
id="rw-answer"
@@ -713,9 +703,9 @@ export default function ReasoningWorkspace({
<button
type="submit"
disabled={!answer.trim()}
className="rounded-lg bg-blue-700 px-5 py-2 text-sm font-medium text-white transition hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-40"
className="rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-40"
>
Update situation
Update
</button>
</div>
</form>
@@ -730,7 +720,7 @@ export default function ReasoningWorkspace({
)}
{/* ── Current understanding (active investigation only) ─ */}
{hasCurrentSummaryCondition && !hasSelectedQuestion === false && (
{hasCurrentSummaryCondition && hasSelectedQuestion && (
<CurrentUnderstandingCard currentSummary={graph?.currentSummary || result?.updatedSituationGraph?.currentSummary} plainLanguage={propUnderstanding || null} />
)}