diff --git a/AGENTS.md b/AGENTS.md index 045a950..f581bc6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,8 +25,12 @@ src/ index.tsx # App entry point — mounts React root to #root App.tsx # Root component — renders App.css # Root component styles - router.tsx # Route config (createBrowserRouter) + router.tsx # createBrowserRouter,由 routes 树自动生成 env.d.ts # Rsbuild environment type declarations + routes/ + types.ts # RouteItem 类型定义 + index.tsx # 路由树数据(唯一数据源),导出 routes / RouteItem + utils.tsx # toRouteObjects():将路由树转为 React Router RouteObject[] layouts/ RootLayout.tsx # Root layout with nav links and pages/ @@ -44,9 +48,11 @@ tsconfig.json Uses **React Router v7** (`react-router`) with `createBrowserRouter`. -- Route config lives in `src/router.tsx` -- `RootLayout` wraps all routes — add shared nav/header/footer there -- Add new pages under `src/pages/`, register them in `src/router.tsx` +- **唯一数据源**:`src/routes/index.tsx` 维护 `routes: RouteItem[]` 路由树 +- `RouteItem` 字段:`path` / `label` / `icon?` / `component?` / `hideInMenu?` / `redirect?` / `children?` +- `toRouteObjects(routes)` 将路由树转换为 React Router 所需的 `RouteObject[]` +- 菜单、面包屑等模块直接消费 `routes` 数组,无需重复维护路由信息 +- 添加新页面:在 `src/pages/` 创建组件,在 `src/routes/index.tsx` 追加节点即可 ## TypeScript Configuration diff --git a/src/router.tsx b/src/router.tsx index 4341379..1026a0c 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -1,18 +1,13 @@ import { createBrowserRouter } from 'react-router'; import RootLayout from './layouts/RootLayout'; -import About from './pages/About'; -import Home from './pages/Home'; -import NotFound from './pages/NotFound'; +import { routes } from './routes'; +import { toRouteObjects } from './routes/utils'; const router = createBrowserRouter([ { path: '/', element: , - children: [ - { index: true, element: }, - { path: 'about', element: }, - { path: '*', element: }, - ], + children: toRouteObjects(routes), }, ]); diff --git a/src/routes/index.tsx b/src/routes/index.tsx new file mode 100644 index 0000000..166c40b --- /dev/null +++ b/src/routes/index.tsx @@ -0,0 +1,25 @@ +import About from '../pages/About'; +import Home from '../pages/Home'; +import NotFound from '../pages/NotFound'; +import type { RouteItem } from './types'; + +export const routes: RouteItem[] = [ + { + path: '/', + label: '首页', + component: , + }, + { + path: '/about', + label: '关于', + component: , + }, + { + path: '*', + label: '404', + component: , + hideInMenu: true, + }, +]; + +export type { RouteItem }; diff --git a/src/routes/types.ts b/src/routes/types.ts new file mode 100644 index 0000000..7874359 --- /dev/null +++ b/src/routes/types.ts @@ -0,0 +1,18 @@ +import type { ReactNode } from 'react'; + +export interface RouteItem { + /** 路由路径,index 路由使用 '/' */ + path: string; + /** 菜单/面包屑显示名称 */ + label: string; + /** 菜单图标 */ + icon?: ReactNode; + /** 页面组件,叶子节点必填(有 redirect 时忽略) */ + component?: ReactNode; + /** 是否在菜单中隐藏,默认 false */ + hideInMenu?: boolean; + /** 重定向目标路径,设置后忽略 component */ + redirect?: string; + /** 子路由 */ + children?: RouteItem[]; +} diff --git a/src/routes/utils.tsx b/src/routes/utils.tsx new file mode 100644 index 0000000..c057110 --- /dev/null +++ b/src/routes/utils.tsx @@ -0,0 +1,23 @@ +import { Navigate } from 'react-router'; +import type { RouteObject } from 'react-router'; +import type { RouteItem } from './types'; + +export function toRouteObjects(items: RouteItem[]): RouteObject[] { + return items.map((item) => { + if (item.redirect) { + return { path: item.path, element: }; + } + + const route: RouteObject = { + path: item.path === '/' ? undefined : item.path, + index: item.path === '/' ? true : undefined, + element: item.component, + }; + + if (item.children) { + route.children = toRouteObjects(item.children); + } + + return route; + }); +}