From 0dad17106b510f54ff450c2f8427ef71a252553b Mon Sep 17 00:00:00 2001 From: "oleg.vodyanov91@gmail.com" Date: Sun, 13 Apr 2025 22:49:38 +0400 Subject: [PATCH] add static --- .gitignore | 1 - static/links/main.js | 152 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 static/links/main.js diff --git a/.gitignore b/.gitignore index 12b06c5..3acc06b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ init.sql .DS_Store Thumbs.db staticfiles/ -static/ __pycache__/ *.py[cod] diff --git a/static/links/main.js b/static/links/main.js new file mode 100644 index 0000000..f4cb8f8 --- /dev/null +++ b/static/links/main.js @@ -0,0 +1,152 @@ +const newLinkInput = document.getElementById('newLinkInput'); +const addLinkBtn = document.getElementById('addLinkBtn'); +const newLinksContainer = document.getElementById('newLinksContainer'); +const watchedLinksContainer = document.getElementById('watchedLinksContainer'); + +let linksData = []; + +// Fetch all links from the server +function loadLinks() { + fetch('/api/links/') + .then(res => res.json()) + .then(data => { + linksData = data; // store in a global variable + renderLinks(); + }) + .catch(err => console.error(err)); +} + +// Render the links into the two tabs +function renderLinks() { + // separate them + const newLinks = linksData.filter(link => !link.watched); + const watchedLinks = linksData.filter(link => link.watched); + + const newRow = document.createElement('div'); + newRow.className = 'row gy-4'; + + // Render "New" links + newLinksContainer.innerHTML = ''; + newLinks.forEach(link => { + const col = document.createElement('div'); + col.className = 'col-12 col-sm-6 col-md-4 col-lg-3'; // responsive columns + col.appendChild(createLinkElement(link, false)); + newRow.appendChild(col); + }); + + newLinksContainer.appendChild(newRow); + + const watchedRow = document.createElement('div'); + watchedRow.className = 'row gy-4'; + + // Render "Watched" links + watchedLinksContainer.innerHTML = ''; + watchedLinks.forEach(link => { + const col = document.createElement('div'); + col.className = 'col-12 col-sm-6 col-md-4 col-lg-3'; + col.appendChild(createLinkElement(link, true)); + watchedRow.appendChild(col); + }); + + watchedLinksContainer.appendChild(watchedRow); + + reinitializeInstagramEmbeds(); +} + +// Create a DOM element for a single link +function createLinkElement(link, isWatched) { + const wrapper = document.createElement('div'); + wrapper.className = 'mb-3'; + + // Instagram embed blockquote + const blockquote = document.createElement('blockquote'); + blockquote.className = 'instagram-media'; + blockquote.setAttribute('data-instgrm-permalink', link.url); + blockquote.style.background = '#FFF'; + + const p = document.createElement('p'); + p.innerText = 'Loading Instagram...'; + blockquote.appendChild(p); + wrapper.appendChild(blockquote); + + // Button to mark watched if it's not watched + if (!isWatched) { + const watchButton = document.createElement('button'); + watchButton.className = 'btn btn-sm btn-secondary'; + watchButton.innerText = 'Mark Watched'; + watchButton.onclick = () => markLinkWatched(link.id); + wrapper.appendChild(watchButton); + } + + // Delete button + const deleteButton = document.createElement('button'); + deleteButton.innerText = 'Delete'; + deleteButton.className = 'btn btn-sm btn-danger'; + deleteButton.onclick = () => deleteLink(link.id); + wrapper.appendChild(deleteButton); + + return wrapper; +} + +function deleteLink(linkId) { + fetch(`/api/links/${linkId}/delete/`, { + method: 'DELETE' + }) + .then(res => { + if (res.ok) { + linksData = linksData.filter(link => link.id !== linkId); + renderLinks(); + reinitializeInstagramEmbeds(); + } + }) + .catch(err => console.error(err)); +} + +// Re-run the Instagram embed script after we’ve injected new blockquotes +function reinitializeInstagramEmbeds() { + if (window.instgrm) { + window.instgrm.Embeds.process(); + } +} + +// Mark a link as watched +function markLinkWatched(linkId) { + fetch(`/api/links/${linkId}/watched/`, { + method: 'PATCH' + }) + .then(res => res.json()) + .then(updatedLink => { + // Update the local array + const idx = linksData.findIndex(l => l.id === updatedLink.id); + if (idx !== -1) { + linksData[idx] = updatedLink; + } + renderLinks(); + reinitializeInstagramEmbeds(); + }) + .catch(err => console.error(err)); +} + +// Add new link +addLinkBtn.addEventListener('click', () => { + const newUrl = newLinkInput.value.trim(); + if (!newUrl) return; + + fetch('/api/links/add/', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ url: newUrl }) + }) + .then(res => res.json()) + .then(addedLink => { + // update local data + linksData.push(addedLink); + newLinkInput.value = ''; + renderLinks(); + reinitializeInstagramEmbeds(); + }) + .catch(err => console.error(err)); +}); + +// On page load +loadLinks();