From 379445c24457f21fb3247c31154b1c1159f4f7ca Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 23 May 2026 23:37:02 -0400 Subject: [PATCH] =?UTF-8?q?fc3g(ext):=20content=20script=20=E2=80=94=20flo?= =?UTF-8?q?ating=20'Add=20to=20FabledCurator'=20button=20on=20artist=20pag?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- extension/content/content-script.css | 27 +++++++++++++ extension/content/content-script.js | 60 ++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 extension/content/content-script.css create mode 100644 extension/content/content-script.js diff --git a/extension/content/content-script.css b/extension/content/content-script.css new file mode 100644 index 0000000..d55243f --- /dev/null +++ b/extension/content/content-script.css @@ -0,0 +1,27 @@ +.fc-add-source-btn { + all: revert; + position: fixed; bottom: 24px; right: 24px; z-index: 2147483647; + padding: 10px 16px; border-radius: 999px; border: none; + background: rgb(20, 23, 26); color: rgb(244, 186, 122); + font: 500 14px/1.2 system-ui, sans-serif; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); cursor: pointer; + transition: transform 100ms ease; +} +.fc-add-source-btn:hover { transform: translateY(-1px); } +.fc-add-source-btn:disabled { opacity: 0.6; cursor: wait; } + +.fc-toast { + all: revert; + position: fixed; bottom: 84px; right: 24px; z-index: 2147483647; + max-width: 360px; padding: 12px 16px; border-radius: 8px; + background: rgb(20, 23, 26); color: rgb(232, 228, 216); + font: 14px/1.4 system-ui, sans-serif; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); + animation: fc-toast-in 200ms ease; +} +.fc-toast--success { border-left: 3px solid rgb(244, 186, 122); } +.fc-toast--error { border-left: 3px solid rgb(220, 80, 80); } +@keyframes fc-toast-in { + from { transform: translateY(20px); opacity: 0; } + to { transform: translateY(0); opacity: 1; } +} diff --git a/extension/content/content-script.js b/extension/content/content-script.js new file mode 100644 index 0000000..51154b0 --- /dev/null +++ b/extension/content/content-script.js @@ -0,0 +1,60 @@ +(function () { + if (window.__fc_addsource_injected) return; + window.__fc_addsource_injected = true; + + evaluate(); + + const reEval = () => evaluate(); + window.addEventListener('popstate', reEval); + const origPush = history.pushState; + history.pushState = function () { origPush.apply(this, arguments); reEval(); }; + + function evaluate() { + const platform = getPlatformFromUrl(window.location.href); + const onArtist = platform && isArtistPage(window.location.href, platform); + let btn = document.getElementById('fc-add-source-btn'); + if (onArtist && !btn) injectButton(); + else if (!onArtist && btn) btn.remove(); + } + + function injectButton() { + const btn = document.createElement('button'); + btn.id = 'fc-add-source-btn'; + btn.className = 'fc-add-source-btn'; + btn.textContent = '+ Add to FabledCurator'; + btn.addEventListener('click', onClick); + document.body.appendChild(btn); + } + + async function onClick() { + const btn = document.getElementById('fc-add-source-btn'); + btn.disabled = true; + const original = btn.textContent; + btn.textContent = 'Adding…'; + try { + const r = await browser.runtime.sendMessage({ + type: 'ADD_AS_SOURCE', + url: window.location.href, + }); + if (r.error) { + showToast(`Error: ${r.error}`, 'error'); + } else { + const verb = r.created_source ? 'Added' : 'Already a source for'; + showToast(`${verb} ${r.artist?.name || 'artist'} (${r.source?.platform || ''})`, 'success'); + } + } catch (e) { + showToast(`Error: ${e.message}`, 'error'); + } finally { + btn.disabled = false; + btn.textContent = original; + } + } + + function showToast(text, kind) { + const t = document.createElement('div'); + t.className = `fc-toast fc-toast--${kind}`; + t.textContent = text; + document.body.appendChild(t); + setTimeout(() => t.remove(), 4000); + } +})();