feat(dashboard): implement smart auto-layout with expansion and better defaults
This commit implements 5 major improvements to the dashboard layout system:
**1. Improved Default Layout (defaultLayout.js)**
- Changed from 2 tabs to 3 tabs for better organization:
- Tab 1 (Status): User widgets only (userInfo, userStats, userMood, userAttributes)
- Tab 2 (Scene): Scene widgets + characters (calendar, weather, temp, clock, location, presentCharacters)
- Tab 3 (Inventory): Full inventory widget
- Cleaner separation prevents cramming all widgets on one tab
**2. Widget Max Size Limits (widget definition files)**
- Added maxAutoSize property to all widgets (enforced only during auto-arrange):
- Info widgets (calendar, weather, temp, clock): { w: 2, h: 3 }
- Location: { w: 3, h: 3 }
- presentCharacters: { w: 3, h: 6 } (can expand significantly)
- Inventory: { w: 3, h: 8 } (full tab)
- Prevents blind expansion while allowing intelligent space filling
**3. Smart Expansion Algorithm (gridEngine.js)**
- Added expansion pass after compaction in autoLayout():
- Sorts widgets top-to-bottom, left-to-right
- Tries to expand height first (fills vertical gaps)
- Then tries to expand width (fills horizontal gaps)
- Respects maxAutoSize limits from widget definitions
- Only expands if no collision with other widgets
- Widgets now fill available space instead of staying at default sizes
- Example: presentCharacters expands from 2x3 to 3x6 when space available
**4. Auto-Reflow on Column Change (dashboardManager.js)**
- Modified onColumnsChange callback to auto-layout after column count changes
- When grid transitions (2→3 or 3→2), automatically reflo ws widgets
- Prevents overlap and optimizes for new column count
- User experience: seamless adaptation when console opens/closes
**5. Fixed Grid Height/Scrollbar CSS (style.css)**
- Added flex: 1, overflow-y: auto, min-height: 0 to .rpg-dashboard-grid
- Grid now properly fills available space in dashboard container
- Accounts for bottom buttons (manual update, settings)
- Prevents "fingernail of extra height" that caused scrollbars
**Technical Changes:**
- Passed widget registry to GridEngine for maxAutoSize lookups
- getWidgetMaxSize() helper looks up definitions from registry
- Moved registry initialization before GridEngine construction
- Grid now uses flexbox to fill available vertical space
**User-Facing Improvements:**
- Reset layout creates logical 3-tab structure from the start
- Auto-arrange expands widgets to fill available space intelligently
- Resizing window/console automatically reflows layout
- No more unwanted scrollbars from slight overflow
Fixes cramped layouts, underutilized space, and scrollbar issues.
This commit is contained in:
@@ -26,6 +26,9 @@ export class GridEngine {
|
||||
this.snapToGrid = config.snapToGrid !== false;
|
||||
this.container = config.container || null;
|
||||
|
||||
// Widget registry for accessing widget definitions (e.g., maxAutoSize)
|
||||
this.registry = config.registry || null;
|
||||
|
||||
// Container width will be set dynamically
|
||||
this.containerWidth = 0;
|
||||
|
||||
@@ -562,7 +565,92 @@ export class GridEngine {
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[GridEngine] Auto-layout complete (compacted ${compactedCount} widgets)`);
|
||||
console.log(`[GridEngine] Compaction complete (${compactedCount} widgets moved up)`);
|
||||
|
||||
// Expansion pass: Try to expand widgets to fill available space
|
||||
console.log('[GridEngine] Expanding widgets to fill available space...');
|
||||
let expandedCount = 0;
|
||||
|
||||
// Sort widgets by position (top-to-bottom, left-to-right) for orderly expansion
|
||||
const sortedForExpand = [...sorted].sort((a, b) => {
|
||||
if (a.y !== b.y) return a.y - b.y; // Top to bottom
|
||||
return a.x - b.x; // Left to right
|
||||
});
|
||||
|
||||
// Helper to get widget max size from registry
|
||||
const getWidgetMaxSize = (widget) => {
|
||||
// Try to get widget definition from registry
|
||||
if (this.registry && widget.type) {
|
||||
const definition = this.registry.get(widget.type);
|
||||
if (definition && definition.maxAutoSize) {
|
||||
return definition.maxAutoSize;
|
||||
}
|
||||
}
|
||||
// Default max size if not specified (flexible expansion)
|
||||
return { w: this.columns, h: 10 };
|
||||
};
|
||||
|
||||
sortedForExpand.forEach(widget => {
|
||||
const maxSize = getWidgetMaxSize(widget);
|
||||
const originalW = widget.w;
|
||||
const originalH = widget.h;
|
||||
|
||||
// Try expanding height first (fills vertical gaps)
|
||||
let expandedH = false;
|
||||
for (let tryH = originalH + 1; tryH <= Math.min(maxSize.h, originalH + 3); tryH++) {
|
||||
// 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++) {
|
||||
occupied.delete(`${col},${row}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if expanded height is free
|
||||
if (isFree(widget.x, widget.y, widget.w, tryH)) {
|
||||
widget.h = tryH;
|
||||
markOccupied(widget, widget.x, widget.y, widget.w, tryH);
|
||||
expandedH = true;
|
||||
expandedCount++;
|
||||
console.log(`[GridEngine] Expanded ${widget.id} height: ${originalH} → ${tryH}`);
|
||||
break;
|
||||
} else {
|
||||
// Re-mark original and try next size
|
||||
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
||||
}
|
||||
}
|
||||
|
||||
// Try expanding width (fills horizontal gaps)
|
||||
let expandedW = false;
|
||||
for (let tryW = originalW + 1; tryW <= Math.min(maxSize.w, this.columns); tryW++) {
|
||||
// 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++) {
|
||||
occupied.delete(`${col},${row}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if expanded width is free
|
||||
if (isFree(widget.x, widget.y, tryW, widget.h)) {
|
||||
widget.w = tryW;
|
||||
markOccupied(widget, widget.x, widget.y, tryW, widget.h);
|
||||
expandedW = true;
|
||||
expandedCount++;
|
||||
console.log(`[GridEngine] Expanded ${widget.id} width: ${originalW} → ${tryW}`);
|
||||
break;
|
||||
} else {
|
||||
// Re-mark original and try next size
|
||||
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
||||
}
|
||||
}
|
||||
|
||||
if (!expandedH && !expandedW) {
|
||||
// Widget couldn't expand - ensure it's still marked in grid
|
||||
markOccupied(widget, widget.x, widget.y, widget.w, widget.h);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[GridEngine] Expansion complete (${expandedCount} expansions made)`);
|
||||
console.log(`[GridEngine] Auto-layout complete`);
|
||||
return widgets;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user