Give the pages one switch and one prefix each

Three pages had reimplemented the same sliding toggle, and two both claimed
vv-set-* with disjoint class names, which reads as shared and is not.
This commit is contained in:
Gmer4Lfe
2026-08-11 21:59:27 -04:00
parent 67510b8fad
commit 999dbcfdf3
4 changed files with 46 additions and 64 deletions
+37 -37
View File
@@ -72,26 +72,26 @@
}
/* ── Settings panel ─────────────────────────────────────────── */
.vv-set-file { border:1px solid #222; border-radius:5px; margin-bottom:8px; overflow:hidden; }
.vv-set-file-hdr { display:flex; justify-content:space-between; align-items:center; padding:8px 12px;
.vv-pt-set-file { border:1px solid #222; border-radius:5px; margin-bottom:8px; overflow:hidden; }
.vv-pt-set-file-hdr { display:flex; justify-content:space-between; align-items:center; padding:8px 12px;
background:#161616; cursor:pointer; font-size:12px; font-weight:bold; color:#bbb; font-family:monospace; }
.vv-set-file-hdr:hover { background:#1a1a1a; }
.vv-set-file-body { padding:6px 10px 10px; }
.vv-set-sec { border-top:1px solid #1c1c1c; }
.vv-set-sec:first-child { border-top:none; }
.vv-set-sec-hdr { display:flex; justify-content:space-between; align-items:center; padding:6px 4px;
.vv-pt-set-file-hdr:hover { background:#1a1a1a; }
.vv-pt-set-file-body { padding:6px 10px 10px; }
.vv-pt-set-sec { border-top:1px solid #1c1c1c; }
.vv-pt-set-sec:first-child { border-top:none; }
.vv-pt-set-sec-hdr { display:flex; justify-content:space-between; align-items:center; padding:6px 4px;
cursor:pointer; font-size:11px; color:#888; text-transform:uppercase; letter-spacing:.04em; }
.vv-set-sec-hdr:hover { color:#ccc; }
.vv-set-sec-body { padding:4px 0 8px 8px; }
.vv-set-chev { color:#444; font-size:10px; }
.vv-set-field { margin-bottom:10px; }
.vv-set-key { font-size:11px; color:#7ab; font-family:monospace; margin-bottom:2px; }
.vv-set-desc { font-size:10px; color:#555; margin-bottom:3px; line-height:1.4; }
.vv-set-input { width:100%; box-sizing:border-box; background:#0d0d0d; border:1px solid #2a2a2a;
.vv-pt-set-sec-hdr:hover { color:#ccc; }
.vv-pt-set-sec-body { padding:4px 0 8px 8px; }
.vv-pt-set-chev { color:#444; font-size:10px; }
.vv-pt-set-field { margin-bottom:10px; }
.vv-pt-set-key { font-size:11px; color:#7ab; font-family:monospace; margin-bottom:2px; }
.vv-pt-set-desc { font-size:10px; color:#555; margin-bottom:3px; line-height:1.4; }
.vv-pt-set-input { width:100%; box-sizing:border-box; background:#0d0d0d; border:1px solid #2a2a2a;
color:#ddd; padding:5px 8px; border-radius:3px; font-family:monospace; font-size:11px; }
.vv-set-input:focus { outline:none; border-color:#4a8; }
.vv-set-input.changed { border-color:#ff9800; }
textarea.vv-set-input { resize:vertical; white-space:pre; }
.vv-pt-set-input:focus { outline:none; border-color:#4a8; }
.vv-pt-set-input.changed { border-color:#ff9800; }
textarea.vv-pt-set-input { resize:vertical; white-space:pre; }
</style>
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;padding:0 2px;">
@@ -361,9 +361,9 @@ function _renderHostSettings(nodes, isOwner) {
for (const n of nodes) {
const rdonly = isOwner ? '' : 'readonly style="opacity:.5;cursor:default;"';
html += `<div>
<div class="vv-set-key" style="margin-bottom:4px;">${_vvSetEsc(n.id)}</div>
<div class="vv-pt-set-key" style="margin-bottom:4px;">${_vvSetEsc(n.id)}</div>
<input type="text" ${rdonly}
class="vv-set-input vv-pt-host-inp"
class="vv-pt-set-input vv-pt-host-inp"
data-key="${_vvSetEsc(n.id)}" data-file="master.conf" data-type="scalar"
data-orig="${_vvSetEsc(n.hostname)}"
value="${_vvSetEsc(n.hostname)}"
@@ -441,18 +441,18 @@ function _vvRenderArrayCards() {
if (fld.type === 'scalar') continue;
hasArrays = true;
const rows = Math.min(16, (fld.value.match(/\n/g) || []).length + 2);
const attrs = `class="vv-set-input" data-key="${_vvSetEsc(fld.key)}" `
const attrs = `class="vv-pt-set-input" data-key="${_vvSetEsc(fld.key)}" `
+ `data-file="${_vvSetEsc(fld.file)}" data-type="${_vvSetEsc(fld.type)}" `
+ `data-orig="${_vvSetEsc(fld.value)}" oninput="vvPtArrChanged(this)"`;
html += `<div class="vv-set-file">
<div class="vv-set-file-hdr" onclick="vvPtToggleNode(this)">
html += `<div class="vv-pt-set-file">
<div class="vv-pt-set-file-hdr" onclick="vvPtToggleNode(this)">
<span>${_vvSetEsc(fld.key)}</span>
<div style="display:flex;align-items:center;gap:6px;">
${fld.desc ? `<span style="font-size:9px;color:#444;font-weight:normal;font-family:inherit;">${_vvSetEsc(fld.desc)}</span>` : ''}
<span class="vv-set-chev">▸</span>
<span class="vv-pt-set-chev">▸</span>
</div>
</div>
<div class="vv-set-file-body" style="display:none;">
<div class="vv-pt-set-file-body" style="display:none;">
<textarea ${attrs} rows="${rows}">${_vvSetEsc(fld.value)}</textarea>
</div>
</div>`;
@@ -476,13 +476,13 @@ function _vvRenderArrayCards() {
function vvPtArrChanged(el) {
el.classList.toggle('changed', el.value !== el.dataset.orig);
const any = document.querySelector('#vv-pt-arrays-wrap .vv-set-input.changed');
const any = document.querySelector('#vv-pt-arrays-wrap .vv-pt-set-input.changed');
const saveBtn = document.getElementById('vv-pt-arrays-save');
if (saveBtn) saveBtn.style.display = any ? '' : 'none';
}
async function vvPtSaveArrays(btn) {
const changedEls = document.querySelectorAll('#vv-pt-arrays-wrap .vv-set-input.changed');
const changedEls = document.querySelectorAll('#vv-pt-arrays-wrap .vv-pt-set-input.changed');
if (!changedEls.length) return;
const changes = [];
changedEls.forEach(el => changes.push({key: el.dataset.key, file: el.dataset.file, type: el.dataset.type, value: el.value}));
@@ -556,18 +556,18 @@ function vvPtRenderSettings(files) {
const label = f.file === 'master.conf' ? 'master.conf — shared' : f.file + ' — this host';
const scalarFields = f.groups.flatMap(g => g.fields.filter(fld => fld.type === 'scalar'));
if (!scalarFields.length) continue;
html += `<div class="vv-set-file">
<div class="vv-set-file-hdr" onclick="vvPtToggleNode(this)">
<span>${_vvSetEsc(label)}</span><span class="vv-set-chev">▾</span>
html += `<div class="vv-pt-set-file">
<div class="vv-pt-set-file-hdr" onclick="vvPtToggleNode(this)">
<span>${_vvSetEsc(label)}</span><span class="vv-pt-set-chev">▾</span>
</div>
<div class="vv-set-file-body">`;
<div class="vv-pt-set-file-body">`;
for (const fld of scalarFields) {
const attrs = `class="vv-set-input" data-key="${_vvSetEsc(fld.key)}" `
const attrs = `class="vv-pt-set-input" data-key="${_vvSetEsc(fld.key)}" `
+ `data-file="${_vvSetEsc(fld.file)}" data-type="${_vvSetEsc(fld.type)}" `
+ `data-orig="${_vvSetEsc(fld.value)}" oninput="vvPtSetChanged(this)"`;
html += `<div class="vv-set-field">
<div class="vv-set-key">${_vvSetEsc(fld.key)}</div>`;
if (fld.desc) html += `<div class="vv-set-desc">${_vvSetEsc(fld.desc)}</div>`;
html += `<div class="vv-pt-set-field">
<div class="vv-pt-set-key">${_vvSetEsc(fld.key)}</div>`;
if (fld.desc) html += `<div class="vv-pt-set-desc">${_vvSetEsc(fld.desc)}</div>`;
html += `<input type="text" ${attrs} value="${_vvSetEsc(fld.value)}"></div>`;
}
html += `</div></div>`;
@@ -577,7 +577,7 @@ function vvPtRenderSettings(files) {
function vvPtToggleNode(hdr) {
const body = hdr.nextElementSibling;
const chev = hdr.querySelector('.vv-set-chev');
const chev = hdr.querySelector('.vv-pt-set-chev');
const open = body.style.display !== 'none';
body.style.display = open ? 'none' : '';
if (chev) chev.textContent = open ? '▸' : '▾';
@@ -587,12 +587,12 @@ function vvPtSetChanged(el) {
const changed = el.value !== el.dataset.orig;
el.classList.toggle('changed', changed);
// Show Save button if any field is changed
const any = document.querySelector('#vv-pt-settings-body .vv-set-input.changed');
const any = document.querySelector('#vv-pt-settings-body .vv-pt-set-input.changed');
document.getElementById('vv-pt-settings-save').style.display = any ? '' : 'none';
}
async function vvPtSaveSettings(btn) {
const changedEls = document.querySelectorAll('#vv-pt-settings-body .vv-set-input.changed');
const changedEls = document.querySelectorAll('#vv-pt-settings-body .vv-pt-set-input.changed');
if (!changedEls.length) return;
const changes = [];
changedEls.forEach(el => changes.push({