Files
electric-cherry/src/lib/ui/components/HostPreparation.svelte
T

124 lines
3.9 KiB
Svelte

<script lang="ts">
import type { Host } from '$lib/hosts.js';
import { formatGameBytes } from '$lib/game-files.js';
import GameFileTransferProgress from '$ui/components/GameFileTransferProgress.svelte';
let { host }: { host: Host } = $props();
</script>
<div class="preparation" aria-live="polite">
<p>
The default runtime and the latest available Black Ops I and Black Ops II game files are
prepared automatically. Re-enabling a host requires a fresh runtime pull and verification of
both game libraries before it accepts deployments. Running servers keep their current files.
</p>
<p>
Supported hosts also cache Plutonium files to speed up new deployments. This optional cache
refreshes when a new production release is detected; deployments can proceed while it is
unavailable.
</p>
{#if host.preparation}
<p class="status" class:blocked={host.preparation.state === 'blocked'}>
Automatic setup: {host.preparation.state === 'ready'
? 'Ready'
: host.preparation.state === 'preparing'
? 'In progress'
: host.preparation.state === 'blocked'
? 'Needs attention'
: 'Waiting'}
</p>
<ul>
{#each host.preparation.items as item}
<li>
<div class="row">
<strong>{item.label}</strong><span
>{item.state === 'blocked' ? 'Needs attention' : item.state}</span
>
</div>
<p class:blocked={item.state === 'blocked'}>{item.detail}</p>
{#if item.cache && item.cache.status !== 'missing'}
<div class="transfer">
<GameFileTransferProgress
cache={item.cache}
connected={host.connected}
/>
</div>
{:else if item.bytesTotal && item.bytesDownloaded !== undefined && item.state === 'preparing'}
<progress
max={item.bytesTotal}
value={item.bytesDownloaded}
aria-label={`${item.label} download progress`}
></progress>
<small
>{formatGameBytes(item.bytesDownloaded)} / {formatGameBytes(
item.bytesTotal
)}</small
>
{/if}
</li>
{/each}
</ul>
{:else}<p>Setup progress will appear after the host connects.</p>{/if}
<p><a href="/game-files">Upload and view game files →</a></p>
</div>
<style>
.preparation {
display: grid;
gap: 12px;
}
p {
margin: 0;
color: var(--text-secondary);
font-size: var(--text-sm);
line-height: 1.6;
}
.status {
color: var(--text-primary);
}
ul {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 16px;
}
li {
min-width: 0;
}
.row {
display: flex;
justify-content: space-between;
gap: 12px;
font-size: var(--text-sm);
}
strong {
overflow-wrap: anywhere;
}
span {
text-transform: capitalize;
color: var(--text-secondary);
}
li p {
margin-top: 4px;
}
.blocked {
color: var(--state-danger);
}
progress {
width: 100%;
margin-top: 8px;
accent-color: var(--accent-primary);
}
small {
display: block;
color: var(--text-secondary);
font-size: var(--text-xs);
}
a {
color: var(--accent-primary-hover);
}
.transfer {
margin-top: 8px;
}
</style>