diff --git a/messages/de.json b/messages/de.json index 80c8bb4..0103ab7 100644 --- a/messages/de.json +++ b/messages/de.json @@ -294,6 +294,16 @@ "compare_selection_pending": "Auswahl geändert", "compare_apply_selection": "Anwenden & Diagramme neu laden", "compare_customize_models": "Modelle anpassen", + "compare_edit_models": "Modelle bearbeiten", + "compare_edit_variables": "Variablen bearbeiten", + "compare_edit_models_description": "Modelle suchen oder ganze Anbietergruppen auswählen.", + "compare_edit_variables_description": "Variablen suchen oder ganze Themengruppen auswählen.", + "compare_search_models": "Modelle suchen", + "compare_search_variables": "Variablen suchen", + "compare_only_selected": "Nur ausgewählte", + "compare_select_group": "Alle auswählen", + "compare_clear_group": "Alle abwählen", + "compare_no_matching_options": "Keine passenden Optionen.", "compare_no_models_selected": "Keine Modelle ausgewählt.", "compare_remove_model": "{model} entfernen", "compare_timeline_title": "Zeitleiste des Modellvergleichs", diff --git a/messages/en.json b/messages/en.json index 63da40e..7c35009 100644 --- a/messages/en.json +++ b/messages/en.json @@ -294,6 +294,16 @@ "compare_selection_pending": "Selection changed", "compare_apply_selection": "Apply & reload charts", "compare_customize_models": "Customize models", + "compare_edit_models": "Edit models", + "compare_edit_variables": "Edit variables", + "compare_edit_models_description": "Search models or select complete provider families.", + "compare_edit_variables_description": "Search variables or select complete thematic groups.", + "compare_search_models": "Search models", + "compare_search_variables": "Search variables", + "compare_only_selected": "Only selected", + "compare_select_group": "Select all", + "compare_clear_group": "Clear all", + "compare_no_matching_options": "No matching options.", "compare_no_models_selected": "No models selected.", "compare_remove_model": "Remove {model}", "compare_timeline_title": "Model Comparison Timeline", diff --git a/messages/es.json b/messages/es.json index 8355cfc..4388189 100644 --- a/messages/es.json +++ b/messages/es.json @@ -294,6 +294,16 @@ "compare_selection_pending": "Selección modificada", "compare_apply_selection": "Aplicar y recargar gráficos", "compare_customize_models": "Personalizar modelos", + "compare_edit_models": "Editar modelos", + "compare_edit_variables": "Editar variables", + "compare_edit_models_description": "Busca modelos o selecciona familias completas de proveedores.", + "compare_edit_variables_description": "Busca variables o selecciona grupos temáticos completos.", + "compare_search_models": "Buscar modelos", + "compare_search_variables": "Buscar variables", + "compare_only_selected": "Solo seleccionados", + "compare_select_group": "Seleccionar todo", + "compare_clear_group": "Deseleccionar todo", + "compare_no_matching_options": "No hay opciones coincidentes.", "compare_no_models_selected": "No hay modelos seleccionados.", "compare_remove_model": "Quitar {model}", "compare_timeline_title": "Cronología de comparación de modelos", diff --git a/messages/fr.json b/messages/fr.json index 7169592..0adf192 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -294,6 +294,16 @@ "compare_selection_pending": "Sélection modifiée", "compare_apply_selection": "Appliquer et recharger les graphiques", "compare_customize_models": "Personnaliser les modèles", + "compare_edit_models": "Modifier les modèles", + "compare_edit_variables": "Modifier les variables", + "compare_edit_models_description": "Recherchez des modèles ou sélectionnez des fournisseurs entiers.", + "compare_edit_variables_description": "Recherchez des variables ou sélectionnez des groupes thématiques entiers.", + "compare_search_models": "Rechercher des modèles", + "compare_search_variables": "Rechercher des variables", + "compare_only_selected": "Sélection uniquement", + "compare_select_group": "Tout sélectionner", + "compare_clear_group": "Tout désélectionner", + "compare_no_matching_options": "Aucune option correspondante.", "compare_no_models_selected": "Aucun modèle sélectionné.", "compare_remove_model": "Supprimer {model}", "compare_timeline_title": "Chronologie de comparaison des modèles", diff --git a/messages/it.json b/messages/it.json index e230e28..c65a859 100644 --- a/messages/it.json +++ b/messages/it.json @@ -294,6 +294,16 @@ "compare_selection_pending": "Selezione modificata", "compare_apply_selection": "Applica e ricarica i grafici", "compare_customize_models": "Personalizza modelli", + "compare_edit_models": "Modifica modelli", + "compare_edit_variables": "Modifica variabili", + "compare_edit_models_description": "Cerca modelli o seleziona intere famiglie di fornitori.", + "compare_edit_variables_description": "Cerca variabili o seleziona interi gruppi tematici.", + "compare_search_models": "Cerca modelli", + "compare_search_variables": "Cerca variabili", + "compare_only_selected": "Solo selezionati", + "compare_select_group": "Seleziona tutto", + "compare_clear_group": "Deseleziona tutto", + "compare_no_matching_options": "Nessuna opzione corrispondente.", "compare_no_models_selected": "Nessun modello selezionato.", "compare_remove_model": "Rimuovi {model}", "compare_timeline_title": "Cronologia del confronto tra modelli", diff --git a/src/routes/weather/compare/[location]/+page.svelte b/src/routes/weather/compare/[location]/+page.svelte index dbb6eed..fb8e03c 100644 --- a/src/routes/weather/compare/[location]/+page.svelte +++ b/src/routes/weather/compare/[location]/+page.svelte @@ -18,7 +18,6 @@ type ExportableChart, type ExportLegendItem } from '$lib/components/charts'; - import { Checkbox } from '$lib/components/ui/checkbox'; import { Label } from '$lib/components/ui/label'; import { Switch } from '$lib/components/ui/switch'; @@ -41,6 +40,7 @@ import { useHeroActions } from '../../hero.svelte'; import { defaultParameters, hourly, modelGroups, models as modelOptions } from '../../options'; + import ComparisonSelectionDrawer from './ComparisonSelectionDrawer.svelte'; import ModelPictogramTimeline from './ModelPictogramTimeline.svelte'; import { cardinalDirection, @@ -67,6 +67,9 @@ group.filter((variable) => variable.value !== 'cloud_cover') ); const VARIABLE_IDS = new Set(COMPARISON_HOURLY.flat().map((variable) => variable.value)); + const VARIABLE_ORDER = new Map( + COMPARISON_HOURLY.flat().map((variable, index) => [variable.value, index]) + ); const SECONDS_PER_HOUR = 3600; const FETCH_DEBOUNCE_MS = 300; const STANDARD_COMPARE_VARIABLES = [ @@ -95,8 +98,7 @@ let isMobile = $state(false); let comparisonPlotInsetLeft = $derived(isMobile ? 92 : 116); let comparisonPlotInsetRight = $derived(isMobile ? 8 : 20); - let modelsOpen = $state(false); - let customVariablesOpen = $state(false); + let selectionDrawerMode = $state<'models' | 'variables' | null>(null); let params = $state({ ...defaultParameters, @@ -138,6 +140,14 @@ ); } + function orderVariables(values: string[]): string[] { + return [...values].sort( + (left, right) => + (VARIABLE_ORDER.get(left) ?? Number.MAX_SAFE_INTEGER) - + (VARIABLE_ORDER.get(right) ?? Number.MAX_SAFE_INTEGER) + ); + } + let variablesDirty = $derived(!hasSameVariables(params.hourly, appliedHourly)); let modelsDirty = $derived(!hasSameOrder(params.models, appliedModels)); let displayedVariablesStale = $derived( @@ -501,7 +511,19 @@ const nextValues = values.includes(value) ? values.filter((item) => item !== value) : [...values, value]; - params[list] = list === 'models' ? orderModels(nextValues) : nextValues; + params[list] = list === 'models' ? orderModels(nextValues) : orderVariables(nextValues); + } + + function toggleGroupSelection( + list: 'models' | 'hourly', + values: string[], + select: boolean + ): void { + const groupValues = new Set(values); + const nextValues = select + ? [...new Set([...params[list], ...values])] + : params[list].filter((value) => !groupValues.has(value)); + params[list] = list === 'models' ? orderModels(nextValues) : orderVariables(nextValues); } function restoreStandardVariables(): void { @@ -535,10 +557,15 @@ return model ? [model] : []; }) ); - let modelSelectionGroups = $derived( + let modelDrawerGroups = $derived( modelGroups.map((group) => ({ - ...group, - selectedCount: group.models.filter((model) => params.models.includes(model.value)).length + value: group.value, + label: group.label, + options: group.models.map((model) => ({ + value: model.value, + label: model.label, + metadata: [model.resolution, model.update].filter(Boolean).join(' · ') + })) })) ); let selectedVariables = $derived( @@ -551,11 +578,14 @@ params.hourly.length === STANDARD_COMPARE_VARIABLES.length && STANDARD_COMPARE_VARIABLES.every((variable) => params.hourly.includes(variable)) ); - let variableSelectionGroups = $derived( + let variableDrawerGroups = $derived( COMPARISON_HOURLY.map((variables, index) => ({ - label: variableGroupLabels[index], - variables, - selectedCount: variables.filter((variable) => params.hourly.includes(variable.value)).length + value: `variables_${index}`, + label: variableGroupLabels[index](), + options: variables.map((variable) => ({ + value: variable.value, + label: variableLabel(variable.value) + })) })) ); @@ -812,7 +842,7 @@ {/if} - +

{m.compare_models_heading()}

@@ -870,11 +900,10 @@ {#if modelsDirty}
- - {#if modelsOpen} -
-
- {#each modelSelectionGroups as group (group.value)} -
- - {group.label} - - {group.selectedCount}/{group.models.length} - - - -
- {#each group.models as model (model.value)} -
- toggleSelection('models', model.value)} - /> - -
- {/each} -
-
- {/each} -
-
- {/if}
@@ -999,11 +987,10 @@ {#if variablesDirty} + + +
+ +
+ + +
+
+ + +
+ {#if visibleGroups.length > 0} +
+ {#each visibleGroups as visibleGroup (visibleGroup.value)} + {@const fullGroup = groups.find((group) => group.value === visibleGroup.value) ?? visibleGroup} + {@const selection = groupSelection(fullGroup)} +
+
+ + onToggleGroup( + fullGroup.options.map((option) => option.value), + !selection.all + )} + /> + + + {selection.count}/{fullGroup.options.length} + + +
+
+ {#each visibleGroup.options as option (option.value)} +
+ onToggle(option.value)} + /> + +
+ {/each} +
+
+ {/each} +
+ {:else} +
+ {m.compare_no_matching_options()} +
+ {/if} +
+ + + +