From 4a68b2147798b8290efcd3dbd6a83fef54032f65 Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Mon, 1 Jun 2026 23:14:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(plugin-market):=20rename=20component=20fil?= =?UTF-8?q?ter=20to=20"=E6=8F=92=E4=BB=B6=E7=BB=84=E4=BB=B6"=20with=20hint?= =?UTF-8?q?=20tooltip=20+=20persist=20filters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename the in-app plugin market component filter label to "插件组件" / "Plugin Component" - Add an Info icon tooltip explaining what plugin components are (Tool / Command / EventListener, etc.) - Persist filter selections (type / component / tags / sort) in localStorage so they survive reloads; restored on mount (URL type param still wins) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../plugin-market/PluginMarketComponent.tsx | 71 +++++++++++++++++-- web/src/i18n/locales/en-US.ts | 4 +- web/src/i18n/locales/zh-Hans.ts | 4 +- 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx b/web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx index 1f3efeea..c8ed2ccc 100644 --- a/web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx +++ b/web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx @@ -24,7 +24,13 @@ import { FileText, SlidersHorizontal, X, + Info, } from 'lucide-react'; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from '@/components/ui/tooltip'; import PluginMarketCardComponent from './plugin-market-card/PluginMarketCardComponent'; import { PluginMarketCardVO } from './plugin-market-card/PluginMarketCardVO'; import { RecommendationLists } from './RecommendationLists'; @@ -49,6 +55,23 @@ interface SortOption { sortOrder: string; } +// Persist the market filter conditions (type / component / tags / sort) across +// visits via localStorage. +const MARKET_FILTERS_KEY = 'langbot_market_filters'; +interface MarketFilters { + typeFilter?: string; + componentFilter?: string; + selectedTags?: string[]; + sortOption?: string; +} +function loadMarketFilters(): MarketFilters { + try { + return JSON.parse(localStorage.getItem(MARKET_FILTERS_KEY) || '{}'); + } catch { + return {}; + } +} + // 内部组件,用于处理搜索参数 function MarketPageContent({ installPlugin, @@ -70,17 +93,22 @@ function MarketPageContent({ ]; const [searchQuery, setSearchQuery] = useState(''); - const [componentFilter, setComponentFilter] = useState('all'); + const [componentFilter, setComponentFilter] = useState( + () => loadMarketFilters().componentFilter ?? 'all', + ); const [typeFilter, setTypeFilter] = useState(() => { const type = searchParams.get('type'); if (type && validTypes.includes(type)) { return type; } - return 'all'; + const saved = loadMarketFilters().typeFilter; + return saved && validTypes.includes(saved) ? saved : 'all'; }); const activeAdvancedFilters = (typeFilter === 'all' ? 0 : 1) + (componentFilter === 'all' ? 0 : 1); - const [selectedTags, setSelectedTags] = useState([]); + const [selectedTags, setSelectedTags] = useState( + () => loadMarketFilters().selectedTags ?? [], + ); const [availableTags, setAvailableTags] = useState([]); const [tagNames, setTagNames] = useState>({}); const [recommendationLists, setRecommendationLists] = useState< @@ -92,7 +120,26 @@ function MarketPageContent({ const [hasMore, setHasMore] = useState(true); const [currentPage, setCurrentPage] = useState(1); const [total, setTotal] = useState(0); - const [sortOption, setSortOption] = useState('install_count_desc'); + const [sortOption, setSortOption] = useState( + () => loadMarketFilters().sortOption ?? 'install_count_desc', + ); + + // Persist filter conditions so they survive navigation / reload. + useEffect(() => { + try { + localStorage.setItem( + MARKET_FILTERS_KEY, + JSON.stringify({ + typeFilter, + componentFilter, + selectedTags, + sortOption, + }), + ); + } catch { + // ignore storage errors + } + }, [typeFilter, componentFilter, selectedTags, sortOption]); const pageSize = 12; // 每页12个 const searchTimeoutRef = useRef(null); @@ -642,8 +689,22 @@ function MarketPageContent({
-
+
{t('market.filterByComponent')} + + + + + + {t('market.filterByComponentHint')} + +