From 8fd11d72248694a5e79f2621526e8261365e09c8 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Tue, 13 Jan 2026 22:59:08 -0500 Subject: [PATCH] feat(journals): implement Quick Add and unified Append/Prepend shared component - Created AeCompJournalEntryQuickAdd for high-velocity note creation - Extracted robust append/prepend logic from List View into AeCompModalJournalEntryAppend - Unified List and Detail views to use the shared modal for content manipulation - Added explicit Append/Prepend actions to Journal Entry settings menu - Updated TODO.md and Journals module documentation --- TODO.md | 4 +- .../AE_UI_Journals_module_update_2026.md | 8 +- src/routes/journals/+page.svelte | 6 + .../journals/JournalEntry_Header.svelte | 6 + .../journals/JournalEntry_SettingsMenu.svelte | 17 +- .../ae_comp__journal_entry_obj_id_view.svelte | 32 +- .../ae_comp__journal_entry_obj_li.svelte | 425 ++---------------- .../ae_comp__journal_entry_quick_add.svelte | 106 +++++ ...ae_comp__modal_journal_entry_append.svelte | 197 ++++++++ 9 files changed, 403 insertions(+), 398 deletions(-) create mode 100644 src/routes/journals/ae_comp__journal_entry_quick_add.svelte create mode 100644 src/routes/journals/ae_comp__modal_journal_entry_append.svelte diff --git a/TODO.md b/TODO.md index 6d55398b..58aca3ad 100644 --- a/TODO.md +++ b/TODO.md @@ -29,8 +29,8 @@ This is a list of tasks to be completed before the next event/show/conference. - [ ] **Error Transparency**: Update backend to return specific SQLAlchemy/Pydantic errors in `meta.details`. - [ ] **Automated Source of Truth**: Generate `V3_OBJECT_MODELS.md` automatically in `agents_sync/Aether/`. - [ ] **Phase 2: UI/UX Excellence** - - [ ] Implement "Quick Add" for high-velocity entry. - - [ ] Add rapid append/prepend functionality to existing entries. + - [x] Implement "Quick Add" for high-velocity entry. + - [x] Add rapid append/prepend functionality to existing entries. - [ ] Ensure full cross-platform responsiveness (Mobile -> Workstation). - [ ] **Phase 3: Content Portability** - [ ] Implement Structured Markdown import (with metadata). diff --git a/documentation/AE_UI_Journals_module_update_2026.md b/documentation/AE_UI_Journals_module_update_2026.md index 40c4fab8..de12da1b 100644 --- a/documentation/AE_UI_Journals_module_update_2026.md +++ b/documentation/AE_UI_Journals_module_update_2026.md @@ -73,13 +73,13 @@ This document outlines the modernization of the Journals module UI in the Svelte - [x] Verify frontend uses V3 API (`ae_journals__journal.ts`). ### Phase 2: Rapid Entry (Active) -- [ ] Create `ae_comp__journal_entry_quick_add.svelte`. -- [ ] Integrate Quick Add into `+page.svelte`. +- [x] Create `ae_comp__journal_entry_quick_add.svelte`. +- [x] Integrate Quick Add into `+page.svelte`. - [ ] Update `ae_journals_stores.ts` to manage Quick Add state/visibility. ### Phase 3: Content Manipulation -- [ ] Update `JournalEntry_SettingsMenu.svelte` with Append/Prepend actions. -- [ ] Implement Append/Prepend logic in `JournalEntry_Editor.svelte` or helper functions. +- [x] Update `JournalEntry_SettingsMenu.svelte` with Append/Prepend actions. +- [x] Implement Append/Prepend logic in `ae_comp__journal_entry_obj_id_view.svelte`. ### Phase 4: Polish & Security - [ ] Audit encryption flow for Quick Added entries. diff --git a/src/routes/journals/+page.svelte b/src/routes/journals/+page.svelte index 2823527f..49a0faf3 100644 --- a/src/routes/journals/+page.svelte +++ b/src/routes/journals/+page.svelte @@ -32,6 +32,7 @@ import Modal_journals_cfg from './modal_journals_config.svelte'; import Journal_obj_li from './ae_comp__journal_obj_li.svelte'; + import AeCompJournalEntryQuickAdd from './ae_comp__journal_entry_quick_add.svelte'; // import Element_data_store from '$lib/element_data_store_v2.svelte'; @@ -175,6 +176,11 @@ {$ae_loc.person.given_name ? `- ${$ae_loc.person.given_name}` : ''} + +
+ +
+
void; onDecryptHistory: () => void; onChangeJournal: () => void; + onAppend?: () => void; + onPrepend?: () => void; log_lvl?: number; } @@ -39,6 +41,8 @@ onDecrypt, onDecryptHistory, onChangeJournal, + onAppend, + onPrepend, log_lvl = 0 }: Props = $props(); @@ -220,6 +224,8 @@ p-2 md:p-3 rounded-lg shadow-md {onSave} {onDecryptHistory} {onChangeJournal} + {onAppend} + {onPrepend} {log_lvl} />
diff --git a/src/routes/journals/JournalEntry_SettingsMenu.svelte b/src/routes/journals/JournalEntry_SettingsMenu.svelte index 4bef7666..de53d8f2 100644 --- a/src/routes/journals/JournalEntry_SettingsMenu.svelte +++ b/src/routes/journals/JournalEntry_SettingsMenu.svelte @@ -9,7 +9,8 @@ Eye, EyeOff, ShieldCheck, ShieldMinus, Clock, X, Trash2, Settings, Shapes, Copy, RemoveFormatting, CodeXml, TypeOutline, - History, Pencil, PenLine, FileX, SquareLibrary + History, Pencil, PenLine, FileX, SquareLibrary, + ArrowUpToLine, ArrowDownToLine } from '@lucide/svelte'; import { ae_loc, ae_api } from '$lib/stores/ae_stores'; import { journals_slct, journals_loc, journals_sess } from '$lib/ae_journals/ae_journals_stores'; @@ -26,6 +27,8 @@ onSave: () => void; onDecryptHistory: () => void; onChangeJournal: () => void; + onAppend?: () => void; + onPrepend?: () => void; log_lvl?: number; } @@ -37,6 +40,8 @@ onSave, onDecryptHistory, onChangeJournal, + onAppend, + onPrepend, log_lvl = 0 }: Props = $props(); @@ -83,6 +88,16 @@
+ +
+ + +
+
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 92b73559..86a7abda 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 @@ -31,6 +31,7 @@ import AE_MetadataFooter from '$lib/ae_elements/AE_MetadataFooter.svelte'; import JournalEntry_Editor from './JournalEntry_Editor.svelte'; import JournalEntry_Header from './JournalEntry_Header.svelte'; + import AeCompModalJournalEntryAppend from './ae_comp__modal_journal_entry_append.svelte'; // *** Props interface Props { @@ -486,6 +487,22 @@ slct_hosted_file_obj = null; } }); + + // --- Shared Append / Prepend Modal Logic --- + let show_append_modal = $state(false); + let modal_mode: 'append' | 'prepend' | 'auto' = $state('auto'); + + function handle_append_start() { + modal_mode = 'append'; + show_append_modal = true; + $journals_sess.entry.show_menu = false; + } + + function handle_prepend_start() { + modal_mode = 'prepend'; + show_append_modal = true; + $journals_sess.entry.show_menu = false; + }
@@ -596,7 +615,18 @@ - + (show_append_modal = false)} + onUpdate={() => { + show_append_modal = false; + updated_obj = true; // Force refresh of the view + }} + {log_lvl} + /> {:else}
diff --git a/src/routes/journals/ae_comp__journal_entry_obj_li.svelte b/src/routes/journals/ae_comp__journal_entry_obj_li.svelte index 20d55dd8..7b40739c 100644 --- a/src/routes/journals/ae_comp__journal_entry_obj_li.svelte +++ b/src/routes/journals/ae_comp__journal_entry_obj_li.svelte @@ -8,8 +8,7 @@ let { log_lvl = $bindable(0), lq__journal_obj, lq__journal_entry_obj_li }: Props = $props(); // *** Import Svelte specific - import { goto, invalidate, pushState, replaceState } from '$app/navigation'; - import { Modal } from 'flowbite-svelte'; + import { goto } from '$app/navigation'; import { CalendarClock, Check, @@ -17,11 +16,9 @@ Copy, Eye, EyeOff, - FileLock, Files, Fingerprint, Flag, - FlagOff, Group, ListPlus, Lock, @@ -39,50 +36,45 @@ // *** Import Aether specific variables and functions import type { key_val } from '$lib/stores/ae_stores'; import { ae_util } from '$lib/ae_utils/ae_utils'; - import { api } from '$lib/api/api'; import { - ae_snip, ae_loc, ae_sess, ae_api, ae_trig, - slct, - slct_trigger + slct } from '$lib/stores/ae_stores'; import { - journals_loc, journals_sess, journals_slct, - journals_trig + journals_trig, + journals_loc } from '$lib/ae_journals/ae_journals_stores'; import { journals_func } from '$lib/ae_journals/ae_journals_functions'; - - let ae_promises: key_val = $state({}); - // let ae_tmp: key_val = {}; - // let ae_triggers: key_val = {}; + import AeCompModalJournalEntryAppend from './ae_comp__modal_journal_entry_append.svelte'; let tmp_entry_obj: key_val = $state({}); - let tmp_entry_obj_add_timestamp_header: boolean = $state(true); - let tmp_entry_obj_add_timestamp_header_w_day_of_week: boolean = $state(true); - let tmp_entry_obj_add_text_header: string = $state(''); - let tmp_entry_obj_add_text: string = $state(''); - let tmp_entry_obj_changed: boolean = $state(false); + + // Derived state for modal visibility + // We cast to boolean for the prop, but we need to handle the close event to clear the store ID + let show_append_modal = $state(false); $effect(() => { - if (tmp_entry_obj_add_text_header.length || tmp_entry_obj_add_text) { - tmp_entry_obj_changed = true; - } else { - tmp_entry_obj_changed = false; - } + // Sync local boolean with store ID presence + show_append_modal = !!$journals_sess.show__modal_append__journal_entry_id; }); + + function handle_modal_close() { + $journals_sess.show__modal_append__journal_entry_id = null; + show_append_modal = false; + } + + function handle_modal_update() { + handle_modal_close(); + }
{#if $lq__journal_entry_obj_li && $lq__journal_entry_obj_li.length} - - {#each $lq__journal_entry_obj_li as journals_journal_entry_obj, index}
- - @@ -176,8 +166,6 @@ @@ -221,10 +207,7 @@ } try { - // Get the rendered HTML content const htmlContent = element.innerHTML; - - // Use the Clipboard API to write the HTML content as rich text await navigator.clipboard.write([ new ClipboardItem({ 'text/html': new Blob([htmlContent], { @@ -241,10 +224,9 @@ }} class:hidden={journals_journal_entry_obj.template || $lq__journal_obj?.cfg_json?.hide_copy_rich} - class="btn btn-sm p-1 preset-tonal-secondary *:hover:inline lg:text-xs" + class="btn btn-sm p-1 preset-tonal-surface hover:preset-filled-secondary-500 *:hover:inline lg:text-xs" title="Copy the rich text (rendered HTML) content" > - @@ -253,8 +235,6 @@ - - {:else} - - @@ -323,16 +297,12 @@ }); }} class:hidden={$lq__journal_obj?.cfg_json?.hide_copy_encrypted} - class="btn btn-sm p-1 preset-tonal-secondary hover:preset-filled-secondary-500 *:hover:inline text-xs lg:text-sm" + class="btn btn-sm p-1 preset-tonal-surface hover:preset-filled-secondary-500 *:hover:inline text-xs lg:text-sm" title="Copy the encrypted content" > - - - - {/if} @@ -344,8 +314,7 @@ class:hidden={!journals_journal_entry_obj?.data_json?.hosted_file_kv} > - + {journals_journal_entry_obj?.data_json?.hosted_file_kv ? Object.keys( @@ -376,11 +345,9 @@ {#if journals_journal_entry_obj.category_code} -
{#if journals_journal_entry_obj.content} -
-
- +
\ No newline at end of file diff --git a/src/routes/journals/ae_comp__journal_entry_quick_add.svelte b/src/routes/journals/ae_comp__journal_entry_quick_add.svelte new file mode 100644 index 00000000..bf86f016 --- /dev/null +++ b/src/routes/journals/ae_comp__journal_entry_quick_add.svelte @@ -0,0 +1,106 @@ + + +
+
+

Quick Add

+ {#if !target_journal_id} + No Journal Selected + {/if} +
+ + + +
+ + +
+
diff --git a/src/routes/journals/ae_comp__modal_journal_entry_append.svelte b/src/routes/journals/ae_comp__modal_journal_entry_append.svelte new file mode 100644 index 00000000..8d0cf161 --- /dev/null +++ b/src/routes/journals/ae_comp__modal_journal_entry_append.svelte @@ -0,0 +1,197 @@ + + + + + \ No newline at end of file