Files
dees-catalog/ts_web/elements/dees-dashboardgrid/dees-dashboardgrid.demo.ts

406 lines
14 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { html, css, cssManager } from '@design.estate/dees-element';
import type { DeesDashboardgrid } from './dees-dashboardgrid.js';
import '@design.estate/dees-wcctools/demotools';
export const demoFunc = () => {
return html`
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
const grid = elementArg.querySelector('#dashboardGrid') as DeesDashboardgrid;
const seedWidgets = [
{
id: 'metrics1',
x: 0,
y: 0,
w: 3,
h: 2,
title: 'Revenue',
icon: 'lucide:dollarSign',
content: html`
<div style="padding: 20px;">
<div style="font-size: 32px; font-weight: 700; color: ${cssManager.bdTheme('#09090b', '#fafafa')};">$124,563</div>
<div style="color: #22c55e; font-size: 14px; margin-top: 8px;">↑ 12.5% from last month</div>
</div>
`,
},
{
id: 'metrics2',
x: 3,
y: 0,
w: 3,
h: 2,
title: 'Users',
icon: 'lucide:users',
content: html`
<div style="padding: 20px;">
<div style="font-size: 32px; font-weight: 700; color: ${cssManager.bdTheme('#09090b', '#fafafa')};">8,234</div>
<div style="color: #3b82f6; font-size: 14px; margin-top: 8px;"> 5.2% from last week</div>
</div>
`,
},
{
id: 'chart1',
x: 6,
y: 0,
w: 6,
h: 4,
title: 'Analytics',
icon: 'lucide:lineChart',
content: html`
<div style="padding: 20px; height: 100%; display: flex; align-items: center; justify-content: center;">
<div style="text-align: center; color: #71717a;">
<dees-icon .icon=${'lucide:lineChart'} style="font-size: 48px; margin-bottom: 16px;"></dees-icon>
<div>Chart visualization area</div>
</div>
</div>
`,
},
];
grid.widgets = seedWidgets.map(widget => ({ ...widget }));
grid.cellHeight = 80;
grid.margin = { top: 10, right: 10, bottom: 10, left: 10 };
grid.enableAnimation = true;
grid.showGridLines = false;
const baseLayout = grid.getLayout().map(item => ({ ...item }));
const mobileLayout = grid.widgets.map((widget, index) => ({
id: widget.id,
x: 0,
y: index === 0 ? 0 : grid.widgets.slice(0, index).reduce((acc, prev) => acc + prev.h, 0),
w: grid.columns,
h: widget.h,
}));
grid.layouts = {
base: baseLayout,
mobile: mobileLayout,
};
const statusEl = elementArg.querySelector('#dashboardLayoutStatus') as HTMLElement;
const updateStatus = () => {
const layout = grid.getLayout();
statusEl.textContent = `Active breakpoint: ${grid.activeBreakpoint} Tiles: ${layout.length}`;
};
const mediaQuery = window.matchMedia('(max-width: 768px)');
const handleBreakpoint = () => {
const target = mediaQuery.matches ? 'mobile' : 'base';
grid.applyBreakpointLayout(target);
updateStatus();
};
if (typeof mediaQuery.addEventListener === 'function') {
mediaQuery.addEventListener('change', handleBreakpoint);
} else {
(mediaQuery as MediaQueryList & {
addListener?: (listener: (this: MediaQueryList, ev: MediaQueryListEvent) => void) => void;
}).addListener?.(handleBreakpoint);
}
handleBreakpoint();
let widgetCounter = 4;
const buttons = elementArg.querySelectorAll('dees-button');
buttons.forEach(button => {
const text = button.textContent?.trim();
switch (text) {
case 'Toggle Animation':
button.addEventListener('click', () => {
grid.enableAnimation = !grid.enableAnimation;
});
break;
case 'Toggle Grid Lines':
button.addEventListener('click', () => {
grid.showGridLines = !grid.showGridLines;
});
break;
case 'Add Widget':
button.addEventListener('click', () => {
const newWidget = {
id: `widget${widgetCounter++}`,
x: 0,
y: 0,
w: 3,
h: 2,
autoPosition: true,
title: `Widget ${widgetCounter - 1}`,
icon: 'lucide:package',
content: html`
<div style="padding: 20px; text-align: center;">
<div style="color: #71717a;">New widget content</div>
<div style="margin-top: 8px; font-size: 24px; font-weight: 600; color: ${cssManager.bdTheme('#09090b', '#fafafa')};">${Math.floor(
Math.random() * 1000,
)}</div>
</div>
`,
};
grid.addWidget(newWidget, true);
});
break;
case 'Compact Grid':
button.addEventListener('click', () => {
grid.compact();
});
break;
case 'Toggle Edit Mode':
button.addEventListener('click', () => {
grid.editable = !grid.editable;
button.textContent = grid.editable ? 'Lock Grid' : 'Unlock Grid';
});
break;
case 'Reset Layout':
button.addEventListener('click', () => {
grid.applyBreakpointLayout(grid.activeBreakpoint);
});
break;
default:
break;
}
});
// Enhanced logging for reflow events
let lastPlaceholderPosition = null;
let moveEventCounter = 0;
// Helper function to log grid state
const logGridState = (eventName: string, details?: any) => {
const layout = grid.getLayout();
console.group(`🔄 ${eventName} [Event #${++moveEventCounter}]`);
console.log('Timestamp:', new Date().toISOString());
console.log('Grid Configuration:', {
columns: grid.columns,
cellHeight: grid.cellHeight,
margin: grid.margin,
editable: grid.editable,
activeBreakpoint: grid.activeBreakpoint
});
console.log('Current Layout:', layout);
console.log('Widget Count:', layout.length);
console.log('Grid Bounds:', {
totalWidgets: grid.widgets.length,
maxY: Math.max(...layout.map(w => w.y + w.h)),
occupied: layout.map(w => `${w.id}: (${w.x},${w.y}) ${w.w}x${w.h}`).join(', ')
});
if (details) {
console.log('Event Details:', details);
}
console.groupEnd();
};
// Monitor placeholder position changes using MutationObserver
const placeholderObserver = new MutationObserver(() => {
const placeholder = grid.shadowRoot?.querySelector('.placeholder') as HTMLElement;
if (placeholder) {
const currentPosition = {
left: placeholder.style.left,
top: placeholder.style.top,
width: placeholder.style.width,
height: placeholder.style.height
};
if (JSON.stringify(currentPosition) !== JSON.stringify(lastPlaceholderPosition)) {
console.group('📍 Placeholder Position Changed');
console.log('Previous:', lastPlaceholderPosition);
console.log('Current:', currentPosition);
// Extract grid coordinates from style
const gridInfo = grid.shadowRoot?.querySelector('.grid-container');
if (gridInfo) {
console.log('Grid Container Dimensions:', {
width: gridInfo.clientWidth,
height: gridInfo.clientHeight
});
}
console.groupEnd();
lastPlaceholderPosition = currentPosition;
}
}
});
// Start observing the shadow DOM for placeholder changes
if (grid.shadowRoot) {
placeholderObserver.observe(grid.shadowRoot, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['style']
});
}
// Log initial state
logGridState('Initial Grid State');
grid.addEventListener('widget-move', (e: CustomEvent) => {
logGridState('Widget Move', {
widget: e.detail.widget,
displaced: e.detail.displaced,
swappedWith: e.detail.swappedWith
});
});
grid.addEventListener('widget-resize', (e: CustomEvent) => {
logGridState('Widget Resize', {
widget: e.detail.widget,
displaced: e.detail.displaced,
swappedWith: e.detail.swappedWith
});
});
grid.addEventListener('widget-remove', (e: CustomEvent) => {
logGridState('Widget Remove', {
removedWidget: e.detail.widget
});
updateStatus();
});
grid.addEventListener('layout-change', () => {
logGridState('Layout Change');
updateStatus();
});
// Monitor during drag/resize operations using pointer events
grid.addEventListener('pointerdown', (e: PointerEvent) => {
const isHeader = (e.target as HTMLElement).closest('.widget-header');
const isResizeHandle = (e.target as HTMLElement).closest('.resize-handle');
if (isHeader || isResizeHandle) {
console.group(`🎯 Interaction Started: ${isHeader ? 'Drag' : 'Resize'}`);
console.log('Target Widget:', (e.target as HTMLElement).closest('.widget')?.getAttribute('data-widget-id'));
console.log('Pointer Position:', { x: e.clientX, y: e.clientY });
console.groupEnd();
// Track pointer move during interaction
const handlePointerMove = (moveEvent: PointerEvent) => {
const widget = (e.target as HTMLElement).closest('.widget');
if (widget) {
console.log(` Pointer Move:`, {
widgetId: widget.getAttribute('data-widget-id'),
position: { x: moveEvent.clientX, y: moveEvent.clientY },
delta: {
x: moveEvent.clientX - e.clientX,
y: moveEvent.clientY - e.clientY
}
});
}
};
const handlePointerUp = () => {
console.group('🏁 Interaction Ended');
logGridState('Final State After Interaction');
console.groupEnd();
document.removeEventListener('pointermove', handlePointerMove);
document.removeEventListener('pointerup', handlePointerUp);
};
document.addEventListener('pointermove', handlePointerMove);
document.addEventListener('pointerup', handlePointerUp);
}
});
// Log when widgets are added
const originalAddWidget = grid.addWidget.bind(grid);
grid.addWidget = (widget: any, autoPosition?: boolean) => {
console.group(' Adding Widget');
console.log('New Widget:', widget);
console.log('Auto Position:', autoPosition);
const result = originalAddWidget(widget, autoPosition);
logGridState('After Widget Added');
console.groupEnd();
return result;
};
// Log compact operations
const originalCompact = grid.compact.bind(grid);
grid.compact = (direction?: string) => {
console.group('🗜️ Compacting Grid');
console.log('Direction:', direction || 'vertical');
logGridState('Before Compact');
const result = originalCompact(direction);
logGridState('After Compact');
console.groupEnd();
return result;
};
updateStatus();
}}>
<style>
${css`
.demoBox {
position: relative;
background: ${cssManager.bdTheme('#f4f4f5', '#09090b')};
height: 100%;
width: 100%;
padding: 40px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 24px;
}
.demo-controls {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.demo-controls dees-button {
flex-shrink: 0;
}
.grid-container-wrapper {
flex: 1;
min-height: 600px;
position: relative;
}
.info {
color: ${cssManager.bdTheme('#71717a', '#71717a')};
font-size: 12px;
font-family: 'Geist Sans', sans-serif;
text-align: center;
display: flex;
flex-direction: column;
gap: 6px;
}
#dashboardLayoutStatus {
font-weight: 600;
color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')};
}
`}
</style>
<div class="demoBox">
<div class="demo-controls">
<dees-button-group label="Animation:">
<dees-button>Toggle Animation</dees-button>
</dees-button-group>
<dees-button-group label="Display:">
<dees-button>Toggle Grid Lines</dees-button>
</dees-button-group>
<dees-button-group label="Actions:">
<dees-button>Add Widget</dees-button>
<dees-button>Compact Grid</dees-button>
<dees-button>Reset Layout</dees-button>
</dees-button-group>
<dees-button-group label="Mode:">
<dees-button>Toggle Edit Mode</dees-button>
</dees-button-group>
</div>
<div class="grid-container-wrapper">
<dees-dashboardgrid id="dashboardGrid"></dees-dashboardgrid>
</div>
<div class="info">
<div>Drag to reposition, resize from handles, or right-click a header to delete a tile.</div>
<div id="dashboardLayoutStatus"></div>
</div>
</div>
</dees-demowrapper>
`;
};