Files
OSIT-AE-App-Svelte/src/routes/journals/ae_comp__journal_entry_obj_li.svelte
2025-04-02 16:36:10 -04:00

442 lines
20 KiB
Svelte

<script lang="ts">
let log_lvl: number = 1;
// *** Import Svelte specific
import { goto, invalidate, pushState, replaceState } from '$app/navigation';
import {
CalendarClock, CodeXml, Copy,
Eye, EyeOff,
Flag, FlagOff,
NotebookPen, NotebookText, NotepadTextDashed,
RemoveFormatting,
Shapes, Siren,
Tags, TypeOutline
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
import type { key_val } from '$lib/ae_stores';
import { ae_util } from '$lib/ae_utils/ae_utils';
import { api } from '$lib/api';
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { journals_loc, journals_sess, journals_slct, journals_trig } from '$lib/ae_journals/ae_journals_stores';
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
interface Props {
lq__journal_entry_obj_li: any;
}
let { lq__journal_entry_obj_li }: Props = $props();
let ae_promises: key_val = $state({});
// let ae_tmp: key_val = {};
// let ae_triggers: key_val = {};
let tmp_entry_obj: key_val = $state({});
</script>
<section class="journal_list flex flex-col gap-2 items-center justify-center w-full">
{#if $lq__journal_entry_obj_li && $lq__journal_entry_obj_li.length}
<!-- <div class="ae_group">
<span class="ae_label">Group:</span>
<span class="ae_value">{current_group}</span> -->
{#each $lq__journal_entry_obj_li as journals_journal_entry_obj, index}
<div
class="container journal journal_entry_obj border border-1 p-2 mb-2 space-y-2 w-full max-w-screen-lg flex flex-col items-center justify-center bg-white rounded-lg"
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">
<h3
class:dim={journals_journal_entry_obj.hide}
class="journal__name h4"
>
<span class="journal_entry__name">
{#if (journals_journal_entry_obj.alert)}
<Siren class="mx-1 inline-block text-red-500"/>
{/if}
{#if (journals_journal_entry_obj.priority)}
<Flag class="mx-1 inline-block text-yellow-500"/>
{/if}
{#if journals_journal_entry_obj.template}
<NotepadTextDashed class="mx-1 inline-block" />
{@html journals_journal_entry_obj.name ?? '-- no name --'}
{:else if (journals_journal_entry_obj.name)}
<NotebookText class="mx-1 inline-block" />
{@html journals_journal_entry_obj.name}
{:else}
<CalendarClock class="mx-1 inline-block" />
{ae_util.iso_datetime_formatter(journals_journal_entry_obj.created_on, 'datetime_iso_12_no_seconds')}
{/if}
</span>
</h3>
<!-- 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={journals_journal_entry_obj.template}
class="btn btn-sm p-1 variant-soft-secondary hover:variant-filled-secondary *:hover:inline lg:text-xs"
title="Copy the markdown content"
>
<!-- <span class="fas fa-copy mx-1"></span> -->
<Copy size="1em" />
<RemoveFormatting size="2em" />
<span class="hidden">
Copy Plaintext Markdown
</span>
</button>
<!-- Button to copy the rendered to HTML version -->
<button
type="button"
onclick={() => {
// Copy the rendered HTML content to clipboard
// const htmlContent = $lq__journal_entry_obj?.content_md_html || '';
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}
class="btn btn-sm p-1 variant-soft-secondary hover:variant-filled-secondary *:hover:inline lg:text-xs"
title="Copy the rendered HTML content"
>
<!-- <span class="fas fa-copy mx-1"></span> -->
<Copy size="1em" />
<CodeXml size="2em" />
<span class="hidden">
Copy Rendered HTML
</span>
</button>
<!-- Clone entry -->
<button
type="button"
onclick={() => {
// Clone the journal entry
// We only want to clone certain fields from the original journal entry object to avoid conflicts.
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) => {
alert('Journal entry cloned successfully!');
goto(`/journals/${result.journal_id_random}/entry/${result.journal_entry_id_random}`);
}).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 variant-soft-secondary hover:variant-filled-secondary *:hover:inline lg:text-xs"
title="Clone this journal entry"
>
<!-- class="btn btn-sm variant-soft-surface hover:variant-filled-warning transition py-1 px-2" -->
<!-- <Copy strokeWidth="1" /> -->
<Copy size="2em" />
<span class="hidden md:inline">Clone</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 {
// 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], { 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="btn btn-sm p-1 variant-soft-secondary *:hover:inline lg:text-xs"
title="Copy the rich text (rendered HTML) content"
>
<Copy size="1em" />
<TypeOutline size="2em" />
<span class="hidden">Copy Rich Text</span>
</button>
</span>
<div class="flex flex-row flex-wrap gap-2 items-center justify-end">
<!-- Tags for journal entry. Comma delimited list. -->
{#if journals_journal_entry_obj.tags && journals_journal_entry_obj.tags.length}
<div class="tags flex flex-wrap gap-1 items-center justify-start p-1">
<Tags class="mx-1 inline-block"/>
<span class="text-sm text-gray-500 hidden md:inline">Tags:</span>
{#each journals_journal_entry_obj.tags.split(',') as tag}
<span
class="btn btn-sm variant-glass-tertiary hover:variant-ghost-tertiary 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}
<!-- When clicked, this will filter by the category code. -->
<button
type="button"
onclick={() => {
if ($journals_loc.filter__category_code == journals_journal_entry_obj.category_code) {
$journals_loc.filter__category_code = null;
} else {
$journals_loc.filter__category_code = journals_journal_entry_obj.category_code;
// We also want to set the category code used when creating a new journal entry.
$journals_loc.qry__category_code = journals_journal_entry_obj.category_code;
}
$journals_trig.journal_entry_li = true;
if (log_lvl) {
console.log('$journals_loc.filter__category_code', $journals_loc.filter__category_code);
}
}}
class="btn btn-sm variant-outline-secondary hover:variant-filled-secondary 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}/entry/{journals_journal_entry_obj?.journal_entry_id}"
class="btn btn-secondary variant-ghost-primary hover:variant-filled-primary transition"
title={`View ID: ${journals_journal_entry_obj?.id}\n${journals_journal_entry_obj?.name ?? ae_util.iso_datetime_formatter(journals_journal_entry_obj.created_on, 'datetime_iso_12_no_seconds')}`}
>
<NotebookPen class="mx-1 inline-block"/>
<span class="hidden md:inline">
View
</span>
</a>
</div>
</header>
{#if journals_journal_entry_obj.content}
<div
class:hidden={journals_journal_entry_obj.hide}
class="
journal__content w-full p-2 bg-white shadow-md rounded-lg text-wrap text-sm font-mono whitespace-pre-wrap
{$journals_slct.journal_obj.cfg_json.entry_li_max_height ? `${$journals_slct.journal_obj.cfg_json.entry_li_max_height} overflow-scroll` : ''}
"
>
{@html journals_journal_entry_obj.content}
</div>
<!-- This needs to remain hidden for the copy function to work and us not seeing the rendered HTML version. -->
<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}
<!-- <div class="ae_options flex flex-row flex-wrap gap-2 items-center justify-center"> -->
<!-- <a
href="/journals/{journals_journal_entry_obj?.journal_id}/entry/{journals_journal_entry_obj?.journal_entry_id}"
class="btn btn-secondary btn-md variant-ghost-primary hover:variant-filled-primary transition"
title={`View: ${journals_journal_entry_obj?.name}`}
>
<NotebookText class="m-1"/> View
</a> -->
<!-- {#if $ae_loc.trusted_access && $ae_loc.edit_mode}
<button
type="button"
disabled={!$ae_loc.trusted_access}
onclick={() => {
$journals_slct.journal_entry_id = journals_journal_entry_obj.journal_entry_id;
$journals_slct.journal_entry_obj = journals_journal_entry_obj;
$journals_sess.show__modal_view__journal_entry_id = false;
$journals_sess.show__modal_edit__journal_entry_id = $journals_slct.journal_entry_id;
}}
class="novi_btn btn btn-sm variant-glass-warning hover:variant-filled-warning transition"
title={`Edit journal entry: ${journals_journal_entry_obj?.name}`}
>
<span class="fas fa-edit m-1"></span> Edit
</button>
{/if} -->
<!-- </div> -->
<section class="ae_section journal_entry__entry">
<!-- {#if journals_journal_entry_obj?.description}
<div
class="journal_entry__description ae_description"
>
<div class="ae_label journal_entry__description text-sm">Description:</div>
<div class="ae_value journal_entry__description">
{@html journals_journal_entry_obj?.description}
</div>
</div>
{/if} -->
<!-- {#if journals_journal_entry_obj?.entry_html}
<div
class="journal_entry__entry_html ae_entry_html"
>
<div class="ae_label journal_entry__entry_html text-sm">Content:</div>
<div class="ae_value journal_entry__entry_html">
{@html journals_journal_entry_obj?.entry_html}
</div>
</div>
{/if} -->
<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="journal_entry__journal_entry_type"
class:hidden={!journals_journal_entry_obj.journal_entry_type}
>
Type: {journals_journal_entry_obj.journal_entry_type}
</span> -->
<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="journal_entry__updated_on"
class:hidden={!journals_journal_entry_obj.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(() => {
// Optionally, you can provide feedback to the user
// alert('Journal entry updated successfully!');
}).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 variant-soft-surface hover:variant-filled-warning 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}
<!-- </div> -->
{:else}
<p>No journal entry available to show.</p>
{/if}
</section>
<!-- {/if} -->