feat(settings): focus search on Cmd/Ctrl+F and fix empty section headers (#1485)
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
2f99f93142
commit
be2b30f1ad
|
|
@ -428,7 +428,16 @@ export function AccountsPane({ settings, updateSettings }: AccountsPaneProps): R
|
|||
<SearchableSetting
|
||||
title="Codex Accounts"
|
||||
description="Manage which Codex account Orca uses for live rate limit fetching."
|
||||
keywords={['codex', 'account', 'rate limit', 'status bar', 'quota']}
|
||||
// Why: this single SearchableSetting backs the whole Codex section,
|
||||
// including the "Active Codex Account" sub-control (account picker
|
||||
// below). Roll every Codex search entry's title/description/keywords
|
||||
// into one haystack so a search for "Active Codex Account" doesn't
|
||||
// render the section header with no body underneath it.
|
||||
keywords={ACCOUNTS_CODEX_SEARCH_ENTRIES.flatMap((entry) => [
|
||||
entry.title,
|
||||
entry.description ?? '',
|
||||
...(entry.keywords ?? [])
|
||||
])}
|
||||
className="space-y-3 px-1 py-2"
|
||||
>
|
||||
{/* Why: Settings deep-links can target this subsection directly from
|
||||
|
|
|
|||
|
|
@ -422,7 +422,15 @@ export function GeneralPane({ settings, updateSettings }: GeneralPaneProps): Rea
|
|||
<SearchableSetting
|
||||
title="Cache Timer"
|
||||
description="Show a countdown after a Claude agent becomes idle."
|
||||
keywords={['cache', 'timer', 'prompt', 'ttl', 'claude']}
|
||||
// Why: this is the primary control for the section gated by
|
||||
// GENERAL_CACHE_TIMER_SEARCH_ENTRIES (title "Prompt Cache Timer").
|
||||
// Mirroring those keywords keeps a search for "Prompt Cache Timer"
|
||||
// from rendering the section header with no body underneath.
|
||||
keywords={GENERAL_CACHE_TIMER_SEARCH_ENTRIES.flatMap((entry) => [
|
||||
entry.title,
|
||||
entry.description ?? '',
|
||||
...(entry.keywords ?? [])
|
||||
])}
|
||||
className="flex items-center justify-between gap-4 px-1 py-2"
|
||||
>
|
||||
<div className="space-y-0.5">
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
} from '../ui/dialog'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'
|
||||
import { SearchableSetting } from './SearchableSetting'
|
||||
import { MANAGE_SESSIONS_SEARCH_ENTRIES } from './terminal-search'
|
||||
import { useAppStore } from '../../store'
|
||||
import { activateAndRevealWorktree } from '@/lib/worktree-activation'
|
||||
import { activateTabAndFocusPane } from '@/lib/activate-tab-and-focus-pane'
|
||||
|
|
@ -285,9 +286,9 @@ export function ManageSessionsSection(): React.JSX.Element {
|
|||
</div>
|
||||
|
||||
<SearchableSetting
|
||||
title="Daemon sessions running"
|
||||
description="Count of live PTY sessions across all workspaces."
|
||||
keywords={['daemon', 'pty', 'sessions', 'manage', 'kill', 'restart', 'terminal']}
|
||||
title={MANAGE_SESSIONS_SEARCH_ENTRIES[0].title}
|
||||
description={MANAGE_SESSIONS_SEARCH_ENTRIES[0].description}
|
||||
keywords={MANAGE_SESSIONS_SEARCH_ENTRIES[0].keywords}
|
||||
className="space-y-3"
|
||||
>
|
||||
{/* Why: full-width sessions card. The table *is* the primary
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ function Settings(): React.JSX.Element {
|
|||
// leak through into a normal reopen of Settings.
|
||||
const [hiddenExperimentalUnlocked, setHiddenExperimentalUnlocked] = useState(false)
|
||||
const contentScrollRef = useRef<HTMLDivElement | null>(null)
|
||||
const searchInputRef = useRef<HTMLInputElement | null>(null)
|
||||
const terminalFontsLoadedRef = useRef(false)
|
||||
const pendingNavSectionRef = useRef<string | null>(null)
|
||||
const pendingScrollTargetRef = useRef<string | null>(null)
|
||||
|
|
@ -220,6 +221,30 @@ function Settings(): React.JSX.Element {
|
|||
return () => document.removeEventListener('keydown', handleKeyDown)
|
||||
}, [closeSettingsPage])
|
||||
|
||||
useEffect(() => {
|
||||
const handleFindShortcut = (event: KeyboardEvent): void => {
|
||||
if (event.defaultPrevented || event.altKey || event.shiftKey) {
|
||||
return
|
||||
}
|
||||
// Why: Cmd on Mac, Ctrl elsewhere — matches the rest of the app's
|
||||
// mod-key convention (see App.tsx) and aligns with platform Find norms.
|
||||
const mod = isMac ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey
|
||||
if (!mod || event.key.toLowerCase() !== 'f') {
|
||||
return
|
||||
}
|
||||
const input = searchInputRef.current
|
||||
if (!input) {
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
input.focus()
|
||||
input.select()
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', handleFindShortcut)
|
||||
return () => document.removeEventListener('keydown', handleFindShortcut)
|
||||
}, [isMac])
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
// 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 {
|
|||
repoSections={repoNavSections}
|
||||
hasRepos={repos.length > 0}
|
||||
searchQuery={settingsSearchQuery}
|
||||
searchInputRef={searchInputRef}
|
||||
onBack={closeSettingsPage}
|
||||
onSearchChange={setSettingsSearchQuery}
|
||||
onSelectSection={scrollToSection}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import type { RefObject } from 'react'
|
||||
import { ArrowLeft, Search, Server, type LucideIcon, type LucideProps } from 'lucide-react'
|
||||
import { isMacUserAgent } from '@/components/terminal-pane/pane-helpers'
|
||||
import { Button } from '../ui/button'
|
||||
import { Input } from '../ui/input'
|
||||
|
||||
const SEARCH_SHORTCUT_HINT = isMacUserAgent() ? '⌘F' : 'Ctrl+F'
|
||||
|
||||
type NavSection = {
|
||||
id: string
|
||||
title: string
|
||||
|
|
@ -20,6 +24,7 @@ type SettingsSidebarProps = {
|
|||
repoSections: RepoNavSection[]
|
||||
hasRepos: boolean
|
||||
searchQuery: string
|
||||
searchInputRef?: RefObject<HTMLInputElement | null>
|
||||
onBack: () => void
|
||||
onSearchChange: (query: string) => void
|
||||
onSelectSection: (
|
||||
|
|
@ -34,6 +39,7 @@ export function SettingsSidebar({
|
|||
repoSections,
|
||||
hasRepos,
|
||||
searchQuery,
|
||||
searchInputRef,
|
||||
onBack,
|
||||
onSearchChange,
|
||||
onSelectSection
|
||||
|
|
@ -56,11 +62,17 @@ export function SettingsSidebar({
|
|||
<div className="relative">
|
||||
<Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
||||
<Input
|
||||
ref={searchInputRef}
|
||||
value={searchQuery}
|
||||
onChange={(event) => onSearchChange(event.target.value)}
|
||||
placeholder="Search settings"
|
||||
className="pl-9"
|
||||
className="pl-9 pr-14"
|
||||
/>
|
||||
{searchQuery === '' ? (
|
||||
<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">
|
||||
{SEARCH_SHORTCUT_HINT}
|
||||
</kbd>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue