Last round of prettier: npx prettier --write src/

This commit is contained in:
Scott Idem
2026-03-24 13:27:40 -04:00
parent 23d25bf65a
commit a8f3c29b9f
146 changed files with 13201 additions and 9277 deletions

View File

@@ -1,295 +1,320 @@
<script lang="ts">
// *** Import Svelte specific
import { onDestroy, onMount, tick } from 'svelte';
import { afterNavigate } from '$app/navigation';
// *** Import Svelte specific
import { onDestroy, onMount, tick } from 'svelte';
import { afterNavigate } from '$app/navigation';
// *** Import other supporting libraries
// import { liveQuery } from "dexie";
import { Lock, LockOpen, RefreshCw, ShieldEllipsis, ShieldMinus, ShieldPlus, ShieldUser, Unlink, User, UserCheck, UserRound, Wand2 } from '@lucide/svelte';
// *** Import Aether specific variables and functions
import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
// import { core_func } from '$lib/ae_core/ae_core_functions';
// Ideally the Event related stores should not be imported here?
import { events_loc } from '$lib/stores/ae_events_stores';
// import { db_events } from "$lib/db_events";
// *** Import other supporting libraries
// import { liveQuery } from "dexie";
import {
Lock,
LockOpen,
RefreshCw,
ShieldEllipsis,
ShieldMinus,
ShieldPlus,
ShieldUser,
Unlink,
User,
UserCheck,
UserRound,
Wand2
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
import { ae_util } from '$lib/ae_utils/ae_utils';
import {
ae_loc,
ae_sess,
ae_api,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
// import { core_func } from '$lib/ae_core/ae_core_functions';
// Ideally the Event related stores should not be imported here?
import { events_loc } from '$lib/stores/ae_events_stores';
// import { db_events } from "$lib/db_events";
// export let hidden: boolean = false;
// export let hidden: boolean = false;
// *** Setup Svelte properties
interface Props {
log_lvl?: number;
hide?: null | boolean;
focus_input: boolean;
expand?: boolean;
show_passcode_input: boolean;
trigger_clear_access: null | boolean;
// *** Setup Svelte properties
interface Props {
log_lvl?: number;
hide?: null | boolean;
focus_input: boolean;
expand?: boolean;
show_passcode_input: boolean;
trigger_clear_access: null | boolean;
}
let {
log_lvl = $bindable(0),
hide = $bindable(false),
focus_input = $bindable(false),
expand = $bindable(false),
show_passcode_input = $bindable(false),
trigger_clear_access = $bindable(null)
}: Props = $props();
let entered_passcode: null | string = $state(null);
let checked_passcode: null | string = $state(null);
// let password_checked: boolean = $state(false);
// let entered_passcode: null|string = '';
// let show_passcode_input: boolean = $state(false);
// let show_passcode_input: boolean = false;
// let trigger: null|string|boolean = null;
let trigger: null | string | boolean = $state(null);
// const dispatch = createEventDispatcher();
// WARNING: There is a bug (I think) around here related to the entered_passcode not being cleared. There seems to be something different about how Svelte handles state in this component compared to the others. This might be related to the `$effect` or `$derived` usage. Maybe there are conflicting things trying to update the $ae_loc store at the same time.
onMount(() => {
// log_lvl = 2;
if (log_lvl > 1) {
console.log('** Element Mounted: ** Element Access Type');
}
entered_passcode = '';
trigger = null;
// /** @type {HTMLElement | null} */
// const to_focus = document.getElementById('access_passcode_input');
// to_focus?.focus();
});
onDestroy(() => {
if (log_lvl > 1) {
console.log('** Element Destroyed: ** Element Access Type');
}
let {
log_lvl = $bindable(0),
hide = $bindable(false),
focus_input = $bindable(false),
expand = $bindable(false),
show_passcode_input = $bindable(false),
trigger_clear_access = $bindable(null)
}: Props = $props();
// Clean up any references or listeners if needed
entered_passcode = null; // Clear the entered passcode
show_passcode_input = false;
let entered_passcode: null | string = $state(null);
let checked_passcode: null | string = $state(null);
// let password_checked: boolean = $state(false);
// let entered_passcode: null|string = '';
// let show_passcode_input: boolean = $state(false);
// let show_passcode_input: boolean = false;
// Reset trigger
trigger = null;
});
// let trigger: null|string|boolean = null;
let trigger: null | string | boolean = $state(null);
// afterNavigate(() => {
// /** @type {HTMLElement | null} */
// const to_focus = document.getElementById('access_passcode_input');
// to_focus?.focus();
// });
// const dispatch = createEventDispatcher();
$effect(() => {
if (
entered_passcode &&
entered_passcode.length >= 5 &&
entered_passcode != checked_passcode
) {
checked_passcode = entered_passcode;
if (log_lvl) {
console.log(`entered_passcode=${entered_passcode}`);
}
handle_check_access_type_passcode();
}
});
// WARNING: There is a bug (I think) around here related to the entered_passcode not being cleared. There seems to be something different about how Svelte handles state in this component compared to the others. This might be related to the `$effect` or `$derived` usage. Maybe there are conflicting things trying to update the $ae_loc store at the same time.
onMount(() => {
$effect(() => {
if (trigger && $ae_loc.access_type) {
trigger = false;
if (log_lvl) {
console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
}
let access_checks_results = ae_util.process_permission_checks(
$ae_loc.access_type
);
$ae_loc = { ...$ae_loc, ...access_checks_results };
$ae_loc = $ae_loc;
$ae_loc.sys_menu.expand = false;
} else if (trigger) {
trigger = false;
if (log_lvl) {
console.log(`$ae_loc.access_type=not set`);
}
// Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
let access_checks_results = ae_util.process_permission_checks('');
$ae_loc = { ...$ae_loc, ...access_checks_results };
$ae_loc = $ae_loc;
}
});
// This does not seem to work. I feel like it should though...?
$effect(() => {
if (!hide && focus_input) {
focus_input = false;
// log_lvl = 2;
// await tick();
// document.getElementById('access_passcode_input')?.focus();
if (log_lvl > 1) {
console.log('** Element Mounted: ** Element Access Type');
console.log('Effect: Setting focus on the passcode input field');
}
entered_passcode = '';
trigger = null;
/** @type {HTMLElement | null} */
const to_focus = document.getElementById('access_passcode_input');
to_focus?.focus();
}
});
// /** @type {HTMLElement | null} */
// const to_focus = document.getElementById('access_passcode_input');
// to_focus?.focus();
});
onDestroy(() => {
if (log_lvl > 1) {
console.log('** Element Destroyed: ** Element Access Type');
$effect(() => {
if (trigger_clear_access) {
trigger_clear_access = false;
if (log_lvl) {
console.log(`trigger_clear_access=${trigger_clear_access}`);
}
handle_clear_access();
}
});
// Clean up any references or listeners if needed
entered_passcode = null; // Clear the entered passcode
show_passcode_input = false;
function handle_check_access_type_passcode() {
if (log_lvl > 1) {
console.log(
`*** handle_check_access_type_passcode() *** passcode list:`,
$ae_loc.site_access_code_kv
);
}
// Reset trigger
trigger = null;
});
// Reminder: super > manager > administrator > trusted > public > authenticated > anonymous
// afterNavigate(() => {
// /** @type {HTMLElement | null} */
// const to_focus = document.getElementById('access_passcode_input');
// to_focus?.focus();
// });
$effect(() => {
if (entered_passcode && entered_passcode.length >= 5) {
if (
entered_passcode &&
entered_passcode.length >= 5 &&
entered_passcode != checked_passcode
$ae_loc.site_access_code_kv.super.length >= 8 &&
$ae_loc.site_access_code_kv.super == entered_passcode
) {
checked_passcode = entered_passcode;
if (log_lvl) {
console.log(`entered_passcode=${entered_passcode}`);
}
handle_check_access_type_passcode();
}
});
console.log('Super passcode matched');
$effect(() => {
if (trigger && $ae_loc.access_type) {
trigger = false;
if (log_lvl) {
console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
}
window.localStorage.setItem('access_type', 'super');
let access_checks_results = ae_util.process_permission_checks($ae_loc.access_type);
$ae_loc.access_type = 'super';
} else if (
$ae_loc.site_access_code_kv.manager.length >= 5 &&
$ae_loc.site_access_code_kv.manager == entered_passcode
) {
console.log('Manager passcode matched');
$ae_loc = { ...$ae_loc, ...access_checks_results };
$ae_loc = $ae_loc;
$ae_loc.sys_menu.expand = false;
} else if (trigger) {
trigger = false;
if (log_lvl) {
console.log(`$ae_loc.access_type=not set`);
}
window.localStorage.setItem('access_type', 'manager');
// Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
let access_checks_results = ae_util.process_permission_checks('');
$ae_loc.access_type = 'manager';
} else if (
$ae_loc.site_access_code_kv.administrator.length >= 5 &&
$ae_loc.site_access_code_kv.administrator == entered_passcode
) {
console.log('Administrator passcode matched');
$ae_loc = { ...$ae_loc, ...access_checks_results };
$ae_loc = $ae_loc;
}
});
window.localStorage.setItem('access_type', 'administrator');
// This does not seem to work. I feel like it should though...?
$effect(() => {
if (!hide && focus_input) {
focus_input = false;
// log_lvl = 2;
// await tick();
// document.getElementById('access_passcode_input')?.focus();
$ae_loc.access_type = 'administrator';
} else if (
$ae_loc.site_access_code_kv.trusted.length >= 5 &&
$ae_loc.site_access_code_kv.trusted == entered_passcode
) {
console.log('Trusted passcode matched');
window.localStorage.setItem('access_type', 'trusted');
$ae_loc.access_type = 'trusted';
} else if (
$ae_loc.site_access_code_kv.public.length >= 5 &&
$ae_loc.site_access_code_kv.public == entered_passcode
) {
console.log('Public passcode matched');
window.localStorage.setItem('access_type', 'public');
$ae_loc.access_type = 'public';
} else if (
$ae_loc.site_access_code_kv.authenticated == entered_passcode
) {
console.log('Authenticated passcode matched');
window.localStorage.setItem('access_type', 'authenticated');
$ae_loc.access_type = 'authenticated';
} else {
if (log_lvl > 1) {
console.log('Effect: Setting focus on the passcode input field');
}
/** @type {HTMLElement | null} */
const to_focus = document.getElementById('access_passcode_input');
to_focus?.focus();
}
});
$effect(() => {
if (trigger_clear_access) {
trigger_clear_access = false;
if (log_lvl) {
console.log(`trigger_clear_access=${trigger_clear_access}`);
}
handle_clear_access();
}
});
function handle_check_access_type_passcode() {
if (log_lvl > 1) {
console.log(
`*** handle_check_access_type_passcode() *** passcode list:`,
$ae_loc.site_access_code_kv
);
}
// Reminder: super > manager > administrator > trusted > public > authenticated > anonymous
if (entered_passcode && entered_passcode.length >= 5) {
if (
$ae_loc.site_access_code_kv.super.length >= 8 &&
$ae_loc.site_access_code_kv.super == entered_passcode
) {
console.log('Super passcode matched');
window.localStorage.setItem('access_type', 'super');
$ae_loc.access_type = 'super';
} else if (
$ae_loc.site_access_code_kv.manager.length >= 5 &&
$ae_loc.site_access_code_kv.manager == entered_passcode
) {
console.log('Manager passcode matched');
window.localStorage.setItem('access_type', 'manager');
$ae_loc.access_type = 'manager';
} else if (
$ae_loc.site_access_code_kv.administrator.length >= 5 &&
$ae_loc.site_access_code_kv.administrator == entered_passcode
) {
console.log('Administrator passcode matched');
window.localStorage.setItem('access_type', 'administrator');
$ae_loc.access_type = 'administrator';
} else if (
$ae_loc.site_access_code_kv.trusted.length >= 5 &&
$ae_loc.site_access_code_kv.trusted == entered_passcode
) {
console.log('Trusted passcode matched');
window.localStorage.setItem('access_type', 'trusted');
$ae_loc.access_type = 'trusted';
} else if (
$ae_loc.site_access_code_kv.public.length >= 5 &&
$ae_loc.site_access_code_kv.public == entered_passcode
) {
console.log('Public passcode matched');
window.localStorage.setItem('access_type', 'public');
$ae_loc.access_type = 'public';
} else if ($ae_loc.site_access_code_kv.authenticated == entered_passcode) {
console.log('Authenticated passcode matched');
window.localStorage.setItem('access_type', 'authenticated');
$ae_loc.access_type = 'authenticated';
} else {
if (log_lvl > 1) {
console.log('Entered passcode does not match any of the site access codes.');
}
if ($ae_loc.access_type != 'anonymous') {
console.log('Access type is not anonymous');
}
// window.localStorage.setItem('access_type', 'anonymous');
// $ae_loc.access_type = 'anonymous';
// trigger = 'process_permission_check';
// $ae_loc = $ae_loc; // Trigger Svelte just in case
// ae_loc.set($ae_loc);
// console.log($ae_loc);
// dispatch_access_type_changed();
return false;
console.log(
'Entered passcode does not match any of the site access codes.'
);
}
entered_passcode = '';
show_passcode_input = false;
trigger = 'process_permission_check';
$ae_loc.app_cfg.show_element__menu = false;
$ae_loc.app_cfg.show_element__menu_btn = true;
// WARNING 2024-08-21: For some reason the config element does not auto show or hide when the access type changes.
if (!$ae_loc.iframe && $ae_loc.authenticated_access) {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = true;
} else if ($ae_loc.iframe && $ae_loc.trusted_access) {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = true;
} else {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = false;
if ($ae_loc.access_type != 'anonymous') {
console.log('Access type is not anonymous');
}
// window.localStorage.setItem('access_type', 'anonymous');
// $ae_loc.access_type = 'anonymous';
// trigger = 'process_permission_check';
// $ae_loc = $ae_loc; // Trigger Svelte just in case
// ae_loc.set($ae_loc);
// console.log($ae_loc);
// dispatch_access_type_changed();
return true;
} else {
if (log_lvl > 1) {
console.log('Entered passcode too short.');
}
// $ae_loc.access_type = null; // 'anonymous';
// dispatch_access_type_changed()
return null;
return false;
}
}
function handle_clear_access() {
// console.log('handle_clear_access()');
// NOTE: I think it makes since to reset this to anonymous even if logged in as an admin or similar.
window.localStorage.setItem('access_type', 'anonymous');
// $ae_loc.access_type = null; // 'anonymous';
// Revert back to the user's access type after quick access (temporarily escalate permissions) is turned off.
$ae_loc.access_type = $ae_loc.user_access_type ?? 'anonymous';
entered_passcode = '';
show_passcode_input = false;
trigger = 'process_permission_check';
entered_passcode = ''; // Clear the entered passcode
// Reset so the same passcode can be re-entered after clearing.
// Without this, the $effect guard (entered_passcode != checked_passcode) silently
// blocks re-entry of the same passcode until the component remounts (page refresh).
checked_passcode = null;
show_passcode_input = true;
$ae_loc.app_cfg.show_element__menu = false;
$ae_loc.app_cfg.show_element__menu_btn = true;
$ae_loc.edit_mode = false;
// WARNING 2024-08-21: For some reason the config element does not auto show or hide when the access type changes.
if (!$ae_loc.iframe && $ae_loc.authenticated_access) {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = true;
} else if ($ae_loc.iframe && $ae_loc.trusted_access) {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = true;
} else {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = false;
}
// dispatch_access_type_changed();
return true;
} else {
if (log_lvl > 1) {
console.log('Entered passcode too short.');
}
// $ae_loc.access_type = null; // 'anonymous';
// dispatch_access_type_changed()
return null;
}
}
function handle_clear_access() {
// console.log('handle_clear_access()');
// NOTE: I think it makes since to reset this to anonymous even if logged in as an admin or similar.
window.localStorage.setItem('access_type', 'anonymous');
// $ae_loc.access_type = null; // 'anonymous';
// Revert back to the user's access type after quick access (temporarily escalate permissions) is turned off.
$ae_loc.access_type = $ae_loc.user_access_type ?? 'anonymous';
trigger = 'process_permission_check';
entered_passcode = ''; // Clear the entered passcode
// Reset so the same passcode can be re-entered after clearing.
// Without this, the $effect guard (entered_passcode != checked_passcode) silently
// blocks re-entry of the same passcode until the component remounts (page refresh).
checked_passcode = null;
show_passcode_input = true;
$ae_loc.app_cfg.show_element__menu = false;
$ae_loc.app_cfg.show_element__menu_btn = true;
$ae_loc.edit_mode = false;
return true;
}
</script>
<section
@@ -298,24 +323,23 @@
ae_access_type
hidden-print
bg-blue-100 text-gray-900
dark:bg-blue-800 dark:text-gray-200
flex w-full
flex-col flex-wrap
flex flex-col flex-wrap gap-1
items-end justify-center
items-end justify-center gap-1 border-2
border-gray-200 bg-blue-100
w-full
p-1
border-2 border-gray-200
text-gray-900
transition-all delay-150
duration-300 delay-150 hover:delay-1000 hover:ease-out
transition-all
duration-300 hover:delay-1000 hover:ease-out dark:bg-blue-800
dark:text-gray-200
"
class:hidden={hide}
>
class:hidden={hide}>
<!-- class:hidden={!$ae_sess.show__sign_in_out__fields} -->
<header class="ae_header hidden">
<h2 class="text-sm text-center font-semibold">Passcode Sign In</h2>
<h2 class="text-center text-sm font-semibold">Passcode Sign In</h2>
</header>
<!-- Show list of authorized sessions and presentations for a user -->
@@ -349,9 +373,8 @@
// tick();
return false;
}}
class="btn btn-sm preset-tonal-success border border-success-500 hover:preset-filled-success-500 transition-all hover:transition-all *:hover:inline"
title="Syncing the local configuration with the remote configuration."
>
class="btn btn-sm preset-tonal-success border-success-500 hover:preset-filled-success-500 border transition-all hover:transition-all *:hover:inline"
title="Syncing the local configuration with the remote configuration.">
<RefreshCw size="1em" class="m-1" />
<span class="hidden"> Sync </span>
</button>
@@ -369,9 +392,8 @@
// tick();
return true;
}}
class="btn btn-sm preset-tonal-warning border border-warning-500 hover:preset-filled-warning-500 transition-all hover:transition-all *:hover:inline"
title="Currently not syncing with the remote server. Re-sync the local configuration with the remote configuration?"
>
class="btn btn-sm preset-tonal-warning border-warning-500 hover:preset-filled-warning-500 border transition-all hover:transition-all *:hover:inline"
title="Currently not syncing with the remote server. Re-sync the local configuration with the remote configuration?">
<Unlink size="1em" class="m-1" />
<span class="hidden"> Re-sync? </span>
</button>
@@ -411,7 +433,8 @@
{/if}
</div>
<div class="flex flex-row flex-wrap gap-1 items-end justify-end w-full transition-all">
<div
class="flex w-full flex-row flex-wrap items-end justify-end gap-1 transition-all">
{#if $ae_loc?.access_type && $ae_loc?.access_type == 'anonymous'}
<span>
<button
@@ -421,15 +444,16 @@
show_passcode_input = !show_passcode_input;
}}
class="btn btn-sm preset-tonal-success hover:preset-filled-warning-500 access_type_unlock_btn transition-all"
title={show_passcode_input ? 'Cancel passcode entry' : 'Enter a passcode to unlock access'}
>
title={show_passcode_input
? 'Cancel passcode entry'
: 'Enter a passcode to unlock access'}>
{#if show_passcode_input}
<LockOpen size="1em" class="mx-1" />
<span>Cancel</span>
{:else}
<Lock size="1em" class="mx-1" />
<span class="lock_icon">Locked</span>
<LockOpen size="1em" class="mx-1 unlock_icon hidden" />
<LockOpen size="1em" class="unlock_icon mx-1 hidden" />
<span class="unlock_text">Access?</span>
{/if}
</button>
@@ -437,14 +461,13 @@
{/if}
{#if $ae_loc?.access_type && $ae_loc?.access_type != 'anonymous'}
<span class="flex flex-row gap-1 items-center justify-center">
<span class="flex flex-row items-center justify-center gap-1">
<!-- <span class="fas fa-unlock mx-1"></span> -->
<ShieldPlus class="inline-block" />
<span
class="*:hover:inline"
title={`Current access type/level: ${$ae_loc.access_type}`}
>
title={`Current access type/level: ${$ae_loc.access_type}`}>
{#if $ae_loc.access_type == 'super'}
<Wand2 size="1em" class="m-1" />
<span class="hidden">Super</span>
@@ -478,9 +501,8 @@
// trigger_clear_access = true;
show_passcode_input = true;
}}
class="btn btn-sm variant-outline-surface hover:preset-tonal-warning border border-warning-500 transition-all"
title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}
>
class="btn btn-sm variant-outline-surface hover:preset-tonal-warning border-warning-500 border transition-all"
title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}>
<!-- <span class="fas fa-lock mx-1"></span> -->
<!-- <ShieldMinus /> -->
<ShieldEllipsis class="inline-block" />
@@ -495,9 +517,8 @@
show_passcode_input = true;
// show_passcode_input = true;
}}
class="btn btn-sm variant-outline-warning hover:preset-tonal-warning border border-warning-500 transition-all"
title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}
>
class="btn btn-sm variant-outline-warning hover:preset-tonal-warning border-warning-500 border transition-all"
title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}>
<!-- <span class="fas fa-lock mx-1"></span> -->
<ShieldMinus class="inline-block" />
Clear?
@@ -507,7 +528,8 @@
{/if}
{#if show_passcode_input}
<span class="flex flex-row gap-1 items-center justify-between w-full">
<span
class="flex w-full flex-row items-center justify-between gap-1">
<span>
<ShieldEllipsis class="inline-block text-gray-500" />
<span class="unlock_text text-sm">Passcode:</span>
@@ -521,8 +543,7 @@
class:hidden={!show_passcode_input}
type="text"
placeholder="Passcode"
autofocus={show_passcode_input}
/>
autofocus={show_passcode_input} />
<!-- <div class="current_text transition-all">{$ae_loc.access_type}</div> -->
</span>
{/if}
@@ -530,8 +551,8 @@
</section>
<style lang="scss">
/* BEGIN: AE's Svelte Quick Access Type component */
/*
/* BEGIN: AE's Svelte Quick Access Type component */
/*
#xxx-AE-Quick-Access-Type {
// position: absolute;
position: fixed;
@@ -569,7 +590,7 @@
}
*/
/*
/*
#xxx-AE-Quick-Access-Type:hover {
border-top: solid thin hsla(0,0%,0%,.95);
@@ -586,21 +607,21 @@
}
*/
/* #Access-Type .unlock_text {
/* #Access-Type .unlock_text {
transition: width 2s, height 2s, background-color 2s, transform 2s;
} */
/* END: Svelte Access Type component */
/* END: Svelte Access Type component */
.access_type_unlock_btn .unlock_text {
display: none;
}
.access_type_unlock_btn .unlock_text {
display: none;
}
.access_type_unlock_btn:hover .unlock_text {
display: initial;
/* outline: solid thin red; */
}
.access_type_unlock_btn:hover .unlock_text {
display: initial;
/* outline: solid thin red; */
}
/*
/*
.ae_access_type .current_text {
display: none;
}

View File

@@ -1,44 +1,54 @@
<script lang="ts" module>
declare global {
interface Window {
dataLayer: any[];
gtag: (...args: any[]) => void;
}
declare global {
interface Window {
dataLayer: any[];
gtag: (...args: any[]) => void;
}
}
</script>
<script lang="ts">
import { browser } from '$app/environment';
import { browser } from '$app/environment';
interface Props {
log_lvl?: number;
site_google_tracking_id?: string;
}
interface Props {
log_lvl?: number;
site_google_tracking_id?: string;
}
let { log_lvl = 0, site_google_tracking_id = $bindable('') }: Props = $props();
let { log_lvl = 0, site_google_tracking_id = $bindable('') }: Props = $props();
$effect(() => {
if (browser && site_google_tracking_id) {
if (log_lvl) {
console.log(`AE Analytics: site_google_tracking_id = `, site_google_tracking_id);
}
$effect(() => {
if (browser && site_google_tracking_id) {
if (log_lvl) {
console.log(
`AE Analytics: site_google_tracking_id = `,
site_google_tracking_id
);
}
window.dataLayer = window.dataLayer || [];
window.gtag = window.gtag || function gtag() {
window.dataLayer = window.dataLayer || [];
window.gtag =
window.gtag ||
function gtag() {
window.dataLayer.push(arguments);
};
window.gtag('js', new Date());
window.gtag('config', site_google_tracking_id);
if (log_lvl) {
console.log(`AE Analytics: Google Analytics Tracking ID = `, site_google_tracking_id);
}
window.gtag('js', new Date());
window.gtag('config', site_google_tracking_id);
if (log_lvl) {
console.log(
`AE Analytics: Google Analytics Tracking ID = `,
site_google_tracking_id
);
}
});
}
});
</script>
<svelte:head>
{#if site_google_tracking_id}
<script async src="https://www.googletagmanager.com/gtag/js?id={site_google_tracking_id}"></script>
<script
async
src="https://www.googletagmanager.com/gtag/js?id={site_google_tracking_id}"></script>
{/if}
</svelte:head>

View File

@@ -1,103 +1,120 @@
<script lang="ts">
import { Code, Eraser, LockOpen, RefreshCw, Settings, ShieldCheck, ShieldUser, Trash2, UserRound, Users } from '@lucide/svelte';
import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
import E_app_url_builder from '$lib/app_components/e_app_url_builder.svelte';
import {
Code,
Eraser,
LockOpen,
RefreshCw,
Settings,
ShieldCheck,
ShieldUser,
Trash2,
UserRound,
Users
} from '@lucide/svelte';
import { ae_util } from '$lib/ae_utils/ae_utils';
import {
ae_loc,
ae_sess,
ae_api,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
import E_app_url_builder from '$lib/app_components/e_app_url_builder.svelte';
// import Element_theme from '$lib/e_app_theme.svelte';
// import Element_theme from '$lib/e_app_theme.svelte';
let notes: null | string = null;
let all: boolean = false;
let notes: null | string = null;
let all: boolean = false;
interface Props {
log_lvl?: number;
hide?: null | boolean;
expand?: boolean;
// export let theme_mode: null|string = null;
// set_theme_mode?: null|boolean;
// export let theme_name: null|string = null;
// set_theme_name?: null|boolean;
}
interface Props {
log_lvl?: number;
hide?: null | boolean;
expand?: boolean;
// export let theme_mode: null|string = null;
// set_theme_mode?: null|boolean;
// export let theme_name: null|string = null;
// set_theme_name?: null|boolean;
}
let {
log_lvl = $bindable(0),
hide = $bindable(false),
expand = $bindable(false)
// set_theme_mode = null,
// set_theme_name = null
}: Props = $props();
let {
log_lvl = $bindable(0),
hide = $bindable(false),
expand = $bindable(false)
// set_theme_mode = null,
// set_theme_name = null
}: Props = $props();
// const dispatch = createEventDispatcher();
// const dispatch = createEventDispatcher();
// onMount(() => {
// // console.log('** Element Mounted: ** Element App Config');
// if (set_theme_mode) {
// $slct_trigger = 'set_theme_mode';
// }
// if (set_theme_name) {
// $slct_trigger = 'set_theme_name';
// }
// });
// onMount(() => {
// // console.log('** Element Mounted: ** Element App Config');
// if (set_theme_mode) {
// $slct_trigger = 'set_theme_mode';
// }
// if (set_theme_name) {
// $slct_trigger = 'set_theme_name';
// }
// });
// $: if ($slct_trigger == 'set_theme_mode' && $ae_loc?.app_cfg?.theme_mode) {
// console.log(`$ae_loc.app_cfg.theme_mode=${$ae_loc?.app_cfg?.theme_mode}`);
// $slct_trigger = null;
// if ($ae_loc.app_cfg.theme_mode == 'light') {
// document.documentElement.classList.remove('dark');
// document.documentElement.classList.add('light');
// } else if ($ae_loc.app_cfg.theme_mode == 'dark') {
// document.documentElement.classList.remove('light');
// document.documentElement.classList.add('dark');
// }
// }
// $: if ($slct_trigger == 'set_theme_mode' && $ae_loc?.app_cfg?.theme_mode) {
// console.log(`$ae_loc.app_cfg.theme_mode=${$ae_loc?.app_cfg?.theme_mode}`);
// $slct_trigger = null;
// if ($ae_loc.app_cfg.theme_mode == 'light') {
// document.documentElement.classList.remove('dark');
// document.documentElement.classList.add('light');
// } else if ($ae_loc.app_cfg.theme_mode == 'dark') {
// document.documentElement.classList.remove('light');
// document.documentElement.classList.add('dark');
// }
// }
// $: if ($slct_trigger == 'set_theme_name' && $ae_loc?.app_cfg?.theme_name) {
// console.log(`$ae_loc?.app_cfg?.theme_name=${$ae_loc?.app_cfg?.theme_name}`);
// $slct_trigger = null;
// // Update the body attribute named "data-theme" to the current theme name.
// document.body.setAttribute('data-theme', $ae_loc?.app_cfg?.theme_name);
// }
// $: if ($slct_trigger == 'set_theme_name' && $ae_loc?.app_cfg?.theme_name) {
// console.log(`$ae_loc?.app_cfg?.theme_name=${$ae_loc?.app_cfg?.theme_name}`);
// $slct_trigger = null;
// // Update the body attribute named "data-theme" to the current theme name.
// document.body.setAttribute('data-theme', $ae_loc?.app_cfg?.theme_name);
// }
// $: if (entered_passcode && entered_passcode.length >= 5) {
// console.log(`entered_passcode=${entered_passcode}`);
// handle_check_access_type_passcode();
// }
// $: if (entered_passcode && entered_passcode.length >= 5) {
// console.log(`entered_passcode=${entered_passcode}`);
// handle_check_access_type_passcode();
// }
// $: if (trigger && $ae_loc.access_type) {
// console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
// $: if (trigger && $ae_loc.access_type) {
// console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
// let access_checks_results = ae_util.process_permission_checks($ae_loc.access_type);
// let access_checks_results = ae_util.process_permission_checks($ae_loc.access_type);
// $ae_loc = {...$ae_loc, ...access_checks_results};
// } else if (trigger) {
// console.log(`$ae_loc.access_type=not set`);
// $ae_loc = {...$ae_loc, ...access_checks_results};
// } else if (trigger) {
// console.log(`$ae_loc.access_type=not set`);
// // Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
// let access_checks_results = ae_util.process_permission_checks('');
// // Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
// let access_checks_results = ae_util.process_permission_checks('');
// $ae_loc = {...$ae_loc, ...access_checks_results};
// }
// $ae_loc = {...$ae_loc, ...access_checks_results};
// }
function handle_something() {
// console.log('*** handle_something() ***');
}
function handle_something() {
// console.log('*** handle_something() ***');
}
function handle_clear_storage(item: null | string) {
// console.log('*** handle_clear_storage() ***');
// window.localStorage.setItem('access_type', 'anonymous');
// return true;
}
function handle_clear_storage(item: null | string) {
// console.log('*** handle_clear_storage() ***');
// window.localStorage.setItem('access_type', 'anonymous');
// return true;
}
// function dispatch_something_changed() {
// console.log('*** dispatch_something_changed() ***');
// function dispatch_something_changed() {
// console.log('*** dispatch_something_changed() ***');
// console.log(ae_util);
// console.log($ae_loc);
// console.log(ae_util);
// console.log($ae_loc);
// dispatch('access_type_changed', {
// access_type: $ae_loc.access_type
// });
// }
// dispatch('access_type_changed', {
// access_type: $ae_loc.access_type
// });
// }
</script>
<!-- transition duration-500 delay-1000 hover:duration-500 hover:delay-1000 hover:transition-all -->
@@ -107,30 +124,28 @@
ae_app_cfg
hidden-print
bg-blue-100 text-gray-900
dark:bg-blue-800 dark:text-gray-200
flex w-72
max-w-72 flex-col
flex flex-col flex-wrap gap-1
items-end justify-center
w-72 max-w-72
p-1
flex-wrap items-end justify-center gap-1
border-2 border-gray-200
duration-300 delay-150 hover:delay-1000 hover:ease-out
transition-all
bg-blue-100 p-1
text-gray-900
transition-all delay-150
duration-300 hover:delay-1000 hover:ease-out dark:bg-blue-800
dark:text-gray-200
"
class:hidden={hide}
>
class:hidden={hide}>
<header class:hidden={!expand} class="ae_header w-full">
<h2 class="text-sm text-center font-semibold">Config</h2>
<h2 class="text-center text-sm font-semibold">Config</h2>
</header>
<div
class="ae_cfg_content text-xs space-y-4 my-4"
class="ae_cfg_content my-4 space-y-4 text-xs"
class:hidden={!expand}
data-sveltekit-preload-data="false"
>
data-sveltekit-preload-data="false">
<section class="space-y-2">
<div>
<h2 class="strong">Access Type:</h2>
@@ -172,12 +187,16 @@
</a>
{#if $ae_loc.iframe}
<a class="btn btn-sm preset-tonal-secondary" href="/?iframe=false">
<a
class="btn btn-sm preset-tonal-secondary"
href="/?iframe=false">
<Code size="1em" class="mx-1" />
Exit iframe Mode
</a>
{:else}
<a class="btn btn-sm preset-tonal-secondary" href="/?iframe=true">
<a
class="btn btn-sm preset-tonal-secondary"
href="/?iframe=true">
<Code size="1em" class="mx-1" />
Use iframe Mode
</a>
@@ -190,8 +209,7 @@
onclick={() => {
// $ae_loc.
window.location.reload();
}}
>
}}>
<RefreshCw size="1em" class="mx-1" />
Reload &
<Trash2 size="1em" class="mx-1" />
@@ -219,8 +237,7 @@
window.location.reload();
// alert('Local and Session Storage cleared and Indexed DBs deleted. You will probably want to refresh the page.');
}}
>
}}>
<Eraser size="1em" class="mx-1" />
Clear Storage & DB
</button>
@@ -235,7 +252,7 @@
<!-- class:justify-between={expand}
class:justify-end={!expand} -->
<div class="flex flex-row gap-2 items-center justify-between w-full">
<div class="flex w-full flex-row items-center justify-between gap-2">
<!-- {#if !expand} -->
<span>
{#if $ae_loc.access_type && $ae_loc.access_type != 'anonymous'}
@@ -270,14 +287,13 @@ class:justify-end={!expand} -->
<button
class="
ae_cfg_btn
btn btn-sm text-sm
preset-tonal-warning
group transition-all
btn btn-sm preset-tonal-warning
group
text-sm transition-all
"
onclick={() => {
expand = !expand;
}}
>
}}>
<!-- <span class="fas fa-cog m-1"></span> -->
<span class="inline-block" title="Settings">
<Settings class="m-1" />
@@ -287,8 +303,7 @@ class:justify-end={!expand} -->
cfg_text
hidden
group-hover:inline
"
>
">
Settings
</span>
</button>
@@ -296,21 +311,21 @@ class:justify-end={!expand} -->
</section>
<style lang="postcss">
.ae_cfg_btn .cfg_text {
/* display: none; */
}
.ae_cfg_btn .cfg_text {
/* display: none; */
}
.ae_cfg_btn:hover .cfg_text {
/* display: initial; */
/* outline: solid thin red; */
}
.ae_cfg_btn:hover .cfg_text {
/* display: initial; */
/* outline: solid thin red; */
}
/* .access_type .current_text {
/* .access_type .current_text {
display: none;
} */
/* .access_type:hover .current_text {
/* .access_type:hover .current_text {
display: initial;
} */
/* END: AE's Svelte App Config component */
/* END: AE's Svelte App Config component */
</style>

View File

@@ -1,73 +1,73 @@
<script lang="ts">
interface Props {
children?: import('svelte').Snippet;
log_lvl?: number;
value: any;
success?: boolean;
btn_text?: string;
btn_title?: string;
btn_class?: string;
hide_icon?: boolean;
hide_text?: boolean;
icon_name?: string;
interface Props {
children?: import('svelte').Snippet;
log_lvl?: number;
value: any;
success?: boolean;
btn_text?: string;
btn_title?: string;
btn_class?: string;
hide_icon?: boolean;
hide_text?: boolean;
icon_name?: string;
}
let {
children,
log_lvl = 0,
value = $bindable(''),
success = $bindable(false),
btn_text = 'Copy to Clipboard',
btn_title = 'Copy to Clipboard',
btn_class = 'btn btn-sm preset-tonal-warning text-warning-500 m-1',
hide_icon = false,
hide_text = false,
icon_name = 'copy' // copy, check, link
}: Props = $props();
// *** Import Svelte specific
// import { browser } from '$app/environment';
// *** Import other supporting libraries
import {
// ArrowBigRight,
// CircleX,
CircleCheck,
Copy,
// Eye, EyeOff,
// Key,
Link
// LogIn, LogOut, LockKeyhole,
// Mail, MailCheck,
// Menu,
// RefreshCw, RefreshCcw, RefreshCcwDot,
// ShieldEllipsis, ShieldMinus, ShieldPlus, ShieldUser,
// User, UserCheck
} from '@lucide/svelte';
$effect(() => {
if (log_lvl) {
console.log(`Clipboard component initialized with value:`, value);
}
});
let {
children,
log_lvl = 0,
value = $bindable(''),
success = $bindable(false),
btn_text = 'Copy to Clipboard',
btn_title = 'Copy to Clipboard',
btn_class = 'btn btn-sm preset-tonal-warning text-warning-500 m-1',
hide_icon = false,
hide_text = false,
icon_name = 'copy' // copy, check, link
}: Props = $props();
// Select your trigger element
// const elemButton: HTMLButtonElement | null = document.querySelector('[data-button]');
// *** Import Svelte specific
// import { browser } from '$app/environment';
// *** Import other supporting libraries
import {
// ArrowBigRight,
// CircleX,
CircleCheck,
Copy,
// Eye, EyeOff,
// Key,
Link
// LogIn, LogOut, LockKeyhole,
// Mail, MailCheck,
// Menu,
// RefreshCw, RefreshCcw, RefreshCcwDot,
// ShieldEllipsis, ShieldMinus, ShieldPlus, ShieldUser,
// User, UserCheck
} from '@lucide/svelte';
$effect(() => {
if (log_lvl) {
console.log(`Clipboard component initialized with value:`, value);
}
});
// Select your trigger element
// const elemButton: HTMLButtonElement | null = document.querySelector('[data-button]');
// Add a click event handler to the trigger
// elemButton?.addEventListener('click', () => {
// // Call the Clipboard API
// navigator.clipboard
// // Use the `writeText` method write content to the clipboard
// .writeText(value)
// // Handle confirmation
// .then(() => {
// if (log_lvl) {
// console.log(`Clipboard write successful: ${value}`);
// }
// success = true;
// });
// });
// Add a click event handler to the trigger
// elemButton?.addEventListener('click', () => {
// // Call the Clipboard API
// navigator.clipboard
// // Use the `writeText` method write content to the clipboard
// .writeText(value)
// // Handle confirmation
// .then(() => {
// if (log_lvl) {
// console.log(`Clipboard write successful: ${value}`);
// }
// success = true;
// });
// });
</script>
<button
@@ -93,15 +93,20 @@
// }
}}
class={btn_class}
title={btn_title}
>
title={btn_title}>
<!-- {@render btn_text} -->
{#if icon_name === 'link'}
<Link class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}" size="1.2em" />
<Link
class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}"
size="1.2em" />
{:else if icon_name === 'check'}
<CircleCheck class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}" size="1.2em" />
<CircleCheck
class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}"
size="1.2em" />
{:else}
<Copy class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}" size="1.2em" />
<Copy
class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}"
size="1.2em" />
{/if}
<span class={hide_text ? 'hidden' : 'inline-block'}>
{btn_text}

View File

@@ -1,25 +1,31 @@
<script lang="ts">
// *** Import Svelte specific
// *** Import Svelte specific
// *** Import other supporting libraries
import { Bug, CircleX, Info, ToggleLeft, ToggleRight, X } from '@lucide/svelte';
// *** Import other supporting libraries
import { Bug, CircleX, Info, ToggleLeft, ToggleRight, X } from '@lucide/svelte';
// *** Import Aether specific variables and functions
// import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
// *** Import Aether specific variables and functions
// import { ae_util } from '$lib/ae_utils/ae_utils';
import {
ae_loc,
ae_sess,
ae_api,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
// *** Setup Svelte properties
interface Props {
log_lvl?: number;
hide?: null | boolean;
expand?: boolean;
}
// *** Setup Svelte properties
interface Props {
log_lvl?: number;
hide?: null | boolean;
expand?: boolean;
}
let {
log_lvl = $bindable(0),
hide = $bindable(false),
expand = $bindable(false)
}: Props = $props();
let {
log_lvl = $bindable(0),
hide = $bindable(false),
expand = $bindable(false)
}: Props = $props();
</script>
<!-- App Debug Menu -->
@@ -31,28 +37,28 @@ hover:opacity-100 -->
ae_app__debug_menu
hidden-print
z-50
absolute bottom-0 left-0
md:text-md
lg:text-md xl:text-md transition-delay-1000
flex
text-sm sm:text-sm md:text-md lg:text-md xl:text-md 2xl:text-lg
dark:text-slate-400 dark:hover:text-slate-200
bg-red-100/60 dark:bg-red-800/50
hover:bg-red-200 hover:dark:bg-red-900
mx-1 my-2
max-h-min
max-w-lg
transition-all
transition-delay-1000
transition-duration-1000
absolute bottom-0 left-0 z-50 mx-1 my-2
flex max-h-min
max-w-lg border-2
border-red-300 bg-red-100/60
text-sm transition-all
ease-in
hover:border-red-500
hover:bg-red-200
sm:text-sm
2xl:text-lg
dark:border-red-700
border-2
border-red-300 dark:border-red-700
hover:border-red-500 hover:dark:border-red-500
dark:bg-red-800/50
dark:text-slate-400 hover:dark:border-red-500
hover:dark:bg-red-900 dark:hover:text-slate-200
"
class:top-0={expand}
class:w-full={expand}
@@ -60,29 +66,27 @@ hover:opacity-100 -->
class:border-transparent={!expand}
class:dark:border-transparent={!expand}
class:hover:border-transparent={!expand}
class:hover:bg-transparent={!expand}
>
class:hover:bg-transparent={!expand}>
<div
class:hidden={!expand}
class:border-red-200={expand}
class:dark:border-red-800={expand}
class="
transition-all
transition-delay-1000
transition-duration-1000
ease-in
overflow-y-auto
px-1 py-4
opacity-50
hover:opacity-100
relative
"
>
overflow-y-auto
px-1
py-4 opacity-50
transition-all
ease-in
hover:opacity-100
">
<!-- flex flex-col items-center justify-center max-h-full outline -->
<div>
<!-- <span class="fas fa-bug mx-1"></span> -->
<Bug class="inline-block mx-1" />
<Bug class="mx-1 inline-block" />
<span>Debug</span>
</div>
@@ -91,7 +95,8 @@ hover:opacity-100 -->
</pre>
</div>
<span class="absolute top-0 right-0 flex flex-row gap-1 items-center justify-center">
<span
class="absolute top-0 right-0 flex flex-row items-center justify-center gap-1">
<button
type="button"
onclick={() => {
@@ -104,16 +109,21 @@ hover:opacity-100 -->
hover:preset-tonal-success
transition-all
"
title="Turn debug content and styles off and on"
>
title="Turn debug content and styles off and on">
{#if $ae_loc?.debug_mode}
<!-- <span class="fas fa-toggle-on mx-1"></span> -->
<ToggleRight strokeWidth="2.5" color="green" class="inline-block mx-1" />
<ToggleRight
strokeWidth="2.5"
color="green"
class="mx-1 inline-block" />
<span>Debug</span>
<span class="hidden"> Mode On </span>
{:else}
<!-- <span class="fas fa-toggle-off mx-1"></span> -->
<ToggleLeft strokeWidth="1" color="gray" class="inline-block mx-1" />
<ToggleLeft
strokeWidth="1"
color="gray"
class="mx-1 inline-block" />
<span>Debug?</span>
<span class="hidden"> Mode Off </span>
{/if}
@@ -137,10 +147,9 @@ hover:opacity-100 -->
preset-outlined-surface-400-600 preset-filled-suface-200-800
hover:preset-tonal-success
transition-all
"
>
">
<!-- <span class="fas fa-info-circle mx-1"></span> -->
<Info class="inline-block mx-1" />
<Info class="mx-1 inline-block" />
Quick Info
</button>
@@ -157,11 +166,10 @@ hover:opacity-100 -->
hover:preset-tonal-warning
transition-all
"
title="Turn debug content and styles off and on"
>
title="Turn debug content and styles off and on">
<!-- <span class="fas fa-toggle-on mx-1"></span> -->
<!-- <ToggleRight class="inline-block mx-1" /> -->
<CircleX class="inline-block mx-1" />
<CircleX class="mx-1 inline-block" />
<span class="hidden"> Close </span>
<span>Debug</span>
</button>
@@ -177,18 +185,17 @@ hover:opacity-100 -->
id="AE-Quick-Debug"
class="
btn btn-icon
text-xs
p-1
preset-outlined-surface-100-900
hover:preset-filled-warning-100-900
fixed
bottom-8
transition-all
fixed bottom-8 left-2
text-neutral-300 hover:text-neutral-800
left-2
p-1 text-xs text-neutral-300
transition-all hover:text-neutral-800
dark:text-neutral-700 dark:hover:text-neutral-200
"
title="Turn debug content and styles off and on"
>
title="Turn debug content and styles off and on">
<!-- absolute bottom-2 left-2 -->
<!-- fixed bottom-0 left-0 -->
&pi;

View File

@@ -1,80 +1,87 @@
<script lang="ts">
interface Props {
log_lvl?: number;
additional_kv?: key_val;
e_success?: boolean;
e_class?: string;
e_title?: string;
e_text?: string;
e_class_h1?: string;
e_class_h2?: string;
e_class_form_hidden?: string;
e_class_form_showing?: string;
btn_text?: string;
btn_title?: string;
btn_class?: string;
show_btn_class?: string;
hide_icon?: boolean;
}
interface Props {
log_lvl?: number;
additional_kv?: key_val;
e_success?: boolean;
e_class?: string;
e_title?: string;
e_text?: string;
e_class_h1?: string;
e_class_h2?: string;
e_class_form_hidden?: string;
e_class_form_showing?: string;
btn_text?: string;
btn_title?: string;
btn_class?: string;
show_btn_class?: string;
hide_icon?: boolean;
}
let {
log_lvl = $bindable(0),
additional_kv = $bindable({}),
e_success = $bindable(false),
e_class = '',
// e_title = 'Technical Help',
// e_text = 'Request technical help for this application.',
e_class_h1 = $bindable(''),
e_class_h2 = $bindable(''),
e_class_form_hidden = $bindable(''),
e_class_form_showing = $bindable(''),
btn_text = 'Technical Help',
btn_title = 'Technical support help',
btn_class = '',
show_btn_class = '',
hide_icon = false
}: Props = $props();
let {
log_lvl = $bindable(0),
additional_kv = $bindable({}),
e_success = $bindable(false),
e_class = '',
// e_title = 'Technical Help',
// e_text = 'Request technical help for this application.',
e_class_h1 = $bindable(''),
e_class_h2 = $bindable(''),
e_class_form_hidden = $bindable(''),
e_class_form_showing = $bindable(''),
btn_text = 'Technical Help',
btn_title = 'Technical support help',
btn_class = '',
show_btn_class = '',
hide_icon = false
}: Props = $props();
// *** Import Svelte specific
import { goto } from '$app/navigation';
// *** Import Svelte specific
import { goto } from '$app/navigation';
// *** Import other supporting libraries
import { BadgeQuestionMark, ChevronDown, ChevronRight, LifeBuoy, RefreshCw, SquareX } from '@lucide/svelte';
// *** Import Aether specific variables and functions
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger,
type key_val
} from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
// *** Import other supporting libraries
import {
BadgeQuestionMark,
ChevronDown,
ChevronRight,
LifeBuoy,
RefreshCw,
SquareX
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger,
type key_val
} from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
if (log_lvl) {
console.log(`Help - technical support component loaded`);
}
let help_tech_text: string = $state('');
let hide_additional_info: boolean = $state(true);
function prevent_default<T extends Event>(fn: (event: T) => void) {
return function (event: T) {
event.preventDefault();
fn(event);
};
}
function send_help_tech_email() {
if (log_lvl) {
console.log(`Help - technical support component loaded`);
console.log(`*** send_help_tech_email() ***`);
}
let help_tech_text: string = $state('');
let hide_additional_info: boolean = $state(true);
let subject = `Technical Notification - ${$ae_loc.name}`;
function prevent_default<T extends Event>(fn: (event: T) => void) {
return function (event: T) {
event.preventDefault();
fn(event);
};
}
function send_help_tech_email() {
if (log_lvl) {
console.log(`*** send_help_tech_email() ***`);
}
let subject = `Technical Notification - ${$ae_loc.name}`;
let body_html = `
let body_html = `
<div>
Technical Notification,\n\n
<ul>
@@ -102,25 +109,24 @@
</div>
`;
api.send_email({
api_cfg: $ae_api,
from_email:
$ae_loc.site_cfg_json?.noreply_email ??
'noreply+tech@oneskyit.com',
from_name: $ae_loc.site_cfg_json?.noreply_name ?? 'IT NoReply',
// to_email: $ae_loc.site_cfg_json?.admin_email ?? 'admin+tech@oneskyit.com', // 'scott+idaabb@oneskyit.com',
to_email: 'it+tech@oneskyit.com',
// to_email: $idaa_slct.post_obj.email,
// to_email: 'scott+idaabb@oneskyit.com',
// to_name: $ae_loc.site_cfg_json?.admin_name ?? 'IT Tech',
to_name: 'IT Tech',
// to_name: $idaa_slct.post_obj.full_name ?? 'IDAA BB Poster',
subject: subject,
body_html: body_html
});
api.send_email({
api_cfg: $ae_api,
from_email:
$ae_loc.site_cfg_json?.noreply_email ?? 'noreply+tech@oneskyit.com',
from_name: $ae_loc.site_cfg_json?.noreply_name ?? 'IT NoReply',
// to_email: $ae_loc.site_cfg_json?.admin_email ?? 'admin+tech@oneskyit.com', // 'scott+idaabb@oneskyit.com',
to_email: 'it+tech@oneskyit.com',
// to_email: $idaa_slct.post_obj.email,
// to_email: 'scott+idaabb@oneskyit.com',
// to_name: $ae_loc.site_cfg_json?.admin_name ?? 'IT Tech',
to_name: 'IT Tech',
// to_name: $idaa_slct.post_obj.full_name ?? 'IDAA BB Poster',
subject: subject,
body_html: body_html
});
help_tech_text = ''; // Clear the text area after sending
}
help_tech_text = ''; // Clear the text area after sending
}
</script>
<!-- class:bg-radial-[at_55%_50%]={$ae_sess.show_help_tech}
@@ -131,8 +137,8 @@ class:to-90%={$ae_sess.show_help_tech} -->
class="
flex flex-row
items-center justify-center
rounded-lg shadow-2xl
border border-transparent
rounded-lg border
border-transparent shadow-2xl
transition-all
{e_class}
{!$ae_sess.show_help_tech ? e_class_form_hidden : e_class_form_showing}
@@ -148,48 +154,42 @@ class:to-90%={$ae_sess.show_help_tech} -->
class:hover:shadow-blue-200={$ae_sess.show_help_tech}
class:hover:dark:shadow-blue-800={$ae_sess.show_help_tech}
class:bg-blue-100={$ae_sess.show_help_tech}
class:dark:bg-blue-900={$ae_sess.show_help_tech}
>
class:dark:bg-blue-900={$ae_sess.show_help_tech}>
{#if $ae_sess.show_help_tech}
<div
class="
w-xl
flex flex-col gap-1
items-center justify-center
flex
w-xl flex-col items-center
justify-center gap-1
rounded-xl
border border-gray-500/20 bg-blue-200
p-2
border rounded-xl border-gray-500/20
bg-blue-200
dark:bg-blue-800
transition-all
"
>
dark:bg-blue-800
">
<div
class="
d-flex align-items-center justify-content-between
flex flex-row gap-1 items-center justify-between
w-full
"
>
flex w-full flex-row items-center justify-between
gap-1
">
<h1
class="
h1
text-base font-semibold text-gray-800 dark:text-gray-200
w-fit
w-fit text-base font-semibold text-gray-800
dark:text-gray-200
{e_class_h1}
"
>
">
{#if e_success}
<span
class="text-lg text-green-800 dark:text-green-200 font-semibold"
>
<BadgeQuestionMark class="inline-block mr-2" />
class="text-lg font-semibold text-green-800 dark:text-green-200">
<BadgeQuestionMark class="mr-2 inline-block" />
Help Requested
</span>
{:else}
<span
class="text-lg text-gray-800 dark:text-gray-200 font-semibold"
>
<BadgeQuestionMark class="inline-block mr-2" />
class="text-lg font-semibold text-gray-800 dark:text-gray-200">
<BadgeQuestionMark class="mr-2 inline-block" />
<!-- Request Technical Help -->
Notify Technical Support
</span>
@@ -211,8 +211,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
transition-all
{btn_class}
"
title="Close Help Request Form"
>
title="Close Help Request Form">
<!-- <span class="fas fa-times"></span> -->
<SquareX size="1em" />
<span class="sr-only">Close</span>
@@ -222,9 +221,9 @@ class:to-90%={$ae_sess.show_help_tech} -->
<form
class="
m-1
flex flex-col gap-1
items-center justify-center
w-md max-w-lg
flex w-md max-w-lg
flex-col items-center
justify-center gap-1
"
onsubmit={prevent_default(() => {
// Do stuff...
@@ -234,40 +233,37 @@ class:to-90%={$ae_sess.show_help_tech} -->
$ae_sess.show_help_tech = false;
alert('Notification sent to the IT team.');
})}
>
})}>
<textarea
class="
form-control
w-full max-w-lg h-24 p-2
border border-gray-300 rounded
text-gray-950 dark:text-gray-50
bg-white dark:bg-gray-500
h-24 w-full max-w-lg rounded
border border-gray-300 bg-white
p-2 text-gray-950
dark:bg-gray-500 dark:text-gray-50
hover:dark:bg-gray-50
hover:dark:text-gray-950
"
placeholder="Send with or without a description...."
bind:value={help_tech_text}
></textarea>
bind:value={help_tech_text}></textarea>
<button
type="submit"
class="
btn btn-lg
m-1
preset-tonal-warning
preset-outlined-warning-100-900
hover:preset-filled-warning-200-800
m-1
transition-all
{btn_class}
"
title={btn_title}
>
title={btn_title}>
{#if !hide_icon}
<!-- <BadgeQuestionMark class="inline-block mr-2" /> -->
<LifeBuoy class="inline-block m-1" />
<LifeBuoy class="m-1 inline-block" />
{/if}
{#if !help_tech_text}
@@ -280,9 +276,8 @@ class:to-90%={$ae_sess.show_help_tech} -->
<div
class="
text-sm text-gray-700 dark:text-gray-300 text-center italic
"
>
text-center text-sm text-gray-700 italic dark:text-gray-300
">
This is intended for technical issues only. Please contact your
organization's staff if you have a question about your
membership, recorded content, meetings, or posts.
@@ -290,29 +285,25 @@ class:to-90%={$ae_sess.show_help_tech} -->
<div
class="
border border-gray-300 rounded p-2
w-full
max-w-2xl
overflow-scroll
"
>
w-full max-w-2xl overflow-scroll rounded
border
border-gray-300
p-2
">
<div
class="
d-flex align-items-center justify-content-between
flex flex-row gap-1 items-center justify-between
w-full
"
>
flex w-full flex-row items-center justify-between
gap-1
">
<h2
class="
h2
text-base font-semibold text-gray-800 dark:text-gray-200
{e_class_h2}
"
>
">
<span
class="text-base font-semibold text-gray-800 dark:text-gray-200"
>
class="text-base font-semibold text-gray-800 dark:text-gray-200">
Additional Information Included
</span>
</h2>
@@ -325,8 +316,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
"
onclick={() =>
(hide_additional_info = !hide_additional_info)}
title="Toggle additional information"
>
title="Toggle additional information">
<span>
{#if hide_additional_info}
<!-- <span class="fas fa-caret-right"></span> -->
@@ -341,89 +331,75 @@ class:to-90%={$ae_sess.show_help_tech} -->
</button>
</div>
<ul
class="list-disc list-inside text-sm text-gray-800 dark:text-gray-200"
class:hidden={hide_additional_info}
>
class="list-inside list-disc text-sm text-gray-800 dark:text-gray-200"
class:hidden={hide_additional_info}>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Datetime =</span
>
>Datetime =</span>
{new Date().toISOString()}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>URL =</span
>
>URL =</span>
{window.location.href}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Browser =</span
>
>Browser =</span>
{navigator.userAgent}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Viewport Size =</span
>
>Viewport Size =</span>
{window.innerWidth} x {window.innerHeight}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Screen Resolution =</span
>
>Screen Resolution =</span>
{window.screen.width} x {window.screen.height}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Dark mode =</span
>
>Dark mode =</span>
{window?.matchMedia?.('(prefers-color-scheme:dark)')
?.matches ?? false}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>In iframe =</span
>
>In iframe =</span>
{$ae_loc?.iframe}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Theme Mode =</span
>
>Theme Mode =</span>
{$ae_loc?.theme_mode}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Theme Name =</span
>
>Theme Name =</span>
{$ae_loc?.theme_name}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Account ID =</span
>
>Account ID =</span>
{$slct.account_id}
</li>
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>Access Type =</span
>
>Access Type =</span>
{$ae_loc?.access_type}
</li>
{#if $ae_loc?.person_id}
<li>
<span
class="text-sm text-gray-500 dark:text-gray-400"
>person_id =</span
>
>person_id =</span>
{$ae_loc?.person_id}
</li>
<li>
<span
class="text-sm text-gray-500 dark:text-gray-400"
>full_name =</span
>
>full_name =</span>
{$ae_loc?.full_name}
</li>
{/if}
@@ -431,29 +407,25 @@ class:to-90%={$ae_sess.show_help_tech} -->
<li>
<span
class="text-sm text-gray-500 dark:text-gray-400"
>user_id =</span
>
>user_id =</span>
{$ae_loc?.user_id}
</li>
<li>
<span
class="text-sm text-gray-500 dark:text-gray-400"
>username =</span
>
>username =</span>
{$ae_loc?.username}
</li>
<li>
<span
class="text-sm text-gray-500 dark:text-gray-400"
>email =</span
>
>email =</span>
{$ae_loc?.email}
</li>
{/if}
<li>
<span class="text-sm text-gray-500 dark:text-gray-400"
>API Base URL =</span
>
>API Base URL =</span>
{$ae_api.base_url}
</li>
@@ -461,13 +433,12 @@ class:to-90%={$ae_sess.show_help_tech} -->
<h2 class="text-base font-semibold text-gray-800">
Component Info:
</h2>
<ul class="list-disc list-inside text-gray-800 text-sm">
<ul class="list-inside list-disc text-sm text-gray-800">
{#each Object.entries(additional_kv) as [key, value] (key)}
<li>
<span
class="text-sm text-gray-500 dark:text-gray-400"
>{key} =</span
>
>{key} =</span>
{value ?? '-- not set --'}
</li>
{/each}
@@ -475,8 +446,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
{/if}
</ul>
<div
class="text-sm text-gray-700 dark:text-gray-300 text-center italic"
>
class="text-center text-sm text-gray-700 italic dark:text-gray-300">
This information will be included in the help request to
assist technical support in diagnosing the issue.
</div>
@@ -484,11 +454,10 @@ class:to-90%={$ae_sess.show_help_tech} -->
<div
class="
flex flex-row gap-2 items-center justify-around
w-full
mt-2
"
>
mt-2 flex w-full flex-row items-center
justify-around
gap-2
">
<button
type="button"
onclick={() => {
@@ -562,8 +531,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
transition-all
{btn_class}
"
title="Clear App Data & Settings: Clear IndexedDB and reload. If in edit mode localStorage and sessionStorage will also be cleared."
>
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 size="1em" class="inline-block" />
@@ -582,8 +550,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
transition-all
{btn_class}
"
title="Close Help Request Form"
>
title="Close Help Request Form">
<!-- <span class="fas fa-times"></span> -->
<SquareX size="1em" class="inline-block" />
<span class="">Cancel</span>
@@ -603,10 +570,9 @@ class:to-90%={$ae_sess.show_help_tech} -->
{btn_class}
{show_btn_class}
"
title={btn_title}
>
title={btn_title}>
{#if !hide_icon}
<BadgeQuestionMark class="inline-block m-0.5" />
<BadgeQuestionMark class="m-0.5 inline-block" />
{/if}
<span class="hidden">
{btn_text}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,56 +1,63 @@
<script lang="ts">
// *** Import Svelte specific
// import { tick } from 'svelte';
// import { goto, invalidateAll } from '$app/navigation';
// *** Import Svelte specific
// import { tick } from 'svelte';
// import { goto, invalidateAll } from '$app/navigation';
// *** Import other supporting libraries
import {
// ArrowBigRight,
// Bug,
CircleX,
// Eye, EyeOff,
// Key,
// LogIn, LogOut, LockKeyhole,
// Mail, MailCheck,
Menu,
// RefreshCw, RefreshCcwDot,
ShieldEllipsis,
ShieldMinus,
ShieldPlus,
ShieldUser,
ToggleLeft, ToggleRight,
User,
UserCheck,
UserCog,
Wand2,
X
} from '@lucide/svelte';
// *** Import other supporting libraries
import {
// ArrowBigRight,
// Bug,
CircleX,
// Eye, EyeOff,
// Key,
// LogIn, LogOut, LockKeyhole,
// Mail, MailCheck,
Menu,
// RefreshCw, RefreshCcwDot,
ShieldEllipsis,
ShieldMinus,
ShieldPlus,
ShieldUser,
ToggleLeft,
ToggleRight,
User,
UserCheck,
UserCog,
Wand2,
X
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
// import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
// *** Import Aether specific variables and functions
// import { ae_util } from '$lib/ae_utils/ae_utils';
import {
ae_loc,
ae_sess,
ae_api,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
import Element_access_type from '$lib/app_components/e_app_access_type.svelte';
import Element_app_cfg from '$lib/app_components/e_app_cfg.svelte';
import Element_sign_in_out from '$lib/app_components/e_app_sign_in_out.svelte';
import Element_theme from '$lib/app_components/e_app_theme.svelte';
import Element_access_type from '$lib/app_components/e_app_access_type.svelte';
import Element_app_cfg from '$lib/app_components/e_app_cfg.svelte';
import Element_sign_in_out from '$lib/app_components/e_app_sign_in_out.svelte';
import Element_theme from '$lib/app_components/e_app_theme.svelte';
// *** Setup Svelte properties
interface Props {
log_lvl?: number;
data: any;
hide?: null | boolean;
expand?: boolean;
}
// *** Setup Svelte properties
interface Props {
log_lvl?: number;
data: any;
hide?: null | boolean;
expand?: boolean;
}
let {
log_lvl = $bindable(0),
data = null,
hide = $bindable(false),
expand = $bindable(false)
}: Props = $props();
let {
log_lvl = $bindable(0),
data = null,
hide = $bindable(false),
expand = $bindable(false)
}: Props = $props();
let trigger_clear_access: null | boolean = $state(null);
let trigger_clear_access: null | boolean = $state(null);
</script>
<!-- App System Menu -->
@@ -93,38 +100,37 @@ max-w-max -->
ae_app__sys_menu
hidden-print
md:text-md
lg:text-md xl:text-md absolute
right-0
bottom-6
z-50
absolute bottom-6 right-0
flex
opacity-90
hover:opacity-100
w-min
max-w-md
flex flex-col-reverse gap-1
w-min max-w-md flex-col-reverse
items-end justify-center
text-sm sm:text-sm md:text-md lg:text-md xl:text-md 2xl:text-lg
gap-1 rounded-lg border-2 border-blue-300/20 bg-blue-200/90 text-sm
bg-blue-200/90
opacity-90
border-2 rounded-lg
border-blue-300/20 dark:border-blue-700/20
hover:border-blue-500/20 hover:dark:border-blue-500/20
transition-all delay-500
duration-500 ease-in-out
hover:border-blue-500/20 hover:opacity-100
transition-all
delay-500 hover:delay-200
duration-500 hover:duration-200
ease-in-out
hover:delay-200
hover:duration-200 sm:text-sm
2xl:text-lg dark:border-blue-700/20
hover:dark:border-blue-500/20
"
class:top-0={expand && (1 as any) == 3}
class:opacity-100={expand}
class:w-full={expand}
class:hidden={hide}
class:border-transparent={!expand}
class:bg-transparent={!expand}
>
class:bg-transparent={!expand}>
<!-- class:hidden={!expand} -->
<!-- class:preset-filled-warning-100-900={expand} -->
<div
@@ -134,38 +140,40 @@ max-w-max -->
class:dark:bg-blue-500={expand}
class="
hidden-print
flex flex-col items-end justify-end
light:bg-blue-200/10 relative flex w-full
flex-col
items-end
justify-end
gap-1
overflow-y-auto
p-1
w-full
light:bg-blue-200/10
dark:bg-blue-800/10
hover:opacity-100
relative
transition-all
delay-1000 hover:delay-500
duration-200 hover:duration-200
ease-in-out
delay-1000
duration-200
ease-in-out hover:opacity-100
hover:delay-500 hover:duration-200
dark:bg-blue-800/10
"
title="
ID: {$ae_loc?.person_id ?? '-- not set --'} / {$ae_loc?.user_id ?? '-- not set --'}
ID: {$ae_loc?.person_id ?? '-- not set --'} / {$ae_loc?.user_id ??
'-- not set --'}
Name: {$ae_loc?.person?.full_name ?? '-- not set --'}
Username: {$ae_loc?.user?.username ?? '-- not set --'}
Email: {$ae_loc?.user?.email ?? '-- not set --'}
Access Type: {$ae_loc?.access_type ?? '-- not set --'}
"
>
">
{#if $ae_loc?.person_id}
<div class="flex flex-row gap-1 items-center justify-end transition-all w-full group">
<div
class="group flex w-full flex-row items-center justify-end gap-1 transition-all">
<User size="1em" class="mx-1 inline-block text-gray-500" />
<span class:hidden={!expand} class="group-hover:inline-block">
{$ae_loc?.person?.informal_name ?? $ae_loc?.person?.given_name}
{$ae_loc?.person?.informal_name ??
$ae_loc?.person?.given_name}
</span>
</div>
{/if}
@@ -174,54 +182,60 @@ max-w-max -->
<!-- This is currently not set to show if not expanded. Saving space. -->
<div
class:hidden={!expand}
class="flex flex-row gap-1 items-center justify-end transition-all w-full group"
>
<ShieldUser size="1em" class="mx-1 inline-block text-gray-500" />
class="group flex w-full flex-row items-center justify-end gap-1 transition-all">
<ShieldUser
size="1em"
class="mx-1 inline-block text-gray-500" />
<span class:hidden={!expand} class="group-hover:inline-block">
{$ae_loc?.user?.username ?? '-- not set --'}
</span>
</div>
{/if}
<div class="flex flex-row gap-1 items-center justify-end transition-all w-full group">
<div
class="group flex w-full flex-row items-center justify-end gap-1 transition-all">
{#if $ae_loc.access_type && $ae_loc.access_type != 'anonymous'}
<span
class="flex flex-row-reverse gap-1 group text-base"
title={`Current access type/level: ${$ae_loc.access_type}`}
>
class="group flex flex-row-reverse gap-1 text-base"
title={`Current access type/level: ${$ae_loc.access_type}`}>
<!-- <span class="fas fa-unlock mx-1"></span> -->
<!-- <ShieldPlus class="inline-block" /> -->
{#if $ae_loc.access_type == 'super'}
<Wand2 size="1em" class="m-1 inline-block" />
<span class:hidden={!expand} class="hidden group-hover:inline-block"
>Super</span
>
<span
class:hidden={!expand}
class="hidden group-hover:inline-block">Super</span>
{:else if $ae_loc.access_type == 'manager'}
<ShieldUser size="1em" class="m-1 inline-block" />
<span class:hidden={!expand} class="hidden group-hover:inline-block"
>Manager</span
>
<span
class:hidden={!expand}
class="hidden group-hover:inline-block"
>Manager</span>
{:else if $ae_loc.access_type == 'administrator'}
<UserCog size="1em" class="m-1 inline-block" />
<span class:hidden={!expand} class="hidden group-hover:inline-block"
>Administrator</span
>
<span
class:hidden={!expand}
class="hidden group-hover:inline-block"
>Administrator</span>
{:else if $ae_loc.access_type == 'trusted'}
<UserCheck size="1em" class="m-1 inline-block" />
<span class:hidden={!expand} class="hidden group-hover:inline-block"
>Trusted Access</span
>
<span
class:hidden={!expand}
class="hidden group-hover:inline-block"
>Trusted Access</span>
{:else if $ae_loc.access_type == 'public'}
Public
<span class:hidden={!expand} class="hidden group-hover:inline-block"
>Access</span
>
<span
class:hidden={!expand}
class="hidden group-hover:inline-block"
>Access</span>
{:else if $ae_loc.access_type == 'authenticated'}
Authenticated
<span class:hidden={!expand} class="hidden group-hover:inline-block"
>Access</span
>
<span
class:hidden={!expand}
class="hidden group-hover:inline-block"
>Access</span>
{:else if $ae_loc.access_type == 'anonymous'}
Anonymous Access
{:else}
@@ -254,13 +268,13 @@ max-w-max -->
// $ae_loc.sys_menu.expand_btn = true;
}
}}
class="btn btn-sm text-xs variant-outline-surface hover:variant-ghost-warning transition-all group"
title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}
>
class="btn btn-sm variant-outline-surface hover:variant-ghost-warning group text-xs transition-all"
title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}>
<!-- <span class="fas fa-lock mx-1"></span> -->
<!-- <ShieldMinus /> -->
<ShieldEllipsis size="2em" class="inline-block" />
<span class="hidden group-hover:inline-block">Passcode?</span>
<span class="hidden group-hover:inline-block"
>Passcode?</span>
</button>
{:else}
<button
@@ -291,16 +305,17 @@ max-w-max -->
}
}}
class="
btn btn-sm text-xs
flex-row-reverse
variant-outline-surface hover:variant-ghost-warning
transition-all group
btn btn-sm variant-outline-surface
hover:variant-ghost-warning
group flex-row-reverse
text-xs transition-all
"
title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}
>
title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}>
<!-- <span class="fas fa-lock mx-1"></span> Lock? -->
<ShieldMinus class="inline-block" />
<span class="hidden group-hover:inline-block"> Clear? </span>
<span class="hidden group-hover:inline-block">
Clear?
</span>
</button>
{/if}
{:else}
@@ -320,19 +335,22 @@ max-w-max -->
// $ae_loc.app_cfg.show_element__access_type = true;
// $ae_loc.app_cfg.show_element__passcode_input = true;
// await tick();
console.log('Layout button click: Focus on passcode input!');
console.log(
'Layout button click: Focus on passcode input!'
);
/** @type {HTMLElement | null} */
const to_focus = document.getElementById('access_passcode_input');
const to_focus = document.getElementById(
'access_passcode_input'
);
to_focus?.focus();
}}
class="
btn btn-sm text-xs
flex-row-reverse
variant-outline-surface hover:variant-ghost-success
transition-all group
btn btn-sm variant-outline-surface
hover:variant-ghost-success
group flex-row-reverse
text-xs transition-all
"
title="Anonymous public access is currently set. You must Sign In or use a passcode to change your access level."
>
title="Anonymous public access is currently set. You must Sign In or use a passcode to change your access level.">
<!-- <span class="fas fa-lock mx-1 lock_icon"></span> -->
<!-- <span class="">Unlock?</span> -->
<ShieldUser class="inline-block" />
@@ -349,19 +367,21 @@ max-w-max -->
// dispatch_edit_mode_changed();
}}
class="
btn btn-base text-sm
preset-tonal-warning
btn btn-base preset-tonal-warning
preset-outlined-warning-800-200
hover:preset-tonal-success
transition-all group
min-w-22 md:min-w-30 w-full max-w-fit
gap-1
group
w-full max-w-fit
min-w-22 gap-1 text-sm transition-all
md:min-w-30
"
title="Click to turn off edit mode. Edit mode is currently on."
>
title="Click to turn off edit mode. Edit mode is currently on.">
<ToggleRight size="1em" class="m-1 inline-block" />
<span class="text-xs">Edit</span>
<span class="hidden group-hover:inline-block group-hover:text-xs"> Off </span>
<span
class="hidden group-hover:inline-block group-hover:text-xs">
Off
</span>
</button>
{:else if $ae_loc.authenticated_access}
<button
@@ -371,19 +391,21 @@ max-w-max -->
// dispatch_edit_mode_changed();
}}
class="
btn btn-base text-sm
preset-tonal-surface
btn btn-base preset-tonal-surface
preset-outlined-warning-400-600
hover:preset-tonal-warning
transition-all group
min-w-22 md:min-w-30 w-full max-w-fit
gap-1
group
w-full max-w-fit
min-w-22 gap-1 text-sm transition-all
md:min-w-30
"
title="Click to torn on/enable edit mode. Edit mode is currently off/disabled."
>
title="Click to torn on/enable edit mode. Edit mode is currently off/disabled.">
<ToggleLeft size="1em" class="m-1 inline-block" />
<span class="text-xs">Edit</span>
<span class="hidden group-hover:inline-block group-hover:text-xs"> On? </span>
<span
class="hidden group-hover:inline-block group-hover:text-xs">
On?
</span>
</button>
{/if}
@@ -392,12 +414,12 @@ max-w-max -->
type="button"
class:w-full={expand}
class="
btn btn-base text-sm
preset-tonal-surface
btn btn-base preset-tonal-surface
hover:preset-tonal-primary
px-1 py-1
min-w-22 md:min-w-30 w-full max-w-fit
transition-all group
group
w-full max-w-fit
min-w-22 px-1 py-1 text-sm
transition-all md:min-w-30
"
title="Cycle font size: default → larger → smaller"
onclick={() => {
@@ -409,17 +431,19 @@ max-w-max -->
} else {
$ae_loc.font_size_mode = 'default';
}
}}
>
}}>
{#if !$ae_loc.font_size_mode || $ae_loc.font_size_mode === 'default'}
<span class="font-bold text-sm leading-none">A</span>
<span class="hidden group-hover:inline-block text-xs">Font: Normal</span>
<span class="text-sm leading-none font-bold">A</span>
<span class="hidden text-xs group-hover:inline-block"
>Font: Normal</span>
{:else if $ae_loc.font_size_mode === 'larger'}
<span class="font-bold text-base leading-none">A+</span>
<span class="hidden group-hover:inline-block text-xs">Font: Larger</span>
<span class="text-base leading-none font-bold">A+</span>
<span class="hidden text-xs group-hover:inline-block"
>Font: Larger</span>
{:else}
<span class="font-bold text-xs leading-none">A</span>
<span class="hidden group-hover:inline-block text-xs">Font: Smaller</span>
<span class="text-xs leading-none font-bold">A</span>
<span class="hidden text-xs group-hover:inline-block"
>Font: Smaller</span>
{/if}
</button>
@@ -432,13 +456,13 @@ max-w-max -->
type="button"
class:w-full={expand}
class="
btn btn-base text-sm
preset-filled-tertiary-400-600
btn btn-base preset-filled-tertiary-400-600
preset-outlined-tertiary-400-600
hover:preset-filled-success active:preset-filled-success
px-1 py-1
min-w-22 md:min-w-30 w-full max-w-fit
transition-all group
hover:preset-filled-success
active:preset-filled-success group
w-full max-w-fit
min-w-22 px-1 py-1 text-sm
transition-all md:min-w-30
"
title="Show/Hide the system menu"
onclick={async () => {
@@ -472,15 +496,14 @@ max-w-max -->
// $ae_loc.app_cfg.show_element__passcode_input = false;
}
// $ae_loc.sys_menu.expand_btn = !expand_btn;
}}
>
}}>
<!-- <span class=""> -->
{#if expand}
<CircleX class="m-1 inline-block" />
{:else}
<Menu class="m-1 inline-block" />
{/if}
<span class="text-xs hidden group-hover:inline-block"> Menu </span>
<span class="hidden text-xs group-hover:inline-block"> Menu </span>
<!-- </span> -->
</button>
<!-- </div> -->
@@ -499,27 +522,26 @@ max-w-max -->
ae_app__sys_menu
hidden-print
flex flex-col
items-end
justify-end
gap-2
z-20 flex
min-w-48
flex-col
items-end
bg-white dark:bg-gray-800
justify-end
border border-gray-200 dark:border-gray-700
rounded-lg
px-1 py-2
gap-2 rounded-lg
transition-all
delay-1000 hover:delay-100
duration-100 hover:duration-200
ease-in-out
border border-gray-200 bg-white
px-1
py-2 transition-all
z-20 hover:z-30
"
>
delay-1000
duration-100 ease-in-out
hover:z-30 hover:delay-100
hover:duration-200
dark:border-gray-700 dark:bg-gray-800
">
<button
type="button"
class:w-full={expand}
@@ -528,8 +550,8 @@ max-w-max -->
preset-filled-tertiary-400-600
preset-outlined-tertiary-400-600
hover:preset-filled-success active:preset-filled-success
px-6 py-1
transition-all group
group px-6
py-1 transition-all
"
title="Show/Hide the system menu"
onclick={() => {
@@ -549,8 +571,7 @@ max-w-max -->
}
// $ae_loc.sys_menu.expand_btn = !expand_btn;
// $ae_loc.sys_menu.expand = !expand;
}}
>
}}>
{#if expand}
<CircleX class="m-1 inline-block" />
<span class="hidden group-hover:inline-block"> Hide Menu </span>
@@ -564,16 +585,14 @@ max-w-max -->
<span class:hidden={!$ae_loc.edit_mode}>
<Element_app_cfg
hide={$ae_loc.sys_menu.hide_app_cfg}
expand={$ae_loc.sys_menu.expand_app_cfg}
/>
expand={$ae_loc.sys_menu.expand_app_cfg} />
</span>
<span class:hidden={!$ae_loc.edit_mode}>
<Element_theme
hide={$ae_loc.sys_menu.hide_app_cfg}
expand={$ae_loc.sys_menu.expand_app_cfg}
set_theme_mode={true}
set_theme_name={true}
/>
set_theme_name={true} />
</span>
<!-- {/if} -->
@@ -582,8 +601,8 @@ max-w-max -->
<!-- expand={$ae_loc.sys_menu.expand_user} -->
<Element_sign_in_out
{data}
hidden={$ae_loc.iframe || !$ae_loc.app_cfg?.show_element__sign_in_out}
/>
hidden={$ae_loc.iframe ||
!$ae_loc.app_cfg?.show_element__sign_in_out} />
{/if}
{#if !$ae_loc?.sys_menu?.hide_access_type && !$ae_loc?.iframe}
@@ -592,9 +611,10 @@ max-w-max -->
bind:hide={$ae_loc.sys_menu.hide_access_type}
bind:focus_input={$ae_sess.sys_menu.focus_passcode_input}
bind:expand={$ae_loc.sys_menu.expand_access_type}
bind:show_passcode_input={$ae_sess.app_cfg.show_element__passcode_input}
bind:trigger_clear_access
/>
bind:show_passcode_input={
$ae_sess.app_cfg.show_element__passcode_input
}
bind:trigger_clear_access />
{/if}
</div>
</section>

View File

@@ -1,22 +1,28 @@
<script lang="ts">
import { Minimize2, Moon, Sun } from '@lucide/svelte';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
import { Minimize2, Moon, Sun } from '@lucide/svelte';
import {
ae_loc,
ae_sess,
ae_api,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
interface Props {
log_lvl?: number;
hide?: null | boolean;
expand?: boolean;
set_theme_mode: any;
set_theme_name: any;
}
interface Props {
log_lvl?: number;
hide?: null | boolean;
expand?: boolean;
set_theme_mode: any;
set_theme_name: any;
}
let {
log_lvl = $bindable(0),
hide = $bindable(false),
expand = $bindable(false),
set_theme_mode,
set_theme_name
}: Props = $props();
let {
log_lvl = $bindable(0),
hide = $bindable(false),
expand = $bindable(false),
set_theme_mode,
set_theme_name
}: Props = $props();
</script>
<!-- Change light and dark mode -->
@@ -37,25 +43,23 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
bg-surface-100 dark:bg-surface-800
text-surface-900 dark:text-surface-100
border border-surface-200 dark:border-surface-700
border-surface-200 dark:border-surface-700 flex
flex flex-col flex-wrap gap-1
w-72 max-w-72 flex-col flex-wrap
items-end justify-center
w-72 max-w-72
gap-1 rounded-lg
border
p-1
rounded-lg
shadow-md
duration-300 delay-150 hover:delay-1000 hover:ease-out
transition-all
transition-all delay-150 duration-300 hover:delay-1000
hover:ease-out
"
class:hidden={hide}
>
class:hidden={hide}>
<div
class:hidden={!expand}
class="flex flex-row flex-wrap gap-2 items-center justify-between w-full"
>
class="flex w-full flex-row flex-wrap items-center justify-between gap-2">
<!-- Theme Name: -->
<span class="text-sm font-semibold">
{$ae_loc.theme_name}
@@ -74,7 +78,10 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
// document.body.setAttribute('data-theme', $ae_loc?.theme_name);
// NEW for Tailwind v4: Update the html attribute named "data-theme" to the current theme name.
document.documentElement.setAttribute('data-theme', new_theme_name);
document.documentElement.setAttribute(
'data-theme',
new_theme_name
);
// if ($ae_loc.theme_mode == 'light') {
// document.documentElement.classList.remove('dark');
@@ -86,8 +93,7 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
}}
bind:value={$ae_loc.theme_name}
class="select w-32"
title="Theme name"
>
title="Theme name">
<option value="">-- None --</option>
<option value="cerberus">Cerberus</option>
<option value="concord">Concord</option>
@@ -112,41 +118,38 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
</div>
<div
class="flex flex-row flex-wrap gap-2 items-center w-full"
class="flex w-full flex-row flex-wrap items-center gap-2"
class:justify-between={expand}
class:justify-end={!expand}
>
class:justify-end={!expand}>
{#if expand}
<!-- Hide theme options -->
<button
class="
btn btn-sm text-xs
preset-tonal-secondary hover:preset-filled-secondary-500
transition-all group
btn btn-sm preset-tonal-secondary
hover:preset-filled-secondary-500 group
text-xs transition-all
"
onclick={() => {
expand = !expand;
}}
title="Hide Theme Options"
>
title="Hide Theme Options">
<!-- <span class="fas fa-compress-alt"></span> -->
<Minimize2 size="1em" class="m-1" />
<span
class="
hidden
group-hover:inline-block
text-xs
"
>
group-hover:inline-block
">
Hide Theme Options
</span>
</button>
<button
class="
btn btn-sm text-xs
preset-tonal-secondary hover:preset-filled-secondary-500
transition-all group
btn btn-sm preset-tonal-secondary
hover:preset-filled-secondary-500 group
text-xs transition-all
"
onclick={() => {
if ($ae_loc.theme_mode == 'light') {
@@ -157,23 +160,24 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
// DOM sync is handled reactively by the layout effect in +layout.svelte
}}
title="Change light and dark mode"
>
title="Change light and dark mode">
<!-- <span class="fas fa-adjust"></span> -->
{#if $ae_loc.theme_mode == 'light'}
<Sun class="m-1" />
<span class="hidden md:inline-block group-hover:inline-block">Light Mode</span>
<span
class="hidden group-hover:inline-block md:inline-block"
>Light Mode</span>
{:else if $ae_loc.theme_mode == 'dark'}
<Moon class="m-1" />
<span class="hidden group-hover:inline-block">Dark Mode</span>
<span class="hidden group-hover:inline-block"
>Dark Mode</span>
{/if}
<span
class="
hidden
group-hover:inline-block
text-xs
"
>
group-hover:inline-block
">
Change
</span>
</button>
@@ -197,18 +201,19 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
expand = !expand;
}}
title="Change light and dark mode"
>
title="Change light and dark mode">
{#if $ae_loc.theme_mode == 'light'}
<span class="inline-block" title="Light Mode">
<Sun />
</span>
<span class="hidden group-hover:inline-block">Light Mode</span>
<span class="hidden group-hover:inline-block"
>Light Mode</span>
{:else if $ae_loc.theme_mode == 'dark'}
<span class="inline-block" title="Dark Mode">
<Moon />
</span>
<span class="hidden group-hover:inline-block">Dark Mode</span>
<span class="hidden group-hover:inline-block"
>Dark Mode</span>
{/if}
</button>
{/if}

View File

@@ -1,120 +1,136 @@
<script lang="ts">
/**
* e_app_url_builder.svelte
* URL Param Builder — lets admins construct and copy shareable URLs
* with any combination of the supported URL params applied.
*
* Core params:
* ?iframe=true|false — persist kiosk mode (stays in URL)
* ?theme=<name> — set theme name on load (stripped after apply)
* ?theme_mode=light|dark — set light/dark mode on load (stripped after apply)
* ?key=<access_key> — site access key
*
* Launcher params (all stripped from URL after apply):
* ?launcher_menu=hide|show
* ?launcher_header=hide|show
* ?launcher_footer=hide|show
*/
import { page } from '$app/stores';
import { Copy, Check, Link } from '@lucide/svelte';
/**
* e_app_url_builder.svelte
* URL Param Builder — lets admins construct and copy shareable URLs
* with any combination of the supported URL params applied.
*
* Core params:
* ?iframe=true|false — persist kiosk mode (stays in URL)
* ?theme=<name> — set theme name on load (stripped after apply)
* ?theme_mode=light|dark — set light/dark mode on load (stripped after apply)
* ?key=<access_key> — site access key
*
* Launcher params (all stripped from URL after apply):
* ?launcher_menu=hide|show
* ?launcher_header=hide|show
* ?launcher_footer=hide|show
*/
import { page } from '$app/stores';
import { Copy, Check, Link } from '@lucide/svelte';
// --- Per-param: include this param in the output URL?
let use_iframe = $state(false);
let use_theme = $state(false);
let use_theme_mode = $state(false);
let use_key = $state(false);
let use_launcher_menu = $state(false);
let use_launcher_header = $state(false);
let use_launcher_footer = $state(false);
// --- Per-param: include this param in the output URL?
let use_iframe = $state(false);
let use_theme = $state(false);
let use_theme_mode = $state(false);
let use_key = $state(false);
let use_launcher_menu = $state(false);
let use_launcher_header = $state(false);
let use_launcher_footer = $state(false);
// --- Param values
let val_iframe = $state<'true' | 'false'>('true');
let val_theme = $state('nouveau');
let val_theme_mode = $state<'light' | 'dark'>('dark');
let val_key = $state('');
let val_launcher_menu = $state<'hide' | 'show'>('hide');
let val_launcher_header = $state<'hide' | 'show'>('hide');
let val_launcher_footer = $state<'hide' | 'show'>('hide');
// --- Param values
let val_iframe = $state<'true' | 'false'>('true');
let val_theme = $state('nouveau');
let val_theme_mode = $state<'light' | 'dark'>('dark');
let val_key = $state('');
let val_launcher_menu = $state<'hide' | 'show'>('hide');
let val_launcher_header = $state<'hide' | 'show'>('hide');
let val_launcher_footer = $state<'hide' | 'show'>('hide');
// Build the output URL reactively
let built_url = $derived.by(() => {
const base = $page.url;
const u = new URL(base.pathname + base.search + base.hash, base.origin);
// Build the output URL reactively
let built_url = $derived.by(() => {
const base = $page.url;
const u = new URL(base.pathname + base.search + base.hash, base.origin);
// Remove all known params first so we start clean each time
u.searchParams.delete('iframe');
u.searchParams.delete('theme');
u.searchParams.delete('theme_mode');
u.searchParams.delete('key');
u.searchParams.delete('launcher_menu');
u.searchParams.delete('launcher_header');
u.searchParams.delete('launcher_footer');
// Remove all known params first so we start clean each time
u.searchParams.delete('iframe');
u.searchParams.delete('theme');
u.searchParams.delete('theme_mode');
u.searchParams.delete('key');
u.searchParams.delete('launcher_menu');
u.searchParams.delete('launcher_header');
u.searchParams.delete('launcher_footer');
if (use_iframe) u.searchParams.set('iframe', val_iframe);
if (use_theme) u.searchParams.set('theme', val_theme);
if (use_theme_mode) u.searchParams.set('theme_mode', val_theme_mode);
if (use_key && val_key.trim()) u.searchParams.set('key', val_key.trim());
if (use_launcher_menu) u.searchParams.set('launcher_menu', val_launcher_menu);
if (use_launcher_header) u.searchParams.set('launcher_header', val_launcher_header);
if (use_launcher_footer) u.searchParams.set('launcher_footer', val_launcher_footer);
if (use_iframe) u.searchParams.set('iframe', val_iframe);
if (use_theme) u.searchParams.set('theme', val_theme);
if (use_theme_mode) u.searchParams.set('theme_mode', val_theme_mode);
if (use_key && val_key.trim()) u.searchParams.set('key', val_key.trim());
if (use_launcher_menu)
u.searchParams.set('launcher_menu', val_launcher_menu);
if (use_launcher_header)
u.searchParams.set('launcher_header', val_launcher_header);
if (use_launcher_footer)
u.searchParams.set('launcher_footer', val_launcher_footer);
return u.toString();
return u.toString();
});
// Output mode: full URL (default) or params-only string
let params_only = $state(false);
let output = $derived.by(() => {
if (!params_only) return built_url;
const u = new URL(built_url);
return u.search || '(no params set)';
});
let copied = $state(false);
function copy_url() {
navigator.clipboard.writeText(output).then(() => {
copied = true;
setTimeout(() => (copied = false), 2000);
});
}
// Output mode: full URL (default) or params-only string
let params_only = $state(false);
let output = $derived.by(() => {
if (!params_only) return built_url;
const u = new URL(built_url);
return u.search || '(no params set)';
});
let copied = $state(false);
function copy_url() {
navigator.clipboard.writeText(output).then(() => {
copied = true;
setTimeout(() => copied = false, 2000);
});
}
const theme_options = [
{ value: 'cerberus', label: 'Cerberus' },
{ value: 'concord', label: 'Concord' },
{ value: 'crimson', label: 'Crimson' },
{ value: 'hamlindigo', label: 'Hamlindigo' },
{ value: 'modern', label: 'Modern' },
{ value: 'nouveau', label: 'Nouveau' },
{ value: 'rocket', label: 'Rocket' },
{ value: 'terminus', label: 'Terminus' },
{ value: 'vintage', label: 'Vintage' },
{ value: 'wintry', label: 'Wintry' },
{ value: 'AE_OSIT_default', label: 'OSIT' },
{ value: 'AE_Firefly', label: 'Firefly ✦' },
{ value: 'AE_Firefly_SteelBlue', label: 'Firefly SteelBlue ✦' },
{ value: 'AE_Firefly_Indigo', label: 'Firefly Indigo ✦' },
{ value: 'AE_Firefly_Rainbow', label: 'Firefly Rainbow ✨' },
{ value: 'AE_c_IDAA_light', label: 'IDAA light' },
{ value: 'AE_c_LCI', label: 'LCI' },
];
const theme_options = [
{ value: 'cerberus', label: 'Cerberus' },
{ value: 'concord', label: 'Concord' },
{ value: 'crimson', label: 'Crimson' },
{ value: 'hamlindigo', label: 'Hamlindigo' },
{ value: 'modern', label: 'Modern' },
{ value: 'nouveau', label: 'Nouveau' },
{ value: 'rocket', label: 'Rocket' },
{ value: 'terminus', label: 'Terminus' },
{ value: 'vintage', label: 'Vintage' },
{ value: 'wintry', label: 'Wintry' },
{ value: 'AE_OSIT_default', label: 'OSIT' },
{ value: 'AE_Firefly', label: 'Firefly ✦' },
{ value: 'AE_Firefly_SteelBlue', label: 'Firefly SteelBlue ✦' },
{ value: 'AE_Firefly_Indigo', label: 'Firefly Indigo ✦' },
{ value: 'AE_Firefly_Rainbow', label: 'Firefly Rainbow ✨' },
{ value: 'AE_c_IDAA_light', label: 'IDAA light' },
{ value: 'AE_c_LCI', label: 'LCI' }
];
</script>
<section class="space-y-3 text-sm">
<h2 class="text-xs font-semibold uppercase tracking-widest text-surface-500 dark:text-surface-400 flex items-center gap-1">
<h2
class="text-surface-500 dark:text-surface-400 flex items-center gap-1 text-xs font-semibold tracking-widest uppercase">
<Link size="0.9em" /> URL Param Builder
</h2>
<!-- ── Core params ─────────────────────────────────────────────────── -->
<div class="space-y-1.5">
<p class="text-[9px] font-bold uppercase tracking-widest opacity-40 ml-0.5">Core</p>
<p
class="ml-0.5 text-[9px] font-bold tracking-widest uppercase opacity-40">
Core
</p>
<!-- iframe -->
<div class="flex items-center gap-2">
<input id="ubld_iframe" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_iframe} />
<label for="ubld_iframe" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_iframe}>iframe</label>
<select bind:value={val_iframe} disabled={!use_iframe} class="select select-sm text-xs flex-1 disabled:opacity-40">
<input
id="ubld_iframe"
type="checkbox"
class="checkbox checkbox-sm shrink-0"
bind:checked={use_iframe} />
<label
for="ubld_iframe"
class="w-24 cursor-pointer font-mono text-xs select-none"
class:opacity-35={!use_iframe}>iframe</label>
<select
bind:value={val_iframe}
disabled={!use_iframe}
class="select select-sm flex-1 text-xs disabled:opacity-40">
<option value="true">true</option>
<option value="false">false</option>
</select>
@@ -122,9 +138,19 @@
<!-- theme -->
<div class="flex items-center gap-2">
<input id="ubld_theme" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_theme} />
<label for="ubld_theme" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_theme}>theme</label>
<select bind:value={val_theme} disabled={!use_theme} class="select select-sm text-xs flex-1 disabled:opacity-40">
<input
id="ubld_theme"
type="checkbox"
class="checkbox checkbox-sm shrink-0"
bind:checked={use_theme} />
<label
for="ubld_theme"
class="w-24 cursor-pointer font-mono text-xs select-none"
class:opacity-35={!use_theme}>theme</label>
<select
bind:value={val_theme}
disabled={!use_theme}
class="select select-sm flex-1 text-xs disabled:opacity-40">
{#each theme_options as opt}
<option value={opt.value}>{opt.label}</option>
{/each}
@@ -133,9 +159,19 @@
<!-- theme_mode -->
<div class="flex items-center gap-2">
<input id="ubld_theme_mode" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_theme_mode} />
<label for="ubld_theme_mode" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_theme_mode}>theme_mode</label>
<select bind:value={val_theme_mode} disabled={!use_theme_mode} class="select select-sm text-xs flex-1 disabled:opacity-40">
<input
id="ubld_theme_mode"
type="checkbox"
class="checkbox checkbox-sm shrink-0"
bind:checked={use_theme_mode} />
<label
for="ubld_theme_mode"
class="w-24 cursor-pointer font-mono text-xs select-none"
class:opacity-35={!use_theme_mode}>theme_mode</label>
<select
bind:value={val_theme_mode}
disabled={!use_theme_mode}
class="select select-sm flex-1 text-xs disabled:opacity-40">
<option value="light">light</option>
<option value="dark">dark</option>
</select>
@@ -143,27 +179,46 @@
<!-- key -->
<div class="flex items-center gap-2">
<input id="ubld_key" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_key} />
<label for="ubld_key" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_key}>key</label>
<input
id="ubld_key"
type="checkbox"
class="checkbox checkbox-sm shrink-0"
bind:checked={use_key} />
<label
for="ubld_key"
class="w-24 cursor-pointer font-mono text-xs select-none"
class:opacity-35={!use_key}>key</label>
<input
type="text"
bind:value={val_key}
disabled={!use_key}
placeholder="access key"
class="input input-sm text-xs font-mono flex-1 disabled:opacity-40"
/>
class="input input-sm flex-1 font-mono text-xs disabled:opacity-40" />
</div>
</div>
<!-- ── Launcher params ─────────────────────────────────────────────── -->
<div class="space-y-1.5 border-t border-surface-500/20 pt-2.5">
<p class="text-[9px] font-bold uppercase tracking-widest opacity-40 ml-0.5">Launcher</p>
<div class="border-surface-500/20 space-y-1.5 border-t pt-2.5">
<p
class="ml-0.5 text-[9px] font-bold tracking-widest uppercase opacity-40">
Launcher
</p>
<!-- launcher_menu -->
<div class="flex items-center gap-2">
<input id="ubld_launcher_menu" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_launcher_menu} />
<label for="ubld_launcher_menu" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_launcher_menu}>menu</label>
<select bind:value={val_launcher_menu} disabled={!use_launcher_menu} class="select select-sm text-xs flex-1 disabled:opacity-40">
<input
id="ubld_launcher_menu"
type="checkbox"
class="checkbox checkbox-sm shrink-0"
bind:checked={use_launcher_menu} />
<label
for="ubld_launcher_menu"
class="w-24 cursor-pointer font-mono text-xs select-none"
class:opacity-35={!use_launcher_menu}>menu</label>
<select
bind:value={val_launcher_menu}
disabled={!use_launcher_menu}
class="select select-sm flex-1 text-xs disabled:opacity-40">
<option value="hide">hide</option>
<option value="show">show</option>
</select>
@@ -171,9 +226,19 @@
<!-- launcher_header -->
<div class="flex items-center gap-2">
<input id="ubld_launcher_header" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_launcher_header} />
<label for="ubld_launcher_header" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_launcher_header}>header</label>
<select bind:value={val_launcher_header} disabled={!use_launcher_header} class="select select-sm text-xs flex-1 disabled:opacity-40">
<input
id="ubld_launcher_header"
type="checkbox"
class="checkbox checkbox-sm shrink-0"
bind:checked={use_launcher_header} />
<label
for="ubld_launcher_header"
class="w-24 cursor-pointer font-mono text-xs select-none"
class:opacity-35={!use_launcher_header}>header</label>
<select
bind:value={val_launcher_header}
disabled={!use_launcher_header}
class="select select-sm flex-1 text-xs disabled:opacity-40">
<option value="hide">hide</option>
<option value="show">show</option>
</select>
@@ -181,9 +246,19 @@
<!-- launcher_footer -->
<div class="flex items-center gap-2">
<input id="ubld_launcher_footer" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_launcher_footer} />
<label for="ubld_launcher_footer" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_launcher_footer}>footer</label>
<select bind:value={val_launcher_footer} disabled={!use_launcher_footer} class="select select-sm text-xs flex-1 disabled:opacity-40">
<input
id="ubld_launcher_footer"
type="checkbox"
class="checkbox checkbox-sm shrink-0"
bind:checked={use_launcher_footer} />
<label
for="ubld_launcher_footer"
class="w-24 cursor-pointer font-mono text-xs select-none"
class:opacity-35={!use_launcher_footer}>footer</label>
<select
bind:value={val_launcher_footer}
disabled={!use_launcher_footer}
class="select select-sm flex-1 text-xs disabled:opacity-40">
<option value="hide">hide</option>
<option value="show">show</option>
</select>
@@ -191,26 +266,33 @@
</div>
<!-- ── Output ──────────────────────────────────────────────────────── -->
<div class="border-t border-surface-500/20 pt-2.5 space-y-1.5">
<div class="border-surface-500/20 space-y-1.5 border-t pt-2.5">
<div class="flex items-center gap-2">
<input id="ubld_params_only" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={params_only} />
<label for="ubld_params_only" class="text-xs cursor-pointer select-none" class:opacity-35={!params_only}>Params only</label>
<input
id="ubld_params_only"
type="checkbox"
class="checkbox checkbox-sm shrink-0"
bind:checked={params_only} />
<label
for="ubld_params_only"
class="cursor-pointer text-xs select-none"
class:opacity-35={!params_only}>Params only</label>
</div>
<div class="flex gap-1 items-stretch">
<div class="flex items-stretch gap-1">
<input
type="text"
readonly
value={output}
class="input input-sm text-xs font-mono flex-1 bg-surface-50/50 dark:bg-surface-700/50 cursor-text"
class="input input-sm bg-surface-50/50 dark:bg-surface-700/50 flex-1 cursor-text font-mono text-xs"
onclick={(e) => (e.target as HTMLInputElement).select()}
title="Click to select all"
/>
title="Click to select all" />
<button
class="btn btn-sm {copied ? 'preset-filled-success' : 'preset-tonal-primary'} shrink-0 transition-all"
class="btn btn-sm {copied
? 'preset-filled-success'
: 'preset-tonal-primary'} shrink-0 transition-all"
onclick={copy_url}
title="Copy URL to clipboard"
>
title="Copy URL to clipboard">
{#if copied}
<Check size="1em" />
{:else}
@@ -219,5 +301,4 @@
</button>
</div>
</div>
</section>