Files
mnote/wolai-frontend/src/components/editor/blocks/MindmapNavigator.tsx
T

130 lines
3.8 KiB
TypeScript
Raw Normal View History

/* 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>
);
};