From 607e1f25a5012104994870dd86dadf2ee11fa9a9 Mon Sep 17 00:00:00 2001 From: MyPrototypeWhat Date: Fri, 1 Aug 2025 15:12:20 +0800 Subject: [PATCH] refactor(discover): simplify Discover page structure and improve routing logic - Refactored DiscoverPage component to streamline tab and sidebar handling. - Updated routing logic to utilize a new ROUTERS_MAP for better category management. - Removed unused props and simplified state management in useDiscoverCategories hook. - Enhanced DiscoverSidebar and DiscoverMain components for improved clarity and performance. - Adjusted CherryStoreType enum values for consistency in path definitions. --- .../discover/components/DiscoverMain.tsx | 30 +---- .../discover/components/DiscoverSidebar.tsx | 15 +-- .../discover/hooks/useDiscoverCategories.ts | 123 +++++------------- src/renderer/src/pages/discover/index.tsx | 13 +- .../discover/pages/minapps/MinAppsPage.tsx | 2 +- src/renderer/src/pages/discover/routers.ts | 12 +- src/renderer/src/types/cherryStore.ts | 4 +- 7 files changed, 56 insertions(+), 143 deletions(-) diff --git a/src/renderer/src/pages/discover/components/DiscoverMain.tsx b/src/renderer/src/pages/discover/components/DiscoverMain.tsx index 9505a88887..d4391edb51 100644 --- a/src/renderer/src/pages/discover/components/DiscoverMain.tsx +++ b/src/renderer/src/pages/discover/components/DiscoverMain.tsx @@ -1,34 +1,16 @@ import React, { Suspense } from 'react' -import { Navigate, Route, Routes, useLocation } from 'react-router-dom' +import { Navigate, Route, Routes } from 'react-router-dom' import { ROUTERS } from '../routers' -import { InternalCategory } from '../type' - -export interface DiscoverContentProps { - activeTabId: string - currentCategory: InternalCategory | undefined -} - -const DiscoverContent: React.FC = ({ activeTabId, currentCategory }) => { - const location = useLocation() - - if (!currentCategory || !activeTabId) { - return
Loading: Category or Tab ID missing...
- } - - if (!activeTabId && !location.pathname.startsWith('/discover/')) { - return - } +const DiscoverContent: React.FC = () => { return ( - {ROUTERS.map((_Route) => { - if (!_Route.component) return null - return } /> - })} - - Discover Feature Not Found at {location.pathname}} /> + } /> + {ROUTERS.map((route) => ( + } /> + ))} ) diff --git a/src/renderer/src/pages/discover/components/DiscoverSidebar.tsx b/src/renderer/src/pages/discover/components/DiscoverSidebar.tsx index 05744b364b..95df9f96b4 100644 --- a/src/renderer/src/pages/discover/components/DiscoverSidebar.tsx +++ b/src/renderer/src/pages/discover/components/DiscoverSidebar.tsx @@ -1,4 +1,5 @@ -import { SubCategoryItem } from '@renderer/types/cherryStore' +// 还没测,目前助手和小程序用不到这个 + import { Badge } from '@renderer/ui/badge' import { Sidebar, @@ -13,15 +14,9 @@ import { InternalCategory } from '../type' interface DiscoverSidebarProps { activeCategory: InternalCategory | undefined - selectedSubcategory: string - onSelectSubcategory: (subcategoryId: string, row?: SubCategoryItem) => void } -export default function DiscoverSidebar({ - activeCategory, - selectedSubcategory, - onSelectSubcategory -}: DiscoverSidebarProps) { +export default function DiscoverSidebar({ activeCategory }: DiscoverSidebarProps) { if (!activeCategory) { return ( @@ -42,9 +37,9 @@ export default function DiscoverSidebar({ activeCategory.items.map((subItem) => ( { - onSelectSubcategory(subItem.id, subItem) + // onSelectSubcategory(subItem.id, subItem) }} size="sm"> {subItem.name} diff --git a/src/renderer/src/pages/discover/hooks/useDiscoverCategories.ts b/src/renderer/src/pages/discover/hooks/useDiscoverCategories.ts index 8d2cd641ec..3132dfe792 100644 --- a/src/renderer/src/pages/discover/hooks/useDiscoverCategories.ts +++ b/src/renderer/src/pages/discover/hooks/useDiscoverCategories.ts @@ -1,106 +1,53 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { useLocation, useNavigate } from 'react-router-dom' +import { CherryStoreType } from '@renderer/types/cherryStore' +import { useCallback, useMemo } from 'react' +import { useLocation, useNavigate, useSearchParams } from 'react-router-dom' -import { ROUTERS, ROUTERS_ENTRIES } from '../routers' +import { ROUTERS, ROUTERS_MAP } from '../routers' export function useDiscoverCategories() { - const [activeTab, setActiveTab] = useState('') - const [selectedSubcategory, setSelectedSubcategory] = useState('all') - - const navigate = useNavigate() const location = useLocation() + const navigate = useNavigate() + const [searchParams, setSearchParams] = useSearchParams() - // 使用 useRef 来跟踪是否是用户手动导航,避免重复渲染 - const isUserNavigationRef = useRef(false) - - // URL 同步逻辑 - 适配新的 URL 格式 /discover/xxx?category=xxx - useEffect(() => { + const activeTabId = useMemo(() => { + // e.g., location.pathname = /discover/assistant, segments = ['discover', 'assistant'] const pathSegments = location.pathname.split('/').filter(Boolean) - const currentCategoryPath = pathSegments.length >= 2 && pathSegments[0] === 'discover' ? pathSegments[1] : undefined - const searchParams = new URLSearchParams(location.search) - const categoryFromQuery = searchParams.get('category') - const subcategoryFromQuery = searchParams.get('subcategory') || 'all' + const currentTabId = pathSegments[1] as CherryStoreType - // 处理基础路径重定向 - if (location.pathname === '/discover' || location.pathname === '/discover/') { - if (ROUTERS.length > 0) { - const firstCategory = ROUTERS[0] - navigate(`/discover/${firstCategory.path}?category=${firstCategory.id}&subcategory=all`, { replace: true }) + return ROUTERS_MAP.has(currentTabId) ? currentTabId : ROUTERS[0].id + }, [location.pathname]) + + const activeCategoryId = useMemo(() => { + return searchParams.get('categoryId') || 'all' + }, [searchParams]) + + const handleSelectTab = useCallback( + (newTabId: string) => { + if (activeTabId !== newTabId) { + navigate(`/discover/${newTabId}`) } - return - } + }, + [activeTabId, navigate] + ) - // 根据URL格式,优先使用 category 查询参数 - let targetCategoryId: string | null = categoryFromQuery - - // 如果没有 category 参数,尝试从路径推断 - if (!targetCategoryId && currentCategoryPath) { - const categoryFromPath = ROUTERS_ENTRIES[currentCategoryPath] - targetCategoryId = categoryFromPath?.id || null - } - - // 处理无效分类重定向 - if (!targetCategoryId || !ROUTERS_ENTRIES[targetCategoryId]) { - if (ROUTERS.length > 0) { - const firstCategory = ROUTERS[0] - navigate(`/discover/${firstCategory.path}?category=${firstCategory.id}&subcategory=all`, { replace: true }) + const handleSelectCategory = useCallback( + (newCategoryId: string) => { + if (activeCategoryId !== newCategoryId) { + setSearchParams({ categoryId: newCategoryId }) } - return - } - - // 只有当状态确实需要更新时才更新 - if (activeTab !== targetCategoryId) { - setActiveTab(targetCategoryId) - } - - if (selectedSubcategory !== subcategoryFromQuery) { - setSelectedSubcategory(subcategoryFromQuery) - } - - // 重置用户导航标记 - isUserNavigationRef.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [location.pathname, location.search, navigate]) // 故意不包含 activeTab 和 selectedSubcategory 以避免重复渲染 + }, + [activeCategoryId, setSearchParams] + ) const currentCategory = useMemo(() => { - return ROUTERS_ENTRIES[activeTab] - }, [activeTab]) - - // 优化的 Tab 选择处理,使用 useCallback 避免重复渲染 - // 更新为新的 URL 格式 /discover/xxx?category=xxx&subcategory=xxx - const handleSelectTab = useCallback( - (tabId: string) => { - if (activeTab === tabId) return // 如果已经是当前 tab,直接返回 - - const categoryToSelect = ROUTERS_ENTRIES[tabId] - if (categoryToSelect?.path) { - isUserNavigationRef.current = true - navigate(`/discover/${categoryToSelect.path}?category=${tabId}&subcategory=all`) - } - }, - [activeTab, navigate] - ) - - // 优化的子分类选择处理 - const handleSelectSubcategory = useCallback( - (subcategoryId: string) => { - if (selectedSubcategory === subcategoryId) return // 如果已经是当前子分类,直接返回 - - const currentCatDetails = ROUTERS_ENTRIES[activeTab] - if (currentCatDetails?.path) { - isUserNavigationRef.current = true - navigate(`/discover/${currentCatDetails.path}?category=${activeTab}&subcategory=${subcategoryId}`) - } - }, - [selectedSubcategory, activeTab, navigate] - ) + return ROUTERS_MAP.get(activeTabId) + }, [activeTabId]) return { - activeTab, - selectedSubcategory, + activeTabId, + activeCategoryId, currentCategory, handleSelectTab, - handleSelectSubcategory, - setActiveTab + handleSelectCategory } } diff --git a/src/renderer/src/pages/discover/index.tsx b/src/renderer/src/pages/discover/index.tsx index e39d1faf4a..bffc9318ca 100644 --- a/src/renderer/src/pages/discover/index.tsx +++ b/src/renderer/src/pages/discover/index.tsx @@ -10,8 +10,7 @@ import { ROUTERS } from './routers' export default function DiscoverPage() { const { t } = useTranslation() - const { activeTab, selectedSubcategory, currentCategory, handleSelectTab, handleSelectSubcategory } = - useDiscoverCategories() + const { activeTabId, currentCategory, handleSelectTab } = useDiscoverCategories() const tabs = useMemo(() => ROUTERS.map((router) => ({ id: router.id, label: router.title })), []) @@ -26,23 +25,19 @@ export default function DiscoverPage() { {ROUTERS.length > 0 && (
- +
)}
{currentCategory?.hasSidebar && (
- +
)}
- +
diff --git a/src/renderer/src/pages/discover/pages/minapps/MinAppsPage.tsx b/src/renderer/src/pages/discover/pages/minapps/MinAppsPage.tsx index 39ff89a1bc..c52d75247e 100644 --- a/src/renderer/src/pages/discover/pages/minapps/MinAppsPage.tsx +++ b/src/renderer/src/pages/discover/pages/minapps/MinAppsPage.tsx @@ -114,7 +114,7 @@ const ContentContainer = styled.div` flex: 1; flex-direction: row; justify-content: center; - height: 100%; + overflow: hidden; ` // const HeaderContainer = styled.div` diff --git a/src/renderer/src/pages/discover/routers.ts b/src/renderer/src/pages/discover/routers.ts index 3b85f70a79..c5de9324b9 100644 --- a/src/renderer/src/pages/discover/routers.ts +++ b/src/renderer/src/pages/discover/routers.ts @@ -6,7 +6,7 @@ export const ROUTERS = [ { id: CherryStoreType.ASSISTANT, title: i18n.t('assistants.title'), - path: 'assistant', + path: CherryStoreType.ASSISTANT, component: lazy(() => import('./pages/agents/AgentsPage')), hasSidebar: false, // 目前都没有侧边栏 items: [{ id: 'all', name: `All ${i18n.t('assistants.title')}` }] // 预设 "All" 子分类 @@ -14,7 +14,7 @@ export const ROUTERS = [ { id: CherryStoreType.MINI_APP, title: i18n.t('minapp.title'), - path: 'mini-app', + path: CherryStoreType.MINI_APP, component: lazy(() => import('./pages/minapps/MinAppsPage')), hasSidebar: false, // 目前都没有侧边栏 items: [{ id: 'all', name: `All ${i18n.t('minapp.title')}` }] // 预设 "All" 子分类 @@ -47,10 +47,4 @@ export const ROUTERS = [ // } ] -export const ROUTERS_ENTRIES = ROUTERS.reduce( - (acc, { id, ...rest }) => { - acc[id] = rest - return acc - }, - {} as Record<(typeof ROUTERS)[number]['id'], Omit<(typeof ROUTERS)[number], 'id'>> -) +export const ROUTERS_MAP = new Map(ROUTERS.map((router) => [router.id, router])) diff --git a/src/renderer/src/types/cherryStore.ts b/src/renderer/src/types/cherryStore.ts index 38f31e0c5a..65984a8525 100644 --- a/src/renderer/src/types/cherryStore.ts +++ b/src/renderer/src/types/cherryStore.ts @@ -1,6 +1,6 @@ export enum CherryStoreType { - ASSISTANT = 'Assistant', - MINI_APP = 'Mini-App' + ASSISTANT = 'assistant', + MINI_APP = 'mini-app' // KNOWLEDGE = 'Knowledge', // MCP_SERVER = 'MCP-Server', // MODEL_PROVIDER = 'Model-Provider',