feat(app): search on settings shortcuts (#9850)

This commit is contained in:
Rahul A Mistry
2026-01-21 22:05:15 +05:30
committed by GitHub
parent bfbcbc8863
commit b8a0e420f8
9 changed files with 99 additions and 7 deletions

View File

@@ -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>
)

View File

@@ -466,6 +466,8 @@ export const dict = {
"settings.shortcuts.conflict.description": "{{keybind}} er allerede tildelt til {{titles}}.",
"settings.shortcuts.unassigned": "Ikke tildelt",
"settings.shortcuts.pressKeys": "Tryk på taster",
"settings.shortcuts.search.placeholder": "Søg genveje",
"settings.shortcuts.search.empty": "Ingen genveje fundet",
"settings.shortcuts.group.general": "Generelt",
"settings.shortcuts.group.session": "Session",

View File

@@ -475,6 +475,8 @@ export const dict = {
"settings.shortcuts.conflict.description": "{{keybind}} ist bereits {{titles}} zugewiesen.",
"settings.shortcuts.unassigned": "Nicht zugewiesen",
"settings.shortcuts.pressKeys": "Tasten drücken",
"settings.shortcuts.search.placeholder": "Tastenkürzel suchen",
"settings.shortcuts.search.empty": "Keine Tastenkürzel gefunden",
"settings.shortcuts.group.general": "Allgemein",
"settings.shortcuts.group.session": "Sitzung",

View File

@@ -465,6 +465,8 @@ export const dict = {
"settings.shortcuts.conflict.description": "{{keybind}} is already assigned to {{titles}}.",
"settings.shortcuts.unassigned": "Unassigned",
"settings.shortcuts.pressKeys": "Press keys",
"settings.shortcuts.search.placeholder": "Search shortcuts",
"settings.shortcuts.search.empty": "No shortcuts found",
"settings.shortcuts.group.general": "General",
"settings.shortcuts.group.session": "Session",

View File

@@ -469,6 +469,8 @@ export const dict = {
"settings.shortcuts.conflict.description": "{{keybind}} ya está asignado a {{titles}}.",
"settings.shortcuts.unassigned": "Sin asignar",
"settings.shortcuts.pressKeys": "Presiona teclas",
"settings.shortcuts.search.placeholder": "Buscar atajos",
"settings.shortcuts.search.empty": "No se encontraron atajos",
"settings.shortcuts.group.general": "General",
"settings.shortcuts.group.session": "Sesión",

View File

@@ -475,6 +475,8 @@ export const dict = {
"settings.shortcuts.conflict.description": "{{keybind}} est déjà assigné à {{titles}}.",
"settings.shortcuts.unassigned": "Non assigné",
"settings.shortcuts.pressKeys": "Appuyez sur les touches",
"settings.shortcuts.search.placeholder": "Rechercher des raccourcis",
"settings.shortcuts.search.empty": "Aucun raccourci trouvé",
"settings.shortcuts.group.general": "Général",
"settings.shortcuts.group.session": "Session",

View File

@@ -464,6 +464,8 @@ export const dict = {
"settings.shortcuts.conflict.description": "{{keybind}} は既に {{titles}} に割り当てられています。",
"settings.shortcuts.unassigned": "未割り当て",
"settings.shortcuts.pressKeys": "キーを押してください",
"settings.shortcuts.search.placeholder": "ショートカットを検索",
"settings.shortcuts.search.empty": "ショートカットが見つかりません",
"settings.shortcuts.group.general": "一般",
"settings.shortcuts.group.session": "セッション",

View File

@@ -465,6 +465,8 @@ export const dict = {
"settings.shortcuts.conflict.description": "{{keybind}}은(는) 이미 {{titles}}에 할당되어 있습니다.",
"settings.shortcuts.unassigned": "할당되지 않음",
"settings.shortcuts.pressKeys": "키 누르기",
"settings.shortcuts.search.placeholder": "단축키 검색",
"settings.shortcuts.search.empty": "단축키를 찾을 수 없습니다",
"settings.shortcuts.group.general": "일반",
"settings.shortcuts.group.session": "세션",

View File

@@ -459,6 +459,8 @@ export const dict = {
"settings.shortcuts.conflict.description": "{{keybind}} 已分配给 {{titles}}。",
"settings.shortcuts.unassigned": "未设置",
"settings.shortcuts.pressKeys": "按下按键",
"settings.shortcuts.search.placeholder": "搜索快捷键",
"settings.shortcuts.search.empty": "未找到快捷键",
"settings.shortcuts.group.general": "通用",
"settings.shortcuts.group.session": "会话",