From 5175677b248c86ea3fcffd9b5e7249e91b4f16aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Thu, 28 May 2026 21:38:18 +0800 Subject: [PATCH] feat: improve search history to show recently used tools with direct navigation - Store feature keys (PageType) in history instead of translated labels - Show icon + name + description in history items (same as search results) - Click or Enter on history item navigates directly to the tool page - Remove History icon import (no longer needed) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/components/TopBar.tsx | 61 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/src/components/TopBar.tsx b/src/components/TopBar.tsx index 99f15c6..fc1adad 100644 --- a/src/components/TopBar.tsx +++ b/src/components/TopBar.tsx @@ -1,15 +1,5 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { - ArrowLeft, - ExternalLink, - History, - Monitor, - Moon, - Search, - Settings, - Sun, - X, -} from 'lucide-react'; +import { ArrowLeft, ExternalLink, Monitor, Moon, Search, Settings, Sun, X } from 'lucide-react'; import { useRouter } from '@/providers/RouterProvider'; import { useThemeMode } from '@/providers/ThemeModeProvider'; import { FeatureConfig, FEATURES } from '@/config/features'; @@ -85,12 +75,15 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void }) const displayedHistory = useMemo(() => { if (searchQuery.trim()) return []; - return searchHistory.slice(0, SEARCH_HISTORY_DISPLAY); + return searchHistory + .slice(0, SEARCH_HISTORY_DISPLAY) + .map((key) => ({ key, feature: FEATURES.find((f) => f.key === key) })) + .filter((item) => item.feature && item.feature.key !== 'dashboard'); }, [searchHistory, searchQuery]); - const saveToHistory = async (query: string) => { - if (!query.trim()) return; - const nextHistory = [query, ...searchHistory.filter((h) => h !== query)].slice( + const saveToHistory = async (featureKey: string) => { + if (!featureKey.trim()) return; + const nextHistory = [featureKey, ...searchHistory.filter((h) => h !== featureKey)].slice( 0, SEARCH_HISTORY_LIMIT, ); @@ -100,7 +93,7 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void }) const handleSelectFeature = (feature: FeatureConfig) => { navigateTo(feature.key); - saveToHistory(t(feature.labelKey)); + saveToHistory(feature.key); setSearchQuery(''); setShowResults(false); }; @@ -127,14 +120,9 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void }) if (searchQuery.trim()) { handleSelectFeature(searchResults[selectedIndex]); } else { - const selectedQuery = displayedHistory[selectedIndex]; - if (selectedQuery) { - setSearchQuery(selectedQuery); - setSelectedIndex(-1); - const matched = FEATURES.find( - (f) => f.key !== 'dashboard' && t(f.labelKey) === selectedQuery, - ); - if (matched) handleSelectFeature(matched); + const selected = displayedHistory[selectedIndex]; + if (selected?.feature) { + handleSelectFeature(selected.feature); } } } else if (searchQuery.trim() && searchResults.length > 0) { @@ -252,13 +240,10 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void }) {displayedHistory.map((item, index) => (
  • { - setSearchQuery(item); - setSelectedIndex(-1); - }} + onClick={() => item.feature && handleSelectFeature(item.feature)} className={cn( 'flex items-center gap-3 px-3 py-2 rounded-md cursor-pointer text-sm transition-colors', selectedIndex === index @@ -266,8 +251,22 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void }) : 'hover:bg-muted/60', )} > - - {item} +
    + {item.feature?.icon && } +
    +
    +

    + {item.feature && t(item.feature.labelKey)} +

    +

    + {item.feature && t(item.feature.descriptionKey)} +

    +
  • ))}