strip more seamless and margin improvements

This commit is contained in:
Vincent van der Wal
2026-08-01 11:38:02 +02:00
parent 99c1a89537
commit a0379a1fd6
13 changed files with 706 additions and 188 deletions
+59
View File
@@ -273,6 +273,65 @@ export interface EnsembleForecastResult {
hourlyUnitsFlat: Record<string, string>;
}
// ─── Error Humanizing ───────────────────────────────────────────────────────────
export interface FriendlyWeatherError {
/** Short, plain-language headline. */
title: string;
/** What the user can actually do about it. */
hint?: string;
/** The raw underlying message, for a collapsed "technical details" block. */
detail?: string;
}
/**
* Turns a fetch/API error into something a person can act on. The raw message
* (often API-speak like "No data is available for this location") is kept as
* `detail` so it can be shown collapsed.
*/
export function humanizeWeatherError(err: unknown): FriendlyWeatherError {
const raw = err instanceof Error ? err.message : String(err);
const msg = raw.toLowerCase();
if (
err instanceof TypeError ||
msg.includes('failed to fetch') ||
msg.includes('networkerror') ||
msg.includes('load failed') ||
msg.includes('network request failed')
) {
return {
title: "Couldn't reach the weather service",
hint: 'Check your internet connection and try again.',
detail: raw
};
}
if (
msg.includes('no data is available') ||
msg.includes('not available for this location') ||
msg.includes('out of allowed range') ||
msg.includes('coordinates')
) {
return {
title: 'No data for this location with the selected model',
hint: 'Regional weather models only cover their own area — "Best match" picks a suitable model automatically.',
detail: raw
};
}
if (msg.includes('invalid') || msg.includes('cannot be') || msg.includes('bad request')) {
return {
title: 'The weather service rejected the request',
hint: 'Try different settings, or switch the model back to "Best match".',
detail: raw
};
}
return {
title: 'Loading the weather data failed',
hint: 'Try again in a moment. If it keeps happening, switch the model to "Best match".',
detail: raw
};
}
// ─── Week Forecast Fetch ────────────────────────────────────────────────────────
// Fallback set when the caller does not specify which hourly variables it