- Renamed internal 'preventDefault' to 'prevent_default' in launcher files. - Fixed native 'event.preventDefault()' call in launcher_file_cont.svelte. - Applied batch formatting (printWidth: 80) across the (launcher) module.
940 lines
32 KiB
Svelte
940 lines
32 KiB
Svelte
<script lang="ts">
|
|
let log_lvl: number = $state(1);
|
|
interface Props {
|
|
/** @type {import('./$types').LayoutData} */
|
|
data: any;
|
|
children?: import('svelte').Snippet;
|
|
}
|
|
|
|
let { data, children }: Props = $props();
|
|
|
|
// *** Import Svelte specific
|
|
// import { onMount, tick } from 'svelte';
|
|
import { goto } from '$app/navigation';
|
|
import { sineIn } from 'svelte/easing';
|
|
|
|
// *** Import other supporting libraries
|
|
import { liveQuery } from 'dexie';
|
|
import { Drawer, Footer, Modal } from 'flowbite-svelte';
|
|
import { listen, idle, onIdle, restartCountdown } from 'svelte-idle';
|
|
|
|
import {
|
|
// Brain,
|
|
// House, Library,
|
|
LoaderCircle,
|
|
// RefreshCw,
|
|
Satellite
|
|
} from '@lucide/svelte';
|
|
|
|
// *** Import Aether specific variables and functions
|
|
import type { key_val } from '$lib/stores/ae_stores';
|
|
import { ae_util } from '$lib/ae_utils/ae_utils';
|
|
import { api } from '$lib/api/api';
|
|
import { db_events } from '$lib/ae_events/db_events';
|
|
import {
|
|
ae_snip,
|
|
ae_loc,
|
|
ae_sess,
|
|
ae_api,
|
|
ae_trig,
|
|
slct,
|
|
slct_trigger,
|
|
time
|
|
} from '$lib/stores/ae_stores';
|
|
import {
|
|
events_loc,
|
|
events_sess,
|
|
events_slct,
|
|
events_trigger,
|
|
events_trig
|
|
} from '$lib/stores/ae_events_stores';
|
|
import { events_func } from '$lib/ae_events_functions';
|
|
|
|
import Launcher_cfg from '../launcher_cfg.svelte';
|
|
import Launcher_menu from '../launcher_menu.svelte';
|
|
import Launcher_session_view from '../launcher_session_view.svelte';
|
|
import Element_websocket_v2 from '$lib/elements/element_websocket_v2.svelte';
|
|
|
|
// *** Set initial variables
|
|
let ae_acct = data[$slct.account_id];
|
|
|
|
import { online } from 'svelte/reactivity/window';
|
|
|
|
$ae_sess.disable_sys_nav = true;
|
|
$ae_sess.disable_sys_header = true;
|
|
$ae_sess.disable_sys_footer = true;
|
|
|
|
if (!$events_loc?.launcher) {
|
|
$events_loc.launcher = {
|
|
app_mode: 'default',
|
|
controller: 'local',
|
|
controller_group_code: 'launcher-00',
|
|
ws_connect: false,
|
|
hide_drawer__cfg: true,
|
|
hide_drawer__debug: true
|
|
};
|
|
}
|
|
|
|
if (log_lvl) {
|
|
console.log(`event_id: ${data.params.event_id}`);
|
|
console.log(`event_location_id: ${data.params.event_location_id}`);
|
|
console.log(
|
|
`event_session_id: ${data.url.searchParams.get('session_id')}`
|
|
);
|
|
}
|
|
$events_slct.event_id = data.params.event_id;
|
|
$events_slct.event_location_id = data.params.event_location_id;
|
|
$events_slct.event_session_id = data.url.searchParams.get('session_id');
|
|
|
|
// String-Only ID Vision: Sync the device ID from the native environment
|
|
const native_dev = $ae_loc.native_device;
|
|
if (native_dev) {
|
|
$events_slct.event_device_id =
|
|
native_dev.event_device_id ||
|
|
native_dev.id ||
|
|
native_dev.event_device_id_random ||
|
|
native_dev.id_random;
|
|
}
|
|
|
|
$events_slct.event_location_obj_li = ae_acct.slct.event_location_obj_li ?? [
|
|
''
|
|
];
|
|
$events_slct.id_li__event_location = ae_acct.slct.id_li__event_location ?? [
|
|
''
|
|
];
|
|
|
|
// *** Functions and Logic
|
|
|
|
// Event
|
|
let lq__event_obj = liveQuery(async () => {
|
|
const id = $events_slct?.event_id;
|
|
if (!id) return null;
|
|
if (log_lvl > 1) console.log(`lq__event_obj: event_id = ${id}`);
|
|
let results = await db_events.event.get(id);
|
|
|
|
if ($events_slct.event_obj && results) {
|
|
if (
|
|
JSON.stringify($events_slct.event_obj) !==
|
|
JSON.stringify(results)
|
|
) {
|
|
$events_slct.event_obj = { ...results };
|
|
}
|
|
}
|
|
return results;
|
|
});
|
|
|
|
// Event Device
|
|
let lq__event_device_obj = liveQuery(async () => {
|
|
const id = $events_slct.event_device_id;
|
|
if (!id) return null;
|
|
let results = await db_events.device.get(id);
|
|
if ($events_slct.event_device_obj && results) {
|
|
if (
|
|
JSON.stringify($events_slct.event_device_obj) !==
|
|
JSON.stringify(results)
|
|
) {
|
|
$events_slct.event_device_obj = { ...results };
|
|
}
|
|
}
|
|
return results;
|
|
});
|
|
|
|
// Event File - For Event
|
|
let lq__event_event_file_obj_li = liveQuery(async () => {
|
|
const id = $events_slct.event_id;
|
|
if (!id) return [];
|
|
return await db_events.file
|
|
.where('for_id')
|
|
.equals(id)
|
|
.sortBy('filename');
|
|
});
|
|
|
|
// Event File - For Location
|
|
let lq__location_event_file_obj_li = liveQuery(async () => {
|
|
const id = $events_slct.event_location_id;
|
|
if (!id) return [];
|
|
return await db_events.file
|
|
.where('for_id')
|
|
.equals(id)
|
|
.sortBy('filename');
|
|
});
|
|
|
|
// Event Location
|
|
let lq__event_location_obj = liveQuery(async () => {
|
|
const id = $events_slct.event_location_id;
|
|
if (!id) return null;
|
|
return await db_events.location.get(id);
|
|
});
|
|
|
|
let lq__event_location_obj_li = liveQuery(async () => {
|
|
const id = $events_slct.event_id;
|
|
if (!id) return [];
|
|
return await db_events.location
|
|
.where('event_id')
|
|
.equals(id)
|
|
.sortBy('name');
|
|
});
|
|
|
|
// Event Session (Main View Trigger)
|
|
// Removed $derived wrapper to ensure stable observable subscription in Svelte 5
|
|
let lq__event_session_obj = liveQuery(async () => {
|
|
const id = $events_slct.event_session_id;
|
|
if (!id) return null;
|
|
if (log_lvl)
|
|
console.log(
|
|
`🔍 [Trace] Launcher Layout LQ: Fetching session_id=${id}`
|
|
);
|
|
const start = performance.now();
|
|
let results = await db_events.session.get(id);
|
|
if (log_lvl)
|
|
console.log(
|
|
`📦 [Trace] Launcher Layout LQ: Result obtained in ${(performance.now() - start).toFixed(2)}ms (Result=${results?.name || 'NOT FOUND'})`
|
|
);
|
|
return results;
|
|
});
|
|
|
|
let lq__event_session_obj_li = liveQuery(async () => {
|
|
const id = $events_slct.event_location_id;
|
|
if (!id) return [];
|
|
if (log_lvl > 1)
|
|
console.log(
|
|
`LQ - Using default sort for Event Session list location_id: ${id}`
|
|
);
|
|
let results = await db_events.session
|
|
.where('event_location_id')
|
|
.equals(id)
|
|
.reverse()
|
|
.sortBy('name');
|
|
|
|
if (
|
|
$events_slct.event_session_obj_li &&
|
|
JSON.stringify($events_slct.event_session_obj_li) !==
|
|
JSON.stringify(results)
|
|
) {
|
|
$events_slct.event_session_obj_li = [...(results || [])];
|
|
}
|
|
return results;
|
|
});
|
|
|
|
let trigger_handle_ws_conn = $state(false);
|
|
let trigger_handle_ws_recv = $state(false);
|
|
let trigger_handle_ws_sent = $state(false);
|
|
|
|
/* *** BEGIN *** Handle WebSocket events */
|
|
function handle_ws_conn(ws_conn_status: any) {
|
|
if (log_lvl) console.log('*** handle_ws_conn() ***', ws_conn_status);
|
|
if (ws_conn_status.status == 'connected') {
|
|
$events_sess.launcher.ws = { status: 'connected' };
|
|
} else {
|
|
$events_sess.launcher.ws = { status: 'disconnected' };
|
|
}
|
|
}
|
|
|
|
function handle_ws_recv(ws_recv_status: any) {
|
|
if (log_lvl) console.log('*** handle_ws_recv() ***', ws_recv_status);
|
|
if (ws_recv_status.type == 'cmd' && ws_recv_status.cmd) {
|
|
let cmd = ws_recv_status.cmd;
|
|
if ($events_loc.launcher.controller != 'remote') return;
|
|
|
|
if (cmd.startsWith('ae_load:')) {
|
|
let cmd_parts = cmd.split(':');
|
|
let obj_parts = cmd_parts[1].split('=');
|
|
let obj_type = obj_parts[0];
|
|
let obj_id = obj_parts[1];
|
|
|
|
if (obj_type == 'event_session') {
|
|
$events_slct.event_session_id = obj_id;
|
|
let new_url = new URL(data.url);
|
|
new_url.pathname = `/events/${$lq__event_session_obj?.event_id}/launcher/${$lq__event_session_obj?.event_location_id}`;
|
|
new_url.searchParams.set(
|
|
'session_id',
|
|
$events_slct.event_session_id
|
|
);
|
|
goto(new_url.toString(), { replaceState: false });
|
|
}
|
|
} else if (cmd.startsWith('ae_download:')) {
|
|
let cmd_parts = cmd.split(':');
|
|
let obj_parts = cmd_parts[1].split('=');
|
|
let obj_type = obj_parts[0];
|
|
let obj_id = obj_parts[1];
|
|
let obj_filename = cmd_parts[2];
|
|
|
|
api.get_object({
|
|
api_cfg: $ae_api,
|
|
endpoint: `/v3/action/hosted_file/${obj_id}/download`,
|
|
params: {
|
|
filename: obj_filename,
|
|
key: $ae_api.account_id
|
|
},
|
|
return_blob: true,
|
|
auto_download: true,
|
|
log_lvl: 1
|
|
});
|
|
} else if (cmd.startsWith('ae_open:')) {
|
|
let cmd_parts = cmd.split(':');
|
|
let obj_parts = cmd_parts[1].split('=');
|
|
let obj_id = obj_parts[1];
|
|
|
|
if (obj_parts[0] == 'event_file') {
|
|
$events_sess.launcher.modal__open_event_file_id = null;
|
|
clearInterval(idle_timer_interval);
|
|
saver_looping = false;
|
|
restartCountdown();
|
|
$events_slct.event_file_id = obj_id;
|
|
$events_sess.launcher.modal__open_event_file_id = obj_id;
|
|
}
|
|
} else if (cmd.startsWith('ae_close:')) {
|
|
if (cmd.split(':')[1] == 'event_file_modal') {
|
|
$events_sess.launcher.modal__open_event_file_id = null;
|
|
}
|
|
clearInterval(idle_timer_interval);
|
|
saver_looping = false;
|
|
restartCountdown();
|
|
} else if (cmd.startsWith('ae_refresh:')) {
|
|
if (cmd.split(':')[1] == 'now') location.reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
function handle_ws_sent(ws_sent_status: any) {
|
|
$events_sess.launcher.controller_cmd = null;
|
|
$events_sess.launcher.controller_trigger_send = null;
|
|
}
|
|
|
|
$effect(() => {
|
|
if (trigger_handle_ws_conn) {
|
|
handle_ws_conn(trigger_handle_ws_conn);
|
|
trigger_handle_ws_conn = false;
|
|
}
|
|
});
|
|
|
|
$effect(() => {
|
|
if (trigger_handle_ws_recv) {
|
|
handle_ws_recv(trigger_handle_ws_recv);
|
|
trigger_handle_ws_recv = false;
|
|
}
|
|
});
|
|
|
|
$effect(() => {
|
|
if (trigger_handle_ws_sent) {
|
|
handle_ws_sent(trigger_handle_ws_sent);
|
|
trigger_handle_ws_sent = false;
|
|
}
|
|
});
|
|
|
|
if (!$events_loc.launcher.idle_timer)
|
|
$events_loc.launcher.idle_timer = 5 * 60 * 1000;
|
|
if (!$events_loc.launcher.idle_cycle)
|
|
$events_loc.launcher.idle_cycle = 5 * 1000;
|
|
if (!$events_loc.launcher.idle_loop_period)
|
|
$events_loc.launcher.idle_loop_period = 3 * 60 * 1000;
|
|
|
|
listen({
|
|
timer: $events_loc.launcher.idle_timer,
|
|
cycle: $events_loc.launcher.idle_cycle
|
|
});
|
|
|
|
let idle_timer_interval: any = $state();
|
|
let saver_looping: boolean = $state(false);
|
|
|
|
function handle_idle_client() {
|
|
if (
|
|
$lq__event_session_obj &&
|
|
$lq__event_session_obj?.type_code == 'poster'
|
|
) {
|
|
if (saver_looping) return false;
|
|
saver_looping = true;
|
|
|
|
idle_timer_interval = setInterval(
|
|
() => {
|
|
if ($events_loc.launcher.screen_saver_img_kv) {
|
|
const keys = Object.keys(
|
|
$events_loc.launcher.screen_saver_img_kv
|
|
);
|
|
const rand_index = Math.floor(
|
|
Math.random() * keys.length
|
|
);
|
|
let event_file_obj =
|
|
$events_loc.launcher.screen_saver_img_kv[
|
|
keys[rand_index]
|
|
];
|
|
|
|
$events_slct.event_file_id =
|
|
event_file_obj.event_file_id;
|
|
$events_slct.event_file_obj = event_file_obj;
|
|
$events_sess.launcher.modal__open_event_file_id = null;
|
|
$events_sess.launcher.modal__title =
|
|
event_file_obj.filename ?? '*';
|
|
$events_sess.launcher.modal__open_event_file_id =
|
|
$events_slct.event_file_id;
|
|
$events_sess.launcher.modal__event_file_obj =
|
|
event_file_obj;
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
$events_loc.launcher.idle_loop_period ?? 2 * 60 * 1000
|
|
);
|
|
} else {
|
|
saver_looping = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
onIdle(() => {
|
|
clearInterval(idle_timer_interval);
|
|
handle_idle_client();
|
|
});
|
|
|
|
$effect(() => {
|
|
if (!$idle) {
|
|
clearInterval(idle_timer_interval);
|
|
saver_looping = false;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>
|
|
Æ:
|
|
{$lq__event_location_obj?.name ?? '-- not set --'}
|
|
({$lq__event_session_obj?.name ?? 'Æ loading...'}) - Launcher v3 -
|
|
{$events_loc?.title}
|
|
</title>
|
|
</svelte:head>
|
|
|
|
<div
|
|
class="
|
|
static
|
|
m-auto
|
|
border-x border-gray-200 dark:border-gray-600
|
|
mt-4 mb-16 sm:mb-12
|
|
h-full
|
|
w-full max-w-7xl
|
|
transition-all
|
|
"
|
|
>
|
|
<header
|
|
id="Main-Header"
|
|
class:hidden={$events_loc.launcher.hide__launcher_header}
|
|
class="
|
|
z-20
|
|
absolute top-0 left-0 right-0
|
|
w-full max-w-7xl
|
|
h-12
|
|
p-1 px-12 m-auto
|
|
|
|
flex flex-row items-center justify-around sm:justify-between
|
|
|
|
text-sm hover:text-base
|
|
|
|
bg-slate-200
|
|
|
|
opacity-90 hover:opacity-100
|
|
transition-all duration-1000
|
|
"
|
|
>
|
|
<h3 class="h4 text-center italic text-surface-600-400">
|
|
<button
|
|
type="button"
|
|
class=""
|
|
onclick={() => {
|
|
$events_loc.launcher.hide__launcher_menu =
|
|
!$events_loc.launcher.hide__launcher_menu;
|
|
}}
|
|
title="Toggle Launcher menu"
|
|
>
|
|
<Satellite class="text-base mx-1 inline-block text-gray-500" />
|
|
<abbr title="Aether - Events Module Launcher">
|
|
Æ Launcher
|
|
<span
|
|
class="text-xs align-super font-normal"
|
|
title="Version 3">v3</span
|
|
>
|
|
</abbr>
|
|
</button>
|
|
</h3>
|
|
|
|
{#if $lq__event_obj}
|
|
<h2
|
|
class="hidden md:inline-block h3 text-center text-surface-600-400"
|
|
>
|
|
{$lq__event_obj.cfg_json?.short_name}
|
|
</h2>
|
|
<h3
|
|
class="h4 text-center italic text-surface-600-400"
|
|
title="Location ID: {$lq__event_location_obj?.event_location_id} Name: {$lq__event_location_obj?.name}"
|
|
>
|
|
<button
|
|
type="button"
|
|
class="text-base"
|
|
onclick={() => {
|
|
$ae_loc.edit_mode = !$ae_loc.edit_mode;
|
|
}}
|
|
title="Toggle Edit Mode to show location options and more"
|
|
>
|
|
<span class="fas fa-map-marker-alt"></span>
|
|
<span class="sr-only">Location:</span>
|
|
</button>
|
|
{$lq__event_location_obj?.name}
|
|
</h3>
|
|
{:else}
|
|
<div class="flex flex-row gap-1 items-center justify-center">
|
|
<span class="fas fa-spinner fa-spin mx-1"></span>
|
|
<span>Loading event...</span>
|
|
</div>
|
|
{/if}
|
|
</header>
|
|
|
|
<div
|
|
class="
|
|
h-full min-w-full w-full max-w-full
|
|
flex flex-col sm:flex-row flex-wrap sm:flex-nowrap gap-0
|
|
items-center
|
|
justify-start sm:justify-center
|
|
py-1 px-0.5
|
|
bg-gray-100
|
|
|
|
"
|
|
>
|
|
<section
|
|
id="Main-Nav-Menu"
|
|
class="event_launcher_menu
|
|
h-full
|
|
basis-1/5
|
|
min-w-56 md:min-w-64 lg:min-w-72
|
|
max-w-xs
|
|
pt-0.5 pr-0.5
|
|
flex flex-col gap-1 items-center justify-start
|
|
|
|
border-r border-gray-200 dark:border-gray-700
|
|
hover:bg-surface-100-900
|
|
"
|
|
class:hidden={$events_loc.launcher.hide__launcher_menu}
|
|
>
|
|
<Launcher_menu
|
|
data_url={data.url}
|
|
{lq__event_obj}
|
|
{lq__event_event_file_obj_li}
|
|
{lq__location_event_file_obj_li}
|
|
slct__event_file_id={$events_slct.event_file_id}
|
|
{lq__event_location_obj_li}
|
|
{lq__event_location_obj}
|
|
slct__event_location_id={$events_slct.event_location_id}
|
|
bind:loading__session_li_status={
|
|
$events_sess.launcher.loading__session_li_status
|
|
}
|
|
{lq__event_session_obj_li}
|
|
bind:loading__session_id_status={
|
|
$events_sess.launcher.loading__session_id_status
|
|
}
|
|
{lq__event_session_obj}
|
|
bind:slct__event_session_id={$events_slct.event_session_id}
|
|
bind:trigger_reload__event_session_obj_id={
|
|
$events_sess.launcher.trigger_reload__event_session_obj_id
|
|
}
|
|
bind:trigger_reload__event_session_obj_li={
|
|
$events_sess.launcher.trigger_reload__event_session_obj_li
|
|
}
|
|
bind:trigger_reload__event_location_obj_li={
|
|
$events_sess.launcher.trigger_reload__event_location_obj_li
|
|
}
|
|
></Launcher_menu>
|
|
</section>
|
|
|
|
<section
|
|
id="Main-Content"
|
|
class="event_launcher_main
|
|
h-full
|
|
min-w-xs
|
|
max-w-full
|
|
py-1 px-0.5
|
|
basis-4/5
|
|
flex flex-col gap-1
|
|
items-center
|
|
justify-center
|
|
overflow-y-auto
|
|
"
|
|
>
|
|
{#if !$events_slct.event_location_id}
|
|
<div
|
|
class="flex flex-row items-center justify-center p-8 opacity-50"
|
|
>
|
|
<span class="fas fa-map-marker-alt mx-2 text-2xl"></span>
|
|
<span>Please select a location from the menu</span>
|
|
</div>
|
|
{/if}
|
|
|
|
{#if $events_slct.event_session_id && $lq__event_session_obj}
|
|
<Launcher_session_view
|
|
bind:slct__event_session_id={$events_slct.event_session_id}
|
|
{lq__event_session_obj}
|
|
bind:type_code={$lq__event_session_obj.type_code}
|
|
></Launcher_session_view>
|
|
{:else if $events_slct.event_session_id}
|
|
<div
|
|
class="flex flex-col items-center justify-center p-8 opacity-50"
|
|
>
|
|
<LoaderCircle class="animate-spin mb-2" />
|
|
<span>Loading session details...</span>
|
|
</div>
|
|
{/if}
|
|
</section>
|
|
</div>
|
|
|
|
{@render children?.()}
|
|
</div>
|
|
|
|
<footer
|
|
id="Main-Footer"
|
|
class:hidden={$events_loc.launcher.hide__launcher_footer}
|
|
class="
|
|
z-20
|
|
absolute bottom-0 left-0 right-0
|
|
w-full max-w-7xl
|
|
p-1 m-auto
|
|
|
|
flex flex-row items-center justify-between
|
|
sm:flex-row md:items-center md:justify-between
|
|
|
|
text-xs hover:sm:text-sm hover:md:text-base hover:lg:text-lg
|
|
|
|
|
|
bg-gray-200 border-t border-gray-200
|
|
dark:bg-gray-800 dark:border-gray-600
|
|
|
|
opacity-50 hover:opacity-100
|
|
transition-all duration-1000
|
|
"
|
|
>
|
|
<div
|
|
class="slct_location_name transition-all duration-1000"
|
|
title="Location ID: {$lq__event_location_obj?.event_location_id} Name: {$lq__event_location_obj?.name} | Device ID: {$lq__event_device_obj?.event_device_id} Name: {$lq__event_device_obj?.name}"
|
|
>
|
|
<button
|
|
type="button"
|
|
class=""
|
|
onclick={() => {
|
|
$ae_loc.edit_mode = !$ae_loc.edit_mode;
|
|
}}
|
|
title="Toggle Edit Mode to show location options and more"
|
|
>
|
|
<span class="sr-only">Location:</span>
|
|
<span class="fas fa-map-marker-alt"></span>
|
|
</button>
|
|
{$lq__event_location_obj?.name}
|
|
{#if $lq__event_device_obj?.name}
|
|
<span class="fas fa-laptop mx-1"></span>
|
|
{$lq__event_device_obj?.name}
|
|
{/if}
|
|
</div>
|
|
|
|
<span
|
|
class:preset-tonal-warning={!$idle}
|
|
class:preset-tonal-success={$idle}
|
|
class="group px-1 rounded-md transition-all duration-1000"
|
|
title="The user is currently {$idle ? 'idle' : 'active'}"
|
|
>
|
|
{#if $idle}
|
|
<span class="fas fa-bed mx-1"></span>
|
|
<span class="hidden group-hover:inline"> Idle </span>
|
|
{:else}
|
|
<span class="fas fa-mouse-pointer mx-1"></span>
|
|
<span class="hidden group-hover:inline"> Active </span>
|
|
{/if}
|
|
</span>
|
|
|
|
<span
|
|
class="group px-1 rounded-md transition-all duration-1000"
|
|
title="Online status = {online?.current}"
|
|
>
|
|
<span class="fas fa-wifi mx-1"></span>
|
|
{online?.current ? '' : 'Offline!'}
|
|
</span>
|
|
|
|
<span
|
|
class:hidden={!$events_loc.launcher.ws_connect}
|
|
class:preset-tonal-warning={$events_sess.launcher.ws_connect_status !=
|
|
'connected'}
|
|
class:preset-tonal-success={$events_sess.launcher.ws_connect_status ==
|
|
'connected'}
|
|
class="group px-1 rounded-md transition-all duration-1000"
|
|
title="WebSocket is {$events_sess.launcher.ws_connect_status ==
|
|
'connected'
|
|
? 'connected'
|
|
: 'disconnected'} API: {$ae_api?.base_url}"
|
|
>
|
|
{#if $events_sess.launcher.ws_connect_status == 'connected'}
|
|
<span class="fas fa-sitemap mx-1 text-green-700"></span>
|
|
<span class="hidden group-hover:inline"> WS Connected </span>
|
|
{:else}
|
|
<span class="fas fa-times mx-1"></span>
|
|
<span class="hidden group-hover:inline"> WS Disconnected </span>
|
|
{/if}
|
|
</span>
|
|
|
|
<div
|
|
class="current_datetime font-mono px-2 hover:font-bold hover:bg-white transition-all"
|
|
>
|
|
<span class="hidden md:inline">
|
|
<span class="fas fa-calendar-alt"></span>
|
|
{ae_util.iso_datetime_formatter($time, 'date_full_no_year')}
|
|
</span>
|
|
<span class="hidden sm:inline">
|
|
<span class="fas fa-clock"></span>
|
|
</span>
|
|
{#if $events_loc.launcher?.time_hours == 12}
|
|
{ae_util.iso_datetime_formatter($time, 'time_12_long')}
|
|
{:else}
|
|
{ae_util.iso_datetime_formatter($time, 'time_long')}
|
|
{/if}
|
|
</div>
|
|
</footer>
|
|
|
|
<div class="absolute top-0 left-0 z-20 text-center">
|
|
<button
|
|
type="button"
|
|
onclick={() => ($events_loc.launcher.hide_drawer__cfg = false)}
|
|
class="btn btn-sm p-2.5 preset-tonal-error hover:preset-filled-error-500 transition-all duration-1000"
|
|
class:opacity-25={!$ae_loc.trusted_access}
|
|
class:hover:opacity-75={!$ae_loc.trusted_access}
|
|
>
|
|
<span class="fas fa-biohazard"></span>
|
|
<span class="hidden">Launcher Config</span>
|
|
</button>
|
|
</div>
|
|
|
|
<Drawer
|
|
class="bg-orange-100 opacity-90 hover:opacity-97 transition-all duration-1000 border border-gray-300 dark:border-gray-600 w-full md:w-96 lg:w-[32rem]"
|
|
placement="left"
|
|
transitionType="fly"
|
|
transitionParams={{
|
|
x: -520,
|
|
duration: 200,
|
|
easing: sineIn
|
|
}}
|
|
bind:hidden={$events_loc.launcher.hide_drawer__cfg}
|
|
id="sidebar1"
|
|
>
|
|
<Launcher_cfg></Launcher_cfg>
|
|
|
|
<hr class="my-2 border-gray-300 dark:border-gray-600" />
|
|
|
|
<div
|
|
class="flex flex-row flex-wrap gap-0.5 items-center justify-center max-w-md"
|
|
>
|
|
<a
|
|
href="/events/{$events_slct.event_id}"
|
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500"
|
|
>
|
|
<span class="fas fa-search m-1"></span>
|
|
Session Search
|
|
</a>
|
|
{#if $events_slct?.event_location_id}
|
|
<a
|
|
href="/events/{$events_slct.event_id}/location/{$events_slct.event_location_id}"
|
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500"
|
|
>
|
|
<span class="fas fa-map-marker m-1"></span>
|
|
View Selected Location
|
|
</a>
|
|
{/if}
|
|
{#if $events_slct?.event_session_id}
|
|
<a
|
|
href="/events/{$events_slct.event_id}/session/{$events_slct.event_session_id}"
|
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500"
|
|
>
|
|
<span class="fas fa-chalkboard-teacher m-1"></span>
|
|
View Selected Session
|
|
</a>
|
|
{/if}
|
|
</div>
|
|
</Drawer>
|
|
|
|
<Drawer
|
|
activateClickOutside={false}
|
|
class="bg-red-100 opacity-75 hover:opacity-95 transition-all duration-1000"
|
|
placement="bottom"
|
|
transitionType="fly"
|
|
transitionParams={{
|
|
y: 320,
|
|
duration: 200,
|
|
easing: sineIn
|
|
}}
|
|
bind:hidden={$events_loc.launcher.hide_drawer__debug}
|
|
id="sidebar2"
|
|
>
|
|
<div class="flex flex-row items-center justify-between">
|
|
<h2
|
|
class="text-center mb-4 text-base font-semibold text-gray-500 dark:text-gray-400"
|
|
>
|
|
Debug
|
|
</h2>
|
|
<button
|
|
type="button"
|
|
onclick={() => ($events_loc.launcher.hide_drawer__debug = true)}
|
|
class="mb-4 dark:text-white"
|
|
>
|
|
<span class="fas fa-times"></span>
|
|
<span class="hidden">Close Debug Drawer</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div>
|
|
<pre class="text-xs">
|
|
{JSON.stringify($events_loc.launcher, null, 2)}
|
|
</pre>
|
|
<hr />
|
|
<pre class="text-xs">
|
|
{JSON.stringify($ae_api, null, 2)}
|
|
</pre>
|
|
</div>
|
|
</Drawer>
|
|
|
|
<Modal
|
|
open={$events_sess.launcher?.modal__open_event_file_id}
|
|
autoclose={false}
|
|
placement="top-center"
|
|
class="
|
|
bg-gray-500/90 dark:bg-gray-800/90 text-gray-800 dark:text-gray-200
|
|
rounded-lg border-gray-200 dark:border-gray-700
|
|
divide-y divide-gray-200 dark:divide-gray-700 shadow-md
|
|
relative
|
|
flex flex-col items-center justify-center
|
|
{$events_loc.launcher.controller == 'remote' ? 'min-h-full' : ''}
|
|
min-w-full
|
|
"
|
|
bodyClass="p-0 space-y-0 overflow-y-auto flex flex-col gap-1 items-center justify-center"
|
|
headerClass={`fixed top-0 right-0 left-0 p-1 md:p-2 flex flex-row items-center ${$events_loc.launcher.controller == 'remote' ? 'hidden' : ''} bg-white dark:bg-gray-800 opacity-50 ${$events_loc.launcher.hide__modal_header_title ? 'justify-center' : 'justify-between'}`}
|
|
footerClass="text-center hidden"
|
|
>
|
|
{#snippet header()}
|
|
<h3
|
|
class:hidden={$events_loc.launcher.hide__modal_header_title}
|
|
class="text-lg font-semibold opacity-20 hover:opacity-100 transition-all"
|
|
>
|
|
{$events_sess.launcher?.modal__title ?? 'Digital Poster Display'}
|
|
</h3>
|
|
<button
|
|
type="button"
|
|
class="btn flex-row-reverse group transition-all justify-self-end"
|
|
onclick={() => {
|
|
$events_sess.launcher.modal__open_event_file_id = null;
|
|
}}
|
|
title="Close Modal"
|
|
>
|
|
<span class="fas fa-times my-1.5"></span>
|
|
<span class="hidden group-hover:inline"> Close</span>
|
|
</button>
|
|
{/snippet}
|
|
|
|
<button
|
|
type="button"
|
|
onclick={() => {
|
|
$events_sess.launcher.controller_cmd = `ae_close:event_file_modal`;
|
|
$events_sess.launcher.controller_trigger_send = true;
|
|
}}
|
|
class="
|
|
absolute top-0 right-12
|
|
m-1 p-1
|
|
btn btn-sm
|
|
preset-tonal-error preset-outlined-error hover:preset-filled-success-200-800
|
|
opacity-80 hover:opacity-100 active:opactiy-100
|
|
transition-all
|
|
"
|
|
class:hidden={$events_loc.launcher.controller != 'local_push' ||
|
|
$events_sess.launcher.ws_connect_status != 'connected'}
|
|
title="Close the remote device's display of the poster"
|
|
>
|
|
<span class="fas fa-times m-1"></span>
|
|
<span class="fas fa-tv"></span>
|
|
Close Remote Poster Display Only
|
|
</button>
|
|
|
|
{#if $events_sess.launcher.modal__open_event_file_id}
|
|
<img
|
|
src="{$ae_api.base_url}/v3/action/event_file/{$events_sess.launcher
|
|
.modal__open_event_file_id}/download?filename={$events_slct
|
|
.event_file_obj.filename}&key={$ae_api.account_id}"
|
|
alt="Poster"
|
|
class="min-h-28 min-w-md max-h-full max-w-full"
|
|
/>
|
|
{:else}
|
|
<div class="flex flex-row items-center justify-center p-4">
|
|
<span class="fas fa-info-circle mx-1"></span>
|
|
<span>No image selected</span>
|
|
</div>
|
|
{/if}
|
|
|
|
<button
|
|
type="button"
|
|
onclick={() => {
|
|
$events_sess.launcher.controller_cmd = `ae_close:event_file_modal`;
|
|
$events_sess.launcher.controller_trigger_send = true;
|
|
}}
|
|
class="
|
|
absolute bottom-0 left-12
|
|
m-1 p-1
|
|
btn btn-sm
|
|
preset-tonal-error preset-outlined-error hover:preset-filled-success-200-800
|
|
opacity-80 hover:opacity-100 active:opactiy-100
|
|
transition-all
|
|
"
|
|
class:hidden={$events_loc.launcher.controller != 'local_push' ||
|
|
$events_sess.launcher.ws_connect_status != 'connected'}
|
|
title="Close the remote device's display of the poster"
|
|
>
|
|
<span class="fas fa-times m-1"></span>
|
|
<span class="fas fa-tv"></span>
|
|
Close Remote Poster Display Only
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onclick={() => {
|
|
$events_sess.launcher.modal__title = '';
|
|
$events_sess.launcher.modal__open_event_file_id = null;
|
|
$events_sess.launcher.modal__event_file_obj = null;
|
|
}}
|
|
class="
|
|
absolute bottom-0 right-12
|
|
m-1 p-1
|
|
btn btn-sm
|
|
preset-tonal-success preset-outlined-success hover:preset-filled-success-200-800
|
|
opacity-80 hover:opacity-100 active:opactiy-100
|
|
transition-all
|
|
"
|
|
class:hidden={!$ae_loc.trusted_access &&
|
|
($events_loc.launcher.controller != 'local_push' ||
|
|
$events_sess.launcher.ws_connect_status != 'connected')}
|
|
title="Close this controller's local modal display of this poster"
|
|
>
|
|
<span class="fas fa-times m-1"></span>
|
|
<span class="fas fa-list"></span>
|
|
Close Poster on This Device
|
|
</button>
|
|
</Modal>
|
|
|
|
{#if $events_loc.launcher.controller_group_code && $events_loc.launcher.ws_connect}
|
|
<Element_websocket_v2
|
|
{log_lvl}
|
|
bind:ws_connect={$events_loc.launcher.ws_connect}
|
|
bind:ws_connect_status={$events_sess.launcher.ws_connect_status}
|
|
ws_server={$ae_api.fqdn}
|
|
bind:group_id={$events_loc.launcher.controller_group_code}
|
|
bind:client_id={$events_loc.launcher.controller_client_id}
|
|
bind:cmd={$events_sess.launcher.controller_cmd}
|
|
type={'cmd'}
|
|
bind:trigger_send={$events_sess.launcher.controller_trigger_send}
|
|
bind:trigger_connect={$events_sess.launcher.trigger__ws_connect}
|
|
bind:trigger_disconnect={$events_sess.launcher.trigger__ws_disconnect}
|
|
bind:hide__ws_element={$events_loc.launcher.hide__ws_element}
|
|
bind:hide__ws_form={$events_loc.launcher.hide__ws_form}
|
|
bind:hide__ws_messages={$events_loc.launcher.hide__ws_messages}
|
|
bind:hide__ws_commands={$events_loc.launcher.hide__ws_commands}
|
|
bind:ws_conn_status={trigger_handle_ws_conn}
|
|
bind:ws_recv_status={trigger_handle_ws_recv}
|
|
bind:ws_sent_status={trigger_handle_ws_sent}
|
|
/>
|
|
{/if}
|