diff --git a/browser-extension/background.js b/browser-extension/background.js index 31120cb..fd21c04 100644 --- a/browser-extension/background.js +++ b/browser-extension/background.js @@ -26,6 +26,12 @@ chrome.runtime.onInstalled.addListener(() => { title: 'Clip selection to rNotes', contexts: ['selection'], }); + + chrome.contextMenus.create({ + id: 'unlock-article', + title: 'Unlock & Clip article to rNotes', + contexts: ['page', 'link'], + }); }); // --- Helpers --- @@ -132,6 +138,31 @@ async function uploadImage(imageUrl) { return response.json(); } +async function unlockArticle(url) { + const token = await getToken(); + if (!token) { + showNotification('rNotes Error', 'Not signed in. Open extension settings to sign in.'); + return null; + } + + const settings = await getSettings(); + const response = await fetch(`${settings.host}/api/articles/unlock`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}`, + }, + body: JSON.stringify({ url }), + }); + + if (!response.ok) { + const text = await response.text(); + throw new Error(`Unlock failed: ${response.status} ${text}`); + } + + return response.json(); +} + // --- Context Menu Handler --- chrome.contextMenus.onClicked.addListener(async (info, tab) => { @@ -197,6 +228,28 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => { break; } + case 'unlock-article': { + const targetUrl = info.linkUrl || tab.url; + showNotification('Unlocking Article', `Finding readable version of ${new URL(targetUrl).hostname}...`); + + const result = await unlockArticle(targetUrl); + if (result && result.success && result.archiveUrl) { + // Create a CLIP note with the archive URL + await createNote({ + title: tab.title || 'Unlocked Article', + content: `
Unlocked via ${result.strategy}
Original: ${targetUrl}
Archive: ${result.archiveUrl}
`, + type: 'CLIP', + url: targetUrl, + }); + showNotification('Article Unlocked', `Readable version found via ${result.strategy}`); + // Open the unlocked article in a new tab + chrome.tabs.create({ url: result.archiveUrl }); + } else { + showNotification('Unlock Failed', result?.error || 'No archived version found'); + } + break; + } + case 'clip-selection': { // Get selection HTML let content = ''; diff --git a/browser-extension/popup.html b/browser-extension/popup.html index d0db5ac..69b33a8 100644 --- a/browser-extension/popup.html +++ b/browser-extension/popup.html @@ -133,6 +133,14 @@ color: #e5e5e5; border: 1px solid #404040; } + .btn-unlock { + background: #172554; + color: #93c5fd; + border: 1px solid #1e40af; + } + .btn-unlock svg { + flex-shrink: 0; + } .status { margin: 0 14px 10px; @@ -212,6 +220,16 @@ +