/** * Formatting toolbar for the editor. * Inserts/toggles markdown-like syntax in the CodeMirror editor. */ import type { EditorView } from '@codemirror/view' import '../styles/format-toolbar.css' interface FormatToolbarProps { editorView: EditorView | null previewMode: boolean onPreviewToggle: () => void } function insertPrefix(view: EditorView, prefix: string) { const { state } = view const line = state.doc.lineAt(state.selection.main.head) const lineText = line.text if (lineText.startsWith(prefix)) { // Remove prefix view.dispatch({ changes: { from: line.from, to: line.from + prefix.length, insert: '' }, }) } else { // Add prefix view.dispatch({ changes: { from: line.from, insert: prefix }, }) } view.focus() } function wrapSelection(view: EditorView, wrapper: string) { const { state } = view const sel = state.selection.main const selected = state.sliceDoc(sel.from, sel.to) if (selected.length === 0) { // No selection — insert wrapper pair and place cursor inside const text = `${wrapper}text${wrapper}` view.dispatch({ changes: { from: sel.from, insert: text }, selection: { anchor: sel.from + wrapper.length, head: sel.from + wrapper.length + 4 }, }) } else if (selected.startsWith(wrapper) && selected.endsWith(wrapper)) { // Already wrapped — unwrap const inner = selected.slice(wrapper.length, -wrapper.length) view.dispatch({ changes: { from: sel.from, to: sel.to, insert: inner }, selection: { anchor: sel.from, head: sel.from + inner.length }, }) } else { // Wrap selection const text = `${wrapper}${selected}${wrapper}` view.dispatch({ changes: { from: sel.from, to: sel.to, insert: text }, selection: { anchor: sel.from, head: sel.from + text.length }, }) } view.focus() } function insertColor(view: EditorView, color: string) { const { state } = view const sel = state.selection.main const selected = state.sliceDoc(sel.from, sel.to) const label = selected.length > 0 ? selected : 'label' const text = `[${color}:${label}]` view.dispatch({ changes: { from: sel.from, to: sel.to, insert: text }, selection: { anchor: sel.from, head: sel.from + text.length }, }) view.focus() } const COLORS = [ { name: 'Red', value: '#ef4444' }, { name: 'Orange', value: '#f97316' }, { name: 'Yellow', value: '#eab308' }, { name: 'Green', value: '#22c55e' }, { name: 'Blue', value: '#3b82f6' }, { name: 'Purple', value: '#a855f7' }, ] export function FormatToolbar({ editorView, previewMode, onPreviewToggle }: FormatToolbarProps) { return (
{COLORS.map(c => (
) }