diff --git a/frontend/src/views/DashboardPage.tsx b/frontend/src/views/DashboardPage.tsx index 1d3a63e..7b22479 100644 --- a/frontend/src/views/DashboardPage.tsx +++ b/frontend/src/views/DashboardPage.tsx @@ -299,19 +299,37 @@ function resolveWidgetPlacement(widgets: DashboardWidget[], changed: DashboardWi const minSize = widgetMinSize(changed.type); const w = clampNumber(changed.w, minSize.w, gridColumns); const h = clampNumber(changed.h, minSize.h, 8); - let next = { + const desiredY = clampNumber(changed.y, 0, 80); + const next = { ...changed, w, h, x: clampNumber(changed.x, 0, gridColumns - w), - y: clampNumber(changed.y, 0, 80), + y: desiredY }; - while (widgets.some((widget) => widget.id !== next.id && overlaps(widget, next))) { - next = { ...next, y: next.y + 1 }; + const hasCollision = (y: number) => widgets.some((widget) => widget.id !== next.id && overlaps(widget, { ...next, y })); + + if (!hasCollision(desiredY)) { + return next; } - return next; + const maxExistingRow = Math.max(80, ...widgets.filter((widget) => widget.id !== next.id).map((widget) => widget.y + widget.h + h)); + + for (let distance = 1; distance <= maxExistingRow + h; distance += 1) { + const yAbove = desiredY - distance; + const yBelow = desiredY + distance; + + if (yAbove >= 0 && !hasCollision(yAbove)) { + return { ...next, y: yAbove }; + } + + if (!hasCollision(yBelow)) { + return { ...next, y: yBelow }; + } + } + + return { ...next, y: maxExistingRow + h }; } function placeWidget(widgets: DashboardWidget[], changed: DashboardWidget) {