diff --git a/components/forecast/day-forecast-modal.tsx b/components/forecast/day-forecast-modal.tsx
index 708cdea..0d2e85e 100644
--- a/components/forecast/day-forecast-modal.tsx
+++ b/components/forecast/day-forecast-modal.tsx
@@ -14,6 +14,7 @@ import {
formatForecastTemperature,
formatForecastWind,
getForecastCondition,
+ isForecastNight,
} from "@/lib/forecast-utils";
import { useWeatherStore } from "@/lib/store";
import type { DailyForecast, ForecastSource, HourlyForecast } from "@/types/forecast";
@@ -156,7 +157,7 @@ export function DayForecastModal({
title={getForecastCondition(hour.weatherCode, language)}
>
{formatHour(hour.time)}
-
+
{formatForecastTemperature(hour.temperature, language, temperatureUnit)}
diff --git a/components/forecast/forecast-icon.tsx b/components/forecast/forecast-icon.tsx
index 191d167..309d0fe 100644
--- a/components/forecast/forecast-icon.tsx
+++ b/components/forecast/forecast-icon.tsx
@@ -1,8 +1,8 @@
-import { Cloud, CloudDrizzle, CloudFog, CloudLightning, CloudRain, CloudSnow, CloudSun, Sun } from "lucide-react";
+import { Cloud, CloudDrizzle, CloudFog, CloudLightning, CloudMoon, CloudRain, CloudSnow, CloudSun, MoonStar, Sun } from "lucide-react";
-export function ForecastIcon({ code, className = "" }: { code: number | null; className?: string }) {
- const Icon = code === 0 ? Sun
- : code === 1 || code === 2 ? CloudSun
+export function ForecastIcon({ code, className = "", isNight = false }: { code: number | null; className?: string; isNight?: boolean }) {
+ const Icon = code === 0 ? isNight ? MoonStar : Sun
+ : code === 1 || code === 2 ? isNight ? CloudMoon : CloudSun
: code === 45 || code === 48 ? CloudFog
: code !== null && code >= 51 && code <= 57 ? CloudDrizzle
: code !== null && ((code >= 61 && code <= 67) || (code >= 80 && code <= 82)) ? CloudRain
diff --git a/components/forecast/forecast-panel.tsx b/components/forecast/forecast-panel.tsx
index 9117cb2..8ea1c3b 100644
--- a/components/forecast/forecast-panel.tsx
+++ b/components/forecast/forecast-panel.tsx
@@ -17,9 +17,11 @@ import {
formatForecastRainfall,
formatForecastTemperature,
formatForecastWind,
+ getDailyForecastForHour,
getForecastCondition,
getHourlyForecastForDay,
getUpcomingHourlyForecast,
+ isForecastNight,
} from "@/lib/forecast-utils";
import { useWeatherStore } from "@/lib/store";
import type { DailyForecast, HourlyForecast } from "@/types/forecast";
@@ -153,35 +155,38 @@ export function ForecastPanel({ latitude, longitude, locationName }: { latitude?
{t("forecast.hourly")}
- {upcomingHours.map((hour, index) => (
-
- {formatHour(hour.time)}
-
- {formatForecastTemperature(hour.temperature, language, temperatureUnit)}
- {hour.precipitationProbability === null ? "—" : `${hour.precipitationProbability}%`}
-
-
-
- {formatForecastTemperature(hour.feelsLike, language, temperatureUnit)}
-
-
-
- {formatForecastWind(hour.windSpeed, language, windSpeedUnit)}
-
-
-
- {formatForecastRainfall(hour.precipitation, language)}
-
-
-
- ))}
+ {upcomingHours.map((hour, index) => {
+ const day = getDailyForecastForHour(forecast.daily, hour.time);
+ return (
+
+ {formatHour(hour.time)}
+
+ {formatForecastTemperature(hour.temperature, language, temperatureUnit)}
+ {hour.precipitationProbability === null ? "—" : `${hour.precipitationProbability}%`}
+
+
+
+ {formatForecastTemperature(hour.feelsLike, language, temperatureUnit)}
+
+
+
+ {formatForecastWind(hour.windSpeed, language, windSpeedUnit)}
+
+
+
+ {formatForecastRainfall(hour.precipitation, language)}
+
+
+
+ );
+ })}
diff --git a/lib/forecast-utils.ts b/lib/forecast-utils.ts
index c9a6621..90a95c3 100644
--- a/lib/forecast-utils.ts
+++ b/lib/forecast-utils.ts
@@ -1,7 +1,7 @@
import type { Language, TranslationKey } from "@/lib/i18n";
import { translate } from "@/lib/i18n";
import { DEFAULT_TEMPERATURE_UNIT, DEFAULT_WIND_SPEED_UNIT, formatTemperature, formatWindSpeed } from "@/lib/weather-utils";
-import type { HourlyForecast } from "@/types/forecast";
+import type { DailyForecast, HourlyForecast } from "@/types/forecast";
import type { TemperatureUnit, WindSpeedUnit } from "@/types/units";
export function getForecastConditionKey(code: number | null): TranslationKey {
@@ -89,6 +89,23 @@ export function getHourlyForecastForDay(hours: HourlyForecast[], date: string) {
return hours.filter((hour) => hour.time.startsWith(`${date}T`));
}
+export function getDailyForecastForHour(days: DailyForecast[], time: string) {
+ return days.find((day) => time.startsWith(`${day.date}T`)) ?? null;
+}
+
+export function isForecastNight(time: string, day: Pick | null | undefined) {
+ const hourTimestamp = parseForecastHour(time);
+ const sunriseTimestamp = day?.sunrise ? parseForecastHour(day.sunrise) : null;
+ const sunsetTimestamp = day?.sunset ? parseForecastHour(day.sunset) : null;
+
+ if (hourTimestamp !== null && sunriseTimestamp !== null && sunsetTimestamp !== null) {
+ return hourTimestamp < sunriseTimestamp || hourTimestamp >= sunsetTimestamp;
+ }
+
+ const hour = getForecastHourOfDay(time);
+ return hour !== null && (hour < 6 || hour >= 21);
+}
+
export function isForecastHourPast(time: string) {
const currentHour = getWarsawForecastHour();
const hourTimestamp = parseForecastHour(time);