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>
This commit is contained in:
parent
8e0d470549
commit
02e4f7d6ab
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user