4 changed files with 256 additions and 6 deletions
@ -0,0 +1,154 @@ |
|||
// Simple Dashboard Drag and Drop
|
|||
let isCustomizing = false; |
|||
let draggedCard = null; |
|||
|
|||
// Initialize on page load
|
|||
document.addEventListener('DOMContentLoaded', function () { |
|||
loadLayout(); |
|||
}); |
|||
|
|||
function toggleCustomize() { |
|||
const btn = document.getElementById('customize-btn'); |
|||
const help = document.getElementById('customization-help'); |
|||
const cards = document.querySelectorAll('.draggable-card'); |
|||
const handles = document.querySelectorAll('.drag-handle'); |
|||
|
|||
isCustomizing = !isCustomizing; |
|||
|
|||
if (isCustomizing) { |
|||
btn.textContent = '💾 Save Layout'; |
|||
btn.classList.add('saving'); |
|||
help.style.display = 'block'; |
|||
|
|||
// Enable dragging
|
|||
cards.forEach(card => { |
|||
card.draggable = true; |
|||
card.classList.add('customizable'); |
|||
card.addEventListener('dragstart', handleDragStart); |
|||
card.addEventListener('dragover', handleDragOver); |
|||
card.addEventListener('drop', handleDrop); |
|||
card.addEventListener('dragend', handleDragEnd); |
|||
}); |
|||
|
|||
// Show handles
|
|||
handles.forEach(handle => handle.style.display = 'block'); |
|||
|
|||
} else { |
|||
btn.textContent = '📝 Customize Layout'; |
|||
btn.classList.remove('saving'); |
|||
help.style.display = 'none'; |
|||
|
|||
// Disable dragging
|
|||
cards.forEach(card => { |
|||
card.draggable = false; |
|||
card.classList.remove('customizable'); |
|||
card.removeEventListener('dragstart', handleDragStart); |
|||
card.removeEventListener('dragover', handleDragOver); |
|||
card.removeEventListener('drop', handleDrop); |
|||
card.removeEventListener('dragend', handleDragEnd); |
|||
}); |
|||
|
|||
// Hide handles
|
|||
handles.forEach(handle => handle.style.display = 'none'); |
|||
|
|||
// Save the current layout
|
|||
saveLayout(); |
|||
showMessage('Layout saved!', 'success'); |
|||
} |
|||
} |
|||
|
|||
function handleDragStart(e) { |
|||
draggedCard = e.target.closest('.draggable-card'); |
|||
draggedCard.classList.add('dragging'); |
|||
e.dataTransfer.effectAllowed = 'move'; |
|||
} |
|||
|
|||
function handleDragOver(e) { |
|||
e.preventDefault(); |
|||
e.dataTransfer.dropEffect = 'move'; |
|||
|
|||
const card = e.target.closest('.draggable-card'); |
|||
if (card && card !== draggedCard) { |
|||
const grid = document.getElementById('dashboard-grid'); |
|||
const cards = Array.from(grid.children); |
|||
const draggedIndex = cards.indexOf(draggedCard); |
|||
const targetIndex = cards.indexOf(card); |
|||
|
|||
if (draggedIndex < targetIndex) { |
|||
grid.insertBefore(draggedCard, card.nextSibling); |
|||
} else { |
|||
grid.insertBefore(draggedCard, card); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function handleDrop(e) { |
|||
e.preventDefault(); |
|||
} |
|||
|
|||
function handleDragEnd(e) { |
|||
if (draggedCard) { |
|||
draggedCard.classList.remove('dragging'); |
|||
draggedCard = null; |
|||
} |
|||
} |
|||
|
|||
function saveLayout() { |
|||
const cards = document.querySelectorAll('.draggable-card'); |
|||
const layout = Array.from(cards).map((card, index) => ({ |
|||
id: card.dataset.widgetId, |
|||
position: index |
|||
})); |
|||
localStorage.setItem('dashboard-layout', JSON.stringify(layout)); |
|||
} |
|||
|
|||
function loadLayout() { |
|||
const saved = localStorage.getItem('dashboard-layout'); |
|||
if (!saved) return; |
|||
|
|||
try { |
|||
const layout = JSON.parse(saved); |
|||
const grid = document.getElementById('dashboard-grid'); |
|||
|
|||
// Sort layout by position
|
|||
layout.sort((a, b) => a.position - b.position); |
|||
|
|||
// Reorder cards
|
|||
layout.forEach(item => { |
|||
const card = document.querySelector(`[data-widget-id="${item.id}"]`); |
|||
if (card) grid.appendChild(card); |
|||
}); |
|||
} catch (e) { |
|||
console.warn('Failed to load layout:', e); |
|||
} |
|||
} |
|||
|
|||
function showMessage(text, type) { |
|||
// Create message element
|
|||
const msg = document.createElement('div'); |
|||
msg.textContent = text; |
|||
msg.style.cssText = ` |
|||
position: fixed; |
|||
top: 20px; |
|||
right: 20px; |
|||
padding: 12px 20px; |
|||
border-radius: 4px; |
|||
color: white; |
|||
font-weight: bold; |
|||
z-index: 10000; |
|||
background: ${type === 'success' ? '#10b981' : '#ef4444'}; |
|||
transform: translateX(300px); |
|||
transition: transform 0.3s ease; |
|||
`;
|
|||
|
|||
document.body.appendChild(msg); |
|||
|
|||
// Show message
|
|||
setTimeout(() => msg.style.transform = 'translateX(0)', 100); |
|||
|
|||
// Hide message
|
|||
setTimeout(() => { |
|||
msg.style.transform = 'translateX(300px)'; |
|||
setTimeout(() => document.body.removeChild(msg), 300); |
|||
}, 2000); |
|||
} |
|||
@ -1,17 +1,31 @@ |
|||
{{define "content"}} |
|||
<h2>Dashboard</h2> |
|||
<div class="dashboard-header"> |
|||
<h2>Dashboard</h2> |
|||
<button id="customize-btn" class="customize-btn" onclick="toggleCustomize()"> |
|||
📝 Customize Layout |
|||
</button> |
|||
</div> |
|||
|
|||
<p>Welcome to the ServiceTrade Tools Dashboard.</p> |
|||
|
|||
<div class="dashboard-grid"> |
|||
<div class="dashboard-item"> |
|||
<div id="customization-help" class="customization-help" style="display: none;"> |
|||
💡 <strong>Tip:</strong> Drag and drop the cards to arrange them in your preferred order. |
|||
</div> |
|||
|
|||
<div id="dashboard-grid" class="dashboard-grid"> |
|||
<div class="dashboard-item draggable-card" data-widget-id="invoice-search" data-widget-title="Update Invoice Status"> |
|||
<div class="drag-handle" style="display: none;">⋮⋮</div> |
|||
{{template "invoice_search" .}} |
|||
</div> |
|||
<div class="dashboard-item"> |
|||
|
|||
<div class="dashboard-item draggable-card" data-widget-id="document-upload" data-widget-title="Document Uploads"> |
|||
<div class="drag-handle" style="display: none;">⋮⋮</div> |
|||
{{template "document_upload" .}} |
|||
</div> |
|||
<div class="dashboard-item"> |
|||
|
|||
<div class="dashboard-item draggable-card" data-widget-id="document-remove" data-widget-title="Document Removal"> |
|||
<div class="drag-handle" style="display: none;">⋮⋮</div> |
|||
{{template "document_remove" .}} |
|||
</div> |
|||
<!-- Add more dashboard items as needed --> |
|||
</div> |
|||
{{end}} |
|||
Loading…
Reference in new issue