Files
OSIT-AE-App-Svelte/src/lib/app_components/e_app_url_builder.svelte
2026-03-24 13:27:40 -04:00

305 lines
12 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>