Files
OSIT-AE-App-Svelte/src/routes/events/[event_id]/(launcher)/launcher_menu.svelte
Scott Idem 27c775d816 feat(stores): promote launcher_loc to Svelte 5 PersistedState
Creates ae_events_stores__launcher.svelte.ts with PersistedState keyed
'ae_launcher_loc', following the same pattern as badges, leads, and
pres_mgmt. All 28 launcher component files migrated from
$events_loc.launcher.* to launcher_loc.current.*.

events_local_data_struct in ae_events_stores.ts now carries no sub-module
objects — all four sub-modules (badges, launcher, leads, pres_mgmt) are
authoritative in their own stores. Session state (events_sess.launcher)
is unchanged.

svelte-check: 0 errors, 0 warnings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 16:00:40 -04:00

256 lines
9.1 KiB
Svelte

<script lang="ts">
/**
* launcher_menu.svelte — Aether Launcher: Sidebar Menu Container
*
* PURPOSE:
* The main sidebar panel for the Aether Events Launcher. Composes all menu
* sub-components into a single vertical column and passes data down from the
* parent layout. This is intentionally a thin coordinator — business logic lives
* in the individual sub-components and the layout's liveQuery / effect layer.
*
* STRUCTURE (top to bottom):
* 1. Event-level files (lq__event_event_file_obj_li)
* Files attached directly to the event (e.g. a shared opening slide deck).
* Shown regardless of which room/session is selected.
*
* 2. Location selector (Menu_location_list_menu — edit mode only)
* Dropdown that lets operators switch the active room. Triggers a session
* list reload and navigates the URL to /launcher/{location_id}.
*
* 3. Location-level files (lq__location_event_file_obj_li)
* Files attached to the selected room — e.g. A/V setup guides, room schedules.
* Hidden until a room is selected.
*
* 4. Session list (Menu_session_list_menu)
* Compact button list of all sessions in the selected room. Operators click
* to switch the active session; hover pre-loads after a delay timer.
*
* 5. Launcher controls (Menu_launcher_controls)
* Bottom bar for accessibility and visibility settings: font size cycler,
* light/dark toggle, and (edit mode only) show/hide draft files/sessions.
*
* DATA FLOW:
* All liveQuery stores (lq__*) are passed in from +layout.svelte and originate
* from Dexie IndexedDB — never fetched directly here. Selection state is
* coordinated via $events_slct / $events_loc stores.
*/
interface Props {
lq__event_obj: any;
lq__event_event_file_obj_li: any;
lq__location_event_file_obj_li: any;
slct__event_file_id?: string | null;
lq__event_location_obj_li: any;
lq__event_location_obj?: any;
slct__event_location_id?: string | null;
loading__session_li_status?: null | boolean | string;
lq__event_session_obj_li: any;
loading__session_id_status?: null | boolean | string;
lq__event_session_obj?: any;
slct__event_session_id?: string | null;
trigger_reload__event_obj_id?: boolean | null | string;
trigger_reload__event_session_obj_id?: boolean | null | string;
trigger_reload__event_session_obj_li?: boolean;
trigger_reload__event_location_obj_id?: boolean | null | string;
trigger_reload__event_location_obj_li?: boolean;
log_lvl?: number;
}
let {
lq__event_obj,
lq__event_event_file_obj_li,
lq__location_event_file_obj_li,
slct__event_file_id = $bindable(null),
lq__event_location_obj_li,
lq__event_location_obj,
slct__event_location_id = $bindable(null),
loading__session_li_status = $bindable(null),
lq__event_session_obj_li,
loading__session_id_status = $bindable(null),
lq__event_session_obj,
slct__event_session_id = $bindable(null),
trigger_reload__event_obj_id = $bindable(false),
trigger_reload__event_session_obj_id = $bindable(false),
trigger_reload__event_session_obj_li = $bindable(false),
trigger_reload__event_location_obj_id = $bindable(false),
trigger_reload__event_location_obj_li = $bindable(false),
log_lvl = $bindable(0)
}: Props = $props();
// *** Import Svelte specific
// import { goto } from '$app/navigation';
// *** Import other supporting libraries
// import { liveQuery } from "dexie";
// *** 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 Element_data_store from '$lib/element_data_store.svelte';
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
// import { db_events } from "$lib/ae_events/db_events";
import {
events_sess,
events_slct,
events_trigger
} from '$lib/stores/ae_events_stores';
import { launcher_loc } from '$lib/stores/ae_events_stores__launcher.svelte';
import { events_func } from '$lib/ae_events/ae_events_functions';
import Event_launcher_file_cont from './launcher_file_cont.svelte';
import Menu_location_list_menu from './menu_location_list.svelte';
import Menu_session_list_menu from './menu_session_list.svelte';
import Menu_launcher_controls from './menu_launcher_controls.svelte';
// *** Functions and Logic
$events_trigger = null;
let qry__enabled = 'enabled';
let qry__hidden = 'not_hidden';
if ($ae_loc.administrator_access) {
qry__enabled = 'all';
qry__hidden = 'all';
} else if ($ae_loc.trusted_access) {
qry__enabled = 'enabled';
qry__hidden = 'all';
} else {
qry__enabled = 'enabled';
qry__hidden = 'not_hidden';
}
let ae_promises: key_val = $state({
get_li__event_file: null
});
</script>
<div
class="
event_launcher_menu
h-full
w-full max-w-full
flex flex-col flex-wrap items-center justify-start gap-1
shrink
">
<!-- overflow-x-clip -->
{#if $lq__event_event_file_obj_li}
<div class="flex w-full flex-col gap-0.5 overflow-y-auto">
<!-- <div class="text-xs text-neutral-800/80">
<strong>
Event Files:
{#if $ae_loc.administrator_access}
({$lq__event_event_file_obj_li?.length}&times;)
{/if}
</strong>
</div> -->
{#each $lq__event_event_file_obj_li as event_file_obj, index (event_file_obj.event_file_id)}
<Event_launcher_file_cont
event_file_id={event_file_obj.event_file_id}
{event_file_obj}
hide_launch_icon={true}
hide_meta={true}
hide_created_on={true}
hide_os={true}
hide_size={true}
show_internal_purpose_files={launcher_loc.current.show_content__internal_files}
show_bak_download={$ae_loc.trusted_access &&
$ae_loc.edit_mode}
btn_size={'btn-sm'}
btn_text_align={'text-center'}
text_size={'text-xs'}
text_size_md={'text-xs'}
session_type={event_file_obj?.event_session_type_code ??
'oral'}
open_method={event_file_obj?.event_session_type_code ==
'poster'
? 'modal'
: null}
modal_title={$lq__event_session_obj?.name}
bind:modal__title={$events_sess.launcher.modal__title}
bind:modal__open_event_file_id={
$events_sess.launcher.modal__open_event_file_id
}
bind:modal__event_file_obj={
$events_sess.launcher.modal__event_file_obj
} />
{/each}
</div>
{/if}
{#if $ae_loc.edit_mode}
<Menu_location_list_menu
{lq__event_location_obj_li}
slct_event_location_id={$events_slct.event_location_id}
bind:loading__session_li_status />
{/if}
{#if $lq__location_event_file_obj_li}
<div class="flex w-full flex-col gap-0.5">
{#each $lq__location_event_file_obj_li as event_file_obj, index (event_file_obj.event_file_id)}
<Event_launcher_file_cont
event_file_id={event_file_obj.event_file_id}
{event_file_obj}
hide_launch_icon={true}
hide_meta={true}
hide_created_on={true}
hide_os={true}
hide_size={true}
show_internal_purpose_files={launcher_loc.current.show_content__internal_files}
show_bak_download={$ae_loc.trusted_access &&
$ae_loc.edit_mode}
btn_size={'btn-sm'}
btn_text_align={'text-center'}
text_size={'text-xs'}
text_size_md={'text-xs'}
session_type={event_file_obj?.event_session_type_code ??
'oral'}
open_method={event_file_obj?.event_session_type_code ==
'poster'
? 'modal'
: null}
modal_title={$lq__event_session_obj?.name}
bind:modal__title={$events_sess.launcher.modal__title}
bind:modal__open_event_file_id={
$events_sess.launcher.modal__open_event_file_id
}
bind:modal__event_file_obj={
$events_sess.launcher.modal__event_file_obj
} />
{/each}
</div>
{/if}
{#if $lq__event_session_obj_li}
<Menu_session_list_menu
bind:slct__event_session_id
bind:loading__session_id_status
{lq__event_session_obj_li}
bind:trigger_reload__event_session_obj_id />
{/if}
<div class="mt-auto w-full">
<Menu_launcher_controls />
</div>
</div>