Refactor Journals UI and enhance CodeMirror editor
- Added formatting toolbar to journal entry editor with support for bold, italic, headers, and lists. - Standardized iconography to Lucide across Journals module, removing legacy FontAwesome. - Improved responsiveness and dark mode compatibility in layout and list views. - Refactored CodeMirror component to support external control via editorView binding. - Hardened security by removing unnecessary @html tags in journal names.
This commit is contained in:
60
src/lib/ae_journals/ae_journals_editor_helpers.ts
Normal file
60
src/lib/ae_journals/ae_journals_editor_helpers.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { EditorView } from '@codemirror/view';
|
||||
|
||||
/**
|
||||
* Wraps the current selection in CodeMirror with the given prefix and suffix.
|
||||
*/
|
||||
export function wrapSelection(view: EditorView, prefix: string, suffix: string = prefix) {
|
||||
if (!view) return;
|
||||
const { state, dispatch } = view;
|
||||
const changes = state.changeByRange((range) => {
|
||||
const selectedText = state.doc.sliceString(range.from, range.to);
|
||||
return {
|
||||
changes: [
|
||||
{ from: range.from, insert: prefix },
|
||||
{ from: range.to, insert: suffix }
|
||||
],
|
||||
range: {
|
||||
from: range.from + prefix.length,
|
||||
to: range.to + prefix.length
|
||||
}
|
||||
};
|
||||
});
|
||||
dispatch(state.update(changes, { scrollIntoView: true, userEvent: 'input' }));
|
||||
view.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a prefix at the start of each line in the selection (e.g., for lists or blockquotes).
|
||||
*/
|
||||
export function toggleLinePrefix(view: EditorView, prefix: string) {
|
||||
if (!view) return;
|
||||
const { state, dispatch } = view;
|
||||
const changes = state.changeByRange((range) => {
|
||||
const lines = [];
|
||||
for (let pos = range.from; pos <= range.to; ) {
|
||||
const line = state.doc.lineAt(pos);
|
||||
lines.push(line);
|
||||
pos = line.to + 1;
|
||||
}
|
||||
|
||||
const isAlreadyPrefixed = lines.every(l => l.text.startsWith(prefix));
|
||||
|
||||
const lineChanges = lines.map(l => {
|
||||
if (isAlreadyPrefixed) {
|
||||
return { from: l.from, to: l.from + prefix.length, insert: '' };
|
||||
} else {
|
||||
return { from: l.from, insert: prefix };
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
changes: lineChanges,
|
||||
range: {
|
||||
from: range.from + (isAlreadyPrefixed ? -prefix.length : prefix.length),
|
||||
to: range.to + (isAlreadyPrefixed ? -prefix.length * lines.length : prefix.length * lines.length)
|
||||
}
|
||||
};
|
||||
});
|
||||
dispatch(state.update(changes, { scrollIntoView: true, userEvent: 'input' }));
|
||||
view.focus();
|
||||
}
|
||||
@@ -29,6 +29,7 @@
|
||||
let {
|
||||
content = 'test test test test',
|
||||
new_content = $bindable(''),
|
||||
editorView = $bindable(), // Exposed for external control
|
||||
theme_mode = 'light',
|
||||
extensions = [],
|
||||
editable = true,
|
||||
|
||||
Reference in New Issue
Block a user