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:
@@ -191,8 +191,8 @@ export function registerCalendarWidget(registry, dependencies) {
|
||||
name: 'Calendar',
|
||||
icon: '📅',
|
||||
description: 'Date, weekday, month, and year display',
|
||||
minSize: { w: 2, h: 2 },
|
||||
defaultSize: { w: 2, h: 2 },
|
||||
minSize: { w: 1, h: 2 },
|
||||
defaultSize: { w: 1, h: 2 },
|
||||
requiresSchema: false,
|
||||
|
||||
render(container, config = {}) {
|
||||
@@ -277,8 +277,8 @@ export function registerWeatherWidget(registry, dependencies) {
|
||||
name: 'Weather',
|
||||
icon: '🌤️',
|
||||
description: 'Weather emoji and forecast',
|
||||
minSize: { w: 2, h: 2 },
|
||||
defaultSize: { w: 3, h: 2 },
|
||||
minSize: { w: 1, h: 2 },
|
||||
defaultSize: { w: 1, h: 2 },
|
||||
requiresSchema: false,
|
||||
|
||||
render(container, config = {}) {
|
||||
@@ -309,8 +309,8 @@ export function registerTemperatureWidget(registry, dependencies) {
|
||||
name: 'Temperature',
|
||||
icon: '🌡️',
|
||||
description: 'Temperature display with thermometer',
|
||||
minSize: { w: 2, h: 2 },
|
||||
defaultSize: { w: 2, h: 2 },
|
||||
minSize: { w: 1, h: 2 },
|
||||
defaultSize: { w: 1, h: 2 },
|
||||
requiresSchema: false,
|
||||
|
||||
render(container, config = {}) {
|
||||
@@ -348,8 +348,8 @@ export function registerClockWidget(registry, dependencies) {
|
||||
name: 'Clock',
|
||||
icon: '🕐',
|
||||
description: 'Analog clock with time display',
|
||||
minSize: { w: 2, h: 2 },
|
||||
defaultSize: { w: 2, h: 2 },
|
||||
minSize: { w: 1, h: 2 },
|
||||
defaultSize: { w: 1, h: 2 },
|
||||
requiresSchema: false,
|
||||
|
||||
render(container, config = {}) {
|
||||
@@ -396,8 +396,8 @@ export function registerLocationWidget(registry, dependencies) {
|
||||
name: 'Location',
|
||||
icon: '📍',
|
||||
description: 'Map with location display',
|
||||
minSize: { w: 3, h: 2 },
|
||||
defaultSize: { w: 6, h: 2 },
|
||||
minSize: { w: 2, h: 2 },
|
||||
defaultSize: { w: 2, h: 2 },
|
||||
requiresSchema: false,
|
||||
|
||||
render(container, config = {}) {
|
||||
|
||||
@@ -62,8 +62,8 @@ export function registerInventoryWidget(registry, dependencies) {
|
||||
name: 'Inventory',
|
||||
icon: '🎒',
|
||||
description: 'Full inventory system with On Person, Stored, and Assets',
|
||||
minSize: { w: 6, h: 4 },
|
||||
defaultSize: { w: 8, h: 6 },
|
||||
minSize: { w: 2, h: 4 },
|
||||
defaultSize: { w: 2, h: 6 },
|
||||
requiresSchema: false,
|
||||
|
||||
render(container, config = {}) {
|
||||
|
||||
@@ -235,8 +235,8 @@ export function registerPresentCharactersWidget(registry, dependencies) {
|
||||
name: 'Present Characters',
|
||||
icon: '👥',
|
||||
description: 'Character cards with avatars, traits, and relationships',
|
||||
minSize: { w: 4, h: 3 },
|
||||
defaultSize: { w: 6, h: 4 },
|
||||
minSize: { w: 2, h: 2 },
|
||||
defaultSize: { w: 2, h: 3 },
|
||||
requiresSchema: false,
|
||||
|
||||
render(container, config = {}) {
|
||||
|
||||
@@ -35,8 +35,8 @@ export function registerUserStatsWidget(registry, dependencies) {
|
||||
name: 'User Stats',
|
||||
icon: '❤️',
|
||||
description: 'Health, energy, satiety bars and classic RPG stats',
|
||||
minSize: { w: 4, h: 3 },
|
||||
defaultSize: { w: 6, h: 4 },
|
||||
minSize: { w: 1, h: 2 },
|
||||
defaultSize: { w: 2, h: 3 },
|
||||
requiresSchema: false,
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user