feat: add weather unit preferences
Some checks failed
CI / Lint, test, typecheck and build (push) Has been cancelled
Some checks failed
CI / Lint, test, typecheck and build (push) Has been cancelled
This commit is contained in:
@@ -19,6 +19,8 @@ export function CurrentConditionsCard({ station }: { station: SynopStation }) {
|
||||
const { language, t } = useI18n();
|
||||
const temperatureUnit = useWeatherStore((state) => state.temperatureUnit);
|
||||
const windSpeedUnit = useWeatherStore((state) => state.windSpeedUnit);
|
||||
const precipitationUnit = useWeatherStore((state) => state.precipitationUnit);
|
||||
const pressureUnit = useWeatherStore((state) => state.pressureUnit);
|
||||
const feelsLike = calculateFeelsLike(station.temperature, station.humidity, station.windSpeed);
|
||||
const metrics = [
|
||||
{
|
||||
@@ -36,7 +38,7 @@ export function CurrentConditionsCard({ station }: { station: SynopStation }) {
|
||||
{
|
||||
icon: Gauge,
|
||||
label: t("weather.pressure"),
|
||||
value: formatPressure(station.pressure, language),
|
||||
value: formatPressure(station.pressure, language, pressureUnit),
|
||||
detail: t("weather.pressureDetail"),
|
||||
},
|
||||
{
|
||||
@@ -57,7 +59,7 @@ export function CurrentConditionsCard({ station }: { station: SynopStation }) {
|
||||
{
|
||||
icon: Umbrella,
|
||||
label: t("weather.rainfallTotal"),
|
||||
value: formatRainfall(station.rainfall, language),
|
||||
value: formatRainfall(station.rainfall, language, precipitationUnit),
|
||||
detail: t("weather.rainfallDetail"),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useLocationSearch } from "@/hooks/use-location-search";
|
||||
import { useI18n } from "@/lib/i18n";
|
||||
import { createSelectedLocation, locateSynopStations } from "@/lib/location-utils";
|
||||
import { useWeatherStore } from "@/lib/store";
|
||||
import { formatDistance } from "@/lib/weather-utils";
|
||||
import type { MeteoStationPosition, SynopStation } from "@/types/imgw";
|
||||
import type { SelectedLocation } from "@/types/location";
|
||||
|
||||
@@ -21,6 +22,7 @@ export function LocationSearch({
|
||||
const [query, setQuery] = useState("");
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const selectedLocation = useWeatherStore((state) => state.selectedLocation);
|
||||
const distanceUnit = useWeatherStore((state) => state.distanceUnit);
|
||||
const selectLocation = useWeatherStore((state) => state.selectLocation);
|
||||
const { data: locations, isFetching, isError } = useLocationSearch(query, language);
|
||||
const locatedStations = useMemo(() => locateSynopStations(stations, positions), [positions, stations]);
|
||||
@@ -112,7 +114,7 @@ export function LocationSearch({
|
||||
{t("location.nearest")}
|
||||
<br />
|
||||
<strong className="font-semibold text-foreground">
|
||||
{selected.stationName} · {selected.distanceKm} km
|
||||
{selected.stationName} · {formatDistance(selected.distanceKm, language, distanceUnit)}
|
||||
</strong>
|
||||
</span>
|
||||
) : (
|
||||
@@ -135,7 +137,7 @@ export function LocationSearch({
|
||||
? t("location.currentSource", {
|
||||
location: selectedLocation.name,
|
||||
station: selectedLocation.stationName,
|
||||
distance: selectedLocation.distanceKm,
|
||||
distance: formatDistance(selectedLocation.distanceKm, language, distanceUnit),
|
||||
})
|
||||
: t("location.currentSourceGlobal", { location: selectedLocation.name })}
|
||||
</p>
|
||||
|
||||
@@ -25,6 +25,7 @@ export function StationCard({ station, index = 0 }: { station: SynopStation; ind
|
||||
const selectStation = useWeatherStore((state) => state.selectStation);
|
||||
const temperatureUnit = useWeatherStore((state) => state.temperatureUnit);
|
||||
const windSpeedUnit = useWeatherStore((state) => state.windSpeedUnit);
|
||||
const pressureUnit = useWeatherStore((state) => state.pressureUnit);
|
||||
const favorite = favorites.includes(station.id);
|
||||
const mood = getWeatherMoodFromData(station);
|
||||
const compactWind = station.windSpeed === null ? "—" : formatWind(station.windSpeed, null, language, windSpeedUnit);
|
||||
@@ -77,7 +78,7 @@ export function StationCard({ station, index = 0 }: { station: SynopStation; ind
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<Gauge className="size-3" />
|
||||
{station.pressure === null ? "—" : formatPressure(station.pressure, language).split(" ")[0]}
|
||||
{station.pressure === null ? "—" : formatPressure(station.pressure, language, pressureUnit)}
|
||||
</span>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { AlertTriangle, Droplets, Gauge, MapPin, Navigation, Umbrella, Wind } fr
|
||||
import {
|
||||
calculateFeelsLike,
|
||||
formatDateTime,
|
||||
formatDistance,
|
||||
formatHumidity,
|
||||
formatPressure,
|
||||
formatRainfall,
|
||||
@@ -49,6 +50,9 @@ export function WeatherHero({
|
||||
const { language, t } = useI18n();
|
||||
const temperatureUnit = useWeatherStore((state) => state.temperatureUnit);
|
||||
const windSpeedUnit = useWeatherStore((state) => state.windSpeedUnit);
|
||||
const precipitationUnit = useWeatherStore((state) => state.precipitationUnit);
|
||||
const pressureUnit = useWeatherStore((state) => state.pressureUnit);
|
||||
const distanceUnit = useWeatherStore((state) => state.distanceUnit);
|
||||
const [devEffectOverride, setDevEffectOverride] = useState<DevWeatherEffectOverride | null>(null);
|
||||
const displayedLocationName = locationName ?? station.name;
|
||||
const hasGlobalModel = currentWeather?.coverage === "global-model";
|
||||
@@ -61,6 +65,7 @@ export function WeatherHero({
|
||||
distanceKm !== undefined &&
|
||||
distanceKm !== null &&
|
||||
distanceKm >= 30;
|
||||
const formattedDistance = formatDistance(distanceKm ?? null, language, distanceUnit);
|
||||
const displayedStation = currentWeather
|
||||
? {
|
||||
...station,
|
||||
@@ -91,9 +96,13 @@ export function WeatherHero({
|
||||
: currentWeather?.precipitation10m !== null && currentWeather?.precipitation10m !== undefined
|
||||
? t("weather.rainfall10m")
|
||||
: t("weather.rainfallTotal"),
|
||||
value: formatRainfall(displayedStation.rainfall, language),
|
||||
value: formatRainfall(displayedStation.rainfall, language, precipitationUnit),
|
||||
},
|
||||
{
|
||||
icon: Gauge,
|
||||
label: t("weather.pressure"),
|
||||
value: formatPressure(displayedStation.pressure, language, pressureUnit),
|
||||
},
|
||||
{ icon: Gauge, label: t("weather.pressure"), value: formatPressure(displayedStation.pressure, language) },
|
||||
];
|
||||
const effectPrecipitation10m =
|
||||
devEffectOverride === "rain" || devEffectOverride === "thunderstorm"
|
||||
@@ -149,16 +158,16 @@ export function WeatherHero({
|
||||
: hasFullHybridAnalysis
|
||||
? t("location.heroHybridSource", { location: displayedLocationName })
|
||||
: hasPartialHybridAnalysis
|
||||
? t("location.heroHybridPartial", { station: station.name, distance: distanceKm ?? 0 })
|
||||
? t("location.heroHybridPartial", { station: station.name, distance: formattedDistance })
|
||||
: locationName
|
||||
? t("location.heroStationFallbackWithDistance", {
|
||||
station: station.name,
|
||||
distance: distanceKm ?? 0,
|
||||
distance: formattedDistance,
|
||||
})
|
||||
: t("location.heroStationFallback", { station: station.name })}
|
||||
</p>
|
||||
{hasFullHybridAnalysis && locationName && (
|
||||
<p>{t("location.heroNearestStation", { station: station.name, distance: distanceKm ?? 0 })}</p>
|
||||
<p>{t("location.heroNearestStation", { station: station.name, distance: formattedDistance })}</p>
|
||||
)}
|
||||
{hasDistantFallback && (
|
||||
<p className="flex items-start gap-1.5 text-warning">
|
||||
|
||||
Reference in New Issue
Block a user