|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Custom Dashboard</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<script src="https://unpkg.com/feather-icons"></script> |
|
|
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script> |
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> |
|
|
<style> |
|
|
.widget { |
|
|
transition: all 0.2s ease; |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
min-width: 250px; |
|
|
min-height: 150px; |
|
|
width: calc(33.333% - 20px); |
|
|
flex: 0 0 calc(33.333% - 20px); |
|
|
margin-bottom: 20px; |
|
|
resize: vertical; |
|
|
} |
|
|
.widget.size-1 { |
|
|
width: calc(33.333% - 20px); |
|
|
flex: 0 0 calc(33.333% - 20px); |
|
|
height: 150px; |
|
|
} |
|
|
.widget.size-2 { |
|
|
width: calc(66.666% - 20px); |
|
|
flex: 0 0 calc(66.666% - 20px); |
|
|
height: 200px; |
|
|
} |
|
|
.widget.size-3 { |
|
|
width: calc(100% - 20px); |
|
|
flex: 0 0 calc(100% - 20px); |
|
|
height: 250px; |
|
|
} |
|
|
.resize-controls { |
|
|
position: absolute; |
|
|
right: 10px; |
|
|
top: 10px; |
|
|
display: flex; |
|
|
gap: 5px; |
|
|
z-index: 10; |
|
|
} |
|
|
.resize-btn { |
|
|
width: 20px; |
|
|
height: 20px; |
|
|
background: #f0f0f0; |
|
|
border: 1px solid #ddd; |
|
|
border-radius: 3px; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
cursor: pointer; |
|
|
font-size: 10px; |
|
|
} |
|
|
.resize-btn:hover { |
|
|
background: #e0e0e0; |
|
|
} |
|
|
.widget:hover { |
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); |
|
|
} |
|
|
.bookmark-item { |
|
|
padding: 0.05rem 0.3rem; |
|
|
margin: 0; |
|
|
} |
|
|
.bookmark-item:hover { |
|
|
background-color: rgba(59, 130, 246, 0.1); |
|
|
margin: 0; |
|
|
} |
|
|
.bookmark-link { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
text-decoration: none; |
|
|
color: inherit; |
|
|
flex-grow: 1; |
|
|
padding: 0.1rem 0; |
|
|
} |
|
|
.sortable-ghost { |
|
|
opacity: 0.5; |
|
|
background: #c8ebfb; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50 font-sans"> |
|
|
<div class="container mx-auto px-4 py-8"> |
|
|
|
|
|
<header class="flex justify-between items-center mb-8"> |
|
|
<h1 class="text-3xl font-bold text-blue-600">My Dashboard</h1> |
|
|
<div class="flex space-x-4"> |
|
|
<button id="addWidgetBtn" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition flex items-center"> |
|
|
<i data-feather="plus" class="mr-2"></i> Add Widget |
|
|
</button> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
|
|
|
<div id="widgetsContainer" class="flex flex-wrap gap-6"> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="addWidgetModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> |
|
|
<div class="bg-white rounded-lg p-6 w-full max-w-md"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h3 class="text-xl font-semibold">Add New Widget</h3> |
|
|
<button id="closeWidgetModal" class="text-gray-500 hover:text-gray-700"> |
|
|
<i data-feather="x"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-gray-700 mb-2">Widget Title</label> |
|
|
<input type="text" id="widgetTitle" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> |
|
|
</div> |
|
|
<div class="flex justify-end space-x-3"> |
|
|
<button id="cancelWidget" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300">Cancel</button> |
|
|
<button id="confirmWidget" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Add Widget</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="addBookmarkModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> |
|
|
<div class="bg-white rounded-lg p-6 w-full max-w-md"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h3 class="text-xl font-semibold">Add New Bookmark</h3> |
|
|
<button id="closeBookmarkModal" class="text-gray-500 hover:text-gray-700"> |
|
|
<i data-feather="x"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-gray-700 mb-2">Title</label> |
|
|
<input type="text" id="bookmarkTitle" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> |
|
|
</div> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-gray-700 mb-2">URL</label> |
|
|
<input type="text" id="bookmarkUrl" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="https://"> |
|
|
</div> |
|
|
<div class="flex justify-end space-x-3"> |
|
|
<button id="cancelBookmark" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300">Cancel</button> |
|
|
<button id="confirmBookmark" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Add Bookmark</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="editWidgetModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> |
|
|
<div class="bg-white rounded-lg p-6 w-full max-w-md"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h3 class="text-xl font-semibold">Edit Widget</h3> |
|
|
<button id="closeEditWidgetModal" class="text-gray-500 hover:text-gray-700"> |
|
|
<i data-feather="x"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-gray-700 mb-2">Widget Title</label> |
|
|
<input type="text" id="editWidgetTitle" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> |
|
|
</div> |
|
|
<div class="flex justify-end space-x-3"> |
|
|
<button id="deleteWidget" class="px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600">Delete Widget</button> |
|
|
<button id="saveWidget" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Save Changes</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
feather.replace(); |
|
|
|
|
|
|
|
|
if (!localStorage.getItem('widgets')) { |
|
|
const sampleWidgets = [ |
|
|
{ |
|
|
id: 'widget-' + Date.now(), |
|
|
title: 'Favorites', |
|
|
width: '300px', |
|
|
height: '200px', |
|
|
bookmarks: [ |
|
|
{ id: 'bookmark-' + Date.now() + 1, title: 'Google', url: 'https://google.com' }, |
|
|
{ id: 'bookmark-' + Date.now() + 2, title: 'GitHub', url: 'https://github.com' } |
|
|
] |
|
|
}, |
|
|
{ |
|
|
id: 'widget-' + (Date.now() + 1), |
|
|
title: 'Social', |
|
|
width: '300px', |
|
|
height: '200px', |
|
|
bookmarks: [ |
|
|
{ id: 'bookmark-' + (Date.now() + 3), title: 'Twitter', url: 'https://twitter.com' }, |
|
|
{ id: 'bookmark-' + (Date.now() + 4), title: 'Facebook', url: 'https://facebook.com' } |
|
|
] |
|
|
} |
|
|
]; |
|
|
localStorage.setItem('widgets', JSON.stringify(sampleWidgets)); |
|
|
} |
|
|
|
|
|
|
|
|
loadWidgets(); |
|
|
|
|
|
|
|
|
const widgetsContainer = document.getElementById('widgetsContainer'); |
|
|
new Sortable(widgetsContainer, { |
|
|
animation: 150, |
|
|
ghostClass: 'sortable-ghost', |
|
|
onEnd: function() { |
|
|
saveWidgetsOrder(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const addWidgetModal = document.getElementById('addWidgetModal'); |
|
|
const addBookmarkModal = document.getElementById('addBookmarkModal'); |
|
|
const editWidgetModal = document.getElementById('editWidgetModal'); |
|
|
let currentWidgetId = null; |
|
|
let editMode = false; |
|
|
|
|
|
|
|
|
document.getElementById('addWidgetBtn').addEventListener('click', () => { |
|
|
addWidgetModal.classList.remove('hidden'); |
|
|
}); |
|
|
|
|
|
document.getElementById('closeWidgetModal').addEventListener('click', () => { |
|
|
addWidgetModal.classList.add('hidden'); |
|
|
}); |
|
|
|
|
|
document.getElementById('cancelWidget').addEventListener('click', () => { |
|
|
addWidgetModal.classList.add('hidden'); |
|
|
}); |
|
|
|
|
|
|
|
|
function showAddBookmarkModal(widgetId) { |
|
|
currentWidgetId = widgetId; |
|
|
|
|
|
document.getElementById('bookmarkTitle').value = ''; |
|
|
document.getElementById('bookmarkUrl').value = ''; |
|
|
document.querySelector('#addBookmarkModal h3').textContent = 'Add New Bookmark'; |
|
|
document.getElementById('confirmBookmark').textContent = 'Add Bookmark'; |
|
|
delete document.getElementById('confirmBookmark').dataset.bookmarkId; |
|
|
addBookmarkModal.classList.remove('hidden'); |
|
|
} |
|
|
|
|
|
document.getElementById('closeBookmarkModal').addEventListener('click', () => { |
|
|
addBookmarkModal.classList.add('hidden'); |
|
|
}); |
|
|
|
|
|
document.getElementById('cancelBookmark').addEventListener('click', () => { |
|
|
addBookmarkModal.classList.add('hidden'); |
|
|
}); |
|
|
|
|
|
|
|
|
function showEditWidgetModal(widgetId) { |
|
|
currentWidgetId = widgetId; |
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')); |
|
|
const widget = widgets.find(w => w.id === widgetId); |
|
|
document.getElementById('editWidgetTitle').value = widget.title; |
|
|
editWidgetModal.classList.remove('hidden'); |
|
|
} |
|
|
|
|
|
document.getElementById('closeEditWidgetModal').addEventListener('click', () => { |
|
|
editWidgetModal.classList.add('hidden'); |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('confirmWidget').addEventListener('click', () => { |
|
|
const title = document.getElementById('widgetTitle').value.trim(); |
|
|
if (title) { |
|
|
const newWidget = { |
|
|
id: 'widget-' + Date.now(), |
|
|
title: title, |
|
|
bookmarks: [], |
|
|
size: 1 |
|
|
}; |
|
|
|
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')) || []; |
|
|
widgets.push(newWidget); |
|
|
localStorage.setItem('widgets', JSON.stringify(widgets)); |
|
|
|
|
|
loadWidgets(); |
|
|
addWidgetModal.classList.add('hidden'); |
|
|
document.getElementById('widgetTitle').value = ''; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('confirmBookmark').addEventListener('click', () => { |
|
|
const title = document.getElementById('bookmarkTitle').value.trim(); |
|
|
let url = document.getElementById('bookmarkUrl').value.trim(); |
|
|
|
|
|
if (!url.startsWith('http://') && !url.startsWith('https://')) { |
|
|
url = 'https://' + url; |
|
|
} |
|
|
|
|
|
if (title && url) { |
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')); |
|
|
const widgetIndex = widgets.findIndex(w => w.id === currentWidgetId); |
|
|
|
|
|
if (widgetIndex !== -1) { |
|
|
const bookmarkId = document.getElementById('confirmBookmark').dataset.bookmarkId; |
|
|
|
|
|
if (bookmarkId) { |
|
|
|
|
|
const bookmarkIndex = widgets[widgetIndex].bookmarks.findIndex(b => b.id === bookmarkId); |
|
|
if (bookmarkIndex !== -1) { |
|
|
widgets[widgetIndex].bookmarks[bookmarkIndex].title = title; |
|
|
widgets[widgetIndex].bookmarks[bookmarkIndex].url = url; |
|
|
} |
|
|
} else { |
|
|
|
|
|
const newBookmark = { |
|
|
id: 'bookmark-' + Date.now(), |
|
|
title: title, |
|
|
url: url |
|
|
}; |
|
|
widgets[widgetIndex].bookmarks.push(newBookmark); |
|
|
} |
|
|
|
|
|
localStorage.setItem('widgets', JSON.stringify(widgets)); |
|
|
|
|
|
loadWidgets(); |
|
|
addBookmarkModal.classList.add('hidden'); |
|
|
document.getElementById('bookmarkTitle').value = ''; |
|
|
document.getElementById('bookmarkUrl').value = ''; |
|
|
|
|
|
|
|
|
document.querySelector('#addBookmarkModal h3').textContent = 'Add New Bookmark'; |
|
|
document.getElementById('confirmBookmark').textContent = 'Add Bookmark'; |
|
|
delete document.getElementById('confirmBookmark').dataset.bookmarkId; |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('saveWidget').addEventListener('click', () => { |
|
|
const title = document.getElementById('editWidgetTitle').value.trim(); |
|
|
if (title) { |
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')); |
|
|
const widgetIndex = widgets.findIndex(w => w.id === currentWidgetId); |
|
|
|
|
|
if (widgetIndex !== -1) { |
|
|
widgets[widgetIndex].title = title; |
|
|
localStorage.setItem('widgets', JSON.stringify(widgets)); |
|
|
|
|
|
loadWidgets(); |
|
|
editWidgetModal.classList.add('hidden'); |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('deleteWidget').addEventListener('click', () => { |
|
|
if (confirm('Are you sure you want to delete this widget and all its bookmarks?')) { |
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')); |
|
|
const updatedWidgets = widgets.filter(w => w.id !== currentWidgetId); |
|
|
localStorage.setItem('widgets', JSON.stringify(updatedWidgets)); |
|
|
|
|
|
loadWidgets(); |
|
|
editWidgetModal.classList.add('hidden'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
function loadWidgets() { |
|
|
const widgetsContainer = document.getElementById('widgetsContainer'); |
|
|
widgetsContainer.innerHTML = ''; |
|
|
|
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')) || []; |
|
|
|
|
|
widgets.forEach(widget => { |
|
|
const widgetElement = document.createElement('div'); |
|
|
widgetElement.className = 'widget bg-white rounded-lg shadow-md p-4 relative'; |
|
|
widgetElement.dataset.widgetId = widget.id; |
|
|
widgetElement.style.width = widget.width || '300px'; |
|
|
widgetElement.style.height = widget.height || '200px'; |
|
|
|
|
|
|
|
|
const resizeControls = document.createElement('div'); |
|
|
resizeControls.className = 'resize-controls'; |
|
|
|
|
|
|
|
|
const hSizes = [1, 2, 3]; |
|
|
hSizes.forEach(size => { |
|
|
const sizeBtn = document.createElement('button'); |
|
|
sizeBtn.className = 'resize-btn'; |
|
|
sizeBtn.textContent = `${size}x`; |
|
|
sizeBtn.title = `Width ${size}/3`; |
|
|
sizeBtn.addEventListener('click', (e) => { |
|
|
e.stopPropagation(); |
|
|
resizeWidget(widget.id, size, 'width'); |
|
|
}); |
|
|
resizeControls.appendChild(sizeBtn); |
|
|
}); |
|
|
|
|
|
|
|
|
widgetElement.appendChild(resizeControls); |
|
|
|
|
|
|
|
|
widgetElement.classList.add(`size-${widget.widthSize || 1}`); |
|
|
widgetElement.classList.add(`height-${widget.heightSize || 1}`); |
|
|
widgetElement.style.height = widget.height || '150px'; |
|
|
|
|
|
|
|
|
const header = document.createElement('div'); |
|
|
header.className = 'flex justify-between items-center mb-4'; |
|
|
|
|
|
const title = document.createElement('h2'); |
|
|
title.className = 'text-xl font-semibold text-gray-800'; |
|
|
title.textContent = widget.title; |
|
|
|
|
|
const controls = document.createElement('div'); |
|
|
controls.className = 'flex space-x-2 widget-edit-controls hidden'; |
|
|
|
|
|
const editBtn = document.createElement('button'); |
|
|
editBtn.className = 'text-blue-500 hover:text-blue-700'; |
|
|
editBtn.innerHTML = '<i data-feather="edit-2" class="w-4 h-4"></i>'; |
|
|
editBtn.addEventListener('click', () => showEditWidgetModal(widget.id)); |
|
|
|
|
|
const addBookmarkBtn = document.createElement('button'); |
|
|
addBookmarkBtn.className = 'text-green-500 hover:text-green-700'; |
|
|
addBookmarkBtn.innerHTML = '<i data-feather="plus" class="w-4 h-4"></i>'; |
|
|
addBookmarkBtn.addEventListener('click', () => showAddBookmarkModal(widget.id)); |
|
|
|
|
|
controls.appendChild(addBookmarkBtn); |
|
|
controls.appendChild(editBtn); |
|
|
|
|
|
header.appendChild(title); |
|
|
header.appendChild(controls); |
|
|
|
|
|
|
|
|
const bookmarksList = document.createElement('div'); |
|
|
bookmarksList.className = 'space-y-1'; |
|
|
|
|
|
widget.bookmarks.forEach(bookmark => { |
|
|
const bookmarkItem = document.createElement('div'); |
|
|
bookmarkItem.className = 'bookmark-item flex justify-between items-center p-1 rounded-md transition cursor-pointer'; |
|
|
bookmarkItem.dataset.bookmarkId = bookmark.id; |
|
|
|
|
|
const bookmarkLink = document.createElement('a'); |
|
|
bookmarkLink.className = 'bookmark-link text-blue-600 hover:text-blue-800 flex-grow'; |
|
|
bookmarkLink.href = bookmark.url; |
|
|
bookmarkLink.target = '_blank'; |
|
|
|
|
|
bookmarkLink.addEventListener('dblclick', (e) => { |
|
|
e.preventDefault(); |
|
|
window.open(bookmark.url, '_blank'); |
|
|
}); |
|
|
|
|
|
const linkIcon = document.createElement('i'); |
|
|
linkIcon.dataset.feather = 'external-link'; |
|
|
linkIcon.className = 'mr-1 w-3 h-3'; |
|
|
|
|
|
const linkText = document.createElement('span'); |
|
|
linkText.className = 'truncate'; |
|
|
linkText.textContent = bookmark.title; |
|
|
linkText.title = bookmark.title; |
|
|
|
|
|
bookmarkLink.appendChild(linkIcon); |
|
|
bookmarkLink.appendChild(linkText); |
|
|
|
|
|
const controls = document.createElement('div'); |
|
|
controls.className = 'flex space-x-1 ml-2'; |
|
|
|
|
|
const editBtn = document.createElement('button'); |
|
|
editBtn.className = 'text-gray-500 hover:text-gray-700'; |
|
|
editBtn.innerHTML = '<i data-feather="edit" class="w-3 h-3"></i>'; |
|
|
editBtn.addEventListener('click', (e) => { |
|
|
e.stopPropagation(); |
|
|
editBookmark(widget.id, bookmark.id); |
|
|
}); |
|
|
|
|
|
const deleteBtn = document.createElement('button'); |
|
|
deleteBtn.className = 'text-red-500 hover:text-red-700'; |
|
|
deleteBtn.innerHTML = '<i data-feather="trash-2" class="w-3 h-3"></i>'; |
|
|
deleteBtn.addEventListener('click', (e) => { |
|
|
e.stopPropagation(); |
|
|
deleteBookmark(widget.id, bookmark.id); |
|
|
}); |
|
|
|
|
|
controls.appendChild(editBtn); |
|
|
controls.appendChild(deleteBtn); |
|
|
|
|
|
bookmarkItem.appendChild(bookmarkLink); |
|
|
bookmarkItem.appendChild(controls); |
|
|
|
|
|
bookmarksList.appendChild(bookmarkItem); |
|
|
}); |
|
|
|
|
|
|
|
|
const addBookmarkBtnBottom = document.createElement('button'); |
|
|
addBookmarkBtnBottom.className = 'absolute bottom-2 right-2 p-1 text-blue-500 hover:text-blue-700 rounded-full hover:bg-blue-50'; |
|
|
addBookmarkBtnBottom.innerHTML = '<i data-feather="plus" class="w-4 h-4"></i>'; |
|
|
addBookmarkBtnBottom.addEventListener('click', () => showAddBookmarkModal(widget.id)); |
|
|
|
|
|
widgetElement.appendChild(header); |
|
|
widgetElement.appendChild(bookmarksList); |
|
|
widgetElement.appendChild(addBookmarkBtnBottom); |
|
|
|
|
|
widgetsContainer.appendChild(widgetElement); |
|
|
}); |
|
|
|
|
|
feather.replace(); |
|
|
} |
|
|
|
|
|
|
|
|
function editBookmark(widgetId, bookmarkId) { |
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')); |
|
|
const widgetIndex = widgets.findIndex(w => w.id === widgetId); |
|
|
|
|
|
if (widgetIndex !== -1) { |
|
|
const bookmark = widgets[widgetIndex].bookmarks.find(b => b.id === bookmarkId); |
|
|
if (bookmark) { |
|
|
document.getElementById('bookmarkTitle').value = bookmark.title; |
|
|
document.getElementById('bookmarkUrl').value = bookmark.url; |
|
|
currentWidgetId = widgetId; |
|
|
|
|
|
|
|
|
document.getElementById('confirmBookmark').dataset.bookmarkId = bookmarkId; |
|
|
|
|
|
|
|
|
document.querySelector('#addBookmarkModal h3').textContent = 'Edit Bookmark'; |
|
|
document.getElementById('confirmBookmark').textContent = 'Save Changes'; |
|
|
|
|
|
addBookmarkModal.classList.remove('hidden'); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function deleteBookmark(widgetId, bookmarkId) { |
|
|
if (confirm('Are you sure you want to delete this bookmark?')) { |
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')); |
|
|
const widgetIndex = widgets.findIndex(w => w.id === widgetId); |
|
|
|
|
|
if (widgetIndex !== -1) { |
|
|
widgets[widgetIndex].bookmarks = widgets[widgetIndex].bookmarks.filter(b => b.id !== bookmarkId); |
|
|
localStorage.setItem('widgets', JSON.stringify(widgets)); |
|
|
|
|
|
loadWidgets(); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function saveWidgetsOrder() { |
|
|
const widgetsContainer = document.getElementById('widgetsContainer'); |
|
|
const widgetElements = Array.from(widgetsContainer.children); |
|
|
|
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')); |
|
|
const orderedWidgets = []; |
|
|
|
|
|
widgetElements.forEach(element => { |
|
|
const widgetId = element.dataset.widgetId; |
|
|
const widget = widgets.find(w => w.id === widgetId); |
|
|
if (widget) { |
|
|
orderedWidgets.push(widget); |
|
|
} |
|
|
}); |
|
|
|
|
|
localStorage.setItem('widgets', JSON.stringify(orderedWidgets)); |
|
|
} |
|
|
|
|
|
|
|
|
function resizeWidget(widgetId, size, dimension) { |
|
|
const widgets = JSON.parse(localStorage.getItem('widgets')); |
|
|
const widgetIndex = widgets.findIndex(w => w.id === widgetId); |
|
|
|
|
|
if (widgetIndex !== -1) { |
|
|
if (dimension === 'width') { |
|
|
widgets[widgetIndex].widthSize = size; |
|
|
} else { |
|
|
widgets[widgetIndex].heightSize = size; |
|
|
} |
|
|
|
|
|
localStorage.setItem('widgets', JSON.stringify(widgets)); |
|
|
|
|
|
|
|
|
const widgetElements = document.querySelectorAll('.widget'); |
|
|
widgetElements.forEach(el => { |
|
|
const id = el.dataset.widgetId; |
|
|
const widget = widgets.find(w => w.id === id); |
|
|
|
|
|
|
|
|
el.className = el.className.replace(/\b(size|height)-\d\b/g, ''); |
|
|
|
|
|
|
|
|
const widthSize = widget.widthSize || 1; |
|
|
el.classList.add(`size-${widthSize}`); |
|
|
|
|
|
|
|
|
const heightSize = widget.heightSize || 1; |
|
|
el.classList.add(`height-${heightSize}`); |
|
|
|
|
|
|
|
|
if (heightSize === 1) el.style.height = '150px'; |
|
|
else if (heightSize === 2) el.style.height = '200px'; |
|
|
else if (heightSize === 3) el.style.height = '250px'; |
|
|
}); |
|
|
} |
|
|
} |
|
|
}); |
|
|
</script> |
|
|
</body> |
|
|
</html> |
|
|
|