132 lines
5.6 KiB
Svelte
132 lines
5.6 KiB
Svelte
<script lang="ts">
|
|
/**
|
|
* JournalEntry_Editor.svelte
|
|
* Extracted 2026-01-08 to modularize the massive Journal Entry view.
|
|
* Handles: CodeMirror vs Plain vs Rendered HTML for both View and Edit modes.
|
|
*/
|
|
import { LockKeyhole, Save } from '@lucide/svelte';
|
|
import { ae_loc } from '$lib/stores/ae_stores';
|
|
import { journals_loc, journals_sess } from '$lib/ae_journals/ae_journals_stores';
|
|
import E_app_codemirror_v5 from '$lib/app_components/e_app_codemirror_v5.svelte';
|
|
import type { ae_JournalEntry, ae_Journal } from '$lib/types/ae_types';
|
|
|
|
interface Props {
|
|
entry: ae_JournalEntry;
|
|
journal: ae_Journal;
|
|
tmp_entry_obj: any; // Bindable
|
|
editorView?: any; // Bindable
|
|
has_changed: boolean;
|
|
updated_idb: boolean;
|
|
onSave: () => void;
|
|
}
|
|
|
|
let {
|
|
entry,
|
|
journal,
|
|
tmp_entry_obj = $bindable(),
|
|
editorView = $bindable(),
|
|
has_changed,
|
|
updated_idb,
|
|
onSave
|
|
}: Props = $props();
|
|
|
|
const is_editing = $derived($journals_loc.entry.edit_kv[entry.journal_entry_id] === 'current');
|
|
</script>
|
|
|
|
<div class="journal-entry-editor-wrapper grow w-full flex flex-col items-center">
|
|
{#if !is_editing}
|
|
<!-- VIEW MODE -->
|
|
{#if journal?.cfg_json?.pref_viewer == 'codemirror'}
|
|
<E_app_codemirror_v5
|
|
editable={false}
|
|
readonly={true}
|
|
content={tmp_entry_obj?.content ?? ''}
|
|
bind:new_content={tmp_entry_obj.content}
|
|
theme_mode={$ae_loc.theme_mode}
|
|
placeholder="No content..."
|
|
class="p-2 preset-outlined-success-400-600 shadow-lg rounded-lg w-full max-w-6xl"
|
|
/>
|
|
{:else if journal?.cfg_json?.pref_viewer == 'plain'}
|
|
<pre class="grow w-full max-w-6xl p-2 font-mono text-wrap bg-surface-100 dark:bg-surface-900 shadow-md rounded-lg border border-surface-500/20">
|
|
{tmp_entry_obj.content || '-- No Content --'}
|
|
</pre>
|
|
{:else}
|
|
<!-- Rendered HTML -->
|
|
<article
|
|
class="grow w-full max-w-6xl p-4 bg-surface-50 dark:bg-surface-900 shadow-md rounded-lg border border-surface-500/20 prose dark:prose-invert prose-h1:underline"
|
|
id="rendered_journal_entry_content_{entry.journal_entry_id}"
|
|
>
|
|
{#if tmp_entry_obj?.content_md_html}
|
|
{@html tmp_entry_obj.content_md_html}
|
|
{:else if tmp_entry_obj?.content_encrypted && entry.private}
|
|
<div class="text-sm text-surface-500 italic flex items-center gap-2">
|
|
<LockKeyhole size="1.25em" class="text-success-500" />
|
|
Private encrypted content (Decrypt to view)
|
|
</div>
|
|
{/if}
|
|
</article>
|
|
{/if}
|
|
{:else}
|
|
<!-- EDIT MODE -->
|
|
{#if !tmp_entry_obj?.content && tmp_entry_obj?.content_encrypted}
|
|
<!-- Decryption Required Message -->
|
|
<div class="w-full max-w-6xl p-4 bg-error-100 dark:bg-error-900/30 text-error-900 dark:text-error-100 rounded-lg border border-error-500 flex flex-col gap-2">
|
|
<div class="font-bold flex items-center gap-2">
|
|
<LockKeyhole size="1.25em" />
|
|
Decryption Required
|
|
</div>
|
|
<p class="text-sm">This entry must be decrypted before it can be edited.</p>
|
|
{#if tmp_entry_obj?.content === false}
|
|
<p class="text-xs opacity-80">Decryption failed. Please check your journal passcodes.</p>
|
|
{/if}
|
|
</div>
|
|
{:else}
|
|
<!-- Actual Editor -->
|
|
{#if journal?.cfg_json?.pref_editor == 'codemirror'}
|
|
<E_app_codemirror_v5
|
|
content={tmp_entry_obj?.content ?? ''}
|
|
bind:new_content={tmp_entry_obj.content}
|
|
bind:editorView
|
|
theme_mode={$ae_loc.theme_mode}
|
|
placeholder="Write using Markdown..."
|
|
class="p-2 preset-outlined-warning-300-700 shadow-lg rounded-lg w-full max-w-6xl bg-surface-50 dark:bg-surface-800"
|
|
/>
|
|
{:else}
|
|
<textarea
|
|
bind:value={tmp_entry_obj.content}
|
|
class="textarea grow w-full max-w-6xl p-4 font-mono shadow-lg rounded-lg border-orange-500/30 h-[500px]"
|
|
placeholder="Edit content..."
|
|
></textarea>
|
|
{/if}
|
|
|
|
<!-- Floating Save Button -->
|
|
<button
|
|
type="button"
|
|
onclick={onSave}
|
|
disabled={!has_changed}
|
|
class="btn btn-sm md:btn-md lg:btn-lg fixed top-72 right-6 min-w-32 variant-filled-success shadow-xl z-20 transition-all"
|
|
class:hidden={!has_changed}
|
|
>
|
|
<Save size="1.2em" class="mr-2" /> Save
|
|
</button>
|
|
|
|
<!-- Inline Save Button (Mobile/Context) -->
|
|
<button
|
|
type="button"
|
|
onclick={onSave}
|
|
disabled={!has_changed}
|
|
class="btn variant-filled-warning w-full max-w-96 mt-4"
|
|
class:invisible={!has_changed}
|
|
>
|
|
<Save size="1.2em" class="mr-2" /> Save Changes
|
|
</button>
|
|
|
|
{#if updated_idb}
|
|
<p class="text-xs text-error-500 mt-2 font-bold animate-pulse uppercase tracking-widest">
|
|
IDB object updated since last load!
|
|
</p>
|
|
{/if}
|
|
{/if}
|
|
{/if}
|
|
</div>
|