feat: clean settings cards — name + desc, advanced collapsed, add/remove

This commit is contained in:
Claus Lohmar 2026-08-06 17:50:16 +01:00
parent ebc05762b0
commit 1942c2bb35
2 changed files with 24 additions and 17 deletions

View file

@ -280,39 +280,41 @@ async function renderCameraCards() {
<label>Require login on port 8080 <input type="checkbox" ${config?.auth?.enabled ? 'checked' : ''} data-auth="auth-enabled" style="width:auto"></label> <label>Require login on port 8080 <input type="checkbox" ${config?.auth?.enabled ? 'checked' : ''} data-auth="auth-enabled" style="width:auto"></label>
</div> </div>
</div> </div>
<div style="grid-column:1/-1;display:flex;gap:8px;margin-bottom:4px"> <div style="grid-column:1/-1;display:flex;gap:8px;margin-bottom:4px">
<button class="btn-primary" onclick="addCamera()">+ Add Camera</button> <button class="btn-primary" onclick="addCamera()">+ Add Camera</button>
<span style="color:var(--text-muted);font-size:13px;align-self:center">${cameras.length} camera(s)</span> <span style="color:var(--text-muted);font-size:13px;align-self:center">${cameras.length} camera(s)</span>
</div> </div>
` + cameras.map((c, i) => ` ` + cameras.map((c, i) => `
<div class="camera-card" data-id="${c.id}"> <div class="camera-card" data-id="${c.id}">
<h3>📷 ${c.name || 'Unnamed'} <span style="font-size:11px;color:var(--text-muted)">${c.ip}</span> <h3>📷 ${c.name || 'Camera_' + c.ip.split('.').pop()}
<a href="http://${c.ip}" target="_blank" style="font-size:11px;color:var(--accent);margin-left:8px;text-decoration:none" title="Open camera web interface"> Config</a> <span style="font-size:11px;color:var(--text-muted)">${c.ip}</span>
<button onclick="removeCamera(${i})" style="float:right;background:var(--red);color:#fff;border:none;padding:2px 8px;border-radius:4px;cursor:pointer;font-size:11px"> Remove</button>
</h3>
<div class="camera-card" data-id="${c.id}">
<h3>📷 ${c.name || 'Unnamed'} <span style="font-size:11px;color:var(--text-muted)">${c.ip}</span>
<a href="http://${c.ip}" target="_blank" style="font-size:11px;color:var(--accent);margin-left:8px;text-decoration:none" title="Open camera web interface"> Config</a>
</h3> </h3>
<input type="hidden" value="${escAttr(c.id)}" data-field="id"> <input type="hidden" value="${escAttr(c.id)}" data-field="id">
<input type="hidden" value="${escAttr(c.ip)}" data-field="ip"> <input type="hidden" value="${escAttr(c.ip)}" data-field="ip">
<input type="hidden" value="${c.onvif_port || 80}" data-field="onvif_port"> <input type="hidden" value="${c.onvif_port || 80}" data-field="onvif_port">
<label>Name <input type="text" value="${escAttr(c.name)}" data-field="name"></label> <label>Name <input type="text" value="${escAttr(c.name)}" data-field="name"></label>
<label>Description <textarea data-field="description">${escHtml(c.description)}</textarea></label> <label>Description <textarea data-field="description" rows="2">${escHtml(c.description)}</textarea></label>
<label>RTSP Main <input type="text" value="${escAttr(c.rtsp_main)}" data-field="rtsp_main"></label> <div class="camera-row">
<label>RTSP Sub <input type="text" value="${escAttr(c.rtsp_sub)}" data-field="rtsp_sub"></label> <label>Recording <input type="checkbox" ${c.record ? 'checked' : ''} data-field="record" style="width:auto"></label>
<label>Username <input type="text" value="${escAttr(c.username)}" data-field="username"></label> <button class="adv-toggle" onclick="toggleAdv(this)" style="background:none;border:none;color:var(--accent);cursor:pointer;font-size:12px;margin-left:auto;margin-right:8px"> Advanced</button>
<label>Password <input type="password" value="${escAttr(c.password)}" data-field="password"></label> <button onclick="removeCamera(${i})" class="btn-remove"></button>
<div class="row"> </div>
<label>Enabled <input type="checkbox" ${c.enabled ? 'checked' : ''} data-field="enabled" style="width:auto"></label> <div class="advanced hidden">
<label>Record <input type="checkbox" ${c.record ? 'checked' : ''} data-field="record" style="width:auto"></label> <label>RTSP Main <input type="text" value="${escAttr(c.rtsp_main)}" data-field="rtsp_main"></label>
<label>RTSP Sub <input type="text" value="${escAttr(c.rtsp_sub)}" data-field="rtsp_sub"></label>
<label>Username <input type="text" value="${escAttr(c.username)}" data-field="username"></label>
<label>Password <input type="password" value="${escAttr(c.password)}" data-field="password"></label>
</div> </div>
</div> </div>
`).join(''); `).join('');
} }
// ── Settings: Add / Remove cameras ── // ── Settings: Add / Remove cameras ──
function addCamera() { function toggleAdv(btn) {
const adv = btn.parentElement.parentElement.querySelector('.advanced');
adv.classList.toggle('hidden');
btn.textContent = adv.classList.contains('hidden') ? '▸ Advanced' : '▾ Advanced';
}
const ip = prompt('Camera IP address:', '192.168.1.'); const ip = prompt('Camera IP address:', '192.168.1.');
if (!ip) return; if (!ip) return;
const id = 'cam_' + ip.split('.').pop(); const id = 'cam_' + ip.split('.').pop();

View file

@ -164,6 +164,11 @@ body {
.camera-card textarea { resize: vertical; min-height: 50px; } .camera-card textarea { resize: vertical; min-height: 50px; }
.camera-card .row { display: flex; gap: 8px; align-items: center; margin-top: 8px; } .camera-card .row { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
.camera-card .row label { margin-top: 0; } .camera-card .row label { margin-top: 0; }
.camera-row { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
.advanced { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.advanced.hidden { display: none; }
.btn-remove { background: none; border: none; color: var(--red); cursor: pointer; font-size: 16px; padding: 2px 6px; }
.btn-remove:hover { background: rgba(248,81,73,.15); border-radius: 4px; }
.btn-primary { background: var(--accent); color: #fff; border: none; padding: 8px 20px; border-radius: var(--radius); cursor: pointer; font-size: 14px; } .btn-primary { background: var(--accent); color: #fff; border: none; padding: 8px 20px; border-radius: var(--radius); cursor: pointer; font-size: 14px; }
.btn-success { background: var(--green); color: #fff; border: none; padding: 8px 20px; border-radius: var(--radius); cursor: pointer; font-size: 14px; } .btn-success { background: var(--green); color: #fff; border: none; padding: 8px 20px; border-radius: var(--radius); cursor: pointer; font-size: 14px; }
.btn-primary:hover, .btn-success:hover { opacity: .9; } .btn-primary:hover, .btn-success:hover { opacity: .9; }