/** * Toolbar with Save, Undo, Redo buttons. */ import React from 'react'; import { redo, undo } from '@codemirror/commands'; import { useAppTranslation } from '@features/localization/renderer'; import { Button } from '@renderer/components/ui/button'; import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip'; import { useStore } from '@renderer/store'; import { editorBridge } from '@renderer/utils/editorBridge'; import { shortcutLabel } from '@renderer/utils/platformKeys'; import { Columns2, Eye, Redo2, Save, Undo2, WrapText } from 'lucide-react'; import { useShallow } from 'zustand/react/shallow'; // ============================================================================= // Types // ============================================================================= export type MdPreviewMode = 'off' | 'split' | 'preview'; // ============================================================================= // Component // ============================================================================= interface EditorToolbarProps { isMarkdown?: boolean; mdPreviewMode?: MdPreviewMode; onToggleSplit?: () => void; onToggleFullPreview?: () => void; } export const EditorToolbar = ({ isMarkdown = false, mdPreviewMode = 'off', onToggleSplit, onToggleFullPreview, }: EditorToolbarProps): React.ReactElement | null => { const { t } = useAppTranslation('team'); const { activeTabId, modifiedFiles, saving, lineWrap } = useStore( useShallow((s) => ({ activeTabId: s.editorActiveTabId, modifiedFiles: s.editorModifiedFiles, saving: s.editorSaving, lineWrap: s.editorLineWrap, })) ); const saveFile = useStore((s) => s.saveFile); const toggleLineWrap = useStore((s) => s.toggleLineWrap); if (!activeTabId) return null; const isDirty = !!modifiedFiles[activeTabId]; const isSaving = !!saving[activeTabId]; const handleSave = () => { void saveFile(activeTabId); }; const handleUndo = () => { const view = editorBridge.getView(); if (view) undo(view); }; const handleRedo = () => { const view = editorBridge.getView(); if (view) redo(view); }; return (
} label={t('editor.shortcuts.actions.save')} shortcut={shortcutLabel('⌘ S', 'Ctrl+S')} onClick={handleSave} disabled={!isDirty || isSaving} /> } label={t('editor.shortcuts.actions.undo')} shortcut={shortcutLabel('⌘ Z', 'Ctrl+Z')} onClick={handleUndo} /> } label={t('editor.shortcuts.actions.redo')} shortcut={shortcutLabel('⌘ ⇧ Z', 'Ctrl+Y')} onClick={handleRedo} />
} label={lineWrap ? t('editor.toolbar.disableWordWrap') : t('editor.toolbar.enableWordWrap')} shortcut={shortcutLabel('⌘ ⇧ W', 'Ctrl+Shift+W')} onClick={toggleLineWrap} active={lineWrap} /> {isMarkdown && ( <>
} label={ mdPreviewMode === 'split' ? t('editor.toolbar.closeSplitPreview') : t('editor.shortcuts.actions.splitPreview') } shortcut={shortcutLabel('⌘ ⇧ M', 'Ctrl+Shift+M')} onClick={onToggleSplit ?? (() => {})} active={mdPreviewMode === 'split'} /> } label={ mdPreviewMode === 'preview' ? t('editor.toolbar.closePreview') : t('editor.shortcuts.actions.fullPreview') } shortcut={shortcutLabel('⌘ ⇧ V', 'Ctrl+Shift+V')} onClick={onToggleFullPreview ?? (() => {})} active={mdPreviewMode === 'preview'} /> )}
); }; // ============================================================================= // Toolbar button // ============================================================================= interface ToolbarButtonProps { icon: React.ReactNode; label: string; shortcut: string; onClick: () => void; disabled?: boolean; active?: boolean; } const ToolbarButton = React.memo(function ToolbarButton({ icon, label, shortcut, onClick, disabled = false, active = false, }: ToolbarButtonProps): React.ReactElement { return ( {label} ({shortcut}) ); });