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 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/ip-api for IP geolocation.
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 `ip-api.com`
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 `ip-api.com` directly
68
- from the browser. **Note:** ip-api.com's free tier only serves plain HTTP, so this
69
- fallback will be blocked as mixed content on pages served over HTTPS — deploy the
70
- worker and pass `geoEndpoint` for any HTTPS site.
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 ip-api.com power IP geolocation (see above).
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 = "http://ip-api.com/json/";
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}${ip ? encodeURIComponent(ip) : ""}`);
65
- if (!res.ok) throw new Error(`ip-api lookup failed: ${res.status}`);
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.status === "fail") {
68
- throw new Error(`ip-api lookup failed: ${data.message ?? "unknown 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.regionName,
73
- country: data.country,
72
+ region: data.region,
73
+ country: data.country_name,
74
74
  timezone: data.timezone,
75
- latitude: Number(data.lat),
76
- longitude: Number(data.lon)
75
+ latitude: Number(data.latitude),
76
+ longitude: Number(data.longitude)
77
77
  };
78
78
  }
79
79
 
@@ -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":"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","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 = "http://ip-api.com/json/";
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}${ip ? encodeURIComponent(ip) : ""}`);
34
- if (!res.ok) throw new Error(`ip-api lookup failed: ${res.status}`);
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.status === "fail") {
37
- throw new Error(`ip-api lookup failed: ${data.message ?? "unknown 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.regionName,
42
- country: data.country,
41
+ region: data.region,
42
+ country: data.country_name,
43
43
  timezone: data.timezone,
44
- latitude: Number(data.lat),
45
- longitude: Number(data.lon)
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.0",
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
- "ip-api",
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
+ }