diff --git a/src/lib/ae_journals/ae_journals_editor_helpers.ts b/src/lib/ae_journals/ae_journals_editor_helpers.ts
new file mode 100644
index 00000000..1766af26
--- /dev/null
+++ b/src/lib/ae_journals/ae_journals_editor_helpers.ts
@@ -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();
+}
diff --git a/src/lib/app_components/e_app_codemirror_v5.svelte b/src/lib/app_components/e_app_codemirror_v5.svelte
index 0589a724..0582b42c 100644
--- a/src/lib/app_components/e_app_codemirror_v5.svelte
+++ b/src/lib/app_components/e_app_codemirror_v5.svelte
@@ -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,
diff --git a/src/routes/journals/+layout.svelte b/src/routes/journals/+layout.svelte
index ac19ee23..9b905942 100644
--- a/src/routes/journals/+layout.svelte
+++ b/src/routes/journals/+layout.svelte
@@ -7,7 +7,7 @@
import { goto } from '$app/navigation';
// *** Import other supporting libraries
- import { House, RefreshCw, Satellite } from '@lucide/svelte';
+ import { ArrowDownUp, House, RefreshCw, Satellite } from '@lucide/svelte';
// *** Import Aether specific variables and functions
import { ae_loc, ae_sess, ae_api, slct } from '$lib/stores/ae_stores';
@@ -271,10 +271,6 @@
`Scroll to top button clicked. yScroll: ${yScroll} scrollTop: ${scroll_container().scrollTop}`,
scroll_container()
);
- // document.getElementById('ae_idaa')?.scrollTo(0, 0);
- // document.documentElement?.scrollTo(0, 0);
- // document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
- // document.body.scrollTop = 0; // For Safari
}
});
@@ -284,11 +280,11 @@
behavior: 'smooth'
});
- window.parent.postMessage({ scroll_to: 0 }, '*'); // This should be
+ window.parent.postMessage({ scroll_to: 0 }, '*');
}}
title="Scroll to top"
>
-
+