diff --git a/planner.php b/planner.php index 7cdf42a..4790d1a 100644 --- a/planner.php +++ b/planner.php @@ -579,39 +579,53 @@ for ($h = $startHour; $h <= $endHour; $h++) { default => 'lg:col-span-6' }; ?> -
- -
-
-
- - -
+
+ +
+ +
+ +
-
- -
- - - - + +
+ +
+ + + +
- + - - -
- -
+ +
@@ -1970,14 +1984,14 @@ function setWidgetSpan(wId, span) { wrapper.classList.add(`lg:col-span-${span}`); wrapper.setAttribute('data-col-span', span); - // Knoppen styling bijwerken binnen deze widget + // Knoppen styling bijwerken binnen het instellingen dropdown menu const buttons = wrapper.querySelectorAll('.widget-span-btn'); buttons.forEach(btn => { const bSpan = parseInt(btn.getAttribute('data-span'), 10); if (bSpan === span) { - btn.className = "widget-span-btn px-1.5 py-0.5 rounded text-[10px] font-bold transition bg-indigo-600 text-white shadow-2xs"; + btn.className = "widget-span-btn py-1 text-center text-[11px] font-bold rounded-lg border transition cursor-pointer bg-indigo-600 border-indigo-600 text-white shadow-2xs"; } else { - btn.className = "widget-span-btn px-1.5 py-0.5 rounded text-[10px] font-bold transition text-slate-500 hover:text-slate-800 dark:hover:text-slate-200"; + btn.className = "widget-span-btn py-1 text-center text-[11px] font-bold rounded-lg border transition cursor-pointer bg-slate-50 dark:bg-slate-800/80 border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700"; } }); @@ -1987,6 +2001,9 @@ function setWidgetSpan(wId, span) { item.col_span = span; } + // Sluit het instellingen menu + document.getElementById(`widgetSettingsMenu_${wId}`)?.classList.add('hidden'); + // Trigger resize voor SVG en diagrammen window.dispatchEvent(new Event('resize')); @@ -2002,6 +2019,22 @@ function setWidgetSpan(wId, span) { showWidgetToast(`Formaat aangepast naar ${spanDescriptions[span] || span + ' kolommen'}`, 'success'); } +// --- Widget Instellingen Popover Menu (Tandwieltje) --- +function toggleWidgetSettingsMenu(wId, event) { + if (event) { + event.stopPropagation(); + event.preventDefault(); + } + const menu = document.getElementById(`widgetSettingsMenu_${wId}`); + if (!menu) return; + const isCurrentlyHidden = menu.classList.contains('hidden'); + // Sluit alle open menu's eerst + document.querySelectorAll('.widget-settings-dropdown').forEach(d => d.classList.add('hidden')); + if (isCurrentlyHidden) { + menu.classList.remove('hidden'); + } +} + // --- Widget Inklappen / Uitklappen --- function toggleWidgetCollapse(wId) { const body = document.getElementById(`widget_body_${wId}`); @@ -2023,6 +2056,7 @@ function toggleWidgetCollapse(wId) { // --- Widget Verbergen van Scherm met Undo Toast --- function hideWidgetOnScreen(wId) { + document.getElementById(`widgetSettingsMenu_${wId}`)?.classList.add('hidden'); const wrapper = document.getElementById(`widgetWrapper_${wId}`) || document.querySelector(`.fociz-widget-wrapper[data-widget-id="${wId}"]`); const item = focizWidgets.find(x => x.id === wId); const title = item ? item.title : 'Widget'; @@ -2056,9 +2090,9 @@ function undoHideWidget(wId) { }, 400); } -// --- Direct On-Screen Drag & Drop Engine (HTML5 Native) --- +// --- Direct On-Screen Drag & Drop Engine (Live Shift & Reflow) --- let draggedWidgetEl = null; -let dropPlaceholderEl = null; +let dragInitialIndex = -1; function initPlannerWidgets() { const grid = document.getElementById('focizWidgetGrid'); @@ -2077,13 +2111,6 @@ function initPlannerWidgets() { } catch(e) {} }); - if (!dropPlaceholderEl) { - dropPlaceholderEl = document.createElement('div'); - dropPlaceholderEl.id = 'widgetDropPlaceholder'; - dropPlaceholderEl.className = 'col-span-1 min-w-0 border-2 border-dashed border-indigo-400/80 dark:border-indigo-500/80 bg-indigo-50/50 dark:bg-indigo-950/40 rounded-2xl flex items-center justify-center p-8 text-xs font-bold text-indigo-600 dark:text-indigo-400 pointer-events-none transition-all duration-150'; - dropPlaceholderEl.innerHTML = '
Laat los om hier te plaatsen
'; - } - // Luister naar drag handles document.querySelectorAll('.widget-drag-handle').forEach(handle => { handle.setAttribute('draggable', 'true'); @@ -2092,82 +2119,118 @@ function initPlannerWidgets() { const wrapper = handle.closest('.fociz-widget-wrapper'); if (!wrapper) return; draggedWidgetEl = wrapper; + + // Bewaar beginpositie om te controleren op wijzigingen + const allWrappers = Array.from(grid.querySelectorAll('.fociz-widget-wrapper')); + dragInitialIndex = allWrappers.indexOf(draggedWidgetEl); + e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', wrapper.getAttribute('data-widget-id')); - // Match column span van dragged widget - const curSpan = wrapper.getAttribute('data-col-span') || '6'; - dropPlaceholderEl.className = `lg:col-span-${curSpan} col-span-1 min-w-0 border-2 border-dashed border-indigo-400/80 dark:border-indigo-500/80 bg-indigo-50/60 dark:bg-indigo-950/50 rounded-2xl flex items-center justify-center p-8 text-xs font-bold text-indigo-600 dark:text-indigo-400 pointer-events-none transition-all`; + // Sluit eventuele open popover menu's + document.querySelectorAll('.widget-settings-dropdown').forEach(d => d.classList.add('hidden')); setTimeout(() => { if (draggedWidgetEl) { - draggedWidgetEl.classList.add('opacity-40', 'scale-[0.98]', 'ring-2', 'ring-indigo-500/50'); + draggedWidgetEl.classList.add('opacity-40', 'scale-[0.98]', 'ring-2', 'ring-indigo-500/70', 'shadow-2xl'); } }, 0); }; handle.ondragend = (e) => { if (draggedWidgetEl) { - draggedWidgetEl.classList.remove('opacity-40', 'scale-[0.98]', 'ring-2', 'ring-indigo-500/50'); - } - if (dropPlaceholderEl && dropPlaceholderEl.parentNode) { - dropPlaceholderEl.remove(); + draggedWidgetEl.classList.remove('opacity-40', 'scale-[0.98]', 'ring-2', 'ring-indigo-500/70', 'shadow-2xl'); } + saveCurrentGridOrderIfChanged(); draggedWidgetEl = null; }; }); - // Dragover op grid + // Dragover op grid: verplaatst de widget live in het DOM zodat andere blokken direct opzij schuiven grid.ondragover = (e) => { if (!draggedWidgetEl) return; e.preventDefault(); e.dataTransfer.dropEffect = 'move'; + // Check of cursor onderaan het grid zweeft + const gridRect = grid.getBoundingClientRect(); + if (e.clientY > gridRect.bottom - 40) { + if (grid.lastElementChild !== draggedWidgetEl) { + grid.appendChild(draggedWidgetEl); + } + return; + } + + // Check of cursor bovenaan het grid zweeft + if (e.clientY < gridRect.top + 40) { + if (grid.firstElementChild !== draggedWidgetEl) { + grid.prepend(draggedWidgetEl); + } + return; + } + const target = e.target.closest('.fociz-widget-wrapper'); - if (target && target !== draggedWidgetEl && target !== dropPlaceholderEl) { + if (target && target !== draggedWidgetEl && target.parentElement === grid) { const rect = target.getBoundingClientRect(); - const isAfter = (e.clientY - rect.top) > (rect.height / 2) || (e.clientX - rect.left) > (rect.width / 2); + const midY = rect.top + rect.height / 2; + const midX = rect.left + rect.width / 2; + + // Bepaal of de muis voorbij het midden is (verticaal of horizontaal in dezelfde rij) + const isAfter = (e.clientY > midY) || (Math.abs(e.clientY - midY) < rect.height * 0.35 && e.clientX > midX); + if (isAfter) { - if (target.nextSibling !== dropPlaceholderEl) { - target.after(dropPlaceholderEl); + if (target.nextElementSibling !== draggedWidgetEl) { + target.after(draggedWidgetEl); } } else { - if (target.previousSibling !== dropPlaceholderEl) { - target.before(dropPlaceholderEl); + if (target.previousElementSibling !== draggedWidgetEl) { + target.before(draggedWidgetEl); } } } }; grid.ondrop = (e) => { - if (!draggedWidgetEl) return; e.preventDefault(); - - if (dropPlaceholderEl && dropPlaceholderEl.parentNode) { - dropPlaceholderEl.replaceWith(draggedWidgetEl); - } - if (draggedWidgetEl) { - draggedWidgetEl.classList.remove('opacity-40', 'scale-[0.98]', 'ring-2', 'ring-indigo-500/50'); + draggedWidgetEl.classList.remove('opacity-40', 'scale-[0.98]', 'ring-2', 'ring-indigo-500/70', 'shadow-2xl'); } - - // Volgorde bijwerken - const currentWrappers = Array.from(grid.querySelectorAll('.fociz-widget-wrapper')); - currentWrappers.forEach((el, index) => { - const wId = el.getAttribute('data-widget-id'); - const item = focizWidgets.find(x => x.id === wId); - if (item) { - item.order = index + 1; - } - }); - - persistWidgetLayoutAuto(); - showWidgetToast('Widget verplaatst & indeling opgeslagen', 'success'); - + saveCurrentGridOrderIfChanged(); draggedWidgetEl = null; }; } +function saveCurrentGridOrderIfChanged() { + const grid = document.getElementById('focizWidgetGrid'); + if (!grid) return; + const currentWrappers = Array.from(grid.querySelectorAll('.fociz-widget-wrapper')); + const currentIndex = currentWrappers.indexOf(draggedWidgetEl); + + let hasOrderChanged = false; + currentWrappers.forEach((el, index) => { + const wId = el.getAttribute('data-widget-id'); + const item = focizWidgets.find(x => x.id === wId); + if (item) { + if (item.order !== index + 1) { + item.order = index + 1; + hasOrderChanged = true; + } + } + }); + + if (hasOrderChanged || (dragInitialIndex !== -1 && currentIndex !== dragInitialIndex)) { + persistWidgetLayoutAuto(); + showWidgetToast('Widget verplaatst & indeling opgeslagen', 'success'); + } +} + +// Sluit popup menu's als er buiten wordt geklikt +document.addEventListener('click', (e) => { + if (!e.target.closest('.widget-settings-dropdown') && !e.target.closest('.widget-settings-btn')) { + document.querySelectorAll('.widget-settings-dropdown').forEach(d => d.classList.add('hidden')); + } +}); + // --- Jira Queue & Tickets Widget Engine (v2.0) --- const plannerJiraAssigned = ; const plannerJiraAll = ;