|
@@ -1,6 +1,7 @@
|
|
|
-import React from 'react';
|
|
|
-import { Menu, Button } from 'antd';
|
|
|
+import React, { useState, useRef } from 'react';
|
|
|
+import { Menu, Button, Drawer } from 'antd';
|
|
|
import {
|
|
|
+ MenuUnfoldOutlined,
|
|
|
UserOutlined,
|
|
|
FileSearchOutlined,
|
|
|
AlertOutlined,
|
|
@@ -18,14 +19,43 @@ const NavbarFloat: React.FC<NavbarFloatProps> = ({
|
|
|
position = 'left',
|
|
|
className,
|
|
|
}) => {
|
|
|
- const style: React.CSSProperties = {
|
|
|
- position: 'fixed',
|
|
|
- top: '50%',
|
|
|
- transform: 'translateY(-50%)',
|
|
|
- [position]: 0,
|
|
|
- backgroundColor: '#fff',
|
|
|
- boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
|
|
|
- borderRadius: position === 'left' ? '0 4px 4px 0' : '4px 0 0 4px',
|
|
|
+ const [open, setOpen] = useState(false);
|
|
|
+ const [btnPos, setBtnPos] = useState({
|
|
|
+ x: window.innerWidth - 96,
|
|
|
+ y: window.innerHeight - 96,
|
|
|
+ });
|
|
|
+ const [dragged, setDragged] = useState(false);
|
|
|
+ const dragging = useRef(false);
|
|
|
+ const offset = useRef({ x: 0, y: 0 });
|
|
|
+
|
|
|
+ // 拖拽事件
|
|
|
+ const onMouseDown = (e: React.MouseEvent) => {
|
|
|
+ dragging.current = true;
|
|
|
+ setDragged(false);
|
|
|
+ offset.current = {
|
|
|
+ x: e.clientX - btnPos.x,
|
|
|
+ y: e.clientY - btnPos.y,
|
|
|
+ };
|
|
|
+ document.addEventListener('mousemove', onMouseMove);
|
|
|
+ document.addEventListener('mouseup', onMouseUp);
|
|
|
+ };
|
|
|
+
|
|
|
+ const onMouseMove = (e: MouseEvent) => {
|
|
|
+ if (!dragging.current) return;
|
|
|
+ let x = e.clientX - offset.current.x;
|
|
|
+ let y = e.clientY - offset.current.y;
|
|
|
+ // 限制在窗口内
|
|
|
+ x = Math.max(0, Math.min(window.innerWidth - 80, x));
|
|
|
+ y = Math.max(0, Math.min(window.innerHeight - 80, y));
|
|
|
+ setBtnPos({ x, y });
|
|
|
+ setDragged(true); // 标记为拖拽
|
|
|
+ };
|
|
|
+
|
|
|
+ const onMouseUp = () => {
|
|
|
+ dragging.current = false;
|
|
|
+ setTimeout(() => setDragged(false), 100); // 短暂延迟后重置
|
|
|
+ document.removeEventListener('mousemove', onMouseMove);
|
|
|
+ document.removeEventListener('mouseup', onMouseUp);
|
|
|
};
|
|
|
|
|
|
const menuItems = [
|
|
@@ -58,20 +88,70 @@ const NavbarFloat: React.FC<NavbarFloatProps> = ({
|
|
|
|
|
|
const handleClick: MenuProps['onClick'] = (e) => {
|
|
|
console.log('clicked ', e.key);
|
|
|
+ setOpen(false); // 点击菜单后自动关闭抽屉
|
|
|
};
|
|
|
|
|
|
+ const drawerPlacement = position === 'right' ? 'right' : 'left';
|
|
|
+
|
|
|
return (
|
|
|
- <div
|
|
|
- style={{ ...style, backgroundColor: 'transparent' }}
|
|
|
- className={className}
|
|
|
- >
|
|
|
- <Menu
|
|
|
- mode="vertical"
|
|
|
- onClick={handleClick}
|
|
|
- items={menuItems}
|
|
|
- style={{ border: 'none', backgroundColor: 'transparent' }}
|
|
|
- />
|
|
|
- </div>
|
|
|
+ <>
|
|
|
+ {!open && (
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ position: 'fixed',
|
|
|
+ left: btnPos.x,
|
|
|
+ top: btnPos.y,
|
|
|
+ zIndex: 1100,
|
|
|
+ cursor: 'grab',
|
|
|
+ }}
|
|
|
+ className={className}
|
|
|
+ onMouseDown={onMouseDown}
|
|
|
+ >
|
|
|
+ <Button
|
|
|
+ type="primary"
|
|
|
+ shape="circle"
|
|
|
+ size="large"
|
|
|
+ icon={<MenuUnfoldOutlined style={{ fontSize: 32 }} />}
|
|
|
+ onClick={(e) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ if (dragged) return; // 拖拽后不弹抽屉
|
|
|
+ setOpen(true);
|
|
|
+ }}
|
|
|
+ style={{
|
|
|
+ width: 64,
|
|
|
+ height: 64,
|
|
|
+ backgroundColor: '#fff',
|
|
|
+ color: '#333',
|
|
|
+ boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ userSelect: 'none',
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ <Drawer
|
|
|
+ placement={drawerPlacement}
|
|
|
+ open={open}
|
|
|
+ onClose={() => setOpen(false)}
|
|
|
+ closable={false}
|
|
|
+ bodyStyle={{ padding: 0, background: 'transparent' }}
|
|
|
+ width={120}
|
|
|
+ maskClosable={true}
|
|
|
+ style={{
|
|
|
+ top: 0,
|
|
|
+ height: '100vh',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Menu
|
|
|
+ mode="vertical"
|
|
|
+ onClick={handleClick}
|
|
|
+ items={menuItems}
|
|
|
+ style={{ border: 'none', backgroundColor: 'transparent' }}
|
|
|
+ />
|
|
|
+ </Drawer>
|
|
|
+ </>
|
|
|
);
|
|
|
};
|
|
|
|