video Automations page: match the music page's exact layout

Was a bespoke .vauto- header; now mirrors the music automations page structure 1:1 —
.page-shell.automations-container > .dashboard-header (sweep + automation.png icon +
header-title/subtitle) > .automations-stats ('N Active · N System') > .automations-list
holding the protected '.automations-section.section-protected' System group (chevron +
label + count + collapse, persisted) with the same .automation-card rows. Reuses every
music class; driven by video JS via data-vauto-* hooks (no #id clash). Removed the dead
.vauto-* CSS. Balance clean.
This commit is contained in:
BoulderBadgeDad 2026-06-19 18:05:00 -07:00
parent c78b90826a
commit 5d8db8c5a4
3 changed files with 45 additions and 25 deletions

View file

@ -1313,12 +1313,21 @@
(minus Refresh Beatport Cache + user/playlist ones). Reuses the
music .automation-* card look; built by video/video-automations.js. -->
<section class="video-subpage" data-video-subpage="video-automations" hidden>
<div class="vauto-wrap">
<div class="vauto-head">
<h1 class="vauto-title">Automations</h1>
<p class="vauto-sub" data-vauto-sub>System tasks that keep your library fresh — shared with the music side.</p>
<div class="page-shell automations-container">
<div class="dashboard-header"><div class="dashboard-header-sweep" aria-hidden="true"><span></span></div>
<div class="header-text">
<h2 class="header-title"><img src="/static/automation.png" class="page-header-icon" alt=""><span>Automations</span></h2>
<p class="header-subtitle">System tasks that keep your library fresh — shared with the music side</p>
</div>
<div class="header-spacer"></div>
</div>
<div class="automations-stats" data-vauto-stats></div>
<div class="automations-list" data-vauto-list></div>
<div class="automations-empty" data-vauto-empty style="display:none;">
<div class="automations-empty-icon">&#9889;</div>
<div class="automations-empty-title">No system automations yet</div>
<div class="automations-empty-text">They appear here once the automation engine creates them.</div>
</div>
<div class="vauto-list" data-vauto-list></div>
</div>
</section>
<!-- TV-show detail (drill-in from a show card; not a nav page).

View file

@ -83,7 +83,7 @@
if (a.next_run && a.enabled && timers.indexOf(a.trigger_type) > -1) meta.push('Next: ' + esc(timeUntil(a.next_run)));
else if (a.enabled && timers.indexOf(a.trigger_type) === -1) meta.push('Listening');
if (a.run_count) meta.push('Runs: ' + a.run_count);
if (a.last_error) meta.push('<span class="vauto-err">Error: ' + esc(a.last_error) + '</span>');
if (a.last_error) meta.push('Error: ' + esc(a.last_error));
return '<div class="automation-card system' + (a.enabled ? '' : ' disabled') + '" data-auto-id="' + a.id + '">' +
'<div class="automation-status ' + (a.enabled ? 'enabled' : 'disabled') + '"></div>' +
'<div class="automation-info">' +
@ -105,18 +105,30 @@
function render(list) {
var host = document.querySelector('[data-vauto-list]'); if (!host) return;
var statsEl = document.querySelector('[data-vauto-stats]');
var emptyEl = document.querySelector('[data-vauto-empty]');
var sys = (list || []).filter(isVideoSystem);
var sub = document.querySelector('[data-vauto-sub]');
if (sub) {
var on = sys.filter(function (a) { return a.enabled; }).length;
sub.textContent = sys.length ? (on + ' of ' + sys.length + ' enabled · shared with the music side')
: 'System tasks that keep your library fresh — shared with the music side.';
}
if (!sys.length) {
host.innerHTML = '<div class="vauto-empty">No system automations yet.</div>';
return;
}
host.innerHTML = sys.map(cardHTML).join('');
var active = sys.filter(function (a) { return a.enabled; }).length;
if (statsEl) statsEl.innerHTML = sys.length
? '<span class="auto-stat"><strong>' + active + '</strong> Active</span>' +
'<span class="auto-stat"><strong>' + sys.length + '</strong> System</span>'
: '';
if (!sys.length) { host.innerHTML = ''; if (emptyEl) emptyEl.style.display = ''; return; }
if (emptyEl) emptyEl.style.display = 'none';
var collapsed = false;
try { collapsed = localStorage.getItem('vauto_section_system') === '1'; } catch (e) { /* ignore */ }
// same protected-section structure the music page builds for its System group
host.innerHTML =
'<div class="automations-section section-protected' + (collapsed ? ' collapsed' : '') + '" id="vauto-section-system">' +
'<div class="automations-section-header" data-vauto-toggle>' +
'<span class="section-chevron">&#9660;</span>' +
'<span class="section-label">System</span>' +
'<span class="section-count">' + sys.length + '</span>' +
'<span class="section-line"></span>' +
'</div>' +
'<div class="automations-section-body">' + sys.map(cardHTML).join('') + '</div>' +
'</div>';
}
function load() { getJSON(URL_LIST).then(function (d) { render(Array.isArray(d) ? d : (d && d.automations) || []); }); }
@ -136,6 +148,13 @@
if (_wired) return; _wired = true;
var host = document.querySelector('[data-vauto-list]'); if (!host) return;
host.addEventListener('click', function (e) {
var sect = e.target.closest('[data-vauto-toggle]');
if (sect) {
var s = sect.closest('.automations-section');
s.classList.toggle('collapsed');
try { localStorage.setItem('vauto_section_system', s.classList.contains('collapsed') ? '1' : '0'); } catch (x) { /* ignore */ }
return;
}
var run = e.target.closest('[data-auto-run]');
if (run) {
run.disabled = true;

View file

@ -3350,11 +3350,3 @@ body[data-side="video"] #soulsync-toggle { display: none; }
.vdpg-row-retry:disabled { opacity: 0.5 !important; pointer-events: none; }
@media (hover: none) { .vdpg-row-retry { opacity: 1; pointer-events: auto; transform: none; } }
/* ── Automations page (.vauto-*; reuses the music .automation-* card look) ──── */
.vauto-wrap { max-width: 1100px; padding: 8px 4px 40px; }
.vauto-head { margin-bottom: 22px; }
.vauto-title { font-size: 34px; font-weight: 900; letter-spacing: -0.03em; margin: 0; color: #fff; }
.vauto-sub { margin: 6px 0 0; font-size: 13.5px; font-weight: 600; color: rgba(255, 255, 255, 0.5); }
.vauto-list { display: flex; flex-direction: column; gap: 9px; }
.vauto-empty { text-align: center; padding: 60px 20px; font-size: 14px; color: rgba(255, 255, 255, 0.4); }
.vauto-err { color: #fca5a5; }