Compare commits

...

3 Commits

Author SHA1 Message Date
496084f870 v3.33.0
Some checks failed
Default (tags) / security (push) Failing after 17s
Default (tags) / test (push) Failing after 12s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-01-06 00:45:10 +00:00
c7bff04ae5 feat(dees-statsgrid): add multiPercentage tile type to stats grid 2026-01-06 00:45:10 +00:00
e71efd409b update 2026-01-05 12:07:05 +00:00
6 changed files with 202 additions and 39 deletions

View File

@@ -1,5 +1,14 @@
# Changelog # Changelog
## 2026-01-06 - 3.33.0 - feat(dees-statsgrid)
add multiPercentage tile type to stats grid
- Add new 'multiPercentage' type to IStatsTile (percentages: [{label, value, color?}])
- Implement renderMultiPercentage() to render up to 3 percentage items with label, value and colored progress bars
- Add CSS styles for multi-percentage layout, bars, labels and values
- Update demo to replace 'Error Rate' tile with a 'Resource Usage' multiPercentage example (CPU, Memory, Disk)
- Change is additive and backward-compatible with existing tile types
## 2026-01-04 - 3.32.0 - feat(demo) ## 2026-01-04 - 3.32.0 - feat(demo)
add demoGroup metadata to components and update related dependencies add demoGroup metadata to components and update related dependencies

View File

@@ -1,6 +1,6 @@
{ {
"name": "@design.estate/dees-catalog", "name": "@design.estate/dees-catalog",
"version": "3.32.0", "version": "3.33.0",
"private": false, "private": false,
"description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.", "description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
"main": "dist_ts_web/index.js", "main": "dist_ts_web/index.js",

View File

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@design.estate/dees-catalog', name: '@design.estate/dees-catalog',
version: '3.32.0', version: '3.33.0',
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.' description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
} }

View File

@@ -3,6 +3,8 @@ import type { DeesAppui } from './dees-appui.js';
import type { IAppConfig, IViewActivationContext } from '../../interfaces/appconfig.js'; import type { IAppConfig, IViewActivationContext } from '../../interfaces/appconfig.js';
import type * as interfaces from '../../interfaces/index.js'; import type * as interfaces from '../../interfaces/index.js';
import '@design.estate/dees-wcctools/demotools'; import '@design.estate/dees-wcctools/demotools';
import '../../dees-statsgrid/dees-statsgrid.js';
import type { IStatsTile } from '../../dees-statsgrid/dees-statsgrid.js';
// Demo view component with lifecycle hooks // Demo view component with lifecycle hooks
@customElement('demo-dashboard-view') @customElement('demo-dashboard-view')
@@ -12,6 +14,79 @@ class DemoDashboardView extends DeesElement {
private ctx: IViewActivationContext; private ctx: IViewActivationContext;
private statsTiles: IStatsTile[] = [
{
id: 'users',
title: 'Active Users',
value: 1234,
type: 'number',
icon: 'lucide:users',
description: 'Online now',
color: '#22c55e'
},
{
id: 'api-calls',
title: 'API Calls',
value: 45200,
type: 'trend',
icon: 'lucide:activity',
description: '+12% from last hour',
color: '#3b82f6',
trendData: [32000, 35000, 38000, 41000, 39000, 42000, 45200]
},
{
id: 'health',
title: 'System Health',
value: 99.9,
unit: '%',
type: 'gauge',
icon: 'lucide:heart-pulse',
description: 'All systems operational',
color: '#10b981',
gaugeOptions: {
min: 0,
max: 100,
thresholds: [
{ value: 80, color: '#ef4444' },
{ value: 95, color: '#f59e0b' },
{ value: 100, color: '#10b981' }
]
}
},
{
id: 'response',
title: 'Avg Response',
value: 127,
unit: 'ms',
type: 'number',
icon: 'lucide:timer',
description: '-15ms from yesterday',
color: '#8b5cf6'
},
{
id: 'resources',
title: 'Resource Usage',
value: '',
type: 'multiPercentage',
icon: 'lucide:server',
percentages: [
{ label: 'CPU', value: 67, color: '#3b82f6' },
{ label: 'Memory', value: 84, color: '#8b5cf6' },
{ label: 'Disk', value: 45, color: '#10b981' }
]
},
{
id: 'requests',
title: 'Requests/sec',
value: 1850,
type: 'trend',
icon: 'lucide:zap',
description: 'Current throughput',
color: '#06b6d4',
trendData: [1200, 1400, 1350, 1600, 1750, 1680, 1850]
}
];
onActivate(context: IViewActivationContext) { onActivate(context: IViewActivationContext) {
this.ctx = context; this.ctx = context;
this.activated = true; this.activated = true;
@@ -83,21 +158,9 @@ class DemoDashboardView extends DeesElement {
} }
h1 { color: #fafafa; font-weight: 600; font-size: 24px; margin-bottom: 8px; } h1 { color: #fafafa; font-weight: 600; font-size: 24px; margin-bottom: 8px; }
p { color: #737373; margin-bottom: 32px; } p { color: #737373; margin-bottom: 32px; }
.grid { dees-statsgrid {
display: grid; margin-bottom: 32px;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
} }
.card {
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 8px;
padding: 20px;
}
.card h3 { color: #fafafa; font-size: 14px; font-weight: 600; margin-bottom: 8px; }
.metric { font-size: 32px; font-weight: 700; color: #fafafa; }
.status { display: inline-block; padding: 2px 8px; border-radius: 9px; font-size: 12px; }
.status.active { background: #14532d; color: #4ade80; }
.ctx-actions { .ctx-actions {
margin-top: 32px; margin-top: 32px;
@@ -147,23 +210,10 @@ class DemoDashboardView extends DeesElement {
</style> </style>
<h1>Dashboard</h1> <h1>Dashboard</h1>
<p>Welcome back! Here's an overview of your system.</p> <p>Welcome back! Here's an overview of your system.</p>
<div class="grid"> <dees-statsgrid
<div class="card"> .tiles=${this.statsTiles}
<h3>Active Users</h3> @tile-action=${(e: CustomEvent) => console.log('Tile action:', e.detail)}
<div class="metric">1,234</div> ></dees-statsgrid>
<span class="status active">Online</span>
</div>
<div class="card">
<h3>API Calls</h3>
<div class="metric">45.2K</div>
<p style="color: #4ade80; font-size: 12px; margin: 0;">+12% from last hour</p>
</div>
<div class="card">
<h3>System Health</h3>
<div class="metric">99.9%</div>
<p style="color: #737373; font-size: 12px; margin: 0;">All systems operational</p>
</div>
</div>
<div class="ctx-actions"> <div class="ctx-actions">
<h2>Context Actions (ctx.appui)</h2> <h2>Context Actions (ctx.appui)</h2>

View File

@@ -29,23 +29,30 @@ export interface IStatsTile {
title: string; title: string;
value: number | string; value: number | string;
unit?: string; unit?: string;
type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text'; type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text' | 'multiPercentage';
// For gauge type // For gauge type
gaugeOptions?: { gaugeOptions?: {
min: number; min: number;
max: number; max: number;
thresholds?: Array<{value: number; color: string}>; thresholds?: Array<{value: number; color: string}>;
}; };
// For trend type // For trend type
trendData?: number[]; trendData?: number[];
// For multiPercentage type
percentages?: Array<{
label: string;
value: number;
color?: string;
}>;
// Visual customization // Visual customization
color?: string; color?: string;
icon?: string; icon?: string;
description?: string; description?: string;
// Tile-specific actions // Tile-specific actions
actions?: plugins.tsclass.website.IMenuItem[]; actions?: plugins.tsclass.website.IMenuItem[];
} }
@@ -191,7 +198,6 @@ export class DeesStatsGrid extends DeesElement {
min-height: var(--content-min-height); min-height: var(--content-min-height);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center;
flex: 1; flex: 1;
} }
@@ -274,6 +280,9 @@ export class DeesStatsGrid extends DeesElement {
.percentage-wrapper { .percentage-wrapper {
width: 100%; width: 100%;
position: relative; position: relative;
display: flex;
flex-direction: column;
flex: 1;
} }
.percentage-value { .percentage-value {
@@ -291,6 +300,7 @@ export class DeesStatsGrid extends DeesElement {
background: ${cssManager.bdTheme('#e8e8e8', '#1a1a1a')}; background: ${cssManager.bdTheme('#e8e8e8', '#1a1a1a')};
border-radius: 3px; border-radius: 3px;
overflow: hidden; overflow: hidden;
margin-top: auto;
} }
.percentage-fill { .percentage-fill {
@@ -300,12 +310,69 @@ export class DeesStatsGrid extends DeesElement {
border-radius: 3px; border-radius: 3px;
} }
/* Multi Percentage Styles */
.multi-percentage-wrapper {
width: 100%;
display: flex;
flex-direction: column;
flex: 1;
}
.multi-percentage-items {
display: flex;
flex-direction: column;
gap: 12px;
margin-top: auto;
}
.multi-percentage-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.multi-percentage-header {
display: flex;
justify-content: space-between;
align-items: baseline;
}
.multi-percentage-label {
font-size: 11px;
font-weight: 500;
color: ${cssManager.bdTheme('hsl(215.4 16.3% 46.9%)', 'hsl(215 20.2% 65.1%)')};
letter-spacing: -0.01em;
}
.multi-percentage-value {
font-size: 13px;
font-weight: 600;
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
letter-spacing: -0.01em;
}
.multi-percentage-bar {
width: 100%;
height: 4px;
background: ${cssManager.bdTheme('#e8e8e8', '#1a1a1a')};
border-radius: 2px;
overflow: hidden;
}
.multi-percentage-fill {
height: 100%;
background: ${cssManager.bdTheme('#333333', '#e0e0e0')};
transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 2px;
}
/* Trend Styles */ /* Trend Styles */
.trend-container { .trend-container {
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
flex: 1;
} }
.trend-header { .trend-header {
@@ -341,6 +408,7 @@ export class DeesStatsGrid extends DeesElement {
width: 100%; width: 100%;
height: 28px; height: 28px;
position: relative; position: relative;
margin-top: auto;
} }
.trend-svg { .trend-svg {
@@ -464,6 +532,9 @@ export class DeesStatsGrid extends DeesElement {
case 'trend': case 'trend':
return this.renderTrend(tile); return this.renderTrend(tile);
case 'multiPercentage':
return this.renderMultiPercentage(tile);
case 'text': case 'text':
return html` return html`
<div class="text-value" style="${tile.color ? `color: ${tile.color}` : ''}"> <div class="text-value" style="${tile.color ? `color: ${tile.color}` : ''}">
@@ -595,6 +666,39 @@ export class DeesStatsGrid extends DeesElement {
`; `;
} }
private renderMultiPercentage(tile: IStatsTile): TemplateResult {
if (!tile.percentages || tile.percentages.length === 0) {
return html`<div class="tile-value">${tile.value}</div>`;
}
// Limit to 3 percentages
const items = tile.percentages.slice(0, 3);
return html`
<div class="multi-percentage-wrapper">
<div class="multi-percentage-items">
${items.map(item => {
const percentage = Math.min(100, Math.max(0, item.value));
return html`
<div class="multi-percentage-item">
<div class="multi-percentage-header">
<span class="multi-percentage-label">${item.label}</span>
<span class="multi-percentage-value">${percentage}%</span>
</div>
<div class="multi-percentage-bar">
<div
class="multi-percentage-fill"
style="width: ${percentage}%; ${item.color ? `background: ${item.color}` : ''}"
></div>
</div>
</div>
`;
})}
</div>
</div>
`;
}
private async handleGridAction(action: plugins.tsclass.website.IMenuItem) { private async handleGridAction(action: plugins.tsclass.website.IMenuItem) {
if (action.action) { if (action.action) {
await action.action(); await action.action();