- Implemented DeesInputFileupload component with file upload functionality, including drag-and-drop support, file previews, and clear all option. - Developed DeesInputRichtext component featuring a rich text editor with a formatting toolbar, link management, and word count display. - Created demo for DeesInputRichtext showcasing various use cases including basic editing, placeholder text, different heights, and disabled state. - Added styles for both components to ensure a consistent and user-friendly interface. - Introduced types for toolbar buttons in the rich text editor for better type safety and maintainability.
		
			
				
	
	
		
			484 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			484 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { html, css, cssManager } from '@design.estate/dees-element';
 | |
| import type { DeesChartArea } from './component.js';
 | |
| import '@design.estate/dees-wcctools/demotools';
 | |
| import './component.js';
 | |
| 
 | |
| export const demoFunc = () => {
 | |
|   // Initial dataset values
 | |
|   const initialDatasets = {
 | |
|     system: {
 | |
|       label: 'System Usage (%)',
 | |
|       series: [
 | |
|         {
 | |
|           name: 'CPU',
 | |
|           data: [
 | |
|             { x: new Date(Date.now() - 300000).toISOString(), y: 25 },
 | |
|             { x: new Date(Date.now() - 240000).toISOString(), y: 30 },
 | |
|             { x: new Date(Date.now() - 180000).toISOString(), y: 28 },
 | |
|             { x: new Date(Date.now() - 120000).toISOString(), y: 35 },
 | |
|             { x: new Date(Date.now() - 60000).toISOString(), y: 32 },
 | |
|             { x: new Date().toISOString(), y: 38 },
 | |
|           ],
 | |
|         },
 | |
|         {
 | |
|           name: 'Memory',
 | |
|           data: [
 | |
|             { x: new Date(Date.now() - 300000).toISOString(), y: 45 },
 | |
|             { x: new Date(Date.now() - 240000).toISOString(), y: 48 },
 | |
|             { x: new Date(Date.now() - 180000).toISOString(), y: 46 },
 | |
|             { x: new Date(Date.now() - 120000).toISOString(), y: 52 },
 | |
|             { x: new Date(Date.now() - 60000).toISOString(), y: 50 },
 | |
|             { x: new Date().toISOString(), y: 55 },
 | |
|           ],
 | |
|         },
 | |
|       ],
 | |
|     },
 | |
|   };
 | |
|   
 | |
|   const initialFormatters = {
 | |
|     system: (val: number) => `${val}%`,
 | |
|   };
 | |
|   
 | |
|   return html`
 | |
|     <dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
 | |
|       // Get the chart elements
 | |
|       const chartElement = elementArg.querySelector('#main-chart') as DeesChartArea;
 | |
|       const connectionsChartElement = elementArg.querySelector('#connections-chart') as DeesChartArea;
 | |
|       let intervalId: number;
 | |
|       let connectionsIntervalId: number;
 | |
|       let currentDataset = 'system';
 | |
| 
 | |
|       // Y-axis formatters for different datasets
 | |
|       const formatters = {
 | |
|         system: (val: number) => `${val}%`,
 | |
|         network: (val: number) => `${val} Mbps`,
 | |
|         sales: (val: number) => `$${val.toLocaleString()}`,
 | |
|       };
 | |
|       
 | |
|       // Time window configuration (in milliseconds)
 | |
|       const TIME_WINDOW = 2 * 60 * 1000; // 2 minutes
 | |
|       const UPDATE_INTERVAL = 1000; // 1 second
 | |
|       const DATA_POINT_INTERVAL = 5000; // Show data points every 5 seconds
 | |
|       
 | |
|       // Store previous values for smooth transitions
 | |
|       let previousValues = {
 | |
|         cpu: 30,
 | |
|         memory: 50,
 | |
|         download: 150,
 | |
|         upload: 30,
 | |
|         connections: 150
 | |
|       };
 | |
| 
 | |
|       // Generate initial data points for time window
 | |
|       const generateInitialData = (baseValue: number, variance: number, interval: number = DATA_POINT_INTERVAL) => {
 | |
|         const data = [];
 | |
|         const now = Date.now();
 | |
|         const pointCount = Math.floor(TIME_WINDOW / interval);
 | |
|         
 | |
|         for (let i = pointCount; i >= 0; i--) {
 | |
|           const timestamp = new Date(now - (i * interval)).toISOString();
 | |
|           const value = baseValue + (Math.random() - 0.5) * variance;
 | |
|           data.push({ x: timestamp, y: Math.round(value) });
 | |
|         }
 | |
|         return data;
 | |
|       };
 | |
|       
 | |
|       // Different datasets to showcase
 | |
|       const datasets = {
 | |
|         system: {
 | |
|           label: 'System Usage (%)',
 | |
|           series: [
 | |
|             {
 | |
|               name: 'CPU',
 | |
|               data: generateInitialData(previousValues.cpu, 10),
 | |
|             },
 | |
|             {
 | |
|               name: 'Memory',
 | |
|               data: generateInitialData(previousValues.memory, 8),
 | |
|             },
 | |
|           ],
 | |
|         },
 | |
|         network: {
 | |
|           label: 'Network Traffic (Mbps)',
 | |
|           series: [
 | |
|             {
 | |
|               name: 'Download',
 | |
|               data: generateInitialData(previousValues.download, 30),
 | |
|             },
 | |
|             {
 | |
|               name: 'Upload',
 | |
|               data: generateInitialData(previousValues.upload, 10),
 | |
|             },
 | |
|           ],
 | |
|         },
 | |
|         sales: {
 | |
|           label: 'Sales Analytics',
 | |
|           series: [
 | |
|             {
 | |
|               name: 'Revenue',
 | |
|               data: [
 | |
|                 { x: '2025-01-01', y: 45000 },
 | |
|                 { x: '2025-01-02', y: 52000 },
 | |
|                 { x: '2025-01-03', y: 48000 },
 | |
|                 { x: '2025-01-04', y: 61000 },
 | |
|                 { x: '2025-01-05', y: 58000 },
 | |
|                 { x: '2025-01-06', y: 65000 },
 | |
|               ],
 | |
|             },
 | |
|             {
 | |
|               name: 'Profit',
 | |
|               data: [
 | |
|                 { x: '2025-01-01', y: 12000 },
 | |
|                 { x: '2025-01-02', y: 14000 },
 | |
|                 { x: '2025-01-03', y: 11000 },
 | |
|                 { x: '2025-01-04', y: 18000 },
 | |
|                 { x: '2025-01-05', y: 16000 },
 | |
|                 { x: '2025-01-06', y: 20000 },
 | |
|               ],
 | |
|             },
 | |
|           ],
 | |
|         },
 | |
|       };
 | |
| 
 | |
|       // Generate smooth value transitions
 | |
|       const getNextValue = (current: number, min: number, max: number, maxChange: number = 5) => {
 | |
|         // Add some randomness but keep it close to current value
 | |
|         const change = (Math.random() - 0.5) * maxChange * 2;
 | |
|         let newValue = current + change;
 | |
|         
 | |
|         // Apply some "pressure" to move towards center of range
 | |
|         const center = (min + max) / 2;
 | |
|         const pressure = (center - newValue) * 0.1;
 | |
|         newValue += pressure;
 | |
|         
 | |
|         // Ensure within bounds
 | |
|         newValue = Math.max(min, Math.min(max, newValue));
 | |
|         return Math.round(newValue);
 | |
|       };
 | |
| 
 | |
|       // Track time of last data point
 | |
|       let lastDataPointTime = Date.now();
 | |
|       let connectionsLastUpdate = Date.now();
 | |
|       
 | |
|       // Add real-time data
 | |
|       const addRealtimeData = () => {
 | |
|         if (!chartElement) return;
 | |
|         
 | |
|         const now = Date.now();
 | |
|         
 | |
|         // Only add new data point every DATA_POINT_INTERVAL
 | |
|         const shouldAddPoint = (now - lastDataPointTime) >= DATA_POINT_INTERVAL;
 | |
|         
 | |
|         if (shouldAddPoint) {
 | |
|           lastDataPointTime = now;
 | |
|           const newTimestamp = new Date(now).toISOString();
 | |
|           
 | |
|           // Generate smooth transitions for new values
 | |
|           if (currentDataset === 'system') {
 | |
|             // Generate new values
 | |
|             previousValues.cpu = getNextValue(previousValues.cpu, 20, 50, 3);
 | |
|             previousValues.memory = getNextValue(previousValues.memory, 40, 70, 2);
 | |
|             
 | |
|             // Get current data and add new points
 | |
|             const currentSeries = chartElement.chartSeries.map((series, index) => ({
 | |
|               name: series.name,
 | |
|               data: [
 | |
|                 ...(series.data as Array<{x: any; y: any}>),
 | |
|                 index === 0 
 | |
|                   ? { x: newTimestamp, y: previousValues.cpu }
 | |
|                   : { x: newTimestamp, y: previousValues.memory }
 | |
|               ]
 | |
|             }));
 | |
|             
 | |
|             chartElement.updateSeries(currentSeries, false);
 | |
|             
 | |
|           } else if (currentDataset === 'network') {
 | |
|             // Generate new values
 | |
|             previousValues.download = getNextValue(previousValues.download, 100, 200, 10);
 | |
|             previousValues.upload = getNextValue(previousValues.upload, 20, 50, 5);
 | |
|             
 | |
|             // Get current data and add new points
 | |
|             const currentSeries = chartElement.chartSeries.map((series, index) => ({
 | |
|               name: series.name,
 | |
|               data: [
 | |
|                 ...(series.data as Array<{x: any; y: any}>),
 | |
|                 index === 0 
 | |
|                   ? { x: newTimestamp, y: previousValues.download }
 | |
|                   : { x: newTimestamp, y: previousValues.upload }
 | |
|               ]
 | |
|             }));
 | |
|             
 | |
|             chartElement.updateSeries(currentSeries, false);
 | |
|           }
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       // Update connections chart data
 | |
|       const updateConnections = () => {
 | |
|         if (!connectionsChartElement) return;
 | |
|         
 | |
|         const now = Date.now();
 | |
|         const newTimestamp = new Date(now).toISOString();
 | |
|         
 | |
|         // Generate new connections value with discrete changes
 | |
|         const change = Math.floor(Math.random() * 21) - 10; // -10 to +10 connections
 | |
|         previousValues.connections = Math.max(50, Math.min(300, previousValues.connections + change));
 | |
|         
 | |
|         // Get current data and add new point
 | |
|         const currentSeries = connectionsChartElement.chartSeries;
 | |
|         const newData = [{
 | |
|           name: currentSeries[0]?.name || 'Connections',
 | |
|           data: [
 | |
|             ...(currentSeries[0]?.data as Array<{x: any; y: any}> || []),
 | |
|             { x: newTimestamp, y: previousValues.connections }
 | |
|           ]
 | |
|         }];
 | |
|         
 | |
|         connectionsChartElement.updateSeries(newData, false);
 | |
|       };
 | |
| 
 | |
|       // Switch dataset
 | |
|       const switchDataset = (name: string) => {
 | |
|         currentDataset = name;
 | |
|         const dataset = datasets[name];
 | |
|         chartElement.label = dataset.label;
 | |
|         chartElement.series = dataset.series;
 | |
|         chartElement.yAxisFormatter = formatters[name];
 | |
|         
 | |
|         // Set appropriate y-axis scaling
 | |
|         if (name === 'system') {
 | |
|           chartElement.yAxisScaling = 'percentage';
 | |
|           chartElement.yAxisMax = 100;
 | |
|         } else if (name === 'network') {
 | |
|           chartElement.yAxisScaling = 'dynamic';
 | |
|         } else {
 | |
|           chartElement.yAxisScaling = 'dynamic';
 | |
|         }
 | |
|         
 | |
|         // Reset last data point time to get fresh data immediately
 | |
|         lastDataPointTime = Date.now() - DATA_POINT_INTERVAL;
 | |
|       };
 | |
| 
 | |
|       // Start/stop real-time updates
 | |
|       const startRealtime = () => {
 | |
|         if (!intervalId && (currentDataset === 'system' || currentDataset === 'network')) {
 | |
|           chartElement.realtimeMode = true;
 | |
|           // Only add data every 5 seconds, chart auto-scrolls independently
 | |
|           intervalId = window.setInterval(() => addRealtimeData(), DATA_POINT_INTERVAL);
 | |
|         }
 | |
|         
 | |
|         // Start connections updates
 | |
|         if (!connectionsIntervalId) {
 | |
|           connectionsChartElement.realtimeMode = true;
 | |
|           // Update connections every second
 | |
|           connectionsIntervalId = window.setInterval(() => updateConnections(), UPDATE_INTERVAL);
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       const stopRealtime = () => {
 | |
|         if (intervalId) {
 | |
|           window.clearInterval(intervalId);
 | |
|           intervalId = null;
 | |
|           chartElement.realtimeMode = false;
 | |
|         }
 | |
|         
 | |
|         // Stop connections updates
 | |
|         if (connectionsIntervalId) {
 | |
|           window.clearInterval(connectionsIntervalId);
 | |
|           connectionsIntervalId = null;
 | |
|           connectionsChartElement.realtimeMode = false;
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       // Randomize current data (spike/drop simulation)
 | |
|       const randomizeData = () => {
 | |
|         if (currentDataset === 'system') {
 | |
|           // Simulate CPU/Memory spike
 | |
|           previousValues.cpu = Math.random() > 0.5 ? 85 : 25;
 | |
|           previousValues.memory = Math.random() > 0.5 ? 80 : 45;
 | |
|         } else if (currentDataset === 'network') {
 | |
|           // Simulate network traffic spike
 | |
|           previousValues.download = Math.random() > 0.5 ? 250 : 100;
 | |
|           previousValues.upload = Math.random() > 0.5 ? 80 : 20;
 | |
|         }
 | |
|         
 | |
|         // Also spike connections
 | |
|         previousValues.connections = Math.random() > 0.5 ? 280 : 80;
 | |
|         
 | |
|         // Force immediate update by resetting timers
 | |
|         lastDataPointTime = 0;
 | |
|         connectionsLastUpdate = 0;
 | |
|       };
 | |
| 
 | |
|       // Wire up button click handlers
 | |
|       const buttons = elementArg.querySelectorAll('dees-button');
 | |
|       buttons.forEach(button => {
 | |
|         const text = button.textContent?.trim();
 | |
|         if (text === 'System Usage') {
 | |
|           button.addEventListener('click', () => switchDataset('system'));
 | |
|         } else if (text === 'Network Traffic') {
 | |
|           button.addEventListener('click', () => switchDataset('network'));
 | |
|         } else if (text === 'Sales Data') {
 | |
|           button.addEventListener('click', () => switchDataset('sales'));
 | |
|         } else if (text === 'Start Live') {
 | |
|           button.addEventListener('click', () => startRealtime());
 | |
|         } else if (text === 'Stop Live') {
 | |
|           button.addEventListener('click', () => stopRealtime());
 | |
|         } else if (text === 'Spike Values') {
 | |
|           button.addEventListener('click', () => randomizeData());
 | |
|         }
 | |
|       });
 | |
|       
 | |
|       // Update button states based on current dataset
 | |
|       const updateButtonStates = () => {
 | |
|         const buttons = elementArg.querySelectorAll('dees-button');
 | |
|         buttons.forEach(button => {
 | |
|           const text = button.textContent?.trim();
 | |
|           if (text === 'System Usage') {
 | |
|             button.type = currentDataset === 'system' ? 'highlighted' : 'normal';
 | |
|           } else if (text === 'Network Traffic') {
 | |
|             button.type = currentDataset === 'network' ? 'highlighted' : 'normal';
 | |
|           } else if (text === 'Sales Data') {
 | |
|             button.type = currentDataset === 'sales' ? 'highlighted' : 'normal';
 | |
|           }
 | |
|         });
 | |
|       };
 | |
|       
 | |
|       // Configure main chart with rolling window
 | |
|       chartElement.rollingWindow = TIME_WINDOW;
 | |
|       chartElement.realtimeMode = false; // Will be enabled when starting live updates
 | |
|       chartElement.yAxisScaling = 'percentage'; // Initial system dataset uses percentage
 | |
|       chartElement.yAxisMax = 100;
 | |
|       chartElement.autoScrollInterval = 1000; // Auto-scroll every second
 | |
|       
 | |
|       // Set initial time window
 | |
|       setTimeout(() => {
 | |
|         chartElement.updateTimeWindow();
 | |
|       }, 100);
 | |
|       
 | |
|       // Update button states when dataset changes
 | |
|       const originalSwitchDataset = switchDataset;
 | |
|       const switchDatasetWithButtonUpdate = (name: string) => {
 | |
|         originalSwitchDataset(name);
 | |
|         updateButtonStates();
 | |
|       };
 | |
|       
 | |
|       // Replace switchDataset with the one that updates buttons
 | |
|       buttons.forEach(button => {
 | |
|         const text = button.textContent?.trim();
 | |
|         if (text === 'System Usage') {
 | |
|           button.removeEventListener('click', () => switchDataset('system'));
 | |
|           button.addEventListener('click', () => switchDatasetWithButtonUpdate('system'));
 | |
|         } else if (text === 'Network Traffic') {
 | |
|           button.removeEventListener('click', () => switchDataset('network'));
 | |
|           button.addEventListener('click', () => switchDatasetWithButtonUpdate('network'));
 | |
|         } else if (text === 'Sales Data') {
 | |
|           button.removeEventListener('click', () => switchDataset('sales'));
 | |
|           button.addEventListener('click', () => switchDatasetWithButtonUpdate('sales'));
 | |
|         }
 | |
|       });
 | |
|       
 | |
|       // Initialize connections chart with data
 | |
|       if (connectionsChartElement) {
 | |
|         const initialConnectionsData = generateInitialData(previousValues.connections, 30, UPDATE_INTERVAL);
 | |
|         connectionsChartElement.series = [{
 | |
|           name: 'Connections',
 | |
|           data: initialConnectionsData
 | |
|         }];
 | |
|         
 | |
|         // Configure connections chart
 | |
|         connectionsChartElement.rollingWindow = TIME_WINDOW;
 | |
|         connectionsChartElement.realtimeMode = false; // Will be enabled when starting live updates
 | |
|         connectionsChartElement.yAxisScaling = 'fixed';
 | |
|         connectionsChartElement.yAxisMax = 350;
 | |
|         connectionsChartElement.autoScrollInterval = 1000; // Auto-scroll every second
 | |
|         
 | |
|         // Set initial time window
 | |
|         setTimeout(() => {
 | |
|           connectionsChartElement.updateTimeWindow();
 | |
|         }, 100);
 | |
|       }
 | |
|     }}>
 | |
|       <style>
 | |
|         ${css`
 | |
|         .demoBox {
 | |
|           position: relative;
 | |
|           background: ${cssManager.bdTheme('hsl(0 0% 95%)', 'hsl(0 0% 9%)')};
 | |
|           height: 100%;
 | |
|           width: 100%;
 | |
|           padding: 40px;
 | |
|           box-sizing: border-box;
 | |
|           display: flex;
 | |
|           flex-direction: column;
 | |
|           gap: 24px;
 | |
|         }
 | |
|         
 | |
|         .controls {
 | |
|           display: flex;
 | |
|           flex-wrap: wrap;
 | |
|           gap: 12px;
 | |
|           margin-bottom: 8px;
 | |
|         }
 | |
|         
 | |
|         .chart-container {
 | |
|           flex: 1;
 | |
|           min-height: 400px;
 | |
|         }
 | |
|         
 | |
|         .info {
 | |
|           color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
 | |
|           font-size: 12px;
 | |
|           font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Geist Sans', sans-serif;
 | |
|           text-align: center;
 | |
|           margin-top: 8px;
 | |
|         }
 | |
|       `}
 | |
|     </style>
 | |
|     <div class="demoBox">
 | |
|       <div class="controls">
 | |
|         <dees-button-group label="Dataset:">
 | |
|           <dees-button type="highlighted">System Usage</dees-button>
 | |
|           <dees-button>Network Traffic</dees-button>
 | |
|           <dees-button>Sales Data</dees-button>
 | |
|         </dees-button-group>
 | |
|         
 | |
|         <dees-button-group label="Real-time:">
 | |
|           <dees-button>Start Live</dees-button>
 | |
|           <dees-button>Stop Live</dees-button>
 | |
|         </dees-button-group>
 | |
|         
 | |
|         <dees-button-group label="Actions:">
 | |
|           <dees-button>Spike Values</dees-button>
 | |
|         </dees-button-group>
 | |
|       </div>
 | |
|       
 | |
|       <div class="chart-container">
 | |
|         <dees-chart-area
 | |
|           id="main-chart"
 | |
|           .label=${initialDatasets.system.label}
 | |
|           .series=${initialDatasets.system.series}
 | |
|           .yAxisFormatter=${initialFormatters.system}
 | |
|         ></dees-chart-area>
 | |
|       </div>
 | |
|       
 | |
|       <div class="chart-container" style="margin-top: 20px;">
 | |
|         <dees-chart-area
 | |
|           id="connections-chart"
 | |
|           .label=${'Active Connections'}
 | |
|           .series=${[{
 | |
|             name: 'Connections',
 | |
|             data: [] as Array<{x: any; y: any}>
 | |
|           }]}
 | |
|           .yAxisFormatter=${(val: number) => `${val}`}
 | |
|         ></dees-chart-area>
 | |
|       </div>
 | |
|       
 | |
|       <div class="info">
 | |
|         Real-time monitoring with 2-minute rolling window • 
 | |
|         Updates every second with smooth value transitions • 
 | |
|         Click 'Spike Values' to simulate load spikes
 | |
|       </div>
 | |
|     </div>
 | |
|     </dees-demowrapper>
 | |
|   `;
 | |
| }; |