Use shared form controls and enforce UI patterns (Refs #110)
CI / checks (push) Successful in 4m51s

This commit is contained in:
2026-10-10 00:19:48 -04:00
parent 8d1bb69591
commit cc9c10226e
54 changed files with 1431 additions and 1449 deletions
+28 -32
View File
@@ -1,4 +1,7 @@
<script lang="ts">
import Field from '$ui/components/primitives/Field.svelte';
import Select from '$ui/components/primitives/Select.svelte';
import Input from '$ui/components/primitives/Input.svelte';
import { onMount, untrack } from 'svelte';
import { page } from '$app/stores';
import { pollVisible } from '$ui/poll.js';
@@ -109,21 +112,26 @@
>{/if}
</div>
{#if filtersVisible}<div class="filters">
<input
type="search"
aria-label="Search hosts"
placeholder="Search hosts…"
bind:value={search}
/>
<select aria-label="Filter hosts by status" bind:value={status}
><option value="">All statuses</option><option value="attention"
>Needs attention</option
><option value="offline">Offline</option><option value="preparing"
>Preparing</option
><option value="draining">Draining</option><option value="disabled"
>Disabled</option
><option value="deleting">Deleting</option><option value="ready">Ready</option
></select
<Field label="Search hosts" hiddenLabel class="search"
><Input
type="search"
aria-label="Search hosts"
placeholder="Search hosts…"
bind:value={search}
/></Field
>
<Field label="Filter hosts by status" hiddenLabel
><Select aria-label="Filter hosts by status" bind:value={status}
><option value="">All statuses</option><option value="attention"
>Needs attention</option
><option value="offline">Offline</option><option value="preparing"
>Preparing</option
><option value="draining">Draining</option><option value="disabled"
>Disabled</option
><option value="deleting">Deleting</option><option value="ready"
>Ready</option
></Select
></Field
>
{#if search || status}<Button
variant="ghost"
@@ -170,27 +178,15 @@
font: inherit;
padding: 4px;
}
input,
select {
box-sizing: border-box;
padding: 10px 12px;
color: var(--text-primary);
background: var(--surface-sunken);
border: 1px solid var(--border-control);
border-radius: var(--radius-sm);
font: var(--text-sm) var(--font-body);
}
input {
flex: 1 1 240px;
min-width: 0;
max-width: 440px;
}
input:focus-visible,
select:focus-visible,
button:focus-visible {
outline: 2px solid var(--accent-primary);
outline-offset: 3px;
}
.filters > :global(.search) {
flex: 1 1 240px;
max-width: 440px;
}
.empty {
padding: 24px;
text-align: center;
+21 -42
View File
@@ -1,4 +1,6 @@
<script lang="ts">
import Input from '$ui/components/primitives/Input.svelte';
import Field from '$ui/components/primitives/Field.svelte';
import { timeFormat } from '$ui/stores/time-zone.js';
import RelativeTime from '$ui/components/RelativeTime.svelte';
import Breadcrumbs from '$ui/components/primitives/Breadcrumbs.svelte';
@@ -468,11 +470,8 @@
}}
>
<fieldset disabled={busy || cleaning}>
<label
>Plutainer image<input
required
bind:value={runtimeImage}
/></label
<Field label="Plutainer image">
<Input required bind:value={runtimeImage} /></Field
><Button type="submit" disabled={busy || !host.connected}
>Pull runtime image</Button
>
@@ -509,50 +508,43 @@
<h2>Host configuration</h2>
{#if canManage}<form onsubmit={save}>
<fieldset disabled={busy || cleaning}>
<label
>Friendly name<input
required
maxlength="200"
bind:value={name}
/></label
<Field label="Friendly name">
<Input required maxlength={200} bind:value={name} /></Field
>
<div class="fields">
<label
>First game port<input
<Field label="First game port">
<Input
type="number"
min="1"
max="65535"
required
bind:value={portMin}
/></label
><label
>Last game port<input
/></Field
><Field label="Last game port">
<Input
type="number"
min={portMin}
max="65535"
required
bind:value={portMax}
/></label
/></Field
>
</div>
<label
>Local bind address<input
required
bind:value={bindAddress}
/></label
><label
>Public / NAT address<input
<Field label="Local bind address">
<Input required bind:value={bindAddress} /></Field
><Field label="Public / NAT address">
<Input
bind:value={publicAddress}
placeholder="Optional public hostname or address"
/></label
><label
>Minimum free game storage (GiB)<input
/></Field
><Field label="Minimum free game storage (GiB)">
<Input
type="number"
min="0"
step="0.1"
required
bind:value={minimumFreeGB}
/></label
/></Field
><Button type="submit" disabled={busy}>Save settings</Button>
</fieldset>
</form>{:else}<dl>
@@ -745,20 +737,7 @@
padding: 0;
margin: 0;
}
label {
display: grid;
gap: 8px;
font-size: var(--text-sm);
}
input {
width: 100%;
min-width: 0;
padding: 10px;
color: var(--text-primary);
background: var(--surface-sunken);
border: 1px solid var(--border-control);
border-radius: var(--radius-sm);
}
.fields > * {
flex: 1;
min-width: 120px;