feat(settings): results-only search, keyboard nav, flash animation, Ctrl+F (#264)

Follow-up on #263. Refines the cross-tab search into a proper
command-palette-ish flow and polishes the UX around it.

Results-only mode:
- When a query is active, the tab content is hidden entirely; the
  results list is the only thing shown. Unified list (was: in-place
  current-tab filter + "In other tabs" panel underneath), sorted with
  current-tab matches first and then by score.
- Removed the DOM-based hide/show logic and its CSS helper class, the
  dead searchOtherTabs i18n key, and the searchHits/otherTabHits state.

Keyboard navigation inside the search field:
- ↓/↑ moves selection through the result list (clamped, no wrap).
- Enter activates the selected item (same flow as a click — clears
  query, switches tab, scrolls + opens + flashes the target).
- Mouse hover syncs with the keyboard selection so the two input modes
  don't fight each other.
- Selected item gets accent-border + tinted background; scrollIntoView
  with block:'nearest' keeps it visible when the list is long.

Ctrl/Cmd+F (Settings page only):
- Window keydown listener registered on mount, removed on unmount →
  the shortcut is live only while Settings is rendered.
- Opens the search input, focuses + selects it even if already open.
- preventDefault blocks the native WebKit find bar.
- Placeholder now hints at the shortcut: "… (Ctrl+F)" / "… (⌘F)" on
  macOS, no new i18n keys needed.

Target flash animation:
- After navigating from a result, the target SettingsSubSection gets a
  1.4s accent-colored border + glow pulse so the user immediately sees
  which entry the result pointed at. Reflow trick lets it retrigger
  when clicking the same result twice.

Misc:
- "Next Track Buffering" → "Buffering" in all 8 locales + the section
  comment in Settings.tsx. The SETTINGS_INDEX keeps "next track" as a
  keyword so old search habits still find it.

Co-authored-by: Psychotoxical <dev@psysonic.app>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Frank Stellmacher
2026-04-22 15:12:48 +02:00
committed by GitHub
parent ae7b94f190
commit f0e5b2542b
10 changed files with 139 additions and 105 deletions
+1 -2
View File
@@ -732,7 +732,6 @@ export const ruTranslation = {
aboutContributorsCount_other: '{{count}} вклада',
searchPlaceholder: 'Поиск в настройках…',
searchNoResults: 'Ничего не найдено по вашему запросу.',
searchOtherTabs: 'В других вкладках',
aboutMaintainersLabel: 'Сопровождающие',
integrationsPrivacyTitle: 'Уведомление о конфиденциальности',
integrationsPrivacyBody: 'Все интеграции на этой вкладке включаются <strong>по желанию</strong> и при активации отправляют данные во внешние сервисы или на ваш сервер Navidrome. Last.fm получает вашу историю прослушивания, Discord показывает текущую композицию в вашем профиле, Bandsintown опрашивается по артисту для получения дат гастролей, а «Сейчас играет» делится текущей композицией с другими пользователями вашего сервера Navidrome. Если вы не хотите ничего из этого, просто оставьте соответствующий раздел отключённым.',
@@ -822,7 +821,7 @@ export const ruTranslation = {
gaplessDesc: 'Заранее подгружать следующий трек, чтобы не было тишины',
preloadMode: 'Предзагрузка следующего трека',
preloadModeDesc: 'Когда начинать буферизацию следующего в очереди',
nextTrackBufferingTitle: 'Буферизация следующего трека',
nextTrackBufferingTitle: 'Буферизация',
preloadHotCacheMutualExclusive: 'Предзагрузка и Hot Cache выполняют одну функцию — одновременно может быть активна только одна. Включение одной автоматически отключает другую.',
preloadOff: 'Выкл.',
preloadBalanced: 'Умеренно (за 30 с до конца)',