From 48fbeb397d079d33d8b7c3c201c61d22e1476f88 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Mon, 16 Jun 2025 14:37:09 +0000 Subject: [PATCH] feat(dees-button-group): add new button group component with demo and styling fix(dees-chart-area): improve real-time updates and chart element handling fix(dees-chart-log): refactor demo to store log element reference chore: update dependencies in package.json and pnpm-lock.yaml --- package.json | 4 +- pnpm-lock.yaml | 20 ++-- readme.hints.md | 20 +++- ts_web/elements/dees-button-group.demo.ts | 114 +++++++++++++++++++ ts_web/elements/dees-button-group.ts | 83 ++++++++++++++ ts_web/elements/dees-chart-area.demo.ts | 129 +++++++++++++--------- ts_web/elements/dees-chart-area.ts | 30 +++-- ts_web/elements/dees-chart-log.demo.ts | 13 ++- ts_web/elements/dees-chart-log.ts | 7 +- ts_web/elements/index.ts | 1 + 10 files changed, 334 insertions(+), 87 deletions(-) create mode 100644 ts_web/elements/dees-button-group.demo.ts create mode 100644 ts_web/elements/dees-button-group.ts diff --git a/package.json b/package.json index f663e58..aa5e660 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "dependencies": { "@design.estate/dees-domtools": "^2.1.1", "@design.estate/dees-element": "^2.0.42", - "@design.estate/dees-wcctools": "^1.0.90", + "@design.estate/dees-wcctools": "^1.0.92", "@fortawesome/fontawesome-svg-core": "^6.7.2", "@fortawesome/free-brands-svg-icons": "^6.7.2", "@fortawesome/free-regular-svg-icons": "^6.7.2", @@ -30,7 +30,7 @@ "apexcharts": "^4.7.0", "highlight.js": "11.11.1", "ibantools": "^4.5.1", - "lucide": "^0.514.0", + "lucide": "^0.515.0", "monaco-editor": "^0.52.2", "pdfjs-dist": "^4.10.38", "xterm": "^5.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db91c1a..9a20650 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: ^2.0.42 version: 2.0.42 '@design.estate/dees-wcctools': - specifier: ^1.0.90 - version: 1.0.90 + specifier: ^1.0.92 + version: 1.0.92 '@fortawesome/fontawesome-svg-core': specifier: ^6.7.2 version: 6.7.2 @@ -54,8 +54,8 @@ importers: specifier: ^4.5.1 version: 4.5.1 lucide: - specifier: ^0.514.0 - version: 0.514.0 + specifier: ^0.515.0 + version: 0.515.0 monaco-editor: specifier: ^0.52.2 version: 0.52.2 @@ -305,8 +305,8 @@ packages: '@design.estate/dees-element@2.0.42': resolution: {integrity: sha512-1PzHP6q/PtSiu4P0nCxjSeHtRHn62zoSouMy8JFW2h29FT/CSDVaTUAUqYqnvwE/U98aLNivWTmerZitDF7kBQ==} - '@design.estate/dees-wcctools@1.0.90': - resolution: {integrity: sha512-EHYWHiOe+P261e9fBbOBmkD7lIsOpD+tu4VZQr20oc8vhsFjeUGJqYeBm/Ghwg+Gck/dto+K9zyJNIyQ642cEw==} + '@design.estate/dees-wcctools@1.0.92': + resolution: {integrity: sha512-E4Hnxvvzy2ivJzPHzWL2dmJtBtAD+stnEG7uQ0usQM6NVnarIGPI9PflGSspM75nnA/HKi+lpsqRgp1DtbPqTQ==} '@esbuild/aix-ppc64@0.24.2': resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} @@ -3153,8 +3153,8 @@ packages: resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} engines: {node: '>=16.14'} - lucide@0.514.0: - resolution: {integrity: sha512-GQ3Rzj1qFANBvTmhe8RM3vR491RGnSjHsivA5wSuEj5taLwH1Sv4N7n6ae3ENGsYRzdrkVXZo4ieUbD1WOXmoA==} + lucide@0.515.0: + resolution: {integrity: sha512-n7tFK3R1HdsxwM5rMOa6twAi/4RGZCysc7dmk7Cr2GiOUcnHX0+MX9xw3xynpbekXCgS4+o9HeIWhBl3rZHIAA==} make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} @@ -5176,7 +5176,7 @@ snapshots: - supports-color - vue - '@design.estate/dees-wcctools@1.0.90': + '@design.estate/dees-wcctools@1.0.92': dependencies: '@design.estate/dees-domtools': 2.3.2 '@design.estate/dees-element': 2.0.42 @@ -8846,7 +8846,7 @@ snapshots: lru-cache@8.0.5: {} - lucide@0.514.0: {} + lucide@0.515.0: {} make-dir@3.1.0: dependencies: diff --git a/readme.hints.md b/readme.hints.md index 0d83bdc..85438f8 100644 --- a/readme.hints.md +++ b/readme.hints.md @@ -25,6 +25,7 @@ - Methods: - `updateSeries()`: Update chart data - `appendData()`: Add new data points to existing series +- Demo uses global reference to access chart element (window.__demoChartElement) ### dees-chart-log - Server log viewer component (not a chart despite the name) @@ -40,4 +41,21 @@ - Light/dark theme support - Demo includes realistic server log simulation - Note: In demos, buttons use `@clicked` event (not `@click`) -- Demo uses global reference to access log element (window.__demoLogElement) \ No newline at end of file +- Demo uses global reference to access log element (window.__demoLogElement) + +## UI Components + +### dees-button-group +- Groups multiple buttons together with a unified background +- Properties: + - `label`: Optional label text displayed before the buttons + - `direction`: 'horizontal' | 'vertical' layout +- Features: + - Light/dark theme support + - Flexible layout with proper spacing + - Works with all button types (normal, highlighted, success, danger) +- Use cases: + - View mode selectors + - Action grouping + - Navigation options + - Filter controls \ No newline at end of file diff --git a/ts_web/elements/dees-button-group.demo.ts b/ts_web/elements/dees-button-group.demo.ts new file mode 100644 index 0000000..fd6e3b4 --- /dev/null +++ b/ts_web/elements/dees-button-group.demo.ts @@ -0,0 +1,114 @@ +import { html, css } from '@design.estate/dees-element'; + +export const demoFunc = () => { + return html` + +
+
+

Basic Button Groups

+

Button groups without labels for simple grouping

+ + + Option 1 + Option 2 + Option 3 + +
+ +
+

Labeled Button Groups

+

Button groups with descriptive labels

+ + + Grid + List + Cards + +
+ +
+

Multiple Groups

+

Multiple button groups used together

+ +
+ + System + Network + Sales + + + + 1H + 24H + 7D + 30D + + + + Refresh + Export + +
+
+ +
+

Vertical Button Groups

+

Button groups with vertical layout

+ +
+ + Dashboard + Analytics + Reports + Settings + + + + Add Item + Edit Item + Delete Item + +
+
+ +
+

Mixed Button Types

+

Different button types within groups

+ + + Active + Pending + Inactive + +
+
+ `; +}; \ No newline at end of file diff --git a/ts_web/elements/dees-button-group.ts b/ts_web/elements/dees-button-group.ts new file mode 100644 index 0000000..c8238f8 --- /dev/null +++ b/ts_web/elements/dees-button-group.ts @@ -0,0 +1,83 @@ +import { + DeesElement, + css, + cssManager, + customElement, + html, + property, + type TemplateResult, +} from '@design.estate/dees-element'; + +import * as domtools from '@design.estate/dees-domtools'; +import { demoFunc } from './dees-button-group.demo.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-button-group': DeesButtonGroup; + } +} + +@customElement('dees-button-group') +export class DeesButtonGroup extends DeesElement { + public static demo = demoFunc; + + @property() + public label: string = ''; + + @property() + public direction: 'horizontal' | 'vertical' = 'horizontal'; + + constructor() { + super(); + domtools.elementBasic.setup(); + } + + public static styles = [ + cssManager.defaultStyles, + css` + :host { + display: inline-block; + } + + .button-group { + display: flex; + gap: 8px; + align-items: center; + padding: 8px; + background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.05)', 'rgba(255, 255, 255, 0.05)')}; + border-radius: 6px; + } + + .button-group.vertical { + flex-direction: column; + align-items: stretch; + } + + .label { + color: ${cssManager.bdTheme('#666', '#999')}; + font-size: 12px; + font-family: 'Geist Sans', sans-serif; + margin-right: 8px; + white-space: nowrap; + } + + .button-group.vertical .label { + margin-right: 0; + margin-bottom: 8px; + } + + ::slotted(*) { + margin: 0 !important; + } + `, + ]; + + public render(): TemplateResult { + return html` +
+ ${this.label ? html`${this.label}` : ''} + +
+ `; + } +} \ No newline at end of file diff --git a/ts_web/elements/dees-chart-area.demo.ts b/ts_web/elements/dees-chart-area.demo.ts index 34f9fef..35a4c49 100644 --- a/ts_web/elements/dees-chart-area.demo.ts +++ b/ts_web/elements/dees-chart-area.demo.ts @@ -1,18 +1,11 @@ import { html, css } from '@design.estate/dees-element'; import type { DeesChartArea } from './dees-chart-area.js'; +import '@design.estate/dees-wcctools'; export const demoFunc = () => { let chartElement: DeesChartArea; let intervalId: number; let currentDataset = 'system'; - - // Get element reference after render - setTimeout(() => { - const charts = document.querySelectorAll('dees-chart-area'); - if (charts.length > 0) { - chartElement = charts[charts.length - 1] as DeesChartArea; - } - }, 100); // Y-axis formatters for different datasets const formatters = { @@ -111,11 +104,15 @@ export const demoFunc = () => { return Math.floor(Math.random() * (max - min + 1)) + min; }; + // Get chart element + const getChartElement = () => { + return chartElement; + }; + // Add real-time data const addRealtimeData = () => { - if (!chartElement) return; - - const dataset = datasets[currentDataset]; + const chart = getChartElement(); + if (!chart) return; const newTimestamp = new Date().toISOString(); // Generate new data points based on dataset type @@ -133,29 +130,48 @@ export const demoFunc = () => { ]; } - // Keep only last 10 data points - const currentSeries = chartElement.series.map((series, index) => ({ + // Keep only last 20 data points and update without animation + const currentSeries = chart.series.map((series, index) => ({ ...series, - data: [...series.data.slice(-9), ...(newData[index] || [])], + data: [...series.data.slice(-19), ...(newData[index] || [])], })); - chartElement.series = currentSeries; + // Update without animation for smoother real-time updates + chart.updateSeries(currentSeries, false); }; // Switch dataset const switchDataset = (name: string) => { currentDataset = name; - if (chartElement) { - const dataset = datasets[name]; - chartElement.label = dataset.label; - chartElement.series = dataset.series; - chartElement.yAxisFormatter = formatters[name]; - } + + const updateChart = () => { + const chart = getChartElement(); + if (chart) { + const dataset = datasets[name]; + chart.label = dataset.label; + chart.series = dataset.series; + chart.yAxisFormatter = formatters[name]; + } + }; + + updateChart(); }; // Start/stop real-time updates const startRealtime = () => { if (!intervalId && (currentDataset === 'system' || currentDataset === 'network')) { + const chart = getChartElement(); + if (chart) { + // Disable animations for real-time mode + chart.updateOptions({ + chart: { + animations: { + enabled: false + } + } + }, false, false); + } + intervalId = window.setInterval(() => addRealtimeData(), 2000); } }; @@ -164,29 +180,52 @@ export const demoFunc = () => { if (intervalId) { window.clearInterval(intervalId); intervalId = null; + + const chart = getChartElement(); + if (chart) { + // Re-enable animations when stopping real-time + chart.updateOptions({ + chart: { + animations: { + enabled: true, + speed: 400, + animateGradually: { + enabled: true, + delay: 150 + } + } + } + }, false, true); + } } }; // Randomize current data const randomizeData = () => { - if (!chartElement) return; + const chart = getChartElement(); + if (!chart) return; - const currentSeries = chartElement.series.map(series => ({ + const currentSeries = chart.series.map(series => ({ ...series, - data: series.data.map(point => ({ + data: series.data.map((point: any) => ({ ...point, y: typeof point.y === 'number' - ? point.y * (0.8 + Math.random() * 0.4) // +/- 20% variation + ? Math.round(point.y * (0.8 + Math.random() * 0.4)) // +/- 20% variation : point.y, })), })); - chartElement.series = currentSeries; + // Update with animation for single updates + chart.updateSeries(currentSeries, true); }; return html` -
-
- + switchDataset('system')} type=${currentDataset === 'system' ? 'highlighted' : 'normal'} @@ -252,19 +274,17 @@ export const demoFunc = () => { @clicked=${() => switchDataset('sales')} type=${currentDataset === 'sales' ? 'highlighted' : 'normal'} >Sales Data -
+ -
- + startRealtime()}>Start Live stopRealtime()}>Stop Live -
+ -
- + randomizeData()}>Randomize Values addRealtimeData()}>Add Point -
+
@@ -280,6 +300,7 @@ export const demoFunc = () => { Chart updates every 2 seconds when live mode is active • Try switching datasets and randomizing values
-
+ + `; }; diff --git a/ts_web/elements/dees-chart-area.ts b/ts_web/elements/dees-chart-area.ts index 56b0e74..c9f97ca 100644 --- a/ts_web/elements/dees-chart-area.ts +++ b/ts_web/elements/dees-chart-area.ts @@ -6,7 +6,6 @@ import { html, property, state, - type CSSResult, type TemplateResult, } from '@design.estate/dees-element'; @@ -35,7 +34,7 @@ export class DeesChartArea extends DeesElement { @property({ type: Array }) public series: ApexAxisChartSeries = []; - @property({ type: Function }) + @property({ attribute: false }) public yAxisFormatter: (value: number) => string = (val) => `${val} Mbps`; private resizeObserver: ResizeObserver; @@ -187,9 +186,13 @@ export class DeesChartArea extends DeesElement { enabled: true, speed: 400, animateGradually: { - enabled: true, - delay: 150 + enabled: false, // Disable gradual animation for cleaner updates + delay: 0 }, + dynamicAnimation: { + enabled: true, + speed: 350 + } }, }, dataLabels: { @@ -312,24 +315,29 @@ export class DeesChartArea extends DeesElement { } } - public async updateSeries(newSeries: ApexAxisChartSeries) { + public async updateSeries(newSeries: ApexAxisChartSeries, animate: boolean = true) { if (!this.chart) { return; } - await this.chart.updateSeries(newSeries, true); + this.chart.updateSeries(newSeries, animate); } - public async appendData(seriesIndex: number, newData: any[]) { + public async appendData(newData: { data: any[] }[]) { if (!this.chart) { return; } - const currentSeries = [...this.series]; - if (currentSeries[seriesIndex]) { - currentSeries[seriesIndex].data = [...currentSeries[seriesIndex].data, ...newData]; - await this.updateSeries(currentSeries); + // Use ApexCharts' appendData method for smoother real-time updates + await this.chart.appendData(newData); + } + + public async updateOptions(options: ApexCharts.ApexOptions, redrawPaths?: boolean, animate?: boolean) { + if (!this.chart) { + return; } + + return this.chart.updateOptions(options, redrawPaths, animate); } public async resizeChart() { diff --git a/ts_web/elements/dees-chart-log.demo.ts b/ts_web/elements/dees-chart-log.demo.ts index 2fa968a..5ccdc37 100644 --- a/ts_web/elements/dees-chart-log.demo.ts +++ b/ts_web/elements/dees-chart-log.demo.ts @@ -1,7 +1,10 @@ import { html } from '@design.estate/dees-element'; +import type { DeesChartLog } from './dees-chart-log.js'; +import '@design.estate/dees-wcctools'; export const demoFunc = () => { let intervalId: number; + let logElement: DeesChartLog; const serverSources = ['Server', 'Database', 'API', 'Auth', 'Cache', 'Queue', 'WebSocket', 'Scheduler']; @@ -44,7 +47,6 @@ export const demoFunc = () => { }; const generateRandomLog = () => { - const logElement = (window as any).__demoLogElement; if (!logElement) { console.warn('Log element not ready yet'); return; @@ -119,7 +121,11 @@ export const demoFunc = () => { return html` -