feat(dashboard): Widget-Reihenfolge per Drag-and-Drop anpassbar

Config-Schema um order-Feld erweitert.
Bestehende Configs werden automatisch migriert.
Drag-and-Drop zusätzlich zu Up/Down-Buttons im Customize-Modal.
This commit is contained in:
Ulas Kalayci
2026-04-27 22:27:59 +02:00
parent a66bd2b05c
commit 218282875c
2 changed files with 44 additions and 2 deletions
+30 -2
View File
@@ -112,7 +112,7 @@ function showOnboarding(appContainer) {
const WIDGET_IDS = ['weather', 'tasks', 'calendar', 'birthdays', 'budget', 'family', 'shopping', 'meals', 'notes'];
const DEFAULT_WIDGET_CONFIG = WIDGET_IDS.map((id) => ({ id, visible: true }));
const DEFAULT_WIDGET_CONFIG = WIDGET_IDS.map((id, i) => ({ id, visible: true, order: i }));
function widgetLabel(id) {
const map = {
@@ -869,6 +869,33 @@ function openCustomizeModal(currentConfig, onSave) {
} else if (dir === 'down' && idx < draft.length - 1) {
[draft[idx], draft[idx + 1]] = [draft[idx + 1], draft[idx]];
}
draft.forEach((w, i) => { w.order = i; });
rebuildList();
});
});
list.querySelectorAll('.customize-row').forEach((row, idx) => {
row.setAttribute('draggable', 'true');
row.addEventListener('dragstart', (e) => {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', String(idx));
row.classList.add('customize-row--dragging');
});
row.addEventListener('dragend', () => row.classList.remove('customize-row--dragging'));
row.addEventListener('dragover', (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
row.classList.add('customize-row--over');
});
row.addEventListener('dragleave', () => row.classList.remove('customize-row--over'));
row.addEventListener('drop', (e) => {
e.preventDefault();
row.classList.remove('customize-row--over');
const fromIdx = parseInt(e.dataTransfer.getData('text/plain'), 10);
if (fromIdx === idx) return;
const [moved] = draft.splice(fromIdx, 1);
draft.splice(idx, 0, moved);
draft.forEach((w, i) => { w.order = i; });
rebuildList();
});
});
@@ -996,7 +1023,8 @@ export async function render(container, { user }) {
]);
data = dashRes;
weather = weatherRes.data ?? null;
widgetConfig = prefsRes.data?.dashboard_widgets ?? DEFAULT_WIDGET_CONFIG;
const raw = prefsRes.data?.dashboard_widgets ?? DEFAULT_WIDGET_CONFIG;
widgetConfig = raw.map((w, i) => ({ order: i, ...w })).sort((a, b) => a.order - b.order);
currency = prefsRes.data?.currency ?? 'EUR';
} catch (err) {
console.error('[Dashboard] Ladefehler:', err.message, 'Status:', err.status ?? 'network');
+14
View File
@@ -1266,6 +1266,20 @@
background-color: var(--color-surface-hover);
}
.customize-row[draggable="true"] {
cursor: grab;
}
.customize-row--dragging {
opacity: 0.4;
}
.customize-row--over {
background-color: var(--color-surface-3);
outline: 1px dashed var(--color-border);
outline-offset: -1px;
}
.customize-row__toggle {
position: relative;
display: inline-flex;