diff --git a/src/systems/dashboard/dashboardIntegration.js b/src/systems/dashboard/dashboardIntegration.js index eaf198a..749bf8d 100644 --- a/src/systems/dashboard/dashboardIntegration.js +++ b/src/systems/dashboard/dashboardIntegration.js @@ -246,10 +246,20 @@ function setupDashboardEventListeners(dependencies) { // Auto-layout button const autoLayoutBtn = document.querySelector('#rpg-dashboard-auto-layout'); if (autoLayoutBtn) { - autoLayoutBtn.addEventListener('click', () => { + autoLayoutBtn.addEventListener('click', async () => { if (dashboardManager) { - console.log('[RPG Companion] Auto-layout button clicked'); - dashboardManager.autoLayoutWidgets(); + const confirmed = await showConfirmDialog({ + title: 'Auto-Arrange All Widgets?', + message: 'This will reorganize all widgets across all tabs and may change their positions. This action cannot be undone.', + variant: 'warning', + confirmText: 'Auto-Arrange', + cancelText: 'Cancel' + }); + + if (confirmed) { + console.log('[RPG Companion] Auto-layout button clicked'); + dashboardManager.autoLayoutWidgets(); + } } }); } diff --git a/src/systems/dashboard/dashboardManager.js b/src/systems/dashboard/dashboardManager.js index 296137f..73191ae 100644 --- a/src/systems/dashboard/dashboardManager.js +++ b/src/systems/dashboard/dashboardManager.js @@ -705,7 +705,7 @@ export class DashboardManager { }, { minW: definition.minSize.w, minH: definition.minSize.h - }); + }, allWidgets); // Add edit mode controls if (this.editManager) { @@ -1104,6 +1104,11 @@ export class DashboardManager { }); } + // Disable content editing if in edit mode + if (this.editManager && this.editManager.isEditMode) { + this.editManager.disableContentEditing(); + } + this.notifyChange('tabChanged', { tabId }); } @@ -1283,8 +1288,10 @@ export class DashboardManager { /** * Apply dashboard configuration * @param {Object} config - Dashboard configuration + * @param {Object} options - Optional parameters + * @param {boolean} options.skipInitialSwitch - Skip switching to first tab (caller will handle) */ - applyDashboardConfig(config) { + applyDashboardConfig(config, options = {}) { console.log('[DashboardManager] Applying dashboard config'); // Migrate emoji icons to Font Awesome @@ -1330,8 +1337,8 @@ export class DashboardManager { this.dashboard.defaultTab = this.dashboard.tabs[0].id; } - // Switch to first tab - if (config.tabs.length > 0) { + // Switch to first tab (unless caller will handle it) + if (!options.skipInitialSwitch && config.tabs.length > 0) { this.switchTab(config.tabs[0].id); } @@ -1418,7 +1425,8 @@ export class DashboardManager { }); await this.persistence.resetToDefault(this.defaultLayout); - this.applyDashboardConfig(this.defaultLayout); + // Skip initial switch in applyDashboardConfig since we'll switch after layout calculations + this.applyDashboardConfig(this.defaultLayout, { skipInitialSwitch: true }); // Reset all widgets to default sizes const allWidgets = []; diff --git a/src/systems/dashboard/editModeManager.js b/src/systems/dashboard/editModeManager.js index 6d58490..8040bd3 100644 --- a/src/systems/dashboard/editModeManager.js +++ b/src/systems/dashboard/editModeManager.js @@ -482,6 +482,9 @@ export class EditModeManager { } }); + // Ensure content editing is disabled for all widgets + this.disableContentEditing(); + console.log('[EditModeManager] Synced controls for', widgets.length, 'widgets'); } diff --git a/src/systems/dashboard/resizeHandler.js b/src/systems/dashboard/resizeHandler.js index e112c6c..715559c 100644 --- a/src/systems/dashboard/resizeHandler.js +++ b/src/systems/dashboard/resizeHandler.js @@ -71,8 +71,9 @@ export class ResizeHandler { * @param {Object} widget - Widget data object * @param {Function} onResizeEnd - Callback when resize completes (widget, newW, newH, newX, newY) * @param {Object} constraints - Size constraints {minW, minH, maxW, maxH} + * @param {Array} widgets - All widgets (for grid height calculation) */ - initWidget(element, widget, onResizeEnd, constraints = {}) { + initWidget(element, widget, onResizeEnd, constraints = {}, widgets = []) { // Create resize handles const handles = this.createResizeHandles(); @@ -112,7 +113,7 @@ export class ResizeHandler { } e.preventDefault(); e.stopPropagation(); - this.startResize(e, handleType, element, widget, onResizeEnd, widgetConstraints); + this.startResize(e, handleType, element, widget, onResizeEnd, widgetConstraints, widgets); }; const touchStartHandler = (e) => { @@ -123,7 +124,7 @@ export class ResizeHandler { this.touchTimer = setTimeout(() => { e.preventDefault(); e.stopPropagation(); - this.startResize(e.touches[0], handleType, element, widget, onResizeEnd, widgetConstraints); + this.startResize(e.touches[0], handleType, element, widget, onResizeEnd, widgetConstraints, widgets); }, this.options.touchDelay); }; @@ -255,8 +256,9 @@ export class ResizeHandler { * @param {Object} widget - Widget data * @param {Function} onResizeEnd - Callback when resize completes * @param {Object} constraints - Size constraints + * @param {Array} widgets - All widgets (for grid height calculation) */ - startResize(e, handleType, element, widget, onResizeEnd, constraints) { + startResize(e, handleType, element, widget, onResizeEnd, constraints, widgets = []) { // Create dimension overlay const overlay = this.createDimensionOverlay(); @@ -273,7 +275,8 @@ export class ResizeHandler { overlay, isResizing: true, onResizeEnd, - constraints + constraints, + widgets }; // Add event listeners @@ -551,13 +554,18 @@ export class ResizeHandler { showGridOverlay() { if (this.gridOverlay) return; + // Calculate actual grid height based on widget positions (returns rem) + const widgets = this.resizeState?.widgets || []; + const gridHeightRem = this.gridEngine.calculateGridHeight(widgets); + const gridHeightPx = this.gridEngine.remToPixels(gridHeightRem); + this.gridOverlay = document.createElement('div'); this.gridOverlay.className = 'grid-overlay'; this.gridOverlay.style.position = 'absolute'; this.gridOverlay.style.top = '0'; this.gridOverlay.style.left = '0'; this.gridOverlay.style.width = '100%'; - this.gridOverlay.style.height = '100%'; + this.gridOverlay.style.height = gridHeightPx + 'px'; this.gridOverlay.style.pointerEvents = 'none'; this.gridOverlay.style.zIndex = '9999'; @@ -584,19 +592,25 @@ export class ResizeHandler { highlightGridCells(x, y, w, h) { if (!this.gridOverlay) return; + // Clear previous highlights this.gridOverlay.innerHTML = ''; - const totalGaps = this.gridEngine.gap * (this.gridEngine.columns + 1); + // Convert rem to pixels for calculations + const gapPx = this.gridEngine.remToPixels(this.gridEngine.gap); + const rowHeightPx = this.gridEngine.remToPixels(this.gridEngine.rowHeight); + + // Calculate column width in pixels + const totalGaps = gapPx * (this.gridEngine.columns + 1); const colWidth = (this.gridEngine.containerWidth - totalGaps) / this.gridEngine.columns; for (let row = y; row < y + h; row++) { for (let col = x; col < x + w; col++) { const cell = document.createElement('div'); cell.style.position = 'absolute'; - cell.style.left = (col * (colWidth + this.gridEngine.gap) + this.gridEngine.gap) + 'px'; - cell.style.top = (row * (this.gridEngine.rowHeight + this.gridEngine.gap) + this.gridEngine.gap) + 'px'; + cell.style.left = (col * (colWidth + gapPx) + gapPx) + 'px'; + cell.style.top = (row * (rowHeightPx + gapPx) + gapPx) + 'px'; cell.style.width = colWidth + 'px'; - cell.style.height = this.gridEngine.rowHeight + 'px'; + cell.style.height = rowHeightPx + 'px'; cell.style.backgroundColor = 'rgba(78, 204, 163, 0.3)'; cell.style.border = '2px solid rgba(78, 204, 163, 0.6)'; cell.style.borderRadius = '4px'; diff --git a/style.css b/style.css index 55d149d..edf9d0d 100644 --- a/style.css +++ b/style.css @@ -1803,7 +1803,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld { } /* Prevent text selection in edit mode (especially important for mobile) */ -.edit-mode .rpg-widget-content { +.edit-mode .rpg-widget { user-select: none; -webkit-user-select: none; -moz-user-select: none; @@ -1811,6 +1811,11 @@ body:has(.rpg-panel.rpg-position-left) #sheld { -webkit-touch-callout: none; /* Prevent iOS callout menu */ } +/* Hide edit controls completely when not in edit mode */ +.rpg-dashboard-container:not(.edit-mode) .widget-edit-controls { + display: none !important; +} + /* Hide resize handles when widgets are locked */ .widgets-locked .resize-handles { opacity: 0 !important;