feat(dees-statsgrid): add cpuCores tile type with column spanning, rendering, demo and docs

This commit is contained in:
2026-01-12 18:00:16 +00:00
parent b478ae3071
commit e981ddf2d6
8 changed files with 2083 additions and 156 deletions

View File

@@ -24,12 +24,21 @@ declare global {
}
}
export interface ICpuCore {
id: string | number;
usage: number; // 0-100
label?: string;
}
export interface IStatsTile {
id: string;
title: string;
value: number | string;
unit?: string;
type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text' | 'multiPercentage';
type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text' | 'multiPercentage' | 'cpuCores';
// Layout options
columnSpan?: number; // Number of columns to span (default: 1)
// For gauge type
gaugeOptions?: {
@@ -48,6 +57,9 @@ export interface IStatsTile {
color?: string;
}>;
// For cpuCores type
coresData?: ICpuCore[];
// Visual customization
color?: string;
icon?: string;
@@ -366,6 +378,107 @@ export class DeesStatsGrid extends DeesElement {
border-radius: 2px;
}
/* CPU Cores Styles */
.cpu-cores-wrapper {
width: 100%;
display: flex;
flex-direction: column;
flex: 1;
min-height: 80px;
}
.cpu-cores-header {
display: flex;
align-items: baseline;
gap: 8px;
margin-bottom: 12px;
}
.cpu-cores-value {
font-size: var(--value-font-size);
font-weight: 600;
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
line-height: 1.1;
letter-spacing: -0.025em;
}
.cpu-cores-unit {
font-size: var(--unit-font-size);
font-weight: 400;
color: ${cssManager.bdTheme('hsl(215.4 16.3% 46.9%)', 'hsl(215 20.2% 65.1%)')};
letter-spacing: -0.01em;
}
.cpu-cores-label {
font-size: var(--label-font-size);
font-weight: 500;
color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
letter-spacing: -0.01em;
margin-left: auto;
}
.cpu-cores-bars {
display: flex;
align-items: flex-end;
gap: 3px;
flex: 1;
min-height: 60px;
padding: 4px 0;
}
.cpu-core-bar-container {
flex: 1;
min-width: 6px;
max-width: 24px;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.cpu-core-bar-wrapper {
flex: 1;
width: 100%;
background: ${cssManager.bdTheme('#e8e8e8', '#1a1a1a')};
border-radius: 2px;
display: flex;
flex-direction: column;
justify-content: flex-end;
overflow: hidden;
min-height: 40px;
}
.cpu-core-bar-fill {
width: 100%;
background: ${cssManager.bdTheme('#666666', '#888888')};
transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.3s ease;
border-radius: 2px 2px 0 0;
}
.cpu-core-bar-fill.low {
background: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3%)', 'hsl(142.1 70.6% 45.3%)')};
}
.cpu-core-bar-fill.medium {
background: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')};
}
.cpu-core-bar-fill.high {
background: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 84.2% 60.2%)')};
}
.cpu-core-label {
font-size: 9px;
font-weight: 500;
color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
/* Trend Styles */
.trend-container {
width: 100%;
@@ -488,10 +601,12 @@ export class DeesStatsGrid extends DeesElement {
private renderTile(tile: IStatsTile): TemplateResult {
const hasActions = tile.actions && tile.actions.length > 0;
const clickable = hasActions && tile.actions.length === 1;
const columnSpan = tile.columnSpan && tile.columnSpan > 1 ? tile.columnSpan : undefined;
return html`
<div
<div
class="stats-tile ${clickable ? 'clickable' : ''}"
style="${columnSpan ? `grid-column: span ${columnSpan}` : ''}"
@click=${clickable ? () => this.handleTileAction(tile.actions![0], tile) : undefined}
@contextmenu=${hasActions ? (e: MouseEvent) => this.showContextMenu(e, tile) : undefined}
>
@@ -535,6 +650,9 @@ export class DeesStatsGrid extends DeesElement {
case 'multiPercentage':
return this.renderMultiPercentage(tile);
case 'cpuCores':
return this.renderCpuCores(tile);
case 'text':
return html`
<div class="text-value" style="${tile.color ? `color: ${tile.color}` : ''}">
@@ -699,6 +817,51 @@ export class DeesStatsGrid extends DeesElement {
`;
}
private renderCpuCores(tile: IStatsTile): TemplateResult {
if (!tile.coresData || tile.coresData.length === 0) {
return html`<div class="tile-value">${tile.value}</div>`;
}
const cores = tile.coresData;
const avgUsage = Math.round(cores.reduce((sum, core) => sum + core.usage, 0) / cores.length);
// Determine color class based on usage
const getColorClass = (usage: number): string => {
if (usage < 50) return 'low';
if (usage < 80) return 'medium';
return 'high';
};
return html`
<div class="cpu-cores-wrapper">
<div class="cpu-cores-header">
<span class="cpu-cores-value">${avgUsage}</span>
<span class="cpu-cores-unit">%</span>
<span class="cpu-cores-label">${cores.length} cores</span>
</div>
<div class="cpu-cores-bars">
${cores.map(core => {
const usage = Math.min(100, Math.max(0, core.usage));
const colorClass = getColorClass(usage);
return html`
<div class="cpu-core-bar-container" title="Core ${core.label || core.id}: ${usage}%">
<div class="cpu-core-bar-wrapper">
<div
class="cpu-core-bar-fill ${colorClass}"
style="height: ${usage}%"
></div>
</div>
${cores.length <= 16 ? html`
<span class="cpu-core-label">${core.label || core.id}</span>
` : ''}
</div>
`;
})}
</div>
</div>
`;
}
private async handleGridAction(action: plugins.tsclass.website.IMenuItem) {
if (action.action) {
await action.action();