Skip to content

Commit 19ced60

Browse files
committed
fix(vscode): restore neutral primary and add a brand accent token
The periwinkle that #21 wrote into --primary and --muted-foreground tinted every neutral surface, so both tokens go back to their original oklch values. The accent it was compensating for now lives in its own --brand token, applied only where an accent is actually wanted: inline code in Markdown, and the DynamicWorkflow lane bars and running status dot, which were invisible against --muted once --primary went back to a near-black neutral. The scroll-to-bottom button and the effort toggle return to their blue accents for the same reason. Also: - a finished workflow lane renders a full bar. The bar is scaled to the busiest agent, so a lane that completed in fewer steps kept a permanent gap. - the generation-speed pill in the thinking row no longer wraps "46.0" and "t/s" onto two lines, and uses tabular-nums so it stops resizing.
1 parent 6fe3e4b commit 19ced60

6 files changed

Lines changed: 26 additions & 26 deletions

File tree

apps/vscode/webview-ui/src/components/ChatArea.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function ScrollButton() {
1515
return (
1616
<button
1717
onClick={() => scrollToBottom()}
18-
className={cn("absolute bottom-4 right-4 p-2 rounded-full z-10", "bg-primary text-primary-foreground shadow-lg", "hover:bg-primary/85 transition-all")}
18+
className={cn("absolute bottom-4 right-4 p-2 rounded-full z-10", "bg-blue-400 text-white shadow-lg", "hover:bg-blue-600 transition-all")}
1919
>
2020
<IconArrowDown className="size-4" />
2121
</button>

apps/vscode/webview-ui/src/components/ChatMessage.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function ThinkingIndicator() {
3333

3434
return (
3535
<div className="flex items-center gap-2.5 mt-1 py-1">
36-
<div className="flex items-center gap-2">
36+
<div className="flex min-w-0 items-center gap-2">
3737
<PythinkerLogo className="size-4 shrink-0" />
3838
<span className="text-[11px] font-medium tracking-wide text-zinc-400 dark:text-zinc-300 flex items-center">
3939
<span className="animate-shimmer-text">Pythinking</span>
@@ -45,9 +45,9 @@ function ThinkingIndicator() {
4545
</span>
4646
</div>
4747
{speed > 0 && (
48-
<span className="inline-flex items-center gap-1 text-[10px] font-mono text-zinc-400 dark:text-zinc-400 bg-zinc-800/20 dark:bg-zinc-800/40 px-1.5 py-0.5 rounded-full border border-zinc-700/30">
49-
<IconBolt className="size-3 text-amber-400 animate-pulse" />
50-
<span>{speed.toFixed(1)} t/s</span>
48+
<span className="inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-[10px] font-mono text-zinc-400 dark:text-zinc-400 bg-zinc-800/20 dark:bg-zinc-800/40 px-1.5 py-0.5 rounded-full border border-zinc-700/30">
49+
<IconBolt className="size-3 shrink-0 text-amber-400 animate-pulse" />
50+
<span className="tabular-nums">{speed.toFixed(1)} t/s</span>
5151
</span>
5252
)}
5353
</div>

apps/vscode/webview-ui/src/components/Markdown.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ export const Markdown = memo(function Markdown({ content, className, enableEnric
253253
if (isInline) {
254254
const showColor = enableEnrichment && hasColors(code);
255255
return (
256-
<code className="bg-muted px-1 py-0.5 rounded text-[11px]" {...props}>
256+
// --brand reads as a distinct token without competing with body text.
257+
<code className="bg-muted text-brand px-1 py-0.5 rounded text-[11px]" {...props}>
257258
{showColor ? <ColorEnrichedText text={code} /> : children}
258259
</code>
259260
);

apps/vscode/webview-ui/src/components/ThinkingButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export function ThinkingButton({ mode, effort, efforts = [], alwaysOn = false, d
3333
disabled={disabled || mode === "always"}
3434
className={cn(
3535
"flex items-center gap-0.5 justify-center h-6 min-w-6 px-1 rounded-md transition-all",
36-
active ? "bg-primary/15 text-primary" : "bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground",
37-
!disabled && mode !== "always" && "cursor-pointer hover:bg-primary/25",
36+
active ? "bg-blue-500/15 text-blue-500" : "bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground",
37+
!disabled && mode !== "always" && "cursor-pointer hover:bg-blue-500/25",
3838
(disabled || mode === "always") && "cursor-default",
3939
)}
4040
>

apps/vscode/webview-ui/src/components/WorkflowCard.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,25 @@ function laneMostRecentToolLabel(lane: WorkflowLane): string | null {
4141

4242
function StatusDot({ status }: { status: WorkflowLane["status"] }) {
4343
const color =
44-
status === "running" ? "bg-primary" : status === "done" ? "bg-success" : status === "failed" ? "bg-destructive" : "bg-muted-foreground";
44+
status === "running" ? "bg-brand" : status === "done" ? "bg-success" : status === "failed" ? "bg-destructive" : "bg-muted-foreground";
4545
return <span className={cn("inline-block size-2 rounded-full shrink-0", color)} />;
4646
}
4747

4848
function LaneBar({ fraction, done }: { fraction: number; done: boolean }) {
4949
return (
5050
<div className="h-[3px] w-24 rounded-full bg-muted overflow-hidden shrink-0">
51-
<div className={cn("h-full rounded-full", done ? "bg-success" : "bg-primary")} style={{ width: `${Math.round(fraction * 100)}%` }} />
51+
<div className={cn("h-full rounded-full", done ? "bg-success" : "bg-brand")} style={{ width: `${Math.round(fraction * 100)}%` }} />
5252
</div>
5353
);
5454
}
5555

5656
function LaneRow({ lane, maxSteps, renderStepItem }: { lane: WorkflowLane; maxSteps: number; renderStepItem: (item: UIStepItem) => ReactNode }) {
5757
const [expanded, setExpanded] = useState(false);
58-
const fraction = maxSteps > 0 ? lane.stepCount / maxSteps : 0;
5958
const done = lane.status === "done";
59+
// A finished lane always reads full: the bar is relative to the busiest agent,
60+
// so a lane that did fewer steps than the busiest one would otherwise show a
61+
// gap after it completed.
62+
const fraction = done ? 1 : maxSteps > 0 ? lane.stepCount / maxSteps : 0;
6063
const queued = lane.status === "spawned" && lane.stepCount === 0;
6164
const runningToolLabel = lane.status === "running" ? laneMostRecentToolLabel(lane) : null;
6265
const duration = lane.startedAt !== undefined && lane.endedAt !== undefined ? formatDuration(lane.endedAt - lane.startedAt) : null;

apps/vscode/webview-ui/src/styles/index.css

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,18 @@
1414
--card-foreground: oklch(0.141 0.005 285.823);
1515
--popover: oklch(1 0 0);
1616
--popover-foreground: oklch(0.141 0.005 285.823);
17-
/* Brand periwinkle, matching the CLI (lightColors.primary). Was
18-
oklch(0.21) — a near-black that made every accent surface read as an
19-
unstyled dark chip. */
20-
--primary: #4a5bc4;
17+
--primary: oklch(0.21 0.006 285.885);
2118
--primary-foreground: oklch(1 0 0);
2219
--secondary: oklch(0.967 0.001 286.375);
2320
--secondary-foreground: oklch(0.21 0.006 285.885);
2421
--muted: oklch(0.967 0.001 286.375);
25-
/* Periwinkle, matching the CLI palette (lightColors.primary). Plain grey at
26-
this size read as disabled rather than secondary. */
27-
--muted-foreground: #4a5bc4;
22+
--muted-foreground: oklch(0.552 0.016 285.938);
2823
--accent: oklch(0.967 0.001 286.375);
2924
--accent-foreground: oklch(0.21 0.006 285.885);
3025
--destructive: oklch(0.577 0.245 27.325);
26+
/* Muted periwinkle accent (CLI primary). Used for inline code and progress
27+
fills — --primary is a near-black neutral and disappears against --muted. */
28+
--brand: #4a5bc4;
3129
/* CLI lightColors.success — the "on" colour for toggles. */
3230
--success: #0e7a38;
3331
--success-foreground: oklch(1 0 0);
@@ -43,20 +41,17 @@
4341
--card-foreground: oklch(0.985 0 0);
4442
--popover: oklch(0.18 0.005 285.823);
4543
--popover-foreground: oklch(0.985 0 0);
46-
/* Brand periwinkle, matching the CLI (darkColors.primary). The old
47-
oklch(0.21) was DARKER than --input (oklch 0.274) and barely above the
48-
background, so accent surfaces and "on" states disappeared in dark mode. */
49-
--primary: #bbc6ff;
50-
--primary-foreground: oklch(0.141 0.005 285.823);
44+
--primary: oklch(0.21 0.006 285.885);
45+
--primary-foreground: oklch(0.985 0 0);
5146
--secondary: oklch(0.274 0.006 286.033);
5247
--secondary-foreground: oklch(0.985 0 0);
5348
--muted: oklch(0.274 0.006 286.033);
54-
/* Periwinkle, matching the CLI palette (darkColors.primary). The previous
55-
near-neutral grey sat too close to the background to read at 11px. */
56-
--muted-foreground: #bbc6ff;
49+
--muted-foreground: oklch(0.705 0.015 286.067);
5750
--accent: oklch(0.274 0.006 286.033);
5851
--accent-foreground: oklch(0.985 0 0);
5952
--destructive: oklch(0.704 0.191 22.216);
53+
/* Muted periwinkle accent (CLI primary), dark variant. */
54+
--brand: #aab3e8;
6055
/* CLI darkColors.success — the "on" colour for toggles. */
6156
--success: #4ec87e;
6257
--success-foreground: oklch(0.141 0.005 285.823);
@@ -110,6 +105,7 @@ body {
110105
--color-destructive: var(--destructive);
111106
--color-success: var(--success);
112107
--color-success-foreground: var(--success-foreground);
108+
--color-brand: var(--brand);
113109
--color-border: var(--border);
114110
--color-input: var(--input);
115111
--color-ring: var(--ring);

0 commit comments

Comments
 (0)