From bec94930b41bd72567f8f6632f320c7d77f63475 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:42:22 +0100 Subject: [PATCH] feat(settings): group settings into 4 tabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- css/style.css | 10 ++++++++++ index.html | 6 ++++++ js/app.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/css/style.css b/css/style.css index 3c290e4..b690a6f 100644 --- a/css/style.css +++ b/css/style.css @@ -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; } diff --git a/index.html b/index.html index 3b54da4..014011f 100644 --- a/index.html +++ b/index.html @@ -413,6 +413,12 @@ +
+ + + + +
Appearance
diff --git a/js/app.js b/js/app.js index 5c3447e..8710b65 100644 --- a/js/app.js +++ b/js/app.js @@ -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) {