feat(launcher): add launcher_menu/header/footer URL params to URL builder; strip after apply
This commit is contained in:
@@ -1,45 +1,62 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* e_app_url_builder.svelte
|
||||
* Core URL Param Builder — lets admins construct and copy shareable URLs
|
||||
* with any combination of the core global URL params applied.
|
||||
* URL Param Builder — lets admins construct and copy shareable URLs
|
||||
* with any combination of the supported URL params applied.
|
||||
*
|
||||
* Core params:
|
||||
* ?iframe=true|false — hide sys/debug menus (kiosk mode)
|
||||
* ?theme=<name> — set theme name on load (stripped from URL after apply)
|
||||
* ?theme_mode=light|dark — set light/dark mode on load (stripped from URL after apply)
|
||||
* ?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_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_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);
|
||||
|
||||
// Remove all core params first so we start clean each time
|
||||
// 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_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();
|
||||
});
|
||||
@@ -83,19 +100,21 @@
|
||||
];
|
||||
</script>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-xs font-semibold uppercase tracking-widest text-surface-500 flex items-center gap-1">
|
||||
<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">
|
||||
<Link size="0.9em" /> URL Param Builder
|
||||
</h2>
|
||||
|
||||
<!-- Param toggles -->
|
||||
<div class="space-y-2">
|
||||
<!-- ── Core params ─────────────────────────────────────────────────── -->
|
||||
<div class="space-y-1.5">
|
||||
<p class="text-[9px] font-bold uppercase tracking-widest opacity-40 ml-0.5">Core</p>
|
||||
|
||||
<!-- iframe -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_iframe" type="checkbox" class="checkbox checkbox-sm" bind:checked={use_iframe} />
|
||||
<label for="ubld_iframe" class="w-20 text-xs font-mono">iframe</label>
|
||||
<select bind:value={val_iframe} disabled={!use_iframe} class="select select-sm text-xs flex-1">
|
||||
<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">
|
||||
<option value="true">true</option>
|
||||
<option value="false">false</option>
|
||||
</select>
|
||||
@@ -103,9 +122,9 @@
|
||||
|
||||
<!-- theme -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_theme" type="checkbox" class="checkbox checkbox-sm" bind:checked={use_theme} />
|
||||
<label for="ubld_theme" class="w-20 text-xs font-mono">theme</label>
|
||||
<select bind:value={val_theme} disabled={!use_theme} class="select select-sm text-xs flex-1">
|
||||
<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">
|
||||
{#each theme_options as opt}
|
||||
<option value={opt.value}>{opt.label}</option>
|
||||
{/each}
|
||||
@@ -114,9 +133,9 @@
|
||||
|
||||
<!-- theme_mode -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_theme_mode" type="checkbox" class="checkbox checkbox-sm" bind:checked={use_theme_mode} />
|
||||
<label for="ubld_theme_mode" class="w-20 text-xs font-mono">theme_mode</label>
|
||||
<select bind:value={val_theme_mode} disabled={!use_theme_mode} class="select select-sm text-xs flex-1">
|
||||
<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">
|
||||
<option value="light">light</option>
|
||||
<option value="dark">dark</option>
|
||||
</select>
|
||||
@@ -124,45 +143,81 @@
|
||||
|
||||
<!-- key -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_key" type="checkbox" class="checkbox checkbox-sm" bind:checked={use_key} />
|
||||
<label for="ubld_key" class="w-20 text-xs font-mono">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 text-xs font-mono cursor-pointer 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"
|
||||
class="input input-sm text-xs font-mono flex-1 disabled:opacity-40"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- params_only toggle + output -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_params_only" type="checkbox" class="checkbox checkbox-sm" bind:checked={params_only} />
|
||||
<label for="ubld_params_only" class="text-xs text-surface-500">Params only</label>
|
||||
<!-- ── 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>
|
||||
|
||||
<!-- 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">
|
||||
<option value="hide">hide</option>
|
||||
<option value="show">show</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 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">
|
||||
<option value="hide">hide</option>
|
||||
<option value="show">show</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 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">
|
||||
<option value="hide">hide</option>
|
||||
<option value="show">show</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Output URL -->
|
||||
<div class="flex gap-1 items-stretch">
|
||||
<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"
|
||||
onclick={(e) => (e.target as HTMLInputElement).select()}
|
||||
title="Click to select all"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-sm {copied ? 'preset-filled-success' : 'preset-tonal-primary'} shrink-0 transition-all"
|
||||
onclick={copy_url}
|
||||
title="Copy URL to clipboard"
|
||||
>
|
||||
{#if copied}
|
||||
<Check size="1em" />
|
||||
{:else}
|
||||
<Copy size="1em" />
|
||||
{/if}
|
||||
</button>
|
||||
<!-- ── Output ──────────────────────────────────────────────────────── -->
|
||||
<div class="border-t border-surface-500/20 pt-2.5 space-y-1.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>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1 items-stretch">
|
||||
<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"
|
||||
onclick={(e) => (e.target as HTMLInputElement).select()}
|
||||
title="Click to select all"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-sm {copied ? 'preset-filled-success' : 'preset-tonal-primary'} shrink-0 transition-all"
|
||||
onclick={copy_url}
|
||||
title="Copy URL to clipboard"
|
||||
>
|
||||
{#if copied}
|
||||
<Check size="1em" />
|
||||
{:else}
|
||||
<Copy size="1em" />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -147,6 +147,22 @@
|
||||
if (param_launcher_footer === 'hide') $events_loc.launcher.hide__launcher_footer = true;
|
||||
else if (param_launcher_footer === 'show') $events_loc.launcher.hide__launcher_footer = false;
|
||||
});
|
||||
|
||||
// Strip launcher display params from the URL after applying them — same pattern
|
||||
// as root layout does for ?theme / ?theme_mode. These are "one-shot" apply params;
|
||||
// keeping them in the URL is misleading because toggling the CFG panel would desync.
|
||||
// ?iframe is intentionally left in the URL because it is a persistent mode flag.
|
||||
if (param_launcher_menu || param_launcher_header || param_launcher_footer) {
|
||||
const clean_url = new URL(data.url.href);
|
||||
clean_url.searchParams.delete('launcher_menu');
|
||||
clean_url.searchParams.delete('launcher_header');
|
||||
clean_url.searchParams.delete('launcher_footer');
|
||||
goto(clean_url.pathname + clean_url.search + clean_url.hash, {
|
||||
replaceState: true,
|
||||
noScroll: true,
|
||||
keepFocus: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// String-Only ID Vision: Sync the device ID from the native environment
|
||||
|
||||
Reference in New Issue
Block a user