This commit is contained in:
Vincent van der Wal
2026-07-19 16:13:51 +02:00
parent e031716ce6
commit baa4840b38
26 changed files with 1077 additions and 702 deletions
@@ -1,8 +1,7 @@
<script lang="ts">
import { Label } from '$lib/components/ui/label';
import * as Select from '$lib/components/ui/select';
import { models } from '../../options';
import { findModel, modelGroups } from '../../options';
interface Props {
selectedModel: string;
@@ -11,35 +10,73 @@
let { selectedModel, onModelChange }: Props = $props();
let modelLabel = $derived(
models.find((mo) => String(mo.value) === selectedModel)?.label ?? selectedModel
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'
);
</script>
<div class="mt-6 flex gap-6 md:mt-12">
<div class="relative w-1/2">
<Select.Root
name="model_selection"
type="single"
value={selectedModel}
onValueChange={(val) => {
if (val) onModelChange(val);
}}
<Select.Root
name="model_selection"
type="single"
value={selectedModel}
onValueChange={(val) => {
if (val) onModelChange(val);
}}
>
<Select.Trigger
aria-label="Forecast model 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
class="flex size-9 shrink-0 items-center justify-center rounded-lg bg-primary/12 text-primary"
>
<Select.Trigger
aria-label="Forecast model selection"
class="h-12 cursor-pointer pt-6 [&_svg]:mb-3"
>
{modelLabel}
</Select.Trigger>
<Select.Content preventScroll={false} class="border-border">
{#each models as mo (mo.value)}
<Select.Item class="cursor-pointer" value={mo.value}>{mo.label}</Select.Item>
{/each}
</Select.Content>
<Label class="absolute top-[0.35rem] left-2 z-10 px-1 text-xs text-muted-foreground">
<!-- layered-globe icon: weather model -->
<svg class="size-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.75">
<circle cx="12" cy="12" r="9" />
<path
stroke-linecap="round"
d="M3.6 9h16.8M3.6 15h16.8M12 3a15 15 0 0 1 0 18a15 15 0 0 1 0-18"
/>
</svg>
</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>
</Select.Root>
</div>
</div>
</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>
</div>
</Select.Trigger>
<Select.Content preventScroll={false} class="max-h-[min(480px,60vh)] border-border">
{#each modelGroups as group (group.value)}
<Select.Group>
<Select.GroupHeading
class="text-[10.5px] font-bold tracking-wider text-primary/80 uppercase"
>
{group.label}
</Select.GroupHeading>
{#each group.models as mo (mo.value)}
<Select.Item class="cursor-pointer" value={mo.value} label={mo.label}>
<!-- div, not span: the item base styles force flex row on spans -->
<div class="flex w-full flex-col items-start gap-0 leading-tight">
<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}
</span>
{:else}
<span class="text-[11px] text-muted-foreground">Automatic selection</span>
{/if}
</div>
</Select.Item>
{/each}
</Select.Group>
{/each}
</Select.Content>
</Select.Root>