- Added DeesDashboardgrid class for managing a grid of dashboard widgets. - Implemented widget dragging and resizing capabilities. - Introduced layout management with collision detection and margin resolution. - Created styles for grid layout, widget appearance, and animations. - Added support for customizable margins, cell height, and grid lines. - Included methods for adding, removing, and updating widgets dynamically. - Implemented context menu for widget actions and keyboard navigation support. - Established a responsive design with breakpoint handling for different layouts.
106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
import type { DashboardWidget, GridCellMetrics } from './types.js';
|
|
|
|
export interface PointerPosition {
|
|
clientX: number;
|
|
clientY: number;
|
|
}
|
|
|
|
export interface DragComputationArgs {
|
|
pointer: PointerPosition;
|
|
containerRect: DOMRect;
|
|
metrics: GridCellMetrics;
|
|
columns: number;
|
|
widget: DashboardWidget;
|
|
rtl: boolean;
|
|
dragOffsetX?: number;
|
|
dragOffsetY?: number;
|
|
}
|
|
|
|
export const computeGridCoordinates = ({
|
|
pointer,
|
|
containerRect,
|
|
metrics,
|
|
columns,
|
|
widget,
|
|
rtl,
|
|
dragOffsetX = 0,
|
|
dragOffsetY = 0,
|
|
}: DragComputationArgs): { x: number; y: number } => {
|
|
const relativeX = pointer.clientX - containerRect.left - dragOffsetX;
|
|
const relativeY = pointer.clientY - containerRect.top - dragOffsetY;
|
|
|
|
const marginX = metrics.marginHorizontalPx;
|
|
const marginY = metrics.marginVerticalPx;
|
|
const cellWidth = metrics.cellWidthPx;
|
|
const cellHeight = metrics.cellHeightPx;
|
|
|
|
const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value));
|
|
|
|
const adjustedX = clamp(relativeX - marginX, 0, containerRect.width - marginX);
|
|
const adjustedY = clamp(relativeY - marginY, 0, Number.POSITIVE_INFINITY);
|
|
|
|
const cellPlusMarginX = cellWidth + marginX;
|
|
const cellPlusMarginY = cellHeight + marginY;
|
|
|
|
let gridX = Math.round(adjustedX / cellPlusMarginX);
|
|
if (rtl) {
|
|
gridX = columns - widget.w - gridX;
|
|
}
|
|
gridX = clamp(gridX, 0, columns - widget.w);
|
|
|
|
const gridY = clamp(Math.round(adjustedY / cellPlusMarginY), 0, Number.MAX_SAFE_INTEGER);
|
|
|
|
return { x: gridX, y: gridY };
|
|
};
|
|
|
|
export interface ResizeComputationArgs {
|
|
pointer: PointerPosition;
|
|
containerRect: DOMRect;
|
|
metrics: GridCellMetrics;
|
|
startWidth: number;
|
|
startHeight: number;
|
|
startPointer: PointerPosition;
|
|
handler: 'e' | 's' | 'se';
|
|
widget: DashboardWidget;
|
|
columns: number;
|
|
}
|
|
|
|
export const computeResizeDimensions = ({
|
|
pointer,
|
|
containerRect,
|
|
metrics,
|
|
startWidth,
|
|
startHeight,
|
|
startPointer,
|
|
handler,
|
|
widget,
|
|
columns,
|
|
}: ResizeComputationArgs): { width: number; height: number } => {
|
|
const deltaX = pointer.clientX - startPointer.clientX;
|
|
const deltaY = pointer.clientY - startPointer.clientY;
|
|
|
|
let width = startWidth;
|
|
let height = startHeight;
|
|
|
|
const cellPlusMarginX = metrics.cellWidthPx + metrics.marginHorizontalPx;
|
|
const cellPlusMarginY = metrics.cellHeightPx + metrics.marginVerticalPx;
|
|
|
|
if (handler.includes('e')) {
|
|
const deltaCols = Math.round(deltaX / cellPlusMarginX);
|
|
width = startWidth + deltaCols;
|
|
}
|
|
|
|
if (handler.includes('s')) {
|
|
const deltaRows = Math.round(deltaY / cellPlusMarginY);
|
|
height = startHeight + deltaRows;
|
|
}
|
|
|
|
const clampedWidth = Math.max(widget.minW || 1, Math.min(width, widget.maxW || columns - widget.x));
|
|
const clampedHeight = Math.max(widget.minH || 1, Math.min(height, widget.maxH || Number.MAX_SAFE_INTEGER));
|
|
|
|
return {
|
|
width: clampedWidth,
|
|
height: clampedHeight,
|
|
};
|
|
};
|