Files
idle-xboct/packages/overlay/src/App.svelte
T

81 lines
2.1 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte';
import { mountWorld, type WorldHandle } from '@idle/render';
import { connectWorld, type NetStatus } from './net';
const STATUS_TEXT: Record<NetStatus, string> = {
connecting: 'подключение…',
online: 'онлайн',
reconnecting: 'переподключение…',
};
let host = $state<HTMLDivElement | undefined>(undefined);
let status = $state<NetStatus>('connecting');
onMount(() => {
let world: WorldHandle | undefined;
let disposeNet: (() => void) | undefined;
if (host) {
void mountWorld(host, { backgroundAlpha: 0 }).then((w) => {
world = w;
disposeNet = connectWorld({
onStatus: (s) => {
status = s;
},
onWelcome: (msg) => world?.setWelcome(msg),
onSnapshot: (msg) => world?.applySnapshot(msg),
onDelta: (msg) => world?.applyDelta(msg),
});
});
}
return () => {
disposeNet?.();
world?.destroy();
};
});
</script>
<div class="root">
<div class="world" bind:this={host}></div>
<div class="badge">{STATUS_TEXT[status]}</div>
<!-- онбординг — в самом виджете, чат ботом не засоряем -->
{#if status === 'online'}
<div class="hint">!рубить · !копать · !рыбачить · !ковать &lt;рецепт&gt; · !готовить &lt;рецепт&gt; · !отдых · !костёр · !стоп</div>
{/if}
</div>
<style>
.root {
position: fixed;
inset: 0;
}
.world {
position: absolute;
inset: 0;
}
.badge {
position: absolute;
top: 8px;
right: 8px;
font: 12px/1.4 monospace;
color: #9fb0c3;
background: rgba(16, 19, 26, 0.55);
padding: 2px 8px;
border-radius: 8px;
}
.hint {
position: absolute;
bottom: 14px;
left: 50%;
transform: translateX(-50%);
font: 13px/1.4 monospace;
color: #eef4fa;
background: rgba(16, 19, 26, 0.6);
padding: 5px 14px;
border-radius: 10px;
white-space: nowrap;
}
</style>