Update pluginsupport.js

Signed-off-by: AvaLilac <amyshimplays@gmail.com>
This commit is contained in:
AvaLilac 2026-03-22 18:10:21 -04:00 committed by GitHub
parent e9b04f7dc5
commit 449c819214
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -55,6 +55,164 @@
renderPanel(); renderPanel();
} }
function preloadMonaco() {
return new Promise(resolve => {
if (window.monaco) return resolve();
const loader = document.createElement("script");
loader.src = "https://cdn.jsdelivr.net/npm/monaco-editor@0.45.0/min/vs/loader.js";
loader.onload = function () {
require.config({ paths: { vs: "https://cdn.jsdelivr.net/npm/monaco-editor@0.45.0/min/vs" } });
require(["vs/editor/editor.main"], () => resolve());
};
document.head.appendChild(loader);
});
}
async function openViewerPanel(plugin) {
await preloadMonaco();
const existing = document.getElementById("avia-plugin-viewer-panel");
if (existing) existing.remove();
const panel = document.createElement("div");
panel.id = "avia-plugin-viewer-panel";
Object.assign(panel.style, {
position: "fixed",
bottom: "24px",
left: "24px",
width: "700px",
height: "480px",
background: "var(--md-sys-color-surface, #1e1e1e)",
borderRadius: "16px",
boxShadow: "0 8px 28px rgba(0,0,0,0.45)",
zIndex: "9999999",
display: "flex",
flexDirection: "column",
overflow: "hidden",
border: "1px solid rgba(255,255,255,0.08)",
backdropFilter: "blur(12px)",
color: "#fff"
});
const header = document.createElement("div");
Object.assign(header.style, {
padding: "14px 16px",
fontWeight: "600",
fontSize: "14px",
background: "var(--md-sys-color-surface-container, rgba(255,255,255,0.04))",
borderBottom: "1px solid rgba(255,255,255,0.08)",
cursor: "move",
display: "flex",
alignItems: "center",
gap: "10px",
flex: "0 0 auto"
});
const titleText = document.createElement("span");
titleText.textContent = `Viewing: ${plugin.name}`;
titleText.style.flex = "1";
const readOnlyBadge = document.createElement("span");
readOnlyBadge.textContent = "READ ONLY";
Object.assign(readOnlyBadge.style, {
fontSize: "10px",
fontWeight: "700",
letterSpacing: "0.08em",
padding: "2px 8px",
borderRadius: "20px",
background: "rgba(255,180,0,0.15)",
color: "#ffb400",
border: "1px solid rgba(255,180,0,0.3)"
});
const closeBtn = document.createElement("div");
closeBtn.textContent = "✕";
Object.assign(closeBtn.style, {
cursor: "pointer",
opacity: "0.6",
fontSize: "15px",
lineHeight: "1",
padding: "2px 4px"
});
closeBtn.onmouseenter = () => closeBtn.style.opacity = "1";
closeBtn.onmouseleave = () => closeBtn.style.opacity = "0.6";
closeBtn.onclick = () => panel.remove();
header.appendChild(titleText);
header.appendChild(readOnlyBadge);
header.appendChild(closeBtn);
const urlBar = document.createElement("div");
Object.assign(urlBar.style, {
padding: "8px 16px",
borderBottom: "1px solid rgba(255,255,255,0.06)",
fontSize: "11px",
color: "rgba(255,255,255,0.35)",
fontFamily: "monospace",
background: "rgba(0,0,0,0.15)",
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
flex: "0 0 auto"
});
urlBar.textContent = plugin.url;
urlBar.title = plugin.url;
const editorContainer = document.createElement("div");
editorContainer.style.flex = "1";
editorContainer.style.overflow = "hidden";
const loadingMsg = document.createElement("div");
Object.assign(loadingMsg.style, {
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "100%",
opacity: "0.4",
fontSize: "13px"
});
loadingMsg.textContent = "Fetching source…";
editorContainer.appendChild(loadingMsg);
panel.appendChild(header);
panel.appendChild(urlBar);
panel.appendChild(editorContainer);
document.body.appendChild(panel);
enableDragOn(panel, header);
let code;
try {
const res = await fetch(plugin.url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
code = await res.text();
} catch (err) {
loadingMsg.textContent = `Failed to fetch source: ${err.message}`;
loadingMsg.style.color = "#ff4d4d";
loadingMsg.style.opacity = "1";
return;
}
editorContainer.removeChild(loadingMsg);
monaco.editor.create(editorContainer, {
value: code,
language: "javascript",
theme: "vs-dark",
readOnly: true,
automaticLayout: true,
minimap: { enabled: true },
fontSize: 13,
scrollBeyondLastLine: false,
wordWrap: "off",
domReadOnly: true,
renderValidationDecorations: "off",
renderLineHighlight: "none",
cursorStyle: "block",
cursorBlinking: "solid"
});
}
function togglePluginsPanel() { function togglePluginsPanel() {
let panel = document.getElementById('avia-plugins-panel'); let panel = document.getElementById('avia-plugins-panel');
if (panel) { if (panel) {
@ -63,59 +221,77 @@
} }
panel = document.createElement('div'); panel = document.createElement('div');
panel.id = 'avia-plugins-panel'; panel.id = 'avia-plugins-panel';
panel.style.position = 'fixed'; Object.assign(panel.style, {
panel.style.bottom = '24px'; position: 'fixed',
panel.style.right = '24px'; bottom: '24px',
panel.style.width = '520px'; right: '24px',
panel.style.height = '460px'; width: '520px',
panel.style.background = 'var(--md-sys-color-surface, #1e1e1e)'; height: '460px',
panel.style.color = 'var(--md-sys-color-on-surface, #fff)'; background: 'var(--md-sys-color-surface, #1e1e1e)',
panel.style.borderRadius = '16px'; color: 'var(--md-sys-color-on-surface, #fff)',
panel.style.boxShadow = '0 8px 28px rgba(0,0,0,0.35)'; borderRadius: '16px',
panel.style.zIndex = '999999'; boxShadow: '0 8px 28px rgba(0,0,0,0.35)',
panel.style.display = 'flex'; zIndex: '999999',
panel.style.flexDirection = 'column'; display: 'flex',
panel.style.overflow = 'hidden'; flexDirection: 'column',
panel.style.border = '1px solid rgba(255,255,255,0.08)'; overflow: 'hidden',
panel.style.backdropFilter = 'blur(12px)'; border: '1px solid rgba(255,255,255,0.08)',
backdropFilter: 'blur(12px)'
});
const header = document.createElement('div'); const header = document.createElement('div');
header.textContent = 'Plugins'; header.textContent = 'Plugins';
header.style.padding = '14px 16px'; Object.assign(header.style, {
header.style.fontWeight = '600'; padding: '14px 16px',
header.style.fontSize = '14px'; fontWeight: '600',
header.style.background = 'var(--md-sys-color-surface-container, rgba(255,255,255,0.04))'; fontSize: '14px',
header.style.borderBottom = '1px solid rgba(255,255,255,0.08)'; background: 'var(--md-sys-color-surface-container, rgba(255,255,255,0.04))',
header.style.cursor = 'move'; borderBottom: '1px solid rgba(255,255,255,0.08)',
cursor: 'move'
});
const closeBtn = document.createElement('div'); const closeBtn = document.createElement('div');
closeBtn.textContent = '✕'; closeBtn.textContent = '✕';
closeBtn.style.position = 'absolute'; Object.assign(closeBtn.style, {
closeBtn.style.top = '12px'; position: 'absolute',
closeBtn.style.right = '16px'; top: '12px',
closeBtn.style.cursor = 'pointer'; right: '16px',
closeBtn.style.opacity = '0.7'; cursor: 'pointer',
opacity: '0.7'
});
closeBtn.onclick = () => panel.style.display = 'none'; closeBtn.onclick = () => panel.style.display = 'none';
const controlsBar = document.createElement('div'); const controlsBar = document.createElement('div');
controlsBar.style.padding = '12px 16px'; Object.assign(controlsBar.style, {
controlsBar.style.display = 'flex'; padding: '12px 16px',
controlsBar.style.gap = '8px'; display: 'flex',
controlsBar.style.alignItems = 'center'; gap: '8px',
controlsBar.style.borderBottom = '1px solid rgba(255,255,255,0.08)'; alignItems: 'center',
controlsBar.style.flex = '0 0 auto'; borderBottom: '1px solid rgba(255,255,255,0.08)',
flex: '0 0 auto'
});
const content = document.createElement('div'); const content = document.createElement('div');
content.id = 'avia-plugins-content'; content.id = 'avia-plugins-content';
content.style.flex = '1'; Object.assign(content.style, {
content.style.overflow = 'auto'; flex: '1',
content.style.padding = '16px'; overflow: 'auto',
padding: '16px'
});
const nameInput = document.createElement('input'); const nameInput = document.createElement('input');
nameInput.placeholder = 'Name'; nameInput.placeholder = 'Name';
styleInput(nameInput); styleInput(nameInput);
nameInput.style.width = '110px'; nameInput.style.width = '110px';
const urlInput = document.createElement('input'); const urlInput = document.createElement('input');
urlInput.placeholder = 'Plugin URL'; urlInput.placeholder = 'Plugin URL';
styleInput(urlInput); styleInput(urlInput);
urlInput.style.flex = '1'; urlInput.style.flex = '1';
const addBtn = document.createElement('button'); const addBtn = document.createElement('button');
addBtn.textContent = 'Add'; addBtn.textContent = '+ Add';
styleBtn(addBtn);
addBtn.onclick = () => { addBtn.onclick = () => {
const name = nameInput.value.trim(); const name = nameInput.value.trim();
const url = urlInput.value.trim(); const url = urlInput.value.trim();
@ -127,14 +303,17 @@
urlInput.value = ''; urlInput.value = '';
renderPanel(); renderPanel();
}; };
const refreshAll = document.createElement('button'); const refreshAll = document.createElement('button');
refreshAll.textContent = 'Refresh'; refreshAll.textContent = 'Refresh';
styleBtn(refreshAll);
refreshAll.onclick = () => { refreshAll.onclick = () => {
const plugins = getPlugins(); const plugins = getPlugins();
plugins.forEach(p => { plugins.forEach(p => {
if (p.enabled) queuePlugin(p, true); if (p.enabled) queuePlugin(p, true);
}); });
}; };
controlsBar.appendChild(nameInput); controlsBar.appendChild(nameInput);
controlsBar.appendChild(urlInput); controlsBar.appendChild(urlInput);
controlsBar.appendChild(addBtn); controlsBar.appendChild(addBtn);
@ -144,7 +323,7 @@
panel.appendChild(controlsBar); panel.appendChild(controlsBar);
panel.appendChild(content); panel.appendChild(content);
document.body.appendChild(panel); document.body.appendChild(panel);
enableDrag(panel, header); enableDragOn(panel, header);
renderPanel(); renderPanel();
} }
@ -155,22 +334,41 @@
const plugins = getPlugins(); const plugins = getPlugins();
const runningSnapshot = { ...runningPlugins }; const runningSnapshot = { ...runningPlugins };
const errorSnapshot = { ...pluginErrors }; const errorSnapshot = { ...pluginErrors };
if (plugins.length === 0) {
const empty = document.createElement('div');
empty.textContent = 'No plugins yet. Add one above.';
Object.assign(empty.style, { opacity: '0.4', fontSize: '13px' });
content.appendChild(empty);
return;
}
plugins.forEach((plugin, index) => { plugins.forEach((plugin, index) => {
const isRunning = !!runningSnapshot[plugin.url]; const isRunning = !!runningSnapshot[plugin.url];
const hasError = !!errorSnapshot[plugin.url]; const hasError = !!errorSnapshot[plugin.url];
const row = document.createElement('div'); const row = document.createElement('div');
row.style.display = 'flex'; Object.assign(row.style, {
row.style.justifyContent = 'space-between'; display: 'flex',
row.style.alignItems = 'center'; justifyContent: 'space-between',
row.style.marginBottom = '12px'; alignItems: 'center',
marginBottom: '12px',
padding: '10px 12px',
borderRadius: '10px',
background: 'rgba(255,255,255,0.04)',
border: '1px solid rgba(255,255,255,0.06)'
});
const left = document.createElement('div'); const left = document.createElement('div');
left.style.display = 'flex'; Object.assign(left.style, { display: 'flex', alignItems: 'center', gap: '10px' });
left.style.alignItems = 'center';
left.style.gap = '10px';
const statusDot = document.createElement('div'); const statusDot = document.createElement('div');
statusDot.style.width = '10px'; Object.assign(statusDot.style, {
statusDot.style.height = '10px'; width: '10px',
statusDot.style.borderRadius = '50%'; height: '10px',
borderRadius: '50%',
flexShrink: '0'
});
if (hasError) { if (hasError) {
statusDot.style.background = '#ff4d4d'; statusDot.style.background = '#ff4d4d';
statusDot.style.boxShadow = '0 0 6px #ff4d4d'; statusDot.style.boxShadow = '0 0 6px #ff4d4d';
@ -180,15 +378,20 @@
} else { } else {
statusDot.style.background = '#777'; statusDot.style.background = '#777';
} }
const name = document.createElement('div'); const name = document.createElement('div');
name.textContent = plugin.name; name.textContent = plugin.name;
name.style.fontSize = '13px';
left.appendChild(statusDot); left.appendChild(statusDot);
left.appendChild(name); left.appendChild(name);
const controls = document.createElement('div'); const controls = document.createElement('div');
controls.style.display = 'flex'; Object.assign(controls.style, { display: 'flex', gap: '6px' });
controls.style.gap = '6px';
const toggle = document.createElement('button'); const toggle = document.createElement('button');
toggle.textContent = plugin.enabled ? 'Disable' : 'Enable'; toggle.textContent = plugin.enabled ? 'Disable' : 'Enable';
styleBtn(toggle);
toggle.onclick = () => { toggle.onclick = () => {
plugin.enabled = !plugin.enabled; plugin.enabled = !plugin.enabled;
setPlugins(plugins); setPlugins(plugins);
@ -196,15 +399,24 @@
else stopPlugin(plugin); else stopPlugin(plugin);
renderPanel(); renderPanel();
}; };
const viewBtn = document.createElement('button');
viewBtn.textContent = 'View';
styleBtn(viewBtn, 'rgba(100,160,255,0.15)');
viewBtn.onclick = () => openViewerPanel(plugin);
const remove = document.createElement('button'); const remove = document.createElement('button');
remove.textContent = '✕'; remove.textContent = '✕';
styleBtn(remove, 'rgba(255,80,80,0.15)');
remove.onclick = () => { remove.onclick = () => {
stopPlugin(plugin); stopPlugin(plugin);
plugins.splice(index, 1); plugins.splice(index, 1);
setPlugins(plugins); setPlugins(plugins);
renderPanel(); renderPanel();
}; };
controls.appendChild(toggle); controls.appendChild(toggle);
controls.appendChild(viewBtn);
controls.appendChild(remove); controls.appendChild(remove);
row.appendChild(left); row.appendChild(left);
row.appendChild(controls); row.appendChild(controls);
@ -213,21 +425,43 @@
} }
function styleInput(input) { function styleInput(input) {
input.style.padding = '6px 8px'; Object.assign(input.style, {
input.style.borderRadius = '8px'; padding: '6px 8px',
input.style.border = '1px solid rgba(255,255,255,0.1)'; borderRadius: '8px',
input.style.background = 'rgba(255,255,255,0.05)'; border: '1px solid rgba(255,255,255,0.1)',
input.style.color = '#fff'; background: 'rgba(255,255,255,0.05)',
color: '#fff',
fontSize: '13px'
});
} }
function enableDrag(panel, header) { function styleBtn(btn, bg) {
Object.assign(btn.style, {
padding: '5px 12px',
borderRadius: '8px',
border: 'none',
background: bg || 'rgba(255,255,255,0.08)',
color: '#fff',
cursor: 'pointer',
fontSize: '12px',
whiteSpace: 'nowrap'
});
btn.onmouseenter = () => btn.style.opacity = '0.75';
btn.onmouseleave = () => btn.style.opacity = '1';
}
function enableDragOn(panel, header) {
let isDragging = false, offsetX, offsetY; let isDragging = false, offsetX, offsetY;
header.addEventListener('mousedown', e => { header.addEventListener('mousedown', e => {
isDragging = true; isDragging = true;
offsetX = e.clientX - panel.offsetLeft; offsetX = e.clientX - panel.offsetLeft;
offsetY = e.clientY - panel.offsetTop; offsetY = e.clientY - panel.offsetTop;
document.body.style.userSelect = 'none';
});
document.addEventListener('mouseup', () => {
isDragging = false;
document.body.style.userSelect = '';
}); });
document.addEventListener('mouseup', () => isDragging = false);
document.addEventListener('mousemove', e => { document.addEventListener('mousemove', e => {
if (!isDragging) return; if (!isDragging) return;
panel.style.left = (e.clientX - offsetX) + 'px'; panel.style.left = (e.clientX - offsetX) + 'px';
@ -269,10 +503,7 @@ pluginsBtn.insertBefore(svg, pluginsBtn.firstChild);
function waitForBody(callback) { function waitForBody(callback) {
if (document.body) callback(); if (document.body) callback();
else new MutationObserver((obs) => { else new MutationObserver((obs) => {
if (document.body) { if (document.body) { obs.disconnect(); callback(); }
obs.disconnect();
callback();
}
}).observe(document.documentElement, { childList: true }); }).observe(document.documentElement, { childList: true });
} }
@ -280,6 +511,7 @@ pluginsBtn.insertBefore(svg, pluginsBtn.firstChild);
const observer = new MutationObserver(() => injectButtons()); const observer = new MutationObserver(() => injectButtons());
observer.observe(document.body, { childList: true, subtree: true }); observer.observe(document.body, { childList: true, subtree: true });
injectButtons(); injectButtons();
preloadMonaco();
}); });
getPlugins().forEach(plugin => { getPlugins().forEach(plugin => {