Compare commits

...

2 Commits

Author SHA1 Message Date
librelad
3aad78a6d8 Merge claude/1 2026-05-23 14:46:03 +01:00
librelad
02e4f7d6ab style(backup): match location editor tabs to the app-detail tab design
Reuse the shared .tabs-wrapper/.tab-button/.tab-panel components (same as an
app's Config/Tasks tabs) for the location editor instead of bespoke tab CSS:
emoji + label buttons, equal-width strip, accent active state. Panels toggle
via the .active class like the rest of the UI; only the panel padding is
trimmed so it nests inside the backup row.

Also drop the now-dead 'No advanced options' empty state — every type has at
least Engine + append-only in the Advanced tab.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-23 14:46:03 +01:00
2 changed files with 39 additions and 65 deletions

View File

@ -723,44 +723,14 @@
border-top: 1px dashed rgba(var(--text-rgb), 0.08); border-top: 1px dashed rgba(var(--text-rgb), 0.08);
} }
/* Tabbed location editor (Connection | Retention | Advanced). Splits the /* The location editor reuses the app-detail tab design (.tabs-wrapper /
formerly long single form into one panel per concern. */ .tab-button / .tab-panel from style.css). Only trim the panel padding so it
.backup-loc-tabs { sits inside the backup row's own padding instead of doubling it. */
display: flex; .backup-location-details .tab-panel {
gap: 4px; padding: 16px 2px 2px;
border-bottom: 1px solid rgba(var(--text-rgb), 0.10);
margin-bottom: 16px;
} }
.backup-loc-tab { .backup-location-details .tab-panel > .category-description {
appearance: none;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
padding: 8px 14px;
color: rgba(var(--text-rgb), 0.6);
font: inherit;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: color 0.15s ease, border-color 0.15s ease;
}
.backup-loc-tab:hover {
color: var(--text-primary);
}
.backup-loc-tab.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
.backup-loc-tab-panel[hidden] {
display: none;
}
.backup-loc-tab-panel > .category-description {
margin-top: 0; margin-top: 0;
margin-bottom: 12px; margin-bottom: 12px;
} }

View File

@ -215,7 +215,7 @@ class BackupPage {
b.setAttribute('aria-selected', on ? 'true' : 'false'); b.setAttribute('aria-selected', on ? 'true' : 'false');
}); });
root.querySelectorAll(`[data-tab-panel][data-loc="${tabIdx}"]`).forEach(p => { root.querySelectorAll(`[data-tab-panel][data-loc="${tabIdx}"]`).forEach(p => {
p.toggleAttribute('hidden', p.dataset.tabPanel !== tabName); p.classList.toggle('active', p.dataset.tabPanel === tabName);
}); });
return; return;
} }
@ -678,35 +678,41 @@ class BackupPage {
yearly: l.custom_retention ? (l.keep_yearly || '') : '' yearly: l.custom_retention ? (l.keep_yearly || '') : ''
}; };
const tab = (id, label) => ` // Reuse the app-detail tab design (.tabs-wrapper/.tab-button/.tab-panel
<button type="button" class="backup-loc-tab${id === 'connection' ? ' active' : ''}" data-action="loc-tab" data-loc="${idx}" data-tab="${id}" role="tab" aria-selected="${id === 'connection'}">${label}</button>`; // from style.css) so the Locations editor matches the rest of the UI.
const advancedBody = groups.advanced.length const tab = (id, emoji, label) => `
? this.renderLocFields(idx, groups.advanced, l) <button type="button" class="tab-button${id === 'connection' ? ' active' : ''}" data-action="loc-tab" data-loc="${idx}" data-tab="${id}" role="tab" aria-selected="${id === 'connection'}">
: `<div class="backup-empty-state">No advanced options for this location type.</div>`; <span class="tab-emoji">${emoji}</span>
<span class="tab-name">${label}</span>
</button>`;
return ` return `
<div class="config-category backup-location-config" data-section="location-${idx}"> <div class="config-category backup-location-config" data-section="location-${idx}">
<div class="backup-loc-tabs" role="tablist"> <div class="tabs-wrapper">
${tab('connection', 'Connection')} <div class="tabs-list" role="tablist">
${tab('retention', 'Retention')} ${tab('connection', '🔗', 'Connection')}
${tab('advanced', 'Advanced')} ${tab('retention', '♻️', 'Retention')}
</div> ${tab('advanced', '⚙️', 'Advanced')}
<div class="backup-loc-tab-panel" data-tab-panel="connection" data-loc="${idx}">
<p class="category-description">How LibrePortal connects to this storage location.</p>
<div class="backup-location-connection-fields" id="backup-location-${idx}-connection">
${this.renderLocFields(idx, groups.connection, l)}
</div> </div>
</div> <div class="tabs-content">
<div class="backup-loc-tab-panel" data-tab-panel="retention" data-loc="${idx}" hidden> <div class="tab-panel active" data-tab-panel="connection" data-loc="${idx}">
<p class="category-description">When to delete old backups from this location.</p> <p class="category-description">How LibrePortal connects to this storage location.</p>
<div id="backup-location-${idx}-retention"> <div class="backup-location-connection-fields" id="backup-location-${idx}-connection">
${this.formRetention(`CFG_BACKUP_LOC_${idx}_`, retentionValues, true)} ${this.renderLocFields(idx, groups.connection, l)}
</div> </div>
</div> </div>
<div class="backup-loc-tab-panel" data-tab-panel="advanced" data-loc="${idx}" hidden> <div class="tab-panel" data-tab-panel="retention" data-loc="${idx}">
<p class="category-description">Overrides most locations don't need.</p> <p class="category-description">When to delete old backups from this location.</p>
<div id="backup-location-${idx}-advanced"> <div id="backup-location-${idx}-retention">
${advancedBody} ${this.formRetention(`CFG_BACKUP_LOC_${idx}_`, retentionValues, true)}
</div>
</div>
<div class="tab-panel" data-tab-panel="advanced" data-loc="${idx}">
<p class="category-description">Overrides most locations don't need.</p>
<div id="backup-location-${idx}-advanced">
${this.renderLocFields(idx, groups.advanced, l)}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -776,9 +782,7 @@ class BackupPage {
// applies to some types), so rebuild it alongside the Connection tab. // applies to some types), so rebuild it alongside the Connection tab.
const adv = document.getElementById(`backup-location-${idx}-advanced`); const adv = document.getElementById(`backup-location-${idx}-advanced`);
if (adv) { if (adv) {
adv.innerHTML = groups.advanced.length adv.innerHTML = this.renderLocFields(idx, groups.advanced, { ...loc, type });
? this.renderLocFields(idx, groups.advanced, { ...loc, type })
: `<div class="backup-empty-state">No advanced options for this location type.</div>`;
this.tagFieldsForSave(adv); this.tagFieldsForSave(adv);
} }