Last active
October 21, 2024 13:41
-
-
Save SMUsamaShah/274b50a188b96ae0cda69ff79821cde5 to your computer and use it in GitHub Desktop.
Save current link to dynalist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
const TOKEN = "YOUR_DYNALIST_TOKEN"; | |
const FILE_ID = "YOUR_FILE_ID"; | |
const INBOX_NODE_ID = "YOUR_INBOX_NODE_ID"; | |
let savedNodeId = null; | |
let updateTimer = null; | |
// Utility Functions | |
// DOM Utils | |
function createDiv() { return document.createElement('div'); } | |
function appendToBody(element) { document.body.appendChild(element); } | |
function setInnerHTML(element, html) { element.innerHTML = html; } | |
function querySelector(parent, selector) { return parent.querySelector(selector); } | |
function getSelectedText() { return window.getSelection().toString().trim(); } | |
// UI Utils | |
function setStatus(statusSpan, message) { statusSpan.textContent = message; } | |
function hideElement(element) { element.style.display = 'none'; } | |
function showElement(element) { element.style.display = 'inline'; } | |
function removeElement(element) { element.remove(); } | |
function focusElement(element) { element.focus(); } | |
// API Utils | |
async function callDynalistApi(endpoint, changes) { | |
const response = await fetch(endpoint, { | |
method: "POST", | |
headers: {"Content-Type": "application/json"}, | |
body: JSON.stringify({ | |
token: TOKEN, | |
file_id: FILE_ID, | |
changes: changes | |
}) | |
}); | |
return await response.json(); | |
} | |
// DOM Creation | |
function createPopup(description = "") { | |
const popupDiv = createDiv(); | |
const popupHtml = `<div id="dynalist-popup" style="position:fixed; top:10px; right:10px; z-index:999999; background:white; padding:15px; border:1px solid #ccc; border-radius:4px; box-shadow:0 2px 8px rgba(0,0,0,0.2); width:300px;"> | |
<h3 id="dyn-title" style="margin:0 0 10px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;"></h3> | |
<input type="text" id="dyn-description" placeholder="Add description..." style="width:100%; margin-bottom:10px; padding:5px; box-sizing:border-box;" value="${description}"> | |
<div style="display:flex; justify-content:space-between; align-items:center;"> | |
<button id="dyn-delete">Delete</button> | |
<button id="dyn-close">Close</button> | |
<span id="dyn-status" style="margin-left:10px;"></span> | |
</div> | |
</div>`; | |
setInnerHTML(popupDiv, popupHtml); | |
appendToBody(popupDiv); | |
return popupDiv.firstElementChild; | |
} | |
function getElements(popup) { | |
return { | |
titleElem: querySelector(popup, '#dyn-title'), | |
descInput: querySelector(popup, '#dyn-description'), | |
deleteBtn: querySelector(popup, '#dyn-delete'), | |
closeBtn: querySelector(popup, '#dyn-close'), | |
statusSpan: querySelector(popup, '#dyn-status') | |
}; | |
} | |
// API Operations | |
async function saveToDynalist(title, url, description = "") { | |
const result = await callDynalistApi( | |
"https://dynalist.io/api/v1/doc/edit", | |
[{ | |
action: "insert", | |
parent_id: INBOX_NODE_ID, | |
index: -1, | |
content: `${title} ${url}`, | |
note: `${description}`, | |
checked: false | |
}] | |
); | |
if (result._code === "Ok" && result.new_node_ids?.length > 0) { | |
return result.new_node_ids[0]; | |
} | |
throw new Error(result._msg || 'Failed to save to Dynalist'); | |
} | |
async function updateDynalist(nodeId, description) { | |
return await callDynalistApi( | |
"https://dynalist.io/api/v1/doc/edit", | |
[{ | |
action: "edit", | |
node_id: nodeId, | |
note: description | |
}] | |
); | |
} | |
async function deleteDynalist(nodeId) { | |
return await callDynalistApi( | |
"https://dynalist.io/api/v1/doc/edit", | |
[{ | |
action: "delete", | |
node_id: nodeId | |
}] | |
); | |
} | |
// Event Handlers | |
function handleDescriptionInput(e, elements) { | |
if (!savedNodeId) return; | |
setStatus(elements.statusSpan, 'Updating...'); | |
clearTimeout(updateTimer); | |
updateTimer = setTimeout(async () => { | |
try { | |
const result = await updateDynalist(savedNodeId, e.target.value); | |
setStatus(elements.statusSpan, result._code === "Ok" ? 'Updated' : 'Error updating'); | |
} catch (err) { | |
setStatus(elements.statusSpan, 'Error updating'); | |
console.error(err); | |
} | |
}, 400); | |
} | |
async function handleDelete(elements, popup) { | |
if (!savedNodeId) return; | |
setStatus(elements.statusSpan, 'Deleting...'); | |
try { | |
const result = await deleteDynalist(savedNodeId); | |
if (result._code === "Ok") { | |
setStatus(elements.statusSpan, 'Deleted'); | |
setTimeout(() => removeElement(popup), 500); | |
} else { | |
setStatus(elements.statusSpan, 'Error deleting'); | |
} | |
} catch (err) { | |
setStatus(elements.statusSpan, 'Error deleting'); | |
console.error(err); | |
} | |
} | |
// Initial Save | |
async function performInitialSave(elements) { | |
setStatus(elements.statusSpan, 'Saving...'); | |
try { | |
savedNodeId = await saveToDynalist(document.title, window.location.href, elements.descInput.value); | |
setStatus(elements.statusSpan, 'Saved'); | |
showElement(elements.deleteBtn); | |
return true; | |
} catch (err) { | |
setStatus(elements.statusSpan, 'Error saving'); | |
console.error(err); | |
return false; | |
} | |
} | |
// Setup | |
function setupEventListeners(popup, elements) { | |
elements.descInput.addEventListener('input', e => handleDescriptionInput(e, elements)); | |
elements.deleteBtn.addEventListener('click', () => handleDelete(elements, popup)); | |
elements.closeBtn.addEventListener('click', () => removeElement(popup)); | |
} | |
function initializePopup(popup, elements) { | |
elements.titleElem.textContent = document.title; | |
hideElement(elements.deleteBtn); | |
} | |
// Main function | |
async function init() { | |
const selectedText = getSelectedText(); | |
const popup = createPopup(selectedText); | |
const elements = getElements(popup); | |
initializePopup(popup, elements); | |
setupEventListeners(popup, elements); | |
const saveSuccessful = await performInitialSave(elements); | |
if (saveSuccessful) { | |
focusElement(elements.descInput); | |
} | |
} | |
init(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment