Files
VFXdemo/admin.js
2026-04-02 10:00:57 +08:00

99 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const API_BASE = "/api/shaders";
const nameInput = document.getElementById("name-input");
const authorInput = document.getElementById("author-input");
const codeInput = document.getElementById("code-input");
const saveBtn = document.getElementById("save-btn");
const exampleBtn = document.getElementById("example-btn");
const listEl = document.getElementById("list");
const EXAMPLE = `void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
float t = iTime;
float v = sin(uv.x * 9.0 + t * 2.0) + cos(uv.y * 8.0 - t * 1.4);
vec3 col = 0.5 + 0.5 * cos(vec3(0.2, 1.2, 2.2) + v + t);
fragColor = vec4(col, 1.0);
}`;
function validateClientCode(code) {
const hasMainImage = code.includes("mainImage");
const hasAngleMain = code.includes("_umainImage");
if (!hasMainImage && !hasAngleMain) return "代码需包含 mainImage 或 _umainImage。";
return "";
}
async function fetchList() {
const res = await fetch(API_BASE);
if (!res.ok) throw new Error("加载失败");
return res.json();
}
function renderList(items) {
listEl.innerHTML = "";
if (!items.length) {
listEl.innerHTML = "<div>暂无数据</div>";
return;
}
items.forEach((item) => {
const row = document.createElement("div");
row.className = "item";
row.innerHTML = `
<div>
<strong>${item.name}</strong>
<div style="font-size:12px;color:#9fb2df;">${item.author || "unknown"} · ${item.id}</div>
</div>
<button>删除</button>
`;
row.querySelector("button").addEventListener("click", async () => {
await fetch(`${API_BASE}/${encodeURIComponent(item.id)}`, { method: "DELETE" });
await reload();
});
listEl.appendChild(row);
});
}
async function reload() {
const items = await fetchList();
renderList(items);
}
saveBtn.addEventListener("click", async () => {
const name = nameInput.value.trim();
const author = authorInput.value.trim();
const code = codeInput.value.trim();
if (!name) {
alert("名称必填");
return;
}
const err = validateClientCode(code);
if (err) {
alert(err);
return;
}
const res = await fetch(API_BASE, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, author, code }),
});
if (!res.ok) {
const payload = await res.json().catch(() => ({}));
alert(payload.error || "保存失败");
return;
}
const payload = await res.json().catch(() => ({}));
if (payload.sourceFormat === "angle-metal-auto-converted") {
alert("已自动解构并转换为 GLSL展示页可直接渲染。");
}
nameInput.value = "";
authorInput.value = "";
codeInput.value = "";
await reload();
});
exampleBtn.addEventListener("click", () => {
nameInput.value = "New Shader";
authorInput.value = "you";
codeInput.value = EXAMPLE;
});
reload();