From 164833651154fe31cc31a3579ef5cc74d9144e17 Mon Sep 17 00:00:00 2001 From: NW Date: Mon, 6 Jul 2026 19:22:22 +0100 Subject: [PATCH] fix(admin/dashboard): restore layout BEFORE SortableJS init - Reorder DOM elements from localStorage BEFORE initializing SortableJS - Initialize Sortable AFTER layout restoration so it tracks correct DOM - Add console.log for save/restore debugging --- src/admin/views/dashboard.ejs | 86 ++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 27 deletions(-) diff --git a/src/admin/views/dashboard.ejs b/src/admin/views/dashboard.ejs index 66ea7f0..2bffc8a 100644 --- a/src/admin/views/dashboard.ejs +++ b/src/admin/views/dashboard.ejs @@ -435,10 +435,65 @@ // ===== SortableJS: Draggable Panels with localStorage ===== (function() { + var STORAGE_KEY = 'dashboardLayout'; var rows = document.querySelectorAll('.main-content > .row'); - rows.forEach(function(row, rowIndex) { + + // === STEP 1: Restore saved layout FIRST (before Sortable init) === + var saved = localStorage.getItem(STORAGE_KEY); + if (saved) { + try { + var layout = JSON.parse(saved); + console.log('[Dashboard] Restoring layout:', layout); + + // Build flat map of all panels across all rows + var allCols = []; + rows.forEach(function(row) { + allCols = allCols.concat(Array.from(row.children)); + }); + + var panelMap = {}; + allCols.forEach(function(col) { + var panel = col.querySelector('.panel'); + if (panel && panel.dataset.panelId) { + panelMap[panel.dataset.panelId] = col; + } + }); + + // Clear all rows first + rows.forEach(function(row) { + while (row.firstChild) { + row.removeChild(row.firstChild); + } + }); + + // Re-append columns into correct rows based on saved layout + rows.forEach(function(row, rowIndex) { + var order = layout['row' + rowIndex]; + if (!order || !order.length) return; + order.forEach(function(panelId) { + var col = panelMap[panelId]; + if (col) { + row.appendChild(col); + delete panelMap[panelId]; // mark as placed + } + }); + }); + + // Any panels not placed (new or removed from layout) go back to first row + Object.values(panelMap).forEach(function(col) { + if (rows[0]) rows[0].appendChild(col); + }); + + console.log('[Dashboard] Layout restored successfully'); + } catch(e) { + console.error('[Dashboard] Failed to restore layout:', e); + } + } + + // === STEP 2: Initialize Sortable AFTER layout is restored === + rows.forEach(function(row) { new Sortable(row, { - group: 'dashboard-row-' + rowIndex, + group: 'dashboard-panels', handle: '.panel-hdr', animation: 150, ghostClass: 'sortable-ghost', @@ -450,34 +505,11 @@ return panel ? panel.dataset.panelId : null; }).filter(Boolean); }); - localStorage.setItem('dashboardLayout', JSON.stringify(layout)); + localStorage.setItem(STORAGE_KEY, JSON.stringify(layout)); + console.log('[Dashboard] Layout saved:', layout); } }); }); - - // Restore saved layout - var saved = localStorage.getItem('dashboardLayout'); - if (saved) { - try { - var layout = JSON.parse(saved); - rows.forEach(function(row, rowIndex) { - var order = layout['row' + rowIndex]; - if (!order || !order.length) return; - var children = Array.from(row.children); - var panelMap = {}; - children.forEach(function(col) { - var panel = col.querySelector('.panel'); - if (panel && panel.dataset.panelId) { - panelMap[panel.dataset.panelId] = col; - } - }); - order.forEach(function(panelId) { - var col = panelMap[panelId]; - if (col) row.appendChild(col); - }); - }); - } catch(e) {} - } })(); })();