fc3g(ext): content script — floating 'Add to FabledCurator' button on artist pages
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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; }
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user