| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>LinkList - Manage Your Links</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .fade-in { |
| animation: fadeIn 0.3s ease-in-out; |
| } |
| |
| @keyframes fadeIn { |
| from { opacity: 0; transform: translateY(10px); } |
| to { opacity: 1; transform: translateY(0); } |
| } |
| |
| .link-card:hover .link-actions { |
| opacity: 1; |
| } |
| |
| .custom-scrollbar::-webkit-scrollbar { |
| width: 6px; |
| height: 6px; |
| } |
| |
| .custom-scrollbar::-webkit-scrollbar-track { |
| background: #f1f1f1; |
| border-radius: 10px; |
| } |
| |
| .custom-scrollbar::-webkit-scrollbar-thumb { |
| background: #c1c1c1; |
| border-radius: 10px; |
| } |
| |
| .custom-scrollbar::-webkit-scrollbar-thumb:hover { |
| background: #a8a8a8; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50 min-h-screen"> |
| <div class="container mx-auto px-4 py-8"> |
| |
| <header class="flex justify-between items-center mb-8"> |
| <div class="flex items-center"> |
| <i class="fas fa-link text-indigo-600 text-3xl mr-3"></i> |
| <h1 class="text-2xl font-bold text-gray-800">LinkList</h1> |
| </div> |
| <button id="newListBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center"> |
| <i class="fas fa-plus mr-2"></i> New List |
| </button> |
| </header> |
| |
| |
| <div class="flex flex-col lg:flex-row gap-6"> |
| |
| <div class="w-full lg:w-1/4 bg-white rounded-xl shadow-sm p-4 h-fit"> |
| <h2 class="font-semibold text-lg text-gray-700 mb-4 flex items-center"> |
| <i class="fas fa-list mr-2 text-indigo-500"></i> Your Lists |
| </h2> |
| <div id="listsContainer" class="space-y-2 max-h-96 overflow-y-auto custom-scrollbar"> |
| |
| <div class="p-3 bg-indigo-50 rounded-lg border border-indigo-100"> |
| <div class="flex justify-between items-center"> |
| <span class="font-medium text-indigo-700">Quick Access</span> |
| <span class="text-xs bg-indigo-100 text-indigo-800 px-2 py-1 rounded-full">3 links</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="w-full lg:w-3/4"> |
| |
| <div class="bg-white rounded-xl shadow-sm p-4 mb-6"> |
| <div class="flex justify-between items-center"> |
| <div> |
| <h2 id="currentListName" class="font-semibold text-xl text-gray-800">Quick Access</h2> |
| <p id="currentListDesc" class="text-sm text-gray-500">Your frequently visited links</p> |
| </div> |
| <div class="flex space-x-2"> |
| <button id="editListBtn" class="p-2 text-gray-500 hover:text-indigo-600 hover:bg-indigo-50 rounded-full"> |
| <i class="fas fa-pencil-alt"></i> |
| </button> |
| <button id="deleteListBtn" class="p-2 text-gray-500 hover:text-red-600 hover:bg-red-50 rounded-full"> |
| <i class="fas fa-trash-alt"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="bg-white rounded-xl shadow-sm p-4 mb-6"> |
| <div class="flex items-center space-x-3"> |
| <div class="flex-1"> |
| <input id="newLinkUrl" type="url" placeholder="https://example.com" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
| </div> |
| <button id="addLinkBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg"> |
| Add Link |
| </button> |
| </div> |
| <div id="linkDetailsForm" class="mt-4 hidden"> |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Title</label> |
| <input id="linkTitle" type="text" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
| </div> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Category</label> |
| <input id="linkCategory" type="text" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
| </div> |
| <div class="md:col-span-2"> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Description</label> |
| <textarea id="linkDescription" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"></textarea> |
| </div> |
| </div> |
| <div class="mt-4 flex justify-end space-x-3"> |
| <button id="cancelLinkBtn" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">Cancel</button> |
| <button id="saveLinkBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Save Link</button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="linksContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> |
| |
| <div class="link-card bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100 hover:shadow-md transition-all duration-200 fade-in"> |
| <div class="p-4"> |
| <div class="flex items-start"> |
| <div class="bg-indigo-100 p-3 rounded-lg mr-3"> |
| <i class="fas fa-globe text-indigo-600"></i> |
| </div> |
| <div class="flex-1 min-w-0"> |
| <h3 class="font-medium text-gray-800 truncate">Google</h3> |
| <p class="text-sm text-gray-500 truncate">Search engine</p> |
| <a href="https://google.com" target="_blank" class="text-xs text-indigo-600 hover:underline block mt-1 truncate">https://google.com</a> |
| </div> |
| </div> |
| </div> |
| <div class="link-actions bg-gray-50 px-4 py-2 border-t border-gray-100 flex justify-end opacity-0 transition-opacity duration-200"> |
| <button class="p-1 text-gray-400 hover:text-indigo-600"> |
| <i class="fas fa-pencil-alt text-sm"></i> |
| </button> |
| <button class="p-1 text-gray-400 hover:text-red-600 ml-2"> |
| <i class="fas fa-trash-alt text-sm"></i> |
| </button> |
| </div> |
| </div> |
| |
| <div class="link-card bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100 hover:shadow-md transition-all duration-200 fade-in"> |
| <div class="p-4"> |
| <div class="flex items-start"> |
| <div class="bg-blue-100 p-3 rounded-lg mr-3"> |
| <i class="fab fa-twitter text-blue-500"></i> |
| </div> |
| <div class="flex-1 min-w-0"> |
| <h3 class="font-medium text-gray-800 truncate">Twitter</h3> |
| <p class="text-sm text-gray-500 truncate">Social media platform</p> |
| <a href="https://twitter.com" target="_blank" class="text-xs text-indigo-600 hover:underline block mt-1 truncate">https://twitter.com</a> |
| </div> |
| </div> |
| </div> |
| <div class="link-actions bg-gray-50 px-4 py-2 border-t border-gray-100 flex justify-end opacity-0 transition-opacity duration-200"> |
| <button class="p-1 text-gray-400 hover:text-indigo-600"> |
| <i class="fas fa-pencil-alt text-sm"></i> |
| </button> |
| <button class="p-1 text-gray-400 hover:text-red-600 ml-2"> |
| <i class="fas fa-trash-alt text-sm"></i> |
| </button> |
| </div> |
| </div> |
| |
| <div class="link-card bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100 hover:shadow-md transition-all duration-200 fade-in"> |
| <div class="p-4"> |
| <div class="flex items-start"> |
| <div class="bg-red-100 p-3 rounded-lg mr-3"> |
| <i class="fab fa-youtube text-red-600"></i> |
| </div> |
| <div class="flex-1 min-w-0"> |
| <h3 class="font-medium text-gray-800 truncate">YouTube</h3> |
| <p class="text-sm text-gray-500 truncate">Video sharing platform</p> |
| <a href="https://youtube.com" target="_blank" class="text-xs text-indigo-600 hover:underline block mt-1 truncate">https://youtube.com</a> |
| </div> |
| </div> |
| </div> |
| <div class="link-actions bg-gray-50 px-4 py-2 border-t border-gray-100 flex justify-end opacity-0 transition-opacity duration-200"> |
| <button class="p-1 text-gray-400 hover:text-indigo-600"> |
| <i class="fas fa-pencil-alt text-sm"></i> |
| </button> |
| <button class="p-1 text-gray-400 hover:text-red-600 ml-2"> |
| <i class="fas fa-trash-alt text-sm"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="newListModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl p-6 w-full max-w-md fade-in"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-lg font-semibold text-gray-800">Create New List</h3> |
| <button id="closeNewListModal" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div class="space-y-4"> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">List Name</label> |
| <input id="newListName" type="text" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="e.g. Work Resources"> |
| </div> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Description</label> |
| <textarea id="newListDesc" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="Brief description of this list"></textarea> |
| </div> |
| <div class="flex justify-end space-x-3 pt-2"> |
| <button id="cancelNewList" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">Cancel</button> |
| <button id="saveNewList" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Create List</button> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="editListModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl p-6 w-full max-w-md fade-in"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-lg font-semibold text-gray-800">Edit List</h3> |
| <button id="closeEditListModal" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div class="space-y-4"> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">List Name</label> |
| <input id="editListName" type="text" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
| </div> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Description</label> |
| <textarea id="editListDesc" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"></textarea> |
| </div> |
| <div class="flex justify-end space-x-3 pt-2"> |
| <button id="cancelEditList" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">Cancel</button> |
| <button id="saveEditList" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Save Changes</button> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="deleteModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl p-6 w-full max-w-md fade-in"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-lg font-semibold text-gray-800">Confirm Deletion</h3> |
| <button id="closeDeleteModal" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div class="space-y-4"> |
| <p class="text-gray-700">Are you sure you want to delete this list? All links in this list will also be deleted. This action cannot be undone.</p> |
| <div class="flex justify-end space-x-3 pt-4"> |
| <button id="cancelDelete" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">Cancel</button> |
| <button id="confirmDelete" class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700">Delete</button> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <script> |
| |
| const newListBtn = document.getElementById('newListBtn'); |
| const newListModal = document.getElementById('newListModal'); |
| const closeNewListModal = document.getElementById('closeNewListModal'); |
| const cancelNewList = document.getElementById('cancelNewList'); |
| const saveNewList = document.getElementById('saveNewList'); |
| const newListName = document.getElementById('newListName'); |
| const newListDesc = document.getElementById('newListDesc'); |
| |
| const editListBtn = document.getElementById('editListBtn'); |
| const editListModal = document.getElementById('editListModal'); |
| const closeEditListModal = document.getElementById('closeEditListModal'); |
| const cancelEditList = document.getElementById('cancelEditList'); |
| const saveEditList = document.getElementById('saveEditList'); |
| const editListName = document.getElementById('editListName'); |
| const editListDesc = document.getElementById('editListDesc'); |
| |
| const deleteListBtn = document.getElementById('deleteListBtn'); |
| const deleteModal = document.getElementById('deleteModal'); |
| const closeDeleteModal = document.getElementById('closeDeleteModal'); |
| const cancelDelete = document.getElementById('cancelDelete'); |
| const confirmDelete = document.getElementById('confirmDelete'); |
| |
| const addLinkBtn = document.getElementById('addLinkBtn'); |
| const newLinkUrl = document.getElementById('newLinkUrl'); |
| const linkDetailsForm = document.getElementById('linkDetailsForm'); |
| const cancelLinkBtn = document.getElementById('cancelLinkBtn'); |
| const saveLinkBtn = document.getElementById('saveLinkBtn'); |
| const linkTitle = document.getElementById('linkTitle'); |
| const linkCategory = document.getElementById('linkCategory'); |
| const linkDescription = document.getElementById('linkDescription'); |
| |
| const listsContainer = document.getElementById('listsContainer'); |
| const linksContainer = document.getElementById('linksContainer'); |
| const currentListName = document.getElementById('currentListName'); |
| const currentListDesc = document.getElementById('currentListDesc'); |
| |
| |
| let lists = [ |
| { |
| id: 'list-1', |
| name: 'Quick Access', |
| description: 'Your frequently visited links', |
| links: [ |
| { |
| id: 'link-1', |
| title: 'Google', |
| url: 'https://google.com', |
| description: 'Search engine', |
| category: 'Search', |
| icon: 'globe' |
| }, |
| { |
| id: 'link-2', |
| title: 'Twitter', |
| url: 'https://twitter.com', |
| description: 'Social media platform', |
| category: 'Social', |
| icon: 'twitter' |
| }, |
| { |
| id: 'link-3', |
| title: 'YouTube', |
| url: 'https://youtube.com', |
| description: 'Video sharing platform', |
| category: 'Entertainment', |
| icon: 'youtube' |
| } |
| ] |
| } |
| ]; |
| |
| let currentListId = 'list-1'; |
| |
| |
| function init() { |
| renderLists(); |
| renderLinks(currentListId); |
| |
| |
| newListBtn.addEventListener('click', () => newListModal.classList.remove('hidden')); |
| closeNewListModal.addEventListener('click', () => newListModal.classList.add('hidden')); |
| cancelNewList.addEventListener('click', () => newListModal.classList.add('hidden')); |
| saveNewList.addEventListener('click', createNewList); |
| |
| editListBtn.addEventListener('click', openEditListModal); |
| closeEditListModal.addEventListener('click', () => editListModal.classList.add('hidden')); |
| cancelEditList.addEventListener('click', () => editListModal.classList.add('hidden')); |
| saveEditList.addEventListener('click', saveListChanges); |
| |
| deleteListBtn.addEventListener('click', () => deleteModal.classList.remove('hidden')); |
| closeDeleteModal.addEventListener('click', () => deleteModal.classList.add('hidden')); |
| cancelDelete.addEventListener('click', () => deleteModal.classList.add('hidden')); |
| confirmDelete.addEventListener('click', deleteCurrentList); |
| |
| addLinkBtn.addEventListener('click', toggleLinkForm); |
| cancelLinkBtn.addEventListener('click', toggleLinkForm); |
| saveLinkBtn.addEventListener('click', addNewLink); |
| } |
| |
| |
| function renderLists() { |
| listsContainer.innerHTML = ''; |
| |
| lists.forEach(list => { |
| const listElement = document.createElement('div'); |
| listElement.className = `p-3 rounded-lg border cursor-pointer hover:bg-gray-50 transition-colors ${list.id === currentListId ? 'bg-indigo-50 border-indigo-100' : 'bg-white border-gray-200'}`; |
| listElement.innerHTML = ` |
| <div class="flex justify-between items-center"> |
| <span class="font-medium ${list.id === currentListId ? 'text-indigo-700' : 'text-gray-700'}">${list.name}</span> |
| <span class="text-xs bg-gray-100 text-gray-800 px-2 py-1 rounded-full">${list.links.length} links</span> |
| </div> |
| `; |
| |
| listElement.addEventListener('click', () => { |
| currentListId = list.id; |
| renderLists(); |
| renderLinks(currentListId); |
| updateCurrentListHeader(); |
| }); |
| |
| listsContainer.appendChild(listElement); |
| }); |
| } |
| |
| |
| function renderLinks(listId) { |
| linksContainer.innerHTML = ''; |
| |
| const currentList = lists.find(list => list.id === listId); |
| if (!currentList) return; |
| |
| currentList.links.forEach(link => { |
| const linkCard = document.createElement('div'); |
| linkCard.className = 'link-card bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100 hover:shadow-md transition-all duration-200 fade-in'; |
| |
| |
| let iconColor = 'indigo'; |
| let iconClass = 'fas fa-globe'; |
| |
| if (link.icon === 'twitter') { |
| iconColor = 'blue'; |
| iconClass = 'fab fa-twitter'; |
| } else if (link.icon === 'youtube') { |
| iconColor = 'red'; |
| iconClass = 'fab fa-youtube'; |
| } else if (link.icon === 'github') { |
| iconColor = 'gray'; |
| iconClass = 'fab fa-github'; |
| } |
| |
| linkCard.innerHTML = ` |
| <div class="p-4"> |
| <div class="flex items-start"> |
| <div class="bg-${iconColor}-100 p-3 rounded-lg mr-3"> |
| <i class="${iconClass} text-${iconColor}-600"></i> |
| </div> |
| <div class="flex-1 min-w-0"> |
| <h3 class="font-medium text-gray-800 truncate">${link.title}</h3> |
| <p class="text-sm text-gray-500 truncate">${link.description}</p> |
| <a href="${link.url}" target="_blank" class="text-xs text-indigo-600 hover:underline block mt-1 truncate">${link.url}</a> |
| </div> |
| </div> |
| </div> |
| <div class="link-actions bg-gray-50 px-4 py-2 border-t border-gray-100 flex justify-end opacity-0 transition-opacity duration-200"> |
| <button class="p-1 text-gray-400 hover:text-indigo-600 edit-link" data-id="${link.id}"> |
| <i class="fas fa-pencil-alt text-sm"></i> |
| </button> |
| <button class="p-1 text-gray-400 hover:text-red-600 ml-2 delete-link" data-id="${link.id}"> |
| <i class="fas fa-trash-alt text-sm"></i> |
| </button> |
| </div> |
| `; |
| |
| linksContainer.appendChild(linkCard); |
| }); |
| |
| |
| document.querySelectorAll('.edit-link').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| const linkId = e.currentTarget.getAttribute('data-id'); |
| editLink(linkId); |
| }); |
| }); |
| |
| document.querySelectorAll('.delete-link').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| const linkId = e.currentTarget.getAttribute('data-id'); |
| deleteLink(linkId); |
| }); |
| }); |
| } |
| |
| |
| function updateCurrentListHeader() { |
| const currentList = lists.find(list => list.id === currentListId); |
| if (currentList) { |
| currentListName.textContent = currentList.name; |
| currentListDesc.textContent = currentList.description; |
| } |
| } |
| |
| |
| function createNewList() { |
| const name = newListName.value.trim(); |
| const description = newListDesc.value.trim(); |
| |
| if (!name) { |
| alert('Please enter a list name'); |
| return; |
| } |
| |
| const newList = { |
| id: 'list-' + Date.now(), |
| name, |
| description, |
| links: [] |
| }; |
| |
| lists.push(newList); |
| newListName.value = ''; |
| newListDesc.value = ''; |
| newListModal.classList.add('hidden'); |
| |
| currentListId = newList.id; |
| renderLists(); |
| renderLinks(currentListId); |
| updateCurrentListHeader(); |
| } |
| |
| |
| function openEditListModal() { |
| const currentList = lists.find(list => list.id === currentListId); |
| if (currentList) { |
| editListName.value = currentList.name; |
| editListDesc.value = currentList.description; |
| editListModal.classList.remove('hidden'); |
| } |
| } |
| |
| |
| function saveListChanges() { |
| const name = editListName.value.trim(); |
| const description = editListDesc.value.trim(); |
| |
| if (!name) { |
| alert('Please enter a list name'); |
| return; |
| } |
| |
| const listIndex = lists.findIndex(list => list.id === currentListId); |
| if (listIndex !== -1) { |
| lists[listIndex].name = name; |
| lists[listIndex].description = description; |
| |
| editListModal.classList.add('hidden'); |
| renderLists(); |
| updateCurrentListHeader(); |
| } |
| } |
| |
| |
| function deleteCurrentList() { |
| if (lists.length <= 1) { |
| alert('You must have at least one list'); |
| deleteModal.classList.add('hidden'); |
| return; |
| } |
| |
| lists = lists.filter(list => list.id !== currentListId); |
| currentListId = lists[0].id; |
| |
| deleteModal.classList.add('hidden'); |
| renderLists(); |
| renderLinks(currentListId); |
| updateCurrentListHeader(); |
| } |
| |
| |
| function toggleLinkForm() { |
| if (linkDetailsForm.classList.contains('hidden')) { |
| const url = newLinkUrl.value.trim(); |
| if (!url) { |
| alert('Please enter a URL first'); |
| return; |
| } |
| |
| |
| let title = ''; |
| try { |
| const urlObj = new URL(url); |
| title = urlObj.hostname.replace('www.', '').split('.')[0]; |
| title = title.charAt(0).toUpperCase() + title.slice(1); |
| } catch (e) { |
| title = 'New Link'; |
| } |
| |
| linkTitle.value = title; |
| linkCategory.value = ''; |
| linkDescription.value = ''; |
| linkDetailsForm.classList.remove('hidden'); |
| } else { |
| linkDetailsForm.classList.add('hidden'); |
| } |
| } |
| |
| |
| function addNewLink() { |
| const url = newLinkUrl.value.trim(); |
| const title = linkTitle.value.trim() || 'Untitled Link'; |
| const category = linkCategory.value.trim() || 'General'; |
| const description = linkDescription.value.trim() || 'No description'; |
| |
| if (!url) { |
| alert('Please enter a URL'); |
| return; |
| } |
| |
| |
| let icon = 'globe'; |
| try { |
| const domain = new URL(url).hostname; |
| if (domain.includes('twitter')) icon = 'twitter'; |
| else if (domain.includes('youtube')) icon = 'youtube'; |
| else if (domain.includes('github')) icon = 'github'; |
| } catch (e) { |
| console.error('Invalid URL'); |
| } |
| |
| const newLink = { |
| id: 'link-' + Date.now(), |
| title, |
| url, |
| description, |
| category, |
| icon |
| }; |
| |
| const listIndex = lists.findIndex(list => list.id === currentListId); |
| if (listIndex !== -1) { |
| lists[listIndex].links.push(newLink); |
| |
| newLinkUrl.value = ''; |
| linkDetailsForm.classList.add('hidden'); |
| renderLinks(currentListId); |
| } |
| } |
| |
| |
| function editLink(linkId) { |
| const currentList = lists.find(list => list.id === currentListId); |
| if (!currentList) return; |
| |
| const link = currentList.links.find(l => l.id === linkId); |
| if (!link) return; |
| |
| |
| deleteLink(linkId); |
| |
| newLinkUrl.value = link.url; |
| linkTitle.value = link.title; |
| linkCategory.value = link.category; |
| linkDescription.value = link.description; |
| linkDetailsForm.classList.remove('hidden'); |
| } |
| |
| |
| function deleteLink(linkId) { |
| if (!confirm('Are you sure you want to delete this link?')) return; |
| |
| const listIndex = lists.findIndex(list => list.id === currentListId); |
| if (listIndex !== -1) { |
| lists[listIndex].links = lists[listIndex].links.filter(link => link.id !== linkId); |
| renderLinks(currentListId); |
| } |
| } |
| |
| |
| document.addEventListener('DOMContentLoaded', init); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=kyupark/linklist" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |