feat: enhance ResponsiveGridRenderer with row margin calculations

- Added rowMinY and rowMaxBottom properties to ProcessedRow for improved layout calculations.
- Implemented dynamic margin adjustments between rows in the ResponsiveGridRenderer to enhance visual spacing.
- Refactored TabsWidget to streamline the ResponsiveGridRenderer integration, removing unnecessary wrapper divs for cleaner structure.
- Introduced ScaledCustomPanel for better handling of component rendering in split panel layouts.

Made-with: Cursor
This commit is contained in:
kjs
2026-03-12 14:19:48 +09:00
parent 966191786a
commit df47c27b77
7 changed files with 261 additions and 139 deletions

View File

@@ -109,6 +109,8 @@ interface ProcessedRow {
mainComponent?: ComponentData;
overlayComps: ComponentData[];
normalComps: ComponentData[];
rowMinY?: number;
rowMaxBottom?: number;
}
function FullWidthOverlayRow({
@@ -227,6 +229,10 @@ export function ResponsiveGridRenderer({
}
}
const allComps = [...fullWidthComps, ...normalComps];
const rowMinY = allComps.length > 0 ? Math.min(...allComps.map(c => c.position.y)) : 0;
const rowMaxBottom = allComps.length > 0 ? Math.max(...allComps.map(c => c.position.y + (c.size?.height || 40))) : 0;
if (fullWidthComps.length > 0 && normalComps.length > 0) {
for (const fwComp of fullWidthComps) {
processedRows.push({
@@ -234,6 +240,8 @@ export function ResponsiveGridRenderer({
mainComponent: fwComp,
overlayComps: normalComps,
normalComps: [],
rowMinY,
rowMaxBottom,
});
}
} else if (fullWidthComps.length > 0) {
@@ -243,6 +251,8 @@ export function ResponsiveGridRenderer({
mainComponent: fwComp,
overlayComps: [],
normalComps: [],
rowMinY,
rowMaxBottom,
});
}
} else {
@@ -250,6 +260,8 @@ export function ResponsiveGridRenderer({
type: "normal",
overlayComps: [],
normalComps,
rowMinY,
rowMaxBottom,
});
}
}
@@ -261,15 +273,26 @@ export function ResponsiveGridRenderer({
style={{ minHeight: "200px" }}
>
{processedRows.map((processedRow, rowIndex) => {
const rowMarginTop = (() => {
if (rowIndex === 0) return 0;
const prevRow = processedRows[rowIndex - 1];
const prevBottom = prevRow.rowMaxBottom ?? 0;
const currTop = processedRow.rowMinY ?? 0;
const designGap = currTop - prevBottom;
if (designGap <= 0) return 0;
return Math.min(Math.max(Math.round(designGap * 0.5), 4), 48);
})();
if (processedRow.type === "fullwidth" && processedRow.mainComponent) {
return (
<FullWidthOverlayRow
key={`row-${rowIndex}`}
main={processedRow.mainComponent}
overlayComps={processedRow.overlayComps}
canvasWidth={canvasWidth}
renderComponent={renderComponent}
/>
<div key={`row-${rowIndex}`} style={{ marginTop: rowMarginTop > 0 ? `${rowMarginTop}px` : undefined }}>
<FullWidthOverlayRow
main={processedRow.mainComponent}
overlayComps={processedRow.overlayComps}
canvasWidth={canvasWidth}
renderComponent={renderComponent}
/>
</div>
);
}
@@ -290,7 +313,7 @@ export function ResponsiveGridRenderer({
allButtons && "justify-end px-2 py-1",
hasFlexHeightComp ? "min-h-0 flex-1" : "flex-shrink-0"
)}
style={{ gap: `${gap}px` }}
style={{ gap: `${gap}px`, marginTop: rowMarginTop > 0 ? `${rowMarginTop}px` : undefined }}
>
{normalComps.map((component) => {
const typeId = getComponentTypeId(component);
@@ -337,10 +360,10 @@ export function ResponsiveGridRenderer({
flexGrow: 1,
flexShrink: 1,
minWidth: isMobile ? "100%" : undefined,
minHeight: useFlexHeight ? "300px" : undefined,
height: useFlexHeight ? "100%" : (component.size?.height
minHeight: useFlexHeight ? "300px" : (component.size?.height
? `${component.size.height}px`
: "auto"),
: undefined),
height: useFlexHeight ? "100%" : "auto",
}}
>
{renderComponent(component)}