import { Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
DbDashboardComponent,
DbWidgetContentDefDirective,
type DbDashboard,
type DbWidgetType,
} from '@sda/dashboard-elements-ui';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, DbDashboardComponent, DbWidgetContentDefDirective],
template: `
`,
styles: [`
.demo-container {
height: 100vh;
display: flex;
flex-direction: column;
}
/* Stats Widget */
.widget-stats {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
padding: 1.5rem;
}
.stat-value {
font-size: 2.5rem;
font-weight: 700;
color: #3b82f6;
margin-bottom: 0.5rem;
line-height: 1;
}
.stat-label {
font-size: 0.75rem;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.05em;
font-weight: 600;
}
/* Chart Widget */
.widget-chart {
padding: 1rem;
height: 100%;
display: flex;
flex-direction: column;
}
.chart-title {
font-size: 0.875rem;
font-weight: 600;
color: #6b7280;
margin-bottom: 1rem;
}
.chart-placeholder {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.chart-svg {
width: 100%;
height: 100%;
max-height: 200px;
}
/* Table Widget */
.widget-table {
padding: 0;
overflow: auto;
height: 100%;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 0.75rem 1rem;
text-align: left;
border-bottom: 1px solid #e5e7eb;
}
th {
background: #f9fafb;
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #6b7280;
position: sticky;
top: 0;
z-index: 1;
}
td {
font-size: 0.875rem;
}
tbody tr:hover {
background: #f9fafb;
}
.status {
display: inline-block;
padding: 0.25rem 0.625rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 500;
}
.status--success {
background: #d1fae5;
color: #065f46;
}
.status--warning {
background: #fef3c7;
color: #92400e;
}
.positive {
color: #059669;
font-weight: 600;
}
.negative {
color: #dc2626;
font-weight: 600;
}
/* List Widget */
.widget-list {
padding: 0.5rem 0;
overflow: auto;
height: 100%;
}
.list-item {
display: flex;
align-items: center;
padding: 0.75rem 1rem;
gap: 0.75rem;
border-bottom: 1px solid #e5e7eb;
transition: background 150ms;
}
.list-item:hover {
background: #f9fafb;
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 0.875rem;
}
.list-item__content {
flex: 1;
min-width: 0;
}
.list-item__title {
font-size: 0.875rem;
font-weight: 500;
color: #111827;
margin-bottom: 0.25rem;
}
.list-item__subtitle {
font-size: 0.75rem;
color: #6b7280;
}
.list-item__meta {
font-size: 0.75rem;
color: #9ca3af;
}
`],
})
export class AppComponent {
dashboard = signal({
id: 'demo-dashboard',
title: 'Analytics Dashboard',
layouts: [
{
breakpoint: 'lg',
columns: 12,
rowHeight: 80,
gap: 16,
widgets: [
{ id: 'widget-1', col: 1, row: 1, colSpan: 3, rowSpan: 2 },
{ id: 'widget-2', col: 4, row: 1, colSpan: 3, rowSpan: 2 },
{ id: 'widget-3', col: 7, row: 1, colSpan: 3, rowSpan: 2 },
{ id: 'widget-4', col: 10, row: 1, colSpan: 3, rowSpan: 2 },
{ id: 'widget-5', col: 1, row: 3, colSpan: 8, rowSpan: 4 },
{ id: 'widget-6', col: 9, row: 3, colSpan: 4, rowSpan: 4 },
],
},
],
widgets: [
{
id: 'widget-1',
type: 'stats',
title: 'Total Users',
icon: 'users',
layout: { id: 'widget-1', col: 1, row: 1, colSpan: 3, rowSpan: 2 },
config: { value: '2,845', label: 'Total Users' },
},
{
id: 'widget-2',
type: 'stats',
title: 'Revenue',
icon: 'dollar-sign',
layout: { id: 'widget-2', col: 4, row: 1, colSpan: 3, rowSpan: 2 },
config: { value: '$54.2K', label: 'Monthly Revenue' },
},
{
id: 'widget-3',
type: 'stats',
title: 'Conversion',
icon: 'trending-up',
layout: { id: 'widget-3', col: 7, row: 1, colSpan: 3, rowSpan: 2 },
config: { value: '28.5%', label: 'Conversion Rate' },
},
{
id: 'widget-4',
type: 'stats',
title: 'Active Now',
icon: 'activity',
layout: { id: 'widget-4', col: 10, row: 1, colSpan: 3, rowSpan: 2 },
config: { value: '124', label: 'Active Sessions' },
},
{
id: 'widget-5',
type: 'chart',
title: 'Revenue Trend',
icon: 'bar-chart-2',
layout: { id: 'widget-5', col: 1, row: 3, colSpan: 8, rowSpan: 4 },
},
{
id: 'widget-6',
type: 'list',
title: 'Recent Activity',
icon: 'activity',
layout: { id: 'widget-6', col: 9, row: 3, colSpan: 4, rowSpan: 4 },
},
],
});
widgetTypes: DbWidgetType[] = [
{
type: 'stats',
label: 'Stats Card',
icon: 'bar-chart',
description: 'Display key metrics and statistics',
category: 'analytics',
defaultLayout: {
colSpan: 3,
rowSpan: 2,
minColSpan: 2,
minRowSpan: 2,
maxColSpan: 4,
maxRowSpan: 3,
},
component: class {},
},
{
type: 'chart',
label: 'Chart',
icon: 'line-chart',
description: 'Visualize data with charts',
category: 'analytics',
defaultLayout: {
colSpan: 6,
rowSpan: 4,
minColSpan: 4,
minRowSpan: 3,
},
component: class {},
},
{
type: 'table',
label: 'Data Table',
icon: 'table',
description: 'Display tabular data',
category: 'data',
defaultLayout: {
colSpan: 6,
rowSpan: 4,
minColSpan: 4,
minRowSpan: 3,
},
component: class {},
},
{
type: 'list',
label: 'Activity List',
icon: 'list',
description: 'Show recent activities or notifications',
category: 'data',
defaultLayout: {
colSpan: 4,
rowSpan: 4,
minColSpan: 3,
minRowSpan: 3,
},
component: class {},
},
];
sampleListItems = [
{ initial: 'JD', title: 'John Doe completed a task', subtitle: 'Project Alpha', time: '2m ago' },
{ initial: 'SM', title: 'Sarah Miller uploaded a file', subtitle: 'Document.pdf', time: '15m ago' },
{ initial: 'RJ', title: 'Robert Johnson commented', subtitle: 'Great work on this!', time: '1h ago' },
{ initial: 'EW', title: 'Emily White created an issue', subtitle: 'Bug #234', time: '2h ago' },
{ initial: 'MC', title: 'Michael Chen merged PR #45', subtitle: 'Feature: Add dashboard', time: '3h ago' },
];
onWidgetAdd(event: any) {
console.log('Widget added:', event);
const newWidgets = [...this.dashboard().widgets, event.widget];
this.dashboard.update(d => ({ ...d, widgets: newWidgets }));
}
onWidgetRemove(event: any) {
console.log('Widget removed:', event);
const filtered = this.dashboard().widgets.filter((w: any) => w.id !== event.widget.id);
this.dashboard.update(d => ({ ...d, widgets: filtered }));
}
onWidgetMove(event: any) {
console.log('Widget moved:', event);
}
onSave(event: any) {
console.log('Dashboard saved:', event);
alert('Dashboard saved successfully!');
}
}