import { useState, useCallback, useRef, useEffect } from 'react' import { useNavigate } from 'react-router-dom' import { ChevronLeft, Save, Download, FileJson, FileCode, Image, FileText, Undo2, Redo2, MousePointer2, Hand, FileOutput, Upload, Cable } from 'lucide-react' import { cn } from '@/lib/utils' export type InteractionMode = 'select' | 'pan' | 'connect' interface DiagramHeaderProps { name: string clientName: string | null isDirty: boolean isSaving: boolean lastSavedAt: Date | null diagramId: string | null onNameChange: (name: string) => void onSave: () => void onExportPng: () => void onExportSvg: () => void onExportPdf: () => void onExportJson: () => void onExportDrawio: () => void onImportDrawio: () => void // draw.io import — triggered from Export menu onUndo: () => void onRedo: () => void canUndo: boolean canRedo: boolean interactionMode: InteractionMode onModeChange: (mode: InteractionMode) => void } export function DiagramHeader({ name, clientName, isDirty, isSaving, lastSavedAt, diagramId, onNameChange, onSave, onExportPng, onExportSvg, onExportPdf, onExportJson, onExportDrawio, onImportDrawio, onUndo, onRedo, canUndo, canRedo, interactionMode, onModeChange, }: DiagramHeaderProps) { const navigate = useNavigate() const [editing, setEditing] = useState(false) const [editValue, setEditValue] = useState(name) const [showExportMenu, setShowExportMenu] = useState(false) const inputRef = useRef(null) const exportMenuRef = useRef(null) useEffect(() => { if (editing && inputRef.current) { inputRef.current.focus() inputRef.current.select() } }, [editing]) useEffect(() => { setEditValue(name) }, [name]) useEffect(() => { if (!showExportMenu) return const handleClick = (e: MouseEvent) => { if (exportMenuRef.current && !exportMenuRef.current.contains(e.target as HTMLElement)) { setShowExportMenu(false) } } document.addEventListener('mousedown', handleClick) return () => document.removeEventListener('mousedown', handleClick) }, [showExportMenu]) const handleConfirmName = useCallback(() => { setEditing(false) if (editValue.trim() && editValue !== name) { onNameChange(editValue.trim()) } else { setEditValue(name) } }, [editValue, name, onNameChange]) const formatLastSaved = () => { if (!lastSavedAt) return null // eslint-disable-next-line react-hooks/purity const diff = Date.now() - lastSavedAt.getTime() if (diff < 60_000) return 'Saved just now' const mins = Math.floor(diff / 60_000) return `Saved ${mins}m ago` } return (
{/* Interaction mode toggle */}
{editing ? ( setEditValue(e.target.value)} onBlur={handleConfirmName} onKeyDown={e => { if (e.key === 'Enter') handleConfirmName(); if (e.key === 'Escape') { setEditing(false); setEditValue(name) } }} className="rounded border border-accent bg-input px-2 py-1 text-sm font-heading font-semibold text-heading focus:outline-none" /> ) : ( )} {clientName && ( {clientName} )}
{isDirty && !isSaving ? ( Unsaved changes ) : lastSavedAt ? ( {formatLastSaved()} ) : null}
{showExportMenu && (
Export as
{diagramId && ( )}
Import
)}
) }