fix(dashboard): correct auto-layout boundary check to eliminate empty space at bottom

- Changed boundary check from >= to > to allow widgets to properly fill viewport
- Updated viewport calculation to use grid container's clientHeight directly
- Added gap compensation in row calculation to account for last row having no trailing gap
- Widgets now expand to use all available vertical space without leaving unused rows

The issue was that y + h represents the row AFTER the widget ends, not the last
occupied row, so >= was too conservative. With maxVisibleRows=7 (rows 0-6), a
widget at y=3 can now expand to h=4 (rows 3,4,5,6) instead of being blocked.
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-10-26 16:45:49 +11:00
parent 6af499b07a
commit bd56f24c45
+10 -9
View File
@@ -439,17 +439,18 @@ export class GridEngine {
const preserveOrder = options.preserveOrder || false; const preserveOrder = options.preserveOrder || false;
// Calculate maximum visible rows based on VISIBLE viewport height (not scrollable container height) // Calculate maximum visible rows based on grid container's actual viewport height
let maxVisibleRows = 100; // Fallback let maxVisibleRows = 100; // Fallback
if (this.container) { if (this.container) {
// Use parent container height (visible viewport) instead of scrollable container height // Use grid container's own clientHeight (actual visible viewport area)
// The grid container has overflow-y: auto, so clientHeight would return scrollable area // Don't use parentElement which includes the header (tabs + buttons)
const viewportElement = this.container.parentElement || this.container; const viewportHeight = this.container.clientHeight; // pixels
const viewportHeight = viewportElement.clientHeight; // pixels
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize); // px per rem const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize); // px per rem
const viewportHeightRem = viewportHeight / rootFontSize; const viewportHeightRem = viewportHeight / rootFontSize;
const rowHeightWithGap = this.rowHeight + this.gap; const rowHeightWithGap = this.rowHeight + this.gap;
maxVisibleRows = Math.floor(viewportHeightRem / rowHeightWithGap); // Add gap to calculation because last row doesn't need trailing gap
// Formula: (height + gap) / (rowHeight + gap) accounts for N rows with N-1 gaps
maxVisibleRows = Math.floor((viewportHeightRem + this.gap) / rowHeightWithGap);
console.log('[GridEngine] Viewport height:', viewportHeight + 'px', '=', viewportHeightRem.toFixed(2) + 'rem', '→', maxVisibleRows, 'visible rows'); console.log('[GridEngine] Viewport height:', viewportHeight + 'px', '=', viewportHeightRem.toFixed(2) + 'rem', '→', maxVisibleRows, 'visible rows');
} }
@@ -623,9 +624,9 @@ export class GridEngine {
let expandedH = false; let expandedH = false;
for (let tryH = originalH + 1; tryH <= maxSize.h; tryH++) { for (let tryH = originalH + 1; tryH <= maxSize.h; tryH++) {
// Check if expansion would go beyond visible area // Check if expansion would go beyond visible area
// Use >= because row indices are 0-based (8 rows = indices 0-7, so row 8 is out of bounds) // y + h represents the row AFTER the widget ends, so > check (not >=) is correct
if (widget.y + tryH >= maxVisibleRows) { if (widget.y + tryH > maxVisibleRows) {
console.log(`[GridEngine] ${widget.id} cannot expand to h=${tryH} (would exceed visible area: row ${widget.y + tryH} >= ${maxVisibleRows})`); console.log(`[GridEngine] ${widget.id} cannot expand to h=${tryH} (would exceed visible area: row ${widget.y + tryH} > ${maxVisibleRows})`);
break; break;
} }