Merge MonacoCSS Plugin directly into Themes as the native panel

Signed-off-by: AvaLilac <257690424+AvaLilac@users.noreply.github.com>
This commit is contained in:
AvaLilac 2026-04-06 18:43:09 -04:00 committed by GitHub
parent 8b0e6588fd
commit dec110d795
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -4,7 +4,8 @@
window.__AVIA_THEMES_LOADED__ = true; window.__AVIA_THEMES_LOADED__ = true;
const STORAGE_KEY = "avia_themes"; const STORAGE_KEY = "avia_themes";
let editingTheme = null; let editingThemeId = null;
let monacoEditorInstance = null;
const TEMPLATE = `/* const TEMPLATE = `/*
@name Whatever name here @name Whatever name here
@ -18,6 +19,19 @@
const getThemes = () => JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); const getThemes = () => JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]");
const setThemes = (data) => localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); const setThemes = (data) => localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
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);
});
}
function parseMeta(css) { function parseMeta(css) {
const name = css.match(/@name\s+(.+)/)?.[1] || "Unknown Theme"; const name = css.match(/@name\s+(.+)/)?.[1] || "Unknown Theme";
const author = css.match(/@author\s+(.+)/)?.[1] || "Unknown"; const author = css.match(/@author\s+(.+)/)?.[1] || "Unknown";
@ -49,8 +63,7 @@
function applyThemes() { function applyThemes() {
document.querySelectorAll(".avia-theme-style").forEach(e => e.remove()); document.querySelectorAll(".avia-theme-style").forEach(e => e.remove());
const themes = getThemes(); getThemes().forEach(theme => {
themes.forEach(theme=>{
if (!theme.enabled) return; if (!theme.enabled) return;
const style = document.createElement("style"); const style = document.createElement("style");
style.className = "avia-theme-style"; style.className = "avia-theme-style";
@ -93,44 +106,63 @@
}); });
} }
function openThemeEditor(theme){ async function openThemeEditor(themeId) {
editingTheme = theme; await preloadMonaco();
let panel = document.getElementById('avia-theme-editor');
editingThemeId = themeId;
const themes = getThemes();
const theme = themes.find(t => t.id === themeId);
if (!theme) return;
const meta = parseMeta(theme.css);
let panel = document.getElementById("avia-theme-editor");
if (panel) { if (panel) {
panel.style.display = "flex"; panel.style.display = "flex";
panel.querySelector("textarea").value = theme.css; panel.querySelector("#avia-theme-editor-title").textContent = "Theme Editor — " + meta.name;
if (monacoEditorInstance) {
monacoEditorInstance._aviaThemeId = themeId;
const model = monacoEditorInstance.getModel();
if (model) model.setValue(theme.css || "");
}
return; return;
} }
panel = document.createElement("div"); panel = document.createElement("div");
panel.id = "avia-theme-editor"; panel.id = "avia-theme-editor";
Object.assign(panel.style, { Object.assign(panel.style, {
position: "fixed", position: "fixed",
bottom: "24px", bottom: "24px",
right: "24px", right: "24px",
width:"420px", width: "650px",
height:"340px", height: "420px",
background: "var(--md-sys-color-surface, #1e1e1e)", background: "var(--md-sys-color-surface, #1e1e1e)",
color: "var(--md-sys-color-on-surface, #fff)", color: "var(--md-sys-color-on-surface, #fff)",
borderRadius: "16px", borderRadius: "16px",
boxShadow: "0 8px 28px rgba(0,0,0,0.35)", boxShadow: "0 8px 28px rgba(0,0,0,0.35)",
zIndex:999999, zIndex: "9999999",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
overflow: "hidden", overflow: "hidden",
border: "1px solid rgba(255,255,255,0.08)", border: "1px solid rgba(255,255,255,0.08)",
backdropFilter: "blur(12px)" backdropFilter: "blur(12px)"
}); });
const header = document.createElement("div"); const header = document.createElement("div");
header.textContent="Theme Editor"; header.id = "avia-theme-editor-title";
header.textContent = "Theme Editor — " + meta.name;
Object.assign(header.style, { Object.assign(header.style, {
padding: "14px 16px", padding: "14px 16px",
fontWeight: "600", fontWeight: "600",
fontSize: "14px", fontSize: "14px",
background: "var(--md-sys-color-surface-container, rgba(255,255,255,0.04))", background: "var(--md-sys-color-surface-container, rgba(255,255,255,0.04))",
borderBottom: "1px solid rgba(255,255,255,0.08)", borderBottom: "1px solid rgba(255,255,255,0.08)",
cursor:"move" cursor: "move",
color: "#fff",
flex: "0 0 auto"
}); });
makeDraggable(panel, header); makeDraggable(panel, header);
const close = document.createElement("div"); const close = document.createElement("div");
close.textContent = "✕"; close.textContent = "✕";
Object.assign(close.style, { Object.assign(close.style, {
@ -141,37 +173,49 @@
opacity: "0.6", opacity: "0.6",
fontSize: "15px", fontSize: "15px",
lineHeight: "1", lineHeight: "1",
padding:"2px 4px" padding: "2px 4px",
color: "#fff"
}); });
close.onmouseenter = () => close.style.opacity = "1"; close.onmouseenter = () => close.style.opacity = "1";
close.onmouseleave = () => close.style.opacity = "0.6"; close.onmouseleave = () => close.style.opacity = "0.6";
close.onclick = () => panel.style.display = "none"; close.onclick = () => panel.style.display = "none";
const textarea=document.createElement("textarea");
Object.assign(textarea.style,{ const editorContainer = document.createElement("div");
flex:"1", editorContainer.style.flex = "1";
border:"none",
outline:"none",
resize:"none",
padding:"16px",
background:"transparent",
color:"inherit",
fontFamily:"monospace",
fontSize:"13px"
});
textarea.value=theme.css;
textarea.addEventListener("input",()=>{
const themes=getThemes();
const t=themes.find(x=>x.id===editingTheme.id);
if(!t) return;
t.css=textarea.value;
setThemes(themes);
applyThemes();
if(window.__avia_refresh_themes_panel){window.__avia_refresh_themes_panel();}
});
panel.appendChild(header); panel.appendChild(header);
panel.appendChild(close); panel.appendChild(close);
panel.appendChild(textarea); panel.appendChild(editorContainer);
document.body.appendChild(panel); document.body.appendChild(panel);
monacoEditorInstance = monaco.editor.create(editorContainer, {
value: theme.css || "",
language: "css",
theme: "vs-dark",
automaticLayout: true,
minimap: { enabled: false },
fontSize: 13,
scrollBeyondLastLine: false,
wordWrap: "on"
});
monacoEditorInstance._aviaThemeId = themeId;
monacoEditorInstance.onDidChangeModelContent(() => {
const id = monacoEditorInstance._aviaThemeId;
if (!id) return;
const value = monacoEditorInstance.getValue();
const all = getThemes();
const target = all.find(t => t.id === id);
if (!target) return;
target.css = value;
setThemes(all);
applyThemes();
header.textContent = "Theme Editor — " + parseMeta(value).name;
if (typeof window.__avia_refresh_themes_panel === "function") {
window.__avia_refresh_themes_panel();
}
});
} }
function toggleThemesPanel() { function toggleThemesPanel() {
@ -180,6 +224,7 @@
panel.style.display = panel.style.display === "none" ? "flex" : "none"; panel.style.display = panel.style.display === "none" ? "flex" : "none";
return; return;
} }
panel = document.createElement("div"); panel = document.createElement("div");
panel.id = "avia-themes-panel"; panel.id = "avia-themes-panel";
Object.assign(panel.style, { Object.assign(panel.style, {
@ -192,7 +237,7 @@
color: "var(--md-sys-color-on-surface, #fff)", color: "var(--md-sys-color-on-surface, #fff)",
borderRadius: "16px", borderRadius: "16px",
boxShadow: "0 8px 28px rgba(0,0,0,0.35)", boxShadow: "0 8px 28px rgba(0,0,0,0.35)",
zIndex:999999, zIndex: "999999",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
overflow: "hidden", overflow: "hidden",
@ -319,10 +364,8 @@
dropOverlay.style.opacity = "0"; dropOverlay.style.opacity = "0";
panel.style.border = "1px solid rgba(255,255,255,0.08)"; panel.style.border = "1px solid rgba(255,255,255,0.08)";
dragDepth = 0; dragDepth = 0;
const files = [...e.dataTransfer.files].filter(f => f.name.endsWith(".css") || f.name.endsWith(".txt")); const files = [...e.dataTransfer.files].filter(f => f.name.endsWith(".css") || f.name.endsWith(".txt"));
if (!files.length) return; if (!files.length) return;
const themes = getThemes(); const themes = getThemes();
for (const file of files) { for (const file of files) {
const css = await file.text(); const css = await file.text();
@ -356,8 +399,7 @@
padding: "10px 12px", padding: "10px 12px",
borderRadius: "10px", borderRadius: "10px",
background: "rgba(255,255,255,0.04)", background: "rgba(255,255,255,0.04)",
border:"1px solid rgba(255,255,255,0.06)", border: "1px solid rgba(255,255,255,0.06)"
marginBottom:"0"
}); });
const left = document.createElement("div"); const left = document.createElement("div");
@ -395,13 +437,13 @@
const edit = document.createElement("button"); const edit = document.createElement("button");
edit.textContent = "Edit"; edit.textContent = "Edit";
styleBtn(edit, "rgba(100,160,255,0.15)"); styleBtn(edit, "rgba(100,160,255,0.15)");
edit.onclick=()=>openThemeEditor(theme); edit.onclick = () => openThemeEditor(theme.id);
const dlBtn = document.createElement("button"); const dlBtn = document.createElement("button");
dlBtn.textContent = "Export"; dlBtn.textContent = "Export";
styleBtn(dlBtn, "rgba(80,200,120,0.15)"); styleBtn(dlBtn, "rgba(80,200,120,0.15)");
dlBtn.title = "Download theme as .css"; dlBtn.title = "Download theme as .css";
dlBtn.onclick=(e)=>{ dlBtn.onclick = e => {
e.stopPropagation(); e.stopPropagation();
downloadTheme(theme); downloadTheme(theme);
}; };
@ -475,5 +517,6 @@
new MutationObserver(injectButton).observe(document.body, { childList: true, subtree: true }); new MutationObserver(injectButton).observe(document.body, { childList: true, subtree: true });
injectButton(); injectButton();
applyThemes(); applyThemes();
preloadMonaco();
})(); })();