better editor

This commit is contained in:
2026-04-29 15:03:40 +02:00
parent 3603f52979
commit f054014825
+175 -130
View File
@@ -1,10 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>FSDB Editor</title> <title>FSDB Editor</title>
<style> <style>
body { body {
margin: 0; margin: 0;
font-family: sans-serif; font-family: sans-serif;
@@ -12,126 +11,192 @@
color: #eee; color: #eee;
} }
.container { .controls {
padding: 8px 10px;
border-bottom: 1px solid #333;
background: #161616;
display: flex; display: flex;
height: 100vh; align-items: center;
} gap: 14px;
flex-wrap: wrap;
}
.panel { .picker-group {
display: flex;
align-items: center;
gap: 6px;
}
.picker-label {
font-size: 12px;
color: #888;
white-space: nowrap;
}
.seg-row {
display: flex;
gap: 3px;
}
.seg-btn {
font-size: 12px;
padding: 4px 9px;
border-radius: 5px;
border: 1px solid #444;
background: #1e1e1e;
color: #ccc;
cursor: pointer;
white-space: nowrap;
transition: background 0.1s;
}
.seg-btn:hover { background: #2a2a2a; }
.seg-btn.active {
background: #1a3a5c;
color: #7ab8f5;
border-color: #2a5a8c;
font-weight: 600;
}
.playlist-display {
font-family: monospace;
font-size: 13px;
color: #777;
padding: 4px 8px;
border: 1px solid #333;
border-radius: 5px;
background: #1a1a1a;
}
.playlist-display span {
color: #eee;
font-weight: 600;
}
.refresh-btn {
font-size: 12px;
padding: 4px 10px;
border-radius: 5px;
border: 1px solid #444;
background: #222;
color: #eee;
cursor: pointer;
}
.refresh-btn:hover { background: #333; }
.container {
display: flex;
height: calc(100vh - 52px);
}
.panel {
flex: 1; flex: 1;
padding: 10px; padding: 10px;
box-sizing: border-box; box-sizing: border-box;
overflow-y: auto; overflow-y: auto;
border-right: 1px solid #333; border-right: 1px solid #333;
} }
.panel:last-child { .panel:last-child { border-right: none; }
border-right: none;
}
h2 { h2 {
margin-top: 0; margin-top: 0;
font-size: 16px; font-size: 13px;
color: #aaa; color: #777;
} font-weight: 500;
}
.item { .item {
padding: 6px; padding: 5px 7px;
margin: 2px 0; margin: 2px 0;
cursor: pointer; cursor: pointer;
border-radius: 4px; border-radius: 4px;
} font-size: 13px;
}
.item:hover { .item:hover { background: #1e1e1e; }
background: #222; .dir { color: #6cf; }
} .file { color: #ccc; }
</style>
</head>
<body>
<div class="controls">
<div class="picker-group">
<span class="picker-label">Day</span>
<div class="seg-row" id="dayPicker"></div>
</div>
<div class="picker-group">
<span class="picker-label">Part</span>
<div class="seg-row" id="partPicker"></div>
</div>
<div class="playlist-display">playlist: <span id="playlistVal">friday/day</span></div>
<button class="refresh-btn" onclick="refreshPlaylist()">Refresh</button>
</div>
.dir { <div class="container">
color: #6cf;
}
.file {
color: #ccc;
}
.controls {
padding: 5px;
border-bottom: 1px solid #333;
}
button {
margin-right: 5px;
background: #222;
color: #eee;
border: 1px solid #444;
padding: 5px 8px;
cursor: pointer;
}
button:hover {
background: #333;
}
input {
background: #222;
color: #eee;
border: 1px solid #444;
padding: 4px;
}
</style>
</head>
<body>
<div class="controls">
Playlist:
<input id="playlist" value="default">
<button onclick="refreshPlaylist()">Refresh</button>
</div>
<div class="container">
<div class="panel"> <div class="panel">
<h2>Ref Dir</h2> <h2>Ref Dir</h2>
<div id="ref"></div> <div id="ref"></div>
</div> </div>
<div class="panel">
<div class="panel">
<h2>Playlist</h2> <h2>Playlist</h2>
<div id="playlistView"></div> <div id="playlistView"></div>
</div> </div>
</div>
</div> <script>
const DAYS = ["monday","tuesday","wednesday","thursday","friday","saturday","sunday"];
const PARTS = ["day","morning","night","late_night"];
<script> let selectedDay = "friday";
const ws = new WebSocket("/ws"); let selectedPart = "day";
let currentPlaylist = "default"; function buildPicker(containerId, items, getCurrent, setCurrent) {
const el = document.getElementById(containerId);
el.innerHTML = "";
items.forEach(val => {
const btn = document.createElement("button");
btn.className = "seg-btn" + (getCurrent() === val ? " active" : "");
btn.textContent = val.replace("_", " ");
btn.onclick = () => {
setCurrent(val);
buildPicker(containerId, items, getCurrent, setCurrent);
updateDisplay();
refreshPlaylist();
};
el.appendChild(btn);
});
}
ws.onopen = () => { function updateDisplay() {
document.getElementById("playlistVal").textContent = selectedDay + "/" + selectedPart;
}
function getPlaylistName() {
return selectedDay + "/" + selectedPart;
}
buildPicker("dayPicker", DAYS, () => selectedDay, v => { selectedDay = v; });
buildPicker("partPicker", PARTS, () => selectedPart, v => { selectedPart = v; });
const ws = new WebSocket("/ws");
ws.onopen = () => {
console.log("WS connected"); console.log("WS connected");
}; refreshPlaylist();
};
ws.onmessage = (ev) => { ws.onmessage = (ev) => {
const msg = JSON.parse(ev.data); const msg = JSON.parse(ev.data);
if (msg.event === "state") renderRef(msg.data.dirs);
if (msg.event === "fsdb_list") renderPlaylist(msg.data);
};
if (msg.event === "state") { function renderRef(data) {
renderRef(msg.data.dirs);
}
if (msg.event === "fsdb_list") {
renderPlaylist(msg.data);
}
};
function getPlaylistName() {
currentPlaylist = document.getElementById("playlist").value || "";
return currentPlaylist;
}
function renderRef(data) {
const el = document.getElementById("ref"); const el = document.getElementById("ref");
el.innerHTML = ""; el.innerHTML = "";
data.dirs.forEach(d => { data.dirs.forEach(d => {
const div = document.createElement("div"); const div = document.createElement("div");
div.className = "item dir"; div.className = "item dir";
@@ -139,7 +204,6 @@ function renderRef(data) {
div.onclick = () => addDir(d); div.onclick = () => addDir(d);
el.appendChild(div); el.appendChild(div);
}); });
data.files.forEach(f => { data.files.forEach(f => {
const div = document.createElement("div"); const div = document.createElement("div");
div.className = "item file"; div.className = "item file";
@@ -147,12 +211,11 @@ function renderRef(data) {
div.onclick = () => addFile(f); div.onclick = () => addFile(f);
el.appendChild(div); el.appendChild(div);
}); });
} }
function renderPlaylist(data) { function renderPlaylist(data) {
const el = document.getElementById("playlistView"); const el = document.getElementById("playlistView");
el.innerHTML = ""; el.innerHTML = "";
data.dirs.forEach(d => { data.dirs.forEach(d => {
const div = document.createElement("div"); const div = document.createElement("div");
div.className = "item dir"; div.className = "item dir";
@@ -160,7 +223,6 @@ function renderPlaylist(data) {
div.onclick = () => removeEntry(d); div.onclick = () => removeEntry(d);
el.appendChild(div); el.appendChild(div);
}); });
data.files.forEach(f => { data.files.forEach(f => {
const div = document.createElement("div"); const div = document.createElement("div");
div.className = "item file"; div.className = "item file";
@@ -168,44 +230,27 @@ function renderPlaylist(data) {
div.onclick = () => removeEntry(f); div.onclick = () => removeEntry(f);
el.appendChild(div); el.appendChild(div);
}); });
} }
function addFile(name) { function addFile(name) {
ws.send(JSON.stringify({ ws.send(JSON.stringify({ action: "fsdb_add", name, playlist: getPlaylistName() }));
action: "fsdb_add",
name: name,
playlist: getPlaylistName()
}));
setTimeout(refreshPlaylist, 100); setTimeout(refreshPlaylist, 100);
} }
function addDir(name) { function addDir(name) {
ws.send(JSON.stringify({ ws.send(JSON.stringify({ action: "fsdb_add_dir", name, playlist: getPlaylistName() }));
action: "fsdb_add_dir",
name: name,
playlist: getPlaylistName()
}));
setTimeout(refreshPlaylist, 100); setTimeout(refreshPlaylist, 100);
} }
function removeEntry(name) { function removeEntry(name) {
if (!confirm("Remove " + name + "?")) return; if (!confirm("Remove " + name + "?")) return;
ws.send(JSON.stringify({ action: "fsdb_remove", name, playlist: getPlaylistName() }));
ws.send(JSON.stringify({
action: "fsdb_remove",
name: name,
playlist: getPlaylistName()
}));
setTimeout(refreshPlaylist, 100); setTimeout(refreshPlaylist, 100);
} }
function refreshPlaylist() { function refreshPlaylist() {
ws.send(JSON.stringify({ ws.send(JSON.stringify({ action: "fsdb_list", playlist: getPlaylistName() }));
action: "fsdb_list", }
playlist: getPlaylistName() </script>
})); </body>
}
</script>
</body>
</html> </html>