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:
@@ -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.
|
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.
|
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.
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ export default function InvestigationMap({ turnCount = 0 }) {
|
|||||||
if (!hasActiveTopics && groups.established.length === 0) return null;
|
if (!hasActiveTopics && groups.established.length === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border border-gray-200 bg-white p-5" role="region" aria-label="Investigation map preview">
|
<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 uppercase tracking-wide text-gray-500">
|
<h2 className="mb-1 text-sm font-semibold tracking-tight text-gray-400">
|
||||||
Investigation Map Preview
|
Investigation Map Preview
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mb-3 text-xs text-gray-400">
|
<p className="mb-3 text-xs text-gray-400">
|
||||||
|
|||||||
@@ -132,40 +132,19 @@ function InvestigationSummaryPanel({ graph, selectedQuestion, result, updateStat
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Questions */}
|
{/* Questions — hidden when no meaningful value to show */}
|
||||||
<div className="grid grid-cols-2 gap-4">
|
{isInvestigating && questionsRemaining > 0 && (
|
||||||
<div>
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<span className="block text-xs text-gray-400">Questions answered</span>
|
<div>
|
||||||
<span className={`text-lg font-semibold ${colors.text}`}>{questionsAnswered}</span>
|
<span className="block text-xs text-gray-400">Questions answered</span>
|
||||||
</div>
|
<span className={`text-lg font-semibold ${colors.text}`}>{questionsAnswered}</span>
|
||||||
<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>
|
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,15 +249,14 @@ function CurrentInvestigationCard({ selectedQuestion, graph }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="investigation-card rounded-lg border-2 border-green-300 bg-green-50 p-6">
|
<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">
|
<h2 className="mb-2 text-sm font-bold tracking-wide text-green-700">
|
||||||
Current investigation
|
Investigation
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xl font-semibold leading-snug text-gray-900">{q}</p>
|
<p className="text-xl font-semibold leading-snug text-gray-900">{q}</p>
|
||||||
{whyMattersText && (
|
{whyMattersText && (
|
||||||
<div className="mt-4 space-y-1">
|
<p className="mt-4 text-sm leading-relaxed text-green-800">
|
||||||
<h3 className="text-xs font-bold uppercase tracking-wide text-green-800">Why this matters</h3>
|
{whyMattersText}
|
||||||
<p className="text-sm text-gray-700">{whyMattersText}</p>
|
</p>
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -318,9 +317,9 @@ function CurrentUnderstandingCard({ currentSummary, plainLanguage }) {
|
|||||||
if (!summary) return null;
|
if (!summary) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border border-gray-200 bg-white p-5">
|
<div className="rounded-lg border border-gray-100 bg-white px-6 pt-5 pb-6">
|
||||||
<h2 className="mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500">
|
<h2 className="mb-4 text-xl font-semibold tracking-tight text-gray-800">
|
||||||
Current understanding
|
Understanding
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm leading-relaxed text-gray-700">{summary}</p>
|
<p className="text-sm leading-relaxed text-gray-700">{summary}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -332,9 +331,9 @@ function PlainLanguageCard({ summary }) {
|
|||||||
if (!summary) return null;
|
if (!summary) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border border-gray-200 bg-white p-5">
|
<div className="rounded-lg border border-gray-100 bg-white px-6 pt-5 pb-6">
|
||||||
<h2 className="mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500">
|
<h2 className="mb-4 text-xl font-semibold tracking-tight text-gray-800">
|
||||||
Current understanding
|
Understanding
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm leading-relaxed text-gray-700">{summary}</p>
|
<p className="text-sm leading-relaxed text-gray-700">{summary}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -363,22 +362,13 @@ function InvestigationHistoryCard({ turn }) {
|
|||||||
{displayedQuestion}
|
{displayedQuestion}
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
<div className="space-y-2 px-4 pb-3 pt-1">
|
<div className="space-y-2 px-4 pb-4 pt-2">
|
||||||
<p>
|
|
||||||
<strong>Your answer</strong>
|
|
||||||
</p>
|
|
||||||
<p className="text-gray-700">{turn.answer}</p>
|
<p className="text-gray-700">{turn.answer}</p>
|
||||||
|
|
||||||
{turn.acknowledgement && (
|
{turn.acknowledgement && (
|
||||||
<>
|
<p className="italic text-gray-500">
|
||||||
<hr className="border-gray-200" />
|
{turn.acknowledgement}
|
||||||
<p>
|
</p>
|
||||||
<strong>What changed</strong>
|
|
||||||
</p>
|
|
||||||
<p className="italic text-gray-500">
|
|
||||||
{turn.acknowledgement}
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
@@ -393,8 +383,8 @@ function InvestigationHistory({ turns }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3" data-testid="investigation-history">
|
<div className="space-y-3" data-testid="investigation-history">
|
||||||
<h2 className="text-xs font-bold uppercase tracking-wider text-gray-400">
|
<h2 className="text-xs font-semibold tracking-wider text-gray-400">
|
||||||
Investigation history
|
History
|
||||||
</h2>
|
</h2>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{turns.map((turn) => (
|
{turns.map((turn) => (
|
||||||
@@ -412,9 +402,9 @@ function OriginalSituation({ scenario, centralStatement }) {
|
|||||||
if (!text) return null;
|
if (!text) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border border-gray-200 bg-gray-50/70 px-5 py-4">
|
<div className="rounded-lg border border-gray-100 bg-gray-50/70 px-5 py-4">
|
||||||
<h2 className="mb-2 text-xs font-bold uppercase tracking-widest text-gray-400">
|
<h2 className="mb-2 text-xs font-semibold tracking-wider text-gray-400">
|
||||||
Original situation
|
Situation
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p className="whitespace-pre-wrap text-sm leading-relaxed text-gray-700">
|
<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">
|
<form onSubmit={handleUpdateCaptureAndSubmit} className="space-y-4 rounded-lg border border-gray-200 bg-white p-5">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="rw-answer" className="mb-2 block text-sm font-medium text-gray-700">
|
<label htmlFor="rw-answer" className="mb-2 block text-sm font-medium text-gray-700">
|
||||||
Your response
|
Response
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
id="rw-answer"
|
id="rw-answer"
|
||||||
@@ -713,9 +703,9 @@ export default function ReasoningWorkspace({
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!answer.trim()}
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -730,7 +720,7 @@ export default function ReasoningWorkspace({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* ── Current understanding (active investigation only) ─ */}
|
{/* ── Current understanding (active investigation only) ─ */}
|
||||||
{hasCurrentSummaryCondition && !hasSelectedQuestion === false && (
|
{hasCurrentSummaryCondition && hasSelectedQuestion && (
|
||||||
<CurrentUnderstandingCard currentSummary={graph?.currentSummary || result?.updatedSituationGraph?.currentSummary} plainLanguage={propUnderstanding || null} />
|
<CurrentUnderstandingCard currentSummary={graph?.currentSummary || result?.updatedSituationGraph?.currentSummary} plainLanguage={propUnderstanding || null} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user