Skip to content

Commit 28a6667

Browse files
committed
🤖 fix: restore VerticalTokenMeter proportional scaling, fix context bar rounding
Regressions fixed: - Restored usagePercentage-based flex scaling in VerticalTokenMeter (bar height reflects context usage) - Fixed context usage bar rounded corners by wrapping segments in overflow-hidden container - Kept slider outside the bar container for proper positioning
1 parent a4d98a1 commit 28a6667

File tree

6 files changed

+104
-88
lines changed

6 files changed

+104
-88
lines changed

‎src/browser/components/AIView.tsx‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ const AIViewInner: React.FC<AIViewProps> = ({
9191
const pendingSendOptions = useSendMessageOptions(workspaceId);
9292
const pendingModel = pendingSendOptions.model;
9393

94-
const { threshold: autoCompactionThreshold } =
95-
useAutoCompactionSettings(workspaceId, pendingModel);
94+
const { threshold: autoCompactionThreshold } = useAutoCompactionSettings(
95+
workspaceId,
96+
pendingModel
97+
);
9698
const handledModelErrorsRef = useRef<Set<string>>(new Set());
9799

98100
useEffect(() => {

‎src/browser/components/RightSidebar.tsx‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,8 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
139139
const model = lastUsage?.model ?? null;
140140

141141
// Auto-compaction settings: threshold per-model
142-
const {
143-
threshold: autoCompactThreshold,
144-
setThreshold: setAutoCompactThreshold,
145-
} = useAutoCompactionSettings(workspaceId, model);
142+
const { threshold: autoCompactThreshold, setThreshold: setAutoCompactThreshold } =
143+
useAutoCompactionSettings(workspaceId, model);
146144

147145
// Memoize vertical meter data calculation to prevent unnecessary re-renders
148146
const verticalMeterData = React.useMemo(() => {

‎src/browser/components/RightSidebar/CostsTab.tsx‎

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,8 @@ const CostsTabComponent: React.FC<CostsTabProps> = ({ workspaceId }) => {
6969
const currentModel = contextUsage?.model ?? null;
7070

7171
// Auto-compaction settings: threshold per-model (100 = disabled)
72-
const {
73-
threshold: autoCompactThreshold,
74-
setThreshold: setAutoCompactThreshold,
75-
} = useAutoCompactionSettings(workspaceId, currentModel);
72+
const { threshold: autoCompactThreshold, setThreshold: setAutoCompactThreshold } =
73+
useAutoCompactionSettings(workspaceId, currentModel);
7674

7775
// Session usage for cost
7876
const sessionUsage = React.useMemo(() => {
@@ -187,56 +185,59 @@ const CostsTabComponent: React.FC<CostsTabProps> = ({ workspaceId }) => {
187185
</span>
188186
</div>
189187
<div className="relative w-full py-2">
190-
{/* Bar container - relative for slider positioning */}
191-
<div className="bg-border-light relative flex h-1.5 w-full overflow-visible rounded-[3px]">
192-
{cachedPercentage > 0 && (
193-
<div
194-
key="cached"
195-
className="h-full transition-[width] duration-300"
196-
style={{
197-
width: `${cachedPercentage}%`,
198-
background: TOKEN_COMPONENT_COLORS.cached,
199-
}}
200-
/>
201-
)}
202-
{cacheCreatePercentage > 0 && (
188+
{/* Bar container - relative for slider positioning, overflow-hidden for rounded corners */}
189+
<div className="bg-border-light relative h-1.5 w-full overflow-hidden rounded-[3px]">
190+
{/* Segments container - flex layout for stacked percentages */}
191+
<div className="flex h-full w-full">
192+
{cachedPercentage > 0 && (
193+
<div
194+
key="cached"
195+
className="h-full transition-[width] duration-300"
196+
style={{
197+
width: `${cachedPercentage}%`,
198+
background: TOKEN_COMPONENT_COLORS.cached,
199+
}}
200+
/>
201+
)}
202+
{cacheCreatePercentage > 0 && (
203+
<div
204+
key="cacheCreate"
205+
className="h-full transition-[width] duration-300"
206+
style={{
207+
width: `${cacheCreatePercentage}%`,
208+
background: TOKEN_COMPONENT_COLORS.cached,
209+
}}
210+
/>
211+
)}
203212
<div
204-
key="cacheCreate"
213+
key="input"
205214
className="h-full transition-[width] duration-300"
206215
style={{
207-
width: `${cacheCreatePercentage}%`,
208-
background: TOKEN_COMPONENT_COLORS.cached,
216+
width: `${inputPercentage}%`,
217+
background: TOKEN_COMPONENT_COLORS.input,
209218
}}
210219
/>
211-
)}
212-
<div
213-
key="input"
214-
className="h-full transition-[width] duration-300"
215-
style={{
216-
width: `${inputPercentage}%`,
217-
background: TOKEN_COMPONENT_COLORS.input,
218-
}}
219-
/>
220-
<div
221-
key="output"
222-
className="h-full transition-[width] duration-300"
223-
style={{
224-
width: `${outputPercentage}%`,
225-
background: TOKEN_COMPONENT_COLORS.output,
226-
}}
227-
/>
228-
{reasoningPercentage > 0 && (
229220
<div
230-
key="reasoning"
221+
key="output"
231222
className="h-full transition-[width] duration-300"
232223
style={{
233-
width: `${reasoningPercentage}%`,
234-
background: TOKEN_COMPONENT_COLORS.thinking,
224+
width: `${outputPercentage}%`,
225+
background: TOKEN_COMPONENT_COLORS.output,
235226
}}
236227
/>
237-
)}
228+
{reasoningPercentage > 0 && (
229+
<div
230+
key="reasoning"
231+
className="h-full transition-[width] duration-300"
232+
style={{
233+
width: `${reasoningPercentage}%`,
234+
background: TOKEN_COMPONENT_COLORS.thinking,
235+
}}
236+
/>
237+
)}
238+
</div>
238239
</div>
239-
{/* Threshold slider overlay */}
240+
{/* Threshold slider overlay - positioned relative to outer container */}
240241
{maxTokens && (
241242
<HorizontalThresholdSlider
242243
key="slider"

‎src/browser/components/RightSidebar/ThresholdSlider.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ export const HorizontalThresholdSlider: React.FC<HorizontalThresholdSliderProps>
7373
};
7474

7575
const applyThreshold = (pct: number) => {
76-
config.setThreshold(pct >= DISABLE_THRESHOLD ? 100 : Math.min(pct, AUTO_COMPACTION_THRESHOLD_MAX));
76+
config.setThreshold(
77+
pct >= DISABLE_THRESHOLD ? 100 : Math.min(pct, AUTO_COMPACTION_THRESHOLD_MAX)
78+
);
7779
};
7880

7981
applyThreshold(calcPercent(e.clientX));

‎src/browser/components/RightSidebar/VerticalTokenMeter.tsx‎

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ interface VerticalTokenMeterProps {
1717
const VerticalTokenMeterComponent: React.FC<VerticalTokenMeterProps> = ({ data }) => {
1818
if (data.segments.length === 0) return null;
1919

20+
// Scale the bar based on context window usage (0-100%)
21+
const usagePercentage = data.maxTokens ? data.totalPercentage : 100;
22+
2023
return (
2124
<div
2225
className="bg-separator border-border-light flex h-full w-5 flex-col items-center border-l py-3"
@@ -32,43 +35,55 @@ const VerticalTokenMeterComponent: React.FC<VerticalTokenMeterProps> = ({ data }
3235
</div>
3336
)}
3437

35-
{/* The bar with tooltip */}
36-
<div className="flex w-full flex-1 flex-col items-center px-[6px]">
37-
<TooltipWrapper>
38-
<TokenMeter
39-
segments={data.segments}
40-
orientation="vertical"
41-
data-meter="token-bar"
42-
data-segment-count={data.segments.length}
43-
/>
44-
<Tooltip>
45-
<div className="font-primary flex flex-col gap-2 text-xs">
46-
<div className="text-foreground text-[13px] font-semibold">Last Request</div>
47-
<div className="border-border-light my-1 border-t" />
48-
{data.segments.map((seg, i) => (
49-
<div key={i} className="flex justify-between gap-4">
50-
<div className="flex items-center gap-1.5">
51-
<div
52-
className="h-2 w-2 shrink-0 rounded-full"
53-
style={{ background: seg.color }}
54-
/>
55-
<span>{getSegmentLabel(seg.type)}</span>
38+
{/* Bar container - flex to scale bar proportionally to usage */}
39+
<div className="flex min-h-0 w-full flex-1 flex-col items-center">
40+
{/* Used portion - grows based on usage percentage */}
41+
<div
42+
className="flex min-h-[20px] w-full flex-col items-center px-[6px]"
43+
style={{ flex: usagePercentage }}
44+
>
45+
<div className="flex flex-1 flex-col">
46+
<TooltipWrapper>
47+
<TokenMeter
48+
segments={data.segments}
49+
orientation="vertical"
50+
data-meter="token-bar"
51+
data-segment-count={data.segments.length}
52+
/>
53+
<Tooltip>
54+
<div className="font-primary flex flex-col gap-2 text-xs">
55+
<div className="text-foreground text-[13px] font-semibold">Last Request</div>
56+
<div className="border-border-light my-1 border-t" />
57+
{data.segments.map((seg, i) => (
58+
<div key={i} className="flex justify-between gap-4">
59+
<div className="flex items-center gap-1.5">
60+
<div
61+
className="h-2 w-2 shrink-0 rounded-full"
62+
style={{ background: seg.color }}
63+
/>
64+
<span>{getSegmentLabel(seg.type)}</span>
65+
</div>
66+
<span className="text-foreground font-medium">
67+
{formatTokens(seg.tokens)}
68+
</span>
69+
</div>
70+
))}
71+
<div className="border-border-light my-1 border-t" />
72+
<div className="text-muted text-[11px]">
73+
Total: {formatTokens(data.totalTokens)}
74+
{data.maxTokens && ` / ${formatTokens(data.maxTokens)}`}
75+
{data.maxTokens && ` (${data.totalPercentage.toFixed(1)}%)`}
76+
</div>
77+
<div className="text-dim mt-2 text-[10px] italic">
78+
💡 Expand your viewport to see full details
5679
</div>
57-
<span className="text-foreground font-medium">{formatTokens(seg.tokens)}</span>
5880
</div>
59-
))}
60-
<div className="border-border-light my-1 border-t" />
61-
<div className="text-muted text-[11px]">
62-
Total: {formatTokens(data.totalTokens)}
63-
{data.maxTokens && ` / ${formatTokens(data.maxTokens)}`}
64-
{data.maxTokens && ` (${data.totalPercentage.toFixed(1)}%)`}
65-
</div>
66-
<div className="text-dim mt-2 text-[10px] italic">
67-
💡 Expand your viewport to see full details
68-
</div>
69-
</div>
70-
</Tooltip>
71-
</TooltipWrapper>
81+
</Tooltip>
82+
</TooltipWrapper>
83+
</div>
84+
</div>
85+
{/* Empty portion - takes remaining space */}
86+
<div className="w-full" style={{ flex: Math.max(0, 100 - usagePercentage) }} />
7287
</div>
7388
</div>
7489
);

‎src/browser/hooks/useAutoCompactionSettings.ts‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { usePersistedState } from "@/browser/hooks/usePersistedState";
2-
import {
3-
getAutoCompactionThresholdKey,
4-
} from "@/common/constants/storage";
2+
import { getAutoCompactionThresholdKey } from "@/common/constants/storage";
53
import { DEFAULT_AUTO_COMPACTION_THRESHOLD_PERCENT } from "@/common/constants/ui";
64

75
export interface AutoCompactionSettings {

0 commit comments

Comments
 (0)