use-weather-forecast 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# use-weather-forecast
|
|
2
2
|
|
|
3
|
-
React weather forecast component using Open-Meteo for current, hourly, and daily forecasts and Cloudflare/
|
|
3
|
+
React weather forecast component using Open-Meteo for current, hourly, and daily forecasts and Cloudflare/ipapi.co for IP geolocation.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -62,12 +62,14 @@ This package no longer uses ipinfo.io. Instead:
|
|
|
62
62
|
|
|
63
63
|
- Pass `geoEndpoint` pointing at a deployed instance of the bundled Cloudflare Worker
|
|
64
64
|
(`worker/geo-worker.ts`) for accurate results. The worker reads Cloudflare's built-in
|
|
65
|
-
geolocation (`request.cf`) for the visitor's own IP, and falls back to `
|
|
65
|
+
geolocation (`request.cf`) for the visitor's own IP, and falls back to `ipapi.co`
|
|
66
66
|
when a `?ip=` query param (or the `ip` prop) is supplied for an arbitrary address.
|
|
67
|
-
- If `geoEndpoint` is omitted, the package falls back to calling `
|
|
68
|
-
from the browser.
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
- If `geoEndpoint` is omitted, the package falls back to calling `ipapi.co` directly
|
|
68
|
+
from the browser (`https://ipapi.co/json/`, or `https://ipapi.co/<ip>/json/` when an
|
|
69
|
+
`ip` is supplied). Unlike the previous ip-api.com fallback, this works over HTTPS with
|
|
70
|
+
no mixed-content issues, though ipapi.co's free tier is rate-limited (1,000
|
|
71
|
+
requests/day) — deploy the worker and pass `geoEndpoint` for higher-volume or
|
|
72
|
+
production use.
|
|
71
73
|
|
|
72
74
|
### Deploying the geo worker
|
|
73
75
|
|
|
@@ -82,4 +84,4 @@ This deploys `worker/geo-worker.ts` via Wrangler. Use the resulting `*.workers.d
|
|
|
82
84
|
## Notes
|
|
83
85
|
|
|
84
86
|
- Open-Meteo powers the forecast data.
|
|
85
|
-
- Cloudflare's `request.cf` and
|
|
87
|
+
- Cloudflare's `request.cf` and ipapi.co power IP geolocation (see above).
|
package/dist/index.cjs
CHANGED
|
@@ -45,7 +45,7 @@ function getWeatherIcon(code, isDay = 1) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// src/api/geolocation.ts
|
|
48
|
-
var DEFAULT_IP_API_URL = "
|
|
48
|
+
var DEFAULT_IP_API_URL = "https://ipapi.co";
|
|
49
49
|
async function getClientLocation(geoEndpoint, ip) {
|
|
50
50
|
if (geoEndpoint) {
|
|
51
51
|
const url = ip ? `${geoEndpoint}?ip=${encodeURIComponent(ip)}` : geoEndpoint;
|
|
@@ -61,19 +61,19 @@ async function getClientLocation(geoEndpoint, ip) {
|
|
|
61
61
|
longitude: Number(data2.longitude)
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
-
const res = await fetch(`${DEFAULT_IP_API_URL}
|
|
65
|
-
if (!res.ok) throw new Error(`
|
|
64
|
+
const res = await fetch(`${DEFAULT_IP_API_URL}/${ip ? `${encodeURIComponent(ip)}/` : ""}json/`);
|
|
65
|
+
if (!res.ok) throw new Error(`ipapi.co lookup failed: ${res.status}`);
|
|
66
66
|
const data = await res.json();
|
|
67
|
-
if (data.
|
|
68
|
-
throw new Error(`
|
|
67
|
+
if (data.error) {
|
|
68
|
+
throw new Error(`ipapi.co lookup failed: ${data.reason ?? "unknown error"}`);
|
|
69
69
|
}
|
|
70
70
|
return {
|
|
71
71
|
city: data.city,
|
|
72
|
-
region: data.
|
|
73
|
-
country: data.
|
|
72
|
+
region: data.region,
|
|
73
|
+
country: data.country_name,
|
|
74
74
|
timezone: data.timezone,
|
|
75
|
-
latitude: Number(data.
|
|
76
|
-
longitude: Number(data.
|
|
75
|
+
latitude: Number(data.latitude),
|
|
76
|
+
longitude: Number(data.longitude)
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/weatherCodes.ts","../src/api/geolocation.ts","../src/api/forecast.ts","../src/hooks/useWeatherForecast.ts","../src/icons/BaseIcon.tsx","../src/icons/weather-icons.tsx","../src/icons/WeatherIcon.tsx","../src/components/WeatherForecast.tsx"],"sourcesContent":["export * from './types';\nexport * from './weatherCodes';\nexport * from './api/geolocation';\nexport * from './api/forecast';\nexport * from './hooks/useWeatherForecast';\nexport * from './icons/WeatherIcon';\nexport * from './components/WeatherForecast';\n","import type { WeatherCondition } from './types';\n\nexport function getWeatherIcon(code: number, isDay = 1): WeatherCondition {\n if (code === 0) return 'sun';\n if ([1, 2].includes(code)) return isDay ? 'cloud-sun' : 'clouds';\n if (code === 3) return 'clouds';\n if ([45, 48].includes(code)) return 'cloud-fog';\n if ([51, 53, 55, 56, 57].includes(code)) return 'cloud-drizzle';\n if ([61, 63].includes(code)) return 'cloud-showers';\n if ([65, 66, 67, 80, 81, 82].includes(code)) return 'cloud-showers-heavy';\n if ([71, 73, 75, 77, 85, 86].includes(code)) return 'cloud-snow';\n if (code === 95) return 'cloud-bolt';\n if ([96, 99].includes(code)) return 'cloud-hail';\n return 'clouds';\n}\n","import type { WeatherLocation } from '../types';\n\n// ip-api.com's free tier only serves plain HTTP (HTTPS requires their paid plan),\n// so this default will be blocked as mixed content on pages served over HTTPS.\n// Deploy worker/geo-worker.ts and pass its URL as `geoEndpoint` to avoid that.\nconst DEFAULT_IP_API_URL = 'http://ip-api.com/json/';\n\ntype IpApiResponse = {\n status: 'success' | 'fail';\n city?: string;\n regionName?: string;\n country?: string;\n timezone?: string;\n lat?: number;\n lon?: number;\n message?: string;\n};\n\ntype GeoWorkerResponse = {\n city?: string;\n region?: string;\n country?: string;\n timezone?: string;\n latitude?: number | string;\n longitude?: number | string;\n};\n\nexport async function getClientLocation(geoEndpoint?: string, ip?: string): Promise<WeatherLocation> {\n if (geoEndpoint) {\n const url = ip ? `${geoEndpoint}?ip=${encodeURIComponent(ip)}` : geoEndpoint;\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Geolocation worker lookup failed: ${res.status}`);\n const data: GeoWorkerResponse = await res.json();\n\n return {\n city: data.city,\n region: data.region,\n country: data.country,\n timezone: data.timezone,\n latitude: Number(data.latitude),\n longitude: Number(data.longitude),\n };\n }\n\n const res = await fetch(`${DEFAULT_IP_API_URL}${ip ? encodeURIComponent(ip) : ''}`);\n if (!res.ok) throw new Error(`ip-api lookup failed: ${res.status}`);\n const data: IpApiResponse = await res.json();\n\n if (data.status === 'fail') {\n throw new Error(`ip-api lookup failed: ${data.message ?? 'unknown error'}`);\n }\n\n return {\n city: data.city,\n region: data.regionName,\n country: data.country,\n timezone: data.timezone,\n latitude: Number(data.lat),\n longitude: Number(data.lon),\n };\n}\n","import type { WeatherForecastData, WeatherForecastOptions, WeatherLocation } from '../types';\nimport { getWeatherIcon } from '../weatherCodes';\nimport { getClientLocation } from './geolocation';\n\nfunction buildUrl(latitude: number, longitude: number, options: WeatherForecastOptions) {\n const params = new URLSearchParams({\n latitude: String(latitude),\n longitude: String(longitude),\n timezone: options.location?.timezone || 'auto',\n temperature_unit: options.temperatureUnit || 'fahrenheit',\n wind_speed_unit: options.windSpeedUnit || 'mph',\n forecast_days: String(options.forecastDays ?? 5),\n forecast_hours: String(options.forecastHours ?? 24),\n current: [\n 'temperature_2m',\n 'weather_code',\n 'is_day',\n 'rain',\n 'showers',\n 'snowfall',\n 'wind_speed_10m',\n ].join(','),\n hourly: [\n 'temperature_2m',\n 'weather_code',\n 'precipitation_probability',\n 'rain',\n 'showers',\n 'snowfall',\n ].join(','),\n daily: [\n 'temperature_2m_max',\n 'temperature_2m_min',\n 'weather_code',\n 'precipitation_probability_max',\n ].join(','),\n });\n\n return `https://api.open-meteo.com/v1/forecast?${params.toString()}`;\n}\n\nexport async function getWeatherForecast(\n options: WeatherForecastOptions = {}\n): Promise<WeatherForecastData> {\n let location: WeatherLocation;\n\n if (typeof options.latitude === 'number' && typeof options.longitude === 'number') {\n location = {\n ...options.location,\n latitude: options.latitude,\n longitude: options.longitude,\n };\n } else {\n location = await getClientLocation(options.geoEndpoint, options.ip);\n }\n\n const url = buildUrl(location.latitude, location.longitude, { ...options, location });\n const response = await fetch(url, { headers: { 'Content-Type': 'application/json' } });\n\n if (!response.ok) {\n throw new Error(`Weather request failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n\n if (!data?.current || !data?.hourly || !data?.daily) {\n throw new Error('Invalid weather response');\n }\n\n return {\n location,\n current: {\n time: data.current.time,\n temperature: Math.round(data.current.temperature_2m),\n weatherCode: data.current.weather_code,\n icon: getWeatherIcon(data.current.weather_code, data.current.is_day),\n isDay: data.current.is_day,\n rain: data.current.rain,\n showers: data.current.showers,\n snowfall: data.current.snowfall,\n windSpeed: data.current.wind_speed_10m,\n },\n hourly: data.hourly.time.map((time: string, index: number) => ({\n time,\n temperature: Math.round(data.hourly.temperature_2m[index]),\n weatherCode: data.hourly.weather_code[index],\n precipitationProbability: data.hourly.precipitation_probability?.[index],\n rain: data.hourly.rain?.[index],\n showers: data.hourly.showers?.[index],\n snowfall: data.hourly.snowfall?.[index],\n icon: getWeatherIcon(data.hourly.weather_code[index]),\n })),\n daily: data.daily.time.map((date: string, index: number) => ({\n date,\n min: Math.round(data.daily.temperature_2m_min[index]),\n max: Math.round(data.daily.temperature_2m_max[index]),\n weatherCode: data.daily.weather_code[index],\n precipitationProbabilityMax: data.daily.precipitation_probability_max?.[index],\n icon: getWeatherIcon(data.daily.weather_code[index]),\n })),\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { WeatherForecastData, WeatherForecastOptions } from '../types';\nimport { getWeatherForecast } from '../api/forecast';\n\nexport function useWeatherForecast(options: WeatherForecastOptions = {}) {\n const [data, setData] = useState<WeatherForecastData | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let active = true;\n setLoading(true);\n setError(null);\n\n getWeatherForecast(options)\n .then((result) => { if (active) setData(result); })\n .catch((err) => { if (active) setError(err instanceof Error ? err : new Error('Unknown error')); })\n .finally(() => { if (active) setLoading(false); });\n\n return () => { active = false; };\n }, [\n options.latitude,\n options.longitude,\n options.geoEndpoint,\n options.ip,\n options.forecastDays,\n options.forecastHours,\n options.temperatureUnit,\n options.windSpeedUnit,\n options.location?.timezone,\n ]);\n\n return { data, error, loading };\n}\n","import React from 'react';\nimport type { IconProps } from '../types';\n\nexport function BaseIcon({ title, children, ...props }: IconProps & { children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n role={title ? 'img' : 'presentation'}\n aria-hidden={title ? undefined : true}\n aria-label={title}\n {...props}\n >\n {title ? <title>{title}</title> : null}\n {children}\n </svg>\n );\n}\n","import React from 'react';\nimport type { IconProps } from '../types';\nimport { BaseIcon } from './BaseIcon';\n\nexport const CloudBoltIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M7 18a4.815 4.815 0 0 1-3.327-1.318A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 0 7h-1m-4.75-5L11 17.5h3.375l-2.25 4.5\" /></BaseIcon>\n);\nexport const CloudDrizzleIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M12 18v1m-3-4v1m6-1v1m2 3v1M7 19v1m-3-3.034a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662\" /></BaseIcon>\n);\nexport const CloudFogIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M5 21h7m4 0h3M8 17h8\" /></BaseIcon>\n);\nexport const CloudHailIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8 17.45v.1m-1.5 3.9v.1m10.5-4.1v.1m-1.5 3.9v.1m-3-4.1v.1m-1.5 3.9v.1m10.475-4.575A3.5 3.5 0 0 0 19 11h-1c.146-.65.148-1.32.006-1.97a4.784 4.784 0 0 0-.831-1.823 5.36 5.36 0 0 0-1.544-1.398 5.964 5.964 0 0 0-2.02-.759 6.224 6.224 0 0 0-2.19-.006 5.971 5.971 0 0 0-2.024.749C8.157 6.533 7.295 7.687 7 9a4.815 4.815 0 0 0-3.327 1.318A4.403 4.403 0 0 0 2.295 13.5c0 1.194.496 2.338 1.378 3.182.105.1.214.195.327.284m4.5.534a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm10.5-4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-3-4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Z\" /></BaseIcon>\n);\nexport const CloudShowersIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M12 13v2m0 3v2m4-5v2m0 3v2m-8-7v2m0 3v2\" /></BaseIcon>\n);\nexport const CloudShowersHeavyIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M16 15v6m-8-6v6m4-8v6\" /></BaseIcon>\n);\nexport const CloudSleetIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M13.5 17.45a1 1 0 1 0-2 0h2Zm-2 .1a1 1 0 1 0 2 0h-2Zm.5 3.9a1 1 0 1 0-2 0h2Zm-2 .1a1 1 0 1 0 2 0h-2Zm-6.327-4.868.692-.723-.692.723ZM7 9v1a1 1 0 0 0 .976-.781L7 9Zm2.397-3.207.512.858-.512-.858ZM18 11l-.976-.219A1 1 0 0 0 18 12v-1Zm2.768 5.268a1 1 0 0 0 1.414 1.414l-.707-.707-.707-.707ZM3.379 17.75a1 1 0 0 0 1.242-1.567L4 16.966l-.62.784Zm5.55-.379a1 1 0 0 0-1.857-.742L8 17l.928.371ZM5.071 21.63a1 1 0 0 0 1.856.742L6 22l-.928-.371Zm13.857-4.258a1 1 0 0 0-1.857-.742L18 17l.928.371Zm-3.857 4.258a1 1 0 0 0 1.857.742L16 22l-.928-.371ZM13 17.5h-1a.5.5 0 0 1 .5-.5v2a1.5 1.5 0 0 0 1.5-1.5h-1Zm-.5.5v-1a.5.5 0 0 1 .5.5h-2a1.5 1.5 0 0 0 1.5 1.5v-1Zm-.5-.5h1a.5.5 0 0 1-.5.5v-2a1.5 1.5 0 0 0-1.5 1.5h1Zm.5-.5v1a.5.5 0 0 1-.5-.5h2a1.5 1.5 0 0 0-1.5-1.5v1Zm0 .45h-1v.1h2v-.1h-1Zm-1 4.05h-1a.5.5 0 0 1 .5-.5v2a1.5 1.5 0 0 0 1.5-1.5h-1Zm-.5.5v-1a.5.5 0 0 1 .5.5h-2A1.5 1.5 0 0 0 11 23v-1Zm-.5-.5h1a.5.5 0 0 1-.5.5v-2a1.5 1.5 0 0 0-1.5 1.5h1Zm.5-.5v1a.5.5 0 0 1-.5-.5h2A1.5 1.5 0 0 0 11 20v1Zm0 .45h-1v.1h2v-.1h-1Zm-7.327-4.768.692-.723a3.403 3.403 0 0 1-1.07-2.459h-2c0 1.473.613 2.877 1.687 3.905l.691-.723ZM2.295 13.5h1c0-.914.38-1.8 1.07-2.46l-.692-.722-.69-.723A5.403 5.403 0 0 0 1.294 13.5h1Zm1.378-3.182.692.723A3.815 3.815 0 0 1 7 10V8c-1.499 0-2.945.57-4.018 1.595l.691.723ZM7 9l.976.219c.23-1.024.91-1.956 1.933-2.568l-.512-.858-.513-.859c-1.456.87-2.5 2.245-2.86 3.847L7 9Zm2.397-3.207.512.858a4.972 4.972 0 0 1 1.686-.622l-.173-.985-.174-.985a6.971 6.971 0 0 0-2.364.875l.513.859Zm2.025-.749.173.985a5.223 5.223 0 0 1 1.837.005l.18-.984.178-.984a7.223 7.223 0 0 0-2.542-.007l.174.985Zm2.19.006-.18.984c.606.11 1.177.326 1.681.631l.518-.856.518-.855a6.963 6.963 0 0 0-2.359-.888l-.179.984Zm2.02.76-.519.855c.505.305.93.693 1.257 1.136l.805-.594.805-.594a6.361 6.361 0 0 0-1.831-1.659l-.518.855Zm1.543 1.397-.805.594c.326.442.549.932.66 1.441l.976-.212.978-.213a5.786 5.786 0 0 0-1.005-2.204l-.804.594Zm.831 1.823-.977.212c.111.509.11 1.031-.005 1.539L18 11l.976.219c.178-.792.18-1.609.008-2.402l-.978.213ZM18 11v1h1v-2h-1v1Zm1 0v1a2.5 2.5 0 0 1 1.768.732l.707-.707.707-.707A4.5 4.5 0 0 0 19 10v1Zm2.475 1.025-.707.707A2.5 2.5 0 0 1 21.5 14.5h2a4.5 4.5 0 0 0-1.318-3.182l-.707.707ZM22.5 14.5h-1a2.5 2.5 0 0 1-.732 1.768l.707.707.707.707A4.5 4.5 0 0 0 23.5 14.5h-1ZM4 16.966l.62-.784a3.684 3.684 0 0 1-.255-.223l-.692.723-.69.723c.126.121.259.237.396.345L4 16.966ZM8 17l-.928-.371-2 5L6 22l.928.371 2-5L8 17Zm10 0-.928-.371-2 5L16 22l.928.371 2-5L18 17Z\" /></BaseIcon>\n);\nexport const CloudSnowIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8 15h2m-1-1v2m5-1h2m-1-1v2M5 21h2m-1-1v2m5-2h2m-1-1v2m5 0h2m-1-1v2M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662\" /></BaseIcon>\n);\nexport const CloudSunIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M10.201 19.997c-1.977 0-3.58-1.544-3.58-3.448 0-1.903 1.603-3.446 3.58-3.446.303-1.355 1.38-2.461 2.827-2.902 1.445-.44 3.042-.148 4.186.77 1.144.915 1.663 2.312 1.361 3.667h.761c1.472 0 2.664 1.2 2.664 2.68A2.672 2.672 0 0 1 19.336 20h-9.134m2.66-12.934a4.166 4.166 0 0 0-2.677-1.732m2.677 1.732 2.744-1.892m-2.744 1.892c.55.796.802 1.754.723 2.709m-3.4-4.44a4.167 4.167 0 0 0-3.118.667m3.118-.668.602-3.278m-3.72 3.946A4.167 4.167 0 0 0 5.334 8.68m1.733-2.678L5.174 3.26m.16 5.42c-.2 1.088.041 2.21.669 3.12m-.669-3.12-3.278-.601m3.947 3.72-2.744 1.893m2.744-1.893a4.167 4.167 0 0 0 2.174 1.607\" /></BaseIcon>\n);\nexport const CloudsIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8.958 21.05C6.772 21.05 5 19.344 5 17.24s1.772-3.81 3.958-3.81c.335-1.498 1.525-2.72 3.124-3.207 1.598-.487 3.363-.164 4.628.85 1.264 1.011 1.837 2.556 1.504 4.053h.842A2.953 2.953 0 0 1 22 18.09a2.954 2.954 0 0 1-2.945 2.964H8.958M18 8c-.5-2.5-3.532-3.401-5.5-2.5a3.117 3.117 0 0 0-2.11-2.312c-1.352-.411-2.845-.138-3.915.72-1.07.855-1.554 2.161-1.273 3.428h-.711A2.498 2.498 0 0 0 2 9.843c0 1.094.695 2.023 1.666 2.366\" /></BaseIcon>\n);\nexport const SnowflakeIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"m9.25 4-1 2H6m-2.25 4L5 12m0 0-1.25 2M5 12h3m-3 0H2.5m17.75-2L19 12l1.25 2M6 18h2.25l1 2M14 9h-4m4 0 3-5m-3 5 2 3m-6-3L7 4m3 5-2 3m0 0 2 3m0 0-3 5m3-5h4m2-3-2 3m2-3h5.5M14 15l3 5M14.75 4l1 2H18m0 12h-2.25l-1 2\" /></BaseIcon>\n);\nexport const SunIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M12 4V2m0 20v-2m10-8h-2M4 12H2m15.657-5.657 1.414-1.414M4.93 19.07l1.414-1.414m12.728 1.414-1.414-1.414M6.343 6.343 4.93 4.929M7 12a5 5 0 1 0 10 0 5 5 0 0 0-10 0Z\" /></BaseIcon>\n);\nexport const WindIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M9.59 4.59A2 2 0 1 1 11 8H2m10.59 11.41A2 2 0 1 0 14 16H2m15.73-8.27A2.5 2.5 0 1 1 19.5 12H2\" /></BaseIcon>\n);\n","import React from 'react';\nimport type { IconProps, WeatherCondition } from '../types';\nimport {\n CloudBoltIcon,\n CloudDrizzleIcon,\n CloudFogIcon,\n CloudHailIcon,\n CloudShowersHeavyIcon,\n CloudShowersIcon,\n CloudSleetIcon,\n CloudSnowIcon,\n CloudSunIcon,\n CloudsIcon,\n SnowflakeIcon,\n SunIcon,\n} from './weather-icons';\n\nconst iconMap: Record<WeatherCondition, React.ComponentType<IconProps>> = {\n sun: SunIcon,\n 'cloud-sun': CloudSunIcon,\n clouds: CloudsIcon,\n 'cloud-fog': CloudFogIcon,\n 'cloud-drizzle': CloudDrizzleIcon,\n 'cloud-showers': CloudShowersIcon,\n 'cloud-showers-heavy': CloudShowersHeavyIcon,\n 'cloud-sleet': CloudSleetIcon,\n 'cloud-snow': CloudSnowIcon,\n snowflake: SnowflakeIcon,\n 'cloud-bolt': CloudBoltIcon,\n 'cloud-hail': CloudHailIcon,\n};\n\nexport function WeatherIcon({ condition, ...props }: IconProps & { condition: WeatherCondition }) {\n const Icon = iconMap[condition] || CloudsIcon;\n return <Icon {...props} />;\n}\n","import React from 'react';\nimport { useWeatherForecast } from '../hooks/useWeatherForecast';\nimport type { HourlyWeather, WeatherForecastOptions, WindSpeedUnit } from '../types';\nimport { WeatherIcon } from '../icons/WeatherIcon';\nimport { WindIcon } from '../icons/weather-icons';\n\ntype Props = WeatherForecastOptions & {\n className?: string;\n style?: React.CSSProperties;\n compact?: boolean;\n};\n\nconst WIND_SPEED_UNIT_LABELS: Record<WindSpeedUnit, string> = {\n kmh: 'km/h',\n mph: 'mph',\n ms: 'm/s',\n kn: 'kn',\n};\n\nfunction closestHour(hourly: HourlyWeather[], targetTime: Date): HourlyWeather | undefined {\n return hourly.reduce<HourlyWeather | undefined>((closest, hour) => {\n const diff = Math.abs(new Date(hour.time).getTime() - targetTime.getTime());\n const closestDiff = closest ? Math.abs(new Date(closest.time).getTime() - targetTime.getTime()) : Infinity;\n return diff < closestDiff ? hour : closest;\n }, undefined);\n}\n\nconst styles = {\n root: {\n fontFamily: 'system-ui, sans-serif',\n border: '1px solid #e5e7eb',\n borderRadius: 12,\n padding: 16,\n background: '#fff',\n color: '#111827',\n maxWidth: 640,\n } as React.CSSProperties,\n row: { display: 'flex', alignItems: 'center', gap: 8 } as React.CSSProperties,\n hours: { display: 'flex', gap: 12, overflowX: 'auto', paddingBottom: 4 } as React.CSSProperties,\n hourCard: { minWidth: 72, textAlign: 'center' as const, padding: 8, borderRadius: 8, background: '#f9fafb' },\n dayRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, padding: '8px 0', borderBottom: '1px solid #f3f4f6' } as React.CSSProperties,\n compactRoot: { fontFamily: 'system-ui, sans-serif', display: 'flex', flexDirection: 'column', gap: 8, padding: '10px 14px', borderRadius: 8 } as React.CSSProperties,\n compactHeader: { display: 'flex', alignItems: 'center', gap: 10 } as React.CSSProperties,\n compactHeaderText: { display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' } as React.CSSProperties,\n compactDateTime: { fontSize: 11, opacity: 0.7 } as React.CSSProperties,\n compactStats: { display: 'flex', flexWrap: 'wrap', gap: 12, fontSize: 12, opacity: 0.9 } as React.CSSProperties,\n compactStat: { display: 'flex', alignItems: 'center', gap: 4, whiteSpace: 'nowrap' } as React.CSSProperties,\n};\n\nexport function WeatherForecast(props: Props) {\n const { data, loading, error } = useWeatherForecast(props);\n\n if (loading) return null;\n if (error) return <div className={props.className} style={props.style}>Error: {error.message}</div>;\n if (!data) return <div className={props.className} style={props.style}>No forecast available.</div>;\n\n if (props.compact) {\n const now = new Date(data.current.time);\n const today = data.daily[0];\n const tomorrow = data.daily[1];\n const in6Hours = closestHour(data.hourly, new Date(now.getTime() + 6 * 60 * 60 * 1000));\n const windSpeedUnitLabel = WIND_SPEED_UNIT_LABELS[props.windSpeedUnit ?? 'mph'];\n\n return (\n <div className={props.className} style={{ ...styles.compactRoot, ...props.style }}>\n <div style={styles.compactHeader}>\n <WeatherIcon condition={data.current.icon} width={24} height={24} title=\"Current weather\" />\n <div>\n <div style={styles.compactHeaderText}>\n <strong style={{ fontSize: 16 }}>{data.current.temperature}°</strong>\n <span style={{ fontSize: 14, opacity: 0.8 }}>\n {data.location?.city || 'Current location'}\n </span>\n </div>\n <div style={styles.compactDateTime}>\n {now.toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}\n {' · '}\n {now.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })}\n </div>\n </div>\n </div>\n\n <div style={styles.compactStats}>\n {today && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={today.icon} width={16} height={16} title=\"Today's high and low\" />\n {today.max}° / {today.min}°\n </span>\n )}\n {tomorrow && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={tomorrow.icon} width={16} height={16} title=\"Tomorrow\" />\n Tomorrow {tomorrow.max}°\n </span>\n )}\n <span style={styles.compactStat}>\n <WindIcon width={16} height={16} title=\"Wind speed\" />\n {data.current.windSpeed !== undefined ? `${Math.round(data.current.windSpeed)} ${windSpeedUnitLabel}` : '—'}\n </span>\n {in6Hours && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={in6Hours.icon} width={16} height={16} title=\"In 6 hours\" />\n {in6Hours.temperature}° in 6h\n </span>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div className={props.className} style={{ ...styles.root, ...props.style }}>\n <div>\n <h3 style={{ margin: 0, fontSize: 20 }}>\n {data.location?.city || 'Current location'}\n {data.location?.region ? `, ${data.location.region}` : ''}\n </h3>\n <div style={{ ...styles.row, marginTop: 8 }}>\n <WeatherIcon condition={data.current.icon} width={28} height={28} title=\"Current weather\" />\n <strong style={{ fontSize: 28 }}>{data.current.temperature}°</strong>\n </div>\n </div>\n\n <div style={{ marginTop: 20 }}>\n <h4 style={{ margin: '0 0 10px 0' }}>Next hours</h4>\n <div style={styles.hours}>\n {data.hourly.slice(0, props.forecastHours ?? 12).map((hour) => (\n <div key={hour.time} style={styles.hourCard}>\n <div style={{ fontSize: 12 }}>{new Date(hour.time).toLocaleTimeString([], { hour: 'numeric' })}</div>\n <WeatherIcon condition={hour.icon} width={20} height={20} style={{ margin: '6px auto' }} />\n <div>{hour.temperature}°</div>\n </div>\n ))}\n </div>\n </div>\n\n <div style={{ marginTop: 20 }}>\n <h4 style={{ margin: '0 0 10px 0' }}>Next days</h4>\n <div>\n {data.daily.map((day) => (\n <div key={day.date} style={styles.dayRow}>\n <div style={{ width: 120 }}>{new Date(day.date).toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}</div>\n <WeatherIcon condition={day.icon} width={20} height={20} />\n <div>{day.min}° / {day.max}°</div>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["res","data","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/weatherCodes.ts","../src/api/geolocation.ts","../src/api/forecast.ts","../src/hooks/useWeatherForecast.ts","../src/icons/BaseIcon.tsx","../src/icons/weather-icons.tsx","../src/icons/WeatherIcon.tsx","../src/components/WeatherForecast.tsx"],"sourcesContent":["export * from './types';\nexport * from './weatherCodes';\nexport * from './api/geolocation';\nexport * from './api/forecast';\nexport * from './hooks/useWeatherForecast';\nexport * from './icons/WeatherIcon';\nexport * from './components/WeatherForecast';\n","import type { WeatherCondition } from './types';\n\nexport function getWeatherIcon(code: number, isDay = 1): WeatherCondition {\n if (code === 0) return 'sun';\n if ([1, 2].includes(code)) return isDay ? 'cloud-sun' : 'clouds';\n if (code === 3) return 'clouds';\n if ([45, 48].includes(code)) return 'cloud-fog';\n if ([51, 53, 55, 56, 57].includes(code)) return 'cloud-drizzle';\n if ([61, 63].includes(code)) return 'cloud-showers';\n if ([65, 66, 67, 80, 81, 82].includes(code)) return 'cloud-showers-heavy';\n if ([71, 73, 75, 77, 85, 86].includes(code)) return 'cloud-snow';\n if (code === 95) return 'cloud-bolt';\n if ([96, 99].includes(code)) return 'cloud-hail';\n return 'clouds';\n}\n","import type { WeatherLocation } from '../types';\n\nconst DEFAULT_IP_API_URL = 'https://ipapi.co';\n\ntype IpApiResponse = {\n city?: string;\n region?: string;\n country_name?: string;\n timezone?: string;\n latitude?: number;\n longitude?: number;\n error?: boolean;\n reason?: string;\n};\n\ntype GeoWorkerResponse = {\n city?: string;\n region?: string;\n country?: string;\n timezone?: string;\n latitude?: number | string;\n longitude?: number | string;\n};\n\nexport async function getClientLocation(geoEndpoint?: string, ip?: string): Promise<WeatherLocation> {\n if (geoEndpoint) {\n const url = ip ? `${geoEndpoint}?ip=${encodeURIComponent(ip)}` : geoEndpoint;\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Geolocation worker lookup failed: ${res.status}`);\n const data: GeoWorkerResponse = await res.json();\n\n return {\n city: data.city,\n region: data.region,\n country: data.country,\n timezone: data.timezone,\n latitude: Number(data.latitude),\n longitude: Number(data.longitude),\n };\n }\n\n const res = await fetch(`${DEFAULT_IP_API_URL}/${ip ? `${encodeURIComponent(ip)}/` : ''}json/`);\n if (!res.ok) throw new Error(`ipapi.co lookup failed: ${res.status}`);\n const data: IpApiResponse = await res.json();\n\n if (data.error) {\n throw new Error(`ipapi.co lookup failed: ${data.reason ?? 'unknown error'}`);\n }\n\n return {\n city: data.city,\n region: data.region,\n country: data.country_name,\n timezone: data.timezone,\n latitude: Number(data.latitude),\n longitude: Number(data.longitude),\n };\n}\n","import type { WeatherForecastData, WeatherForecastOptions, WeatherLocation } from '../types';\nimport { getWeatherIcon } from '../weatherCodes';\nimport { getClientLocation } from './geolocation';\n\nfunction buildUrl(latitude: number, longitude: number, options: WeatherForecastOptions) {\n const params = new URLSearchParams({\n latitude: String(latitude),\n longitude: String(longitude),\n timezone: options.location?.timezone || 'auto',\n temperature_unit: options.temperatureUnit || 'fahrenheit',\n wind_speed_unit: options.windSpeedUnit || 'mph',\n forecast_days: String(options.forecastDays ?? 5),\n forecast_hours: String(options.forecastHours ?? 24),\n current: [\n 'temperature_2m',\n 'weather_code',\n 'is_day',\n 'rain',\n 'showers',\n 'snowfall',\n 'wind_speed_10m',\n ].join(','),\n hourly: [\n 'temperature_2m',\n 'weather_code',\n 'precipitation_probability',\n 'rain',\n 'showers',\n 'snowfall',\n ].join(','),\n daily: [\n 'temperature_2m_max',\n 'temperature_2m_min',\n 'weather_code',\n 'precipitation_probability_max',\n ].join(','),\n });\n\n return `https://api.open-meteo.com/v1/forecast?${params.toString()}`;\n}\n\nexport async function getWeatherForecast(\n options: WeatherForecastOptions = {}\n): Promise<WeatherForecastData> {\n let location: WeatherLocation;\n\n if (typeof options.latitude === 'number' && typeof options.longitude === 'number') {\n location = {\n ...options.location,\n latitude: options.latitude,\n longitude: options.longitude,\n };\n } else {\n location = await getClientLocation(options.geoEndpoint, options.ip);\n }\n\n const url = buildUrl(location.latitude, location.longitude, { ...options, location });\n const response = await fetch(url, { headers: { 'Content-Type': 'application/json' } });\n\n if (!response.ok) {\n throw new Error(`Weather request failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n\n if (!data?.current || !data?.hourly || !data?.daily) {\n throw new Error('Invalid weather response');\n }\n\n return {\n location,\n current: {\n time: data.current.time,\n temperature: Math.round(data.current.temperature_2m),\n weatherCode: data.current.weather_code,\n icon: getWeatherIcon(data.current.weather_code, data.current.is_day),\n isDay: data.current.is_day,\n rain: data.current.rain,\n showers: data.current.showers,\n snowfall: data.current.snowfall,\n windSpeed: data.current.wind_speed_10m,\n },\n hourly: data.hourly.time.map((time: string, index: number) => ({\n time,\n temperature: Math.round(data.hourly.temperature_2m[index]),\n weatherCode: data.hourly.weather_code[index],\n precipitationProbability: data.hourly.precipitation_probability?.[index],\n rain: data.hourly.rain?.[index],\n showers: data.hourly.showers?.[index],\n snowfall: data.hourly.snowfall?.[index],\n icon: getWeatherIcon(data.hourly.weather_code[index]),\n })),\n daily: data.daily.time.map((date: string, index: number) => ({\n date,\n min: Math.round(data.daily.temperature_2m_min[index]),\n max: Math.round(data.daily.temperature_2m_max[index]),\n weatherCode: data.daily.weather_code[index],\n precipitationProbabilityMax: data.daily.precipitation_probability_max?.[index],\n icon: getWeatherIcon(data.daily.weather_code[index]),\n })),\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { WeatherForecastData, WeatherForecastOptions } from '../types';\nimport { getWeatherForecast } from '../api/forecast';\n\nexport function useWeatherForecast(options: WeatherForecastOptions = {}) {\n const [data, setData] = useState<WeatherForecastData | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let active = true;\n setLoading(true);\n setError(null);\n\n getWeatherForecast(options)\n .then((result) => { if (active) setData(result); })\n .catch((err) => { if (active) setError(err instanceof Error ? err : new Error('Unknown error')); })\n .finally(() => { if (active) setLoading(false); });\n\n return () => { active = false; };\n }, [\n options.latitude,\n options.longitude,\n options.geoEndpoint,\n options.ip,\n options.forecastDays,\n options.forecastHours,\n options.temperatureUnit,\n options.windSpeedUnit,\n options.location?.timezone,\n ]);\n\n return { data, error, loading };\n}\n","import React from 'react';\nimport type { IconProps } from '../types';\n\nexport function BaseIcon({ title, children, ...props }: IconProps & { children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n role={title ? 'img' : 'presentation'}\n aria-hidden={title ? undefined : true}\n aria-label={title}\n {...props}\n >\n {title ? <title>{title}</title> : null}\n {children}\n </svg>\n );\n}\n","import React from 'react';\nimport type { IconProps } from '../types';\nimport { BaseIcon } from './BaseIcon';\n\nexport const CloudBoltIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M7 18a4.815 4.815 0 0 1-3.327-1.318A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 0 7h-1m-4.75-5L11 17.5h3.375l-2.25 4.5\" /></BaseIcon>\n);\nexport const CloudDrizzleIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M12 18v1m-3-4v1m6-1v1m2 3v1M7 19v1m-3-3.034a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662\" /></BaseIcon>\n);\nexport const CloudFogIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M5 21h7m4 0h3M8 17h8\" /></BaseIcon>\n);\nexport const CloudHailIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8 17.45v.1m-1.5 3.9v.1m10.5-4.1v.1m-1.5 3.9v.1m-3-4.1v.1m-1.5 3.9v.1m10.475-4.575A3.5 3.5 0 0 0 19 11h-1c.146-.65.148-1.32.006-1.97a4.784 4.784 0 0 0-.831-1.823 5.36 5.36 0 0 0-1.544-1.398 5.964 5.964 0 0 0-2.02-.759 6.224 6.224 0 0 0-2.19-.006 5.971 5.971 0 0 0-2.024.749C8.157 6.533 7.295 7.687 7 9a4.815 4.815 0 0 0-3.327 1.318A4.403 4.403 0 0 0 2.295 13.5c0 1.194.496 2.338 1.378 3.182.105.1.214.195.327.284m4.5.534a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm10.5-4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-3-4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Z\" /></BaseIcon>\n);\nexport const CloudShowersIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M12 13v2m0 3v2m4-5v2m0 3v2m-8-7v2m0 3v2\" /></BaseIcon>\n);\nexport const CloudShowersHeavyIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M16 15v6m-8-6v6m4-8v6\" /></BaseIcon>\n);\nexport const CloudSleetIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M13.5 17.45a1 1 0 1 0-2 0h2Zm-2 .1a1 1 0 1 0 2 0h-2Zm.5 3.9a1 1 0 1 0-2 0h2Zm-2 .1a1 1 0 1 0 2 0h-2Zm-6.327-4.868.692-.723-.692.723ZM7 9v1a1 1 0 0 0 .976-.781L7 9Zm2.397-3.207.512.858-.512-.858ZM18 11l-.976-.219A1 1 0 0 0 18 12v-1Zm2.768 5.268a1 1 0 0 0 1.414 1.414l-.707-.707-.707-.707ZM3.379 17.75a1 1 0 0 0 1.242-1.567L4 16.966l-.62.784Zm5.55-.379a1 1 0 0 0-1.857-.742L8 17l.928.371ZM5.071 21.63a1 1 0 0 0 1.856.742L6 22l-.928-.371Zm13.857-4.258a1 1 0 0 0-1.857-.742L18 17l.928.371Zm-3.857 4.258a1 1 0 0 0 1.857.742L16 22l-.928-.371ZM13 17.5h-1a.5.5 0 0 1 .5-.5v2a1.5 1.5 0 0 0 1.5-1.5h-1Zm-.5.5v-1a.5.5 0 0 1 .5.5h-2a1.5 1.5 0 0 0 1.5 1.5v-1Zm-.5-.5h1a.5.5 0 0 1-.5.5v-2a1.5 1.5 0 0 0-1.5 1.5h1Zm.5-.5v1a.5.5 0 0 1-.5-.5h2a1.5 1.5 0 0 0-1.5-1.5v1Zm0 .45h-1v.1h2v-.1h-1Zm-1 4.05h-1a.5.5 0 0 1 .5-.5v2a1.5 1.5 0 0 0 1.5-1.5h-1Zm-.5.5v-1a.5.5 0 0 1 .5.5h-2A1.5 1.5 0 0 0 11 23v-1Zm-.5-.5h1a.5.5 0 0 1-.5.5v-2a1.5 1.5 0 0 0-1.5 1.5h1Zm.5-.5v1a.5.5 0 0 1-.5-.5h2A1.5 1.5 0 0 0 11 20v1Zm0 .45h-1v.1h2v-.1h-1Zm-7.327-4.768.692-.723a3.403 3.403 0 0 1-1.07-2.459h-2c0 1.473.613 2.877 1.687 3.905l.691-.723ZM2.295 13.5h1c0-.914.38-1.8 1.07-2.46l-.692-.722-.69-.723A5.403 5.403 0 0 0 1.294 13.5h1Zm1.378-3.182.692.723A3.815 3.815 0 0 1 7 10V8c-1.499 0-2.945.57-4.018 1.595l.691.723ZM7 9l.976.219c.23-1.024.91-1.956 1.933-2.568l-.512-.858-.513-.859c-1.456.87-2.5 2.245-2.86 3.847L7 9Zm2.397-3.207.512.858a4.972 4.972 0 0 1 1.686-.622l-.173-.985-.174-.985a6.971 6.971 0 0 0-2.364.875l.513.859Zm2.025-.749.173.985a5.223 5.223 0 0 1 1.837.005l.18-.984.178-.984a7.223 7.223 0 0 0-2.542-.007l.174.985Zm2.19.006-.18.984c.606.11 1.177.326 1.681.631l.518-.856.518-.855a6.963 6.963 0 0 0-2.359-.888l-.179.984Zm2.02.76-.519.855c.505.305.93.693 1.257 1.136l.805-.594.805-.594a6.361 6.361 0 0 0-1.831-1.659l-.518.855Zm1.543 1.397-.805.594c.326.442.549.932.66 1.441l.976-.212.978-.213a5.786 5.786 0 0 0-1.005-2.204l-.804.594Zm.831 1.823-.977.212c.111.509.11 1.031-.005 1.539L18 11l.976.219c.178-.792.18-1.609.008-2.402l-.978.213ZM18 11v1h1v-2h-1v1Zm1 0v1a2.5 2.5 0 0 1 1.768.732l.707-.707.707-.707A4.5 4.5 0 0 0 19 10v1Zm2.475 1.025-.707.707A2.5 2.5 0 0 1 21.5 14.5h2a4.5 4.5 0 0 0-1.318-3.182l-.707.707ZM22.5 14.5h-1a2.5 2.5 0 0 1-.732 1.768l.707.707.707.707A4.5 4.5 0 0 0 23.5 14.5h-1ZM4 16.966l.62-.784a3.684 3.684 0 0 1-.255-.223l-.692.723-.69.723c.126.121.259.237.396.345L4 16.966ZM8 17l-.928-.371-2 5L6 22l.928.371 2-5L8 17Zm10 0-.928-.371-2 5L16 22l.928.371 2-5L18 17Z\" /></BaseIcon>\n);\nexport const CloudSnowIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8 15h2m-1-1v2m5-1h2m-1-1v2M5 21h2m-1-1v2m5-2h2m-1-1v2m5 0h2m-1-1v2M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662\" /></BaseIcon>\n);\nexport const CloudSunIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M10.201 19.997c-1.977 0-3.58-1.544-3.58-3.448 0-1.903 1.603-3.446 3.58-3.446.303-1.355 1.38-2.461 2.827-2.902 1.445-.44 3.042-.148 4.186.77 1.144.915 1.663 2.312 1.361 3.667h.761c1.472 0 2.664 1.2 2.664 2.68A2.672 2.672 0 0 1 19.336 20h-9.134m2.66-12.934a4.166 4.166 0 0 0-2.677-1.732m2.677 1.732 2.744-1.892m-2.744 1.892c.55.796.802 1.754.723 2.709m-3.4-4.44a4.167 4.167 0 0 0-3.118.667m3.118-.668.602-3.278m-3.72 3.946A4.167 4.167 0 0 0 5.334 8.68m1.733-2.678L5.174 3.26m.16 5.42c-.2 1.088.041 2.21.669 3.12m-.669-3.12-3.278-.601m3.947 3.72-2.744 1.893m2.744-1.893a4.167 4.167 0 0 0 2.174 1.607\" /></BaseIcon>\n);\nexport const CloudsIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8.958 21.05C6.772 21.05 5 19.344 5 17.24s1.772-3.81 3.958-3.81c.335-1.498 1.525-2.72 3.124-3.207 1.598-.487 3.363-.164 4.628.85 1.264 1.011 1.837 2.556 1.504 4.053h.842A2.953 2.953 0 0 1 22 18.09a2.954 2.954 0 0 1-2.945 2.964H8.958M18 8c-.5-2.5-3.532-3.401-5.5-2.5a3.117 3.117 0 0 0-2.11-2.312c-1.352-.411-2.845-.138-3.915.72-1.07.855-1.554 2.161-1.273 3.428h-.711A2.498 2.498 0 0 0 2 9.843c0 1.094.695 2.023 1.666 2.366\" /></BaseIcon>\n);\nexport const SnowflakeIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"m9.25 4-1 2H6m-2.25 4L5 12m0 0-1.25 2M5 12h3m-3 0H2.5m17.75-2L19 12l1.25 2M6 18h2.25l1 2M14 9h-4m4 0 3-5m-3 5 2 3m-6-3L7 4m3 5-2 3m0 0 2 3m0 0-3 5m3-5h4m2-3-2 3m2-3h5.5M14 15l3 5M14.75 4l1 2H18m0 12h-2.25l-1 2\" /></BaseIcon>\n);\nexport const SunIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M12 4V2m0 20v-2m10-8h-2M4 12H2m15.657-5.657 1.414-1.414M4.93 19.07l1.414-1.414m12.728 1.414-1.414-1.414M6.343 6.343 4.93 4.929M7 12a5 5 0 1 0 10 0 5 5 0 0 0-10 0Z\" /></BaseIcon>\n);\nexport const WindIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M9.59 4.59A2 2 0 1 1 11 8H2m10.59 11.41A2 2 0 1 0 14 16H2m15.73-8.27A2.5 2.5 0 1 1 19.5 12H2\" /></BaseIcon>\n);\n","import React from 'react';\nimport type { IconProps, WeatherCondition } from '../types';\nimport {\n CloudBoltIcon,\n CloudDrizzleIcon,\n CloudFogIcon,\n CloudHailIcon,\n CloudShowersHeavyIcon,\n CloudShowersIcon,\n CloudSleetIcon,\n CloudSnowIcon,\n CloudSunIcon,\n CloudsIcon,\n SnowflakeIcon,\n SunIcon,\n} from './weather-icons';\n\nconst iconMap: Record<WeatherCondition, React.ComponentType<IconProps>> = {\n sun: SunIcon,\n 'cloud-sun': CloudSunIcon,\n clouds: CloudsIcon,\n 'cloud-fog': CloudFogIcon,\n 'cloud-drizzle': CloudDrizzleIcon,\n 'cloud-showers': CloudShowersIcon,\n 'cloud-showers-heavy': CloudShowersHeavyIcon,\n 'cloud-sleet': CloudSleetIcon,\n 'cloud-snow': CloudSnowIcon,\n snowflake: SnowflakeIcon,\n 'cloud-bolt': CloudBoltIcon,\n 'cloud-hail': CloudHailIcon,\n};\n\nexport function WeatherIcon({ condition, ...props }: IconProps & { condition: WeatherCondition }) {\n const Icon = iconMap[condition] || CloudsIcon;\n return <Icon {...props} />;\n}\n","import React from 'react';\nimport { useWeatherForecast } from '../hooks/useWeatherForecast';\nimport type { HourlyWeather, WeatherForecastOptions, WindSpeedUnit } from '../types';\nimport { WeatherIcon } from '../icons/WeatherIcon';\nimport { WindIcon } from '../icons/weather-icons';\n\ntype Props = WeatherForecastOptions & {\n className?: string;\n style?: React.CSSProperties;\n compact?: boolean;\n};\n\nconst WIND_SPEED_UNIT_LABELS: Record<WindSpeedUnit, string> = {\n kmh: 'km/h',\n mph: 'mph',\n ms: 'm/s',\n kn: 'kn',\n};\n\nfunction closestHour(hourly: HourlyWeather[], targetTime: Date): HourlyWeather | undefined {\n return hourly.reduce<HourlyWeather | undefined>((closest, hour) => {\n const diff = Math.abs(new Date(hour.time).getTime() - targetTime.getTime());\n const closestDiff = closest ? Math.abs(new Date(closest.time).getTime() - targetTime.getTime()) : Infinity;\n return diff < closestDiff ? hour : closest;\n }, undefined);\n}\n\nconst styles = {\n root: {\n fontFamily: 'system-ui, sans-serif',\n border: '1px solid #e5e7eb',\n borderRadius: 12,\n padding: 16,\n background: '#fff',\n color: '#111827',\n maxWidth: 640,\n } as React.CSSProperties,\n row: { display: 'flex', alignItems: 'center', gap: 8 } as React.CSSProperties,\n hours: { display: 'flex', gap: 12, overflowX: 'auto', paddingBottom: 4 } as React.CSSProperties,\n hourCard: { minWidth: 72, textAlign: 'center' as const, padding: 8, borderRadius: 8, background: '#f9fafb' },\n dayRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, padding: '8px 0', borderBottom: '1px solid #f3f4f6' } as React.CSSProperties,\n compactRoot: { fontFamily: 'system-ui, sans-serif', display: 'flex', flexDirection: 'column', gap: 8, padding: '10px 14px', borderRadius: 8 } as React.CSSProperties,\n compactHeader: { display: 'flex', alignItems: 'center', gap: 10 } as React.CSSProperties,\n compactHeaderText: { display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' } as React.CSSProperties,\n compactDateTime: { fontSize: 11, opacity: 0.7 } as React.CSSProperties,\n compactStats: { display: 'flex', flexWrap: 'wrap', gap: 12, fontSize: 12, opacity: 0.9 } as React.CSSProperties,\n compactStat: { display: 'flex', alignItems: 'center', gap: 4, whiteSpace: 'nowrap' } as React.CSSProperties,\n};\n\nexport function WeatherForecast(props: Props) {\n const { data, loading, error } = useWeatherForecast(props);\n\n if (loading) return null;\n if (error) return <div className={props.className} style={props.style}>Error: {error.message}</div>;\n if (!data) return <div className={props.className} style={props.style}>No forecast available.</div>;\n\n if (props.compact) {\n const now = new Date(data.current.time);\n const today = data.daily[0];\n const tomorrow = data.daily[1];\n const in6Hours = closestHour(data.hourly, new Date(now.getTime() + 6 * 60 * 60 * 1000));\n const windSpeedUnitLabel = WIND_SPEED_UNIT_LABELS[props.windSpeedUnit ?? 'mph'];\n\n return (\n <div className={props.className} style={{ ...styles.compactRoot, ...props.style }}>\n <div style={styles.compactHeader}>\n <WeatherIcon condition={data.current.icon} width={24} height={24} title=\"Current weather\" />\n <div>\n <div style={styles.compactHeaderText}>\n <strong style={{ fontSize: 16 }}>{data.current.temperature}°</strong>\n <span style={{ fontSize: 14, opacity: 0.8 }}>\n {data.location?.city || 'Current location'}\n </span>\n </div>\n <div style={styles.compactDateTime}>\n {now.toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}\n {' · '}\n {now.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })}\n </div>\n </div>\n </div>\n\n <div style={styles.compactStats}>\n {today && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={today.icon} width={16} height={16} title=\"Today's high and low\" />\n {today.max}° / {today.min}°\n </span>\n )}\n {tomorrow && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={tomorrow.icon} width={16} height={16} title=\"Tomorrow\" />\n Tomorrow {tomorrow.max}°\n </span>\n )}\n <span style={styles.compactStat}>\n <WindIcon width={16} height={16} title=\"Wind speed\" />\n {data.current.windSpeed !== undefined ? `${Math.round(data.current.windSpeed)} ${windSpeedUnitLabel}` : '—'}\n </span>\n {in6Hours && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={in6Hours.icon} width={16} height={16} title=\"In 6 hours\" />\n {in6Hours.temperature}° in 6h\n </span>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div className={props.className} style={{ ...styles.root, ...props.style }}>\n <div>\n <h3 style={{ margin: 0, fontSize: 20 }}>\n {data.location?.city || 'Current location'}\n {data.location?.region ? `, ${data.location.region}` : ''}\n </h3>\n <div style={{ ...styles.row, marginTop: 8 }}>\n <WeatherIcon condition={data.current.icon} width={28} height={28} title=\"Current weather\" />\n <strong style={{ fontSize: 28 }}>{data.current.temperature}°</strong>\n </div>\n </div>\n\n <div style={{ marginTop: 20 }}>\n <h4 style={{ margin: '0 0 10px 0' }}>Next hours</h4>\n <div style={styles.hours}>\n {data.hourly.slice(0, props.forecastHours ?? 12).map((hour) => (\n <div key={hour.time} style={styles.hourCard}>\n <div style={{ fontSize: 12 }}>{new Date(hour.time).toLocaleTimeString([], { hour: 'numeric' })}</div>\n <WeatherIcon condition={hour.icon} width={20} height={20} style={{ margin: '6px auto' }} />\n <div>{hour.temperature}°</div>\n </div>\n ))}\n </div>\n </div>\n\n <div style={{ marginTop: 20 }}>\n <h4 style={{ margin: '0 0 10px 0' }}>Next days</h4>\n <div>\n {data.daily.map((day) => (\n <div key={day.date} style={styles.dayRow}>\n <div style={{ width: 120 }}>{new Date(day.date).toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}</div>\n <WeatherIcon condition={day.icon} width={20} height={20} />\n <div>{day.min}° / {day.max}°</div>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,SAAS,eAAe,MAAc,QAAQ,GAAqB;AACxE,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,CAAC,GAAG,CAAC,EAAE,SAAS,IAAI,EAAG,QAAO,QAAQ,cAAc;AACxD,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,CAAC,IAAI,EAAE,EAAE,SAAS,IAAI,EAAG,QAAO;AACpC,MAAI,CAAC,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE,SAAS,IAAI,EAAG,QAAO;AAChD,MAAI,CAAC,IAAI,EAAE,EAAE,SAAS,IAAI,EAAG,QAAO;AACpC,MAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE,SAAS,IAAI,EAAG,QAAO;AACpD,MAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE,SAAS,IAAI,EAAG,QAAO;AACpD,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,CAAC,IAAI,EAAE,EAAE,SAAS,IAAI,EAAG,QAAO;AACpC,SAAO;AACT;;;ACZA,IAAM,qBAAqB;AAsB3B,eAAsB,kBAAkB,aAAsB,IAAuC;AACnG,MAAI,aAAa;AACf,UAAM,MAAM,KAAK,GAAG,WAAW,OAAO,mBAAmB,EAAE,CAAC,KAAK;AACjE,UAAMA,OAAM,MAAM,MAAM,GAAG;AAC3B,QAAI,CAACA,KAAI,GAAI,OAAM,IAAI,MAAM,qCAAqCA,KAAI,MAAM,EAAE;AAC9E,UAAMC,QAA0B,MAAMD,KAAI,KAAK;AAE/C,WAAO;AAAA,MACL,MAAMC,MAAK;AAAA,MACX,QAAQA,MAAK;AAAA,MACb,SAASA,MAAK;AAAA,MACd,UAAUA,MAAK;AAAA,MACf,UAAU,OAAOA,MAAK,QAAQ;AAAA,MAC9B,WAAW,OAAOA,MAAK,SAAS;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,MAAM,GAAG,kBAAkB,IAAI,KAAK,GAAG,mBAAmB,EAAE,CAAC,MAAM,EAAE,OAAO;AAC9F,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,2BAA2B,IAAI,MAAM,EAAE;AACpE,QAAM,OAAsB,MAAM,IAAI,KAAK;AAE3C,MAAI,KAAK,OAAO;AACd,UAAM,IAAI,MAAM,2BAA2B,KAAK,UAAU,eAAe,EAAE;AAAA,EAC7E;AAEA,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,QAAQ,KAAK;AAAA,IACb,SAAS,KAAK;AAAA,IACd,UAAU,KAAK;AAAA,IACf,UAAU,OAAO,KAAK,QAAQ;AAAA,IAC9B,WAAW,OAAO,KAAK,SAAS;AAAA,EAClC;AACF;;;ACrDA,SAAS,SAAS,UAAkB,WAAmB,SAAiC;AACtF,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,UAAU,OAAO,QAAQ;AAAA,IACzB,WAAW,OAAO,SAAS;AAAA,IAC3B,UAAU,QAAQ,UAAU,YAAY;AAAA,IACxC,kBAAkB,QAAQ,mBAAmB;AAAA,IAC7C,iBAAiB,QAAQ,iBAAiB;AAAA,IAC1C,eAAe,OAAO,QAAQ,gBAAgB,CAAC;AAAA,IAC/C,gBAAgB,OAAO,QAAQ,iBAAiB,EAAE;AAAA,IAClD,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,GAAG;AAAA,IACV,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,GAAG;AAAA,IACV,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,GAAG;AAAA,EACZ,CAAC;AAED,SAAO,0CAA0C,OAAO,SAAS,CAAC;AACpE;AAEA,eAAsB,mBACpB,UAAkC,CAAC,GACL;AAC9B,MAAI;AAEJ,MAAI,OAAO,QAAQ,aAAa,YAAY,OAAO,QAAQ,cAAc,UAAU;AACjF,eAAW;AAAA,MACT,GAAG,QAAQ;AAAA,MACX,UAAU,QAAQ;AAAA,MAClB,WAAW,QAAQ;AAAA,IACrB;AAAA,EACF,OAAO;AACL,eAAW,MAAM,kBAAkB,QAAQ,aAAa,QAAQ,EAAE;AAAA,EACpE;AAEA,QAAM,MAAM,SAAS,SAAS,UAAU,SAAS,WAAW,EAAE,GAAG,SAAS,SAAS,CAAC;AACpF,QAAM,WAAW,MAAM,MAAM,KAAK,EAAE,SAAS,EAAE,gBAAgB,mBAAmB,EAAE,CAAC;AAErF,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,2BAA2B,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,EACrF;AAEA,QAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,MAAI,CAAC,MAAM,WAAW,CAAC,MAAM,UAAU,CAAC,MAAM,OAAO;AACnD,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC5C;AAEA,SAAO;AAAA,IACL;AAAA,IACA,SAAS;AAAA,MACP,MAAM,KAAK,QAAQ;AAAA,MACnB,aAAa,KAAK,MAAM,KAAK,QAAQ,cAAc;AAAA,MACnD,aAAa,KAAK,QAAQ;AAAA,MAC1B,MAAM,eAAe,KAAK,QAAQ,cAAc,KAAK,QAAQ,MAAM;AAAA,MACnE,OAAO,KAAK,QAAQ;AAAA,MACpB,MAAM,KAAK,QAAQ;AAAA,MACnB,SAAS,KAAK,QAAQ;AAAA,MACtB,UAAU,KAAK,QAAQ;AAAA,MACvB,WAAW,KAAK,QAAQ;AAAA,IAC1B;AAAA,IACA,QAAQ,KAAK,OAAO,KAAK,IAAI,CAAC,MAAc,WAAmB;AAAA,MAC7D;AAAA,MACA,aAAa,KAAK,MAAM,KAAK,OAAO,eAAe,KAAK,CAAC;AAAA,MACzD,aAAa,KAAK,OAAO,aAAa,KAAK;AAAA,MAC3C,0BAA0B,KAAK,OAAO,4BAA4B,KAAK;AAAA,MACvE,MAAM,KAAK,OAAO,OAAO,KAAK;AAAA,MAC9B,SAAS,KAAK,OAAO,UAAU,KAAK;AAAA,MACpC,UAAU,KAAK,OAAO,WAAW,KAAK;AAAA,MACtC,MAAM,eAAe,KAAK,OAAO,aAAa,KAAK,CAAC;AAAA,IACtD,EAAE;AAAA,IACF,OAAO,KAAK,MAAM,KAAK,IAAI,CAAC,MAAc,WAAmB;AAAA,MAC3D;AAAA,MACA,KAAK,KAAK,MAAM,KAAK,MAAM,mBAAmB,KAAK,CAAC;AAAA,MACpD,KAAK,KAAK,MAAM,KAAK,MAAM,mBAAmB,KAAK,CAAC;AAAA,MACpD,aAAa,KAAK,MAAM,aAAa,KAAK;AAAA,MAC1C,6BAA6B,KAAK,MAAM,gCAAgC,KAAK;AAAA,MAC7E,MAAM,eAAe,KAAK,MAAM,aAAa,KAAK,CAAC;AAAA,IACrD,EAAE;AAAA,EACJ;AACF;;;ACrGA,mBAAoC;AAI7B,SAAS,mBAAmB,UAAkC,CAAC,GAAG;AACvE,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAqC,IAAI;AACjE,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAuB,IAAI;AACrD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,IAAI;AAE3C,8BAAU,MAAM;AACd,QAAI,SAAS;AACb,eAAW,IAAI;AACf,aAAS,IAAI;AAEb,uBAAmB,OAAO,EACvB,KAAK,CAAC,WAAW;AAAE,UAAI,OAAQ,SAAQ,MAAM;AAAA,IAAG,CAAC,EACjD,MAAM,CAAC,QAAQ;AAAE,UAAI,OAAQ,UAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,eAAe,CAAC;AAAA,IAAG,CAAC,EACjG,QAAQ,MAAM;AAAE,UAAI,OAAQ,YAAW,KAAK;AAAA,IAAG,CAAC;AAEnD,WAAO,MAAM;AAAE,eAAS;AAAA,IAAO;AAAA,EACjC,GAAG;AAAA,IACD,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ,UAAU;AAAA,EACpB,CAAC;AAED,SAAO,EAAE,MAAM,OAAO,QAAQ;AAChC;;;AC5BI;AAFG,SAAS,SAAS,EAAE,OAAO,UAAU,GAAG,MAAM,GAA8C;AACjG,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,MAAM,QAAQ,QAAQ;AAAA,MACtB,eAAa,QAAQ,SAAY;AAAA,MACjC,cAAY;AAAA,MACX,GAAG;AAAA,MAEH;AAAA,gBAAQ,4CAAC,WAAO,iBAAM,IAAW;AAAA,QACjC;AAAA;AAAA;AAAA,EACH;AAEJ;;;ACfuB,IAAAC,sBAAA;AADhB,IAAM,gBAAgB,CAAC,UAC5B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,qXAAoX,GAAE;AAE9Y,IAAM,mBAAmB,CAAC,UAC/B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,0XAAyX,GAAE;AAEnZ,IAAM,eAAe,CAAC,UAC3B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,4WAA2W,GAAE;AAErY,IAAM,gBAAgB,CAAC,UAC5B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,moBAAkoB,GAAE;AAE5pB,IAAM,mBAAmB,CAAC,UAC/B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,+XAA8X,GAAE;AAExZ,IAAM,wBAAwB,CAAC,UACpC,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,6WAA4W,GAAE;AAEtY,IAAM,iBAAiB,CAAC,UAC7B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,05EAAy5E,GAAE;AAEn7E,IAAM,gBAAgB,CAAC,UAC5B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,2ZAA0Z,GAAE;AAEpb,IAAM,eAAe,CAAC,UAC3B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,wlBAAulB,GAAE;AAEjnB,IAAM,aAAa,CAAC,UACzB,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,yaAAwa,GAAE;AAElc,IAAM,gBAAgB,CAAC,UAC5B,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,qNAAoN,GAAE;AAE9O,IAAM,UAAU,CAAC,UACtB,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,sKAAqK,GAAE;AAE/L,IAAM,WAAW,CAAC,UACvB,6CAAC,YAAU,GAAG,OAAO,uDAAC,UAAK,GAAE,gGAA+F,GAAE;;;ACPvH,IAAAC,sBAAA;AAjBT,IAAM,UAAoE;AAAA,EACxE,KAAK;AAAA,EACL,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,cAAc;AAChB;AAEO,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAgD;AAChG,QAAM,OAAO,QAAQ,SAAS,KAAK;AACnC,SAAO,6CAAC,QAAM,GAAG,OAAO;AAC1B;;;ACkBoB,IAAAC,sBAAA;AAzCpB,IAAM,yBAAwD;AAAA,EAC5D,KAAK;AAAA,EACL,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,SAAS,YAAY,QAAyB,YAA6C;AACzF,SAAO,OAAO,OAAkC,CAAC,SAAS,SAAS;AACjE,UAAM,OAAO,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,EAAE,QAAQ,IAAI,WAAW,QAAQ,CAAC;AAC1E,UAAM,cAAc,UAAU,KAAK,IAAI,IAAI,KAAK,QAAQ,IAAI,EAAE,QAAQ,IAAI,WAAW,QAAQ,CAAC,IAAI;AAClG,WAAO,OAAO,cAAc,OAAO;AAAA,EACrC,GAAG,MAAS;AACd;AAEA,IAAM,SAAS;AAAA,EACb,MAAM;AAAA,IACJ,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AAAA,EACA,KAAK,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAE;AAAA,EACrD,OAAO,EAAE,SAAS,QAAQ,KAAK,IAAI,WAAW,QAAQ,eAAe,EAAE;AAAA,EACvE,UAAU,EAAE,UAAU,IAAI,WAAW,UAAmB,SAAS,GAAG,cAAc,GAAG,YAAY,UAAU;AAAA,EAC3G,QAAQ,EAAE,SAAS,QAAQ,YAAY,UAAU,gBAAgB,iBAAiB,KAAK,IAAI,SAAS,SAAS,cAAc,oBAAoB;AAAA,EAC/I,aAAa,EAAE,YAAY,yBAAyB,SAAS,QAAQ,eAAe,UAAU,KAAK,GAAG,SAAS,aAAa,cAAc,EAAE;AAAA,EAC5I,eAAe,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,GAAG;AAAA,EAChE,mBAAmB,EAAE,SAAS,QAAQ,YAAY,YAAY,KAAK,GAAG,UAAU,OAAO;AAAA,EACvF,iBAAiB,EAAE,UAAU,IAAI,SAAS,IAAI;AAAA,EAC9C,cAAc,EAAE,SAAS,QAAQ,UAAU,QAAQ,KAAK,IAAI,UAAU,IAAI,SAAS,IAAI;AAAA,EACvF,aAAa,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,GAAG,YAAY,SAAS;AACrF;AAEO,SAAS,gBAAgB,OAAc;AAC5C,QAAM,EAAE,MAAM,SAAS,MAAM,IAAI,mBAAmB,KAAK;AAEzD,MAAI,QAAS,QAAO;AACpB,MAAI,MAAO,QAAO,8CAAC,SAAI,WAAW,MAAM,WAAW,OAAO,MAAM,OAAO;AAAA;AAAA,IAAQ,MAAM;AAAA,KAAQ;AAC7F,MAAI,CAAC,KAAM,QAAO,6CAAC,SAAI,WAAW,MAAM,WAAW,OAAO,MAAM,OAAO,oCAAsB;AAE7F,MAAI,MAAM,SAAS;AACjB,UAAM,MAAM,IAAI,KAAK,KAAK,QAAQ,IAAI;AACtC,UAAM,QAAQ,KAAK,MAAM,CAAC;AAC1B,UAAM,WAAW,KAAK,MAAM,CAAC;AAC7B,UAAM,WAAW,YAAY,KAAK,QAAQ,IAAI,KAAK,IAAI,QAAQ,IAAI,IAAI,KAAK,KAAK,GAAI,CAAC;AACtF,UAAM,qBAAqB,uBAAuB,MAAM,iBAAiB,KAAK;AAE9E,WACE,8CAAC,SAAI,WAAW,MAAM,WAAW,OAAO,EAAE,GAAG,OAAO,aAAa,GAAG,MAAM,MAAM,GAC9E;AAAA,oDAAC,SAAI,OAAO,OAAO,eACjB;AAAA,qDAAC,eAAY,WAAW,KAAK,QAAQ,MAAM,OAAO,IAAI,QAAQ,IAAI,OAAM,mBAAkB;AAAA,QAC1F,8CAAC,SACC;AAAA,wDAAC,SAAI,OAAO,OAAO,mBACjB;AAAA,0DAAC,YAAO,OAAO,EAAE,UAAU,GAAG,GAAI;AAAA,mBAAK,QAAQ;AAAA,cAAY;AAAA,eAAC;AAAA,YAC5D,6CAAC,UAAK,OAAO,EAAE,UAAU,IAAI,SAAS,IAAI,GACvC,eAAK,UAAU,QAAQ,oBAC1B;AAAA,aACF;AAAA,UACA,8CAAC,SAAI,OAAO,OAAO,iBAChB;AAAA,gBAAI,mBAAmB,CAAC,GAAG,EAAE,SAAS,SAAS,OAAO,SAAS,KAAK,UAAU,CAAC;AAAA,YAC/E;AAAA,YACA,IAAI,mBAAmB,CAAC,GAAG,EAAE,MAAM,WAAW,QAAQ,UAAU,CAAC;AAAA,aACpE;AAAA,WACF;AAAA,SACF;AAAA,MAEA,8CAAC,SAAI,OAAO,OAAO,cAChB;AAAA,iBACC,8CAAC,UAAK,OAAO,OAAO,aAClB;AAAA,uDAAC,eAAY,WAAW,MAAM,MAAM,OAAO,IAAI,QAAQ,IAAI,OAAM,wBAAuB;AAAA,UACvF,MAAM;AAAA,UAAI;AAAA,UAAK,MAAM;AAAA,UAAI;AAAA,WAC5B;AAAA,QAED,YACC,8CAAC,UAAK,OAAO,OAAO,aAClB;AAAA,uDAAC,eAAY,WAAW,SAAS,MAAM,OAAO,IAAI,QAAQ,IAAI,OAAM,YAAW;AAAA,UAAE;AAAA,UACvE,SAAS;AAAA,UAAI;AAAA,WACzB;AAAA,QAEF,8CAAC,UAAK,OAAO,OAAO,aAClB;AAAA,uDAAC,YAAS,OAAO,IAAI,QAAQ,IAAI,OAAM,cAAa;AAAA,UACnD,KAAK,QAAQ,cAAc,SAAY,GAAG,KAAK,MAAM,KAAK,QAAQ,SAAS,CAAC,IAAI,kBAAkB,KAAK;AAAA,WAC1G;AAAA,QACC,YACC,8CAAC,UAAK,OAAO,OAAO,aAClB;AAAA,uDAAC,eAAY,WAAW,SAAS,MAAM,OAAO,IAAI,QAAQ,IAAI,OAAM,cAAa;AAAA,UAChF,SAAS;AAAA,UAAY;AAAA,WACxB;AAAA,SAEJ;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,8CAAC,SAAI,WAAW,MAAM,WAAW,OAAO,EAAE,GAAG,OAAO,MAAM,GAAG,MAAM,MAAM,GACvE;AAAA,kDAAC,SACC;AAAA,oDAAC,QAAG,OAAO,EAAE,QAAQ,GAAG,UAAU,GAAG,GAClC;AAAA,aAAK,UAAU,QAAQ;AAAA,QACvB,KAAK,UAAU,SAAS,KAAK,KAAK,SAAS,MAAM,KAAK;AAAA,SACzD;AAAA,MACA,8CAAC,SAAI,OAAO,EAAE,GAAG,OAAO,KAAK,WAAW,EAAE,GACxC;AAAA,qDAAC,eAAY,WAAW,KAAK,QAAQ,MAAM,OAAO,IAAI,QAAQ,IAAI,OAAM,mBAAkB;AAAA,QAC1F,8CAAC,YAAO,OAAO,EAAE,UAAU,GAAG,GAAI;AAAA,eAAK,QAAQ;AAAA,UAAY;AAAA,WAAC;AAAA,SAC9D;AAAA,OACF;AAAA,IAEA,8CAAC,SAAI,OAAO,EAAE,WAAW,GAAG,GAC1B;AAAA,mDAAC,QAAG,OAAO,EAAE,QAAQ,aAAa,GAAG,wBAAU;AAAA,MAC/C,6CAAC,SAAI,OAAO,OAAO,OAChB,eAAK,OAAO,MAAM,GAAG,MAAM,iBAAiB,EAAE,EAAE,IAAI,CAAC,SACpD,8CAAC,SAAoB,OAAO,OAAO,UACjC;AAAA,qDAAC,SAAI,OAAO,EAAE,UAAU,GAAG,GAAI,cAAI,KAAK,KAAK,IAAI,EAAE,mBAAmB,CAAC,GAAG,EAAE,MAAM,UAAU,CAAC,GAAE;AAAA,QAC/F,6CAAC,eAAY,WAAW,KAAK,MAAM,OAAO,IAAI,QAAQ,IAAI,OAAO,EAAE,QAAQ,WAAW,GAAG;AAAA,QACzF,8CAAC,SAAK;AAAA,eAAK;AAAA,UAAY;AAAA,WAAC;AAAA,WAHhB,KAAK,IAIf,CACD,GACH;AAAA,OACF;AAAA,IAEA,8CAAC,SAAI,OAAO,EAAE,WAAW,GAAG,GAC1B;AAAA,mDAAC,QAAG,OAAO,EAAE,QAAQ,aAAa,GAAG,uBAAS;AAAA,MAC9C,6CAAC,SACE,eAAK,MAAM,IAAI,CAAC,QACf,8CAAC,SAAmB,OAAO,OAAO,QAChC;AAAA,qDAAC,SAAI,OAAO,EAAE,OAAO,IAAI,GAAI,cAAI,KAAK,IAAI,IAAI,EAAE,mBAAmB,CAAC,GAAG,EAAE,SAAS,SAAS,OAAO,SAAS,KAAK,UAAU,CAAC,GAAE;AAAA,QAC7H,6CAAC,eAAY,WAAW,IAAI,MAAM,OAAO,IAAI,QAAQ,IAAI;AAAA,QACzD,8CAAC,SAAK;AAAA,cAAI;AAAA,UAAI;AAAA,UAAK,IAAI;AAAA,UAAI;AAAA,WAAC;AAAA,WAHpB,IAAI,IAId,CACD,GACH;AAAA,OACF;AAAA,KACF;AAEJ;","names":["res","data","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ function getWeatherIcon(code, isDay = 1) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// src/api/geolocation.ts
|
|
17
|
-
var DEFAULT_IP_API_URL = "
|
|
17
|
+
var DEFAULT_IP_API_URL = "https://ipapi.co";
|
|
18
18
|
async function getClientLocation(geoEndpoint, ip) {
|
|
19
19
|
if (geoEndpoint) {
|
|
20
20
|
const url = ip ? `${geoEndpoint}?ip=${encodeURIComponent(ip)}` : geoEndpoint;
|
|
@@ -30,19 +30,19 @@ async function getClientLocation(geoEndpoint, ip) {
|
|
|
30
30
|
longitude: Number(data2.longitude)
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
const res = await fetch(`${DEFAULT_IP_API_URL}
|
|
34
|
-
if (!res.ok) throw new Error(`
|
|
33
|
+
const res = await fetch(`${DEFAULT_IP_API_URL}/${ip ? `${encodeURIComponent(ip)}/` : ""}json/`);
|
|
34
|
+
if (!res.ok) throw new Error(`ipapi.co lookup failed: ${res.status}`);
|
|
35
35
|
const data = await res.json();
|
|
36
|
-
if (data.
|
|
37
|
-
throw new Error(`
|
|
36
|
+
if (data.error) {
|
|
37
|
+
throw new Error(`ipapi.co lookup failed: ${data.reason ?? "unknown error"}`);
|
|
38
38
|
}
|
|
39
39
|
return {
|
|
40
40
|
city: data.city,
|
|
41
|
-
region: data.
|
|
42
|
-
country: data.
|
|
41
|
+
region: data.region,
|
|
42
|
+
country: data.country_name,
|
|
43
43
|
timezone: data.timezone,
|
|
44
|
-
latitude: Number(data.
|
|
45
|
-
longitude: Number(data.
|
|
44
|
+
latitude: Number(data.latitude),
|
|
45
|
+
longitude: Number(data.longitude)
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/weatherCodes.ts","../src/api/geolocation.ts","../src/api/forecast.ts","../src/hooks/useWeatherForecast.ts","../src/icons/BaseIcon.tsx","../src/icons/weather-icons.tsx","../src/icons/WeatherIcon.tsx","../src/components/WeatherForecast.tsx"],"sourcesContent":["import type { WeatherCondition } from './types';\n\nexport function getWeatherIcon(code: number, isDay = 1): WeatherCondition {\n if (code === 0) return 'sun';\n if ([1, 2].includes(code)) return isDay ? 'cloud-sun' : 'clouds';\n if (code === 3) return 'clouds';\n if ([45, 48].includes(code)) return 'cloud-fog';\n if ([51, 53, 55, 56, 57].includes(code)) return 'cloud-drizzle';\n if ([61, 63].includes(code)) return 'cloud-showers';\n if ([65, 66, 67, 80, 81, 82].includes(code)) return 'cloud-showers-heavy';\n if ([71, 73, 75, 77, 85, 86].includes(code)) return 'cloud-snow';\n if (code === 95) return 'cloud-bolt';\n if ([96, 99].includes(code)) return 'cloud-hail';\n return 'clouds';\n}\n","import type { WeatherLocation } from '../types';\n\n// ip-api.com's free tier only serves plain HTTP (HTTPS requires their paid plan),\n// so this default will be blocked as mixed content on pages served over HTTPS.\n// Deploy worker/geo-worker.ts and pass its URL as `geoEndpoint` to avoid that.\nconst DEFAULT_IP_API_URL = 'http://ip-api.com/json/';\n\ntype IpApiResponse = {\n status: 'success' | 'fail';\n city?: string;\n regionName?: string;\n country?: string;\n timezone?: string;\n lat?: number;\n lon?: number;\n message?: string;\n};\n\ntype GeoWorkerResponse = {\n city?: string;\n region?: string;\n country?: string;\n timezone?: string;\n latitude?: number | string;\n longitude?: number | string;\n};\n\nexport async function getClientLocation(geoEndpoint?: string, ip?: string): Promise<WeatherLocation> {\n if (geoEndpoint) {\n const url = ip ? `${geoEndpoint}?ip=${encodeURIComponent(ip)}` : geoEndpoint;\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Geolocation worker lookup failed: ${res.status}`);\n const data: GeoWorkerResponse = await res.json();\n\n return {\n city: data.city,\n region: data.region,\n country: data.country,\n timezone: data.timezone,\n latitude: Number(data.latitude),\n longitude: Number(data.longitude),\n };\n }\n\n const res = await fetch(`${DEFAULT_IP_API_URL}${ip ? encodeURIComponent(ip) : ''}`);\n if (!res.ok) throw new Error(`ip-api lookup failed: ${res.status}`);\n const data: IpApiResponse = await res.json();\n\n if (data.status === 'fail') {\n throw new Error(`ip-api lookup failed: ${data.message ?? 'unknown error'}`);\n }\n\n return {\n city: data.city,\n region: data.regionName,\n country: data.country,\n timezone: data.timezone,\n latitude: Number(data.lat),\n longitude: Number(data.lon),\n };\n}\n","import type { WeatherForecastData, WeatherForecastOptions, WeatherLocation } from '../types';\nimport { getWeatherIcon } from '../weatherCodes';\nimport { getClientLocation } from './geolocation';\n\nfunction buildUrl(latitude: number, longitude: number, options: WeatherForecastOptions) {\n const params = new URLSearchParams({\n latitude: String(latitude),\n longitude: String(longitude),\n timezone: options.location?.timezone || 'auto',\n temperature_unit: options.temperatureUnit || 'fahrenheit',\n wind_speed_unit: options.windSpeedUnit || 'mph',\n forecast_days: String(options.forecastDays ?? 5),\n forecast_hours: String(options.forecastHours ?? 24),\n current: [\n 'temperature_2m',\n 'weather_code',\n 'is_day',\n 'rain',\n 'showers',\n 'snowfall',\n 'wind_speed_10m',\n ].join(','),\n hourly: [\n 'temperature_2m',\n 'weather_code',\n 'precipitation_probability',\n 'rain',\n 'showers',\n 'snowfall',\n ].join(','),\n daily: [\n 'temperature_2m_max',\n 'temperature_2m_min',\n 'weather_code',\n 'precipitation_probability_max',\n ].join(','),\n });\n\n return `https://api.open-meteo.com/v1/forecast?${params.toString()}`;\n}\n\nexport async function getWeatherForecast(\n options: WeatherForecastOptions = {}\n): Promise<WeatherForecastData> {\n let location: WeatherLocation;\n\n if (typeof options.latitude === 'number' && typeof options.longitude === 'number') {\n location = {\n ...options.location,\n latitude: options.latitude,\n longitude: options.longitude,\n };\n } else {\n location = await getClientLocation(options.geoEndpoint, options.ip);\n }\n\n const url = buildUrl(location.latitude, location.longitude, { ...options, location });\n const response = await fetch(url, { headers: { 'Content-Type': 'application/json' } });\n\n if (!response.ok) {\n throw new Error(`Weather request failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n\n if (!data?.current || !data?.hourly || !data?.daily) {\n throw new Error('Invalid weather response');\n }\n\n return {\n location,\n current: {\n time: data.current.time,\n temperature: Math.round(data.current.temperature_2m),\n weatherCode: data.current.weather_code,\n icon: getWeatherIcon(data.current.weather_code, data.current.is_day),\n isDay: data.current.is_day,\n rain: data.current.rain,\n showers: data.current.showers,\n snowfall: data.current.snowfall,\n windSpeed: data.current.wind_speed_10m,\n },\n hourly: data.hourly.time.map((time: string, index: number) => ({\n time,\n temperature: Math.round(data.hourly.temperature_2m[index]),\n weatherCode: data.hourly.weather_code[index],\n precipitationProbability: data.hourly.precipitation_probability?.[index],\n rain: data.hourly.rain?.[index],\n showers: data.hourly.showers?.[index],\n snowfall: data.hourly.snowfall?.[index],\n icon: getWeatherIcon(data.hourly.weather_code[index]),\n })),\n daily: data.daily.time.map((date: string, index: number) => ({\n date,\n min: Math.round(data.daily.temperature_2m_min[index]),\n max: Math.round(data.daily.temperature_2m_max[index]),\n weatherCode: data.daily.weather_code[index],\n precipitationProbabilityMax: data.daily.precipitation_probability_max?.[index],\n icon: getWeatherIcon(data.daily.weather_code[index]),\n })),\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { WeatherForecastData, WeatherForecastOptions } from '../types';\nimport { getWeatherForecast } from '../api/forecast';\n\nexport function useWeatherForecast(options: WeatherForecastOptions = {}) {\n const [data, setData] = useState<WeatherForecastData | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let active = true;\n setLoading(true);\n setError(null);\n\n getWeatherForecast(options)\n .then((result) => { if (active) setData(result); })\n .catch((err) => { if (active) setError(err instanceof Error ? err : new Error('Unknown error')); })\n .finally(() => { if (active) setLoading(false); });\n\n return () => { active = false; };\n }, [\n options.latitude,\n options.longitude,\n options.geoEndpoint,\n options.ip,\n options.forecastDays,\n options.forecastHours,\n options.temperatureUnit,\n options.windSpeedUnit,\n options.location?.timezone,\n ]);\n\n return { data, error, loading };\n}\n","import React from 'react';\nimport type { IconProps } from '../types';\n\nexport function BaseIcon({ title, children, ...props }: IconProps & { children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n role={title ? 'img' : 'presentation'}\n aria-hidden={title ? undefined : true}\n aria-label={title}\n {...props}\n >\n {title ? <title>{title}</title> : null}\n {children}\n </svg>\n );\n}\n","import React from 'react';\nimport type { IconProps } from '../types';\nimport { BaseIcon } from './BaseIcon';\n\nexport const CloudBoltIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M7 18a4.815 4.815 0 0 1-3.327-1.318A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 0 7h-1m-4.75-5L11 17.5h3.375l-2.25 4.5\" /></BaseIcon>\n);\nexport const CloudDrizzleIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M12 18v1m-3-4v1m6-1v1m2 3v1M7 19v1m-3-3.034a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662\" /></BaseIcon>\n);\nexport const CloudFogIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M5 21h7m4 0h3M8 17h8\" /></BaseIcon>\n);\nexport const CloudHailIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8 17.45v.1m-1.5 3.9v.1m10.5-4.1v.1m-1.5 3.9v.1m-3-4.1v.1m-1.5 3.9v.1m10.475-4.575A3.5 3.5 0 0 0 19 11h-1c.146-.65.148-1.32.006-1.97a4.784 4.784 0 0 0-.831-1.823 5.36 5.36 0 0 0-1.544-1.398 5.964 5.964 0 0 0-2.02-.759 6.224 6.224 0 0 0-2.19-.006 5.971 5.971 0 0 0-2.024.749C8.157 6.533 7.295 7.687 7 9a4.815 4.815 0 0 0-3.327 1.318A4.403 4.403 0 0 0 2.295 13.5c0 1.194.496 2.338 1.378 3.182.105.1.214.195.327.284m4.5.534a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm10.5-4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-3-4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Z\" /></BaseIcon>\n);\nexport const CloudShowersIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M12 13v2m0 3v2m4-5v2m0 3v2m-8-7v2m0 3v2\" /></BaseIcon>\n);\nexport const CloudShowersHeavyIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M16 15v6m-8-6v6m4-8v6\" /></BaseIcon>\n);\nexport const CloudSleetIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M13.5 17.45a1 1 0 1 0-2 0h2Zm-2 .1a1 1 0 1 0 2 0h-2Zm.5 3.9a1 1 0 1 0-2 0h2Zm-2 .1a1 1 0 1 0 2 0h-2Zm-6.327-4.868.692-.723-.692.723ZM7 9v1a1 1 0 0 0 .976-.781L7 9Zm2.397-3.207.512.858-.512-.858ZM18 11l-.976-.219A1 1 0 0 0 18 12v-1Zm2.768 5.268a1 1 0 0 0 1.414 1.414l-.707-.707-.707-.707ZM3.379 17.75a1 1 0 0 0 1.242-1.567L4 16.966l-.62.784Zm5.55-.379a1 1 0 0 0-1.857-.742L8 17l.928.371ZM5.071 21.63a1 1 0 0 0 1.856.742L6 22l-.928-.371Zm13.857-4.258a1 1 0 0 0-1.857-.742L18 17l.928.371Zm-3.857 4.258a1 1 0 0 0 1.857.742L16 22l-.928-.371ZM13 17.5h-1a.5.5 0 0 1 .5-.5v2a1.5 1.5 0 0 0 1.5-1.5h-1Zm-.5.5v-1a.5.5 0 0 1 .5.5h-2a1.5 1.5 0 0 0 1.5 1.5v-1Zm-.5-.5h1a.5.5 0 0 1-.5.5v-2a1.5 1.5 0 0 0-1.5 1.5h1Zm.5-.5v1a.5.5 0 0 1-.5-.5h2a1.5 1.5 0 0 0-1.5-1.5v1Zm0 .45h-1v.1h2v-.1h-1Zm-1 4.05h-1a.5.5 0 0 1 .5-.5v2a1.5 1.5 0 0 0 1.5-1.5h-1Zm-.5.5v-1a.5.5 0 0 1 .5.5h-2A1.5 1.5 0 0 0 11 23v-1Zm-.5-.5h1a.5.5 0 0 1-.5.5v-2a1.5 1.5 0 0 0-1.5 1.5h1Zm.5-.5v1a.5.5 0 0 1-.5-.5h2A1.5 1.5 0 0 0 11 20v1Zm0 .45h-1v.1h2v-.1h-1Zm-7.327-4.768.692-.723a3.403 3.403 0 0 1-1.07-2.459h-2c0 1.473.613 2.877 1.687 3.905l.691-.723ZM2.295 13.5h1c0-.914.38-1.8 1.07-2.46l-.692-.722-.69-.723A5.403 5.403 0 0 0 1.294 13.5h1Zm1.378-3.182.692.723A3.815 3.815 0 0 1 7 10V8c-1.499 0-2.945.57-4.018 1.595l.691.723ZM7 9l.976.219c.23-1.024.91-1.956 1.933-2.568l-.512-.858-.513-.859c-1.456.87-2.5 2.245-2.86 3.847L7 9Zm2.397-3.207.512.858a4.972 4.972 0 0 1 1.686-.622l-.173-.985-.174-.985a6.971 6.971 0 0 0-2.364.875l.513.859Zm2.025-.749.173.985a5.223 5.223 0 0 1 1.837.005l.18-.984.178-.984a7.223 7.223 0 0 0-2.542-.007l.174.985Zm2.19.006-.18.984c.606.11 1.177.326 1.681.631l.518-.856.518-.855a6.963 6.963 0 0 0-2.359-.888l-.179.984Zm2.02.76-.519.855c.505.305.93.693 1.257 1.136l.805-.594.805-.594a6.361 6.361 0 0 0-1.831-1.659l-.518.855Zm1.543 1.397-.805.594c.326.442.549.932.66 1.441l.976-.212.978-.213a5.786 5.786 0 0 0-1.005-2.204l-.804.594Zm.831 1.823-.977.212c.111.509.11 1.031-.005 1.539L18 11l.976.219c.178-.792.18-1.609.008-2.402l-.978.213ZM18 11v1h1v-2h-1v1Zm1 0v1a2.5 2.5 0 0 1 1.768.732l.707-.707.707-.707A4.5 4.5 0 0 0 19 10v1Zm2.475 1.025-.707.707A2.5 2.5 0 0 1 21.5 14.5h2a4.5 4.5 0 0 0-1.318-3.182l-.707.707ZM22.5 14.5h-1a2.5 2.5 0 0 1-.732 1.768l.707.707.707.707A4.5 4.5 0 0 0 23.5 14.5h-1ZM4 16.966l.62-.784a3.684 3.684 0 0 1-.255-.223l-.692.723-.69.723c.126.121.259.237.396.345L4 16.966ZM8 17l-.928-.371-2 5L6 22l.928.371 2-5L8 17Zm10 0-.928-.371-2 5L16 22l.928.371 2-5L18 17Z\" /></BaseIcon>\n);\nexport const CloudSnowIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8 15h2m-1-1v2m5-1h2m-1-1v2M5 21h2m-1-1v2m5-2h2m-1-1v2m5 0h2m-1-1v2M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662\" /></BaseIcon>\n);\nexport const CloudSunIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M10.201 19.997c-1.977 0-3.58-1.544-3.58-3.448 0-1.903 1.603-3.446 3.58-3.446.303-1.355 1.38-2.461 2.827-2.902 1.445-.44 3.042-.148 4.186.77 1.144.915 1.663 2.312 1.361 3.667h.761c1.472 0 2.664 1.2 2.664 2.68A2.672 2.672 0 0 1 19.336 20h-9.134m2.66-12.934a4.166 4.166 0 0 0-2.677-1.732m2.677 1.732 2.744-1.892m-2.744 1.892c.55.796.802 1.754.723 2.709m-3.4-4.44a4.167 4.167 0 0 0-3.118.667m3.118-.668.602-3.278m-3.72 3.946A4.167 4.167 0 0 0 5.334 8.68m1.733-2.678L5.174 3.26m.16 5.42c-.2 1.088.041 2.21.669 3.12m-.669-3.12-3.278-.601m3.947 3.72-2.744 1.893m2.744-1.893a4.167 4.167 0 0 0 2.174 1.607\" /></BaseIcon>\n);\nexport const CloudsIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8.958 21.05C6.772 21.05 5 19.344 5 17.24s1.772-3.81 3.958-3.81c.335-1.498 1.525-2.72 3.124-3.207 1.598-.487 3.363-.164 4.628.85 1.264 1.011 1.837 2.556 1.504 4.053h.842A2.953 2.953 0 0 1 22 18.09a2.954 2.954 0 0 1-2.945 2.964H8.958M18 8c-.5-2.5-3.532-3.401-5.5-2.5a3.117 3.117 0 0 0-2.11-2.312c-1.352-.411-2.845-.138-3.915.72-1.07.855-1.554 2.161-1.273 3.428h-.711A2.498 2.498 0 0 0 2 9.843c0 1.094.695 2.023 1.666 2.366\" /></BaseIcon>\n);\nexport const SnowflakeIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"m9.25 4-1 2H6m-2.25 4L5 12m0 0-1.25 2M5 12h3m-3 0H2.5m17.75-2L19 12l1.25 2M6 18h2.25l1 2M14 9h-4m4 0 3-5m-3 5 2 3m-6-3L7 4m3 5-2 3m0 0 2 3m0 0-3 5m3-5h4m2-3-2 3m2-3h5.5M14 15l3 5M14.75 4l1 2H18m0 12h-2.25l-1 2\" /></BaseIcon>\n);\nexport const SunIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M12 4V2m0 20v-2m10-8h-2M4 12H2m15.657-5.657 1.414-1.414M4.93 19.07l1.414-1.414m12.728 1.414-1.414-1.414M6.343 6.343 4.93 4.929M7 12a5 5 0 1 0 10 0 5 5 0 0 0-10 0Z\" /></BaseIcon>\n);\nexport const WindIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M9.59 4.59A2 2 0 1 1 11 8H2m10.59 11.41A2 2 0 1 0 14 16H2m15.73-8.27A2.5 2.5 0 1 1 19.5 12H2\" /></BaseIcon>\n);\n","import React from 'react';\nimport type { IconProps, WeatherCondition } from '../types';\nimport {\n CloudBoltIcon,\n CloudDrizzleIcon,\n CloudFogIcon,\n CloudHailIcon,\n CloudShowersHeavyIcon,\n CloudShowersIcon,\n CloudSleetIcon,\n CloudSnowIcon,\n CloudSunIcon,\n CloudsIcon,\n SnowflakeIcon,\n SunIcon,\n} from './weather-icons';\n\nconst iconMap: Record<WeatherCondition, React.ComponentType<IconProps>> = {\n sun: SunIcon,\n 'cloud-sun': CloudSunIcon,\n clouds: CloudsIcon,\n 'cloud-fog': CloudFogIcon,\n 'cloud-drizzle': CloudDrizzleIcon,\n 'cloud-showers': CloudShowersIcon,\n 'cloud-showers-heavy': CloudShowersHeavyIcon,\n 'cloud-sleet': CloudSleetIcon,\n 'cloud-snow': CloudSnowIcon,\n snowflake: SnowflakeIcon,\n 'cloud-bolt': CloudBoltIcon,\n 'cloud-hail': CloudHailIcon,\n};\n\nexport function WeatherIcon({ condition, ...props }: IconProps & { condition: WeatherCondition }) {\n const Icon = iconMap[condition] || CloudsIcon;\n return <Icon {...props} />;\n}\n","import React from 'react';\nimport { useWeatherForecast } from '../hooks/useWeatherForecast';\nimport type { HourlyWeather, WeatherForecastOptions, WindSpeedUnit } from '../types';\nimport { WeatherIcon } from '../icons/WeatherIcon';\nimport { WindIcon } from '../icons/weather-icons';\n\ntype Props = WeatherForecastOptions & {\n className?: string;\n style?: React.CSSProperties;\n compact?: boolean;\n};\n\nconst WIND_SPEED_UNIT_LABELS: Record<WindSpeedUnit, string> = {\n kmh: 'km/h',\n mph: 'mph',\n ms: 'm/s',\n kn: 'kn',\n};\n\nfunction closestHour(hourly: HourlyWeather[], targetTime: Date): HourlyWeather | undefined {\n return hourly.reduce<HourlyWeather | undefined>((closest, hour) => {\n const diff = Math.abs(new Date(hour.time).getTime() - targetTime.getTime());\n const closestDiff = closest ? Math.abs(new Date(closest.time).getTime() - targetTime.getTime()) : Infinity;\n return diff < closestDiff ? hour : closest;\n }, undefined);\n}\n\nconst styles = {\n root: {\n fontFamily: 'system-ui, sans-serif',\n border: '1px solid #e5e7eb',\n borderRadius: 12,\n padding: 16,\n background: '#fff',\n color: '#111827',\n maxWidth: 640,\n } as React.CSSProperties,\n row: { display: 'flex', alignItems: 'center', gap: 8 } as React.CSSProperties,\n hours: { display: 'flex', gap: 12, overflowX: 'auto', paddingBottom: 4 } as React.CSSProperties,\n hourCard: { minWidth: 72, textAlign: 'center' as const, padding: 8, borderRadius: 8, background: '#f9fafb' },\n dayRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, padding: '8px 0', borderBottom: '1px solid #f3f4f6' } as React.CSSProperties,\n compactRoot: { fontFamily: 'system-ui, sans-serif', display: 'flex', flexDirection: 'column', gap: 8, padding: '10px 14px', borderRadius: 8 } as React.CSSProperties,\n compactHeader: { display: 'flex', alignItems: 'center', gap: 10 } as React.CSSProperties,\n compactHeaderText: { display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' } as React.CSSProperties,\n compactDateTime: { fontSize: 11, opacity: 0.7 } as React.CSSProperties,\n compactStats: { display: 'flex', flexWrap: 'wrap', gap: 12, fontSize: 12, opacity: 0.9 } as React.CSSProperties,\n compactStat: { display: 'flex', alignItems: 'center', gap: 4, whiteSpace: 'nowrap' } as React.CSSProperties,\n};\n\nexport function WeatherForecast(props: Props) {\n const { data, loading, error } = useWeatherForecast(props);\n\n if (loading) return null;\n if (error) return <div className={props.className} style={props.style}>Error: {error.message}</div>;\n if (!data) return <div className={props.className} style={props.style}>No forecast available.</div>;\n\n if (props.compact) {\n const now = new Date(data.current.time);\n const today = data.daily[0];\n const tomorrow = data.daily[1];\n const in6Hours = closestHour(data.hourly, new Date(now.getTime() + 6 * 60 * 60 * 1000));\n const windSpeedUnitLabel = WIND_SPEED_UNIT_LABELS[props.windSpeedUnit ?? 'mph'];\n\n return (\n <div className={props.className} style={{ ...styles.compactRoot, ...props.style }}>\n <div style={styles.compactHeader}>\n <WeatherIcon condition={data.current.icon} width={24} height={24} title=\"Current weather\" />\n <div>\n <div style={styles.compactHeaderText}>\n <strong style={{ fontSize: 16 }}>{data.current.temperature}°</strong>\n <span style={{ fontSize: 14, opacity: 0.8 }}>\n {data.location?.city || 'Current location'}\n </span>\n </div>\n <div style={styles.compactDateTime}>\n {now.toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}\n {' · '}\n {now.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })}\n </div>\n </div>\n </div>\n\n <div style={styles.compactStats}>\n {today && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={today.icon} width={16} height={16} title=\"Today's high and low\" />\n {today.max}° / {today.min}°\n </span>\n )}\n {tomorrow && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={tomorrow.icon} width={16} height={16} title=\"Tomorrow\" />\n Tomorrow {tomorrow.max}°\n </span>\n )}\n <span style={styles.compactStat}>\n <WindIcon width={16} height={16} title=\"Wind speed\" />\n {data.current.windSpeed !== undefined ? `${Math.round(data.current.windSpeed)} ${windSpeedUnitLabel}` : '—'}\n </span>\n {in6Hours && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={in6Hours.icon} width={16} height={16} title=\"In 6 hours\" />\n {in6Hours.temperature}° in 6h\n </span>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div className={props.className} style={{ ...styles.root, ...props.style }}>\n <div>\n <h3 style={{ margin: 0, fontSize: 20 }}>\n {data.location?.city || 'Current location'}\n {data.location?.region ? `, ${data.location.region}` : ''}\n </h3>\n <div style={{ ...styles.row, marginTop: 8 }}>\n <WeatherIcon condition={data.current.icon} width={28} height={28} title=\"Current weather\" />\n <strong style={{ fontSize: 28 }}>{data.current.temperature}°</strong>\n </div>\n </div>\n\n <div style={{ marginTop: 20 }}>\n <h4 style={{ margin: '0 0 10px 0' }}>Next hours</h4>\n <div style={styles.hours}>\n {data.hourly.slice(0, props.forecastHours ?? 12).map((hour) => (\n <div key={hour.time} style={styles.hourCard}>\n <div style={{ fontSize: 12 }}>{new Date(hour.time).toLocaleTimeString([], { hour: 'numeric' })}</div>\n <WeatherIcon condition={hour.icon} width={20} height={20} style={{ margin: '6px auto' }} />\n <div>{hour.temperature}°</div>\n </div>\n ))}\n </div>\n </div>\n\n <div style={{ marginTop: 20 }}>\n <h4 style={{ margin: '0 0 10px 0' }}>Next days</h4>\n <div>\n {data.daily.map((day) => (\n <div key={day.date} style={styles.dayRow}>\n <div style={{ width: 120 }}>{new Date(day.date).toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}</div>\n <WeatherIcon condition={day.icon} width={20} height={20} />\n <div>{day.min}° / {day.max}°</div>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["res","data","jsx","jsx","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/weatherCodes.ts","../src/api/geolocation.ts","../src/api/forecast.ts","../src/hooks/useWeatherForecast.ts","../src/icons/BaseIcon.tsx","../src/icons/weather-icons.tsx","../src/icons/WeatherIcon.tsx","../src/components/WeatherForecast.tsx"],"sourcesContent":["import type { WeatherCondition } from './types';\n\nexport function getWeatherIcon(code: number, isDay = 1): WeatherCondition {\n if (code === 0) return 'sun';\n if ([1, 2].includes(code)) return isDay ? 'cloud-sun' : 'clouds';\n if (code === 3) return 'clouds';\n if ([45, 48].includes(code)) return 'cloud-fog';\n if ([51, 53, 55, 56, 57].includes(code)) return 'cloud-drizzle';\n if ([61, 63].includes(code)) return 'cloud-showers';\n if ([65, 66, 67, 80, 81, 82].includes(code)) return 'cloud-showers-heavy';\n if ([71, 73, 75, 77, 85, 86].includes(code)) return 'cloud-snow';\n if (code === 95) return 'cloud-bolt';\n if ([96, 99].includes(code)) return 'cloud-hail';\n return 'clouds';\n}\n","import type { WeatherLocation } from '../types';\n\nconst DEFAULT_IP_API_URL = 'https://ipapi.co';\n\ntype IpApiResponse = {\n city?: string;\n region?: string;\n country_name?: string;\n timezone?: string;\n latitude?: number;\n longitude?: number;\n error?: boolean;\n reason?: string;\n};\n\ntype GeoWorkerResponse = {\n city?: string;\n region?: string;\n country?: string;\n timezone?: string;\n latitude?: number | string;\n longitude?: number | string;\n};\n\nexport async function getClientLocation(geoEndpoint?: string, ip?: string): Promise<WeatherLocation> {\n if (geoEndpoint) {\n const url = ip ? `${geoEndpoint}?ip=${encodeURIComponent(ip)}` : geoEndpoint;\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Geolocation worker lookup failed: ${res.status}`);\n const data: GeoWorkerResponse = await res.json();\n\n return {\n city: data.city,\n region: data.region,\n country: data.country,\n timezone: data.timezone,\n latitude: Number(data.latitude),\n longitude: Number(data.longitude),\n };\n }\n\n const res = await fetch(`${DEFAULT_IP_API_URL}/${ip ? `${encodeURIComponent(ip)}/` : ''}json/`);\n if (!res.ok) throw new Error(`ipapi.co lookup failed: ${res.status}`);\n const data: IpApiResponse = await res.json();\n\n if (data.error) {\n throw new Error(`ipapi.co lookup failed: ${data.reason ?? 'unknown error'}`);\n }\n\n return {\n city: data.city,\n region: data.region,\n country: data.country_name,\n timezone: data.timezone,\n latitude: Number(data.latitude),\n longitude: Number(data.longitude),\n };\n}\n","import type { WeatherForecastData, WeatherForecastOptions, WeatherLocation } from '../types';\nimport { getWeatherIcon } from '../weatherCodes';\nimport { getClientLocation } from './geolocation';\n\nfunction buildUrl(latitude: number, longitude: number, options: WeatherForecastOptions) {\n const params = new URLSearchParams({\n latitude: String(latitude),\n longitude: String(longitude),\n timezone: options.location?.timezone || 'auto',\n temperature_unit: options.temperatureUnit || 'fahrenheit',\n wind_speed_unit: options.windSpeedUnit || 'mph',\n forecast_days: String(options.forecastDays ?? 5),\n forecast_hours: String(options.forecastHours ?? 24),\n current: [\n 'temperature_2m',\n 'weather_code',\n 'is_day',\n 'rain',\n 'showers',\n 'snowfall',\n 'wind_speed_10m',\n ].join(','),\n hourly: [\n 'temperature_2m',\n 'weather_code',\n 'precipitation_probability',\n 'rain',\n 'showers',\n 'snowfall',\n ].join(','),\n daily: [\n 'temperature_2m_max',\n 'temperature_2m_min',\n 'weather_code',\n 'precipitation_probability_max',\n ].join(','),\n });\n\n return `https://api.open-meteo.com/v1/forecast?${params.toString()}`;\n}\n\nexport async function getWeatherForecast(\n options: WeatherForecastOptions = {}\n): Promise<WeatherForecastData> {\n let location: WeatherLocation;\n\n if (typeof options.latitude === 'number' && typeof options.longitude === 'number') {\n location = {\n ...options.location,\n latitude: options.latitude,\n longitude: options.longitude,\n };\n } else {\n location = await getClientLocation(options.geoEndpoint, options.ip);\n }\n\n const url = buildUrl(location.latitude, location.longitude, { ...options, location });\n const response = await fetch(url, { headers: { 'Content-Type': 'application/json' } });\n\n if (!response.ok) {\n throw new Error(`Weather request failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n\n if (!data?.current || !data?.hourly || !data?.daily) {\n throw new Error('Invalid weather response');\n }\n\n return {\n location,\n current: {\n time: data.current.time,\n temperature: Math.round(data.current.temperature_2m),\n weatherCode: data.current.weather_code,\n icon: getWeatherIcon(data.current.weather_code, data.current.is_day),\n isDay: data.current.is_day,\n rain: data.current.rain,\n showers: data.current.showers,\n snowfall: data.current.snowfall,\n windSpeed: data.current.wind_speed_10m,\n },\n hourly: data.hourly.time.map((time: string, index: number) => ({\n time,\n temperature: Math.round(data.hourly.temperature_2m[index]),\n weatherCode: data.hourly.weather_code[index],\n precipitationProbability: data.hourly.precipitation_probability?.[index],\n rain: data.hourly.rain?.[index],\n showers: data.hourly.showers?.[index],\n snowfall: data.hourly.snowfall?.[index],\n icon: getWeatherIcon(data.hourly.weather_code[index]),\n })),\n daily: data.daily.time.map((date: string, index: number) => ({\n date,\n min: Math.round(data.daily.temperature_2m_min[index]),\n max: Math.round(data.daily.temperature_2m_max[index]),\n weatherCode: data.daily.weather_code[index],\n precipitationProbabilityMax: data.daily.precipitation_probability_max?.[index],\n icon: getWeatherIcon(data.daily.weather_code[index]),\n })),\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { WeatherForecastData, WeatherForecastOptions } from '../types';\nimport { getWeatherForecast } from '../api/forecast';\n\nexport function useWeatherForecast(options: WeatherForecastOptions = {}) {\n const [data, setData] = useState<WeatherForecastData | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let active = true;\n setLoading(true);\n setError(null);\n\n getWeatherForecast(options)\n .then((result) => { if (active) setData(result); })\n .catch((err) => { if (active) setError(err instanceof Error ? err : new Error('Unknown error')); })\n .finally(() => { if (active) setLoading(false); });\n\n return () => { active = false; };\n }, [\n options.latitude,\n options.longitude,\n options.geoEndpoint,\n options.ip,\n options.forecastDays,\n options.forecastHours,\n options.temperatureUnit,\n options.windSpeedUnit,\n options.location?.timezone,\n ]);\n\n return { data, error, loading };\n}\n","import React from 'react';\nimport type { IconProps } from '../types';\n\nexport function BaseIcon({ title, children, ...props }: IconProps & { children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n role={title ? 'img' : 'presentation'}\n aria-hidden={title ? undefined : true}\n aria-label={title}\n {...props}\n >\n {title ? <title>{title}</title> : null}\n {children}\n </svg>\n );\n}\n","import React from 'react';\nimport type { IconProps } from '../types';\nimport { BaseIcon } from './BaseIcon';\n\nexport const CloudBoltIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M7 18a4.815 4.815 0 0 1-3.327-1.318A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 0 7h-1m-4.75-5L11 17.5h3.375l-2.25 4.5\" /></BaseIcon>\n);\nexport const CloudDrizzleIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M12 18v1m-3-4v1m6-1v1m2 3v1M7 19v1m-3-3.034a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662\" /></BaseIcon>\n);\nexport const CloudFogIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M5 21h7m4 0h3M8 17h8\" /></BaseIcon>\n);\nexport const CloudHailIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8 17.45v.1m-1.5 3.9v.1m10.5-4.1v.1m-1.5 3.9v.1m-3-4.1v.1m-1.5 3.9v.1m10.475-4.575A3.5 3.5 0 0 0 19 11h-1c.146-.65.148-1.32.006-1.97a4.784 4.784 0 0 0-.831-1.823 5.36 5.36 0 0 0-1.544-1.398 5.964 5.964 0 0 0-2.02-.759 6.224 6.224 0 0 0-2.19-.006 5.971 5.971 0 0 0-2.024.749C8.157 6.533 7.295 7.687 7 9a4.815 4.815 0 0 0-3.327 1.318A4.403 4.403 0 0 0 2.295 13.5c0 1.194.496 2.338 1.378 3.182.105.1.214.195.327.284m4.5.534a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm10.5-4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-3-4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-1.5 4a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Z\" /></BaseIcon>\n);\nexport const CloudShowersIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M12 13v2m0 3v2m4-5v2m0 3v2m-8-7v2m0 3v2\" /></BaseIcon>\n);\nexport const CloudShowersHeavyIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662M16 15v6m-8-6v6m4-8v6\" /></BaseIcon>\n);\nexport const CloudSleetIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M13.5 17.45a1 1 0 1 0-2 0h2Zm-2 .1a1 1 0 1 0 2 0h-2Zm.5 3.9a1 1 0 1 0-2 0h2Zm-2 .1a1 1 0 1 0 2 0h-2Zm-6.327-4.868.692-.723-.692.723ZM7 9v1a1 1 0 0 0 .976-.781L7 9Zm2.397-3.207.512.858-.512-.858ZM18 11l-.976-.219A1 1 0 0 0 18 12v-1Zm2.768 5.268a1 1 0 0 0 1.414 1.414l-.707-.707-.707-.707ZM3.379 17.75a1 1 0 0 0 1.242-1.567L4 16.966l-.62.784Zm5.55-.379a1 1 0 0 0-1.857-.742L8 17l.928.371ZM5.071 21.63a1 1 0 0 0 1.856.742L6 22l-.928-.371Zm13.857-4.258a1 1 0 0 0-1.857-.742L18 17l.928.371Zm-3.857 4.258a1 1 0 0 0 1.857.742L16 22l-.928-.371ZM13 17.5h-1a.5.5 0 0 1 .5-.5v2a1.5 1.5 0 0 0 1.5-1.5h-1Zm-.5.5v-1a.5.5 0 0 1 .5.5h-2a1.5 1.5 0 0 0 1.5 1.5v-1Zm-.5-.5h1a.5.5 0 0 1-.5.5v-2a1.5 1.5 0 0 0-1.5 1.5h1Zm.5-.5v1a.5.5 0 0 1-.5-.5h2a1.5 1.5 0 0 0-1.5-1.5v1Zm0 .45h-1v.1h2v-.1h-1Zm-1 4.05h-1a.5.5 0 0 1 .5-.5v2a1.5 1.5 0 0 0 1.5-1.5h-1Zm-.5.5v-1a.5.5 0 0 1 .5.5h-2A1.5 1.5 0 0 0 11 23v-1Zm-.5-.5h1a.5.5 0 0 1-.5.5v-2a1.5 1.5 0 0 0-1.5 1.5h1Zm.5-.5v1a.5.5 0 0 1-.5-.5h2A1.5 1.5 0 0 0 11 20v1Zm0 .45h-1v.1h2v-.1h-1Zm-7.327-4.768.692-.723a3.403 3.403 0 0 1-1.07-2.459h-2c0 1.473.613 2.877 1.687 3.905l.691-.723ZM2.295 13.5h1c0-.914.38-1.8 1.07-2.46l-.692-.722-.69-.723A5.403 5.403 0 0 0 1.294 13.5h1Zm1.378-3.182.692.723A3.815 3.815 0 0 1 7 10V8c-1.499 0-2.945.57-4.018 1.595l.691.723ZM7 9l.976.219c.23-1.024.91-1.956 1.933-2.568l-.512-.858-.513-.859c-1.456.87-2.5 2.245-2.86 3.847L7 9Zm2.397-3.207.512.858a4.972 4.972 0 0 1 1.686-.622l-.173-.985-.174-.985a6.971 6.971 0 0 0-2.364.875l.513.859Zm2.025-.749.173.985a5.223 5.223 0 0 1 1.837.005l.18-.984.178-.984a7.223 7.223 0 0 0-2.542-.007l.174.985Zm2.19.006-.18.984c.606.11 1.177.326 1.681.631l.518-.856.518-.855a6.963 6.963 0 0 0-2.359-.888l-.179.984Zm2.02.76-.519.855c.505.305.93.693 1.257 1.136l.805-.594.805-.594a6.361 6.361 0 0 0-1.831-1.659l-.518.855Zm1.543 1.397-.805.594c.326.442.549.932.66 1.441l.976-.212.978-.213a5.786 5.786 0 0 0-1.005-2.204l-.804.594Zm.831 1.823-.977.212c.111.509.11 1.031-.005 1.539L18 11l.976.219c.178-.792.18-1.609.008-2.402l-.978.213ZM18 11v1h1v-2h-1v1Zm1 0v1a2.5 2.5 0 0 1 1.768.732l.707-.707.707-.707A4.5 4.5 0 0 0 19 10v1Zm2.475 1.025-.707.707A2.5 2.5 0 0 1 21.5 14.5h2a4.5 4.5 0 0 0-1.318-3.182l-.707.707ZM22.5 14.5h-1a2.5 2.5 0 0 1-.732 1.768l.707.707.707.707A4.5 4.5 0 0 0 23.5 14.5h-1ZM4 16.966l.62-.784a3.684 3.684 0 0 1-.255-.223l-.692.723-.69.723c.126.121.259.237.396.345L4 16.966ZM8 17l-.928-.371-2 5L6 22l.928.371 2-5L8 17Zm10 0-.928-.371-2 5L16 22l.928.371 2-5L18 17Z\" /></BaseIcon>\n);\nexport const CloudSnowIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8 15h2m-1-1v2m5-1h2m-1-1v2M5 21h2m-1-1v2m5-2h2m-1-1v2m5 0h2m-1-1v2M4 16.966a4.63 4.63 0 0 1-.327-.284A4.403 4.403 0 0 1 2.295 13.5c0-1.194.496-2.338 1.378-3.182A4.815 4.815 0 0 1 7 9c.295-1.313 1.157-2.466 2.397-3.207a5.971 5.971 0 0 1 2.025-.749 6.224 6.224 0 0 1 2.19.006c.721.131 1.408.39 2.02.76a5.36 5.36 0 0 1 1.543 1.397c.407.552.69 1.172.831 1.823.142.65.14 1.32-.006 1.97h1a3.5 3.5 0 0 1 1.5 6.662\" /></BaseIcon>\n);\nexport const CloudSunIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M10.201 19.997c-1.977 0-3.58-1.544-3.58-3.448 0-1.903 1.603-3.446 3.58-3.446.303-1.355 1.38-2.461 2.827-2.902 1.445-.44 3.042-.148 4.186.77 1.144.915 1.663 2.312 1.361 3.667h.761c1.472 0 2.664 1.2 2.664 2.68A2.672 2.672 0 0 1 19.336 20h-9.134m2.66-12.934a4.166 4.166 0 0 0-2.677-1.732m2.677 1.732 2.744-1.892m-2.744 1.892c.55.796.802 1.754.723 2.709m-3.4-4.44a4.167 4.167 0 0 0-3.118.667m3.118-.668.602-3.278m-3.72 3.946A4.167 4.167 0 0 0 5.334 8.68m1.733-2.678L5.174 3.26m.16 5.42c-.2 1.088.041 2.21.669 3.12m-.669-3.12-3.278-.601m3.947 3.72-2.744 1.893m2.744-1.893a4.167 4.167 0 0 0 2.174 1.607\" /></BaseIcon>\n);\nexport const CloudsIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M8.958 21.05C6.772 21.05 5 19.344 5 17.24s1.772-3.81 3.958-3.81c.335-1.498 1.525-2.72 3.124-3.207 1.598-.487 3.363-.164 4.628.85 1.264 1.011 1.837 2.556 1.504 4.053h.842A2.953 2.953 0 0 1 22 18.09a2.954 2.954 0 0 1-2.945 2.964H8.958M18 8c-.5-2.5-3.532-3.401-5.5-2.5a3.117 3.117 0 0 0-2.11-2.312c-1.352-.411-2.845-.138-3.915.72-1.07.855-1.554 2.161-1.273 3.428h-.711A2.498 2.498 0 0 0 2 9.843c0 1.094.695 2.023 1.666 2.366\" /></BaseIcon>\n);\nexport const SnowflakeIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"m9.25 4-1 2H6m-2.25 4L5 12m0 0-1.25 2M5 12h3m-3 0H2.5m17.75-2L19 12l1.25 2M6 18h2.25l1 2M14 9h-4m4 0 3-5m-3 5 2 3m-6-3L7 4m3 5-2 3m0 0 2 3m0 0-3 5m3-5h4m2-3-2 3m2-3h5.5M14 15l3 5M14.75 4l1 2H18m0 12h-2.25l-1 2\" /></BaseIcon>\n);\nexport const SunIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M12 4V2m0 20v-2m10-8h-2M4 12H2m15.657-5.657 1.414-1.414M4.93 19.07l1.414-1.414m12.728 1.414-1.414-1.414M6.343 6.343 4.93 4.929M7 12a5 5 0 1 0 10 0 5 5 0 0 0-10 0Z\" /></BaseIcon>\n);\nexport const WindIcon = (props: IconProps) => (\n <BaseIcon {...props}><path d=\"M9.59 4.59A2 2 0 1 1 11 8H2m10.59 11.41A2 2 0 1 0 14 16H2m15.73-8.27A2.5 2.5 0 1 1 19.5 12H2\" /></BaseIcon>\n);\n","import React from 'react';\nimport type { IconProps, WeatherCondition } from '../types';\nimport {\n CloudBoltIcon,\n CloudDrizzleIcon,\n CloudFogIcon,\n CloudHailIcon,\n CloudShowersHeavyIcon,\n CloudShowersIcon,\n CloudSleetIcon,\n CloudSnowIcon,\n CloudSunIcon,\n CloudsIcon,\n SnowflakeIcon,\n SunIcon,\n} from './weather-icons';\n\nconst iconMap: Record<WeatherCondition, React.ComponentType<IconProps>> = {\n sun: SunIcon,\n 'cloud-sun': CloudSunIcon,\n clouds: CloudsIcon,\n 'cloud-fog': CloudFogIcon,\n 'cloud-drizzle': CloudDrizzleIcon,\n 'cloud-showers': CloudShowersIcon,\n 'cloud-showers-heavy': CloudShowersHeavyIcon,\n 'cloud-sleet': CloudSleetIcon,\n 'cloud-snow': CloudSnowIcon,\n snowflake: SnowflakeIcon,\n 'cloud-bolt': CloudBoltIcon,\n 'cloud-hail': CloudHailIcon,\n};\n\nexport function WeatherIcon({ condition, ...props }: IconProps & { condition: WeatherCondition }) {\n const Icon = iconMap[condition] || CloudsIcon;\n return <Icon {...props} />;\n}\n","import React from 'react';\nimport { useWeatherForecast } from '../hooks/useWeatherForecast';\nimport type { HourlyWeather, WeatherForecastOptions, WindSpeedUnit } from '../types';\nimport { WeatherIcon } from '../icons/WeatherIcon';\nimport { WindIcon } from '../icons/weather-icons';\n\ntype Props = WeatherForecastOptions & {\n className?: string;\n style?: React.CSSProperties;\n compact?: boolean;\n};\n\nconst WIND_SPEED_UNIT_LABELS: Record<WindSpeedUnit, string> = {\n kmh: 'km/h',\n mph: 'mph',\n ms: 'm/s',\n kn: 'kn',\n};\n\nfunction closestHour(hourly: HourlyWeather[], targetTime: Date): HourlyWeather | undefined {\n return hourly.reduce<HourlyWeather | undefined>((closest, hour) => {\n const diff = Math.abs(new Date(hour.time).getTime() - targetTime.getTime());\n const closestDiff = closest ? Math.abs(new Date(closest.time).getTime() - targetTime.getTime()) : Infinity;\n return diff < closestDiff ? hour : closest;\n }, undefined);\n}\n\nconst styles = {\n root: {\n fontFamily: 'system-ui, sans-serif',\n border: '1px solid #e5e7eb',\n borderRadius: 12,\n padding: 16,\n background: '#fff',\n color: '#111827',\n maxWidth: 640,\n } as React.CSSProperties,\n row: { display: 'flex', alignItems: 'center', gap: 8 } as React.CSSProperties,\n hours: { display: 'flex', gap: 12, overflowX: 'auto', paddingBottom: 4 } as React.CSSProperties,\n hourCard: { minWidth: 72, textAlign: 'center' as const, padding: 8, borderRadius: 8, background: '#f9fafb' },\n dayRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, padding: '8px 0', borderBottom: '1px solid #f3f4f6' } as React.CSSProperties,\n compactRoot: { fontFamily: 'system-ui, sans-serif', display: 'flex', flexDirection: 'column', gap: 8, padding: '10px 14px', borderRadius: 8 } as React.CSSProperties,\n compactHeader: { display: 'flex', alignItems: 'center', gap: 10 } as React.CSSProperties,\n compactHeaderText: { display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' } as React.CSSProperties,\n compactDateTime: { fontSize: 11, opacity: 0.7 } as React.CSSProperties,\n compactStats: { display: 'flex', flexWrap: 'wrap', gap: 12, fontSize: 12, opacity: 0.9 } as React.CSSProperties,\n compactStat: { display: 'flex', alignItems: 'center', gap: 4, whiteSpace: 'nowrap' } as React.CSSProperties,\n};\n\nexport function WeatherForecast(props: Props) {\n const { data, loading, error } = useWeatherForecast(props);\n\n if (loading) return null;\n if (error) return <div className={props.className} style={props.style}>Error: {error.message}</div>;\n if (!data) return <div className={props.className} style={props.style}>No forecast available.</div>;\n\n if (props.compact) {\n const now = new Date(data.current.time);\n const today = data.daily[0];\n const tomorrow = data.daily[1];\n const in6Hours = closestHour(data.hourly, new Date(now.getTime() + 6 * 60 * 60 * 1000));\n const windSpeedUnitLabel = WIND_SPEED_UNIT_LABELS[props.windSpeedUnit ?? 'mph'];\n\n return (\n <div className={props.className} style={{ ...styles.compactRoot, ...props.style }}>\n <div style={styles.compactHeader}>\n <WeatherIcon condition={data.current.icon} width={24} height={24} title=\"Current weather\" />\n <div>\n <div style={styles.compactHeaderText}>\n <strong style={{ fontSize: 16 }}>{data.current.temperature}°</strong>\n <span style={{ fontSize: 14, opacity: 0.8 }}>\n {data.location?.city || 'Current location'}\n </span>\n </div>\n <div style={styles.compactDateTime}>\n {now.toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}\n {' · '}\n {now.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })}\n </div>\n </div>\n </div>\n\n <div style={styles.compactStats}>\n {today && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={today.icon} width={16} height={16} title=\"Today's high and low\" />\n {today.max}° / {today.min}°\n </span>\n )}\n {tomorrow && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={tomorrow.icon} width={16} height={16} title=\"Tomorrow\" />\n Tomorrow {tomorrow.max}°\n </span>\n )}\n <span style={styles.compactStat}>\n <WindIcon width={16} height={16} title=\"Wind speed\" />\n {data.current.windSpeed !== undefined ? `${Math.round(data.current.windSpeed)} ${windSpeedUnitLabel}` : '—'}\n </span>\n {in6Hours && (\n <span style={styles.compactStat}>\n <WeatherIcon condition={in6Hours.icon} width={16} height={16} title=\"In 6 hours\" />\n {in6Hours.temperature}° in 6h\n </span>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div className={props.className} style={{ ...styles.root, ...props.style }}>\n <div>\n <h3 style={{ margin: 0, fontSize: 20 }}>\n {data.location?.city || 'Current location'}\n {data.location?.region ? `, ${data.location.region}` : ''}\n </h3>\n <div style={{ ...styles.row, marginTop: 8 }}>\n <WeatherIcon condition={data.current.icon} width={28} height={28} title=\"Current weather\" />\n <strong style={{ fontSize: 28 }}>{data.current.temperature}°</strong>\n </div>\n </div>\n\n <div style={{ marginTop: 20 }}>\n <h4 style={{ margin: '0 0 10px 0' }}>Next hours</h4>\n <div style={styles.hours}>\n {data.hourly.slice(0, props.forecastHours ?? 12).map((hour) => (\n <div key={hour.time} style={styles.hourCard}>\n <div style={{ fontSize: 12 }}>{new Date(hour.time).toLocaleTimeString([], { hour: 'numeric' })}</div>\n <WeatherIcon condition={hour.icon} width={20} height={20} style={{ margin: '6px auto' }} />\n <div>{hour.temperature}°</div>\n </div>\n ))}\n </div>\n </div>\n\n <div style={{ marginTop: 20 }}>\n <h4 style={{ margin: '0 0 10px 0' }}>Next days</h4>\n <div>\n {data.daily.map((day) => (\n <div key={day.date} style={styles.dayRow}>\n <div style={{ width: 120 }}>{new Date(day.date).toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}</div>\n <WeatherIcon condition={day.icon} width={20} height={20} />\n <div>{day.min}° / {day.max}°</div>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["res","data","jsx","jsx","jsx","jsxs"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "use-weather-forecast",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React weather forecast component using Open-Meteo and IP geolocation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"forecast",
|
|
9
9
|
"open-meteo",
|
|
10
10
|
"cloudflare",
|
|
11
|
-
"
|
|
11
|
+
"ipapi",
|
|
12
12
|
"component-library"
|
|
13
13
|
],
|
|
14
14
|
"repository": {
|
|
@@ -52,4 +52,4 @@
|
|
|
52
52
|
"worker:dev": "wrangler dev --config worker/wrangler.jsonc",
|
|
53
53
|
"worker:deploy": "wrangler deploy --config worker/wrangler.jsonc"
|
|
54
54
|
}
|
|
55
|
-
}
|
|
55
|
+
}
|