Files
OSIT-AE-App-Svelte/src/routes/journals/+layout.svelte
2026-03-24 12:25:22 -04:00

409 lines
14 KiB
Svelte

<script lang="ts">
/** @type {import('./$types').LayoutProps} */
let log_lvl = $state(0);
// *** Import Svelte specific
import { untrack } from 'svelte';
// import { browser } from '$app/environment';
import { goto } from '$app/navigation';
// *** Import other supporting libraries
import {
ArrowDownUp,
ArrowRight,
House,
RefreshCw,
Satellite
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
import { ae_loc, ae_sess, ae_api, slct } from '$lib/stores/ae_stores';
import {
journals_loc,
journals_slct,
journals_trig
} from '$lib/ae_journals/ae_journals_stores';
import Element_data_store from '$lib/elements/element_data_store.svelte';
import Help_tech from '$lib/app_components/e_app_help_tech.svelte';
// *** Setup Svelte properties
interface Props {
data: any;
children: any;
}
let { data, children }: Props = $props();
// Use effects for store initializations to prevent render-phase updates
$effect(() => {
untrack(() => {
if ($slct.account_id !== data.account_id) {
$slct.account_id = data.account_id;
}
});
});
let ae_acct = $derived(data[data.account_id]);
$effect(() => {
if (ae_acct) {
untrack(() => {
if ($journals_slct.journal_id !== ae_acct.slct.journal_id) {
$journals_slct.journal_id = ae_acct.slct.journal_id;
}
if (
JSON.stringify($journals_slct.journal_obj_li) !==
JSON.stringify(ae_acct.slct.journal_obj_li)
) {
$journals_slct.journal_obj_li = ae_acct.slct.journal_obj_li;
}
});
}
});
let nav_y_height = $state(0);
let box: any = $state(null);
let xLeft = $state(0);
let xScroll = $state(0);
let xWidth = $state(0);
let yTop = $state(0);
let yScroll = $state(0);
let yHeight = $state(0);
function handle_scroll() {
// console.log(`handle_scroll() called`);
if (box) {
xLeft = box.scrollLeft;
xScroll = box.scrollWidth;
xWidth = box.clientWidth;
yTop = box.scrollTop;
yHeight = box.clientHeight;
yScroll = box.scrollHeight;
// console.log(`handle_scroll() called: ${yTop}`);
}
}
function scroll_container() {
return (
document.getElementById('ae_main_content') ||
document.documentElement ||
document.body
);
}
</script>
<svelte:head>
<title>Journals - {$journals_loc.title ?? 'Æ loading...'}</title>
</svelte:head>
{#if $ae_loc.user_id && $ae_loc.person_id && $ae_loc.trusted_access}
<!-- These are needed: h-full overflow-auto -->
<div
id="ae_main_content"
bind:clientHeight={$ae_loc.iframe_height}
bind:this={box}
onscroll={handle_scroll}
class:iframe={$ae_loc?.iframe}
class="
ae_journals
m-auto flex h-full
max-h-full
max-w-7xl flex-col gap-1
overflow-auto
bg-gray-50 text-gray-800
dark:bg-gray-900 dark:text-gray-200
">
<!-- class:hidden={yTop > 200} -->
<nav
bind:clientHeight={nav_y_height}
class:hidden={yTop > 600}
class:opacity-0={yTop > 250}
class="
submenu
absolute
top-0
right-0 left-0 z-20 m-auto
flex min-h-12
w-full
max-w-7xl flex-row flex-wrap items-center
justify-around gap-1 rounded-b-lg
border-b-2 bg-gray-200 p-1
px-2
pb-2 transition-all
duration-1000 hover:opacity-100
sm:justify-between dark:bg-gray-800
">
<span class="justify-self-start">
<!-- Be sure to explain what &AElig; (Aether) means in the title text or similar! -->
<Satellite
size="1.5em"
class="mx-1 inline-block text-gray-500" />
<abbr title="Aether - Journals Module"> Æ Journals </abbr>
</span>
<a
href="/"
class="btn btn-sm preset-tonal-surface border-surface-500 hover:preset-filled-success-500 border">
<House />
<span class="hidden md:inline"> Home </span>
</a>
<!-- <a href="/about" class="btn btn-sm">About</a> -->
<!-- <a href="/settings" class="btn btn-sm">Settings</a> -->
<button
type="button"
onclick={() => {
if ($ae_loc.edit_mode) {
// Confirm before clearing
if (
!confirm(
'Are you sure you want to clear IndexedDB databases, localStorage, and sessionStorage? This will also reload the page.'
)
) {
return;
}
console.log(
'Clearing IndexedDB, localStorage, sessionStorage, and reloading the page...'
);
// Clear Indexed DB
indexedDB.deleteDatabase('ae_archives_db'); // Archives module
indexedDB.deleteDatabase('ae_core_db');
indexedDB.deleteDatabase('ae_events_db'); // Events module
indexedDB.deleteDatabase('ae_journals_db'); // Journals module
indexedDB.deleteDatabase('ae_posts_db'); // Posts module
indexedDB.deleteDatabase('ae_sponsorships_db'); // Sponsorships module
// Clear localStorage and sessionStorage
// Clearing the localStorage will force it to be re-created.
localStorage.clear();
sessionStorage.clear();
goto('/', { invalidateAll: true });
// window.location.reload(true);
} else {
// Confirm before clearing
if (
!confirm(
'Are you sure you want to clear IndexedDB databases and some caches? This will also reload the page.'
)
) {
return;
}
console.log(
'Clearing IndexedDB, localStorage, sessionStorage, and reloading the page...'
);
// Clear Indexed DB
indexedDB.deleteDatabase('ae_archives_db'); // Archives module
indexedDB.deleteDatabase('ae_core_db');
indexedDB.deleteDatabase('ae_events_db'); // Events module
indexedDB.deleteDatabase('ae_journals_db'); // Journals module
indexedDB.deleteDatabase('ae_posts_db'); // Posts module
indexedDB.deleteDatabase('ae_sponsorships_db'); // Sponsorships module
window.location.reload();
}
// This does not seem to work fast enough or something?
// goto('/', {invalidateAll: true});
// The page does usually seem to reload correctly?
// window.location.reload(true); // true only works with Firefox
// alert('Local and Session Storage cleared and Indexed DBs deleted. You will probably want to refresh the page.');
}}
class="btn btn-sm preset-tonal-surface border-surface-500 hover:preset-filled-warning-500 border"
title="Clear App Data & Settings: Clear IndexedDB and reload. If in edit mode localStorage and sessionStorage will also be cleared.">
<!-- <span class="fas fa-eraser mx-1"></span> -->
<!-- <span class="fas fa-sync mx-1"></span> -->
<RefreshCw />
<span class="hidden md:inline">Clear & Reload</span>
</button>
<Help_tech
e_class=""
e_class_form_hidden=""
e_class_form_showing="min-w-full"
btn_class=""
show_btn_class="btn-info"
additional_kv={{
test: true
}}></Help_tech>
</nav>
<!-- Add overflow-auto to section element to have the main nav sort of sticky at top -->
<section
class:iframe={$ae_loc?.iframe}
class:pt-12={nav_y_height <= 50}
class:pt-20={nav_y_height > 50 && nav_y_height <= 100}
class:pt-32={nav_y_height > 100 && nav_y_height <= 150}
class:pt-40={nav_y_height > 150 && nav_y_height <= 200}
class="
main_content
grow
px-1 pb-48
md:px-2
">
{@render children?.()}
</section>
<div
class:hidden={yTop < 500}
class="
fixed
right-1
bottom-48 z-20 flex
flex-col items-end justify-end gap-1 hover:opacity-100
">
<!-- Scroll to top button -->
<button
type="button"
class="
ae_btn_success_outlined
btn btn-sm btn-secondary
preset-tonal-surface
transition-all duration-500
"
class:hidden={yTop < 500}
class:opacity-80={yTop > 750}
class:opacity-0={yTop < 750}
class:ae_btn_warning_filled={yTop > 1500}
onclick={() => {
if (log_lvl) {
console.log(
`Scroll to top button clicked. yScroll: ${yScroll} scrollTop: ${scroll_container().scrollTop}`,
scroll_container()
);
}
console.log('Not Safari, using smooth scroll to top');
document.getElementById('ae_main_content')?.scrollTo({
top: 0,
behavior: 'smooth'
});
window.parent.postMessage({ scroll_to: 0 }, '*');
}}
title="Scroll to top">
<ArrowDownUp class="rotate-180" />
Scroll to Top
</button>
<!-- Scroll to the right button -->
<!-- Temporarily hidden until I figure out a better way to do this -->
<button
type="button"
class:hidden={1 == 1}
class="
ae_btn_success_outlined
btn btn-sm btn-secondary
preset-tonal-surface
transition-all duration-500
"
class:ae_btn_warning_filled={xLeft + xWidth < xScroll - 750}
onclick={() => {
document.getElementById('ae_main_content')?.scrollTo({
left: 0,
behavior: 'smooth'
});
window.parent.postMessage({ scroll_to: xScroll }, '*');
}}
title="Scroll to right">
<ArrowRight size="1em" class="inline" />
<!-- Scroll to Right
xLeft={xLeft} xScroll={xScroll} xWidth={xWidth} xScroll={xScroll} scrollLeft={scroll_container().scrollLeft}
total={xLeft + xWidth} -->
</button>
<!-- Scroll to bottom button -->
<button
type="button"
class="
ae_btn_success_outlined
btn btn-sm btn-secondary
preset-tonal-surface
transition-all duration-500
"
class:hidden={yTop < 500}
class:opacity-80={yTop > 750}
class:opacity-0={yTop < 750}
class:ae_btn_warning_filled={yTop > 1500}
onclick={() => {
if (log_lvl) {
console.log(
`Scroll to bottom button clicked. yScroll: ${yScroll} scrollTop: ${scroll_container().scrollTop}`,
scroll_container()
);
}
console.log('Not Safari, using smooth scroll to bottom');
document.getElementById('ae_main_content')?.scrollTo({
top: yScroll,
behavior: 'smooth'
});
window.parent.postMessage({ scroll_to: yScroll }, '*');
}}
title="Scroll to bottom">
<ArrowDownUp />
Scroll to Bottom
</button>
</div>
<footer
class:hidden={yTop > 300}
class:opacity-80={yTop < 250}
class:opacity-0={yTop > 250}
class="
footer
absolute
right-0
bottom-0 left-0 z-20 m-auto
flex w-full
max-w-7xl flex-row
flex-wrap items-center justify-between
gap-1 rounded-t-lg
border-t-2 border-gray-200 bg-gray-200
p-1
text-xs transition-all duration-1000
hover:text-base
hover:opacity-100 sm:flex-row
md:items-center md:justify-between
dark:border-gray-600 dark:bg-gray-800
"
class:ae_debug={$ae_loc?.debug}>
<Element_data_store
ds_code="hub__site__appshell_footer"
ds_type="html"
class_li="grow flex flex-row justify-between" />
</footer>
</div>
{:else}
<section
class="main_content flex grow flex-col items-center gap-1 px-1 pb-28 md:px-2">
<p class="text-center">
You are not logged in as a user. You must be signed in to access the
journals module.
</p>
</section>
{/if}