Files
SiteCompanion/sitecompanion/content.js
2026-01-18 04:45:32 -05:00

144 lines
3.2 KiB
JavaScript

function findMinimumScope(text) {
if (!text) return null;
const normalized = text.trim();
if (!normalized) return null;
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
acceptNode: (node) => {
if (node.innerText.includes(normalized)) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_REJECT;
}
});
let deepest = null;
let node = walker.nextNode();
while (node) {
deepest = node;
node = walker.nextNode();
}
return deepest;
}
function createToolbar(presets, position = "bottom-right") {
let toolbar = document.getElementById("sitecompanion-toolbar");
if (toolbar) toolbar.remove();
toolbar = document.createElement("div");
toolbar.id = "sitecompanion-toolbar";
let posStyle = "";
switch (position) {
case "top-left":
posStyle = "top: 20px; left: 20px;";
break;
case "top-right":
posStyle = "top: 20px; right: 20px;";
break;
case "bottom-left":
posStyle = "bottom: 20px; left: 20px;";
break;
case "bottom-center":
posStyle = "bottom: 20px; left: 50%; transform: translateX(-50%);";
break;
case "bottom-right":
default:
posStyle = "bottom: 20px; right: 20px;";
break;
}
toolbar.style.cssText = `
position: fixed;
${posStyle}
background: #fff7ec;
border: 1px solid #e4d6c5;
border-radius: 12px;
padding: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
z-index: 999999;
display: flex;
gap: 8px;
font-family: system-ui, sans-serif;
`;
if (!presets || !presets.length) {
const label = document.createElement("span");
label.textContent = "SiteCompanion";
label.style.fontSize = "12px";
label.style.color = "#6b5f55";
toolbar.appendChild(label);
} else {
for (const preset of presets) {
const btn = document.createElement("button");
btn.textContent = preset.name;
btn.style.cssText = `
padding: 6px 12px;
background: #b14d2b;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 12px;
`;
btn.addEventListener("click", () => {
chrome.runtime.sendMessage({ type: "RUN_PRESET", presetId: preset.id });
});
toolbar.appendChild(btn);
}
}
document.body.appendChild(toolbar);
}
function matchUrl(url, pattern) {
if (!pattern) return false;
const regex = new RegExp("^" + pattern.split("*").join(".*") + "$");
try {
const urlObj = new URL(url);
const target = urlObj.hostname + urlObj.pathname;
return regex.test(target);
} catch {
return false;
}
}
async function refreshToolbar() {
const { sites = [], presets = [], toolbarPosition = "bottom-right" } = await chrome.storage.local.get(["sites", "presets", "toolbarPosition"]);
const currentUrl = window.location.href;
const site = sites.find(s => matchUrl(currentUrl, s.urlPattern));
if (site) {
createToolbar(presets, toolbarPosition);
}
}
const observer = new MutationObserver(() => {
// refreshToolbar(); // Debounce this?
});
// observer.observe(document.documentElement, { childList: true, subtree: true });
refreshToolbar();