From e899e4e012174f6c0a7c1c6f24bd40968936c48e Mon Sep 17 00:00:00 2001 From: liuxuezhuo Date: Tue, 29 Sep 2026 23:53:45 +0800 Subject: [PATCH] feat(context): draw the usage meter as a full ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The meter beside the composer swept a 240° arc from the upper-left around the bottom to the upper-right, so the gap at the top read as a broken circle and the same percentage covered less visual ground than a ring would. The gauge is now a complete circle that fills clockwise from 12 o'clock, drawn with two elements instead of an arc path. Only the shape changes. The percentage label, the hover tooltip with the token counts, and the pale-red warning state above 80% behave as before, and the existing dash-offset maths carries over since the fill length is still a fraction of the stroke's total length. Co-authored-by: QoderAI (Qwen 3.8 Max) --- CHANGELOG.md | 6 ++++++ src/features/chat/ui/input-toolbar.ts | 31 ++++++++++----------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74acf14..5044e1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ version with its date and start a fresh empty `[Unreleased]` above it. ## [Unreleased] +### Changed + +- The context usage meter beside the composer is now a complete ring that fills + clockwise from the top, replacing the 240° arc. The percentage, the hover + tooltip, and the pale-red warning state above 80% are unchanged. + ## [1.0.16] - 2026-09-29 ### Changed diff --git a/src/features/chat/ui/input-toolbar.ts b/src/features/chat/ui/input-toolbar.ts index abd51e4..79b3c67 100644 --- a/src/features/chat/ui/input-toolbar.ts +++ b/src/features/chat/ui/input-toolbar.ts @@ -681,7 +681,7 @@ export class McpServerSelector { export class ContextUsageMeter { private container: HTMLElement; - private fillPath: SVGPathElement | null = null; + private fillPath: SVGCircleElement | null = null; private percentEl: HTMLElement | null = null; private circumference: number = 0; @@ -703,19 +703,7 @@ export class ContextUsageMeter { const cx = size / 2; const cy = size / 2; - // 240° arc: from 150° to 390° (upper-left through bottom to upper-right) - const startAngle = 150; - const endAngle = 390; - const arcDegrees = endAngle - startAngle; - const arcRadians = (arcDegrees * Math.PI) / 180; - this.circumference = radius * arcRadians; - - const startRad = (startAngle * Math.PI) / 180; - const endRad = (endAngle * Math.PI) / 180; - const x1 = cx + radius * Math.cos(startRad); - const y1 = cy + radius * Math.sin(startRad); - const x2 = cx + radius * Math.cos(endRad); - const y2 = cy + radius * Math.sin(endRad); + this.circumference = 2 * Math.PI * radius; const gaugeEl = this.container.createDiv({ cls: 'qoderian-context-meter-gauge' }); const svg = gaugeEl.createSvg('svg', { @@ -726,26 +714,29 @@ export class ContextUsageMeter { }, }); - const pathData = `M ${x1} ${y1} A ${radius} ${radius} 0 1 1 ${x2} ${y2}`; - svg.createSvg('path', { + svg.createSvg('circle', { cls: 'qoderian-meter-bg', attr: { - d: pathData, + cx: String(cx), + cy: String(cy), + r: String(radius), fill: 'none', 'stroke-width': String(strokeWidth), - 'stroke-linecap': 'round', }, }); - const fillPath = svg.createSvg('path', { + const fillPath = svg.createSvg('circle', { cls: 'qoderian-meter-fill', attr: { - d: pathData, + cx: String(cx), + cy: String(cy), + r: String(radius), fill: 'none', 'stroke-width': String(strokeWidth), 'stroke-linecap': 'round', 'stroke-dasharray': String(this.circumference), 'stroke-dashoffset': String(this.circumference), + transform: `rotate(-90 ${cx} ${cy})`, }, }); this.fillPath = fillPath;