Skip to content

Commit be2b30f

Browse files
feat(settings): focus search on Cmd/Ctrl+F and fix empty section headers (#1485)
Co-authored-by: Orca <help@stably.ai>
1 parent 2f99f93 commit be2b30f

5 files changed

Lines changed: 62 additions & 6 deletions

File tree

src/renderer/src/components/settings/AccountsPane.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,16 @@ export function AccountsPane({ settings, updateSettings }: AccountsPaneProps): R
428428
<SearchableSetting
429429
title="Codex Accounts"
430430
description="Manage which Codex account Orca uses for live rate limit fetching."
431-
keywords={['codex', 'account', 'rate limit', 'status bar', 'quota']}
431+
// Why: this single SearchableSetting backs the whole Codex section,
432+
// including the "Active Codex Account" sub-control (account picker
433+
// below). Roll every Codex search entry's title/description/keywords
434+
// into one haystack so a search for "Active Codex Account" doesn't
435+
// render the section header with no body underneath it.
436+
keywords={ACCOUNTS_CODEX_SEARCH_ENTRIES.flatMap((entry) => [
437+
entry.title,
438+
entry.description ?? '',
439+
...(entry.keywords ?? [])
440+
])}
432441
className="space-y-3 px-1 py-2"
433442
>
434443
{/* Why: Settings deep-links can target this subsection directly from

src/renderer/src/components/settings/GeneralPane.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,15 @@ export function GeneralPane({ settings, updateSettings }: GeneralPaneProps): Rea
422422
<SearchableSetting
423423
title="Cache Timer"
424424
description="Show a countdown after a Claude agent becomes idle."
425-
keywords={['cache', 'timer', 'prompt', 'ttl', 'claude']}
425+
// Why: this is the primary control for the section gated by
426+
// GENERAL_CACHE_TIMER_SEARCH_ENTRIES (title "Prompt Cache Timer").
427+
// Mirroring those keywords keeps a search for "Prompt Cache Timer"
428+
// from rendering the section header with no body underneath.
429+
keywords={GENERAL_CACHE_TIMER_SEARCH_ENTRIES.flatMap((entry) => [
430+
entry.title,
431+
entry.description ?? '',
432+
...(entry.keywords ?? [])
433+
])}
426434
className="flex items-center justify-between gap-4 px-1 py-2"
427435
>
428436
<div className="space-y-0.5">

src/renderer/src/components/settings/ManageSessionsSection.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from '../ui/dialog'
1818
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'
1919
import { SearchableSetting } from './SearchableSetting'
20+
import { MANAGE_SESSIONS_SEARCH_ENTRIES } from './terminal-search'
2021
import { useAppStore } from '../../store'
2122
import { activateAndRevealWorktree } from '@/lib/worktree-activation'
2223
import { activateTabAndFocusPane } from '@/lib/activate-tab-and-focus-pane'
@@ -285,9 +286,9 @@ export function ManageSessionsSection(): React.JSX.Element {
285286
</div>
286287

287288
<SearchableSetting
288-
title="Daemon sessions running"
289-
description="Count of live PTY sessions across all workspaces."
290-
keywords={['daemon', 'pty', 'sessions', 'manage', 'kill', 'restart', 'terminal']}
289+
title={MANAGE_SESSIONS_SEARCH_ENTRIES[0].title}
290+
description={MANAGE_SESSIONS_SEARCH_ENTRIES[0].description}
291+
keywords={MANAGE_SESSIONS_SEARCH_ENTRIES[0].keywords}
291292
className="space-y-3"
292293
>
293294
{/* Why: full-width sessions card. The table *is* the primary

src/renderer/src/components/settings/Settings.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ function Settings(): React.JSX.Element {
192192
// leak through into a normal reopen of Settings.
193193
const [hiddenExperimentalUnlocked, setHiddenExperimentalUnlocked] = useState(false)
194194
const contentScrollRef = useRef<HTMLDivElement | null>(null)
195+
const searchInputRef = useRef<HTMLInputElement | null>(null)
195196
const terminalFontsLoadedRef = useRef(false)
196197
const pendingNavSectionRef = useRef<string | null>(null)
197198
const pendingScrollTargetRef = useRef<string | null>(null)
@@ -220,6 +221,30 @@ function Settings(): React.JSX.Element {
220221
return () => document.removeEventListener('keydown', handleKeyDown)
221222
}, [closeSettingsPage])
222223

224+
useEffect(() => {
225+
const handleFindShortcut = (event: KeyboardEvent): void => {
226+
if (event.defaultPrevented || event.altKey || event.shiftKey) {
227+
return
228+
}
229+
// Why: Cmd on Mac, Ctrl elsewhere — matches the rest of the app's
230+
// mod-key convention (see App.tsx) and aligns with platform Find norms.
231+
const mod = isMac ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey
232+
if (!mod || event.key.toLowerCase() !== 'f') {
233+
return
234+
}
235+
const input = searchInputRef.current
236+
if (!input) {
237+
return
238+
}
239+
event.preventDefault()
240+
input.focus()
241+
input.select()
242+
}
243+
244+
document.addEventListener('keydown', handleFindShortcut)
245+
return () => document.removeEventListener('keydown', handleFindShortcut)
246+
}, [isMac])
247+
223248
useEffect(
224249
() => () => {
225250
// Why: the settings search is a transient in-page filter. Leaving it behind makes the next
@@ -603,6 +628,7 @@ function Settings(): React.JSX.Element {
603628
repoSections={repoNavSections}
604629
hasRepos={repos.length > 0}
605630
searchQuery={settingsSearchQuery}
631+
searchInputRef={searchInputRef}
606632
onBack={closeSettingsPage}
607633
onSearchChange={setSettingsSearchQuery}
608634
onSelectSection={scrollToSection}

src/renderer/src/components/settings/SettingsSidebar.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import type { RefObject } from 'react'
12
import { ArrowLeft, Search, Server, type LucideIcon, type LucideProps } from 'lucide-react'
3+
import { isMacUserAgent } from '@/components/terminal-pane/pane-helpers'
24
import { Button } from '../ui/button'
35
import { Input } from '../ui/input'
46

7+
const SEARCH_SHORTCUT_HINT = isMacUserAgent() ? '⌘F' : 'Ctrl+F'
8+
59
type NavSection = {
610
id: string
711
title: string
@@ -20,6 +24,7 @@ type SettingsSidebarProps = {
2024
repoSections: RepoNavSection[]
2125
hasRepos: boolean
2226
searchQuery: string
27+
searchInputRef?: RefObject<HTMLInputElement | null>
2328
onBack: () => void
2429
onSearchChange: (query: string) => void
2530
onSelectSection: (
@@ -34,6 +39,7 @@ export function SettingsSidebar({
3439
repoSections,
3540
hasRepos,
3641
searchQuery,
42+
searchInputRef,
3743
onBack,
3844
onSearchChange,
3945
onSelectSection
@@ -56,11 +62,17 @@ export function SettingsSidebar({
5662
<div className="relative">
5763
<Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
5864
<Input
65+
ref={searchInputRef}
5966
value={searchQuery}
6067
onChange={(event) => onSearchChange(event.target.value)}
6168
placeholder="Search settings"
62-
className="pl-9"
69+
className="pl-9 pr-14"
6370
/>
71+
{searchQuery === '' ? (
72+
<kbd className="pointer-events-none absolute right-2 top-1/2 inline-flex -translate-y-1/2 items-center rounded border border-border/60 bg-background/40 px-1.5 py-px font-mono text-[10px] font-medium text-muted-foreground">
73+
{SEARCH_SHORTCUT_HINT}
74+
</kbd>
75+
) : null}
6476
</div>
6577
</div>
6678

0 commit comments

Comments
 (0)