Modularize Journal Entry Editor and continue God Component decomposition
- Extracted complex View/Edit logic into standalone JournalEntry_Editor.svelte. - Integrated modular editor with bindable state and editorView. - Maintained support for CodeMirror, Plain Text, and Rendered HTML modes. - Simplified main view by removing another 300+ lines of template logic.
This commit is contained in:
131
src/routes/journals/JournalEntry_Editor.svelte
Normal file
131
src/routes/journals/JournalEntry_Editor.svelte
Normal file
@@ -0,0 +1,131 @@
|
||||
<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}
|
||||
bind: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
|
||||
bind: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>
|
||||
@@ -93,6 +93,7 @@
|
||||
import AE_AITools from '$lib/ae_elements/AE_AITools.svelte';
|
||||
import AE_ObjectFlags from '$lib/ae_elements/AE_ObjectFlags.svelte';
|
||||
import AE_MetadataFooter from '$lib/ae_elements/AE_MetadataFooter.svelte';
|
||||
import JournalEntry_Editor from './JournalEntry_Editor.svelte';
|
||||
import JournalEntry_Metadata from './JournalEntry_Metadata.svelte';
|
||||
|
||||
// *** Configuration
|
||||
@@ -1734,332 +1735,40 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if !$journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id]}
|
||||
{#if $lq__journal_obj?.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}
|
||||
bind:theme_mode={$ae_loc.theme_mode}
|
||||
placeholder="Write using Markdown here..."
|
||||
class="
|
||||
p-2
|
||||
preset-outlined-success-400-600
|
||||
hover:preset-tonal-surface
|
||||
shadow-lg rounded-lg
|
||||
"
|
||||
/>
|
||||
{:else if $lq__journal_obj?.cfg_json?.pref_viewer == 'plain'}
|
||||
<pre
|
||||
class="
|
||||
grow
|
||||
basis-full
|
||||
h-full min-h-max max-h-full
|
||||
w-full min-w-full max-w-6xl
|
||||
p-2
|
||||
space-y-1
|
||||
font-mono
|
||||
text-wrap
|
||||
bg-slate-100! text-gray-900!
|
||||
dark:bg-slate-900! dark:text-gray-100!
|
||||
dark:prose-invert
|
||||
shadow-md rounded-lg
|
||||
border border-gray-200 dark:border-gray-700
|
||||
hover:border-green-500 dark:hover:border-green-500
|
||||
">
|
||||
{#if tmp_entry_obj.content}
|
||||
{tmp_entry_obj.content}
|
||||
{/if}
|
||||
</pre>
|
||||
{:else}
|
||||
<!-- rendered has HTML -->
|
||||
<article
|
||||
class="
|
||||
grow
|
||||
basis-full
|
||||
h-full min-h-max max-h-full
|
||||
w-full min-w-full max-w-6xl
|
||||
p-2
|
||||
space-y-1
|
||||
font-mono
|
||||
bg-slate-100! text-gray-900!
|
||||
dark:bg-slate-900! dark:text-gray-100!
|
||||
dark:prose-invert
|
||||
shadow-md rounded-lg
|
||||
border border-gray-200 dark:border-gray-700
|
||||
hover:border-green-500 dark:hover:border-green-500
|
||||
prose
|
||||
prose-h1:underline prose-h1:decoration-double
|
||||
prose-h2:underline
|
||||
prose-h1:text-2xl prose-h2:text-xl prose-h3:text-lg
|
||||
prose-h1:m-0 prose-h2:m-0 prose-h3:m-0 prose-h4:m-0 prose-h5:m-0 prose-h6:m-0
|
||||
prose-li:m-0 prose-li:p-0 prose-li:line-height-none
|
||||
"
|
||||
id="rendered_journal_entry_content_{$lq__journal_entry_obj?.journal_entry_id}"
|
||||
>
|
||||
{#if tmp_entry_obj?.content_md_html}
|
||||
{@html tmp_entry_obj?.content_md_html}
|
||||
{:else if tmp_entry_obj?.content_encrypted && tmp_entry_obj?.private}
|
||||
<div class="text-sm text-gray-500 italic p-4">
|
||||
<LockKeyhole size="1.25em" class="inline mr-2 text-success-500" />
|
||||
Private encrypted content (Decrypt to view)
|
||||
</div>
|
||||
{/if}
|
||||
</article>
|
||||
{/if}
|
||||
{#if $lq__journal_entry_obj?.data_json?.hosted_file_kv}
|
||||
<div class="flex flex-row flex-wrap gap-1 items-center justify-center w-full">
|
||||
<span class="">
|
||||
<!-- <SquareDownload size="1em" class="mx-1 inline-block"/> -->
|
||||
<FileDown size="1em" class="mx-1 inline-block" />
|
||||
<span class="text-sm text-gray-500 hidden sm:inline">
|
||||
Download Files:
|
||||
</span>
|
||||
</span>
|
||||
<!-- Main Content Editor/Viewer -->
|
||||
|
||||
{#each Object.entries($lq__journal_entry_obj?.data_json?.hosted_file_kv) as [key, hosted_file_obj]}
|
||||
<Comp_hosted_files_download_button
|
||||
hosted_file_id={hosted_file_obj?.hosted_file_id_random ?? ''}
|
||||
{hosted_file_obj}
|
||||
linked_to_type="journal_entry"
|
||||
linked_to_id={$lq__journal_entry_obj?.journal_entry_id}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{:else if $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] == 'current'}
|
||||
<!-- && !($lq__journal_entry_obj?.content_encrypted && decrypted_content)) -->
|
||||
<!-- class="flex flex-row flex-wrap gap-1 items-center justify-center w-full max-w-sm" -->
|
||||
<JournalEntry_Editor
|
||||
|
||||
{#if !tmp_entry_obj?.content && tmp_entry_obj?.content_encrypted}
|
||||
<div
|
||||
class="
|
||||
grow
|
||||
basis-full
|
||||
h-full min-h-max max-h-full
|
||||
w-full min-w-full max-w-6xl
|
||||
p-2
|
||||
space-y-1
|
||||
bg-red-100 text-gray-900
|
||||
dark:bg-red-900 dark:text-gray-100
|
||||
shadow-lg rounded-lg
|
||||
border border-red-200 dark:border-red-700
|
||||
hover:border-red-500 dark:hover:border-red-500
|
||||
"
|
||||
>
|
||||
<div>The entry must be decrypted before it can be edited.</div>
|
||||
{#if tmp_entry_obj?.content === false && $journals_sess?.journal_kv[$lq__journal_obj?.id]?.journal_passcode_verified}
|
||||
<div class="text-sm text-red-500">
|
||||
<LockKeyhole strokeWidth="1.5" color="red" class="inline-block" />
|
||||
Decryption failed. Check the passcode(s).
|
||||
</div>
|
||||
{:else if tmp_entry_obj?.content === false}
|
||||
<div class="text-sm text-red-500">
|
||||
<LockKeyhole strokeWidth="1.5" color="red" class="inline-block" />
|
||||
Decryption failed. You may need to enter the Journal's private passcode.
|
||||
</div>
|
||||
{/if}
|
||||
{#if tmp_entry_obj?.content === false && $lq__journal_obj?.id && $journals_sess?.journal_kv[$lq__journal_obj?.id]?.journal_passcode_verified}
|
||||
<div class="text-sm text-red-500">
|
||||
This might not be encoded with the private passcode or a passcode
|
||||
has changed?
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
{#if $lq__journal_obj?.cfg_json?.pref_editor == 'codemirror'}
|
||||
<!-- Toolbar for CodeMirror (Temporarily disabled) -->
|
||||
<!--
|
||||
<div class="flex flex-row flex-wrap gap-1 p-1 bg-surface-100-900 border-x border-t border-orange-300 dark:border-orange-700 rounded-t-lg w-full max-w-6xl">
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Bold" onclick={() => wrapSelection(editorView, '**')}>
|
||||
<Bold size="1.25em" />
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Italic" onclick={() => wrapSelection(editorView, '*')}>
|
||||
<Italic size="1.25em" />
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Strikethrough" onclick={() => wrapSelection(editorView, '~~')}>
|
||||
<Strikethrough size="1.25em" />
|
||||
</button>
|
||||
<span class="border-r border-surface-500 mx-1"></span>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Header 1" onclick={() => toggleLinePrefix(editorView, '# ')}>
|
||||
<span class="font-bold">H1</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Header 2" onclick={() => toggleLinePrefix(editorView, '## ')}>
|
||||
<span class="font-bold">H2</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Header 3" onclick={() => toggleLinePrefix(editorView, '### ')}>
|
||||
<span class="font-bold">H3</span>
|
||||
</button>
|
||||
<span class="border-r border-surface-500 mx-1"></span>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Bullet List" onclick={() => toggleLinePrefix(editorView, '- ')}>
|
||||
<List size="1.25em" />
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Ordered List" onclick={() => toggleLinePrefix(editorView, '1. ')}>
|
||||
<ListOrdered size="1.25em" />
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Blockquote" onclick={() => toggleLinePrefix(editorView, '> ')}>
|
||||
<Quote size="1.25em" />
|
||||
</button>
|
||||
<span class="border-r border-surface-500 mx-1"></span>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Link" onclick={() => wrapSelection(editorView, '[', '](https://)')}>
|
||||
<Link size="1.25em" />
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm preset-tonal-surface hover:preset-filled-secondary-500" title="Code" onclick={() => wrapSelection(editorView, '`')}>
|
||||
<CodeXml size="1.25em" />
|
||||
</button>
|
||||
</div>
|
||||
-->
|
||||
entry={$lq__journal_entry_obj}
|
||||
|
||||
journal={$lq__journal_obj}
|
||||
|
||||
bind:tmp_entry_obj={tmp_entry_obj}
|
||||
|
||||
bind:editorView={editorView}
|
||||
|
||||
has_changed={tmp_entry_obj_changed}
|
||||
|
||||
updated_idb={updated_idb}
|
||||
|
||||
onSave={update_journal_entry}
|
||||
|
||||
<E_app_codemirror_v5
|
||||
content={tmp_entry_obj?.content ?? ''}
|
||||
bind:new_content={tmp_entry_obj.content}
|
||||
bind:editorView
|
||||
bind:theme_mode={$ae_loc.theme_mode}
|
||||
placeholder="Write using Markdown here..."
|
||||
class="
|
||||
p-2
|
||||
preset-outlined-warning-300-700
|
||||
shadow-lg rounded-b-lg rounded-t-none
|
||||
bg-gray-100 text-gray-950
|
||||
dark:bg-gray-800 dark:text-gray-100
|
||||
"
|
||||
/>
|
||||
{:else}
|
||||
<textarea
|
||||
bind:value={tmp_entry_obj.content}
|
||||
ondblclick={() => {
|
||||
// if ($ae_loc.trusted_access && $ae_loc.edit_mode) {
|
||||
// // Toggle edit mode
|
||||
// $journals_loc.entry.edit = !$journals_loc.entry.edit;
|
||||
// $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] = $journals_loc.entry.edit;
|
||||
// }
|
||||
}}
|
||||
class="
|
||||
grow
|
||||
shrink-0
|
||||
basis-full
|
||||
h-max min-h-max max-h-full
|
||||
w-full min-w-full max-w-6xl
|
||||
p-2
|
||||
space-y-1
|
||||
font-mono
|
||||
bg-slate-100 text-gray-900
|
||||
dark:bg-slate-900 dark:text-gray-100
|
||||
shadow-lg rounded-lg
|
||||
border border-orange-200 dark:border-orange-700
|
||||
hover:border-orange-500 dark:hover:border-orange-500
|
||||
"
|
||||
placeholder="Edit journal entry content here..."
|
||||
></textarea>
|
||||
{/if}
|
||||
|
||||
<!-- Only enable editing if the user has trusted access -->
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
update_journal_entry();
|
||||
}}
|
||||
disabled={!tmp_entry_obj_changed}
|
||||
class:invisible={!tmp_entry_obj_changed}
|
||||
class="
|
||||
btn btn-sm md:btn-md lg:btn-lg
|
||||
|
||||
|
||||
min-w-72 w-full lg:min-w-96
|
||||
max-w-96
|
||||
<!-- Main Content Editor/Viewer -->
|
||||
<JournalEntry_Editor
|
||||
entry={$lq__journal_entry_obj}
|
||||
journal={$lq__journal_obj}
|
||||
bind:tmp_entry_obj={tmp_entry_obj}
|
||||
bind:editorView={editorView}
|
||||
has_changed={tmp_entry_obj_changed}
|
||||
updated_idb={updated_idb}
|
||||
onSave={update_journal_entry}
|
||||
/>
|
||||
|
||||
preset-outlined-warning-900-100
|
||||
preset-filled-warning-50-950
|
||||
|
||||
hover:variant-outline-success-900-100
|
||||
hover:preset-filled-success-50-950
|
||||
"
|
||||
>
|
||||
<Save strokeWidth="1" class="inline-block" />
|
||||
Save Changes
|
||||
</button>
|
||||
|
||||
<!-- Do a quick check to see if the updated_on timestamp has changed. Specifically, if the entry was updated since the last time it was loaded. -->
|
||||
{#if updated_idb}
|
||||
<span class="text-sm text-red-500">
|
||||
WARNING: IDB object has been updated since last load.
|
||||
</span>
|
||||
{/if}
|
||||
<!-- Updated: {orig_entry_obj?.updated_on}
|
||||
Updated obj? {updated_obj} -->
|
||||
|
||||
<!-- && $lq__journal_entry_obj?.updated_on !== orig_entry_obj?.updated_on -->
|
||||
|
||||
<!-- Using absolute or fixed position -->
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
update_journal_entry();
|
||||
}}
|
||||
disabled={!tmp_entry_obj_changed}
|
||||
class:hidden={!tmp_entry_obj_changed}
|
||||
class="
|
||||
btn btn-sm md:btn-md lg:btn-lg
|
||||
|
||||
fixed top-96 md:top-72 right-6
|
||||
min-w-24 w-full lg:min-w-32
|
||||
max-w-40
|
||||
|
||||
preset-outlined-warning-900-100
|
||||
preset-filled-warning-50-950
|
||||
|
||||
hover:variant-outline-success-900-100
|
||||
hover:preset-filled-success-50-950
|
||||
|
||||
"
|
||||
>
|
||||
<Save strokeWidth="1" class="inline-block" />
|
||||
Save Changes
|
||||
</button>
|
||||
|
||||
<!-- </div> -->
|
||||
{/if}
|
||||
|
||||
{#if $lq__journal_entry_obj?.journal_entry_id}
|
||||
<Comp_journal_entry_file_li
|
||||
{log_lvl}
|
||||
link_to_type="journal_entry"
|
||||
link_to_id={$lq__journal_entry_obj?.journal_entry_id}
|
||||
{lq__journal_entry_obj}
|
||||
/>
|
||||
|
||||
<!-- Object.keys(hosted_file_kv ?? {}).length -->
|
||||
{#if $lq__journal_entry_obj?.data_json?.hosted_file_kv}
|
||||
<div
|
||||
class="flex flex-row flex-wrap gap-1 items-center justify-center w-full"
|
||||
>
|
||||
<span class="">
|
||||
<!-- <SquareDownload size="1em" class="mx-1 inline-block"/> -->
|
||||
<FileDown size="1em" class="mx-1 inline-block" />
|
||||
<span class="text-sm text-gray-500 hidden sm:inline">
|
||||
Download Files:
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{#each Object.entries($lq__journal_entry_obj?.data_json?.hosted_file_kv) as [key, hosted_file_obj]}
|
||||
<Comp_hosted_files_download_button
|
||||
hosted_file_id={hosted_file_obj?.hosted_file_id_random ?? ''}
|
||||
{hosted_file_obj}
|
||||
linked_to_type="journal_entry"
|
||||
linked_to_id={$lq__journal_entry_obj?.journal_entry_id}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<section
|
||||
class="ae_section journal_entry__hosted_file border border-gray-200 rounded p-2 space-y-2"
|
||||
>
|
||||
<span class="fas fa-exclamation-triangle text-red-500"></span>
|
||||
Save the form first before uploading a file.
|
||||
</section>
|
||||
{/if}
|
||||
{:else if $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] == 'history'}
|
||||
{#if $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] == 'history'}
|
||||
<div
|
||||
class="grow basis-full flex flex-col items-center justify-center h-full w-full max-w-6xl"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user