Skip to content

Commit 3443750

Browse files
cursoragentaisrv0762
andcommitted
Refactor: Improve chart styling and theme support
This commit enhances the visual appearance of charts by introducing new color palettes and gradients. It also adds support for the user's preferred color scheme (light/dark mode) by dynamically adjusting chart colors and backgrounds. Additionally, several UI elements have been updated with rounded corners and improved styling for a more modern look. Co-authored-by: aisrv0762 <[email protected]>
1 parent 1e147d7 commit 3443750

File tree

2 files changed

+196
-63
lines changed

2 files changed

+196
-63
lines changed

web/runtime-dashboard/src/main.ts

Lines changed: 145 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ const charts: echarts.ECharts[] = [];
8383
const trafficChart = initChart("trafficChart");
8484
const requestChart = initChart("requestChart");
8585
const diskChart = initChart("diskChart");
86+
const colorSchemeMedia = window.matchMedia("(prefers-color-scheme: light)");
8687

8788
setHistoryWindow(historyMinutes);
8889

@@ -105,6 +106,13 @@ window.addEventListener("resize", () => {
105106
charts.forEach((chart) => chart.resize());
106107
});
107108

109+
colorSchemeMedia.addEventListener("change", () => {
110+
charts.forEach((chart) => chart.resize());
111+
if (lastContext) {
112+
renderFromCache();
113+
}
114+
});
115+
108116
function initChart(elementId: string): echarts.ECharts {
109117
const el = document.getElementById(elementId) as HTMLDivElement | null;
110118
if (!el) {
@@ -252,43 +260,75 @@ function updateTrafficChart() {
252260

253261
const ingressSeries = trafficHistory.map((p) => [p.time, p.ingress]);
254262
const egressSeries = trafficHistory.map((p) => [p.time, p.egress]);
263+
const palette = getChartPalette();
255264

256265
const option: echarts.EChartsOption = {
266+
backgroundColor: "transparent",
267+
textStyle: { color: palette.text },
257268
color: ["#4ade80", "#60a5fa"],
258269
tooltip: {
259270
trigger: "axis",
260271
axisPointer: { type: "cross" },
272+
backgroundColor: palette.tooltipBg,
273+
borderColor: palette.tooltipBg,
274+
textStyle: { color: palette.tooltipText },
261275
valueFormatter: (value) => (value ? formatBytesPerSecond(Number(value)) : "--")
262276
},
263277
legend: {
264278
data: ["Ingress", "Egress"],
265-
top: 0
279+
top: 0,
280+
textStyle: { color: palette.muted }
281+
},
282+
grid: { left: 48, right: 24, top: 40, bottom: 70 },
283+
xAxis: {
284+
type: "time",
285+
boundaryGap: false,
286+
axisLabel: { color: palette.muted },
287+
axisLine: { lineStyle: { color: palette.axis } },
288+
splitLine: { show: true, lineStyle: { color: palette.splitLine } }
266289
},
267-
grid: { left: 40, right: 20, top: 30, bottom: 40 },
268-
xAxis: { type: "time", boundaryGap: false },
269290
yAxis: {
270291
type: "value",
271292
axisLabel: {
293+
color: palette.muted,
272294
formatter: (val: number) => formatBytesPerSecond(val as number)
273-
}
295+
},
296+
axisLine: { lineStyle: { color: palette.axis } },
297+
splitLine: { lineStyle: { color: palette.splitLine } }
274298
},
275299
dataZoom: [
276300
{ type: "inside", realtime: true },
277-
{ type: "slider", height: 12, bottom: 0 }
301+
{
302+
type: "slider",
303+
height: 14,
304+
bottom: 12,
305+
borderColor: "transparent",
306+
backgroundColor: "rgba(255,255,255,0.08)",
307+
handleIcon:
308+
"M8.2,13.3V86.7h2.6V13.3H8.2z M41.6,13.3V86.7h2.6V13.3H41.6z",
309+
handleSize: "80%"
310+
}
278311
],
279-
series: [
280312
{
281313
name: "Ingress",
282314
type: "line",
283315
smooth: true,
284316
showSymbol: false,
317+
lineStyle: { width: 2 },
318+
areaStyle: {
319+
color: createAreaGradient("rgba(74, 222, 128, 0.45)", "rgba(74, 222, 128, 0.05)")
320+
},
285321
data: ingressSeries
286322
},
287323
{
288324
name: "Egress",
289325
type: "line",
290326
smooth: true,
291327
showSymbol: false,
328+
lineStyle: { width: 2 },
329+
areaStyle: {
330+
color: createAreaGradient("rgba(96, 165, 250, 0.4)", "rgba(96, 165, 250, 0.05)")
331+
},
292332
data: egressSeries
293333
}
294334
]
@@ -312,40 +352,72 @@ function updateRequestChart() {
312352

313353
const grpcSeries = requestHistory.map((p) => [p.time, p.grpc]);
314354
const urpcSeries = requestHistory.map((p) => [p.time, p.urpc]);
355+
const palette = getChartPalette();
315356

316357
const option: echarts.EChartsOption = {
358+
backgroundColor: "transparent",
359+
textStyle: { color: palette.text },
317360
color: ["#f472b6", "#fbbf24"],
318361
tooltip: {
319362
trigger: "axis",
320363
axisPointer: { type: "cross" },
364+
backgroundColor: palette.tooltipBg,
365+
borderColor: palette.tooltipBg,
366+
textStyle: { color: palette.tooltipText },
321367
valueFormatter: (value) => (value ? formatReqPerSecond(Number(value)) : "--")
322368
},
323-
legend: { data: ["gRPC", "uRPC"], top: 0 },
324-
grid: { left: 40, right: 20, top: 30, bottom: 40 },
325-
xAxis: { type: "time", boundaryGap: false },
369+
legend: { data: ["gRPC", "uRPC"], top: 0, textStyle: { color: palette.muted } },
370+
grid: { left: 48, right: 24, top: 40, bottom: 70 },
371+
xAxis: {
372+
type: "time",
373+
boundaryGap: false,
374+
axisLabel: { color: palette.muted },
375+
axisLine: { lineStyle: { color: palette.axis } },
376+
splitLine: { show: true, lineStyle: { color: palette.splitLine } }
377+
},
326378
yAxis: {
327379
type: "value",
328380
axisLabel: {
381+
color: palette.muted,
329382
formatter: (val: number) => formatReqPerSecond(val as number)
330-
}
383+
},
384+
axisLine: { lineStyle: { color: palette.axis } },
385+
splitLine: { lineStyle: { color: palette.splitLine } }
331386
},
332387
dataZoom: [
333388
{ type: "inside", realtime: true },
334-
{ type: "slider", height: 12, bottom: 0 }
389+
{
390+
type: "slider",
391+
height: 14,
392+
bottom: 12,
393+
borderColor: "transparent",
394+
backgroundColor: "rgba(255,255,255,0.08)",
395+
handleIcon:
396+
"M8.2,13.3V86.7h2.6V13.3H8.2z M41.6,13.3V86.7h2.6V13.3H41.6z",
397+
handleSize: "80%"
398+
}
335399
],
336400
series: [
337401
{
338402
name: "gRPC",
339403
type: "line",
340404
smooth: true,
341405
showSymbol: false,
406+
lineStyle: { width: 2 },
407+
areaStyle: {
408+
color: createAreaGradient("rgba(244, 114, 182, 0.35)", "rgba(244, 114, 182, 0.05)")
409+
},
342410
data: grpcSeries
343411
},
344412
{
345413
name: "uRPC",
346414
type: "line",
347415
smooth: true,
348416
showSymbol: false,
417+
lineStyle: { width: 2 },
418+
areaStyle: {
419+
color: createAreaGradient("rgba(251, 191, 36, 0.35)", "rgba(251, 191, 36, 0.05)")
420+
},
349421
data: urpcSeries
350422
}
351423
]
@@ -378,18 +450,32 @@ function renderDiskChart() {
378450
return;
379451
}
380452

381-
const series = Array.from(diskSeriesHistory.entries()).map(([root, data]) => ({
453+
const palette = getChartPalette();
454+
const series = Array.from(diskSeriesHistory.entries()).map(([root, data], index) => ({
382455
name: root,
383456
type: "line",
384457
smooth: true,
385458
showSymbol: false,
459+
lineStyle: { width: 2 },
460+
areaStyle: {
461+
opacity: 0.2,
462+
color: createAreaGradient(
463+
`rgba(96, 109, 255, ${0.35 - index * 0.03})`,
464+
"rgba(96, 109, 255, 0.02)"
465+
)
466+
},
386467
data
387468
}));
388469

389470
const option: echarts.EChartsOption = {
471+
backgroundColor: "transparent",
472+
textStyle: { color: palette.text },
390473
tooltip: {
391474
trigger: "axis",
392475
axisPointer: { type: "cross" },
476+
backgroundColor: palette.tooltipBg,
477+
borderColor: palette.tooltipBg,
478+
textStyle: { color: palette.tooltipText },
393479
formatter: (params: any) => {
394480
if (!Array.isArray(params) || !params.length) {
395481
return "";
@@ -410,21 +496,40 @@ function renderDiskChart() {
410496
},
411497
legend: {
412498
type: "scroll",
413-
top: 0
499+
top: 0,
500+
textStyle: { color: palette.muted }
501+
},
502+
grid: { left: 48, right: 24, top: 40, bottom: 70 },
503+
xAxis: {
504+
type: "time",
505+
boundaryGap: false,
506+
axisLabel: { color: palette.muted },
507+
axisLine: { lineStyle: { color: palette.axis } },
508+
splitLine: { show: true, lineStyle: { color: palette.splitLine } }
414509
},
415-
grid: { left: 40, right: 20, top: 30, bottom: 40 },
416-
xAxis: { type: "time", boundaryGap: false },
417510
yAxis: {
418511
type: "value",
419512
min: 0,
420513
max: 100,
421514
axisLabel: {
515+
color: palette.muted,
422516
formatter: (val: number) => `${val}%`
423-
}
517+
},
518+
axisLine: { lineStyle: { color: palette.axis } },
519+
splitLine: { lineStyle: { color: palette.splitLine } }
424520
},
425521
dataZoom: [
426522
{ type: "inside", realtime: true },
427-
{ type: "slider", height: 12, bottom: 0 }
523+
{
524+
type: "slider",
525+
height: 14,
526+
bottom: 12,
527+
borderColor: "transparent",
528+
backgroundColor: "rgba(255,255,255,0.08)",
529+
handleIcon:
530+
"M8.2,13.3V86.7h2.6V13.3H8.2z M41.6,13.3V86.7h2.6V13.3H41.6z",
531+
handleSize: "80%"
532+
}
428533
],
429534
series
430535
};
@@ -884,9 +989,12 @@ function formatReqPerSecond(value: number): string {
884989
}
885990

886991
function formatBytes(value: number | null): string {
887-
if (!Number.isFinite(value as number) || (value as number) <= 0) {
992+
if (!Number.isFinite(value as number) || value == null) {
888993
return "--";
889994
}
995+
if (value === 0) {
996+
return "0 B";
997+
}
890998
const units = ["B", "KiB", "MiB", "GiB", "TiB"];
891999
let idx = 0;
8921000
let val = value as number;
@@ -938,3 +1046,22 @@ function formatDuration(ms: number): string {
9381046
}
9391047
return `${seconds}s`;
9401048
}
1049+
1050+
function getChartPalette() {
1051+
const text = getCssVar("--text-primary", "#f8fafc");
1052+
const muted = getCssVar("--text-muted", "#94a3b8");
1053+
const axis = muted || "#94a3b8";
1054+
const splitLine = colorSchemeMedia.matches
1055+
? "rgba(21, 25, 51, 0.12)"
1056+
: "rgba(148, 163, 184, 0.2)";
1057+
const tooltipBg = colorSchemeMedia.matches ? "rgba(255,255,255,0.96)" : "rgba(15,23,42,0.95)";
1058+
const tooltipText = colorSchemeMedia.matches ? "#151933" : "#f8fafc";
1059+
return { text, muted, axis, splitLine, tooltipBg, tooltipText };
1060+
}
1061+
1062+
function createAreaGradient(topColor: string, bottomColor: string) {
1063+
return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
1064+
{ offset: 0, color: topColor },
1065+
{ offset: 1, color: bottomColor }
1066+
]);
1067+
}

0 commit comments

Comments
 (0)