feat(launcher): Oral/Poster Kiosk mode preset toggle + ae_mode WS command
Adds a two-button Session Mode Preset toggle in Display & App Modes cfg:
- 'Oral / Default' restores all menus/headers/iframe off
- 'Poster Kiosk' sets iframe=true + hides menu, header, footer
When WS is connected (local_push or remote controller), tapping a preset
sends ae_mode:poster / ae_mode:oral to all connected devices so an operator
can reconfigure the whole room from one device.
ae_mode:{poster|oral} command handler added to handle_ws_recv() in
+layout.svelte — receives and applies the same preset on remote devices.
This commit is contained in:
@@ -1,12 +1,55 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ae_loc } from '$lib/stores/ae_stores';
|
import { ae_loc } from '$lib/stores/ae_stores';
|
||||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||||
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
import Launcher_Cfg_Section from './launcher_cfg_section.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
on_expand?: () => void;
|
on_expand?: () => void;
|
||||||
}
|
}
|
||||||
let { on_expand }: Props = $props();
|
let { on_expand }: Props = $props();
|
||||||
|
|
||||||
|
// Poster Kiosk mode presets:
|
||||||
|
// iframe=true hides global site chrome
|
||||||
|
// hide__launcher_menu/header/footer removes all launcher panels
|
||||||
|
// Oral/Default restores everything.
|
||||||
|
// WHY: A single tap lets event staff reconfigure a device (or all WS-connected
|
||||||
|
// remote devices) for a session type without touching individual toggles.
|
||||||
|
const POSTER_PRESET = {
|
||||||
|
iframe: true,
|
||||||
|
hide__launcher_menu: true,
|
||||||
|
hide__launcher_header: true,
|
||||||
|
hide__launcher_footer: true
|
||||||
|
};
|
||||||
|
const ORAL_PRESET = {
|
||||||
|
iframe: false,
|
||||||
|
hide__launcher_menu: false,
|
||||||
|
hide__launcher_header: false,
|
||||||
|
hide__launcher_footer: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Detect current mode: if both iframe AND hide_menu are on, we're in poster mode.
|
||||||
|
// Individual overrides are still possible via the checkboxes below.
|
||||||
|
let is_poster_mode = $derived(
|
||||||
|
$ae_loc.iframe === true && $events_loc.launcher.hide__launcher_menu === true
|
||||||
|
);
|
||||||
|
|
||||||
|
function apply_mode(mode: 'poster' | 'oral') {
|
||||||
|
const preset = mode === 'poster' ? POSTER_PRESET : ORAL_PRESET;
|
||||||
|
$ae_loc.iframe = preset.iframe;
|
||||||
|
$events_loc.launcher.hide__launcher_menu = preset.hide__launcher_menu;
|
||||||
|
$events_loc.launcher.hide__launcher_header = preset.hide__launcher_header;
|
||||||
|
$events_loc.launcher.hide__launcher_footer = preset.hide__launcher_footer;
|
||||||
|
|
||||||
|
// Push to WS-connected remote devices when we're acting as a controller.
|
||||||
|
// Only send when connected so the UI button doesn't silently no-op.
|
||||||
|
if (
|
||||||
|
$events_loc.launcher.ws_connect &&
|
||||||
|
($events_loc.launcher.controller === 'local_push' || $events_loc.launcher.controller === 'remote')
|
||||||
|
) {
|
||||||
|
$events_sess.launcher.controller_cmd = `ae_mode:${mode}`;
|
||||||
|
$events_sess.launcher.controller_trigger_send = 'trigger';
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Launcher_Cfg_Section
|
<Launcher_Cfg_Section
|
||||||
@@ -18,6 +61,38 @@
|
|||||||
>
|
>
|
||||||
<!-- Content omitted for brevity, preserved in file -->
|
<!-- Content omitted for brevity, preserved in file -->
|
||||||
<div class="col-span-full flex flex-col gap-3">
|
<div class="col-span-full flex flex-col gap-3">
|
||||||
|
<!-- 0. Oral / Poster Kiosk Mode Preset Toggle -->
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<p class="text-[9px] font-bold uppercase opacity-50 ml-1">Session Mode Preset</p>
|
||||||
|
<div class="grid grid-cols-2 gap-1 bg-surface-500/5 p-1 rounded-lg">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onclick={() => apply_mode('oral')}
|
||||||
|
class="btn btn-xs font-bold text-[10px]"
|
||||||
|
class:preset-filled-secondary={!is_poster_mode}
|
||||||
|
class:preset-tonal-surface={is_poster_mode}
|
||||||
|
title="Standard oral/presentation layout — menus and headers visible"
|
||||||
|
>
|
||||||
|
<span class="fas fa-chalkboard-teacher mr-1 opacity-70"></span>
|
||||||
|
Oral / Default
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onclick={() => apply_mode('poster')}
|
||||||
|
class="btn btn-xs font-bold text-[10px]"
|
||||||
|
class:preset-filled-primary={is_poster_mode}
|
||||||
|
class:preset-tonal-surface={!is_poster_mode}
|
||||||
|
title="Digital Poster kiosk — hides site chrome, menu, header & footer"
|
||||||
|
>
|
||||||
|
<span class="fas fa-id-badge mr-1 opacity-70"></span>
|
||||||
|
Poster Kiosk
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{#if $events_loc.launcher.ws_connect && ($events_loc.launcher.controller === 'local_push' || $events_loc.launcher.controller === 'remote')}
|
||||||
|
<p class="text-[8px] opacity-40 italic ml-1">Applies to all connected WS devices</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 1. App Mode Selection -->
|
<!-- 1. App Mode Selection -->
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<p class="text-[9px] font-bold uppercase opacity-50 ml-1"
|
<p class="text-[9px] font-bold uppercase opacity-50 ml-1"
|
||||||
|
|||||||
@@ -415,6 +415,21 @@
|
|||||||
else if (zoom_target === 'zoom') modal_zoom_fit = false;
|
else if (zoom_target === 'zoom') modal_zoom_fit = false;
|
||||||
} else if (cmd.startsWith('ae_refresh:')) {
|
} else if (cmd.startsWith('ae_refresh:')) {
|
||||||
if (cmd.split(':')[1] == 'now') location.reload();
|
if (cmd.split(':')[1] == 'now') location.reload();
|
||||||
|
} else if (cmd.startsWith('ae_mode:')) {
|
||||||
|
// WHY: Allows a controller to remotely push a display mode preset
|
||||||
|
// (e.g. switch all poster kiosks into kiosk mode without touching each device).
|
||||||
|
const mode_target = cmd.split(':')[1];
|
||||||
|
if (mode_target === 'poster') {
|
||||||
|
$ae_loc.iframe = true;
|
||||||
|
$events_loc.launcher.hide__launcher_menu = true;
|
||||||
|
$events_loc.launcher.hide__launcher_header = true;
|
||||||
|
$events_loc.launcher.hide__launcher_footer = true;
|
||||||
|
} else if (mode_target === 'oral') {
|
||||||
|
$ae_loc.iframe = false;
|
||||||
|
$events_loc.launcher.hide__launcher_menu = false;
|
||||||
|
$events_loc.launcher.hide__launcher_header = false;
|
||||||
|
$events_loc.launcher.hide__launcher_footer = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user