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:
parent
8b0e6588fd
commit
dec110d795
1 changed files with 298 additions and 255 deletions
|
|
@ -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();
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue