feat(settings): group settings into 4 tabs
Long settings panel → 4 tabs (Général / Sécurité / Account / Sync & Backup). Each section (.slideover-field) is keyed by its label text to a tab via SETTINGS_TAB_OF; applySettingsTab toggles .is-tab-hidden on the rest. No HTML restructure (sections were already .slideover-field siblings), no dep. The existing settings search composes: a live query suspends the tab filter so cross-tab matches show, clearing it restores the active tab. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2183,6 +2183,16 @@ body[data-editor-position="center"]:has(#settingsPanel.is-open)::before {
|
||||
.settings-search-clear svg { width: 12px; height: 12px; }
|
||||
.settings-search-clear:hover { color: var(--text); background: var(--bg-elev-2); }
|
||||
.settings-search-wrap.has-query .settings-search-clear { display: inline-flex; }
|
||||
/* Settings tabs — group sections; JS toggles .is-tab-hidden. */
|
||||
.settings-tabs { display: flex; gap: 4px; padding: 0 16px 8px; flex-wrap: wrap; }
|
||||
.settings-tab {
|
||||
flex: 1; min-width: 70px; padding: 6px 10px; font-size: 12px; cursor: pointer;
|
||||
color: var(--text-dim); background: var(--bg-elev-2); border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
}
|
||||
.settings-tab:hover { background: var(--bg-elev-3); }
|
||||
.settings-tab.is-active { color: var(--accent-fg); background: var(--accent); border-color: var(--accent); }
|
||||
.slideover-field.is-tab-hidden { display: none; }
|
||||
/* Hidden section + per-row + no-results banner driven by JS. */
|
||||
.slideover-field.is-search-hidden,
|
||||
.setting-row.is-search-hidden { display: none; }
|
||||
|
||||
@@ -413,6 +413,12 @@
|
||||
<svg><use href="#i-x"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="settings-tabs" id="settingsTabs">
|
||||
<button class="settings-tab is-active" data-tab="general">Général</button>
|
||||
<button class="settings-tab" data-tab="security">Sécurité</button>
|
||||
<button class="settings-tab" data-tab="account">Account</button>
|
||||
<button class="settings-tab" data-tab="sync">Sync & Backup</button>
|
||||
</div>
|
||||
<div class="slideover-body" id="settingsBody">
|
||||
<div class="slideover-field">
|
||||
<div class="slideover-field-label">Appearance</div>
|
||||
|
||||
@@ -7808,6 +7808,31 @@ function closeSettings() {
|
||||
$('#settingsPanel').classList.remove('is-open');
|
||||
}
|
||||
|
||||
// Settings tabs — each section (.slideover-field, keyed by its label text)
|
||||
// belongs to one tab; the active tab shows its sections, hides the rest.
|
||||
const SETTINGS_TAB_OF = {
|
||||
'Appearance': 'general',
|
||||
'Security': 'security', 'Clipboard privacy': 'security',
|
||||
'PIN unlock': 'security', 'Quick unlock': 'security', 'Recovery key': 'security',
|
||||
'Account': 'account',
|
||||
'Export': 'sync', 'Sync (WebDAV)': 'sync', 'Auto-backup': 'sync', 'Import': 'sync',
|
||||
};
|
||||
let settingsActiveTab = 'general';
|
||||
|
||||
function applySettingsTab(tab) {
|
||||
if (tab) settingsActiveTab = tab;
|
||||
$$('#settingsTabs .settings-tab').forEach(b =>
|
||||
b.classList.toggle('is-active', b.dataset.tab === settingsActiveTab));
|
||||
// A live search filters rows across ALL sections — suspend the tab filter
|
||||
// so a match in another tab isn't hidden. Empty search → tab filter on.
|
||||
const searching = !!($('#settingsSearch') && $('#settingsSearch').value.trim());
|
||||
$$('#settingsBody > .slideover-field').forEach(sec => {
|
||||
const lbl = sec.querySelector('.slideover-field-label');
|
||||
const t = lbl ? (SETTINGS_TAB_OF[lbl.textContent.trim()] || 'general') : 'general';
|
||||
sec.classList.toggle('is-tab-hidden', !searching && t !== settingsActiveTab);
|
||||
});
|
||||
}
|
||||
|
||||
// Filter the settings panel by text. Matches against the label + the
|
||||
// section body so e.g. "Ctrl" finds the hotkeys section via its button
|
||||
// labels. Empty query = show everything. Adds a "No matches" hint when
|
||||
@@ -7874,6 +7899,7 @@ function applySettingsSearch(rawQuery) {
|
||||
if (body) body.appendChild(banner);
|
||||
}
|
||||
banner.classList.toggle('is-visible', q.length > 0 && totalShownRows === 0);
|
||||
applySettingsTab(); // re-apply tab filter (off while searching, on when cleared)
|
||||
}
|
||||
|
||||
// ---- Auto-lock with 30s warning countdown -------------------
|
||||
@@ -8759,6 +8785,8 @@ async function init() {
|
||||
// Settings search box: live filter on every input. Escape clears the
|
||||
// query (without closing the panel — the existing Esc handler also
|
||||
// closes settings, but only when focus isn't inside an input).
|
||||
$$('#settingsTabs .settings-tab').forEach(b =>
|
||||
b.addEventListener('click', () => applySettingsTab(b.dataset.tab)));
|
||||
const sInput = $('#settingsSearch');
|
||||
const sClear = $('#settingsSearchClear');
|
||||
if (sInput) {
|
||||
|
||||
Reference in New Issue
Block a user