fix(dashboard): stabilize four-column widget placement

This commit is contained in:
2026-07-30 15:36:59 +02:00
parent f0732bead2
commit 49afc6d73d
10 changed files with 491 additions and 72 deletions
+19 -1
View File
@@ -3,6 +3,7 @@ import {
useLayoutEffect,
useRef,
useState,
type CSSProperties,
type HTMLAttributes,
type DragEvent as ReactDragEvent,
type ReactNode
@@ -23,6 +24,7 @@ import {
} from "@govoplan/core-webui";
import {
dashboardMasonryRowSpan,
dashboardWidgetColumnSpan,
defaultWidgetSize,
widgetIsConfigurable,
type DashboardWidgetPlacement
@@ -117,6 +119,7 @@ export default function DashboardGrid({
return (
<div
className={`dashboard-widget-grid${configuring ? " is-configuring" : ""}`}
data-dashboard-grid
onDragOver={(event) => {
if (!configuring || event.target !== event.currentTarget) return;
onDragOverEnd(event);
@@ -131,6 +134,7 @@ export default function DashboardGrid({
key={`catalogue-placeholder:${item.widgetId}`}
title={widget?.title ?? "New widget"}
size={item.size}
columnStart={item.columnStart}
onDragOver={(event) => event.preventDefault()}
onDrop={onDropPreview}
/>
@@ -145,6 +149,7 @@ export default function DashboardGrid({
key={placement.instanceId}
title={widget.title}
size={placement.size}
columnStart={placement.columnStart}
preserveHeight
onDragOver={(event) => event.preventDefault()}
onDrop={onDropPreview}
@@ -167,6 +172,7 @@ export default function DashboardGrid({
<DashboardMasonryItem
key={placement.instanceId}
className={`dashboard-widget dashboard-widget-${placement.size}`}
style={dashboardColumnStyle(placement.columnStart)}
onDragOver={
configuring
? (event) => onDragOver(event, placement.instanceId)
@@ -246,6 +252,7 @@ export default function DashboardGrid({
function DashboardDropPlaceholder({
title,
size,
columnStart,
preserveHeight = false,
onDragOver,
onDrop,
@@ -253,6 +260,7 @@ function DashboardDropPlaceholder({
}: {
title: string;
size: DashboardWidgetPlacement["size"];
columnStart: number;
preserveHeight?: boolean;
onDragOver: (event: ReactDragEvent<HTMLElement>) => void;
onDrop: (event: ReactDragEvent<HTMLElement>) => void;
@@ -268,9 +276,13 @@ function DashboardDropPlaceholder({
]
.filter(Boolean)
.join(" ")}
style={dashboardColumnStyle(columnStart)}
onDragOver={onDragOver}
onDrop={onDrop}
aria-label={`Place ${title} here`}
aria-label={
`Place ${title} in column ${columnStart}, spanning `
+ `${dashboardWidgetColumnSpan(size)} columns`
}
>
{children && (
<div className="dashboard-widget-placeholder-content">
@@ -285,6 +297,12 @@ function DashboardDropPlaceholder({
);
}
function dashboardColumnStyle(columnStart: number): CSSProperties {
return {
"--dashboard-column-start": columnStart
} as CSSProperties;
}
function DashboardMasonryItem({
children,
...props