- Replace all Skeleton v2 variant-* classes with v4 preset-* equivalents - variant-filled-* → preset-filled-* - variant-soft-* / variant-ghost-* → preset-tonal-* - variant-outline-* → preset-outlined-* - variant-form-material removed from inputs/selects/textareas - input-bordered removed - Fix dark mode: journal entry content hover (dark:hover:bg-blue-950) - Fix dark mode: journal obj view section/description bg and text colors - Fix modal headers: add dismissable=false + explicit X close button (all 3 journals modals) - Fix DaisyUI wrappers removed from modal_journal_entry_append - app.css: add global select padding-inline to fix text-against-border issue
764 lines
37 KiB
Svelte
764 lines
37 KiB
Svelte
<script lang="ts">
|
||
interface Props {
|
||
log_lvl?: number;
|
||
lq__journal_obj: any;
|
||
lq__journal_entry_obj_li: any;
|
||
show_found_header?: boolean;
|
||
}
|
||
|
||
let {
|
||
log_lvl = $bindable(0),
|
||
lq__journal_obj,
|
||
lq__journal_entry_obj_li,
|
||
show_found_header = true
|
||
}: Props = $props();
|
||
|
||
// *** Import Svelte specific
|
||
import { goto } from '$app/navigation';
|
||
import {
|
||
CalendarClock,
|
||
Check,
|
||
CodeXml,
|
||
Copy,
|
||
Eye,
|
||
EyeOff,
|
||
Files,
|
||
Fingerprint,
|
||
Flag,
|
||
Group,
|
||
ListPlus,
|
||
Lock,
|
||
NotebookPen,
|
||
NotebookText,
|
||
NotepadTextDashed,
|
||
RemoveFormatting,
|
||
Shapes,
|
||
Siren,
|
||
Tags,
|
||
TypeOutline,
|
||
X,
|
||
LoaderCircle,
|
||
BookOpenText
|
||
} from 'lucide-svelte';
|
||
|
||
// *** 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 {
|
||
ae_loc,
|
||
ae_sess,
|
||
ae_api,
|
||
ae_trig,
|
||
slct
|
||
} from '$lib/stores/ae_stores';
|
||
import {
|
||
journals_sess,
|
||
journals_slct,
|
||
journals_trig,
|
||
journals_loc
|
||
} from '$lib/ae_journals/ae_journals_stores';
|
||
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
|
||
import AeCompModalJournalEntryAppend from './ae_comp__modal_journal_entry_append.svelte';
|
||
|
||
let tmp_entry_obj: key_val = $state({});
|
||
|
||
// 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(() => {
|
||
// 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();
|
||
}
|
||
|
||
// Derived list of visible items (Standardized Search Pattern 2026-01-27)
|
||
// Ensures count matches exactly what is rendered to the user
|
||
let visible_journal_entry_obj_li = $derived(
|
||
(() => {
|
||
// Subscribe to the observable
|
||
const list = $lq__journal_entry_obj_li;
|
||
|
||
// Return null to signify 'loading' vs [] for 'empty'
|
||
if (list === undefined || list === null) return null;
|
||
if (!Array.isArray(list)) return [];
|
||
|
||
const filtered = list.filter((item: any) => {
|
||
if (!item) return false;
|
||
|
||
const is_hidden = item.hide === true || item.hide === 1;
|
||
const is_disabled = item.enable === false || item.enable === 0;
|
||
|
||
// Standard Visibility: Filter out hidden/disabled if not in Edit Mode
|
||
if (!$ae_loc.edit_mode) {
|
||
return !is_hidden && !is_disabled;
|
||
}
|
||
|
||
// Edit Mode Gating:
|
||
// - To see Hidden: Must have Trusted Access or higher
|
||
if (is_hidden && !$ae_loc.trusted_access) return false;
|
||
|
||
// - To see Disabled: Must have Administrator Access or higher
|
||
if (is_disabled && !$ae_loc.administrator_access) return false;
|
||
|
||
return true;
|
||
});
|
||
|
||
if (log_lvl)
|
||
console.log(
|
||
`visible_journal_entry_obj_li: Input=${list.length}, Output=${filtered.length}`
|
||
);
|
||
|
||
return filtered;
|
||
})()
|
||
);
|
||
</script>
|
||
|
||
<section
|
||
class="journal_list flex flex-col gap-1 md:gap-2 items-center justify-center w-full"
|
||
>
|
||
{#if visible_journal_entry_obj_li === null}
|
||
<!-- Loading state -->
|
||
<div class="flex flex-col items-center justify-center p-10 opacity-50">
|
||
<LoaderCircle size="2em" class="animate-spin mb-2" />
|
||
<p>Loading visible entries...</p>
|
||
</div>
|
||
{:else if visible_journal_entry_obj_li.length > 0}
|
||
{#if show_found_header}
|
||
<div class="w-full max-w-(--breakpoint-lg) mb-2">
|
||
<h2 class="h4 flex items-center gap-2 px-2">
|
||
<span class="text-sm text-gray-500 font-normal">
|
||
Found:
|
||
</span>
|
||
<span
|
||
class="badge preset-tonal-success font-bold text-lg px-3 py-1"
|
||
>
|
||
{visible_journal_entry_obj_li.length}<span
|
||
class="text-gray-400 dark:text-gray-600"
|
||
>×</span
|
||
>
|
||
</span>
|
||
</h2>
|
||
</div>
|
||
{/if}
|
||
|
||
{#each visible_journal_entry_obj_li as journals_journal_entry_obj, index (journals_journal_entry_obj.journal_entry_id)}
|
||
<div
|
||
class="
|
||
container journal journal_entry_obj
|
||
border
|
||
px-2 py-1 space-y-1
|
||
w-full max-w-(--breakpoint-lg)
|
||
flex flex-col items-center justify-center
|
||
bg-white text-gray-900
|
||
dark:bg-gray-800 dark:text-gray-200
|
||
rounded-lg
|
||
hover:bg-gray-100 hover:dark:bg-gray-700
|
||
hover:border-gray-300
|
||
transition-all duration-500 ease-out
|
||
"
|
||
class:dim={!journals_journal_entry_obj.enable}
|
||
class:bg-warning-100={!journals_journal_entry_obj?.enable}
|
||
>
|
||
<header
|
||
class="ae_header flex flex-row gap-2 items-center justify-between w-full"
|
||
>
|
||
<span class="flex flex-row flex-wrap gap-1">
|
||
<span class="journal_entry__name *:hover:inline-block">
|
||
{#if journals_journal_entry_obj.alert}
|
||
<Siren
|
||
size="1.25em"
|
||
class="mx-1 inline-block text-red-500"
|
||
/>
|
||
{/if}
|
||
|
||
{#if journals_journal_entry_obj.priority}
|
||
<Flag
|
||
size="1.25em"
|
||
class="mx-1 inline-block text-yellow-500"
|
||
/>
|
||
{/if}
|
||
|
||
{#if journals_journal_entry_obj.group}
|
||
<Group
|
||
size="1.25em"
|
||
class="mx-1 inline-block text-green-500"
|
||
/>
|
||
<span class="text-xs text-gray-500 hidden"
|
||
>Group:</span
|
||
>
|
||
<span
|
||
class="font-semibold text-sm text-gray-500 hidden md:inline"
|
||
>
|
||
{journals_journal_entry_obj.group}
|
||
</span>
|
||
{/if}
|
||
</span>
|
||
|
||
<h3
|
||
class:dim={journals_journal_entry_obj.hide}
|
||
class="journal__name h4"
|
||
>
|
||
{#if journals_journal_entry_obj.template}
|
||
<NotepadTextDashed
|
||
class="mx-1 inline-block text-neutral-800/60 dark:text-neutral-50/60"
|
||
/>
|
||
|
||
{@html journals_journal_entry_obj.name ??
|
||
'-- no name --'}
|
||
{:else if journals_journal_entry_obj.name}
|
||
<NotebookText
|
||
class="mx-1 inline-block text-neutral-800/60 dark:text-neutral-50/60"
|
||
/>
|
||
{@html journals_journal_entry_obj.name}
|
||
{:else}
|
||
<CalendarClock
|
||
class="mx-1 inline-block text-neutral-800/60 dark:text-neutral-50/60"
|
||
/>
|
||
{ae_util.iso_datetime_formatter(
|
||
journals_journal_entry_obj.created_on,
|
||
'datetime_iso_12_no_seconds'
|
||
)}
|
||
{/if}
|
||
</h3>
|
||
|
||
<span
|
||
class="flex flex-row flex-wrap gap-1 items-center justify-center"
|
||
>
|
||
{#if !journals_journal_entry_obj.private}
|
||
<!-- Button to copy the Markdown version -->
|
||
<button
|
||
type="button"
|
||
onclick={() => {
|
||
let tmp_entry_obj =
|
||
journals_journal_entry_obj;
|
||
|
||
navigator.clipboard
|
||
.writeText(tmp_entry_obj.content)
|
||
.then(() => {
|
||
alert(
|
||
'Markdown content copied to clipboard!'
|
||
);
|
||
})
|
||
.catch((error) => {
|
||
console.error(
|
||
'Failed to copy content:',
|
||
error
|
||
);
|
||
alert(
|
||
'Failed to copy content.'
|
||
);
|
||
});
|
||
}}
|
||
class:hidden={$lq__journal_obj?.cfg_json
|
||
?.hide_copy_plain_md}
|
||
class="btn btn-sm p-1 preset-tonal-surface hover:preset-filled-secondary-500 *:hover:inline text-xs lg:text-sm"
|
||
title="Copy the markdown content"
|
||
>
|
||
<RemoveFormatting size="1.25em" />
|
||
<span class="hidden">
|
||
Copy Plaintext Markdown
|
||
</span>
|
||
</button>
|
||
|
||
<!-- Button to copy the rendered to HTML version -->
|
||
<button
|
||
type="button"
|
||
onclick={() => {
|
||
let htmlContent =
|
||
journals_journal_entry_obj.content_md_html ||
|
||
'';
|
||
|
||
navigator.clipboard
|
||
.writeText(htmlContent)
|
||
.then(() => {
|
||
alert(
|
||
'Rendered HTML content copied to clipboard!'
|
||
);
|
||
})
|
||
.catch((error) => {
|
||
console.error(
|
||
'Failed to copy HTML content:',
|
||
error
|
||
);
|
||
alert(
|
||
'Failed to copy HTML content.'
|
||
);
|
||
});
|
||
}}
|
||
class:hidden={journals_journal_entry_obj.template ||
|
||
$lq__journal_obj?.cfg_json
|
||
?.hide_copy_html}
|
||
class="btn btn-sm p-1 preset-tonal-surface hover:preset-filled-secondary-500 *:hover:inline lg:text-xs"
|
||
title="Copy the rendered HTML content"
|
||
>
|
||
<CodeXml size="1.25em" />
|
||
<span class="hidden">
|
||
Copy HTML Markup
|
||
</span>
|
||
</button>
|
||
|
||
<!-- Button to copy the rich text (rendered HTML) version -->
|
||
<button
|
||
type="button"
|
||
onclick={async () => {
|
||
const element = document.getElementById(
|
||
`rendered_journal_entry_content_${journals_journal_entry_obj.journal_entry_id}`
|
||
);
|
||
if (!element) {
|
||
console.error(
|
||
'Element not found: rendered_journal_entry_content'
|
||
);
|
||
alert(
|
||
'Failed to copy rich content.'
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const htmlContent =
|
||
element.innerHTML;
|
||
await navigator.clipboard.write([
|
||
new ClipboardItem({
|
||
'text/html': new Blob(
|
||
[htmlContent],
|
||
{
|
||
type: 'text/html'
|
||
}
|
||
)
|
||
})
|
||
]);
|
||
|
||
alert(
|
||
'Rendered rich content copied to clipboard!'
|
||
);
|
||
} catch (error) {
|
||
console.error(
|
||
'Failed to copy rich content:',
|
||
error
|
||
);
|
||
alert(
|
||
'Failed to copy rich content.'
|
||
);
|
||
}
|
||
}}
|
||
class:hidden={journals_journal_entry_obj.template ||
|
||
$lq__journal_obj?.cfg_json
|
||
?.hide_copy_rich}
|
||
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"
|
||
>
|
||
<TypeOutline size="1.25em" />
|
||
<span class="hidden">Copy Rich Text</span>
|
||
</button>
|
||
|
||
<!-- Clone entry -->
|
||
<button
|
||
type="button"
|
||
onclick={() => {
|
||
let data_kv = {
|
||
code: journals_journal_entry_obj.code,
|
||
category_code:
|
||
journals_journal_entry_obj.category_code,
|
||
name: journals_journal_entry_obj.name,
|
||
short_name:
|
||
journals_journal_entry_obj.short_name,
|
||
content:
|
||
journals_journal_entry_obj.content,
|
||
description:
|
||
journals_journal_entry_obj.description,
|
||
tags: journals_journal_entry_obj.tags
|
||
};
|
||
|
||
journals_func
|
||
.create_ae_obj__journal_entry({
|
||
api_cfg: $ae_api,
|
||
journal_id:
|
||
journals_journal_entry_obj.journal_id,
|
||
data_kv: data_kv,
|
||
log_lvl: log_lvl
|
||
})
|
||
.then((result) => {
|
||
if (
|
||
result?.journal_id &&
|
||
result?.journal_entry_id
|
||
) {
|
||
alert(
|
||
'Journal entry cloned successfully!'
|
||
);
|
||
goto(
|
||
`/journals/${result.journal_id}/entry/${result.journal_entry_id}`
|
||
);
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
console.error(
|
||
'Error cloning journal entry:',
|
||
error
|
||
);
|
||
alert(
|
||
'Failed to clone journal entry.'
|
||
);
|
||
});
|
||
}}
|
||
class:hidden={!journals_journal_entry_obj.template}
|
||
class="btn btn-sm p-1 preset-tonal-surface hover:preset-filled-secondary-500 *:hover:inline lg:text-xs"
|
||
title="Clone this journal entry"
|
||
>
|
||
<Copy size="1.25em" />
|
||
<span class="hidden md:inline">Clone</span>
|
||
</button>
|
||
{:else}
|
||
<Lock
|
||
size="1.25em"
|
||
class="mx-1 inline-block text-red-400 dark:text-red-600"
|
||
/>
|
||
<span class="text-xs text-gray-500 hidden"
|
||
>Private</span
|
||
>
|
||
|
||
<!-- Button to copy the Markdown version -->
|
||
<button
|
||
type="button"
|
||
onclick={() => {
|
||
let tmp_entry_obj =
|
||
journals_journal_entry_obj;
|
||
|
||
navigator.clipboard
|
||
.writeText(
|
||
tmp_entry_obj.content_encrypted
|
||
)
|
||
.then(() => {
|
||
alert(
|
||
'Encrypted content copied to clipboard!'
|
||
);
|
||
})
|
||
.catch((error) => {
|
||
console.error(
|
||
'Failed to copy content:',
|
||
error
|
||
);
|
||
alert(
|
||
'Failed to copy content.'
|
||
);
|
||
});
|
||
}}
|
||
class:hidden={$lq__journal_obj?.cfg_json
|
||
?.hide_copy_encrypted}
|
||
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"
|
||
>
|
||
<Fingerprint size="1.25em" />
|
||
<span class="hidden"> Copy Encrypted </span>
|
||
</button>
|
||
{/if}
|
||
</span>
|
||
</span>
|
||
|
||
<div
|
||
class="flex flex-row flex-wrap gap-2 items-center justify-end"
|
||
>
|
||
<!-- Linked file count -->
|
||
<div
|
||
class="ae_linked_file_count flex flex-row flex-wrap gap-0.5 items-center justify-start"
|
||
class:hidden={!journals_journal_entry_obj?.data_json
|
||
?.hosted_file_kv}
|
||
>
|
||
<Files class="mx-1 inline-block" />
|
||
<span class="text-xs text-gray-500 hidden md:inline"
|
||
>Linked files:</span
|
||
>
|
||
<span class="font-semibold text-sm text-gray-500">
|
||
{journals_journal_entry_obj?.data_json
|
||
?.hosted_file_kv
|
||
? Object.keys(
|
||
journals_journal_entry_obj?.data_json
|
||
?.hosted_file_kv
|
||
).length
|
||
: 0}×
|
||
</span>
|
||
</div>
|
||
|
||
<!-- Tags for journal entry. Comma delimited list. -->
|
||
{#if journals_journal_entry_obj.tags && journals_journal_entry_obj.tags.length}
|
||
<div
|
||
class="tags flex flex-row flex-wrap gap-0.5 items-center justify-start p-1"
|
||
>
|
||
<Tags class="mx-1 inline-block" />
|
||
<span
|
||
class="text-xs text-gray-500 hidden md:inline"
|
||
>Tags:</span
|
||
>
|
||
|
||
{#each journals_journal_entry_obj.tags.split(',') as tag (tag)}
|
||
<span
|
||
class="btn btn-sm preset-tonal-tertiary hover:preset-tonal-tertiary border border-tertiary-500 transition py-1 px-2"
|
||
title={`Tag: ${tag.trim()}`}
|
||
>
|
||
{tag.trim()}
|
||
</span>
|
||
{/each}
|
||
</div>
|
||
{/if}
|
||
|
||
<!-- Category code for journal entry -->
|
||
{#if journals_journal_entry_obj.category_code}
|
||
<button
|
||
type="button"
|
||
onclick={() => {
|
||
if (
|
||
$journals_loc.entry
|
||
.qry__category_code ==
|
||
journals_journal_entry_obj.category_code
|
||
) {
|
||
$journals_loc.entry.qry__category_code =
|
||
null;
|
||
} else {
|
||
$journals_loc.entry.qry__category_code =
|
||
journals_journal_entry_obj.category_code;
|
||
}
|
||
if (
|
||
$journals_loc.entry.search_version ===
|
||
undefined
|
||
)
|
||
$journals_loc.entry.search_version = 0;
|
||
$journals_loc.entry.search_version++;
|
||
}}
|
||
class:bg-green-100={$journals_loc.entry
|
||
.qry__category_code ==
|
||
journals_journal_entry_obj.category_code}
|
||
class="btn btn-sm preset-outlined-secondary hover:preset-filled-secondary-500 transition py-1 px-2"
|
||
title={`Filter by category: ${journals_journal_entry_obj.category_code}`}
|
||
>
|
||
<Shapes class="mx-1 inline-block" />
|
||
{journals_journal_entry_obj.category_code ??
|
||
'-- no category --'}
|
||
</button>
|
||
{/if}
|
||
|
||
<a
|
||
href="/journals/{journals_journal_entry_obj?.journal_id ??
|
||
$lq__journal_obj?.journal_id}/entry/{journals_journal_entry_obj?.journal_entry_id}"
|
||
class="btn preset-tonal-primary border border-primary-500 hover:preset-filled-primary-500 transition"
|
||
title={`View ID: ${journals_journal_entry_obj?.id}
|
||
${journals_journal_entry_obj?.name ?? ae_util.iso_datetime_formatter(journals_journal_entry_obj.created_on, 'datetime_iso_12_no_seconds')}
|
||
Journal ID: ${journals_journal_entry_obj?.journal_id}
|
||
`}
|
||
>
|
||
<NotebookPen class="mx-1 inline-block" />
|
||
<span class="hidden md:inline"> View </span>
|
||
</a>
|
||
|
||
<!-- Button to show a modal that will allow for a quick append to Journal Entry option. -->
|
||
<button
|
||
type="button"
|
||
onclick={() => {
|
||
$journals_sess.show__modal_append__journal_entry_id =
|
||
journals_journal_entry_obj?.id;
|
||
tmp_entry_obj = JSON.parse(
|
||
JSON.stringify(journals_journal_entry_obj)
|
||
);
|
||
}}
|
||
class="btn btn-icon btn-sm preset-tonal-surface border border-surface-500 hover:preset-filled-secondary-500 transition"
|
||
title={$lq__journal_obj?.cfg_json?.entry_add_text ==
|
||
'append'
|
||
? 'Append to Journal Entry'
|
||
: 'Prepend to Journal Entry'}
|
||
>
|
||
<ListPlus />
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
{#if journals_journal_entry_obj.content}
|
||
<div
|
||
class:hidden={journals_journal_entry_obj.hide ||
|
||
(journals_journal_entry_obj.private &&
|
||
$journals_slct.journal_obj?.cfg_json
|
||
.hide_private) ||
|
||
(journals_journal_entry_obj.personal &&
|
||
$journals_slct.journal_obj?.cfg_json
|
||
.hide_personal) ||
|
||
(journals_journal_entry_obj.professional &&
|
||
$journals_slct.journal_obj?.cfg_json
|
||
.hide_professional)}
|
||
class="journal__content
|
||
w-full p-1
|
||
bg-slate-100 text-gray-900
|
||
dark:bg-slate-900 dark:text-gray-100
|
||
shadow-lg rounded-lg
|
||
border border-gray-200 dark:border-gray-700
|
||
text-wrap text-sm font-mono whitespace-pre-wrap
|
||
transition-all
|
||
delay-1000 hover:delay-1000 active:delay-100
|
||
duration-1000 hover:duration-200 active:duration-200
|
||
ease-in-out
|
||
active:z-10
|
||
hover:bg-blue-100 dark:hover:bg-blue-950 hover:border-blue-500 dark:hover:border-blue-500
|
||
overflow-scroll
|
||
{$journals_slct.journal_obj.cfg_json.entry_li_max_height
|
||
? `${$journals_slct.journal_obj.cfg_json.entry_li_max_height}`
|
||
: ''}
|
||
|
||
{$journals_slct.journal_obj.cfg_json
|
||
.entry_li_click_max_height
|
||
? `${$journals_slct.journal_obj.cfg_json.entry_li_click_max_height}`
|
||
: ''}
|
||
|
||
{$journals_slct.journal_obj.cfg_json
|
||
.entry_li_hover_max_height
|
||
? `${$journals_slct.journal_obj.cfg_json.entry_li_hover_max_height}`
|
||
: ''}
|
||
"
|
||
>
|
||
{@html journals_journal_entry_obj.content}
|
||
</div>
|
||
|
||
<article
|
||
class="prose hidden"
|
||
id="rendered_journal_entry_content_{journals_journal_entry_obj.journal_entry_id}"
|
||
>
|
||
{@html journals_journal_entry_obj?.content_md_html}
|
||
</article>
|
||
{/if}
|
||
|
||
<section
|
||
class:hidden={!journals_journal_entry_obj?.original_datetime &&
|
||
!journals_journal_entry_obj?.original_timezone}
|
||
class="ae_section journal_entry__entry"
|
||
>
|
||
<div
|
||
class="ae_group"
|
||
class:hidden={!journals_journal_entry_obj?.original_datetime &&
|
||
!journals_journal_entry_obj?.original_timezone}
|
||
>
|
||
<span class="ae_label text-sm">Original date/time:</span
|
||
>
|
||
{#if journals_journal_entry_obj.original_datetime}
|
||
<span
|
||
class="ae_value ae_prop prop_original_datetime font-semibold"
|
||
>{ae_util.iso_datetime_formatter(
|
||
journals_journal_entry_obj.original_datetime,
|
||
'datetime_12_long'
|
||
)}</span
|
||
>
|
||
{/if}
|
||
{#if journals_journal_entry_obj.original_timezone}
|
||
<span class="ae_label text-sm">Timezone:</span>
|
||
<span class="ae_value font-semibold"
|
||
>{journals_journal_entry_obj.original_timezone}</span
|
||
>
|
||
{/if}
|
||
</div>
|
||
</section>
|
||
|
||
<section
|
||
class="ae_meta mt-2 flex flex-col sm:flex-row gap-2 items-center justify-center text-xs text-gray-500"
|
||
>
|
||
<span
|
||
class:hidden={!$ae_loc.trusted_access ||
|
||
!$ae_loc.edit_mode}
|
||
class="flex flex-row gap-1 items-center justify-center"
|
||
>
|
||
<span class="journal_entry__created_on">
|
||
Created:
|
||
{ae_util.iso_datetime_formatter(
|
||
journals_journal_entry_obj.created_on,
|
||
'datetime_12_long'
|
||
)}
|
||
</span>
|
||
<span
|
||
class:hidden={!journals_journal_entry_obj.updated_on}
|
||
class="journal_entry__updated_on"
|
||
>
|
||
Last update:
|
||
{ae_util.iso_datetime_formatter(
|
||
journals_journal_entry_obj.updated_on,
|
||
'datetime_12_long'
|
||
)}
|
||
</span>
|
||
</span>
|
||
|
||
<!-- Set/unset hide (boolean) -->
|
||
<button
|
||
type="button"
|
||
onclick={() => {
|
||
let data_kv = {
|
||
hide: journals_journal_entry_obj?.hide
|
||
? false
|
||
: true
|
||
};
|
||
journals_func
|
||
.update_ae_obj__journal_entry({
|
||
api_cfg: $ae_api,
|
||
journal_entry_id:
|
||
journals_journal_entry_obj.journal_entry_id,
|
||
data_kv: data_kv,
|
||
log_lvl: log_lvl
|
||
})
|
||
.then(() => {})
|
||
.catch((error) => {
|
||
console.error(
|
||
'Error updating journal entry:',
|
||
error
|
||
);
|
||
alert('Failed to update journal entry.');
|
||
});
|
||
}}
|
||
class:hidden={!$ae_loc.edit_mode}
|
||
class="btn btn-sm preset-tonal-surface hover:preset-filled-warning-500 transition py-1 px-2"
|
||
title={`Set entry as ${journals_journal_entry_obj.hide ? 'visible' : 'hidden'}`}
|
||
>
|
||
{#if journals_journal_entry_obj.hide}
|
||
<EyeOff
|
||
strokeWidth="1"
|
||
color="hsla( 0, 100%, 50%, .5)"
|
||
class="inline-block"
|
||
/>
|
||
<span class="hidden md:inline">Hidden</span>
|
||
{:else}
|
||
<Eye
|
||
strokeWidth="2.5"
|
||
color="hsla( 120, 100%, 25%, .5)"
|
||
class="inline-block"
|
||
/>
|
||
<span class="hidden lg:inline">Visible</span>
|
||
{/if}
|
||
</button>
|
||
</section>
|
||
</div>
|
||
{/each}
|
||
|
||
<!-- Modal for quick append to Journal Entry -->
|
||
{#if $journals_sess.show__modal_append__journal_entry_id}
|
||
<AeCompModalJournalEntryAppend
|
||
bind:open={show_append_modal}
|
||
journal_entry={tmp_entry_obj}
|
||
journal_config={$lq__journal_obj?.cfg_json}
|
||
on_close={handle_modal_close}
|
||
on_update={handle_modal_update}
|
||
{log_lvl}
|
||
/>
|
||
{/if}
|
||
{:else}
|
||
<div
|
||
class="flex flex-col items-center justify-center p-10 opacity-50 text-center"
|
||
>
|
||
<BookOpenText size="3em" class="mb-2 opacity-20 mx-auto" />
|
||
<p>
|
||
No Journal Entry available to show. Please check the query
|
||
filters or create a new Entry.
|
||
</p>
|
||
</div>
|
||
{/if}
|
||
</section>
|