Adds item-level search inside Settings so users can find concrete settings like provider auth, agent mode, terminal font size, tunnel options, notification events, and similar controls instead of only filtering top-level pages. Groups search results by Settings page and shows localized labels plus optional descriptions where useful. Supports keyboard navigation with Arrow Up/Down, Enter, and Escape, matching the existing autocomplete interaction style. Opens the correct Settings page or split-page draft state before scrolling to the matching control. Highlights the matched setting with a subtle token-based background so users can see where they landed without an aggressive outline. Adds explicit data-settings-item anchors across Settings pages and a centralized search registry with runtime/mobile availability guards. Updates Settings UI skill guidance so future Settings changes keep search registry entries, anchors, localization, and availability guards in sync.
7.3 KiB
7.3 KiB
Settings Item Search Plan
Goal
Add Settings search that finds individual settings items, not only top-level pages.
The search should behave like this:
- User types a query in the Settings navigation area.
- Results show matching concrete settings, grouped or labeled by their Settings page.
- Each result shows the item title and, when available, its description.
- Clicking a result opens the correct Settings page.
- After the page renders, the matching row/card/section scrolls into view.
- The matched item gets a short visual highlight so the user can see where they landed.
Current Architecture Notes
- Settings shell lives in
packages/ui/src/components/views/SettingsView.tsx. - Page metadata and slugs live in
packages/ui/src/lib/settings/metadata.ts. - Settings localization lives in
packages/ui/src/lib/i18n/messages/*.settings.ts. - Settings UI text is read through
useI18n()andt(key). - Standard page wrappers live in
packages/ui/src/components/sections/shared/.
Proposed Architecture
Use an explicit searchable item registry instead of scraping React or the DOM.
Each searchable item should contain:
id: stable item id, for exampleappearance.language.page: targetSettingsPageSlug, for exampleappearance.titleKey: localized title key.descriptionKey: optional localized description key.keywords: optional non-visible search helpers.isAvailable: optional runtime/mobile guard for item-level availability.
Example:
{
id: 'appearance.language',
page: 'appearance',
titleKey: 'settings.appearance.language.label',
descriptionKey: 'settings.appearance.language.description',
keywords: ['locale', 'translation', 'ui language'],
}
Implementation Steps
-
Create
packages/ui/src/lib/settings/search.ts.- Export
SETTINGS_SEARCH_ITEMS. - Export a helper to build localized search results from
t(). - Filter by page availability and
visiblePageSlugs.
- Export
-
Add search UI to
SettingsView.tsx.- Search input should live in the left Settings navigation area on desktop.
- On mobile, keep behavior simple: show results in the nav stage and open target page on select.
- When query is empty, keep the existing navigation list.
- When query has text, replace the normal nav list with concrete search results.
-
Add click behavior for a search result.
- Set
settingsPageto the result page. - Store pending target item id in component state/ref.
- After content renders, find
[data-settings-item="<id>"]. - Scroll it into view.
- Add a temporary highlight using a data attribute or CSS class.
- Set
-
Add a tiny shared anchor/highlight pattern.
- Prefer adding
data-settings-item="..."to existing row/card containers. - Avoid wrappers that change layout.
- Keep highlight styling generic, for example a short ring/background transition.
- Prefer adding
-
Add initial searchable coverage.
- Start with high-value pages that already use many localized strings:
appearancechatsessionsnotificationsgitprovidersagents
- Add more pages incrementally.
- Start with high-value pages that already use many localized strings:
-
Validation.
- Run
bun run type-check. - Run
bun run lint. - Manually verify search result navigation for at least one single page and one split page.
- Run
Current Implementation Status
Done:
packages/ui/src/lib/settings/search.tsexists and exports the explicit registry plus localized result builder.- Search input is wired into
SettingsView.tsx. - Results are grouped by page header.
- ArrowUp, ArrowDown, Enter, and Escape work while the search input is focused.
- Result click opens the target page and scrolls to
[data-settings-item="..."]. - Matching target gets a temporary highlight via
data-settings-search-highlight. - Search respects page availability,
visiblePageSlugs, and item-level platform/runtime/mobile guards. - Initial anchors exist for
appearance,chat,sessions,notifications,git, andusage.
Covered pages/items so far:
appearance: themes, localization, PWA/mobile-only controls, layout controls, navigation controls, usage reports.chat: render mode, transport, reasoning, layout/message toggles, mobile status bar, dotfiles, queue/draft/spellcheck.sessions: defaults, retention, desktop network controls, OpenCode CLI controls.notifications: delivery, events, background push.git: GitHub account, identities, changes view, Gitmoji, gitignored files.usage: header menu visibility, model quotas section.agents: create action plus static editor fields for name, mode, model, temperature, Top P, system prompt, and permissions.commands: create action plus static editor fields for name, agent, model, and template.mcp: create action plus static editor sections for server, command/URL, environment variables, and advanced remote options.plugins: add action plus static editor fields for spec, options JSON, and file content.snippets: create action plus snippet content editor.providers: connect action plus auth, connection details, and models sections.skills.installed: create action plus basic information, instructions, and supporting files sections.behavior: global AGENTS.md and response style sections.projects: static project metadata fields and worktree section, excluding individual projects.skills.catalog: source repository, catalog search, and add catalog action, excluding individual catalog skills/sources.magic-prompts: visible prompt, instructions, and reset-all action, excluding individual prompt result generation beyond the selected editor page.shortcuts: keyboard shortcut editor section.voice: voice setup, speech recognition, and playback sections.tunnel: provider, tunnel type, TTLs, managed remote/local configuration, and start/connect link sections.remote-instances: client auth/pairing and desktop direct-host sections; SSH instance dialog fields stay out of search because they require selected-instance state.
Still pending:
- Add state-aware filtering for settings that are hidden based on current settings values, not just platform. Examples:
chat.activity-default-mode,chat.collapsible-reasoning. - Add focused tests for
buildSettingsSearchResults, especially runtime/mobile filtering.
Out of scope by decision:
- Do not generate search results from dynamic store entities such as individual agents, commands, MCP servers, snippets, plugins, skills, providers, or projects.
- For split pages, search should cover predictable static create actions, editor fields, and sections only.
Important Constraints
- Do not rely on localized key naming alone for navigation. The registry is the source of truth.
- Do not parse JSX or scrape the DOM to discover settings automatically.
- Search should use current locale strings, with English fallback already handled by i18n.
- Do not introduce broad Zustand state for transient search query/highlight state. Keep it local to
SettingsViewunless another surface needs it. - Keep page behavior unchanged when the query is empty.
- If a page is unavailable in the current runtime, its search items must not appear.
Future Improvements
- Add fuzzy ranking instead of simple substring matching.
- Support deep-linking to settings items from URLs or app commands.
- Add complete registry coverage for all Settings pages.