76 lines
2.3 KiB
Svelte
76 lines
2.3 KiB
Svelte
<script lang="ts">
|
|
import { page } from '$app/state';
|
|
import { onMount, untrack } from 'svelte';
|
|
import PresentationDisplay from '#lib/components/PresentationDisplay.svelte';
|
|
import type { PageProps } from './$types';
|
|
|
|
let { data }: PageProps = $props();
|
|
let view = $state(untrack(() => data.view ?? { revision: -1, content: null }));
|
|
let connection = $state<'connected' | 'waiting' | 'interrupted'>(
|
|
untrack(() => (data.view ? 'connected' : 'waiting'))
|
|
);
|
|
|
|
onMount(() => {
|
|
let stopped = false;
|
|
let timer: ReturnType<typeof setTimeout>;
|
|
async function refresh() {
|
|
try {
|
|
const response = await fetch(`/heinzlive/${page.params.token}/state`, {
|
|
headers: { Accept: 'application/json' },
|
|
cache: 'no-store'
|
|
});
|
|
if (!response.ok) throw new Error('STATE_UNAVAILABLE');
|
|
const next = await response.json();
|
|
if (next.revision !== view.revision) view = next;
|
|
connection = 'connected';
|
|
} catch {
|
|
connection = 'interrupted';
|
|
}
|
|
if (!stopped) timer = setTimeout(refresh, connection === 'interrupted' ? 3000 : 1000);
|
|
}
|
|
async function connect() {
|
|
const accessKey = decodeURIComponent(location.hash.slice(1));
|
|
if (accessKey) {
|
|
const response = await fetch(`/heinzlive/${data.channelId}/access`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ key: accessKey })
|
|
});
|
|
if (!response.ok) {
|
|
connection = 'interrupted';
|
|
return;
|
|
}
|
|
}
|
|
timer = setTimeout(refresh, 0);
|
|
}
|
|
void connect();
|
|
return () => {
|
|
stopped = true;
|
|
clearTimeout(timer);
|
|
};
|
|
});
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>heinzlive</title>
|
|
<meta name="robots" content="noindex, nofollow, noarchive" />
|
|
</svelte:head>
|
|
|
|
<main class:empty={!view.content} class="heinzlive-output">
|
|
<div class="output-connection sr-only" class:problem={connection === 'interrupted'} role="status">
|
|
<span></span>{connection === 'interrupted' ? 'Verbindung unterbrochen' : 'Verbunden'}
|
|
</div>
|
|
{#if view.content}
|
|
{#key view.revision}
|
|
<PresentationDisplay
|
|
content={view.content}
|
|
imageSrc={view.content.images.length
|
|
? view.content.mode === 'text'
|
|
? `/heinzlive/${page.params.token}/media`
|
|
: `/heinzlive/${page.params.token}/media/${view.content.images[0].id}`
|
|
: `/heinzlive/${page.params.token}/preview-image`}
|
|
/>
|
|
{/key}
|
|
{/if}
|
|
</main>
|