Jake Shore 96e52666c5 MCPEngine full sync — studio scaffold, factory v2, server updates, state.json — 2026-02-12
=== NEW ===
- studio/ — MCPEngine Studio scaffold (Next.js monorepo, build plan)
- docs/FACTORY-V2.md — Factory v2 architecture doc
- docs/CALENDLY_MCP_BUILD_SUMMARY.md — Calendly MCP build report

=== UPDATED SERVERS ===
- fieldedge: Added jobs-tools, UI build script, main entry update
- lightspeed: Updated main + server entry points
- squarespace: Added collection-browser + page-manager apps
- toast: Added main + server entry points

=== INFRA ===
- infra/command-center/state.json — Updated pipeline state
- infra/command-center/FACTORY-V2.md — Factory v2 operator playbook
2026-02-12 17:58:33 -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>
);
}