Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
359 changes: 358 additions & 1 deletion package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"dev": "svelte-kit sync && vite dev --host",
"build": "svelte-kit sync && vite build -l info",
"build-weather": "BUILD_WEATHER_PAGES=true svelte-kit sync && BUILD_WEATHER_PAGES=true vite build -l info",
"build:weather": "BUILD_WEATHER_PAGES=true svelte-kit sync && BUILD_WEATHER_PAGES=true vite build -l info",
"staging": "NODE_ENV=development vite build --mode development",
"preview": "vite preview --host",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
Expand Down Expand Up @@ -50,6 +50,7 @@
"prettier": "^3.6.0",
"prettier-plugin-svelte": "^3.4.0",
"prettier-plugin-tailwindcss": "^0.7.1",
"replace-in-file": "^8.3.0",
"start-server-and-test": "^2.1.0",
"svelte": "^5.43.2",
"svelte-check": "^4.3.0",
Expand Down
56 changes: 56 additions & 0 deletions scripts/fetch-domain-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import fs from 'fs';
import { replaceInFileSync } from 'replace-in-file';

export const fetchDomainData = (generateNewOptionFiles = true) => {
return {
name: 'pull-domain-data',
transform(code, id, options) {
if (id.includes('src/routes/en/docs') && id.endsWith('options.ts')) {
if (options?.ssr) {
if (id.includes('dwd-api')) {
const basePath = id.replace('options.ts', '');
const domainMetaData = JSON.parse(
fs.readFileSync(basePath + 'meta-data-poc.json', 'utf8')
);

fetch('https://openmeteo.s3.amazonaws.com/data/dwd_icon/static/meta.json')
.then((response) => response.json())
.then(function (response) {
console.log(response);
let newHourly = `export const hourly = [
[`;
for (const [index, variable] of domainMetaData.variables.entries()) {
newHourly += `
{ value: '${variable}', label: '${domainMetaData.labels[index]}' },`;
}

newHourly += `
]
];`;

const regex = /export const hourly = \[[\s\S]*?\];/;

if (generateNewOptionFiles) {
const replaceOptions = {
files: basePath + 'domains/dwd-icon.ts',
from: regex,
to: newHourly,
countMatches: true
};

try {
const results = replaceInFileSync(replaceOptions);
console.log('Replacement results:', results);
} catch (error) {
console.error('Error occurred:', error);
}
} else {
return code.replace(regex, newHourly);
}
});
}
}
}
}
};
};
9 changes: 9 additions & 0 deletions src/lib/components/variables/all-hourly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const allHourly = [
{ value: 'temperature_2m', label: 'Temperature (2 m)' },
{ value: 'relative_humidity_2m', label: 'Relative Humidity (2 m)' },
{ value: 'apparent_temperature', label: 'Apparent Temperature' },
{ value: 'precipitation', label: 'Precipitation (rain + showers + snow)' },
{ value: 'surface_pressure', label: 'Surface Pressure' },
{ value: 'sea_level_pressure', label: 'Sea Level Pressure' },
{ value: 'weather_code', label: 'Weather code' }
];
5 changes: 5 additions & 0 deletions src/lib/components/variables/hourly-variables-empty.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
import { fade } from 'svelte/transition';
</script>

<div in:fade class="mt-2 min-h-[250px]"></div>
124 changes: 85 additions & 39 deletions src/lib/components/variables/hourly-variables.svelte
Original file line number Diff line number Diff line change
@@ -1,53 +1,99 @@
<script lang="ts">
import { fade } from 'svelte/transition';

import { Checkbox } from '$lib/components/ui/checkbox';
import { Label } from '$lib/components/ui/label';

import { type Parameters } from '$lib/docs';

import { allHourly } from './all-hourly';

interface Props {
params: Parameters;
hourly;
hourly: { value: string; label: string }[][];
}

let { params = $bindable(), hourly }: Props = $props();

let hourlyFlat = $derived(hourly.flat());
let hourlyValues = $derived(hourlyFlat.map((h) => h.value));

const getVariable = (variable: string) => {
for (let h of allHourly) {
if (variable === h.value) {
return h;
}
}
return null;
};

let notAvailable = $derived(
params.hourly
?.filter((h: string) => !hourlyValues?.includes(h))
.map((nA: string) => getVariable(nA))
);
</script>

<div class="mt-6 md:mt-12">
<a href="#hourly_weather_variables"
><h2 id="hourly_weather_variables" class="text-2xl md:text-3xl">Hourly Weather Variables</h2></a
>
<div
class="mt-2 grid grid-flow-row gap-x-2 gap-y-2 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4"
>
{#each hourly as group, i (i)}
<div>
{#each group as { value, label } (value)}
<div class="group flex items-center" title={label}>
<Checkbox
id="{value}_hourly"
class="bg-muted/50 border-border-dark cursor-pointer duration-100 group-hover:border-[currentColor]"
{value}
checked={params.hourly?.includes(value)}
aria-labelledby="{value}_label"
onCheckedChange={() => {
if (params.hourly?.includes(value)) {
params.hourly = params.hourly.filter((item) => {
return item !== value;
});
} else if (params.hourly) {
params.hourly.push(value);
params.hourly = params.hourly;
}
}}
/>
<Label
id="{value}_label"
for="{value}_hourly"
class="cursor-pointer truncate py-[0.1rem] pl-[0.42rem]">{label}</Label
>
</div>
{/each}
</div>
{/each}
</div>
<div
in:fade
class="mt-2 grid grid-flow-row gap-x-2 gap-y-2 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4"
>
{#each hourly as group, i (i)}
<div>
{#each group as { value, label } (value)}
<div class="group flex items-center" title={label}>
<Checkbox
id="{value}_hourly"
class="bg-muted/50 border-border-dark cursor-pointer duration-100 group-hover:border-[currentColor]"
{value}
checked={params.hourly?.includes(value)}
aria-labelledby="{value}_label"
onCheckedChange={() => {
if (params.hourly?.includes(value)) {
params.hourly = params.hourly.filter((item: string) => {
return item !== value;
});
} else if (params.hourly) {
params.hourly.push(value);
params.hourly = params.hourly;
}
}}
/>
<Label
id="{value}_label"
for="{value}_hourly"
class="cursor-pointer truncate py-[0.1rem] pl-[0.42rem]">{label}</Label
>
</div>
{/each}
</div>
{/each}
{#if notAvailable.length > 0}
<div transition:fade>
<div class="font-bold">Not available for selected model:</div>
{#each notAvailable as { value, label } (value)}
<div class="group flex items-center opacity-40" title={label}>
<Checkbox
id="{value}_hourly"
class="bg-muted/50 border-border-dark cursor-pointer duration-100 group-hover:border-[currentColor]"
{value}
checked={params.hourly?.includes(value)}
aria-labelledby="{value}_label"
onclick={() => {
if (params.hourly?.includes(value)) {
params.hourly = params.hourly.filter((item) => {
return item !== value;
});
}
}}
/>
<Label
id="{value}_label"
for="{value}_hourly"
class="cursor-pointer truncate py-[0.1rem] pl-[0.42rem]">{label}</Label
>
</div>
{/each}
</div>
{/if}
</div>
65 changes: 52 additions & 13 deletions src/routes/en/docs/dwd-api/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts">
import { onMount } from 'svelte';
import { slide } from 'svelte/transition';
import { fade, slide } from 'svelte/transition';

import { resolve } from '$app/paths';

import { urlHashStore } from '$lib/stores/url-hash-store';

Expand All @@ -16,19 +18,22 @@

import * as Accordion from '$lib/components/ui/accordion';
import * as Alert from '$lib/components/ui/alert';
import { Button } from '$lib/components/ui/button';
import { Checkbox } from '$lib/components/ui/checkbox';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import * as Select from '$lib/components/ui/select';
import * as ToggleGroup from '$lib/components/ui/toggle-group';

import AccordionItem from '$lib/components/accordion/accordion-item.svelte';
import DarkmodeToggle from '$lib/components/header/darkmode-toggle/darkmode-toggle.svelte';
import LicenceSelector from '$lib/components/licence/licence-selector.svelte';
import LocationSelection from '$lib/components/location/location-selection.svelte';
import PressureLevelsHelpTable from '$lib/components/pressure/pressure-levels-help-table.svelte';
import ResultPreview from '$lib/components/response/results-preview.svelte';
import Settings from '$lib/components/settings/settings.svelte';
import TimeSelector from '$lib/components/time/time-selector.svelte';
import HourlyVariablesEmpty from '$lib/components/variables/hourly-variables-empty.svelte';
import HourlyVariables from '$lib/components/variables/hourly-variables.svelte';

import {
Expand All @@ -46,14 +51,18 @@
daily,
defaultParameters,
forecastDaysOptions,
hourly,
// hourly,
levels,
minutely_15,
models,
pressureVariables,
solarVariables
} from './options';

import(`./domains/dwd-icon`);
import(`./domains/dwd-icon-d2`);
import(`./domains/dwd-icon-europe`);

const params = urlHashStore({
latitude: [52.52],
longitude: [13.41],
Expand All @@ -65,11 +74,6 @@
$params.timezone == 'UTC' && ($params.daily ? $params.daily.length > 0 : false)
);

let forecastDays = $derived(
forecastDaysOptions.find((fco) => fco.value == $params.forecast_days)
);
let pastDays = $derived(pastDaysOptions.find((pdo) => pdo.value == $params.past_days));

// Additional variable settings
let forecastHours = $derived(
forecastHoursOptions.find((fho) => String(fho.value) == $params.forecast_hours)
Expand All @@ -93,10 +97,10 @@
onMount(() => {
if (
(countVariables(additionalVariables, $params.hourly).active ||
forecastHours.value ||
pastHours.value ||
temporalResolution.value ||
cellSelection.value) &&
forecastHours?.value ||
pastHours?.value ||
temporalResolution?.value ||
cellSelection?.value) &&
!accordionValues.includes('additional-variables')
) {
accordionValues.push('additional-variables');
Expand Down Expand Up @@ -137,6 +141,11 @@

let lastDate = new Date();
lastDate.setDate(lastDate.getDate() + 8);

let model = $state('dwd-icon');
let hourly = $derived.by(async () => {
return (await import(`./domains/${model}.ts`)).hourly;
});
</script>

<svelte:head>
Expand All @@ -163,7 +172,7 @@
delivering 15-minutely data for short-term forecasts in central Europe and 11 km resolution
global forecasts. The ICON model is a preferred choice in <a
class="text-link underline"
href="/en/docs">generic weather forecast API</a
href={resolve('/en/docs')}>generic weather forecast API</a
> if no other high resolution weather models are available.
</Alert.Description>
</Alert.Root>
Expand All @@ -181,8 +190,38 @@
{lastDate}
/>

<Button
class="mt-3"
onclick={() => {
model = 'dwd-icon';
}}>DWD ICON</Button
>
<Button
class="mt-3"
onclick={() => {
model = 'dwd-icon-europe';
}}>DWD ICON EU</Button
>
<Button
class="mt-3"
onclick={() => {
model = 'dwd-icon-d2';
}}>DWD ICON D2</Button
>

<!-- HOURLY -->
<HourlyVariables bind:params={$params} {hourly} />
<div class="mt-6 md:mt-12">
<a href="#hourly_weather_variables"
><h2 id="hourly_weather_variables" class="text-2xl md:text-3xl">
Hourly Weather Variables
</h2></a
>
{#await hourly}
<HourlyVariablesEmpty />
{:then hourly}
<HourlyVariables bind:params={$params} {hourly} />
{/await}
</div>

<!-- ADDITIONAL VARIABLES -->
<div class="mt-6">
Expand Down
9 changes: 9 additions & 0 deletions src/routes/en/docs/dwd-api/domains/dwd-icon-d2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const hourly = [
[
{ value: 'temperature_2m', label: 'Temperature (2 m)' },
{ value: 'relative_humidity_2m', label: 'Relative Humidity (2 m)' },
{ value: 'surface_pressure', label: 'Surface Pressure' },
{ value: 'sea_level_pressure', label: 'Sea Level Pressure' },
{ value: 'weather_code', label: 'Weather code' }
]
];
10 changes: 10 additions & 0 deletions src/routes/en/docs/dwd-api/domains/dwd-icon-europe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const hourly = [
[
{ value: 'temperature_2m', label: 'Temperature (2 m)' },
{ value: 'relative_humidity_2m', label: 'Relative Humidity (2 m)' },
{ value: 'apparent_temperature', label: 'Apparent Temperature' },
{ value: 'precipitation', label: 'Precipitation (rain + showers + snow)' },
{ value: 'surface_pressure', label: 'Surface Pressure' },
{ value: 'sea_level_pressure', label: 'Sea Level Pressure' }
]
];
Loading