From c408fcbe92867a0d1e3a516fc44d467444531319 Mon Sep 17 00:00:00 2001 From: core Date: Mon, 1 Jun 2026 23:55:20 +0500 Subject: [PATCH] mobile: hamburger drawer for mode select; live=pause/play, archive=seek MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move mode selection (Live / Архив) into a top hamburger side-drawer instead of the bottom bar. Header now shows the ☰ button + current mode title. Live view has a single pause/play button (no seek bar); Archive keeps native controls for seeking (перемотка). VERSION 0.0.151 -> 0.0.152 Co-Authored-By: Claude Opus 4.8 (1M context) --- VERSION | 2 +- frontend/mobile.html | 22 ++++++++++---- frontend/static/mobile.css | 59 ++++++++++++++++++++++++++++---------- frontend/static/mobile.js | 21 +++++++++++--- 4 files changed, 78 insertions(+), 26 deletions(-) diff --git a/VERSION b/VERSION index be8c9e1..7117656 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.151 +0.0.152 diff --git a/frontend/mobile.html b/frontend/mobile.html index bc41f6d..6638260 100644 --- a/frontend/mobile.html +++ b/frontend/mobile.html @@ -9,9 +9,20 @@
-
CoRE.Vizion+
+
+ + Live +
- + + + + +
@@ -20,6 +31,9 @@
Нет камер
+
+ +
@@ -35,10 +49,6 @@
-
diff --git a/frontend/static/mobile.css b/frontend/static/mobile.css index c771f0f..03357ef 100644 --- a/frontend/static/mobile.css +++ b/frontend/static/mobile.css @@ -8,12 +8,42 @@ html, body { .m-app { display: flex; flex-direction: column; height: 100%; } .m-head { - height: 44px; flex: none; display: flex; align-items: center; justify-content: center; - background: #161a22; border-bottom: 1px solid #272d3a; + height: 48px; flex: none; display: flex; align-items: center; gap: 10px; + padding: 0 8px; background: #161a22; border-bottom: 1px solid #272d3a; + position: relative; z-index: 30; } -.m-brand { font-weight: 700; font-size: 16px; letter-spacing: .3px; } +.m-burger { + background: none; border: 0; color: #e6e9ef; font-size: 22px; line-height: 1; + padding: 6px 10px; border-radius: 8px; cursor: pointer; +} +.m-burger:active { background: #1d2230; } +.m-title { font-weight: 600; font-size: 16px; letter-spacing: .3px; } +.m-brand { font-weight: 700; font-size: 17px; letter-spacing: .3px; } .m-brand span { color: #c0392b; } +/* бутерброд-меню: боковая шторка + затемнение */ +.m-scrim { position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 40; } +.m-scrim[hidden] { display: none; } +.m-drawer { + position: fixed; top: 0; left: 0; bottom: 0; width: 240px; max-width: 80vw; z-index: 50; + background: #161a22; border-right: 1px solid #272d3a; + display: flex; flex-direction: column; + transform: translateX(-100%); transition: transform .22s ease; +} +.m-drawer.open { transform: translateX(0); } +.m-drawer-head { + height: 56px; flex: none; display: flex; align-items: center; padding: 0 18px; + border-bottom: 1px solid #272d3a; +} +.m-nav { + display: flex; align-items: center; gap: 14px; width: 100%; text-align: left; + background: none; border: 0; border-left: 3px solid transparent; color: #cdd3e0; + padding: 16px 18px; font: 600 16px/1 inherit; cursor: pointer; +} +.m-nav .i { font-size: 20px; width: 24px; text-align: center; } +.m-nav:active { background: #1d2230; } +.m-nav.active { color: #fff; background: #1d2230; border-left-color: #c0392b; } + .m-view { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; } .m-bar { @@ -45,17 +75,16 @@ html, body { .m-seg.active .m-dur { color: #fff; } .m-empty { color: #8b93a7; text-align: center; padding: 28px 16px; font-size: 14px; } -.m-tabs { - flex: none; display: flex; justify-content: center; background: #161a22; - border-top: 1px solid #272d3a; padding: 8px 12px; - padding-bottom: calc(8px + env(safe-area-inset-bottom, 0)); +/* live: видео по центру + панель только с пауза/воспроизведение */ +#view-live .m-player { flex: 1; display: flex; align-items: center; justify-content: center; } +.m-ctrl { + flex: none; display: flex; align-items: center; justify-content: center; + background: #161a22; border-top: 1px solid #272d3a; + padding: 12px; padding-bottom: calc(12px + env(safe-area-inset-bottom, 0)); } -/* одна кнопка-переключатель режима (или/или): показывает текущий режим, тап — меняет */ -.m-mode { - display: inline-flex; align-items: center; justify-content: center; gap: 10px; - min-width: 190px; background: #1d2230; color: #e6e9ef; border: 1px solid #272d3a; - border-radius: 10px; padding: 12px 28px; cursor: pointer; - font: 600 15px/1 inherit; letter-spacing: .3px; +.m-cbtn { + width: 58px; height: 58px; border-radius: 50%; background: #c0392b; color: #fff; + border: 0; font-size: 22px; line-height: 1; cursor: pointer; + display: flex; align-items: center; justify-content: center; } -.m-mode:active { background: #232a3a; } -.m-mode .i { font-size: 18px; color: #c0392b; } +.m-cbtn:active { background: #a93226; } diff --git a/frontend/static/mobile.js b/frontend/static/mobile.js index 6ed149b..3282438 100644 --- a/frontend/static/mobile.js +++ b/frontend/static/mobile.js @@ -44,16 +44,29 @@ const M = { else if (lv.webkitEnterFullscreen) lv.webkitEnterFullscreen(); // iOS }); - // одна кнопка снизу — переключатель режима (или/или): Live ⇄ Архив - document.getElementById("m-mode").onclick = () => - this.showView(this.view === "live" ? "arch" : "live"); + // бутерброд-меню сверху: выбор режима (Live / Архив) + const drawer = document.getElementById("m-drawer"); + const scrim = document.getElementById("m-scrim"); + const setMenu = (open) => { drawer.classList.toggle("open", open); scrim.hidden = !open; }; + document.getElementById("m-burger").onclick = () => setMenu(!drawer.classList.contains("open")); + scrim.onclick = () => setMenu(false); + document.querySelectorAll(".m-nav").forEach((b) => { + b.onclick = () => { this.showView(b.dataset.view); setMenu(false); }; + }); + + // live: только пауза / воспроизведение + const lt = document.getElementById("m-live-toggle"); + lt.onclick = () => { if (lv.paused) lv.play().catch(() => {}); else lv.pause(); }; + lv.addEventListener("play", () => { lt.textContent = "⏸"; }); + lv.addEventListener("pause", () => { lt.textContent = "▶"; }); this.showView("live"); }, showView(v) { this.view = v; - document.getElementById("m-mode-name").textContent = v === "live" ? "Live" : "Архив"; + document.getElementById("m-title").textContent = v === "live" ? "Live" : "Архив"; + document.querySelectorAll(".m-nav").forEach((b) => b.classList.toggle("active", b.dataset.view === v)); document.getElementById("view-live").hidden = v !== "live"; document.getElementById("view-arch").hidden = v !== "arch"; if (v === "live") { this.stopArch(); this.startLive(); }