305 lines
12 KiB
Svelte
305 lines
12 KiB
Svelte
<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';
|
||
|
||
// --- 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');
|
||
|
||
// 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');
|
||
|
||
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();
|
||
});
|
||
|
||
// 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' }
|
||
];
|
||
</script>
|
||
|
||
<section class="space-y-3 text-sm">
|
||
<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="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 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>
|
||
</div>
|
||
|
||
<!-- 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 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}
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 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 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>
|
||
</div>
|
||
|
||
<!-- 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 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 flex-1 font-mono text-xs disabled:opacity-40" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Launcher params ─────────────────────────────────────────────── -->
|
||
<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 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>
|
||
</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 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>
|
||
</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 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>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Output ──────────────────────────────────────────────────────── -->
|
||
<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="cursor-pointer text-xs select-none"
|
||
class:opacity-35={!params_only}>Params only</label>
|
||
</div>
|
||
|
||
<div class="flex items-stretch gap-1">
|
||
<input
|
||
type="text"
|
||
readonly
|
||
value={output}
|
||
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" />
|
||
<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>
|