Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 83 additions & 7 deletions packages/app/src/components/settings-keybinds.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 }[]>()

Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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>
)
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/da.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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": "セッション",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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": "세션",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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": "会话",
Expand Down