Prettier for everything else left
This commit is contained in:
@@ -1,62 +1,69 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { RefreshCw, Home, AlertTriangle } from '@lucide/svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { page } from '$app/state';
|
||||
import { RefreshCw, Home, AlertTriangle } from '@lucide/svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
let status = $derived(page.status);
|
||||
let message = $derived(page.error?.message || 'An unexpected error occurred');
|
||||
|
||||
// Check if it looks like a connection/API failure
|
||||
let is_connection_error = $derived(
|
||||
message.toLowerCase().includes('site lookup failed') ||
|
||||
let status = $derived(page.status);
|
||||
let message = $derived(page.error?.message || 'An unexpected error occurred');
|
||||
|
||||
// Check if it looks like a connection/API failure
|
||||
let is_connection_error = $derived(
|
||||
message.toLowerCase().includes('site lookup failed') ||
|
||||
message.toLowerCase().includes('fetch') ||
|
||||
status === 500
|
||||
);
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-center justify-center min-h-screen p-4 bg-surface-50 dark:bg-surface-900 text-center">
|
||||
<div class="max-w-md p-8 rounded-2xl shadow-xl bg-white dark:bg-surface-800 border border-surface-200 dark:border-surface-700">
|
||||
|
||||
<div
|
||||
class="bg-surface-50 dark:bg-surface-900 flex min-h-screen flex-col items-center justify-center p-4 text-center">
|
||||
<div
|
||||
class="dark:bg-surface-800 border-surface-200 dark:border-surface-700 max-w-md rounded-2xl border bg-white p-8 shadow-xl">
|
||||
<div class="mb-6 flex justify-center">
|
||||
<div class="p-4 rounded-full bg-error-100 dark:bg-error-900 text-error-600 dark:text-error-400">
|
||||
<div
|
||||
class="bg-error-100 dark:bg-error-900 text-error-600 dark:text-error-400 rounded-full p-4">
|
||||
<AlertTriangle size={48} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 class="text-6xl font-black mb-2 text-surface-900 dark:text-white">{status}</h1>
|
||||
<h2 class="text-2xl font-bold mb-4 text-surface-700 dark:text-surface-200">
|
||||
<h1 class="text-surface-900 mb-2 text-6xl font-black dark:text-white">
|
||||
{status}
|
||||
</h1>
|
||||
<h2
|
||||
class="text-surface-700 dark:text-surface-200 mb-4 text-2xl font-bold">
|
||||
{#if is_connection_error}
|
||||
Connection Failure
|
||||
{:else}
|
||||
Something went wrong
|
||||
{/if}
|
||||
</h2>
|
||||
|
||||
|
||||
<p class="text-surface-600 dark:text-surface-400 mb-8 leading-relaxed">
|
||||
{message}
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<button
|
||||
<button
|
||||
onclick={() => browser && window.location.reload()}
|
||||
class="btn btn-lg preset-filled-primary-500 hover:preset-filled-primary-600 w-full font-bold"
|
||||
>
|
||||
class="btn btn-lg preset-filled-primary-500 hover:preset-filled-primary-600 w-full font-bold">
|
||||
<RefreshCw class="mr-2 size-5" />
|
||||
Retry Connection
|
||||
</button>
|
||||
|
||||
<a
|
||||
href="/"
|
||||
class="btn btn-lg preset-outlined-surface-500 w-full font-bold"
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
class="btn btn-lg preset-outlined-surface-500 w-full font-bold">
|
||||
<Home class="mr-2 size-5" />
|
||||
Return Home
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{#if is_connection_error}
|
||||
<div class="mt-8 pt-6 border-t border-surface-100 dark:border-surface-700 text-sm text-surface-500">
|
||||
<p>If you are onsite at an event, please check your network connection or contact the registration desk.</p>
|
||||
<div
|
||||
class="border-surface-100 dark:border-surface-700 text-surface-500 mt-8 border-t pt-6 text-sm">
|
||||
<p>
|
||||
If you are onsite at an event, please check your network
|
||||
connection or contact the registration desk.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,297 +1,335 @@
|
||||
<script lang="ts">
|
||||
/** @type {import('./$types').LayoutData} */
|
||||
/** @type {import('./$types').LayoutData} */
|
||||
|
||||
let log_lvl: number = 0;
|
||||
let log_lvl: number = 0;
|
||||
|
||||
// *** Import Svelte specific
|
||||
import { untrack } from 'svelte';
|
||||
import { goto, invalidateAll } from '$app/navigation';
|
||||
// *** Import Svelte specific
|
||||
import { untrack } from 'svelte';
|
||||
import { goto, invalidateAll } from '$app/navigation';
|
||||
|
||||
import '../app.css';
|
||||
import '../app.css';
|
||||
|
||||
// *** Import other supporting libraries
|
||||
// *** Import other supporting libraries
|
||||
|
||||
// Highlight JS
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import 'highlight.js/styles/github-dark.css';
|
||||
// Highlight JS
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import 'highlight.js/styles/github-dark.css';
|
||||
|
||||
import { browser } from '$app/environment';
|
||||
import { online } from 'svelte/reactivity/window';
|
||||
import xml from 'highlight.js/lib/languages/xml'; // for HTML
|
||||
import css from 'highlight.js/lib/languages/css';
|
||||
import javascript from 'highlight.js/lib/languages/javascript';
|
||||
import typescript from 'highlight.js/lib/languages/typescript';
|
||||
import { browser } from '$app/environment';
|
||||
import { online } from 'svelte/reactivity/window';
|
||||
import xml from 'highlight.js/lib/languages/xml'; // for HTML
|
||||
import css from 'highlight.js/lib/languages/css';
|
||||
import javascript from 'highlight.js/lib/languages/javascript';
|
||||
import typescript from 'highlight.js/lib/languages/typescript';
|
||||
|
||||
hljs.registerLanguage('xml', xml); // for HTML
|
||||
hljs.registerLanguage('css', css);
|
||||
hljs.registerLanguage('javascript', javascript);
|
||||
hljs.registerLanguage('typescript', typescript);
|
||||
hljs.registerLanguage('xml', xml); // for HTML
|
||||
hljs.registerLanguage('css', css);
|
||||
hljs.registerLanguage('javascript', javascript);
|
||||
hljs.registerLanguage('typescript', typescript);
|
||||
|
||||
// *** Import Aether specific variables and functions
|
||||
// import Analytics from '$lib/app_components/e_app_analytics.svelte';
|
||||
import { ae_loc, ae_sess, ae_api, slct, slct_trigger, ae_auth_error } from '$lib/stores/ae_stores';
|
||||
import { LoaderCircle } from '@lucide/svelte';
|
||||
// *** Import Aether specific variables and functions
|
||||
// import Analytics from '$lib/app_components/e_app_analytics.svelte';
|
||||
import {
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
slct,
|
||||
slct_trigger,
|
||||
ae_auth_error
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { LoaderCircle } from '@lucide/svelte';
|
||||
|
||||
import E_app_debug_menu from '$lib/app_components/e_app_debug_menu.svelte';
|
||||
import E_app_sys_bar from '$lib/app_components/e_app_sys_bar.svelte';
|
||||
import { pwa_install } from '$lib/pwa/pwa_install.svelte';
|
||||
import E_app_debug_menu from '$lib/app_components/e_app_debug_menu.svelte';
|
||||
import E_app_sys_bar from '$lib/app_components/e_app_sys_bar.svelte';
|
||||
import { pwa_install } from '$lib/pwa/pwa_install.svelte';
|
||||
|
||||
interface Props {
|
||||
data: any;
|
||||
children?: import('svelte').Snippet;
|
||||
interface Props {
|
||||
data: any;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let { data, children }: Props = $props();
|
||||
|
||||
// STABLE DERIVATION: Using prop data directly to avoid store loops
|
||||
let ae_acct = $derived(data[data.account_id]);
|
||||
|
||||
let flag_clear_idb: boolean = $state(false);
|
||||
let flag_clear_local: boolean = $state(false);
|
||||
let flag_clear_sess: boolean = $state(false);
|
||||
let flag_reload: boolean = $state(false);
|
||||
|
||||
let flag_new_ver: boolean = $state(false);
|
||||
let flag_expired: boolean = $state(false);
|
||||
let flag_denied: boolean = $state(false);
|
||||
|
||||
// Connection Status
|
||||
let is_offline = $derived(browser && online.current === false);
|
||||
let api_unreachable = $derived($ae_loc?.account_id === 'ghost');
|
||||
let api_error_msg = $derived($ae_loc?.account_name || 'API Server Unreachable');
|
||||
let show_connection_details = $state(true);
|
||||
|
||||
let last_reload_time = 0;
|
||||
|
||||
// Shallow equality guard — avoids triggering Svelte store updates when the merged
|
||||
// object is functionally identical to the current one. Comparing JSON.stringify on
|
||||
// large objects like $ae_loc (site config, device info, flags) is expensive and
|
||||
// runs on every navigation. Key-by-key identity check is O(n keys), not O(n chars).
|
||||
function shallow_equal(
|
||||
a: Record<string, any>,
|
||||
b: Record<string, any>
|
||||
): boolean {
|
||||
const keys_a = Object.keys(a);
|
||||
const keys_b = Object.keys(b);
|
||||
if (keys_a.length !== keys_b.length) return false;
|
||||
for (const k of keys_a) {
|
||||
if (a[k] !== b[k]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let { data, children }: Props = $props();
|
||||
// 1. CONSOLIDATED SYNC EFFECT (One single point of entry for store updates)
|
||||
$effect(() => {
|
||||
if (!browser || !ae_acct) return;
|
||||
|
||||
// STABLE DERIVATION: Using prop data directly to avoid store loops
|
||||
let ae_acct = $derived(data[data.account_id]);
|
||||
untrack(() => {
|
||||
if (log_lvl > 1) console.log('ROOT: Running Sync Effect');
|
||||
|
||||
let flag_clear_idb: boolean = $state(false);
|
||||
let flag_clear_local: boolean = $state(false);
|
||||
let flag_clear_sess: boolean = $state(false);
|
||||
let flag_reload: boolean = $state(false);
|
||||
|
||||
let flag_new_ver: boolean = $state(false);
|
||||
let flag_expired: boolean = $state(false);
|
||||
let flag_denied: boolean = $state(false);
|
||||
|
||||
// Connection Status
|
||||
let is_offline = $derived(browser && online.current === false);
|
||||
let api_unreachable = $derived($ae_loc?.account_id === 'ghost');
|
||||
let api_error_msg = $derived($ae_loc?.account_name || 'API Server Unreachable');
|
||||
let show_connection_details = $state(true);
|
||||
|
||||
let last_reload_time = 0;
|
||||
|
||||
// Shallow equality guard — avoids triggering Svelte store updates when the merged
|
||||
// object is functionally identical to the current one. Comparing JSON.stringify on
|
||||
// large objects like $ae_loc (site config, device info, flags) is expensive and
|
||||
// runs on every navigation. Key-by-key identity check is O(n keys), not O(n chars).
|
||||
function shallow_equal(a: Record<string, any>, b: Record<string, any>): boolean {
|
||||
const keys_a = Object.keys(a);
|
||||
const keys_b = Object.keys(b);
|
||||
if (keys_a.length !== keys_b.length) return false;
|
||||
for (const k of keys_a) {
|
||||
if (a[k] !== b[k]) return false;
|
||||
// A. Sync Global Stores
|
||||
const current_api = $ae_api;
|
||||
const new_api = { ...current_api, ...(ae_acct.api || {}) };
|
||||
// Deep check for JWT specifically to avoid extra triggers
|
||||
if (current_api.jwt !== $ae_loc.jwt) new_api.jwt = $ae_loc.jwt;
|
||||
if (!shallow_equal(current_api, new_api)) {
|
||||
$ae_api = new_api;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 1. CONSOLIDATED SYNC EFFECT (One single point of entry for store updates)
|
||||
$effect(() => {
|
||||
if (!browser || !ae_acct) return;
|
||||
const current_loc = $ae_loc;
|
||||
const new_loc = { ...current_loc, ...(ae_acct.loc || {}) };
|
||||
// Restore structural integrity if clobbered
|
||||
if (!new_loc.sys_menu)
|
||||
new_loc.sys_menu = {
|
||||
hide: false,
|
||||
hide_access_type: false,
|
||||
expand_access_type: false,
|
||||
hide_edit_mode: false,
|
||||
expand_edit_mode: false,
|
||||
hide_user: false,
|
||||
expand_user: false,
|
||||
hide_theme: false,
|
||||
expand_theme: false,
|
||||
hide_cfg: false,
|
||||
expand_cfg: false
|
||||
};
|
||||
if (!new_loc.debug_menu)
|
||||
new_loc.debug_menu = { hide: false, expand: false };
|
||||
|
||||
if (!shallow_equal(current_loc, new_loc)) {
|
||||
$ae_loc = new_loc;
|
||||
}
|
||||
|
||||
const current_slct = $slct;
|
||||
const new_slct = { ...current_slct, ...(ae_acct.slct || {}) };
|
||||
if (!shallow_equal(current_slct, new_slct)) {
|
||||
$slct = new_slct;
|
||||
}
|
||||
|
||||
// B. Version & Sanity Check
|
||||
if (new_loc.ver && $ae_sess.ver && new_loc.ver !== $ae_sess.ver) {
|
||||
if (!flag_new_ver) {
|
||||
console.log('ROOT: Version mismatch detected');
|
||||
flag_new_ver = true;
|
||||
flag_reload = true;
|
||||
}
|
||||
}
|
||||
|
||||
// C. Access Check (Idempotent)
|
||||
if (new_loc.site_access_key || new_loc.site_domain_access_key) {
|
||||
const key = new_loc.allow_access;
|
||||
const match =
|
||||
new_loc.site_access_key === key ||
|
||||
new_loc.site_domain_access_key === key;
|
||||
if (!match && !new_loc.trusted_access) {
|
||||
if (new_loc.allow_access !== false)
|
||||
$ae_loc.allow_access = false;
|
||||
if (!flag_denied) flag_denied = true;
|
||||
}
|
||||
} else if (new_loc.allow_access !== true) {
|
||||
$ae_loc.allow_access = true;
|
||||
}
|
||||
|
||||
// D. Theme Initialization (Once)
|
||||
if (!current_loc.theme_mode) {
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
$ae_loc.theme_mode = 'dark';
|
||||
else $ae_loc.theme_mode = 'light';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 2. RELOAD THROTTLE EFFECT
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
|
||||
if (flag_reload) {
|
||||
untrack(() => {
|
||||
if (log_lvl > 1) console.log("ROOT: Running Sync Effect");
|
||||
|
||||
// A. Sync Global Stores
|
||||
const current_api = $ae_api;
|
||||
const new_api = { ...current_api, ...(ae_acct.api || {}) };
|
||||
// Deep check for JWT specifically to avoid extra triggers
|
||||
if (current_api.jwt !== $ae_loc.jwt) new_api.jwt = $ae_loc.jwt;
|
||||
if (!shallow_equal(current_api, new_api)) {
|
||||
$ae_api = new_api;
|
||||
}
|
||||
|
||||
const current_loc = $ae_loc;
|
||||
const new_loc = { ...current_loc, ...(ae_acct.loc || {}) };
|
||||
// Restore structural integrity if clobbered
|
||||
if (!new_loc.sys_menu) new_loc.sys_menu = { hide: false, hide_access_type: false, expand_access_type: false, hide_edit_mode: false, expand_edit_mode: false, hide_user: false, expand_user: false, hide_theme: false, expand_theme: false, hide_cfg: false, expand_cfg: false };
|
||||
if (!new_loc.debug_menu) new_loc.debug_menu = { hide: false, expand: false };
|
||||
|
||||
if (!shallow_equal(current_loc, new_loc)) {
|
||||
$ae_loc = new_loc;
|
||||
}
|
||||
|
||||
const current_slct = $slct;
|
||||
const new_slct = { ...current_slct, ...(ae_acct.slct || {}) };
|
||||
if (!shallow_equal(current_slct, new_slct)) {
|
||||
$slct = new_slct;
|
||||
}
|
||||
|
||||
// B. Version & Sanity Check
|
||||
if (new_loc.ver && $ae_sess.ver && new_loc.ver !== $ae_sess.ver) {
|
||||
if (!flag_new_ver) {
|
||||
console.log("ROOT: Version mismatch detected");
|
||||
flag_new_ver = true;
|
||||
flag_reload = true;
|
||||
}
|
||||
}
|
||||
|
||||
// C. Access Check (Idempotent)
|
||||
if (new_loc.site_access_key || new_loc.site_domain_access_key) {
|
||||
const key = new_loc.allow_access;
|
||||
const match = (new_loc.site_access_key === key || new_loc.site_domain_access_key === key);
|
||||
if (!match && !new_loc.trusted_access) {
|
||||
if (new_loc.allow_access !== false) $ae_loc.allow_access = false;
|
||||
if (!flag_denied) flag_denied = true;
|
||||
}
|
||||
} else if (new_loc.allow_access !== true) {
|
||||
$ae_loc.allow_access = true;
|
||||
}
|
||||
|
||||
// D. Theme Initialization (Once)
|
||||
if (!current_loc.theme_mode) {
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) $ae_loc.theme_mode = 'dark';
|
||||
else $ae_loc.theme_mode = 'light';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 2. RELOAD THROTTLE EFFECT
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
|
||||
if (flag_reload) {
|
||||
untrack(() => {
|
||||
const now = Date.now();
|
||||
if (now - last_reload_time < 10000) {
|
||||
console.warn("ROOT: Critical loop prevention - reload suppressed");
|
||||
flag_reload = false;
|
||||
return;
|
||||
}
|
||||
last_reload_time = now;
|
||||
const now = Date.now();
|
||||
if (now - last_reload_time < 10000) {
|
||||
console.warn(
|
||||
'ROOT: Critical loop prevention - reload suppressed'
|
||||
);
|
||||
flag_reload = false;
|
||||
|
||||
if (flag_clear_local) clear_local();
|
||||
if (flag_clear_sess) clear_sess();
|
||||
|
||||
console.log("ROOT: Executing throttled reload");
|
||||
invalidateAll();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 3. UI STATE & THEME DOM EFFECT
|
||||
let is_hydrating = $state(true);
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
|
||||
// Theme name — controls which Skeleton color palette is active
|
||||
document.documentElement.setAttribute('data-theme', $ae_loc?.theme_name ?? 'nouveau');
|
||||
|
||||
// Dark/light class — controls Tailwind v4 class-based dark mode variant.
|
||||
// @custom-variant dark in app.css registers this; without it the class does nothing.
|
||||
if ($ae_loc?.theme_mode === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.classList.remove('light');
|
||||
} else {
|
||||
document.documentElement.classList.add('light');
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
// Font size mode — cycles default | larger | smaller.
|
||||
// CSS classes are defined in app.css; no class = browser default (16px).
|
||||
document.documentElement.classList.remove('font-size-larger', 'font-size-smaller');
|
||||
if ($ae_loc?.font_size_mode === 'larger') {
|
||||
document.documentElement.classList.add('font-size-larger');
|
||||
} else if ($ae_loc?.font_size_mode === 'smaller') {
|
||||
document.documentElement.classList.add('font-size-smaller');
|
||||
}
|
||||
|
||||
// Hydration overlay timer
|
||||
if ($ae_loc?.account_id) {
|
||||
const timer = setTimeout(() => is_hydrating = false, 500);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
});
|
||||
|
||||
function clear_idb() {
|
||||
indexedDB.deleteDatabase('ae_archives_db');
|
||||
indexedDB.deleteDatabase('ae_core_db');
|
||||
indexedDB.deleteDatabase('ae_events_db');
|
||||
indexedDB.deleteDatabase('ae_journals_db');
|
||||
indexedDB.deleteDatabase('ae_posts_db');
|
||||
indexedDB.deleteDatabase('ae_sponsorships_db');
|
||||
}
|
||||
|
||||
function clear_local() {
|
||||
localStorage.clear();
|
||||
}
|
||||
|
||||
function clear_sess() {
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
// 4. EXTERNAL INTERFACES EFFECT
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
|
||||
// Initialise PWA install prompt listener (captures beforeinstallprompt early).
|
||||
pwa_install.init();
|
||||
|
||||
// Save DS to local
|
||||
let ae_ds = ae_acct?.ds;
|
||||
if (ae_ds) {
|
||||
for (let [key, value] of Object.entries(ae_ds)) {
|
||||
localStorage.setItem(`ae_ds__${key}`, JSON.stringify(value));
|
||||
return;
|
||||
}
|
||||
last_reload_time = now;
|
||||
flag_reload = false;
|
||||
|
||||
if (flag_clear_local) clear_local();
|
||||
if (flag_clear_sess) clear_sess();
|
||||
|
||||
console.log('ROOT: Executing throttled reload');
|
||||
invalidateAll();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 3. UI STATE & THEME DOM EFFECT
|
||||
let is_hydrating = $state(true);
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
|
||||
// Theme name — controls which Skeleton color palette is active
|
||||
document.documentElement.setAttribute(
|
||||
'data-theme',
|
||||
$ae_loc?.theme_name ?? 'nouveau'
|
||||
);
|
||||
|
||||
// Dark/light class — controls Tailwind v4 class-based dark mode variant.
|
||||
// @custom-variant dark in app.css registers this; without it the class does nothing.
|
||||
if ($ae_loc?.theme_mode === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.classList.remove('light');
|
||||
} else {
|
||||
document.documentElement.classList.add('light');
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
// Font size mode — cycles default | larger | smaller.
|
||||
// CSS classes are defined in app.css; no class = browser default (16px).
|
||||
document.documentElement.classList.remove(
|
||||
'font-size-larger',
|
||||
'font-size-smaller'
|
||||
);
|
||||
if ($ae_loc?.font_size_mode === 'larger') {
|
||||
document.documentElement.classList.add('font-size-larger');
|
||||
} else if ($ae_loc?.font_size_mode === 'smaller') {
|
||||
document.documentElement.classList.add('font-size-smaller');
|
||||
}
|
||||
|
||||
// Hydration overlay timer
|
||||
if ($ae_loc?.account_id) {
|
||||
const timer = setTimeout(() => (is_hydrating = false), 500);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
});
|
||||
|
||||
function clear_idb() {
|
||||
indexedDB.deleteDatabase('ae_archives_db');
|
||||
indexedDB.deleteDatabase('ae_core_db');
|
||||
indexedDB.deleteDatabase('ae_events_db');
|
||||
indexedDB.deleteDatabase('ae_journals_db');
|
||||
indexedDB.deleteDatabase('ae_posts_db');
|
||||
indexedDB.deleteDatabase('ae_sponsorships_db');
|
||||
}
|
||||
|
||||
function clear_local() {
|
||||
localStorage.clear();
|
||||
}
|
||||
|
||||
function clear_sess() {
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
// 4. EXTERNAL INTERFACES EFFECT
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
|
||||
// Initialise PWA install prompt listener (captures beforeinstallprompt early).
|
||||
pwa_install.init();
|
||||
|
||||
// Save DS to local
|
||||
let ae_ds = ae_acct?.ds;
|
||||
if (ae_ds) {
|
||||
for (let [key, value] of Object.entries(ae_ds)) {
|
||||
localStorage.setItem(`ae_ds__${key}`, JSON.stringify(value));
|
||||
}
|
||||
}
|
||||
|
||||
// Message Bridge
|
||||
const handler = (event: MessageEvent) => {
|
||||
if (event.data.type === 'api_download_blob') {
|
||||
$ae_sess.api_download_kv[event.data.task_id] = { ...event.data };
|
||||
} else if (event.data.type === 'api_post_json_form') {
|
||||
$ae_sess.api_upload_kv[event.data.task_id] = { ...event.data };
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
|
||||
// Iframe Detection
|
||||
let iframe = data.url.searchParams.get('iframe');
|
||||
if (iframe === 'true') {
|
||||
$ae_loc.iframe = true;
|
||||
// Hide the AE system bar by default in iframe embeds — it's nav chrome
|
||||
// the host page doesn't need. Trusted admins can override with show_menu=true
|
||||
// to access the menu while testing an embedded page (e.g. video_conferences).
|
||||
$ae_loc.sys_menu.hide = true;
|
||||
} else if (iframe === 'false') {
|
||||
$ae_loc.iframe = false;
|
||||
// Message Bridge
|
||||
const handler = (event: MessageEvent) => {
|
||||
if (event.data.type === 'api_download_blob') {
|
||||
$ae_sess.api_download_kv[event.data.task_id] = { ...event.data };
|
||||
} else if (event.data.type === 'api_post_json_form') {
|
||||
$ae_sess.api_upload_kv[event.data.task_id] = { ...event.data };
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
|
||||
// show_menu=true — override to show the AE system bar even inside an iframe.
|
||||
// Intended for trusted/admin users who need menu access while testing an embed.
|
||||
// hide_menu=true — explicitly hide the bar outside of iframe contexts.
|
||||
const menu_override = data.url.searchParams.get('show_menu');
|
||||
if (menu_override === 'true') $ae_loc.sys_menu.hide = false;
|
||||
else if (data.url.searchParams.get('hide_menu') === 'true') $ae_loc.sys_menu.hide = true;
|
||||
// Iframe Detection
|
||||
let iframe = data.url.searchParams.get('iframe');
|
||||
if (iframe === 'true') {
|
||||
$ae_loc.iframe = true;
|
||||
// Hide the AE system bar by default in iframe embeds — it's nav chrome
|
||||
// the host page doesn't need. Trusted admins can override with show_menu=true
|
||||
// to access the menu while testing an embedded page (e.g. video_conferences).
|
||||
$ae_loc.sys_menu.hide = true;
|
||||
} else if (iframe === 'false') {
|
||||
$ae_loc.iframe = false;
|
||||
}
|
||||
|
||||
// Theme URL params — ?theme=AE_Firefly_SteelBlue&theme_mode=dark
|
||||
// Applied once on load, then silently removed from the URL (no history entry).
|
||||
const url_theme = data.url.searchParams.get('theme');
|
||||
const url_theme_mode = data.url.searchParams.get('theme_mode');
|
||||
if (url_theme || url_theme_mode) {
|
||||
if (url_theme) $ae_loc.theme_name = url_theme;
|
||||
if (url_theme_mode === 'light' || url_theme_mode === 'dark') $ae_loc.theme_mode = url_theme_mode;
|
||||
const clean_url = new URL(data.url.href);
|
||||
clean_url.searchParams.delete('theme');
|
||||
clean_url.searchParams.delete('theme_mode');
|
||||
goto(clean_url.pathname + clean_url.search + clean_url.hash, {
|
||||
replaceState: true,
|
||||
noScroll: true,
|
||||
keepFocus: true
|
||||
});
|
||||
}
|
||||
// show_menu=true — override to show the AE system bar even inside an iframe.
|
||||
// Intended for trusted/admin users who need menu access while testing an embed.
|
||||
// hide_menu=true — explicitly hide the bar outside of iframe contexts.
|
||||
const menu_override = data.url.searchParams.get('show_menu');
|
||||
if (menu_override === 'true') $ae_loc.sys_menu.hide = false;
|
||||
else if (data.url.searchParams.get('hide_menu') === 'true')
|
||||
$ae_loc.sys_menu.hide = true;
|
||||
|
||||
// Electron Detection
|
||||
if ((window as any).native_app || (window as any).aetherNative) {
|
||||
if (!$ae_loc.is_native) $ae_loc.is_native = true;
|
||||
}
|
||||
// Theme URL params — ?theme=AE_Firefly_SteelBlue&theme_mode=dark
|
||||
// Applied once on load, then silently removed from the URL (no history entry).
|
||||
const url_theme = data.url.searchParams.get('theme');
|
||||
const url_theme_mode = data.url.searchParams.get('theme_mode');
|
||||
if (url_theme || url_theme_mode) {
|
||||
if (url_theme) $ae_loc.theme_name = url_theme;
|
||||
if (url_theme_mode === 'light' || url_theme_mode === 'dark')
|
||||
$ae_loc.theme_mode = url_theme_mode;
|
||||
const clean_url = new URL(data.url.href);
|
||||
clean_url.searchParams.delete('theme');
|
||||
clean_url.searchParams.delete('theme_mode');
|
||||
goto(clean_url.pathname + clean_url.search + clean_url.hash, {
|
||||
replaceState: true,
|
||||
noScroll: true,
|
||||
keepFocus: true
|
||||
});
|
||||
}
|
||||
|
||||
return () => window.removeEventListener('message', handler);
|
||||
});
|
||||
// Electron Detection
|
||||
if ((window as any).native_app || (window as any).aetherNative) {
|
||||
if (!$ae_loc.is_native) $ae_loc.is_native = true;
|
||||
}
|
||||
|
||||
// 5. SESSION EXPIRED EFFECT — watches ae_auth_error and raises the banner when the API signals 401/403.
|
||||
// Guards on $ae_loc.jwt so that unauthenticated first-loads (no stored JWT) never trigger it —
|
||||
// 401s are expected on first visit and should not look like a session expiry.
|
||||
$effect(() => {
|
||||
if ($ae_auth_error?.type === 'expired') {
|
||||
untrack(() => {
|
||||
if ($ae_loc?.jwt) flag_expired = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
return () => window.removeEventListener('message', handler);
|
||||
});
|
||||
|
||||
// 5. SESSION EXPIRED EFFECT — watches ae_auth_error and raises the banner when the API signals 401/403.
|
||||
// Guards on $ae_loc.jwt so that unauthenticated first-loads (no stored JWT) never trigger it —
|
||||
// 401s are expected on first visit and should not look like a session expiry.
|
||||
$effect(() => {
|
||||
if ($ae_auth_error?.type === 'expired') {
|
||||
untrack(() => {
|
||||
if ($ae_loc?.jwt) flag_expired = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -299,18 +337,32 @@
|
||||
</svelte:head>
|
||||
|
||||
{#if browser && (is_offline || api_unreachable)}
|
||||
<div class="print:hidden fixed top-0 left-0 right-0 z-100 p-4 preset-filled-error-500 text-center shadow-2xl flex items-center justify-center gap-4">
|
||||
<span class="text-xl font-bold">{is_offline ? 'Offline' : api_error_msg}</span>
|
||||
<button class="btn btn-sm preset-tonal-surface" onclick={() => window.location.reload()}>Retry</button>
|
||||
<div
|
||||
class="preset-filled-error-500 fixed top-0 right-0 left-0 z-100 flex items-center justify-center gap-4 p-4 text-center shadow-2xl print:hidden">
|
||||
<span class="text-xl font-bold"
|
||||
>{is_offline ? 'Offline' : api_error_msg}</span>
|
||||
<button
|
||||
class="btn btn-sm preset-tonal-surface"
|
||||
onclick={() => window.location.reload()}>Retry</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if browser && flag_expired}
|
||||
<div class="print:hidden fixed top-0 left-0 right-0 z-50 px-4 py-2 preset-filled-warning-500 shadow-xl flex items-center justify-between gap-4">
|
||||
<p class="text-sm font-semibold">Your session has expired. Please reload or sign in again.</p>
|
||||
<div class="flex gap-2 items-center shrink-0">
|
||||
<button class="btn btn-sm preset-tonal-surface" onclick={() => window.location.reload()}>Reload</button>
|
||||
<button class="btn btn-sm preset-outlined-surface" onclick={() => { flag_expired = false; ae_auth_error.set({ type: null, ts: null }); }}>✕</button>
|
||||
<div
|
||||
class="preset-filled-warning-500 fixed top-0 right-0 left-0 z-50 flex items-center justify-between gap-4 px-4 py-2 shadow-xl print:hidden">
|
||||
<p class="text-sm font-semibold">
|
||||
Your session has expired. Please reload or sign in again.
|
||||
</p>
|
||||
<div class="flex shrink-0 items-center gap-2">
|
||||
<button
|
||||
class="btn btn-sm preset-tonal-surface"
|
||||
onclick={() => window.location.reload()}>Reload</button>
|
||||
<button
|
||||
class="btn btn-sm preset-outlined-surface"
|
||||
onclick={() => {
|
||||
flag_expired = false;
|
||||
ae_auth_error.set({ type: null, ts: null });
|
||||
}}>✕</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -319,30 +371,45 @@
|
||||
{@render children?.()}
|
||||
|
||||
{#if is_hydrating}
|
||||
<div class="print:hidden fixed inset-0 z-99 flex flex-col items-center justify-center bg-surface-50/80 dark:bg-surface-900/80 backdrop-blur-sm transition-opacity duration-500">
|
||||
<div class="preset-filled-surface-100-900 p-8 rounded-2xl shadow-2xl flex flex-col items-center gap-4">
|
||||
<LoaderCircle size="3rem" class="animate-spin text-primary-500" />
|
||||
<div class="text-center font-bold text-xl">Hydrating Aether...</div>
|
||||
<div
|
||||
class="bg-surface-50/80 dark:bg-surface-900/80 fixed inset-0 z-99 flex flex-col items-center justify-center backdrop-blur-sm transition-opacity duration-500 print:hidden">
|
||||
<div
|
||||
class="preset-filled-surface-100-900 flex flex-col items-center gap-4 rounded-2xl p-8 shadow-2xl">
|
||||
<LoaderCircle
|
||||
size="3rem"
|
||||
class="text-primary-500 animate-spin" />
|
||||
<div class="text-center text-xl font-bold">
|
||||
Hydrating Aether...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else if browser && flag_denied}
|
||||
<div class="flex flex-col items-center justify-center h-screen gap-6 p-8">
|
||||
<h1 class="text-4xl font-black text-error-500">Access Denied</h1>
|
||||
<button class="btn preset-filled-primary" onclick={() => window.location.reload()}>Reload</button>
|
||||
<div class="flex h-screen flex-col items-center justify-center gap-6 p-8">
|
||||
<h1 class="text-error-500 text-4xl font-black">Access Denied</h1>
|
||||
<button
|
||||
class="btn preset-filled-primary"
|
||||
onclick={() => window.location.reload()}>Reload</button>
|
||||
</div>
|
||||
{:else if browser}
|
||||
<div class="flex items-center justify-center h-screen"><LoaderCircle size="2.5rem" class="animate-spin opacity-20" /></div>
|
||||
<div class="flex h-screen items-center justify-center">
|
||||
<LoaderCircle size="2.5rem" class="animate-spin opacity-20" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if browser && (!$ae_loc?.iframe || $ae_loc?.trusted_access)}
|
||||
<!-- print:hidden wrapper: sys/debug menus are fixed overlays — must not appear on printed pages -->
|
||||
<div class="print:hidden">
|
||||
<E_app_sys_bar {data} bind:hide={$ae_loc.sys_menu.hide} bind:expand={$ae_sess.sys_menu.expand} />
|
||||
<E_app_sys_bar
|
||||
{data}
|
||||
bind:hide={$ae_loc.sys_menu.hide}
|
||||
bind:expand={$ae_sess.sys_menu.expand} />
|
||||
|
||||
<!-- You must be in Edit Mode to initially see the Debug expand button. Once expanded, you can toggle the Edit Mode while still seeing the expanded Debug content. -->
|
||||
{#if $ae_loc.edit_mode || $ae_loc.debug_menu.expand}
|
||||
<E_app_debug_menu bind:hide={$ae_loc.debug_menu.hide} bind:expand={$ae_loc.debug_menu.expand} />
|
||||
<E_app_debug_menu
|
||||
bind:hide={$ae_loc.debug_menu.hide}
|
||||
bind:expand={$ae_loc.debug_menu.expand} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
PUBLIC_AE_API_PATH,
|
||||
PUBLIC_AE_API_SECRET_KEY,
|
||||
PUBLIC_AE_API_CRUD_SUPER_KEY,
|
||||
PUBLIC_AE_BOOTSTRAP_KEY,
|
||||
PUBLIC_AE_BOOTSTRAP_KEY
|
||||
// PUBLIC_AE_NO_ACCOUNT_ID,
|
||||
// PUBLIC_AE_NO_ACCOUNT_ID_TOKEN
|
||||
} from '$env/static/public';
|
||||
@@ -130,32 +130,54 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
try {
|
||||
// Use the db_core instance directly for a quick lookup
|
||||
const { db_core } = await import('$lib/ae_core/db_core');
|
||||
const cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
|
||||
const cached = await db_core.site_domain
|
||||
.where('fqdn')
|
||||
.equals(fqdn)
|
||||
.first();
|
||||
if (cached) {
|
||||
if (log_lvl) console.log('ROOT LOAD: Found cached site domain. Unblocking layout.');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'ROOT LOAD: Found cached site domain. Unblocking layout.'
|
||||
);
|
||||
result = cached;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.warn('ROOT LOAD: Failed to read from Dexie cache.', e);
|
||||
if (log_lvl)
|
||||
console.warn('ROOT LOAD: Failed to read from Dexie cache.', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect Aether Native Bridge (Electron)
|
||||
if (typeof window !== 'undefined' && (window as any).aetherNative) {
|
||||
is_native = true;
|
||||
if (log_lvl) console.log('ROOT LOAD: Detected Aether Native Bridge. Requesting device config...');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'ROOT LOAD: Detected Aether Native Bridge. Requesting device config...'
|
||||
);
|
||||
try {
|
||||
const native_device_config = await (window as any).aetherNative.get_device_config();
|
||||
const native_device_config = await (
|
||||
window as any
|
||||
).aetherNative.get_device_config();
|
||||
if (native_device_config) {
|
||||
if (log_lvl) console.log('ROOT LOAD: Native device config received:', native_device_config);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'ROOT LOAD: Native device config received:',
|
||||
native_device_config
|
||||
);
|
||||
// Map native device config to the expected result structure
|
||||
// Use native as source of truth if available
|
||||
result = {
|
||||
...native_device_config,
|
||||
// Ensure naming consistency
|
||||
account_id: native_device_config.account_id || native_device_config.account_id_random,
|
||||
site_id: native_device_config.site_id || native_device_config.site_id_random,
|
||||
site_domain_id: native_device_config.site_domain_id || native_device_config.site_domain_id_random,
|
||||
account_id:
|
||||
native_device_config.account_id ||
|
||||
native_device_config.account_id_random,
|
||||
site_id:
|
||||
native_device_config.site_id ||
|
||||
native_device_config.site_id_random,
|
||||
site_domain_id:
|
||||
native_device_config.site_domain_id ||
|
||||
native_device_config.site_domain_id_random
|
||||
};
|
||||
|
||||
// Inject native device metadata into the location state with SAFE MERGE
|
||||
@@ -163,50 +185,76 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
const incoming_dev = native_device_config.native_device;
|
||||
|
||||
// String-Only ID Vision: Ensure semantic fields use the random string ID
|
||||
if (incoming_dev.event_device_id_random) incoming_dev.event_device_id = incoming_dev.event_device_id_random;
|
||||
if (incoming_dev.event_id_random) incoming_dev.event_id = incoming_dev.event_id_random;
|
||||
if (incoming_dev.id_random) incoming_dev.id = incoming_dev.id_random;
|
||||
if (incoming_dev.event_device_id_random)
|
||||
incoming_dev.event_device_id =
|
||||
incoming_dev.event_device_id_random;
|
||||
if (incoming_dev.event_id_random)
|
||||
incoming_dev.event_id = incoming_dev.event_id_random;
|
||||
if (incoming_dev.id_random)
|
||||
incoming_dev.id = incoming_dev.id_random;
|
||||
|
||||
// 1. Recover existing user overrides from localStorage
|
||||
let existing_dev = {};
|
||||
try {
|
||||
const raw = localStorage.getItem('ae_loc');
|
||||
if (raw) existing_dev = JSON.parse(raw).native_device || {};
|
||||
if (raw)
|
||||
existing_dev = JSON.parse(raw).native_device || {};
|
||||
} catch (e) {}
|
||||
|
||||
// 2. Merge: Priority to EXISTING overrides for specific timers
|
||||
ae_loc_init['native_device'] = {
|
||||
...incoming_dev,
|
||||
// Persist these specific user-controlled fields
|
||||
check_event_loop_period: (existing_dev as any).check_event_loop_period || incoming_dev.check_event_loop_period,
|
||||
check_event_device_loop_period: (existing_dev as any).check_event_device_loop_period || incoming_dev.check_event_device_loop_period,
|
||||
check_event_location_loop_period: (existing_dev as any).check_event_location_loop_period || incoming_dev.check_event_location_loop_period,
|
||||
check_event_session_loop_period: (existing_dev as any).check_event_session_loop_period || incoming_dev.check_event_session_loop_period,
|
||||
check_event_loop_period:
|
||||
(existing_dev as any).check_event_loop_period ||
|
||||
incoming_dev.check_event_loop_period,
|
||||
check_event_device_loop_period:
|
||||
(existing_dev as any)
|
||||
.check_event_device_loop_period ||
|
||||
incoming_dev.check_event_device_loop_period,
|
||||
check_event_location_loop_period:
|
||||
(existing_dev as any)
|
||||
.check_event_location_loop_period ||
|
||||
incoming_dev.check_event_location_loop_period,
|
||||
check_event_session_loop_period:
|
||||
(existing_dev as any)
|
||||
.check_event_session_loop_period ||
|
||||
incoming_dev.check_event_session_loop_period,
|
||||
// Use API value if present; default to 2 (never preserve from localStorage — stale values cause orphaned cache dirs)
|
||||
hash_prefix_length: incoming_dev.hash_prefix_length || 2
|
||||
};
|
||||
|
||||
// Map specific operational paths
|
||||
ae_loc_init['local_file_cache_path'] = incoming_dev.local_file_cache_path;
|
||||
ae_loc_init['host_file_temp_path'] = incoming_dev.host_file_temp_path;
|
||||
ae_loc_init['local_file_cache_path'] =
|
||||
incoming_dev.local_file_cache_path;
|
||||
ae_loc_init['host_file_temp_path'] =
|
||||
incoming_dev.host_file_temp_path;
|
||||
ae_loc_init['recording_path'] = incoming_dev.recording_path;
|
||||
}
|
||||
|
||||
// IMPORTANT: Update API settings with the native-authorized key if present
|
||||
if (native_device_config.aether_api_key) {
|
||||
ae_api_init['api_secret_key'] = native_device_config.aether_api_key;
|
||||
ae_api_headers['x-aether-api-key'] = native_device_config.aether_api_key;
|
||||
ae_api_init['api_secret_key'] =
|
||||
native_device_config.aether_api_key;
|
||||
ae_api_headers['x-aether-api-key'] =
|
||||
native_device_config.aether_api_key;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('ROOT LOAD: Failed to fetch native device config.', err);
|
||||
console.error(
|
||||
'ROOT LOAD: Failed to fetch native device config.',
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API site lookup only if we have no result yet
|
||||
if (!result) {
|
||||
try {
|
||||
if (log_lvl) console.log(`ROOT LOAD: No cache. Starting site lookup V3 for ${fqdn}...`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`ROOT LOAD: No cache. Starting site lookup V3 for ${fqdn}...`
|
||||
);
|
||||
|
||||
// Use dedicated Bootstrap key — limited permissions, no account_id required.
|
||||
// Key is injected at build time from PUBLIC_AE_BOOTSTRAP_KEY in .env.
|
||||
@@ -226,14 +274,24 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
view: 'base',
|
||||
log_lvl
|
||||
});
|
||||
if (log_lvl) console.log(`ROOT LOAD: Site lookup result for ${fqdn}:`, result);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`ROOT LOAD: Site lookup result for ${fqdn}:`,
|
||||
result
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(`ROOT LOAD: Site lookup critical failure for ${fqdn}.`, err);
|
||||
console.error(
|
||||
`ROOT LOAD: Site lookup critical failure for ${fqdn}.`,
|
||||
err
|
||||
);
|
||||
api_error = true;
|
||||
}
|
||||
} else {
|
||||
// We have a result (cache or native), fire off the refresh in the background to update Dexie
|
||||
if (log_lvl) console.log('ROOT LOAD: Result already obtained. Background refresh triggered.');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'ROOT LOAD: Result already obtained. Background refresh triggered.'
|
||||
);
|
||||
lookup_site_domain({
|
||||
api_cfg: ae_api_init,
|
||||
fqdn,
|
||||
@@ -243,14 +301,22 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
}
|
||||
|
||||
// Defensive check: if result is false (common from API helper) or null, use emergency ghost
|
||||
if (!result || typeof result !== 'object' || result.account_id === 'ghost') {
|
||||
console.warn(`ROOT LOAD: Falsy or Ghost result for ${fqdn}. Forcing fallback message.`);
|
||||
if (
|
||||
!result ||
|
||||
typeof result !== 'object' ||
|
||||
result.account_id === 'ghost'
|
||||
) {
|
||||
console.warn(
|
||||
`ROOT LOAD: Falsy or Ghost result for ${fqdn}. Forcing fallback message.`
|
||||
);
|
||||
result = {
|
||||
id: 'ghost',
|
||||
id_random: 'ghost',
|
||||
account_id_random: 'ghost',
|
||||
account_code: 'ghost',
|
||||
account_name: api_error ? 'API Connection Failed' : 'Domain Not Registered',
|
||||
account_name: api_error
|
||||
? 'API Connection Failed'
|
||||
: 'Domain Not Registered',
|
||||
site_id_random: 'ghost',
|
||||
site_domain_id_random: 'ghost',
|
||||
enable: '1',
|
||||
@@ -278,7 +344,8 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
ae_loc_init['account_name'] = json_data.account_name || 'Ghost Account';
|
||||
|
||||
ae_loc_init['site_id'] = json_data.site_id || 'ghost';
|
||||
ae_loc_init['site_domain_id'] = json_data.site_domain_id || json_data.site_domain_id || 'ghost';
|
||||
ae_loc_init['site_domain_id'] =
|
||||
json_data.site_domain_id || json_data.site_domain_id || 'ghost';
|
||||
ae_loc_init['site_enable'] = json_data.enable || '1';
|
||||
ae_loc_init['site_header_image_path'] = json_data.header_image_path || '';
|
||||
ae_loc_init['site_style_href'] = json_data.style_href || '';
|
||||
@@ -286,12 +353,16 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
ae_loc_init['site_access_code_kv'] = json_data.access_code_kv_json || {};
|
||||
ae_loc_init['site_cfg_json'] = json_data.cfg_json || {};
|
||||
ae_loc_init['site_access_key'] = json_data.access_key || '';
|
||||
ae_loc_init['site_domain_access_key'] = json_data.site_domain_access_key || '';
|
||||
ae_loc_init['site_domain_access_key'] =
|
||||
json_data.site_domain_access_key || '';
|
||||
|
||||
ae_loc_init['base_url'] = url.origin;
|
||||
ae_loc_init['hostname'] = url.hostname;
|
||||
|
||||
if (!ae_loc_init['site_access_key'] && !ae_loc_init['site_domain_access_key']) {
|
||||
if (
|
||||
!ae_loc_init['site_access_key'] &&
|
||||
!ae_loc_init['site_domain_access_key']
|
||||
) {
|
||||
ae_loc_init['key_checked'] = true;
|
||||
ae_loc_init['allow_access'] = true;
|
||||
} else {
|
||||
@@ -304,10 +375,11 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
if (access_key == ae_loc_init['site_access_key']) {
|
||||
ae_loc_init['key_checked'] = ae_loc_init['site_access_key'];
|
||||
ae_loc_init['allow_access'] = ae_loc_init['site_access_key'];
|
||||
}
|
||||
else if (access_key == ae_loc_init['site_domain_access_key']) {
|
||||
ae_loc_init['key_checked'] = ae_loc_init['site_domain_access_key'];
|
||||
ae_loc_init['allow_access'] = ae_loc_init['site_domain_access_key'];
|
||||
} else if (access_key == ae_loc_init['site_domain_access_key']) {
|
||||
ae_loc_init['key_checked'] =
|
||||
ae_loc_init['site_domain_access_key'];
|
||||
ae_loc_init['allow_access'] =
|
||||
ae_loc_init['site_domain_access_key'];
|
||||
} else {
|
||||
ae_loc_init['key_checked'] = true;
|
||||
ae_loc_init['allow_access'] = false;
|
||||
@@ -323,7 +395,8 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
// });
|
||||
// }
|
||||
|
||||
ae_loc_init['account_name'] = json_data.account_name || 'Account Name Not Set';
|
||||
ae_loc_init['account_name'] =
|
||||
json_data.account_name || 'Account Name Not Set';
|
||||
|
||||
// ae_acct['api'] = ae_api_init; // DO NOT USE: This overwrites our isolated clone from line 65
|
||||
ae_acct['loc'] = ae_loc_init;
|
||||
@@ -331,7 +404,7 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
ae_acct['slct'] = {
|
||||
account_id: account_id,
|
||||
site_domain_id: ae_loc_init.site_domain_id,
|
||||
site_id: ae_loc_init.site_id,
|
||||
site_id: ae_loc_init.site_id
|
||||
// event_id: ae_loc_init.site_cfg_json?.slct__event_id,
|
||||
// event_badge_template_id: ae_loc_init.site_cfg_json?.slct__event_badge_template_id,
|
||||
// sponsorship_cfg_id: ae_loc_init.site_cfg_json?.slct__sponsorship_cfg_id
|
||||
@@ -339,7 +412,11 @@ export async function load({ fetch, params, parent, route, url }) {
|
||||
|
||||
data_struct[account_id] = ae_acct;
|
||||
|
||||
if (log_lvl) console.log('ROOT LOAD: Final data_struct structure ready.', Object.keys(data_struct));
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'ROOT LOAD: Final data_struct structure ready.',
|
||||
Object.keys(data_struct)
|
||||
);
|
||||
|
||||
return data_struct;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,42 @@
|
||||
<script lang="ts">
|
||||
// console.log(`ae_root +page data:`, data);
|
||||
// console.log(`ae_root +page data:`, data);
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
import { Brain, House, Library, RefreshCw, RefreshCcwDot, Satellite } from '@lucide/svelte';
|
||||
import {
|
||||
Brain,
|
||||
House,
|
||||
Library,
|
||||
RefreshCw,
|
||||
RefreshCcwDot,
|
||||
Satellite
|
||||
} from '@lucide/svelte';
|
||||
|
||||
// import { PUBLIC_TESTING } from '$env/static/public';
|
||||
// console.log(`AE Config - +page.svelte PUBLIC_TESTING:`, PUBLIC_TESTING);
|
||||
// import { PUBLIC_TESTING } from '$env/static/public';
|
||||
// console.log(`AE Config - +page.svelte PUBLIC_TESTING:`, PUBLIC_TESTING);
|
||||
|
||||
import Element_data_store from '$lib/elements/element_data_store.svelte';
|
||||
import Element_data_store from '$lib/elements/element_data_store.svelte';
|
||||
|
||||
// import { api } from '$lib/api';
|
||||
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
interface Props {
|
||||
/** @type {import('./$types').PageData} */
|
||||
data: any;
|
||||
}
|
||||
// import { api } from '$lib/api';
|
||||
import {
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
interface Props {
|
||||
/** @type {import('./$types').PageData} */
|
||||
data: any;
|
||||
}
|
||||
|
||||
let { data }: Props = $props();
|
||||
// import type { key_val } from '$lib/ae_stores';
|
||||
// console.log($ae_loc, $ae_sess, $ae_api);
|
||||
let { data }: Props = $props();
|
||||
// import type { key_val } from '$lib/ae_stores';
|
||||
// console.log($ae_loc, $ae_sess, $ae_api);
|
||||
|
||||
onMount(() => {
|
||||
console.log(`Root: +page.svelte; URL: ${data.url}`);
|
||||
});
|
||||
onMount(() => {
|
||||
console.log(`Root: +page.svelte; URL: ${data.url}`);
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -31,23 +44,24 @@
|
||||
</svelte:head>
|
||||
|
||||
<section
|
||||
class="ae_root md:container h-full mx-auto flex flex-col items-center p-4 space-y-12"
|
||||
class="ae_root mx-auto flex h-full flex-col items-center space-y-12 p-4 md:container"
|
||||
class:ae_root--auth_access={$ae_loc.auth_access}
|
||||
class:ae_root--public_access={$ae_loc.public_access}
|
||||
class:ae_root--trusted_access={$ae_loc.trusted_access}
|
||||
class:ae_root--administrator_access={$ae_loc.administrator_access}
|
||||
class:ae_root--manager_access={$ae_loc.manager_access}
|
||||
class:ae_root--super_access={$ae_loc.super_access}
|
||||
>
|
||||
class:ae_root--super_access={$ae_loc.super_access}>
|
||||
<Element_data_store
|
||||
ds_code="hub__site__root_page_header"
|
||||
ds_type="html"
|
||||
for_type={null}
|
||||
for_id={null}
|
||||
ds_name="Default: AE Hub - Site root page header HTML"
|
||||
class_li={!$ae_loc.manager_access && $ae_sess.ds_loaded.hub__site__root_page_header === false ? 'hidden' : ''}
|
||||
bind:ds_loaded={$ae_sess.ds_loaded.hub__site__root_page_header}
|
||||
/>
|
||||
class_li={!$ae_loc.manager_access &&
|
||||
$ae_sess.ds_loaded.hub__site__root_page_header === false
|
||||
? 'hidden'
|
||||
: ''}
|
||||
bind:ds_loaded={$ae_sess.ds_loaded.hub__site__root_page_header} />
|
||||
<!-- page header DS: {$ae_sess.ds_loaded.hub__site__root_page_header} -->
|
||||
|
||||
<Element_data_store
|
||||
@@ -57,24 +71,24 @@
|
||||
for_id={null}
|
||||
ds_name="Default: AE Hub - Site root page content HTML"
|
||||
show_edit={false}
|
||||
class_li={!$ae_loc.manager_access && $ae_sess.ds_loaded.hub__site__root_page_content === false ? 'hidden' : 'grow'}
|
||||
bind:ds_loaded={$ae_sess.ds_loaded.hub__site__root_page_content}
|
||||
/>
|
||||
class_li={!$ae_loc.manager_access &&
|
||||
$ae_sess.ds_loaded.hub__site__root_page_content === false
|
||||
? 'hidden'
|
||||
: 'grow'}
|
||||
bind:ds_loaded={$ae_sess.ds_loaded.hub__site__root_page_content} />
|
||||
<!-- page content DS: {$ae_sess.ds_loaded.hub__site__root_page_content} -->
|
||||
|
||||
<section class="flex flex-col gap-2 items-center p-4 space-y-6">
|
||||
<section class="flex flex-col items-center gap-2 space-y-6 p-4">
|
||||
<div
|
||||
data-sveltekit-preload-data="false"
|
||||
class="flex flex-row flex-wrap items-center justify-center"
|
||||
>
|
||||
class="flex flex-row flex-wrap items-center justify-center">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
window.location.reload();
|
||||
}}
|
||||
class="btn btn-sm m-1 preset-tonal-surface hover:preset-outlined-warning text-error-300 hover:text-error-800 transition-all"
|
||||
title="Reload page to clear some caches and check for updates"
|
||||
>
|
||||
class="btn btn-sm preset-tonal-surface hover:preset-outlined-warning text-error-300 hover:text-error-800 m-1 transition-all"
|
||||
title="Reload page to clear some caches and check for updates">
|
||||
<!-- <span class="fas fa-sync mx-1"></span> -->
|
||||
<RefreshCw class="mx-1" />
|
||||
Reload
|
||||
@@ -105,9 +119,8 @@
|
||||
);
|
||||
window.location.reload();
|
||||
}}
|
||||
class="btn btn-sm m-1 p-1 preset-tonal-surface hover:preset-outlined-warning text-error-300 hover:text-error-800 transition-all"
|
||||
title="Clear IDB, localStorage, and sessionStorage and then reload to clear the page cache"
|
||||
>
|
||||
class="btn btn-sm preset-tonal-surface hover:preset-outlined-warning text-error-300 hover:text-error-800 m-1 p-1 transition-all"
|
||||
title="Clear IDB, localStorage, and sessionStorage and then reload to clear the page cache">
|
||||
<!-- <span class="fas fa-sync mx-1"></span> -->
|
||||
<RefreshCcwDot class="mx-1" />
|
||||
Clear Storage and Reload
|
||||
@@ -126,11 +139,10 @@
|
||||
$ae_sess.ds_loaded.hub__site__root_page_footer === false
|
||||
? 'hidden'
|
||||
: ''}
|
||||
bind:ds_loaded={$ae_sess.ds_loaded.hub__site__root_page_footer}
|
||||
/>
|
||||
bind:ds_loaded={$ae_sess.ds_loaded.hub__site__root_page_footer} />
|
||||
<!-- page footer DS: {$ae_sess.ds_loaded.hub__site__root_page_footer} -->
|
||||
|
||||
<ol class="list-decimal hidden">
|
||||
<ol class="hidden list-decimal">
|
||||
<li>Placeholder for Tailwind</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user