feat: add hide_ae_menu toggle to Jitsi URL builder advanced panel
Adds ae_hide_menu=true query param option to suppress the AE navigation chrome when embedding the Jitsi video conference page in Novi or other host pages that provide their own navigation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,67 +1,78 @@
|
||||
<script lang="ts">
|
||||
// ae_idaa_comp__jitsi_url_builder.svelte
|
||||
// Builds and previews Jitsi iframe URLs for testing and Novi page configuration.
|
||||
// Only shown to trusted_access users — not for general IDAA members.
|
||||
// ae_idaa_comp__jitsi_url_builder.svelte
|
||||
// Builds and previews Jitsi iframe URLs for testing and Novi page configuration.
|
||||
// Only shown to trusted_access users — not for general IDAA members.
|
||||
|
||||
// --- Environment presets ---
|
||||
const BASE_URL_OPTIONS = [
|
||||
{ label: 'Production', value: 'https://sk-idaa.oneskyit.com/idaa/video_conferences' },
|
||||
{ label: 'Dev / Staging', value: 'https://dev-idaa.oneskyit.com/idaa/video_conferences' },
|
||||
{ label: 'Local', value: 'http://idaa.localhost:5173/idaa/video_conferences' },
|
||||
{ label: 'Custom…', value: 'custom' }
|
||||
];
|
||||
// --- Environment presets ---
|
||||
const BASE_URL_OPTIONS = [
|
||||
{
|
||||
label: 'Production',
|
||||
value: 'https://sk-idaa.oneskyit.com/idaa/video_conferences'
|
||||
},
|
||||
{
|
||||
label: 'Dev / Staging',
|
||||
value: 'https://dev-idaa.oneskyit.com/idaa/video_conferences'
|
||||
},
|
||||
{
|
||||
label: 'Local',
|
||||
value: 'http://idaa.localhost:5173/idaa/video_conferences'
|
||||
},
|
||||
{ label: 'Custom…', value: 'custom' }
|
||||
];
|
||||
|
||||
// --- State ---
|
||||
let base_url_preset = $state(BASE_URL_OPTIONS[1].value); // dev by default
|
||||
let base_url_custom = $state('');
|
||||
let room_name = $state('IDAA-Test-Meeting');
|
||||
let site_key = $state('restricted-access');
|
||||
let uuid = $state('');
|
||||
let is_moderator = $state(false);
|
||||
let domain = $state('jitsi.dgrzone.com');
|
||||
let start_muted = $state(true);
|
||||
let start_hidden = $state(false);
|
||||
let disable_incoming_msg = $state(true);
|
||||
let disable_participant_joined = $state(false);
|
||||
let disable_participant_left = $state(false);
|
||||
let disable_reaction = $state(true);
|
||||
let disable_raise_hand = $state(true);
|
||||
// --- State ---
|
||||
let base_url_preset = $state(BASE_URL_OPTIONS[1].value); // dev by default
|
||||
let base_url_custom = $state('');
|
||||
let room_name = $state('IDAA-Test-Meeting');
|
||||
let site_key = $state('restricted-access');
|
||||
let uuid = $state('');
|
||||
let is_moderator = $state(false);
|
||||
let domain = $state('jitsi.dgrzone.com');
|
||||
let start_muted = $state(true);
|
||||
let start_hidden = $state(false);
|
||||
let disable_incoming_msg = $state(true);
|
||||
let disable_participant_joined = $state(false);
|
||||
let disable_participant_left = $state(false);
|
||||
let disable_reaction = $state(true);
|
||||
let disable_raise_hand = $state(true);
|
||||
|
||||
// Toggle to hide AE system menu when embedding in other pages
|
||||
let hide_ae_menu = $state(false);
|
||||
// Toggle to hide AE system menu when embedding in other pages
|
||||
let hide_ae_menu = $state(false);
|
||||
|
||||
let show_advanced = $state(false);
|
||||
let show_sound = $state(false);
|
||||
let output_mode = $state<'url' | 'iframe'>('url');
|
||||
let copied = $state(false);
|
||||
let show_advanced = $state(false);
|
||||
let show_sound = $state(false);
|
||||
let output_mode = $state<'url' | 'iframe'>('url');
|
||||
let copied = $state(false);
|
||||
|
||||
// --- Derived URL ---
|
||||
let effective_base = $derived(
|
||||
base_url_preset === 'custom' ? base_url_custom.trim() : base_url_preset
|
||||
);
|
||||
// --- Derived URL ---
|
||||
let effective_base = $derived(
|
||||
base_url_preset === 'custom' ? base_url_custom.trim() : base_url_preset
|
||||
);
|
||||
|
||||
let built_url = $derived.by(() => {
|
||||
if (!effective_base || !room_name.trim()) return '';
|
||||
const p = new URLSearchParams();
|
||||
if (uuid.trim()) p.set('uuid', uuid.trim());
|
||||
p.set('iframe', 'true');
|
||||
p.set('key', site_key.trim() || 'restricted-access');
|
||||
p.set('room', room_name.trim());
|
||||
if (is_moderator) p.set('moderator', 'true');
|
||||
if (domain.trim() && domain.trim() !== 'jitsi.dgrzone.com') p.set('domain', domain.trim());
|
||||
if (start_muted) p.set('start_muted', 'true');
|
||||
if (start_hidden) p.set('start_hidden', 'true');
|
||||
if (disable_incoming_msg) p.set('incoming_msg_sound', 'true');
|
||||
if (disable_participant_joined) p.set('participant_joined_sound', 'true');
|
||||
if (disable_participant_left) p.set('participant_left_sound', 'true');
|
||||
if (disable_reaction) p.set('reaction_sound', 'true');
|
||||
if (disable_raise_hand) p.set('raise_hand_sound', 'true');
|
||||
// AE embed option: hide AE system menu when embedding in other pages
|
||||
if (hide_ae_menu) p.set('ae_hide_menu', 'true');
|
||||
return `${effective_base}?${p.toString()}`;
|
||||
});
|
||||
let built_url = $derived.by(() => {
|
||||
if (!effective_base || !room_name.trim()) return '';
|
||||
const p = new URLSearchParams();
|
||||
if (uuid.trim()) p.set('uuid', uuid.trim());
|
||||
p.set('iframe', 'true');
|
||||
p.set('key', site_key.trim() || 'restricted-access');
|
||||
p.set('room', room_name.trim());
|
||||
if (is_moderator) p.set('moderator', 'true');
|
||||
if (domain.trim() && domain.trim() !== 'jitsi.dgrzone.com')
|
||||
p.set('domain', domain.trim());
|
||||
if (start_muted) p.set('start_muted', 'true');
|
||||
if (start_hidden) p.set('start_hidden', 'true');
|
||||
if (disable_incoming_msg) p.set('incoming_msg_sound', 'true');
|
||||
if (disable_participant_joined)
|
||||
p.set('participant_joined_sound', 'true');
|
||||
if (disable_participant_left) p.set('participant_left_sound', 'true');
|
||||
if (disable_reaction) p.set('reaction_sound', 'true');
|
||||
if (disable_raise_hand) p.set('raise_hand_sound', 'true');
|
||||
// AE embed option: hide AE system menu when embedding in other pages
|
||||
if (hide_ae_menu) p.set('ae_hide_menu', 'true');
|
||||
return `${effective_base}?${p.toString()}`;
|
||||
});
|
||||
|
||||
let iframe_snippet = $derived(`<p>
|
||||
let iframe_snippet = $derived(`<p>
|
||||
<iframe
|
||||
width="100%"
|
||||
height="950"
|
||||
@@ -74,229 +85,313 @@
|
||||
></iframe>
|
||||
</p>`);
|
||||
|
||||
let output = $derived(output_mode === 'iframe' ? iframe_snippet : built_url);
|
||||
let output = $derived(
|
||||
output_mode === 'iframe' ? iframe_snippet : built_url
|
||||
);
|
||||
|
||||
function copy_output() {
|
||||
if (!output) return;
|
||||
navigator.clipboard.writeText(output).then(() => {
|
||||
copied = true;
|
||||
setTimeout(() => (copied = false), 2000);
|
||||
});
|
||||
}
|
||||
function copy_output() {
|
||||
if (!output) return;
|
||||
navigator.clipboard.writeText(output).then(() => {
|
||||
copied = true;
|
||||
setTimeout(() => (copied = false), 2000);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-3 text-sm">
|
||||
<!-- Environment + Room (always visible) -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||
<div>
|
||||
<label
|
||||
for="jub_base_url"
|
||||
class="block text-xs uppercase tracking-wide opacity-40 mb-1"
|
||||
>
|
||||
Environment
|
||||
</label>
|
||||
<select
|
||||
id="jub_base_url"
|
||||
bind:value={base_url_preset}
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm"
|
||||
>
|
||||
{#each BASE_URL_OPTIONS as opt}
|
||||
<option value={opt.value}>{opt.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{#if base_url_preset === 'custom'}
|
||||
<input
|
||||
type="url"
|
||||
bind:value={base_url_custom}
|
||||
placeholder="https://…/idaa/video_conferences"
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono mt-1"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="jub_room"
|
||||
class="block text-xs uppercase tracking-wide opacity-40 mb-1"
|
||||
>
|
||||
Room Name <span class="text-error-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="jub_room"
|
||||
bind:value={room_name}
|
||||
placeholder="IDAA-Meeting-Room"
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Environment + Room (always visible) -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||
<div>
|
||||
<label for="jub_base_url" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
|
||||
Environment
|
||||
</label>
|
||||
<select
|
||||
id="jub_base_url"
|
||||
bind:value={base_url_preset}
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm"
|
||||
>
|
||||
{#each BASE_URL_OPTIONS as opt}
|
||||
<option value={opt.value}>{opt.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{#if base_url_preset === 'custom'}
|
||||
<input
|
||||
type="url"
|
||||
bind:value={base_url_custom}
|
||||
placeholder="https://…/idaa/video_conferences"
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono mt-1"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<label for="jub_room" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
|
||||
Room Name <span class="text-error-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="jub_room"
|
||||
bind:value={room_name}
|
||||
placeholder="IDAA-Meeting-Room"
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- UUID + Key -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||
<div>
|
||||
<label
|
||||
for="jub_uuid"
|
||||
class="block text-xs uppercase tracking-wide opacity-40 mb-1"
|
||||
>
|
||||
Novi UUID <span class="opacity-60">(blank = guest)</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="jub_uuid"
|
||||
bind:value={uuid}
|
||||
placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="jub_key"
|
||||
class="block text-xs uppercase tracking-wide opacity-40 mb-1"
|
||||
>
|
||||
Site Key
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="jub_key"
|
||||
bind:value={site_key}
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UUID + Key -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||
<div>
|
||||
<label for="jub_uuid" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
|
||||
Novi UUID <span class="opacity-60">(blank = guest)</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="jub_uuid"
|
||||
bind:value={uuid}
|
||||
placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="jub_key" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
|
||||
Site Key
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="jub_key"
|
||||
bind:value={site_key}
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Moderator toggle -->
|
||||
<label class="flex items-center gap-2 cursor-pointer w-fit">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={is_moderator}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-sm">Moderator</span>
|
||||
<span class="text-xs opacity-40"
|
||||
>(requests JWT, enables lobby + activity logging)</span
|
||||
>
|
||||
</label>
|
||||
|
||||
<!-- Moderator toggle -->
|
||||
<label class="flex items-center gap-2 cursor-pointer w-fit">
|
||||
<input type="checkbox" bind:checked={is_moderator} class="checkbox checkbox-sm" />
|
||||
<span class="text-sm">Moderator</span>
|
||||
<span class="text-xs opacity-40">(requests JWT, enables lobby + activity logging)</span>
|
||||
</label>
|
||||
<!-- Advanced toggle -->
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (show_advanced = !show_advanced)}
|
||||
class="flex items-center gap-1 text-xs opacity-60 hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<span
|
||||
class="fas {show_advanced ? 'fa-chevron-up' : 'fa-chevron-down'}"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
{show_advanced ? 'Hide' : 'Show'} advanced options
|
||||
</button>
|
||||
|
||||
<!-- Advanced toggle -->
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (show_advanced = !show_advanced)}
|
||||
class="flex items-center gap-1 text-xs opacity-60 hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<span class="fas {show_advanced ? 'fa-chevron-up' : 'fa-chevron-down'}" aria-hidden="true"></span>
|
||||
{show_advanced ? 'Hide' : 'Show'} advanced options
|
||||
</button>
|
||||
{#if show_advanced}
|
||||
<div
|
||||
class="border border-surface-200-800 rounded-xl p-3 space-y-3 bg-surface-100-900"
|
||||
>
|
||||
<!-- Domain -->
|
||||
<div>
|
||||
<label
|
||||
for="jub_domain"
|
||||
class="block text-xs uppercase tracking-wide opacity-40 mb-1"
|
||||
>
|
||||
Jitsi Domain
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="jub_domain"
|
||||
bind:value={domain}
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if show_advanced}
|
||||
<div class="border border-surface-200-800 rounded-xl p-3 space-y-3 bg-surface-100-900">
|
||||
<!-- Domain -->
|
||||
<div>
|
||||
<label for="jub_domain" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
|
||||
Jitsi Domain
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="jub_domain"
|
||||
bind:value={domain}
|
||||
class="border border-surface-200-800 rounded px-2 py-1 w-full bg-surface-50-950 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
<!-- AE menu — hides the AE nav chrome; useful when embedding in Novi or pages with their own navigation -->
|
||||
<label class="flex items-center gap-2 cursor-pointer w-fit">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={hide_ae_menu}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-xs"
|
||||
>Hide AE system menu <span class="opacity-40"
|
||||
>(ae_hide_menu=true)</span
|
||||
></span
|
||||
>
|
||||
</label>
|
||||
|
||||
<!-- AE menu toggle -->
|
||||
<div>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={hide_ae_menu} class="checkbox checkbox-sm" />
|
||||
<span class="text-xs">Hide AE system menu (for embed)</span>
|
||||
</label>
|
||||
</div>
|
||||
<!-- Start options -->
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={start_muted}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-xs">Start muted</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={start_hidden}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-xs">Start hidden (video off)</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Start options -->
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={start_muted} class="checkbox checkbox-sm" />
|
||||
<span class="text-xs">Start muted</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={start_hidden} class="checkbox checkbox-sm" />
|
||||
<span class="text-xs">Start hidden (video off)</span>
|
||||
</label>
|
||||
</div>
|
||||
<!-- Sound settings -->
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (show_sound = !show_sound)}
|
||||
class="flex items-center gap-1 text-xs opacity-60 hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<span
|
||||
class="fas {show_sound
|
||||
? 'fa-chevron-up'
|
||||
: 'fa-chevron-down'}"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
{show_sound ? 'Hide' : 'Show'} sound settings
|
||||
</button>
|
||||
{#if show_sound}
|
||||
<div class="flex flex-wrap gap-4 mt-2">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={disable_incoming_msg}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-xs"
|
||||
>Disable incoming msg sound</span
|
||||
>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={disable_participant_joined}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-xs"
|
||||
>Disable participant joined sound</span
|
||||
>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={disable_participant_left}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-xs"
|
||||
>Disable participant left sound</span
|
||||
>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={disable_reaction}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-xs">Disable reaction sound</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={disable_raise_hand}
|
||||
class="checkbox checkbox-sm"
|
||||
/>
|
||||
<span class="text-xs">Disable raise hand sound</span
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Sound settings -->
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (show_sound = !show_sound)}
|
||||
class="flex items-center gap-1 text-xs opacity-60 hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<span class="fas {show_sound ? 'fa-chevron-up' : 'fa-chevron-down'}" aria-hidden="true"></span>
|
||||
{show_sound ? 'Hide' : 'Show'} sound settings
|
||||
</button>
|
||||
{#if show_sound}
|
||||
<div class="flex flex-wrap gap-4 mt-2">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={disable_incoming_msg} class="checkbox checkbox-sm" />
|
||||
<span class="text-xs">Disable incoming msg sound</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={disable_participant_joined} class="checkbox checkbox-sm" />
|
||||
<span class="text-xs">Disable participant joined sound</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={disable_participant_left} class="checkbox checkbox-sm" />
|
||||
<span class="text-xs">Disable participant left sound</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={disable_reaction} class="checkbox checkbox-sm" />
|
||||
<span class="text-xs">Disable reaction sound</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={disable_raise_hand} class="checkbox checkbox-sm" />
|
||||
<span class="text-xs">Disable raise hand sound</span>
|
||||
</label>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Output -->
|
||||
<div class="border-t border-surface-200-800 pt-3 space-y-2">
|
||||
<!-- Mode toggle -->
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (output_mode = 'url')}
|
||||
class="btn btn-sm {output_mode === 'url' ? 'preset-tonal-primary' : 'preset-tonal-surface border border-surface-200-800'}"
|
||||
>
|
||||
<span class="fas fa-link mr-1" aria-hidden="true"></span>
|
||||
URL
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (output_mode = 'iframe')}
|
||||
class="btn btn-sm {output_mode === 'iframe' ? 'preset-tonal-primary' : 'preset-tonal-surface border border-surface-200-800'}"
|
||||
>
|
||||
<span class="fas fa-code mr-1" aria-hidden="true"></span>
|
||||
iframe HTML
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if built_url}
|
||||
<div class="flex gap-1 items-stretch">
|
||||
<textarea
|
||||
readonly
|
||||
rows={output_mode === 'iframe' ? 8 : 2}
|
||||
value={output}
|
||||
class="border border-surface-200-800 rounded px-2 py-1.5 w-full bg-surface-50-950 text-xs font-mono resize-none cursor-text"
|
||||
onclick={(e) => (e.target as HTMLTextAreaElement).select()}
|
||||
title="Click to select all"
|
||||
></textarea>
|
||||
<button
|
||||
type="button"
|
||||
onclick={copy_output}
|
||||
title="Copy to clipboard"
|
||||
class="btn btn-sm shrink-0 self-start {copied ? 'preset-tonal-success' : 'preset-tonal-primary'} transition-colors"
|
||||
>
|
||||
<span class="fas {copied ? 'fa-check' : 'fa-copy'}" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
{#if output_mode === 'url'}
|
||||
<a
|
||||
href={built_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-xs text-primary-600 dark:text-primary-400 hover:underline inline-flex items-center gap-1"
|
||||
>
|
||||
<span class="fas fa-external-link-alt" aria-hidden="true"></span>
|
||||
Open in new tab
|
||||
</a>
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="text-xs opacity-40 italic">Fill in Room Name to generate a URL.</p>
|
||||
{/if}
|
||||
</div>
|
||||
<!-- Output -->
|
||||
<div class="border-t border-surface-200-800 pt-3 space-y-2">
|
||||
<!-- Mode toggle -->
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (output_mode = 'url')}
|
||||
class="btn btn-sm {output_mode === 'url'
|
||||
? 'preset-tonal-primary'
|
||||
: 'preset-tonal-surface border border-surface-200-800'}"
|
||||
>
|
||||
<span class="fas fa-link mr-1" aria-hidden="true"></span>
|
||||
URL
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (output_mode = 'iframe')}
|
||||
class="btn btn-sm {output_mode === 'iframe'
|
||||
? 'preset-tonal-primary'
|
||||
: 'preset-tonal-surface border border-surface-200-800'}"
|
||||
>
|
||||
<span class="fas fa-code mr-1" aria-hidden="true"></span>
|
||||
iframe HTML
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if built_url}
|
||||
<div class="flex gap-1 items-stretch">
|
||||
<textarea
|
||||
readonly
|
||||
rows={output_mode === 'iframe' ? 8 : 2}
|
||||
value={output}
|
||||
class="border border-surface-200-800 rounded px-2 py-1.5 w-full bg-surface-50-950 text-xs font-mono resize-none cursor-text"
|
||||
onclick={(e) => (e.target as HTMLTextAreaElement).select()}
|
||||
title="Click to select all"
|
||||
></textarea>
|
||||
<button
|
||||
type="button"
|
||||
onclick={copy_output}
|
||||
title="Copy to clipboard"
|
||||
class="btn btn-sm shrink-0 self-start {copied
|
||||
? 'preset-tonal-success'
|
||||
: 'preset-tonal-primary'} transition-colors"
|
||||
>
|
||||
<span
|
||||
class="fas {copied ? 'fa-check' : 'fa-copy'}"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</button>
|
||||
</div>
|
||||
{#if output_mode === 'url'}
|
||||
<a
|
||||
href={built_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-xs text-primary-600 dark:text-primary-400 hover:underline inline-flex items-center gap-1"
|
||||
>
|
||||
<span class="fas fa-external-link-alt" aria-hidden="true"
|
||||
></span>
|
||||
Open in new tab
|
||||
</a>
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="text-xs opacity-40 italic">
|
||||
Fill in Room Name to generate a URL.
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user