build generic weather week

This commit is contained in:
Vincent van der Wal
2026-07-19 22:53:20 +02:00
parent cd1a47b6c3
commit e258c70670
5 changed files with 241 additions and 42 deletions
@@ -1,22 +1,35 @@
<script lang="ts">
import * as Select from '$lib/components/ui/select';
import { findModel, modelGroups } from '../../options';
import { type WeatherModelGroup, modelGroups } from '../../options';
interface Props {
selectedModel: string;
onModelChange: (model: string) => void;
/** Model list to offer; defaults to the deterministic forecast models */
groups?: WeatherModelGroup[];
label?: string;
}
let { selectedModel, onModelChange }: Props = $props();
let {
selectedModel,
onModelChange,
groups = modelGroups,
label = 'Weather model'
}: Props = $props();
let model = $derived(findModel(selectedModel));
let modelLabel = $derived(model?.label ?? selectedModel);
let modelMeta = $derived(
model?.resolution && model.resolution !== 'varies'
? `${model.resolution} · updated ${model.update}`
: 'Automatically picks the best model for this location'
let model = $derived(
groups.flatMap((group) => group.models).find((mo) => mo.value === selectedModel)
);
let modelLabel = $derived(model?.label ?? selectedModel);
let modelMeta = $derived.by(() => {
if (model?.resolution && model.resolution !== 'varies') {
return model.update ? `${model.resolution} · updated ${model.update}` : model.resolution;
}
return selectedModel === 'best_match'
? 'Automatically picks the best model for this location'
: '';
});
</script>
<Select.Root
@@ -28,7 +41,7 @@
}}
>
<Select.Trigger
aria-label="Forecast model selection"
aria-label="{label} selection"
class="group h-auto min-w-64 cursor-pointer gap-3 rounded-xl border-2 border-primary/35 bg-card py-2 ps-2.5 shadow-sm transition-colors hover:border-primary/70 hover:shadow-md data-[size=default]:h-auto data-[state=open]:border-primary sm:min-w-72"
>
<div
@@ -45,16 +58,18 @@
</div>
<div class="flex min-w-0 flex-1 flex-col items-start gap-0 overflow-hidden text-left">
<span class="text-[11px] font-semibold tracking-wide text-primary uppercase">
Weather model
{label}
</span>
<span class="max-w-full truncate text-sm font-bold text-foreground">{modelLabel}</span>
<span class="max-w-full truncate text-[11px] leading-tight text-muted-foreground">
{modelMeta}
</span>
{#if modelMeta}
<span class="max-w-full truncate text-[11px] leading-tight text-muted-foreground">
{modelMeta}
</span>
{/if}
</div>
</Select.Trigger>
<Select.Content preventScroll={false} class="max-h-[min(480px,60vh)] border-border">
{#each modelGroups as group (group.value)}
{#each groups as group (group.value)}
<Select.Group>
<Select.GroupHeading
class="text-[10.5px] font-bold tracking-wider text-primary/80 uppercase"
@@ -68,9 +83,9 @@
<span class="font-medium">{mo.label}</span>
{#if mo.resolution && mo.resolution !== 'varies'}
<span class="text-[11px] text-muted-foreground">
{mo.resolution} · updated {mo.update}
{mo.resolution}{mo.update ? ` · updated ${mo.update}` : ''}
</span>
{:else}
{:else if mo.value === 'best_match'}
<span class="text-[11px] text-muted-foreground">Automatic selection</span>
{/if}
</div>