From 9af1fa1d422ac8252d92c4a1e8b7c031fcba94a8 Mon Sep 17 00:00:00 2001 From: ZingerLittleBee <6970999@gmail.com> Date: Wed, 27 May 2026 23:52:47 +0800 Subject: [PATCH 01/18] refactor(web): polish gauge widget visuals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - move 270° gap to the bottom (speedometer-style horseshoe) - fill the card by enlarging the ring radius and dropping end-cap balls - lock the visible card to a 1:1 aspect via container-size queries so it stays square inside non-square grid cells - add internal padding between the ring and the card border - move the server name into the bottom arc gap --- .../components/dashboard/dashboard-grid.tsx | 2 - .../components/dashboard/widgets/gauge.tsx | 153 ++++++++++-------- ...2026-05-27-gauge-widget-redesign-design.md | 4 +- 3 files changed, 87 insertions(+), 72 deletions(-) diff --git a/apps/web/src/components/dashboard/dashboard-grid.tsx b/apps/web/src/components/dashboard/dashboard-grid.tsx index efd545b6..391fc1fc 100644 --- a/apps/web/src/components/dashboard/dashboard-grid.tsx +++ b/apps/web/src/components/dashboard/dashboard-grid.tsx @@ -265,8 +265,6 @@ export function DashboardGrid({ h: autoIdSet.has(item.i) ? item.h : Math.max(SCALE, Math.round(item.h / SCALE) * SCALE) } if (squareIdSet.has(item.i)) { - // Lock height to width (in fine units, h = w * SCALE) so the gauge - // stays a coarse-unit square no matter which dimension the user drags. base.h = base.w * SCALE } return base diff --git a/apps/web/src/components/dashboard/widgets/gauge.tsx b/apps/web/src/components/dashboard/widgets/gauge.tsx index e6282097..e0838c06 100644 --- a/apps/web/src/components/dashboard/widgets/gauge.tsx +++ b/apps/web/src/components/dashboard/widgets/gauge.tsx @@ -12,12 +12,14 @@ interface GaugeWidgetProps { // SVG geometry constants (viewBox is 100x100) const VIEWBOX = 100 const CENTER = VIEWBOX / 2 -const RADIUS = 38 +// Radius pushes the ring close to the viewBox edge so the gauge fills the +// card; clamped so the round linecap (STROKE/2 outward) still fits inside. +const RADIUS = 44 const STROKE = 8 -const BALL_R = 5.5 -const BALL_R_INNER = 2 -// 270° sweep, gap centered at top. Angles in degrees, clockwise from 12 o'clock. -const START_ANGLE = 135 +// 270° sweep, gap centered at bottom. Angles in degrees, clockwise from 12 o'clock. +// Start at 7:30 (225°), sweep clockwise past 9, 12, 3 to 4:30 (135°), leaving a +// 90° gap centered at 6 o'clock — matches the reference horseshoe orientation. +const START_ANGLE = 225 const SWEEP = 270 interface Gradient { @@ -109,79 +111,94 @@ export function GaugeWidget({ config, servers }: GaugeWidgetProps) { const trackPathD = arcPath(CENTER, CENTER, RADIUS, START_ANGLE, trackEnd) const progressPathD = arcPath(CENTER, CENTER, RADIUS, START_ANGLE, progressEnd) - const startCap = polarToCartesian(CENTER, CENTER, RADIUS, START_ANGLE) - const endCap = polarToCartesian(CENTER, CENTER, RADIUS, progressEnd) const showProgress = value > 0 - return ( -