FEAT: Added weather card which nicely displays the weather conditions from a METAR object
Some checks failed
Run Unit and Integration Tests / test (push) Failing after 1m0s
Run Unit and Integration Tests / test (pull_request) Failing after 53s
Build and Push Development Docker Image / build-and-push (push) Failing after 2m49s

This commit is contained in:
2025-06-20 11:56:31 +01:00
parent 85bed825fc
commit 75b7afcba9
2 changed files with 102 additions and 9 deletions

View File

@ -0,0 +1,99 @@
<script lang="ts">
import Card from './Card.svelte';
import type { Metar } from '$lib/api/types/metar';
export let metar: Metar;
// Determine condition from METAR fields
let condition = 'Unknown';
$: {
// Prefer wxString, then clouds[0].cover, then metarType
if (metar.wxString) {
condition = metar.wxString;
} else if (metar.clouds && metar.clouds.length > 0 && metar.clouds[0].cover) {
condition = metar.clouds[0].cover;
} else if (metar.metarType) {
condition = metar.metarType;
}
}
// Choose icon and style based on condition
let icon = '';
let bg = '';
let effect = '';
$: {
const cond = condition?.toLowerCase();
if (cond.includes('cavok') || cond.includes('clear') || cond.includes('clr')) {
icon = '☀️';
bg = 'bg-yellow-100 border-yellow-300 text-yellow-700';
effect = '';
} else if (cond.includes('rain') || cond.includes('shower') || cond.includes('tsra') || cond.includes('ra') || cond.includes('br')) {
icon = '🌧️';
bg = 'bg-blue-100 border-blue-300 text-blue-700';
effect = 'rain-effect';
} else if (cond.includes('cloud') || cond.includes('ovc') || cond.includes('bkn') || cond.includes('sct') || cond.includes('few')) {
icon = '☁️';
bg = 'bg-gray-100 border-gray-300 text-gray-700';
effect = '';
} else if (cond.includes('snow')) {
icon = '❄️';
bg = 'bg-blue-50 border-blue-200 text-blue-500';
effect = 'snow-effect';
} else if (cond.includes('fog') || cond.includes('mist')) {
icon = '🌫️';
bg = 'bg-gray-200 border-gray-400 text-gray-600';
effect = '';
} else {
icon = '🌡️';
bg = 'bg-slate-100 border-slate-300 text-slate-700';
effect = '';
}
}
</script>
<Card containerStyle={`rounded-xl shadow-md border-2 ${bg} relative overflow-hidden`}>
<div slot="content" class="flex flex-col items-center py-4">
<div class="text-4xl mb-2">{icon}</div>
<div class="text-xl font-bold">{metar.icaoId}</div>
<div class="text-md mb-1">{metar.name}</div>
<div class="text-2xl font-semibold">{metar.temp}°C</div>
<div class="text-sm italic mb-2">{metar.altim}hPa</div>
<div class="text-xs text-gray-500 truncate w-full text-center"><code>{metar.rawOb}</code></div>
</div>
{#if effect === 'rain-effect'}
<div class="absolute inset-0 pointer-events-none rain"></div>
{/if}
{#if effect === 'snow-effect'}
<div class="absolute inset-0 pointer-events-none snow"></div>
{/if}
</Card>
<style>
.rain {
background-image: repeating-linear-gradient(
120deg,
rgba(0, 0, 255, 0.1) 0 2px,
transparent 2px 8px
);
animation: rainmove 0.7s linear infinite;
}
@keyframes rainmove {
0% { background-position: 0 0; }
100% { background-position: 20px 40px; }
}
.snow {
background-image: radial-gradient(white 1.5px, transparent 2px),
radial-gradient(white 1.5px, transparent 2px);
background-size: 20px 20px;
background-position: 0 0, 10px 10px;
opacity: 0.5;
animation: snowmove 1.5s linear infinite;
}
@keyframes snowmove {
0% { background-position: 0 0, 10px 10px; }
100% { background-position: 0 20px, 10px 30px; }
}
</style>

View File

@ -8,6 +8,7 @@
import { aviationWeatherApi } from '$lib/api/weatherservice';
import type { Metar } from '$lib/api/types/metar'
import { onDestroy } from 'svelte';
import WeatherCard from '$lib/components/Cards/WeatherCard.svelte';
let metar: Metar | null = null;
let loading = false;
@ -54,15 +55,8 @@
<span class="text-red-600 text-xl">{error}</span>
{:else if metar}
<div class="text-left text-lg space-y-2">
<div><strong>ICAO:</strong> {metar.icaoId}</div>
<div><strong>Airport:</strong> {metar.name}</div>
<div><strong>Observed:</strong> {metar.reportTime}</div>
<div><strong>Temperature:</strong> {metar.temp}°C</div>
<div><strong>Dew Point:</strong> {metar.dewp}°C</div>
<div><strong>Wind:</strong> {metar.wdir}° at {metar.wspd}kt</div>
<div><strong>Visibility:</strong> {metar.visib}</div>
<div><strong>Pressure:</strong> {metar.altim} hPa</div>
<div><strong>Raw METAR:</strong> <code>{metar.rawOb}</code></div>
<WeatherCard metar={metar}/>
{console.log(metar)}
</div>
{:else}
<Loading />