f0eed0ca3f
Deploy / Build Production Runtime Images (push) Has been skipped
Deploy / Deploy Production (push) Has been skipped
Deploy / Production Browser E2E (push) Has been skipped
Deploy / Deploy Staging (push) Failing after 192h26m58s
CI/CD Pipeline / Frontend Lint (push) Failing after 192h27m37s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 192h27m46s
70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
/**
|
||
* Sidebar - 侧边栏导航组件(Task 1.3)
|
||
*
|
||
* 功能:
|
||
* - 分组导航菜单(创作工具 / 资源管理 / 系统)
|
||
* - 每个菜单项:图标 + 文字
|
||
* - 当前页面对应菜单项高亮(基于路由匹配)
|
||
* - 点击跳转路由
|
||
* - 折叠态:仅显示图标,隐藏文字(通过 SidebarContext 读取 collapsed 状态)
|
||
* - 响应式:移动端自动折叠
|
||
*/
|
||
import React, { useContext } from "react";
|
||
import { useLocation, useNavigate } from "react-router-dom";
|
||
import { SidebarContext } from "./MainLayout";
|
||
import { NAV_GROUPS } from "@/config/navigation";
|
||
import "./Sidebar.css";
|
||
|
||
/** 判断菜单项是否激活 */
|
||
const isMenuItemActive = (pathname: string, path: string): boolean => {
|
||
if (path === "/dashboard") {
|
||
return pathname === "/" || pathname === "/dashboard";
|
||
}
|
||
return pathname.startsWith(path);
|
||
};
|
||
|
||
const Sidebar: React.FC = () => {
|
||
const { collapsed } = useContext(SidebarContext);
|
||
const location = useLocation();
|
||
const navigate = useNavigate();
|
||
|
||
const handleNavigate = (path: string) => {
|
||
navigate(path);
|
||
};
|
||
|
||
return (
|
||
<div
|
||
className={`xx-sidebar-nav${collapsed ? " xx-sidebar-nav--collapsed" : ""}`}
|
||
>
|
||
{NAV_GROUPS.map((group) => (
|
||
<div className="xx-sidebar-group" key={group.title}>
|
||
{!collapsed && (
|
||
<div className="xx-sidebar-group-title">{group.title}</div>
|
||
)}
|
||
<ul className="xx-sidebar-menu" role="menu">
|
||
{group.items.map((item) => {
|
||
const active = isMenuItemActive(location.pathname, item.path);
|
||
return (
|
||
<li
|
||
key={item.key}
|
||
className={`xx-sidebar-menu-item${active ? " xx-active" : ""}`}
|
||
role="menuitem"
|
||
title={collapsed ? item.label : undefined}
|
||
onClick={() => handleNavigate(item.path)}
|
||
>
|
||
<span className="xx-sidebar-menu-icon">{item.icon}</span>
|
||
{!collapsed && (
|
||
<span className="xx-sidebar-menu-label">{item.label}</span>
|
||
)}
|
||
</li>
|
||
);
|
||
})}
|
||
</ul>
|
||
</div>
|
||
))}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default Sidebar;
|