From dd0390a5dd3d237a92e73346681000bcc59dcc96 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Thu, 8 Jan 2026 15:38:28 -0500 Subject: [PATCH] Refine Journals UI and harden entry toggle logic - Implemented 3-state (View/Eye/Save) toggle in journal entry header with Lucide icons. - Hardened change detection logic using Svelte 5 .by for reliable UI updates. - Improved header responsiveness and scaling across device sizes. - Commented out experimental CodeMirror toolbar to maintain stability while keeping the helper code for reference. --- .../ae_journals/ae_journals_editor_helpers.ts | 47 +++-- .../ae_comp__journal_entry_obj_id_view.svelte | 163 +++++------------- 2 files changed, 66 insertions(+), 144 deletions(-) diff --git a/src/lib/ae_journals/ae_journals_editor_helpers.ts b/src/lib/ae_journals/ae_journals_editor_helpers.ts index 1766af26..d7889fa6 100644 --- a/src/lib/ae_journals/ae_journals_editor_helpers.ts +++ b/src/lib/ae_journals/ae_journals_editor_helpers.ts @@ -1,35 +1,30 @@ -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); +export function wrapSelection(view: any, prefix: string, suffix: string = prefix) { + if (!view || view.updateInProgress) return; + + const { state } = view; + view.dispatch(state.changeByRange((range: any) => { return { changes: [ - { from: range.from, insert: prefix }, - { from: range.to, insert: suffix } + {from: range.from, insert: prefix}, + {from: range.to, insert: suffix} ], - range: { - from: range.from + prefix.length, - to: range.to + prefix.length - } + range: range.constructor.range(range.from + prefix.length, 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) => { +export function toggleLinePrefix(view: any, prefix: string) { + if (!view || view.updateInProgress) return; + + const { state } = view; + view.dispatch(state.changeByRange((range: any) => { const lines = []; for (let pos = range.from; pos <= range.to; ) { const line = state.doc.lineAt(pos); @@ -38,7 +33,6 @@ export function toggleLinePrefix(view: EditorView, prefix: string) { } 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: '' }; @@ -47,14 +41,13 @@ export function toggleLinePrefix(view: EditorView, prefix: string) { } }); + const newFrom = range.from + (isAlreadyPrefixed ? -prefix.length : prefix.length); + const newTo = range.to + (isAlreadyPrefixed ? (-prefix.length * lines.length) : (prefix.length * lines.length)); + return { changes: lineChanges, - range: { - from: range.from + (isAlreadyPrefixed ? -prefix.length : prefix.length), - to: range.to + (isAlreadyPrefixed ? -prefix.length * lines.length : prefix.length * lines.length) - } + range: range.constructor.range(newFrom, Math.max(newFrom, newTo)) }; - }); - dispatch(state.update(changes, { scrollIntoView: true, userEvent: 'input' })); + })); view.focus(); -} +} \ No newline at end of file diff --git a/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte b/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte index 1288727b..9dacc9c6 100644 --- a/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte +++ b/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte @@ -9,7 +9,6 @@ ArrowDown01, ArrowDown10, ArrowDownUp, - Bold, BookHeart, Bot, BotMessageSquare, @@ -32,10 +31,6 @@ Group, Hash, History, - Italic, - Link, - List, - ListOrdered, Loader, LockKeyhole, LockKeyholeOpen, @@ -48,7 +43,6 @@ Pencil, PenLine, Plus, - Quote, RemoveFormatting, Save, Search, @@ -60,7 +54,6 @@ Siren, Skull, SquareLibrary, - Strikethrough, Tags, Trash2, TypeOutline, @@ -157,11 +150,24 @@ // let orig_entry_obj: key_val = $state({}); let orig_entry_obj: key_val | null = $state({}); - let tmp_entry_obj_changed: boolean = $state(false); let tmp_entry_obj: key_val = $state({}); let updated_obj: boolean = $state(true); // Start with true to force population of orig and tmp values. let updated_idb: boolean = $state(true); // Updated in a separate browser session + // Idiomatic Svelte 5 change detection + let tmp_entry_obj_changed = $derived.by(() => { + if (!tmp_entry_obj || !orig_entry_obj || not_obj(tmp_entry_obj) || not_obj(orig_entry_obj)) { + return false; + } + + return ( + tmp_entry_obj.content !== orig_entry_obj.content || + tmp_entry_obj.name !== orig_entry_obj.name || + tmp_entry_obj.tags !== orig_entry_obj.tags || + tmp_entry_obj.category_code !== orig_entry_obj.category_code + ); + }); + // let tmp_entry_obj: key_val = { ...$lq__journal_entry_obj }; // let tmp_entry_obj = $derived(async () => { @@ -610,51 +616,7 @@ log_lvl: 1 }); console.log('Journal entry updated successfully:', response); - // tick(); updated_obj = true; - - // tick(); - - // orig_entry_obj = { ...await $lq__journal_entry_obj }; - // tmp_entry_obj = { ...await $lq__journal_entry_obj }; - // if ($journals_loc?.entry?.decrypt_kv[$lq__journal_entry_obj?.journal_entry_id]) { - // if (!tmp_entry_obj?.content && tmp_entry_obj?.content_encrypted) { - // console.log('TEST: Decrypting the content...'); - - // tmp_entry_obj.content = await ae_util.decrypt_wrapper(tmp_entry_obj?.content_encrypted, journal_key); - // tmp_entry_obj.content_md_html = handle_marked(tmp_entry_obj?.content); - - // orig_entry_obj.content = await ae_util.decrypt_wrapper(orig_entry_obj?.content_encrypted, journal_key); - // orig_entry_obj.content_md_html = handle_marked(orig_entry_obj?.content); - // } - // if (!tmp_entry_obj?.history && tmp_entry_obj?.history_encrypted) { - // console.log('TEST: Decrypting the history...'); - - // tmp_entry_obj.history = await ae_util.decrypt_wrapper(tmp_entry_obj?.history_encrypted, journal_key); - // tmp_entry_obj.history_md_html = handle_marked(tmp_entry_obj?.history); - - // orig_entry_obj.history = await ae_util.decrypt_wrapper(orig_entry_obj?.history_encrypted, journal_key); - // orig_entry_obj.history_md_html = handle_marked(orig_entry_obj?.history); - // } - // } - // console.log('TEST: tmp_entry_obj:', tmp_entry_obj); - - // updated_obj = true; - // updated_idb = false; - - // journals_func.update_ae_obj__journal_entry({ - // api_cfg: $ae_api, - // journal_entry_id: $lq__journal_entry_obj?.journal_entry_id, - // data_kv: data_kv, - // log_lvl: 1, - // }) - // .then((response) => { - // console.log('HERE: response', response); - // updated_obj = true; - // updated_idb = false; - // console.log('Journal entry updated successfully!'); - // }) - // tick(); } catch (error) { console.error('Error updating journal entry:', error); alert('Failed to update journal entry.'); @@ -954,95 +916,61 @@ items-center justify-between w-full bg-gray-100 dark:bg-gray-800 - p-1 rounded-lg shadow-md + p-2 md:p-3 rounded-lg shadow-md " > -
+
-

- - - +

{#if $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] == 'current'} - - - - + {:else} {#if $lq__journal_entry_obj?.name} - {@html $lq__journal_entry_obj?.name} {:else} - {ae_util.iso_datetime_formatter( $lq__journal_entry_obj?.created_on, 'datetime_iso_12_no_seconds' @@ -1050,7 +978,6 @@ {/if} {/if} -

@@ -2662,7 +2589,8 @@ tabindex={$ae_loc.edit_mode ? 0 : -1} --> {#if $lq__journal_obj?.cfg_json?.pref_editor == 'codemirror'} - + +
+ -->