feat(mindmap): 引入官方工具栏/侧栏并修复节点选择
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Minus, Plus, Maximize, Map, MapPin, Minimize, Eye, EyeOff } from "lucide-react";
|
||||
|
||||
type NavigatorProps = {
|
||||
mindmap: any;
|
||||
fullscreen: boolean;
|
||||
toggleFullscreen?: () => void; // Optional for now
|
||||
onToggleMiniMap?: () => void;
|
||||
miniMapOpen?: boolean;
|
||||
};
|
||||
|
||||
export const MindmapNavigator = ({
|
||||
mindmap,
|
||||
fullscreen,
|
||||
toggleFullscreen,
|
||||
onToggleMiniMap,
|
||||
miniMapOpen,
|
||||
}: NavigatorProps) => {
|
||||
const [scale, setScale] = useState(100);
|
||||
const [isReadonly, setIsReadonly] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!mindmap) return;
|
||||
|
||||
const handleScale = (s: number) => {
|
||||
setScale(Math.round(s * 100));
|
||||
};
|
||||
|
||||
mindmap.on("scale", handleScale);
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
setScale(Math.round(mindmap.view.scale * 100));
|
||||
|
||||
// Handle readonly state sync if needed
|
||||
// mindmap.on("mode_change", (mode) => setIsReadonly(mode === 'readonly'));
|
||||
|
||||
return () => {
|
||||
mindmap.off("scale", handleScale);
|
||||
};
|
||||
}, [mindmap]);
|
||||
|
||||
const handleZoomIn = () => mindmap?.view.enlarge();
|
||||
const handleZoomOut = () => mindmap?.view.narrow();
|
||||
const handleCenter = () => mindmap?.renderer.setRootNodeCenter();
|
||||
|
||||
const handleReadonly = () => {
|
||||
const newMode = !isReadonly;
|
||||
setIsReadonly(newMode);
|
||||
mindmap?.setMode(newMode ? 'readonly' : 'edit');
|
||||
};
|
||||
|
||||
const handleScaleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const val = parseInt(e.target.value);
|
||||
if (!isNaN(val) && val > 0) {
|
||||
setScale(val);
|
||||
const cx = mindmap.width / 2;
|
||||
const cy = mindmap.height / 2;
|
||||
mindmap.view.setScale(val / 100, cx, cy);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="absolute bottom-4 right-4 flex items-center gap-2 rounded-lg border border-gray-200 bg-white p-2 shadow-md text-gray-600">
|
||||
<button
|
||||
onClick={handleCenter}
|
||||
className="rounded p-1 hover:bg-gray-100"
|
||||
title="回到中心"
|
||||
>
|
||||
<MapPin className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<div className="mx-1 h-4 w-px bg-gray-200" />
|
||||
|
||||
<button
|
||||
onClick={onToggleMiniMap}
|
||||
className={`rounded p-1 hover:bg-gray-100 ${miniMapOpen ? "bg-blue-50 text-blue-600" : ""}`}
|
||||
title={miniMapOpen ? "关闭小地图" : "打开小地图"}
|
||||
>
|
||||
<Map className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleReadonly}
|
||||
className={`rounded p-1 hover:bg-gray-100 ${isReadonly ? "bg-blue-50 text-blue-600" : ""}`}
|
||||
title={isReadonly ? "切换编辑模式" : "切换只读模式"}
|
||||
>
|
||||
{isReadonly ? <Eye className="h-4 w-4" /> : <EyeOff className="h-4 w-4" />}
|
||||
</button>
|
||||
|
||||
{toggleFullscreen && (
|
||||
<button
|
||||
onClick={toggleFullscreen}
|
||||
className="rounded p-1 hover:bg-gray-100"
|
||||
title={fullscreen ? "退出全屏" : "全屏"}
|
||||
>
|
||||
{fullscreen ? <Minimize className="h-4 w-4" /> : <Maximize className="h-4 w-4" />}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="mx-1 h-4 w-px bg-gray-200" />
|
||||
|
||||
<button
|
||||
onClick={handleZoomOut}
|
||||
className="rounded p-1 hover:bg-gray-100"
|
||||
title="缩小"
|
||||
>
|
||||
<Minus className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<div className="flex items-center text-xs">
|
||||
<input
|
||||
type="number"
|
||||
value={scale}
|
||||
onChange={handleScaleInput}
|
||||
className="w-8 text-center bg-transparent outline-none appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
||||
/>
|
||||
<span>%</span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleZoomIn}
|
||||
className="rounded p-1 hover:bg-gray-100"
|
||||
title="放大"
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user