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
+40 -46
View File
@@ -1,4 +1,7 @@
<script lang="ts">
import Input from '$ui/components/primitives/Input.svelte';
import Select from '$ui/components/primitives/Select.svelte';
import Field from '$ui/components/primitives/Field.svelte';
import RelativeTime from '$ui/components/RelativeTime.svelte';
import { untrack } from 'svelte';
import { page } from '$app/stores';
@@ -129,17 +132,17 @@
<section class="history" aria-label="Match history">
{#snippet filterFields(suffix: string)}
<div class="filters">
{#if server === undefined}<label for={`match-game${suffix}`}
>Game<select
{#if server === undefined}<Field forId={`match-game${suffix}`} label="Game">
<Select
id={`match-game${suffix}`}
value={filters.game}
onchange={(event) => update({ game: event.currentTarget.value, map: '' })}
><option value="">All games</option><option value="t5">Black Ops I</option
><option value="t6">Black Ops II</option></select
></label
><option value="t6">Black Ops II</option></Select
></Field
>{/if}
<label for={`match-map${suffix}`}
>Map<select
<Field forId={`match-map${suffix}`} label="Map">
<Select
id={`match-map${suffix}`}
value={filters.map}
onchange={(event) => update({ map: event.currentTarget.value })}
@@ -153,7 +156,7 @@
? ` · ${map.game === 't5' ? 'BO1' : 'BO2'}`
: ''}</option
>{/each}
</select></label
</Select></Field
>
{#if server === undefined}<form
role="search"
@@ -163,32 +166,32 @@
if (suffix) filtersOpen = false;
}}
>
<label for={`match-search${suffix}`}
>Server<input
<Field forId={`match-search${suffix}`} label="Server">
<Input
id={`match-search${suffix}`}
type="search"
bind:value={search}
maxlength="100"
maxlength={100}
placeholder="Find a server…"
aria-describedby={`match-search-help${suffix}`}
/></label
/></Field
>
<span id={`match-search-help${suffix}`} class="sr-only"
>Press Enter to search by server name.</span
>
</form>{/if}
<label for={`match-days${suffix}`}
>Date range<select
<Field forId={`match-days${suffix}`} label="Date range">
<Select
id={`match-days${suffix}`}
value={String(filters.days)}
onchange={(event) => update({ days: event.currentTarget.value })}
><option value="0">All time</option><option value="7">Last 7 days</option
><option value="30">Last 30 days</option><option value="90">Last 90 days</option
></select
></label
></Select
></Field
>
<label for={`match-status${suffix}`}
>Status<select
<Field forId={`match-status${suffix}`} label="Status">
<Select
id={`match-status${suffix}`}
value={filters.status}
onchange={(event) => update({ status: event.currentTarget.value })}
@@ -196,28 +199,28 @@
>Completed</option
><option value="active">In progress</option><option value="interrupted"
>Interrupted</option
></select
></label
></Select
></Field
>
{#if suffix}
<label for={`match-sort${suffix}`}
>Sort by<select
<Field forId={`match-sort${suffix}`} label="Sort by">
<Select
id={`match-sort${suffix}`}
value={filters.sort}
onchange={(event) => update({ sort: event.currentTarget.value })}
>{#each sorts as item}<option value={item.key}>{item.label}</option
>{/each}</select
></label
>{/each}</Select
></Field
>
<label for={`match-order${suffix}`}
>Order<select
<Field forId={`match-order${suffix}`} label="Order">
<Select
id={`match-order${suffix}`}
value={filters.direction}
onchange={(event) => update({ direction: event.currentTarget.value })}
><option value="desc">Highest or newest first</option><option value="asc"
>Lowest or oldest first</option
></select
></label
></Select
></Field
>
{/if}
</div>
@@ -460,30 +463,19 @@
flex-wrap: wrap;
gap: var(--space-3);
}
label,
form {
flex: 1;
min-width: 145px;
}
label {
display: flex;
.filters :global(.field) {
flex: 1;
min-width: 145px;
}
.filters :global(.field) {
flex-direction: column;
gap: 6px;
color: var(--text-secondary);
font-size: var(--text-xs);
}
input,
select {
width: 100%;
min-height: 40px;
padding: 8px 10px;
border: 1px solid var(--border-control);
border-radius: var(--radius-md);
background: var(--surface-sunken);
color: var(--text-primary);
font: inherit;
font-size: var(--text-sm);
}
summary {
cursor: pointer;
color: var(--text-secondary);
@@ -640,10 +632,12 @@
display: grid;
grid-template-columns: minmax(0, 1fr);
}
.filters > label,
.filters > form {
min-width: 0;
}
.filters > :global(.field) {
min-width: 0;
}
.context {
gap: var(--space-1) var(--space-2);
}