- ae_comp__journal_obj_li: compact tap-target rows, glow wrapper, plain gray dark mode (no Skeleton paired utils) - +page.svelte (journals index): fix 'Managed by Account Name Not Set' bug, responsive spacing, glow on quick-add - ae_comp__journal_obj_id_view: glow wrapper, explicit bg-white/dark:bg-gray-900, remove broken dynamic color class - ae_comp__journal_entry_obj_li: glow wrapper, left-accent border on cards, fix dark mode hover - ae_comp__journal_entry_obj_id_view: glow wrapper, consistent gray dark mode, edit-mode ring indicator - ae_comp__journal_entry_header: replace Skeleton surface vars with plain grays (dark mode fix) - e_app_theme: fix theme selector panel readability in dark mode
286 lines
9.4 KiB
Svelte
286 lines
9.4 KiB
Svelte
<script lang="ts">
|
|
// *** Import Svelte specific
|
|
import { goto } from '$app/navigation';
|
|
|
|
// *** Import other supporting libraries
|
|
import {
|
|
BookPlus,
|
|
BookOpenText,
|
|
FilePlus,
|
|
Menu,
|
|
Pencil,
|
|
FileDown,
|
|
FileUp,
|
|
Settings,
|
|
LoaderCircle
|
|
} from 'lucide-svelte';
|
|
|
|
// *** Import Aether specific variables and functions
|
|
import { ae_util } from '$lib/ae_utils/ae_utils';
|
|
import {
|
|
ae_snip,
|
|
ae_loc,
|
|
ae_sess,
|
|
ae_api,
|
|
ae_trig,
|
|
slct,
|
|
slct_trigger
|
|
} from '$lib/stores/ae_stores';
|
|
import {
|
|
journals_loc,
|
|
journals_sess,
|
|
journals_slct,
|
|
journals_trig,
|
|
journals_prom
|
|
} from '$lib/ae_journals/ae_journals_stores';
|
|
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
|
|
import Journal_obj_id_edit from './ae_comp__journal_obj_id_edit.svelte';
|
|
|
|
interface Props {
|
|
log_lvl?: number;
|
|
lq__journal_obj: any;
|
|
lq__journal_entry_obj_li: any;
|
|
on_show_export?: () => void;
|
|
on_show_import?: () => void;
|
|
}
|
|
|
|
let {
|
|
log_lvl = 0,
|
|
lq__journal_obj,
|
|
lq__journal_entry_obj_li,
|
|
on_show_export,
|
|
on_show_import
|
|
}: Props = $props();
|
|
|
|
// let ae_promises: key_val = {};
|
|
// let ae_tmp: key_val = {};
|
|
// let ae_trigger: any = null;
|
|
// let ae_triggers: key_val = {};
|
|
|
|
let typed_journal_passcode: string = $state('');
|
|
let passcode_timer: any = $state(null);
|
|
|
|
$effect(() => {
|
|
if (typed_journal_passcode?.length > 4) {
|
|
if (!$journals_sess?.journal_kv) {
|
|
$journals_sess.journal_kv = {};
|
|
}
|
|
if (!$journals_sess.journal_kv[$lq__journal_obj?.id]) {
|
|
$journals_sess.journal_kv[$lq__journal_obj?.id] = {};
|
|
}
|
|
|
|
verify_journal_passcode();
|
|
}
|
|
|
|
// We need to set a timeout to force the user to re-enter their private passcode
|
|
if (
|
|
$lq__journal_obj?.id &&
|
|
$journals_sess?.journal_kv[$lq__journal_obj?.id] &&
|
|
$journals_sess?.journal_kv[$lq__journal_obj?.id]
|
|
?.journal_passcode_verified
|
|
) {
|
|
if (passcode_timer) {
|
|
if (log_lvl) {
|
|
console.log('Passcode timer already set');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Use journal.passcode_timeout (assuming it's in minutes, default to 5)
|
|
const timeout_minutes = $lq__journal_obj?.passcode_timeout ?? 5;
|
|
const timeout_ms = 1000 * 60 * timeout_minutes;
|
|
|
|
if (log_lvl) {
|
|
console.log(
|
|
`Setting passcode timer for ${timeout_minutes} minutes (${timeout_ms}ms)`
|
|
);
|
|
}
|
|
|
|
passcode_timer = setTimeout(() => {
|
|
if (log_lvl) {
|
|
console.log('Passcode timer expired');
|
|
}
|
|
typed_journal_passcode = '';
|
|
if (!$journals_sess?.journal_kv[$lq__journal_obj?.id]) {
|
|
$journals_sess.journal_kv[$lq__journal_obj?.id] = {};
|
|
}
|
|
|
|
// Reset verification and decryption flags
|
|
$journals_sess.journal_kv[
|
|
$lq__journal_obj?.id
|
|
].journal_passcode_verified = false;
|
|
$journals_sess.journal_kv[
|
|
$lq__journal_obj?.id
|
|
].journal_passcode_decrypted = false;
|
|
|
|
passcode_timer = null;
|
|
}, timeout_ms);
|
|
}
|
|
});
|
|
|
|
function verify_journal_passcode() {
|
|
if (log_lvl) {
|
|
console.log(
|
|
`verify_journal_passcode: typed_journal_passcode = ${typed_journal_passcode} journal private passcode = ${$lq__journal_obj?.private_passcode}`
|
|
);
|
|
}
|
|
|
|
if (typed_journal_passcode === $lq__journal_obj?.private_passcode) {
|
|
console.log('Matched journal private passcode');
|
|
if (!$journals_sess?.journal_kv[$lq__journal_obj?.id]) {
|
|
$journals_sess.journal_kv[$lq__journal_obj?.id] = {};
|
|
}
|
|
$journals_sess.journal_kv[$lq__journal_obj?.id] = {
|
|
typed_journal_passcode: typed_journal_passcode,
|
|
journal_passcode_verified: true
|
|
};
|
|
|
|
typed_journal_passcode = '';
|
|
} else {
|
|
}
|
|
}
|
|
|
|
async function handle_new_entry() {
|
|
let data_kv = {
|
|
category_code: null
|
|
};
|
|
if ($journals_loc.entry.qry__category_code) {
|
|
data_kv.category_code = $journals_loc.entry.qry__category_code;
|
|
}
|
|
|
|
try {
|
|
const results = await journals_func.create_ae_obj__journal_entry({
|
|
api_cfg: $ae_api,
|
|
journal_id: $lq__journal_obj?.journal_id,
|
|
data_kv: data_kv,
|
|
log_lvl: log_lvl
|
|
});
|
|
|
|
if (results?.journal_entry_id) {
|
|
$journals_slct.journal_entry_id =
|
|
results.journal_entry_id;
|
|
$journals_loc.entry.edit_kv[$journals_slct.journal_entry_id] =
|
|
'current';
|
|
goto(
|
|
`/journals/${$lq__journal_obj?.journal_id}/entry/${results.journal_entry_id}`
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error creating journal entry:', error);
|
|
alert('Failed to create new journal entry.');
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="relative group/view w-full mx-2 my-1">
|
|
<!-- Glow ring — mirrors Quick Add and Journal List -->
|
|
<div
|
|
class="absolute -inset-1 bg-linear-to-r from-primary-500 to-secondary-500
|
|
rounded-2xl blur opacity-10 dark:opacity-20
|
|
group-hover/view:opacity-25 dark:group-hover/view:opacity-35
|
|
transition duration-700 pointer-events-none"
|
|
></div>
|
|
<section
|
|
class="relative rounded-xl p-3 w-full
|
|
flex flex-col gap-2 items-center justify-center
|
|
bg-white dark:bg-gray-900
|
|
border border-gray-200 dark:border-gray-700
|
|
text-gray-900 dark:text-gray-100
|
|
shadow-xl"
|
|
bind:clientHeight={$ae_loc.iframe_height_modal_body}
|
|
>
|
|
<header
|
|
class="ae_header journal__header flex flex-row flex-wrap gap-2 items-center justify-between w-full"
|
|
>
|
|
<h2 class="journal__name h3 text-center">
|
|
<BookOpenText class="inline-block text-primary-500/80" />
|
|
{@html $lq__journal_obj?.name ?? 'Loading...'}
|
|
|
|
{#if $ae_loc.edit_mode}
|
|
<span
|
|
class="badge preset-tonal-success font-bold text-lg px-2 ml-2"
|
|
title="Entries matching current filters"
|
|
>
|
|
{$lq__journal_entry_obj_li?.length ?? '0'}<span
|
|
class="text-xs opacity-50 ml-0.5">×</span
|
|
>
|
|
</span>
|
|
{/if}
|
|
|
|
{#await $journals_prom.load__journal_entry_obj_li}
|
|
<LoaderCircle
|
|
size="1em"
|
|
class="inline-block animate-spin ml-1 text-primary-500"
|
|
/>
|
|
{/await}
|
|
</h2>
|
|
|
|
<div
|
|
class="grow flex flex-row flex-wrap gap-2 items-center justify-end"
|
|
>
|
|
<!-- Simplified Config Trigger -->
|
|
<button
|
|
type="button"
|
|
onclick={() =>
|
|
($journals_sess.show__modal_edit__journal_obj = true)}
|
|
class="btn preset-tonal-secondary py-1 px-3 shadow-md"
|
|
title="Journal Config & Actions"
|
|
>
|
|
<Settings size="1.2em" class="mr-2" />
|
|
<span class="hidden md:inline">Config</span>
|
|
</button>
|
|
|
|
<!-- Passcode Verification (Condensed) -->
|
|
{#if !$journals_sess?.journal_kv[$lq__journal_obj?.id]?.journal_passcode_verified}
|
|
<div class="flex gap-1">
|
|
<input
|
|
autocomplete="off"
|
|
type="text"
|
|
bind:value={typed_journal_passcode}
|
|
placeholder="Passcode"
|
|
class="input input-sm w-32"
|
|
/>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Show Journal description -->
|
|
{#if $lq__journal_obj?.description && $ae_loc.edit_mode}
|
|
<div
|
|
class="
|
|
prose
|
|
space-y-1
|
|
p-2
|
|
w-full max-w-(--breakpoint-sm) md:max-w-(--breakpoint-md)
|
|
font-mono
|
|
bg-gray-50 text-gray-900
|
|
dark:bg-gray-800 dark:text-gray-100
|
|
shadow-md rounded-lg
|
|
text-sm font-normal text-wrap word-break
|
|
|
|
prose-p:m-0 prose-p:p-0
|
|
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
|
|
"
|
|
>
|
|
{@html $lq__journal_obj.description_md_html}
|
|
</div>
|
|
{/if}
|
|
</section>
|
|
</div>
|
|
|
|
<!-- Standardized Journal Action/Config Modal -->
|
|
<Journal_obj_id_edit
|
|
{log_lvl}
|
|
{lq__journal_obj}
|
|
bind:show={$journals_sess.show__modal_edit__journal_obj}
|
|
on_new_entry={handle_new_entry}
|
|
{on_show_export}
|
|
{on_show_import}
|
|
/>
|