feat: add interactive daily forecast details

This commit is contained in:
zv
2026-06-02 15:31:36 +02:00
parent 352287bc38
commit d089a71bef
9 changed files with 368 additions and 15 deletions

View File

@@ -1,5 +1,6 @@
import type { Language, TranslationKey } from "@/lib/i18n";
import { translate } from "@/lib/i18n";
import type { HourlyForecast } from "@/types/forecast";
export function getForecastConditionKey(code: number | null): TranslationKey {
if (code === 0) return "forecast.condition.clear";
@@ -26,3 +27,38 @@ export function formatForecastRainfall(value: number | null, language: Language)
if (value === null) return "—";
return `${new Intl.NumberFormat(language === "pl" ? "pl-PL" : "en-GB", { maximumFractionDigits: 1 }).format(value)} mm`;
}
export function formatForecastWind(value: number | null, language: Language) {
if (value === null) return "—";
return `${new Intl.NumberFormat(language === "pl" ? "pl-PL" : "en-GB", {
minimumFractionDigits: 1,
maximumFractionDigits: 1,
}).format(value)} m/s`;
}
function getWarsawForecastHour(date = new Date()) {
const parts = new Intl.DateTimeFormat("en-CA", {
timeZone: "Europe/Warsaw",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
hourCycle: "h23",
}).formatToParts(date);
const getPart = (type: Intl.DateTimeFormatPartTypes) => parts.find((part) => part.type === type)?.value ?? "";
return `${getPart("year")}-${getPart("month")}-${getPart("day")}T${getPart("hour")}:00`;
}
export function getUpcomingHourlyForecast(hours: HourlyForecast[], limit = 24) {
const currentHour = getWarsawForecastHour();
return hours.filter((hour) => hour.time >= currentHour).slice(0, limit);
}
export function getHourlyForecastForDay(hours: HourlyForecast[], date: string) {
return hours.filter((hour) => hour.time.startsWith(`${date}T`));
}
export function isForecastHourPast(time: string) {
return time < getWarsawForecastHour();
}