import { Pin, Paintbrush2, Droplet, Settings, Save, Upload, Minus, Square, X, MousePointer2, Globe, FolderOpen, ChevronDown, ImageDown, LogOut, FilePlus, GripVertical, FileArchive } from 'lucide-react'; import { useAppStore } from '../store'; import { useRef, useState } from 'react'; import { invoke } from '@tauri-apps/api/core'; import { getCurrentWindow } from '@tauri-apps/api/window'; const appWindow = getCurrentWindow(); function showToast(msg: string) { window.dispatchEvent(new CustomEvent('muse:toast', { detail: msg })); } export const Toolbar = () => { const { images, textNotes, annotations, palettes, zoom, setZoom, pan, setPan, globalDesaturate, setGlobalDesaturate, isAlwaysOnTop, setIsAlwaysOnTop, bgOpacity, setBgOpacity, isClickThrough, setIsClickThrough, isAnnotationMode, setIsAnnotationMode, isSettingsOpen, setIsSettingsOpen, setTextNotes, setImages, setAnnotations, setPalettes, isBrowserOpen, setIsBrowserOpen, isLibraryOpen, setIsLibraryOpen, currentScreen, setCurrentScreen, activeProjectId, setActiveProjectId, boardTitle, setBoardTitle } = useAppStore(); const [isBoardMenuOpen, setIsBoardMenuOpen] = useState(false); const fileInputRef = useRef(null); const handleExportFile = () => { const filename = `${(boardTitle || 'board').replace(/[^a-zA-Z0-9 ]/g, '').trim().replace(/\s+/g, '-').toLowerCase() || 'board'}.json`; const state = JSON.stringify({ textNotes, images, annotations, palettes, zoom, pan, title: boardTitle }, null, 2); const blob = new Blob([state], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); showToast(`✓ Exported "${filename}"`); }; const handleExportRefs = async () => { const filename = `${(boardTitle || 'board').replace(/[^a-zA-Z0-9 ]/g, '').trim().replace(/\s+/g, '-').toLowerCase() || 'board'}.refs`; const state = JSON.stringify({ textNotes, images, annotations, palettes, zoom, pan, title: boardTitle }); try { const bytes = await invoke('refs_export', { stateJson: state }); const blob = new Blob([new Uint8Array(bytes)], { type: 'application/octet-stream' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); showToast(`✓ Exported "${filename}" — portable archive with all images`); } catch (e) { showToast(`✗ Export failed: ${e}`); console.error('Export .refs failed:', e); } }; const handleQuickSave = () => { if (!activeProjectId) return; invoke('project_save', { id: activeProjectId, state: JSON.stringify({ textNotes, images, annotations, palettes, zoom, pan, title: boardTitle }), title: boardTitle }).then(() => showToast('✓ Saved')).catch(() => showToast('✗ Save failed')); }; const handleLoad = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = (ev) => { try { const d = JSON.parse(ev.target?.result as string); if (d.images) setImages(d.images); if (d.textNotes) setTextNotes(d.textNotes); if (d.annotations) setAnnotations(d.annotations); if (d.palettes) setPalettes(d.palettes); if (d.zoom) setZoom(d.zoom); if (d.pan) setPan(d.pan); if (d.title) setBoardTitle(d.title); showToast(`✓ Loaded "${file.name}"`); } catch { showToast('✗ Failed to parse file'); } }; reader.readAsText(file); e.target.value = ''; }; const handleCloseProject = () => { setIsBoardMenuOpen(false); handleQuickSave(); setCurrentScreen('hub'); }; const handleNewBoard = async () => { setIsBoardMenuOpen(false); handleQuickSave(); try { const entry = await invoke('project_create', { title: null }); setActiveProjectId(entry.id); setBoardTitle(entry.title); } catch {} setImages([]); setTextNotes([]); setAnnotations([]); setPalettes([]); setZoom(1); setPan({ x: 0, y: 0 }); }; const handleRename = (newTitle: string) => { const title = newTitle.trim() || 'Untitled Board'; setBoardTitle(title); if (activeProjectId) invoke('project_rename', { id: activeProjectId, title }).catch(() => {}); }; return
handleRename(e.currentTarget.textContent || '')} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); (e.target as HTMLElement).blur(); } }}>{boardTitle}
{isBoardMenuOpen && <>
setIsBoardMenuOpen(false)} />
}
{Math.round(zoom * 100)}%
{isAlwaysOnTop && <>
{bgOpacity}% setBgOpacity(Number(e.target.value))} className="w-16 accent-[var(--accent)]" />
}
; };