Skip to content

Commit 7064ff6

Browse files
committed
fix(web): align thread details summaries and usage rows with the design
1 parent 92c487d commit 7064ff6

3 files changed

Lines changed: 31 additions & 53 deletions

File tree

‎apps/web/src/components/chat/ThreadDetailsControl.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const parts = {
1717
row: THREAD_DETAILS_PANEL_ROW_CLASS,
1818
heading:
1919
"flex min-w-0 flex-1 items-center gap-2 rounded-md text-left text-caption text-muted-foreground hover:text-foreground focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
20+
usage:
21+
"col-span-4 grid min-w-0 grid-cols-subgrid items-center rounded-md text-left text-meta text-muted-foreground hover:text-foreground focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
2022
choice: THREAD_DETAILS_PANEL_CHOICE_ROW_CLASS,
2123
icon: THREAD_DETAILS_PANEL_ICON_ACTION_CLASS,
2224
meta: THREAD_DETAILS_PANEL_META_ACTION_CLASS,

‎apps/web/src/components/chat/ThreadDetailsSection.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export function ThreadDetailsSection({
9797
setDisclosure({ empty, collapsed: empty ? !isCollapsed : null });
9898
}}
9999
>
100-
<span>{title}</span>
100+
<span className="shrink-0">{title}</span>
101101
{summary ? (
102102
<span className="ms-auto truncate text-caption text-muted-foreground">{summary}</span>
103103
) : null}

‎apps/web/src/components/chat/ThreadDetailsUsage.tsx‎

Lines changed: 28 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ import { type ContextWindowSnapshot, formatContextWindowTokens } from "../../lib
2121
import { cn } from "../../lib/utils";
2222
import { formatUpcomingTimestamp } from "../../timestampFormat";
2323
import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
24+
import { Button } from "../ui/button";
2425
import { ThreadDetailsControl } from "./ThreadDetailsControl";
25-
import { ContextWindowMeter } from "./ContextWindowMeter";
26+
import { ContextWindowMeter, ContextWindowSegments } from "./ContextWindowMeter";
2627
import { ThreadDetailsSection } from "./ThreadDetailsSection";
2728

29+
// The canvas reserves the same icon, label, meter, percent and trailing columns in every row.
30+
const USAGE_ROW_CLASS =
31+
"grid grid-cols-[1rem_3.625rem_minmax(0,1fr)_1.875rem_2.75rem] items-center gap-x-2 ps-3 pe-2 text-meta";
32+
2833
const PACE_LABEL: Record<LimitPace, string> = {
2934
ahead: "Ahead of pace",
3035
on: "On pace",
@@ -97,18 +102,13 @@ export function ThreadDetailsContext({
97102
}
98103
const maxTokens = usage.maxTokens != null && usage.maxTokens > 0 ? usage.maxTokens : null;
99104
const used = maxTokens !== null ? Math.max(0, Math.min(100, usage.usedPercentage ?? 0)) : null;
100-
const threshold = usage.autoCompactThreshold ?? null;
101-
const tick =
102-
maxTokens !== null && threshold !== null && threshold > 0 && threshold < maxTokens
103-
? (threshold / maxTokens) * 100
104-
: null;
105105
const tokens =
106106
maxTokens !== null
107107
? `${formatContextWindowTokens(usage.usedTokens)} / ${formatContextWindowTokens(maxTokens)}`
108108
: `${formatContextWindowTokens(usage.usedTokens)} tokens`;
109109
return (
110110
<ThreadDetailsSection title="Context window" variant="usage">
111-
<div className="flex min-h-11 items-center gap-2 ps-3 pe-2 text-meta">
111+
<div className={cn(USAGE_ROW_CLASS, "h-8")}>
112112
<ContextWindowMeter
113113
usage={usage}
114114
side="left"
@@ -117,54 +117,29 @@ export function ThreadDetailsContext({
117117
compactDisabledReason={compactDisabledReason}
118118
trigger={
119119
<ThreadDetailsControl
120-
part="heading"
120+
part="usage"
121121
aria-label={`Context: ${tokens}${maxTokens !== null ? " tokens" : ""}${used !== null ? `, ${Math.round(used)}% used` : " used"}`}
122122
>
123123
<GaugeIcon className="size-4 shrink-0" />
124-
<span className="flex min-w-0 flex-1 flex-col gap-1 text-meta">
125-
<span className="flex items-center justify-between gap-2 text-foreground">
126-
<span>Context</span>
127-
{used !== null ? (
128-
<span className="tabular-nums text-muted-foreground">{Math.round(used)}%</span>
129-
) : null}
130-
</span>
131-
<span className="flex items-center gap-2">
132-
{used !== null ? (
133-
<span className="relative h-1 min-w-0 flex-1 rounded-full bg-muted-foreground/20">
134-
<span
135-
className={cn(
136-
"absolute inset-y-0 left-0 rounded-full",
137-
used >= 90 ? "bg-error" : used >= 80 ? "bg-warning" : "bg-foreground/80",
138-
)}
139-
style={{ width: used > 0 ? `max(${used}%, 2px)` : "0%" }}
140-
/>
141-
{tick !== null ? (
142-
<span
143-
aria-hidden
144-
className="absolute -top-[3px] h-2.5 w-0.5 rounded-sm bg-muted-foreground"
145-
style={{ left: `${tick}%` }}
146-
/>
147-
) : null}
148-
</span>
149-
) : null}
150-
<span className="shrink-0 text-caption tabular-nums text-muted-foreground">
151-
{tokens}
152-
</span>
153-
</span>
124+
<span className="flex h-6 items-center text-foreground">Context</span>
125+
{used !== null ? <ContextWindowSegments usage={usage} /> : <span />}
126+
<span className="text-end tabular-nums text-muted-foreground">
127+
{used !== null ? `${Math.round(used)}%` : ""}
154128
</span>
155129
</ThreadDetailsControl>
156130
}
157131
/>
158-
<span className="flex w-11 shrink-0 justify-end">
132+
<span className="flex justify-end">
159133
{onCompact ? (
160-
<ThreadDetailsControl
161-
part="icon"
134+
<Button
135+
size="icon-xs"
136+
variant="secondary"
162137
aria-label="Compact context"
163138
disabled={compactDisabled}
164139
onClick={onCompact}
165140
>
166-
<Minimize2Icon className="size-3.5" />
167-
</ThreadDetailsControl>
141+
<Minimize2Icon className="size-[13px]" />
142+
</Button>
168143
) : null}
169144
</span>
170145
</div>
@@ -249,18 +224,21 @@ function UsageRow({
249224
}) {
250225
return (
251226
<Tooltip>
252-
<div className="flex h-8 items-center gap-2 ps-3 pe-2 text-meta">
227+
<div className={cn(USAGE_ROW_CLASS, "h-8")}>
253228
<TooltipTrigger
254229
render={
255230
<div
256231
tabIndex={0}
257232
aria-label={`${label}: ${ariaValue}`}
258-
className="flex min-w-0 flex-1 cursor-default items-center gap-2 rounded-lg outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
233+
className={cn(
234+
"grid min-w-0 cursor-default grid-cols-subgrid items-center gap-x-2 rounded-lg outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
235+
fill === null ? "col-span-5" : "col-span-4",
236+
)}
259237
/>
260238
}
261239
>
262240
<span className="shrink-0 text-muted-foreground [&>svg]:size-4">{icon}</span>
263-
<span className="w-14.5 shrink-0 truncate">{label}</span>
241+
<span className="truncate">{label}</span>
264242
{fill !== null ? (
265243
<span className="relative h-1 min-w-0 flex-1 rounded-full bg-muted-foreground/20">
266244
{fill > 0 ? (
@@ -284,21 +262,19 @@ function UsageRow({
284262
/>
285263
) : null}
286264
</span>
287-
) : (
288-
<span className="flex-1" />
289-
)}
265+
) : null}
290266
<span
291267
className={cn(
292-
"w-7.5 shrink-0 text-end tabular-nums text-muted-foreground",
293-
fill === null && "w-auto",
268+
"text-end tabular-nums text-muted-foreground",
269+
fill === null && "col-span-3",
294270
tone === "error" && "text-error-foreground",
295271
tone === "warning" && "text-warning-foreground",
296272
)}
297273
>
298274
{value}
299275
</span>
300276
</TooltipTrigger>
301-
<span className="flex w-11 shrink-0 justify-end">{trailing}</span>
277+
{fill !== null ? <span className="flex justify-end">{trailing}</span> : null}
302278
</div>
303279
<TooltipPopup side="left" sideOffset={16}>
304280
<div className="flex flex-col gap-0.5 text-muted-foreground">{tooltip}</div>

0 commit comments

Comments
 (0)