import { getChunks } from '@codemirror/merge'; import { EditorView, showPanel } from '@codemirror/view'; import type { CodeEditorFile } from '../types/types'; type EditorToolbarLabels = { changes: string; previousChange: string; nextChange: string; hideDiff: string; showDiff: string; collapse: string; expand: string; }; type CreateEditorToolbarPanelParams = { file: CodeEditorFile; showDiff: boolean; isSidebar: boolean; isExpanded: boolean; onToggleDiff: () => void; onPopOut: (() => void) | null; onToggleExpand: (() => void) | null; labels: EditorToolbarLabels; }; const getDiffVisibilityIcon = (showDiff: boolean) => { if (showDiff) { return ''; } return ''; }; const getExpandIcon = (isExpanded: boolean) => { if (isExpanded) { return ''; } return ''; }; export const createEditorToolbarPanelExtension = ({ file, showDiff, isSidebar, isExpanded, onToggleDiff, onPopOut, onToggleExpand, labels, }: CreateEditorToolbarPanelParams) => { const hasToolbarButtons = Boolean(file.diffInfo || (isSidebar && onPopOut) || (isSidebar && onToggleExpand)); if (!hasToolbarButtons) { return []; } const createPanel = (view: EditorView) => { const dom = document.createElement('div'); dom.className = 'cm-editor-toolbar-panel'; let currentIndex = 0; const updatePanel = () => { const hasDiff = Boolean(file.diffInfo && showDiff); const chunksData = hasDiff ? getChunks(view.state) : null; const chunks = chunksData?.chunks || []; const chunkCount = chunks.length; let toolbarHtml = '
'; toolbarHtml += '
'; if (hasDiff) { toolbarHtml += ` ${chunkCount > 0 ? `${currentIndex + 1}/${chunkCount}` : '0'} ${labels.changes} `; } toolbarHtml += '
'; toolbarHtml += '
'; if (file.diffInfo) { toolbarHtml += ` `; } if (isSidebar && onPopOut) { toolbarHtml += ` `; } if (isSidebar && onToggleExpand) { toolbarHtml += ` `; } toolbarHtml += '
'; toolbarHtml += '
'; dom.innerHTML = toolbarHtml; if (hasDiff) { const previousButton = dom.querySelector('.cm-diff-nav-prev'); const nextButton = dom.querySelector('.cm-diff-nav-next'); previousButton?.addEventListener('click', () => { if (chunks.length === 0) { return; } currentIndex = currentIndex > 0 ? currentIndex - 1 : chunks.length - 1; const chunk = chunks[currentIndex]; if (chunk) { view.dispatch({ effects: EditorView.scrollIntoView(chunk.fromB, { y: 'center' }), }); } updatePanel(); }); nextButton?.addEventListener('click', () => { if (chunks.length === 0) { return; } currentIndex = currentIndex < chunks.length - 1 ? currentIndex + 1 : 0; const chunk = chunks[currentIndex]; if (chunk) { view.dispatch({ effects: EditorView.scrollIntoView(chunk.fromB, { y: 'center' }), }); } updatePanel(); }); } const toggleDiffButton = dom.querySelector('.cm-toggle-diff-btn'); toggleDiffButton?.addEventListener('click', onToggleDiff); const popOutButton = dom.querySelector('.cm-popout-btn'); popOutButton?.addEventListener('click', () => { onPopOut?.(); }); const expandButton = dom.querySelector('.cm-expand-btn'); expandButton?.addEventListener('click', () => { onToggleExpand?.(); }); }; updatePanel(); return { top: true, dom, update: updatePanel, }; }; return [showPanel.of(createPanel)]; };