feat(dashboard): implement smart widget scaling and improved auto-layout

- Add resetWidgetSizesToDefault() to reset all widgets to default sizes before auto-arrange/reset
- Implement continuous expansion algorithm that fills available space up to maxAutoSize limits
- Add visible height detection to prevent widgets expanding beyond viewport (no forced scroll)
- Update all widget defaultSize and maxAutoSize for optimal 1x1 compact layouts
  - Info widgets (calendar, weather, temp, clock): 1x1 default, 1x2 max
  - Location: 2x2 max (was 3x3)
  - Characters: 3x5 max, moved to 'scene' category (eliminates Social tab)
  - User Info: 2x1 max (prevents expansion)
  - User Mood: 1x1 default and max (compact top-right placement)
  - User Attributes: 3x5 max (fills bottom space)
  - User Stats: 3x3 max
- Fix CSS scaling for 1x1 widgets
  - Replace viewport-based units with fixed rem values
  - Reduce icon/graphic sizes to fit with visible text
  - Add explicit gaps and padding for consistent spacing
  - Set line-height: 1 to prevent text overflow
- Reorganize default layout
  - Status tab: User Info (2x1) + Mood (1x1 top right) + Stats + Attributes
  - Scene tab: Info widgets (1x1) + Location + Characters (all on one tab)
  - Inventory tab: Full inventory widget

Auto-arrange and reset now properly size widgets to defaults and expand to fill
available space without exceeding visible area.
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-10-23 22:08:04 +11:00
parent f61e6390fb
commit 3dd7b017a6
10 changed files with 146 additions and 74 deletions
+38 -12
View File
@@ -435,10 +435,22 @@ export class GridEngine {
const preserveOrder = options.preserveOrder || false;
// Calculate maximum visible rows based on container height
let maxVisibleRows = 100; // Fallback
if (this.container) {
const containerHeight = this.container.clientHeight; // pixels
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize); // px per rem
const containerHeightRem = containerHeight / rootFontSize;
const rowHeightWithGap = this.rowHeight + this.gap;
maxVisibleRows = Math.floor(containerHeightRem / rowHeightWithGap);
console.log('[GridEngine] Container height:', containerHeight + 'px', '=', containerHeightRem.toFixed(2) + 'rem', '→', maxVisibleRows, 'rows');
}
console.log('[GridEngine] Auto-layout started:', {
widgetCount: widgets.length,
columns: this.columns,
preserveOrder
preserveOrder,
maxVisibleRows
});
// Sort widgets (or preserve input order for category-aware layout)
@@ -586,8 +598,8 @@ export class GridEngine {
return definition.maxAutoSize;
}
}
// Default max size if not specified (flexible expansion)
return { w: this.columns, h: 10 };
// Default max size if not specified (conservative expansion)
return { w: this.columns, h: 3 };
};
sortedForExpand.forEach(widget => {
@@ -595,9 +607,15 @@ export class GridEngine {
const originalW = widget.w;
const originalH = widget.h;
// Try expanding height first (fills vertical gaps)
// Try expanding height first (fills vertical gaps) - keep trying until maxSize or collision
let expandedH = false;
for (let tryH = originalH + 1; tryH <= Math.min(maxSize.h, originalH + 3); tryH++) {
for (let tryH = originalH + 1; tryH <= maxSize.h; tryH++) {
// Check if expansion would go beyond visible area
if (widget.y + tryH > maxVisibleRows) {
console.log(`[GridEngine] ${widget.id} cannot expand to h=${tryH} (would exceed visible area: row ${widget.y + tryH} > ${maxVisibleRows})`);
break;
}
// Clear current position
for (let row = widget.y; row < widget.y + widget.h; row++) {
for (let col = widget.x; col < widget.x + widget.w; col++) {
@@ -611,15 +629,19 @@ export class GridEngine {
markOccupied(widget, widget.x, widget.y, widget.w, tryH);
expandedH = true;
expandedCount++;
console.log(`[GridEngine] Expanded ${widget.id} height: ${originalH}${tryH}`);
break;
// Continue trying to expand further
} else {
// Re-mark original and try next size
// Hit a collision, stop expanding height
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
break;
}
}
// Try expanding width (fills horizontal gaps)
if (expandedH) {
console.log(`[GridEngine] Expanded ${widget.id} height: ${originalH}${widget.h}`);
}
// Try expanding width (fills horizontal gaps) - keep trying until maxSize or collision
let expandedW = false;
for (let tryW = originalW + 1; tryW <= Math.min(maxSize.w, this.columns); tryW++) {
// Clear current position
@@ -635,14 +657,18 @@ export class GridEngine {
markOccupied(widget, widget.x, widget.y, tryW, widget.h);
expandedW = true;
expandedCount++;
console.log(`[GridEngine] Expanded ${widget.id} width: ${originalW}${tryW}`);
break;
// Continue trying to expand further
} else {
// Re-mark original and try next size
// Hit a collision, stop expanding width
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
break;
}
}
if (expandedW) {
console.log(`[GridEngine] Expanded ${widget.id} width: ${originalW}${widget.w}`);
}
if (!expandedH && !expandedW) {
// Widget couldn't expand - ensure it's still marked in grid
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);