Files
if.u.clients.web/src/components/SiderMenu.tsx

134 lines
4.1 KiB
TypeScript

import React from 'react';
import { Layout, Menu, Grid, Drawer, Button } from 'antd';
import { HeartOutlined, FormOutlined, UnorderedListOutlined, MenuOutlined } from '@ant-design/icons';
import './SiderMenu.css';
const { Sider } = Layout;
// 新增:支持外部导航回调 + 受控选中态
type Props = {
onNavigate?: (key: string) => void;
selectedKey?: string;
mobileOpen?: boolean; // 外部控制移动端抽屉开关
onMobileToggle?: (open: boolean) => void; // 顶栏触发开关
};
const SiderMenu: React.FC<Props> = ({ onNavigate, selectedKey, mobileOpen, onMobileToggle }) => {
const screens = Grid.useBreakpoint();
const isMobile = !screens.md;
const [collapsed, setCollapsed] = React.useState(false);
const [selectedKeys, setSelectedKeys] = React.useState<string[]>(['home']);
const [internalMobileOpen, setInternalMobileOpen] = React.useState(false);
const [topbarHeight, setTopbarHeight] = React.useState<number>(56);
React.useEffect(() => {
const update = () => {
const el = document.querySelector('.topbar') as HTMLElement | null;
const h = el?.clientHeight || 56;
setTopbarHeight(h);
};
update();
window.addEventListener('resize', update);
return () => window.removeEventListener('resize', update);
}, []);
React.useEffect(() => {
setCollapsed(isMobile);
}, [isMobile]);
// 根据外部 selectedKey 同步选中态
React.useEffect(() => {
if (selectedKey) {
setSelectedKeys([selectedKey]);
}
}, [selectedKey]);
const items = [
{ key: 'home', label: '注册', icon: <FormOutlined /> },
{ key: 'menu1', label: '列表', icon: <UnorderedListOutlined /> },
];
// 移动端:使用 Drawer 覆盖主内容
if (isMobile) {
const open = mobileOpen ?? internalMobileOpen;
const setOpen = (v: boolean) => (onMobileToggle ? onMobileToggle(v) : setInternalMobileOpen(v));
const showInternalTrigger = !onMobileToggle; // 若无外部控制,则显示内部按钮
return (
<>
{showInternalTrigger && (
<Button
className="mobile-menu-trigger"
type="default"
icon={<MenuOutlined />}
onClick={() => setInternalMobileOpen((o) => !o)}
/>
)}
<Drawer
className="mobile-menu-drawer"
placement="left"
width="100%"
open={open}
onClose={() => setOpen(false)}
rootStyle={{ top: topbarHeight, height: `calc(100% - ${topbarHeight}px)` }}
styles={{ body: { padding: 0 }, header: { display: 'none' } }}
>
<div className="sider-header">
<HeartOutlined style={{ fontSize: 22 }} />
<div>
<div className="sider-title"></div>
<div className="sider-desc"></div>
</div>
</div>
<Menu
theme="dark"
mode="inline"
selectedKeys={selectedKeys}
onClick={({ key }) => {
const k = String(key);
setSelectedKeys([k]);
setOpen(false); // 选择后自动收起
onNavigate?.(k);
}}
items={items}
/>
</Drawer>
</>
);
}
// PC 端:保持 Sider 行为不变
return (
<Sider
width={260}
collapsible
collapsed={collapsed}
onCollapse={(c) => setCollapsed(c)}
breakpoint="md"
collapsedWidth={64}
theme="dark"
>
<div className={`sider-header ${collapsed ? 'collapsed' : ''}`}>
<HeartOutlined style={{ fontSize: 22 }} />
{!collapsed && (
<div>
<div className="sider-title"></div>
<div className="sider-desc"></div>
</div>
)}
</div>
<Menu
theme="dark"
mode="inline"
selectedKeys={selectedKeys}
onClick={({ key }) => {
const k = String(key);
setSelectedKeys([k]);
onNavigate?.(k);
}}
items={items}
/>
</Sider>
);
};
export default SiderMenu;