diff --git a/client/src/components/weather-widget.tsx b/client/src/components/weather-widget.tsx index b4b2965..b8101f9 100644 --- a/client/src/components/weather-widget.tsx +++ b/client/src/components/weather-widget.tsx @@ -76,20 +76,22 @@ export function WeatherWidget() { } } - if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition( - async (pos) => { - const city = await reverseGeocode(pos.coords.latitude, pos.coords.longitude); - fetchWeather(pos.coords.latitude, pos.coords.longitude, city); - }, - () => { + async function getLocationByIP() { + try { + const res = await fetch("https://ipapi.co/json/"); + const data = await res.json(); + if (data.latitude && data.longitude) { + const city = data.city || await reverseGeocode(data.latitude, data.longitude); + fetchWeather(data.latitude, data.longitude, city); + } else { fetchWeather(defaultLat, defaultLon, defaultCity); - }, - { timeout: 5000 } - ); - } else { - fetchWeather(defaultLat, defaultLon, defaultCity); + } + } catch { + fetchWeather(defaultLat, defaultLon, defaultCity); + } } + + getLocationByIP(); }, []); if (loading) { @@ -125,3 +127,107 @@ export function WeatherWidget() { ); } + +export function SidebarWeatherWidget() { + const [weather, setWeather] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const defaultLat = 46.55; + const defaultLon = 14.55; + const defaultCity = "Klagenfurt"; + + async function fetchWeather(lat: number, lon: number, city: string) { + try { + const res = await fetch( + `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t=temperature_2m,weather_code,wind_speed_10m,relative_humidity_2m&daily=temperature_2m_max,temperature_2m_min,weather_code&timezone=auto&forecast_days=3` + ); + const data = await res.json(); + setWeather({ + temperature: Math.round(data.current.temperature_2m), + weatherCode: data.current.weather_code, + windSpeed: Math.round(data.current.wind_speed_10m), + humidity: data.current.relative_humidity_2m, + city, + }); + setForecast(data.daily ? data.daily.time.slice(1, 3).map((d: string, i: number) => ({ + day: new Date(d).toLocaleDateString("de-DE", { weekday: "short" }), + high: Math.round(data.daily.temperature_2m_max[i + 1]), + low: Math.round(data.daily.temperature_2m_min[i + 1]), + code: data.daily.weather_code[i + 1], + })) : []); + } catch { + } finally { + setLoading(false); + } + } + + async function getLocationByIP() { + try { + const res = await fetch("https://ipapi.co/json/"); + const ipData = await res.json(); + if (ipData.latitude && ipData.longitude) { + fetchWeather(ipData.latitude, ipData.longitude, ipData.city || "Unbekannt"); + } else { + fetchWeather(defaultLat, defaultLon, defaultCity); + } + } catch { + fetchWeather(defaultLat, defaultLon, defaultCity); + } + } + + getLocationByIP(); + }, []); + + const [forecast, setForecast] = useState<{ day: string; high: number; low: number; code: number }[]>([]); + + if (loading) { + return ( +
+
+
+ ); + } + + if (!weather) return null; + + return ( +
+
+
+ + {weather.city} +
+ + {new Date().toLocaleDateString("de-DE", { weekday: "short", day: "numeric", month: "short" })} + +
+ +
+
{getWeatherIcon(weather.weatherCode)}
+
+
{weather.temperature}°
+
{getWeatherText(weather.weatherCode)}
+
+
+ +
+ {weather.windSpeed} km/h + {weather.humidity}% +
+ + {forecast.length > 0 && ( +
+ {forecast.map((f) => ( +
+
{f.day}
+
{getWeatherIcon(f.code)}
+
{f.high}°
+
{f.low}°
+
+ ))} +
+ )} +
+ ); +} diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 0658fa3..1e239d1 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -12,7 +12,7 @@ import { PhotoGalleryWidget } from "@/components/photo-gallery"; import { HoroscopeWidget } from "@/components/horoscope-widget"; import { RecipeWidget } from "@/components/recipe-widget"; import { NewsWidget } from "@/components/news-widget"; -import { WeatherWidget } from "@/components/weather-widget"; +import { WeatherWidget, SidebarWeatherWidget } from "@/components/weather-widget"; import { BreakingNewsWidget } from "@/components/breaking-news-widget"; import { useState, useEffect, useCallback, useRef, useMemo } from "react"; @@ -587,8 +587,9 @@ export default function Home() {
)} -
+
{articles && articles.length > 0 && new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime()).slice(0, 5)} />} +