feat(dashboard): add auto-layout button with smart widget packing

Implements intelligent auto-layout system that efficiently arranges widgets to maximize space usage while respecting panel width constraints.

**Key Features:**
- Smart packing algorithm that sorts by widget area and finds optimal positions
- Respects responsive column count (2-4 columns based on panel width)
- Prefers full-width widgets when possible to eliminate gaps
- Fallback to narrower widths for better vertical packing
- Maintains minimum widget sizes

**Implementation:**
- GridEngine.autoLayout() - Core packing algorithm with collision detection
- DashboardManager.autoLayoutWidgets() - High-level API that re-renders after layout
- Auto-Arrange button in dashboard header (uses fa-table-cells-large icon)
- Event handler wired to call autoLayoutWidgets with preferFullWidth=true

**Algorithm Strategy:**
1. Sort widgets by area (largest first) for efficient packing
2. For each widget, try full-width placement first
3. Find first available position using row-by-row scan
4. If position is too far down, try narrower widths
5. Mark cells as occupied to prevent overlaps

**Testing Notes:**
- Works with current responsive column system (2-4 columns)
- Respects minimum sizes and column constraints
- Re-renders all widgets after repositioning
- Auto-saves layout changes

Part of Epic 2: Dashboard Widget Library
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-10-23 14:00:00 +11:00
parent e32a008f0b
commit 122bb3194a
13 changed files with 668 additions and 87 deletions
+62 -13
View File
@@ -8,10 +8,13 @@
/**
* Generate default dashboard configuration
*
* Creates a two-tab layout:
* - "Status" tab: User stats, info box, present characters
* Creates a two-tab layout optimized for 2-column side panel:
* - "Status" tab: User stats, modular info widgets (calendar, weather, temp, clock, location), present characters
* - "Inventory" tab: Full inventory widget
*
* All positions sized for 2-column grid (w: 1-2, full width = 2).
* Layout will adapt if panel width increases to 3-4 columns.
*
* @returns {Object} Default dashboard configuration
*/
export function generateDefaultDashboard() {
@@ -19,7 +22,8 @@ export function generateDefaultDashboard() {
version: 2,
gridConfig: {
columns: 12,
// Columns calculated dynamically by GridEngine (2-4 based on panel width)
// Mobile: always 2, Desktop: 2-4 based on width
rowHeight: 80,
gap: 12,
snapToGrid: true,
@@ -33,35 +37,80 @@ export function generateDefaultDashboard() {
icon: '📊',
order: 0,
widgets: [
// Row 1: User Stats (full width)
{
id: 'widget-userstats',
type: 'userStats',
x: 0,
y: 0,
w: 6,
w: 2,
h: 3,
config: {
showClassicStats: true,
statBarStyle: 'gradient'
}
},
// Row 2: Calendar (left) + Weather (right)
{
id: 'widget-infobox',
type: 'infoBox',
x: 6,
y: 0,
w: 6,
id: 'widget-calendar',
type: 'calendar',
x: 0,
y: 3,
w: 1,
h: 2,
config: {}
},
{
id: 'widget-weather',
type: 'weather',
x: 1,
y: 3,
w: 1,
h: 2,
config: {
layout: 'horizontal'
compact: false
}
},
// Row 3: Temperature (left) + Clock (right)
{
id: 'widget-temperature',
type: 'temperature',
x: 0,
y: 5,
w: 1,
h: 2,
config: {
unit: 'celsius'
}
},
{
id: 'widget-clock',
type: 'clock',
x: 1,
y: 5,
w: 1,
h: 2,
config: {
format: 'digital'
}
},
// Row 4: Location (full width)
{
id: 'widget-location',
type: 'location',
x: 0,
y: 7,
w: 2,
h: 2,
config: {}
},
// Row 5-6: Present Characters (full width)
{
id: 'widget-presentchars',
type: 'presentCharacters',
x: 0,
y: 3,
w: 12,
y: 9,
w: 2,
h: 3,
config: {
cardLayout: 'grid',
@@ -81,7 +130,7 @@ export function generateDefaultDashboard() {
type: 'inventory',
x: 0,
y: 0,
w: 12,
w: 2,
h: 6,
config: {
defaultSubTab: 'onPerson',