diff --git a/cmd/server/web/css/style.css b/cmd/server/web/css/style.css
index 961b1d4..bcbc77c 100644
--- a/cmd/server/web/css/style.css
+++ b/cmd/server/web/css/style.css
@@ -196,3 +196,78 @@ h1 {
font-size: 15px;
}
}
+
+.accordion-header {
+ cursor: pointer;
+ user-select: none;
+}
+
+.accordion-header:hover {
+ opacity: 0.7;
+}
+
+.accordion-body {
+ max-height: 520px;
+ overflow: hidden;
+ transition: max-height 0.3s ease;
+}
+
+.accordion-body.collapsed {
+ max-height: 0;
+}
+
+.progress-with-signal {
+ display: flex;
+ align-items: center;
+ gap: 0;
+}
+
+.progress-90 {
+ flex: 0 0 86%;
+ margin-right: 10px;
+}
+
+/* ===== SIGNAL ICON ===== */
+.signal-icon {
+ display: flex;
+ align-items: flex-end;
+ gap: 4px;
+ width: 34px;
+ height: 34px;
+ flex-shrink: 0;
+}
+
+.sig-bar {
+ flex: 1;
+ border-radius: 2px;
+ min-width: 5px;
+ border: 1.5px solid #00ff88;
+ background-color: transparent;
+ transition: background-color 0.3s, border-color 0.3s;
+}
+
+.sig-bar-1 { height: 25%; }
+.sig-bar-2 { height: 50%; }
+.sig-bar-3 { height: 75%; }
+.sig-bar-4 { height: 100%; }
+
+/* Активные — зелёная заливка */
+.sig-bar.active-1,
+.sig-bar.active-2,
+.sig-bar.active-3,
+.sig-bar.active-4 {
+ background-color: #00ff88;
+ border-color: #00ff88;
+}
+
+/* Неактивные — прозрачные, только контур */
+.sig-bar.dim {
+ background-color: transparent;
+ border-color: #1a3a1a;
+}
+
+#last-byte {
+ font-size: 18px;
+ font-weight: bold;
+ color: #00ff88;
+}
\ No newline at end of file
diff --git a/cmd/server/web/dashboard.html b/cmd/server/web/dashboard.html
index 7c361f7..e1affb7 100644
--- a/cmd/server/web/dashboard.html
+++ b/cmd/server/web/dashboard.html
@@ -21,19 +21,21 @@
-
-
ПОСЛЕДНИЙ СИГНАЛ
-
--
-
-
-
УРОВНИ КАНАЛОВ
-
Канал 1
-
@@ -53,8 +55,10 @@
-
ПОТОК ДАННЫХ (последние 32)
-
+
+
diff --git a/cmd/server/web/js/app.js b/cmd/server/web/js/app.js
index c82f79c..41fa28b 100644
--- a/cmd/server/web/js/app.js
+++ b/cmd/server/web/js/app.js
@@ -1,19 +1,14 @@
-// ===== BIT RENDER =====
-function renderBits(byte) {
- const bits = document.getElementById("bits");
- bits.innerHTML = "";
+// ===== ACCORDION =====
+const historyHeader = document.getElementById("history-header");
+const historyBody = document.getElementById("history-body");
+let accordionOpen = false;
+historyBody.classList.add("collapsed"); // изначально свёрнут
- byte = Number(byte || 0);
-
- for (let i = 7; i >= 0; i--) {
- const v = (byte >> i) & 1;
-
- const d = document.createElement("div");
- d.className = "bit" + (v ? " on" : "");
- d.textContent = v;
- bits.appendChild(d);
- }
-}
+historyHeader.addEventListener("click", () => {
+ accordionOpen = !accordionOpen;
+ historyHeader.textContent = (accordionOpen ? "▼" : "▶") + " ПРИНЯТЫЕ ДАННЫЕ";
+ historyBody.classList.toggle("collapsed", !accordionOpen);
+});
// ===== PROGRESS BAR =====
function setBar(id, value) {
@@ -21,6 +16,31 @@ function setBar(id, value) {
document.getElementById(id).style.width = value + "%";
}
+// ===== SIGNAL ICON =====
+function setSignal(percent) {
+ const bars = document.querySelectorAll(".sig-bar");
+ bars.forEach(b => {
+ b.classList.remove("active-1", "active-2", "active-3", "active-4");
+ b.classList.add("dim");
+ });
+
+ if (percent > 75) {
+ bars[0].classList.add("active-1"); bars[0].classList.remove("dim");
+ bars[1].classList.add("active-2"); bars[1].classList.remove("dim");
+ bars[2].classList.add("active-3"); bars[2].classList.remove("dim");
+ bars[3].classList.add("active-4"); bars[3].classList.remove("dim");
+ } else if (percent > 50) {
+ bars[0].classList.add("active-1"); bars[0].classList.remove("dim");
+ bars[1].classList.add("active-2"); bars[1].classList.remove("dim");
+ bars[2].classList.add("active-3"); bars[2].classList.remove("dim");
+ } else if (percent > 25) {
+ bars[0].classList.add("active-1"); bars[0].classList.remove("dim");
+ bars[1].classList.add("active-2"); bars[1].classList.remove("dim");
+ } else if (percent > 0) {
+ bars[0].classList.add("active-1"); bars[0].classList.remove("dim");
+ }
+}
+
// ===== SMOOTHING =====
let lastValue = 0;
@@ -60,12 +80,6 @@ async function update() {
document.getElementById("meta").textContent =
"аптайм: " + uptime + "s | буфер: " + filled;
- // ===== LATEST =====
- const latest = Number(h.latest || 0);
- document.getElementById("latest").textContent = latest;
-
- renderBits(latest);
-
// ===== HISTORY =====
const arr = Array.isArray(hist.bytes) ? hist.bytes : [];
@@ -89,6 +103,8 @@ async function update() {
// ===== ONLY CHANNEL 1 =====
setBar("bar1", smooth);
+ document.getElementById("last-byte").textContent = filtered;
+ setSignal(smooth);
} catch (e) {
console.error("UPDATE ERROR:", e);
@@ -96,6 +112,5 @@ async function update() {
}
}
-// быстрее и плавнее
setInterval(update, 500);
-update();
+update();
\ No newline at end of file