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)];
};