2026-02-06 23:01:30 -05:00

98 lines
2.9 KiB
TypeScript

'use client';
import React, { useCallback, useState } from 'react';
import { useReactFlow } from '@xyflow/react';
import {
ZoomIn,
ZoomOut,
Maximize2,
Map,
LayoutGrid,
} from 'lucide-react';
interface ToolbarButtonProps {
icon: React.ReactNode;
label: string;
onClick: () => void;
active?: boolean;
}
function ToolbarButton({ icon, label, onClick, active }: ToolbarButtonProps) {
return (
<button
onClick={onClick}
title={label}
className={`
flex items-center justify-center w-8 h-8 rounded-full
transition-colors duration-150
${active
? 'bg-indigo-500/20 text-indigo-400'
: 'text-gray-400 hover:text-gray-200 hover:bg-gray-700/60'
}
`}
>
{icon}
</button>
);
}
export function CanvasToolbar() {
const { zoomIn, zoomOut, fitView } = useReactFlow();
const [minimapVisible, setMinimapVisible] = useState(true);
const handleZoomIn = useCallback(() => zoomIn({ duration: 200 }), [zoomIn]);
const handleZoomOut = useCallback(() => zoomOut({ duration: 200 }), [zoomOut]);
const handleFitView = useCallback(() => fitView({ duration: 300, padding: 0.2 }), [fitView]);
const handleToggleMinimap = useCallback(() => {
setMinimapVisible((prev) => !prev);
// Toggle minimap visibility via CSS since ReactFlow MiniMap doesn't have a built-in toggle
const minimap = document.querySelector('.react-flow__minimap') as HTMLElement;
if (minimap) {
minimap.style.display = minimapVisible ? 'none' : 'block';
}
}, [minimapVisible]);
const handleAutoLayout = useCallback(() => {
// Auto-layout: redistribute nodes in a grid pattern
// This dispatches to the store which handles repositioning
const event = new CustomEvent('canvas:auto-layout');
window.dispatchEvent(event);
}, []);
return (
<div className="absolute bottom-6 left-1/2 -translate-x-1/2 z-50">
<div className="flex items-center gap-1 bg-gray-800 border border-gray-700 rounded-full px-2 py-1 shadow-lg">
<ToolbarButton
icon={<ZoomIn className="w-4 h-4" />}
label="Zoom In"
onClick={handleZoomIn}
/>
<ToolbarButton
icon={<ZoomOut className="w-4 h-4" />}
label="Zoom Out"
onClick={handleZoomOut}
/>
<div className="w-px h-5 bg-gray-700 mx-0.5" />
<ToolbarButton
icon={<Maximize2 className="w-4 h-4" />}
label="Fit View"
onClick={handleFitView}
/>
<ToolbarButton
icon={<Map className="w-4 h-4" />}
label="Toggle MiniMap"
onClick={handleToggleMinimap}
active={minimapVisible}
/>
<div className="w-px h-5 bg-gray-700 mx-0.5" />
<ToolbarButton
icon={<LayoutGrid className="w-4 h-4" />}
label="Auto Layout"
onClick={handleAutoLayout}
/>
</div>
</div>
);
}