diff options
| author | Rahul A Mistry <[email protected]> | 2026-01-21 22:05:15 +0530 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-21 10:35:15 -0600 |
| commit | b8a0e420f8e8c3abb8ceceecb3e511236e2e9735 (patch) | |
| tree | 47e1a374574b326cc959ffb3d75528b5ef21f25f /packages/app/src/components | |
| parent | bfbcbc88632869f1a6b86b05a3fff0c7a46e5863 (diff) | |
| download | opencode-b8a0e420f8e8c3abb8ceceecb3e511236e2e9735.tar.gz opencode-b8a0e420f8e8c3abb8ceceecb3e511236e2e9735.zip | |
feat(app): search on settings shortcuts (#9850)
Diffstat (limited to 'packages/app/src/components')
| -rw-r--r-- | packages/app/src/components/settings-keybinds.tsx | 90 |
1 files changed, 83 insertions, 7 deletions
diff --git a/packages/app/src/components/settings-keybinds.tsx b/packages/app/src/components/settings-keybinds.tsx index 13a0042ff..3f1f34e5f 100644 --- a/packages/app/src/components/settings-keybinds.tsx +++ b/packages/app/src/components/settings-keybinds.tsx @@ -1,6 +1,10 @@ import { Component, For, Show, createMemo, createSignal, onCleanup, onMount } from "solid-js" import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { TextField } from "@opencode-ai/ui/text-field" import { showToast } from "@opencode-ai/ui/toast" +import fuzzysort from "fuzzysort" import { formatKeybind, parseKeybind, useCommand } from "@/context/command" import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" @@ -108,6 +112,7 @@ export const SettingsKeybinds: Component = () => { const settings = useSettings() const [active, setActive] = createSignal<string | null>(null) + const [filter, setFilter] = createSignal("") const stop = () => { if (!active()) return @@ -197,6 +202,45 @@ export const SettingsKeybinds: Component = () => { return out }) + const filtered = createMemo(() => { + const query = filter().toLowerCase().trim() + if (!query) return grouped() + + const map = list() + const out = new Map<KeybindGroup, string[]>() + + for (const group of GROUPS) out.set(group, []) + + const items = Array.from(map.entries()).map(([id, meta]) => ({ + id, + title: meta.title, + group: meta.group, + keybind: command.keybind(id) || "", + })) + + const results = fuzzysort.go(query, items, { + keys: ["title", "keybind"], + threshold: -10000, + }) + + for (const result of results) { + const item = result.obj + const ids = out.get(item.group) + if (!ids) continue + ids.push(item.id) + } + + return out + }) + + const hasResults = createMemo(() => { + for (const group of GROUPS) { + const ids = filtered().get(group) ?? [] + if (ids.length > 0) return true + } + return false + }) + const used = createMemo(() => { const map = new Map<string, { id: string; title: string }[]>() @@ -313,22 +357,43 @@ export const SettingsKeybinds: Component = () => { "linear-gradient(to bottom, var(--surface-raised-stronger-non-alpha) calc(100% - 24px), transparent)", }} > - <div class="flex items-center justify-between gap-4 pt-6 pb-8 max-w-[720px]"> - <h2 class="text-16-medium text-text-strong">{language.t("settings.shortcuts.title")}</h2> - <Button size="small" variant="secondary" onClick={resetAll} disabled={!hasOverrides()}> - {language.t("settings.shortcuts.reset.button")} - </Button> + <div class="flex flex-col gap-4 pt-6 pb-6 max-w-[720px]"> + <div class="flex items-center justify-between gap-4"> + <h2 class="text-16-medium text-text-strong">{language.t("settings.shortcuts.title")}</h2> + <Button size="small" variant="secondary" onClick={resetAll} disabled={!hasOverrides()}> + {language.t("settings.shortcuts.reset.button")} + </Button> + </div> + + <div class="flex items-center gap-2 px-3 py-2 rounded-lg bg-surface-base"> + <Icon name="magnifying-glass" class="text-icon-weak-base flex-shrink-0" /> + <TextField + variant="ghost" + type="text" + value={filter()} + onChange={setFilter} + placeholder={language.t("settings.shortcuts.search.placeholder")} + spellcheck={false} + autocorrect="off" + autocomplete="off" + autocapitalize="off" + class="flex-1" + /> + <Show when={filter()}> + <IconButton icon="circle-x" variant="ghost" onClick={() => setFilter("")} /> + </Show> + </div> </div> </div> <div class="flex flex-col gap-8 max-w-[720px]"> <For each={GROUPS}> {(group) => ( - <Show when={(grouped().get(group) ?? []).length > 0}> + <Show when={(filtered().get(group) ?? []).length > 0}> <div class="flex flex-col gap-1"> <h3 class="text-14-medium text-text-strong pb-2">{language.t(groupKey[group])}</h3> <div class="bg-surface-raised-base px-4 rounded-lg"> - <For each={grouped().get(group) ?? []}> + <For each={filtered().get(group) ?? []}> {(id) => ( <div class="flex items-center justify-between gap-4 py-3 border-b border-border-weak-base last:border-none"> <span class="text-14-regular text-text-strong">{title(id)}</span> @@ -357,6 +422,17 @@ export const SettingsKeybinds: Component = () => { </Show> )} </For> + + <Show when={filter() && !hasResults()}> + <div class="flex flex-col items-center justify-center py-12 text-center"> + <span class="text-14-regular text-text-weak"> + {language.t("settings.shortcuts.search.empty")} + </span> + <Show when={filter()}> + <span class="text-14-regular text-text-strong mt-1">"{filter()}"</span> + </Show> + </div> + </Show> </div> </div> ) |
