diff --git a/src/web/public/index.html b/src/web/public/index.html index b48e4c08..f8ad5c46 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -1679,6 +1679,9 @@ diff --git a/src/web/public/settings-ui.js b/src/web/public/settings-ui.js index 3e8fd626..366e89ad 100644 --- a/src/web/public/settings-ui.js +++ b/src/web/public/settings-ui.js @@ -1458,6 +1458,9 @@ Object.assign(CodemanApp.prototype, { // with no UI left to turn it back off. Preserve the prior stored preference. if (_prev.showTokenCount !== undefined) settings.showTokenCount = _prev.showTokenCount; if (_prev.showCost !== undefined) settings.showCost = _prev.showCost; + // Shortcut overrides are edited from the Shortcuts tab (not rebuilt from the + // general-settings DOM), so the fresh rebuild would drop them on every save. + if (_prev.shortcutOverrides !== undefined) settings.shortcutOverrides = _prev.shortcutOverrides; // Save to localStorage this.saveAppSettingsToStorage(settings); diff --git a/src/web/public/styles.css b/src/web/public/styles.css index ea5dbc07..68dd0731 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -5812,6 +5812,13 @@ kbd { color: var(--text-dim); } +.shortcut-overlay-footer { + margin-top: 0.75rem; + padding-top: 0.75rem; + border-top: 1px solid var(--border); + text-align: right; +} + .away-digest-ranges { display: flex; flex-wrap: wrap; diff --git a/test/shortcut-registry-overlay.test.ts b/test/shortcut-registry-overlay.test.ts index 014c9468..24b63301 100644 --- a/test/shortcut-registry-overlay.test.ts +++ b/test/shortcut-registry-overlay.test.ts @@ -59,6 +59,22 @@ describe('shortcut registry and overlay', () => { expect(css).toContain('.shortcut-capture-btn,'); expect(css).toContain('.shortcut-overlay-row {'); }); + + it('saveAppSettings preserves shortcutOverrides (rebuilt-from-DOM saves must not wipe them)', () => { + // Same trap as showTokenCount/showCost: saveAppSettings() rebuilds the settings + // object fresh from the DOM, so keys edited elsewhere (the Shortcuts tab) must be + // explicitly carried over from the previously stored blob. + expect(settingsSource).toContain( + 'if (_prev.shortcutOverrides !== undefined) settings.shortcutOverrides = _prev.shortcutOverrides;' + ); + }); + + it('keeps the full help modal reachable now that Ctrl+? opens the registry overlay', () => { + // The legacy #helpModal (full shortcut reference) lost its only opener when + // Ctrl+? was rerouted to the overlay; the overlay footer must link to it. + expect(htmlSource).toContain('shortcut-overlay-footer'); + expect(htmlSource).toContain('app.closeShortcutOverlay(); app.showHelp()'); + }); }); // ─── Functional coverage (vm-sandbox harness, mirrors run-mode-ui.test.ts) ────