From 4efca226f67891861008e15d29c2f81120e31c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Tue, 25 Aug 2026 16:53:29 +0000 Subject: [PATCH] spotlight on ctrl+space, theme browser on ctrl+shift+up/down, no backdrop behind the theme list --- .../Dashboard/Layout/Header/ThemeSwitcher.tsx | 12 +++++------ .../Dashboard/Layout/Spotlight/Spotlight.tsx | 13 ++++++++---- src/apps/officer-web/locales/en-GB.json | 4 ++-- src/apps/officer-web/locales/es-ES.json | 4 ++-- src/apps/officer-web/locales/fr-FR.json | 4 ++-- src/apps/officer-web/locales/pt-PT.json | 4 ++-- src/apps/officer-web/locales/sv-SE.json | 4 ++-- src/apps/officer-web/state/shortcuts.ts | 4 ++-- src/workspaces/theme/src/useThemeKeys.ts | 20 +++++++++++-------- 9 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/apps/officer-web/Screens/Dashboard/Layout/Header/ThemeSwitcher.tsx b/src/apps/officer-web/Screens/Dashboard/Layout/Header/ThemeSwitcher.tsx index 48a60707..442cf60e 100644 --- a/src/apps/officer-web/Screens/Dashboard/Layout/Header/ThemeSwitcher.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Layout/Header/ThemeSwitcher.tsx @@ -24,10 +24,10 @@ const { * * ── The overlay ── * - * `ctrl+shift+space` opens a list in the middle of the screen; `j`/`k` move through it and `l` applies the - * focused theme to the app BEHIND it. That is the whole idea, and it is why this is a portal over a - * translucent backdrop rather than a modal dialog: you are meant to watch the application change while - * you browse, so as little of it as possible should be covered. + * `ctrl+shift+↑/↓` opens a list in the middle of the screen; `j`/`k` move through it and `l` applies the + * focused theme to the app BEHIND it. That is the whole idea, and it is why this is a portal with no + * backdrop rather than a modal dialog: you are meant to watch the application change while you browse, + * so nothing of it should be covered. * * Ported from the owner's `vimazing`, keys and all. */ @@ -156,9 +156,9 @@ export const ThemeSwitcher = () => { {open && createPortal(
setOpen(false)} >
{ // anywhere — including inside a panel that has its own key handling. useEffect(() => { const onKey = (ev: KeyboardEvent) => { - // `code`, not `key`: shift+space reports `key: ' '` on most layouts and something else on a few, while + // `code`, not `key`: ctrl+space reports `key: ' '` on most layouts and something else on a few, while // the physical key is `Space` everywhere. // - // Every other modifier must be ABSENT. `ctrl+shift+space` is the theme browser, and one chord opening - // both is the bug that took a capture-phase listener to fix on the theme side. + // Every other modifier must be ABSENT. `ctrl+shift+space` and `ctrl+alt+space` are the theme + // browser, and one chord opening both is the bug that took a capture-phase listener to fix on the + // theme side. + // + // Was shift+space until 2026-08-25: typing fires shift+space constantly (any capitalized word + // followed by a space), so the launcher kept popping open mid-sentence. Ctrl+space doesn't happen in + // normal typing. // // No focus check. There was one, inherited from shift-space where it was mandatory, and keeping it // "as belt-and-braces" was wrong in the plainest way: focus is usually IN the chat composer, so the // guard meant the launcher did not open from the place it is most often wanted. `preventDefault` // below covers the only thing the guard was protecting against — a layout that would otherwise type // a character. - if (ev.shiftKey && !ev.ctrlKey && !ev.altKey && !ev.metaKey && ev.code === 'Space') { + if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && ev.code === 'Space') { ev.preventDefault(); // Take focus off whatever had it, explicitly, before the overlay mounts. The effect below focuses // this panel's own input, and on paper that is enough — but "on paper" is what produced arrow keys diff --git a/src/apps/officer-web/locales/en-GB.json b/src/apps/officer-web/locales/en-GB.json index 54a6e18b..f07249f9 100644 --- a/src/apps/officer-web/locales/en-GB.json +++ b/src/apps/officer-web/locales/en-GB.json @@ -478,11 +478,11 @@ "codeEditor": "Code Editor" }, "theme": { - "pillTitle": "Theme: {{name}} · ctrl+shift+←/→ cycle · ctrl+shift+space browse · ctrl+shift+f {{starAction}}", + "pillTitle": "Theme: {{name}} · ctrl+shift+←/→ cycle · ctrl+shift+↑/↓ browse · ctrl+shift+f {{starAction}}", "pillLabel": "Theme: {{name}}", "star": "star", "unstar": "unstar", - "cycleHint": "ctrl+shift+←/→ cycle · ctrl+shift+space browse", + "cycleHint": "ctrl+shift+←/→ cycle · ctrl+shift+↑/↓ browse", "everyShortcutHint": "ctrl+? for every shortcut", "favouritesOnly": "Favourites only ({{count}})", "favourites": "Favourites ({{count}})", diff --git a/src/apps/officer-web/locales/es-ES.json b/src/apps/officer-web/locales/es-ES.json index e4e923a2..dd416d51 100644 --- a/src/apps/officer-web/locales/es-ES.json +++ b/src/apps/officer-web/locales/es-ES.json @@ -478,11 +478,11 @@ "codeEditor": "Editor de código" }, "theme": { - "pillTitle": "Tema: {{name}} · ctrl+shift+←/→ recorrer · ctrl+shift+space explorar · ctrl+shift+f {{starAction}}", + "pillTitle": "Tema: {{name}} · ctrl+shift+←/→ recorrer · ctrl+shift+↑/↓ explorar · ctrl+shift+f {{starAction}}", "pillLabel": "Tema: {{name}}", "star": "marcar", "unstar": "desmarcar", - "cycleHint": "ctrl+shift+←/→ recorrer · ctrl+shift+space explorar", + "cycleHint": "ctrl+shift+←/→ recorrer · ctrl+shift+↑/↓ explorar", "everyShortcutHint": "ctrl+? para todos los atajos", "favouritesOnly": "Solo favoritos ({{count}})", "favourites": "Favoritos ({{count}})", diff --git a/src/apps/officer-web/locales/fr-FR.json b/src/apps/officer-web/locales/fr-FR.json index 72449952..8f091e17 100644 --- a/src/apps/officer-web/locales/fr-FR.json +++ b/src/apps/officer-web/locales/fr-FR.json @@ -478,11 +478,11 @@ "codeEditor": "Éditeur de code" }, "theme": { - "pillTitle": "Thème : {{name}} · ctrl+shift+←/→ parcourir · ctrl+shift+space explorer · ctrl+shift+f {{starAction}}", + "pillTitle": "Thème : {{name}} · ctrl+shift+←/→ parcourir · ctrl+shift+↑/↓ explorer · ctrl+shift+f {{starAction}}", "pillLabel": "Thème : {{name}}", "star": "marquer", "unstar": "démarquer", - "cycleHint": "ctrl+shift+←/→ parcourir · ctrl+shift+space explorer", + "cycleHint": "ctrl+shift+←/→ parcourir · ctrl+shift+↑/↓ explorer", "everyShortcutHint": "ctrl+? pour tous les raccourcis", "favouritesOnly": "Favoris uniquement ({{count}})", "favourites": "Favoris ({{count}})", diff --git a/src/apps/officer-web/locales/pt-PT.json b/src/apps/officer-web/locales/pt-PT.json index 87790a03..da7535fb 100644 --- a/src/apps/officer-web/locales/pt-PT.json +++ b/src/apps/officer-web/locales/pt-PT.json @@ -478,11 +478,11 @@ "codeEditor": "Editor de código" }, "theme": { - "pillTitle": "Tema: {{name}} · ctrl+shift+←/→ percorrer · ctrl+shift+space explorar · ctrl+shift+f {{starAction}}", + "pillTitle": "Tema: {{name}} · ctrl+shift+←/→ percorrer · ctrl+shift+↑/↓ explorar · ctrl+shift+f {{starAction}}", "pillLabel": "Tema: {{name}}", "star": "marcar", "unstar": "desmarcar", - "cycleHint": "ctrl+shift+←/→ percorrer · ctrl+shift+space explorar", + "cycleHint": "ctrl+shift+←/→ percorrer · ctrl+shift+↑/↓ explorar", "everyShortcutHint": "ctrl+? para todos os atalhos", "favouritesOnly": "Apenas favoritos ({{count}})", "favourites": "Favoritos ({{count}})", diff --git a/src/apps/officer-web/locales/sv-SE.json b/src/apps/officer-web/locales/sv-SE.json index a0920077..0bc4748b 100644 --- a/src/apps/officer-web/locales/sv-SE.json +++ b/src/apps/officer-web/locales/sv-SE.json @@ -478,11 +478,11 @@ "codeEditor": "Kod-editor" }, "theme": { - "pillTitle": "Tema: {{name}} · ctrl+shift+←/→ bläddra · ctrl+shift+space bläddra i galleri · ctrl+shift+f {{starAction}}", + "pillTitle": "Tema: {{name}} · ctrl+shift+←/→ bläddra · ctrl+shift+↑/↓ bläddra i galleri · ctrl+shift+f {{starAction}}", "pillLabel": "Tema: {{name}}", "star": "stjärnmärk", "unstar": "avmarkera stjärna", - "cycleHint": "ctrl+shift+←/→ bläddra · ctrl+shift+space galleri", + "cycleHint": "ctrl+shift+←/→ bläddra · ctrl+shift+↑/↓ galleri", "everyShortcutHint": "ctrl+? för alla kortkommandon", "favouritesOnly": "Endast favoriter ({{count}})", "favourites": "Favoriter ({{count}})", diff --git a/src/apps/officer-web/state/shortcuts.ts b/src/apps/officer-web/state/shortcuts.ts index e4ea9b1f..0bbf6968 100644 --- a/src/apps/officer-web/state/shortcuts.ts +++ b/src/apps/officer-web/state/shortcuts.ts @@ -42,7 +42,7 @@ export const SHORTCUT_SECTIONS: ShortcutSection[] = [ titleKey: 'shortcuts.navigation', shortcuts: [ { - keys: 'Shift+Space', + keys: 'Ctrl+Space', descriptionKey: 'shortcuts.spotlight', implementedIn: 'Layout/Spotlight/Spotlight.tsx', }, @@ -54,7 +54,7 @@ export const SHORTCUT_SECTIONS: ShortcutSection[] = [ noteKey: 'shortcuts.themesNote', shortcuts: [ { - keys: 'Ctrl+Shift+Space', + keys: 'Ctrl+Shift+↑ / ↓', descriptionKey: 'shortcuts.openBrowser', implementedIn: 'theme/useThemeKeys.ts', }, diff --git a/src/workspaces/theme/src/useThemeKeys.ts b/src/workspaces/theme/src/useThemeKeys.ts index eab58346..f1aa0b3d 100644 --- a/src/workspaces/theme/src/useThemeKeys.ts +++ b/src/workspaces/theme/src/useThemeKeys.ts @@ -9,7 +9,7 @@ import type { ThemeId } from './themes'; * * ctrl+shift+→ next theme, from anywhere, no UI * ctrl+shift+← previous theme - * ctrl+shift+space open the list, then browse it + * ctrl+shift+↑/↓ open the list, then browse it * ctrl+shift+f star or unstar the current theme, from anywhere * * One modifier for all three, which took some choosing. `ctrl+alt+arrows` switches WORKSPACE on GNOME and @@ -78,18 +78,22 @@ export function useThemeKeys(options: ThemeKeysOptions = {}) { const onKeyDown = (event: KeyboardEvent) => { const { themeId: current, focused: focus, open: isOpen } = state.current; - // Toggle the list. `ctrl+alt+space` is still accepted alongside `ctrl+shift+space` — it is what this - // shipped with first, and fingers are quicker to learn than to unlearn. - if (event.ctrlKey && (event.shiftKey || event.altKey) && event.code === 'Space') { + // Toggle the list. Vertical arrows on the SAME modifier as the horizontal cycle — one family: + // `ctrl+shift+←/→` steps the theme, `ctrl+shift+↑/↓` opens the browse. Was `ctrl+shift+space` + // (with a `ctrl+alt+space` legacy) until 2026-08-25; both space chords are gone, not kept as + // aliases, because `ctrl+space` became Spotlight the same day and space chords near it invite + // the wrong reflex. + if (event.ctrlKey && event.shiftKey && !event.altKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) { event.preventDefault(); /* Two problems solved by two lines, and both were reported from the same keystroke. `stopPropagation` stops the header's dropdown ALSO opening. The theme pill is a Radix - DropdownMenuTrigger, and a focused trigger opens on Space — so if the pill happened to have focus, - the chord opened the overlay and the menu behind it. React attaches its handlers at the root, which - bubbles before window, so the trigger saw the key first no matter what this listener did with it. - This listener now runs in the CAPTURE phase and stops the event dead. + DropdownMenuTrigger, and a focused trigger opens on ArrowDown (it did on Space too, when Space + was the chord) — so if the pill happened to have focus, the chord opened the overlay and the + menu behind it. React attaches its handlers at the root, which bubbles before window, so the + trigger saw the key first no matter what this listener did with it. This listener now runs in + the CAPTURE phase and stops the event dead. The blur stops the overlay opening with focus still in a text field, which made j/k/l do nothing: the guard below correctly refuses to steal keys from an input, and the input never lost focus.