live: group paging next to play/stop; add grid-split menu before fullscreen
The grid control footer is regrouped: ⏮ play/stop ⏭ now sit together in the centre (left section empty). On the right, before fullscreen, a new ▦ split button opens an upward popup menu with the layouts 4/9/16/25/36/49/64 that calls setDim; the menu respects maxDim (16+ mode), highlights the active layout, and closes on outside click. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+15
-4
@@ -29,14 +29,25 @@
|
|||||||
<main id="live-main">
|
<main id="live-main">
|
||||||
<div class="grid g4" id="grid"></div>
|
<div class="grid g4" id="grid"></div>
|
||||||
<footer class="grid-bar" id="grid-bar">
|
<footer class="grid-bar" id="grid-bar">
|
||||||
<div class="gb-left">
|
<div class="gb-left"></div>
|
||||||
<button class="gb-btn" id="gb-prev" title="Предыдущая страница" aria-label="Предыдущая страница">⏮</button>
|
|
||||||
</div>
|
|
||||||
<div class="gb-center">
|
<div class="gb-center">
|
||||||
|
<button class="gb-btn" id="gb-prev" title="Предыдущая страница" aria-label="Предыдущая страница">⏮</button>
|
||||||
<button class="gb-btn gb-play" id="gb-play" title="Просмотр / стоп" aria-label="Просмотр / стоп">⏸</button>
|
<button class="gb-btn gb-play" id="gb-play" title="Просмотр / стоп" aria-label="Просмотр / стоп">⏸</button>
|
||||||
|
<button class="gb-btn" id="gb-next" title="Следующая страница" aria-label="Следующая страница">⏭</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="gb-right">
|
<div class="gb-right">
|
||||||
<button class="gb-btn" id="gb-next" title="Следующая страница" aria-label="Следующая страница">⏭</button>
|
<div class="gb-split">
|
||||||
|
<button class="gb-btn" id="gb-split" title="Раскладка сетки" aria-label="Раскладка сетки">▦</button>
|
||||||
|
<div class="gb-split-menu" id="gb-split-menu">
|
||||||
|
<button data-grid="2">4</button>
|
||||||
|
<button data-grid="3">9</button>
|
||||||
|
<button data-grid="4">16</button>
|
||||||
|
<button data-grid="5">25</button>
|
||||||
|
<button data-grid="6">36</button>
|
||||||
|
<button data-grid="7">49</button>
|
||||||
|
<button data-grid="8">64</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<button class="gb-btn" id="gb-fs" title="Полный экран" aria-label="Полный экран">⛶</button>
|
<button class="gb-btn" id="gb-fs" title="Полный экран" aria-label="Полный экран">⛶</button>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
+20
-3
@@ -517,8 +517,8 @@ const Live = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
applyMaxDim() {
|
applyMaxDim() {
|
||||||
// скрыть пункты подменю с числом больше лимита (режим 16+)
|
// скрыть пункты с числом больше лимита (режим 16+) — и в сайдбаре, и в меню «Раскладка»
|
||||||
document.querySelectorAll(".subnav .subitem[data-grid]").forEach((a) => {
|
document.querySelectorAll(".subnav .subitem[data-grid], .gb-split-menu button[data-grid]").forEach((a) => {
|
||||||
a.hidden = +a.dataset.grid > this.maxDim;
|
a.hidden = +a.dataset.grid > this.maxDim;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -537,7 +537,7 @@ const Live = {
|
|||||||
localStorage.setItem("corevision.grid", String(this.dim));
|
localStorage.setItem("corevision.grid", String(this.dim));
|
||||||
this.page = 0; // смена размера сетки → первая страница
|
this.page = 0; // смена размера сетки → первая страница
|
||||||
this.fillSelected(); // selected = камеры текущей страницы
|
this.fillSelected(); // selected = камеры текущей страницы
|
||||||
document.querySelectorAll("#live-subnav .subitem, .subnav .subitem").forEach((a) =>
|
document.querySelectorAll("#live-subnav .subitem, .subnav .subitem, .gb-split-menu button").forEach((a) =>
|
||||||
a.classList.toggle("active", +a.dataset.grid === this.dim));
|
a.classList.toggle("active", +a.dataset.grid === this.dim));
|
||||||
if (rerender) this.renderGrid();
|
if (rerender) this.renderGrid();
|
||||||
this.updatePager();
|
this.updatePager();
|
||||||
@@ -605,6 +605,23 @@ const Live = {
|
|||||||
if (gbPlay) gbPlay.onclick = (e) => { e.preventDefault(); this.setPlaying(!this.playing); };
|
if (gbPlay) gbPlay.onclick = (e) => { e.preventDefault(); this.setPlaying(!this.playing); };
|
||||||
const gbFs = document.getElementById("gb-fs");
|
const gbFs = document.getElementById("gb-fs");
|
||||||
if (gbFs) gbFs.onclick = (e) => { e.preventDefault(); fsMain(); };
|
if (gbFs) gbFs.onclick = (e) => { e.preventDefault(); fsMain(); };
|
||||||
|
// меню «Раскладка» (window split): 4/9/16/25/36/49/64 → setDim
|
||||||
|
const gbSplit = document.getElementById("gb-split");
|
||||||
|
const splitMenu = document.getElementById("gb-split-menu");
|
||||||
|
if (gbSplit && splitMenu) {
|
||||||
|
gbSplit.onclick = (e) => { e.preventDefault(); splitMenu.classList.toggle("open"); };
|
||||||
|
splitMenu.onclick = (e) => {
|
||||||
|
const b = e.target.closest("button[data-grid]");
|
||||||
|
if (!b) return;
|
||||||
|
e.preventDefault();
|
||||||
|
history.replaceState(null, "", "/?grid=" + b.dataset.grid);
|
||||||
|
this.setDim(+b.dataset.grid);
|
||||||
|
splitMenu.classList.remove("open");
|
||||||
|
};
|
||||||
|
document.addEventListener("click", (e) => { // клик вне меню — закрыть
|
||||||
|
if (!e.target.closest(".gb-split")) splitMenu.classList.remove("open");
|
||||||
|
});
|
||||||
|
}
|
||||||
this.updatePlayBtn();
|
this.updatePlayBtn();
|
||||||
this.updatePager();
|
this.updatePager();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -190,6 +190,22 @@ footer.grid-bar {
|
|||||||
.grid-bar .gb-btn:hover:not(:disabled) { border-color: #c0392b; color: #fff; }
|
.grid-bar .gb-btn:hover:not(:disabled) { border-color: #c0392b; color: #fff; }
|
||||||
.grid-bar .gb-btn:disabled { opacity: .3; cursor: default; }
|
.grid-bar .gb-btn:disabled { opacity: .3; cursor: default; }
|
||||||
.grid-bar .gb-play { min-width: 42px; font-size: 15px; }
|
.grid-bar .gb-play { min-width: 42px; font-size: 15px; }
|
||||||
|
/* кнопка «Раскладка» (window split) + всплывающее меню (раскрывается вверх) */
|
||||||
|
.grid-bar .gb-split { position: relative; display: inline-flex; }
|
||||||
|
.grid-bar .gb-split-menu {
|
||||||
|
display: none; position: absolute; bottom: calc(100% + 6px); right: 0; z-index: 50;
|
||||||
|
flex-direction: column; gap: 2px; padding: 4px; min-width: 60px;
|
||||||
|
background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
|
||||||
|
box-shadow: 0 6px 20px rgba(0, 0, 0, .5);
|
||||||
|
}
|
||||||
|
.grid-bar .gb-split-menu.open { display: flex; }
|
||||||
|
.grid-bar .gb-split-menu button {
|
||||||
|
height: 24px; padding: 0 10px; border: 1px solid transparent; border-radius: 5px;
|
||||||
|
background: none; color: var(--text); cursor: pointer; font-size: 13px;
|
||||||
|
font-variant-numeric: tabular-nums; text-align: center;
|
||||||
|
}
|
||||||
|
.grid-bar .gb-split-menu button:hover { background: var(--panel-2); }
|
||||||
|
.grid-bar .gb-split-menu button.active { background: var(--accent); border-color: #c0392b; color: #fff; }
|
||||||
.tile {
|
.tile {
|
||||||
position: relative; background: #05070a; border: 1px solid var(--border);
|
position: relative; background: #05070a; border: 1px solid var(--border);
|
||||||
display: flex; align-items: center; justify-content: center; overflow: hidden;
|
display: flex; align-items: center; justify-content: center; overflow: hidden;
|
||||||
|
|||||||
Reference in New Issue
Block a user