{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "weather-dashboard-shadcnui", "type": "registry:component", "title": "Weather Dashboard", "description": "Immersive weather dashboard with hourly charting, weekly outlook, and live air-quality alerts", "registryDependencies": [ "button" ], "dependencies": [ "framer-motion", "react" ], "files": [ { "path": "@uitripled/react-shadcn/src/components/components/weather/weather-dashboard.tsx", "content": "\"use client\";\n\nimport type React from \"react\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { motion, type Variants } from \"framer-motion\";\nimport {\n CalendarDays,\n Cloud,\n CloudLightning,\n CloudRain,\n Droplets,\n Gauge,\n LucideIcon,\n MapPin,\n RefreshCcw,\n Sun,\n Sunrise,\n Sunset,\n Umbrella,\n Wind,\n} from \"lucide-react\";\nimport { useMemo } from \"react\";\nimport {\n Area,\n AreaChart,\n CartesianGrid,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n} from \"recharts\";\n\ntype WeatherCondition = \"sunny\" | \"rain\" | \"cloudy\" | \"storm\";\n\ntype HourlyForecast = {\n time: string;\n temperature: number;\n feelsLike: number;\n precipitationChance: number;\n windSpeed: number;\n condition: WeatherCondition;\n};\n\ntype WeeklyForecast = {\n day: string;\n high: number;\n low: number;\n precipitationChance: number;\n condition: WeatherCondition;\n};\n\ntype WeatherMetric = {\n label: string;\n value: string;\n description: string;\n icon: LucideIcon;\n};\n\ntype AirQualityMetric = {\n label: string;\n value: string;\n status: string;\n description: string;\n};\n\ntype AlertSeverity = \"Advisory\" | \"Watch\" | \"Warning\";\n\ntype WeatherAlert = {\n title: string;\n description: string;\n severity: AlertSeverity;\n icon: LucideIcon;\n};\n\ntype WeatherData = {\n location: string;\n updatedAt: string;\n current: {\n temperature: number;\n feelsLike: number;\n summary: string;\n condition: WeatherCondition;\n humidity: number;\n precipitationChance: number;\n windSpeed: number;\n pressure: number;\n sunrise: string;\n sunset: string;\n };\n hourly: HourlyForecast[];\n weekly: WeeklyForecast[];\n airQuality: AirQualityMetric[];\n alerts: WeatherAlert[];\n};\n\nconst STATIC_WEATHER_DATA: WeatherData = {\n location: \"San Francisco, CA\",\n updatedAt: \"2024-07-12T16:00:00.000Z\",\n current: {\n temperature: 64,\n feelsLike: 62,\n summary: \"Mostly sunny with a coastal breeze\",\n condition: \"sunny\",\n humidity: 62,\n precipitationChance: 15,\n windSpeed: 12,\n pressure: 1016,\n sunrise: \"2024-07-12T13:58:00.000Z\",\n sunset: \"2024-07-13T03:33:00.000Z\",\n },\n hourly: [\n {\n time: \"2024-07-12T16:00:00.000Z\",\n temperature: 60,\n feelsLike: 59,\n precipitationChance: 10,\n windSpeed: 10,\n condition: \"sunny\",\n },\n {\n time: \"2024-07-12T17:00:00.000Z\",\n temperature: 61,\n feelsLike: 60,\n precipitationChance: 12,\n windSpeed: 11,\n condition: \"sunny\",\n },\n {\n time: \"2024-07-12T18:00:00.000Z\",\n temperature: 62,\n feelsLike: 61,\n precipitationChance: 12,\n windSpeed: 12,\n condition: \"sunny\",\n },\n {\n time: \"2024-07-12T19:00:00.000Z\",\n temperature: 63,\n feelsLike: 62,\n precipitationChance: 15,\n windSpeed: 13,\n condition: \"sunny\",\n },\n {\n time: \"2024-07-12T20:00:00.000Z\",\n temperature: 64,\n feelsLike: 63,\n precipitationChance: 18,\n windSpeed: 14,\n condition: \"sunny\",\n },\n {\n time: \"2024-07-12T21:00:00.000Z\",\n temperature: 65,\n feelsLike: 64,\n precipitationChance: 20,\n windSpeed: 14,\n condition: \"sunny\",\n },\n {\n time: \"2024-07-12T22:00:00.000Z\",\n temperature: 66,\n feelsLike: 65,\n precipitationChance: 20,\n windSpeed: 13,\n condition: \"sunny\",\n },\n {\n time: \"2024-07-12T23:00:00.000Z\",\n temperature: 65,\n feelsLike: 64,\n precipitationChance: 18,\n windSpeed: 12,\n condition: \"sunny\",\n },\n {\n time: \"2024-07-13T00:00:00.000Z\",\n temperature: 63,\n feelsLike: 62,\n precipitationChance: 15,\n windSpeed: 11,\n condition: \"cloudy\",\n },\n {\n time: \"2024-07-13T01:00:00.000Z\",\n temperature: 61,\n feelsLike: 60,\n precipitationChance: 12,\n windSpeed: 10,\n condition: \"cloudy\",\n },\n {\n time: \"2024-07-13T02:00:00.000Z\",\n temperature: 59,\n feelsLike: 58,\n precipitationChance: 10,\n windSpeed: 9,\n condition: \"cloudy\",\n },\n {\n time: \"2024-07-13T03:00:00.000Z\",\n temperature: 58,\n feelsLike: 57,\n precipitationChance: 8,\n windSpeed: 8,\n condition: \"cloudy\",\n },\n ],\n weekly: [\n {\n day: \"2024-07-12\",\n high: 66,\n low: 56,\n precipitationChance: 20,\n condition: \"sunny\",\n },\n {\n day: \"2024-07-13\",\n high: 65,\n low: 55,\n precipitationChance: 25,\n condition: \"sunny\",\n },\n {\n day: \"2024-07-14\",\n high: 64,\n low: 54,\n precipitationChance: 30,\n condition: \"cloudy\",\n },\n {\n day: \"2024-07-15\",\n high: 63,\n low: 54,\n precipitationChance: 40,\n condition: \"cloudy\",\n },\n {\n day: \"2024-07-16\",\n high: 62,\n low: 53,\n precipitationChance: 45,\n condition: \"rain\",\n },\n {\n day: \"2024-07-17\",\n high: 64,\n low: 54,\n precipitationChance: 30,\n condition: \"sunny\",\n },\n {\n day: \"2024-07-18\",\n high: 67,\n low: 55,\n precipitationChance: 15,\n condition: \"sunny\",\n },\n ],\n airQuality: [\n {\n label: \"US AQI\",\n value: \"42\",\n status: \"Good\",\n description:\n \"Clear coastal air with minimal particulate matter detected.\",\n },\n {\n label: \"PM2.5\",\n value: \"8.6 µg/m³\",\n status: \"Low particulate levels\",\n description: \"Fine particulates remain well below daily thresholds.\",\n },\n {\n label: \"Dust Index\",\n value: \"18.4 µg/m³\",\n status: \"Minimal dust\",\n description: \"Marine influence keeps airborne dust concentrations low.\",\n },\n ],\n alerts: [\n {\n title: \"Mild onshore breeze continues\",\n description:\n \"Expect a gentle westerly wind through the afternoon with choppy bay waters.\",\n severity: \"Advisory\",\n icon: Wind,\n },\n {\n title: \"Low rain chance through weekend\",\n description:\n \"Stray mist possible near the coast late nights, but dry for most plans.\",\n severity: \"Watch\",\n icon: Umbrella,\n },\n ],\n};\n\nconst containerVariants: Variants = {\n hidden: { opacity: 0 },\n visible: {\n opacity: 1,\n transition: {\n staggerChildren: 0.1,\n delayChildren: 0.2,\n },\n },\n};\n\nconst itemVariants: Variants = {\n hidden: { opacity: 0, y: 16 },\n visible: {\n opacity: 1,\n y: 0,\n transition: { duration: 0.4, ease: \"easeOut\" },\n },\n};\n\nconst listItemVariants: Variants = {\n hidden: { opacity: 0, y: 12 },\n visible: {\n opacity: 1,\n y: 0,\n transition: { duration: 0.35, ease: \"easeOut\" },\n },\n};\n\nconst SEVERITY_STYLES: Record = {\n Advisory: \"bg-blue-500/20 text-blue-600 dark:text-blue-400\",\n Watch: \"bg-amber-500/20 text-amber-600 dark:text-amber-400\",\n Warning: \"bg-red-500/20 text-red-600 dark:text-red-400\",\n};\n\nconst CONDITION_ICONS: Record = {\n sunny: Sun,\n rain: CloudRain,\n cloudy: Cloud,\n storm: CloudLightning,\n};\n\nfunction formatHour(timestamp: string, timezone?: string) {\n return new Intl.DateTimeFormat(undefined, {\n hour: \"numeric\",\n hour12: true,\n timeZone: timezone,\n }).format(new Date(timestamp));\n}\n\nfunction formatDay(timestamp: string, timezone?: string) {\n return new Intl.DateTimeFormat(undefined, {\n weekday: \"short\",\n timeZone: timezone,\n }).format(new Date(timestamp));\n}\n\nfunction formatTime(timestamp: string, timezone?: string) {\n return new Intl.DateTimeFormat(undefined, {\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n timeZone: timezone,\n }).format(new Date(timestamp));\n}\n\nfunction describeHumidity(value: number) {\n if (value >= 70) return \"Humid – expect a touch of mugginess\";\n if (value <= 30) return \"Dry air – hydrate frequently\";\n return \"Comfortable humidity for outdoor plans\";\n}\n\nfunction describeWind(speed: number) {\n if (speed >= 25) return \"Breezy with gusts – secure loose items\";\n if (speed >= 15) return \"Noticeable breeze across the bay\";\n return \"Light winds – calm conditions\";\n}\n\nfunction describePressure(value: number) {\n if (value >= 1020) return \"High pressure holding – skies stay stable\";\n if (value <= 1005) return \"Low pressure developing – expect shifts\";\n return \"Steady pressure – minimal change expected\";\n}\n\nfunction describePrecipitation(chance: number) {\n if (chance >= 60) return \"Keep rain gear handy\";\n if (chance >= 30) return \"Spotty showers possible\";\n return \"Minimal chance of precipitation\";\n}\n\nexport function WeatherDashboard(): React.ReactElement {\n const activeView = \"today\";\n const weatherData = STATIC_WEATHER_DATA;\n\n const weatherMetrics = useMemo(() => {\n return [\n {\n label: \"Humidity\",\n value: weatherData.current.humidity + \"%\",\n description: describeHumidity(weatherData.current.humidity),\n icon: Droplets,\n },\n {\n label: \"Wind\",\n value: weatherData.current.windSpeed + \" mph\",\n description: describeWind(weatherData.current.windSpeed),\n icon: Wind,\n },\n {\n label: \"Pressure\",\n value: weatherData.current.pressure + \" hPa\",\n description: describePressure(weatherData.current.pressure),\n icon: Gauge,\n },\n {\n label: \"Precipitation\",\n value: weatherData.current.precipitationChance + \"%\",\n description: describePrecipitation(\n weatherData.current.precipitationChance\n ),\n icon: Umbrella,\n },\n ];\n }, [weatherData]);\n\n const hourlyChartData = useMemo(\n () =>\n weatherData.hourly.slice(0, 12).map((hour) => ({\n name: formatHour(hour.time),\n temperature: hour.temperature,\n feelsLike: hour.feelsLike,\n })),\n [weatherData]\n );\n\n const hourlyForecast = weatherData.hourly.slice(0, 8);\n const weeklyForecast = weatherData.weekly.slice(0, 7);\n const airQualityMetrics = weatherData.airQuality;\n const alerts = weatherData.alerts;\n\n const updatedMinutesAgo = useMemo(() => {\n const updatedDate = new Date(weatherData.updatedAt);\n const diffMinutes = Math.floor(\n (Date.now() - updatedDate.getTime()) / (1000 * 60)\n );\n if (diffMinutes <= 1) return \"Updated moments ago\";\n if (diffMinutes < 60) return \"Updated \" + diffMinutes + \" minutes ago\";\n const diffHours = Math.floor(diffMinutes / 60);\n if (diffHours === 1) return \"Updated about an hour ago\";\n return \"Updated \" + diffHours + \" hours ago\";\n }, [weatherData.updatedAt]);\n\n return (\n
\n
\n
\n
\n \n \n 7-Day Coastal Outlook\n \n\n
\n

\n Coastal Weather Overview\n

\n

\n \n {weatherData.location}\n \n · {updatedMinutesAgo}\n \n

\n
\n
\n\n
\n {[\"today\", \"week\", \"radar\"].map((view) => (\n \n {view === \"today\" && \"Today\"}\n {view === \"week\" && \"Week\"}\n {view === \"radar\" && \"Radar\"}\n \n ))}\n undefined}\n className=\"gap-2 rounded-lg text-xs uppercase tracking-[0.15em]\"\n >\n \n Refresh\n \n
\n
\n\n \n \n
\n\n
\n
\n
\n
\n \n
\n
\n

\n Right Now\n

\n

\n {weatherData.current.summary}\n

\n
\n
\n\n
\n
\n \n {weatherData.current.temperature}°\n \n \n Feels like {weatherData.current.feelsLike}°\n \n
\n

\n {\"Chance of rain \" +\n weatherData.current.precipitationChance +\n \"% · Sunrise \" +\n formatTime(weatherData.current.sunrise) +\n \" · Sunset \" +\n formatTime(weatherData.current.sunset)}\n

\n
\n
\n\n \n {weatherMetrics.map((metric) => (\n \n \n \n \n
\n

\n {metric.label}\n

\n

\n {metric.value}\n

\n

\n {metric.description}\n

\n
\n \n ))}\n \n\n
\n
\n
\n \n Sunrise\n
\n \n {formatTime(weatherData.current.sunrise)}\n \n
\n
\n
\n \n Sunset\n
\n \n {formatTime(weatherData.current.sunset)}\n \n
\n
\n
\n \n\n \n
\n\n
\n
\n
\n

\n Hourly Forecast\n

\n

\n Temperature trend and precipitation chance through the\n evening\n

\n
\n \n Live radar calibrated\n \n
\n\n
\n \n \n \n \n \n \n \n \n \n \n [\n value?.toString() + \"°\",\n key === \"feelsLike\" ? \"Feels like\" : \"Temperature\",\n ]}\n />\n \n \n \n \n
\n\n \n {hourlyForecast.map((hour) => {\n const Icon = CONDITION_ICONS[hour.condition];\n return (\n \n

\n {formatHour(hour.time)}\n

\n
\n \n {hour.temperature}°\n \n \n {hour.feelsLike}° feels\n \n
\n
\n
\n \n \n \n {hour.windSpeed} mph winds\n
\n \n {hour.precipitationChance}% rain\n \n
\n \n );\n })}\n \n
\n \n\n \n
\n\n
\n
\n
\n

\n Weekly Outlook\n

\n

\n Plan ahead with precipitation risk and temperature swings\n

\n
\n \n Export\n \n
\n\n \n {weeklyForecast.map((day, index) => {\n const Icon = CONDITION_ICONS[day.condition];\n return (\n \n
\n \n {formatDay(day.day)}\n \n {day.precipitationChance}% rain\n
\n
\n
\n \n \n \n
\n

\n {day.high}°\n

\n

\n Low {day.low}°\n

\n
\n
\n \n {day.condition === \"sunny\" && \"Clear\"}\n {day.condition === \"cloudy\" && \"Clouds\"}\n {day.condition === \"rain\" && \"Showers\"}\n {day.condition === \"storm\" && \"Storm\"}\n \n
\n \n );\n })}\n \n
\n \n\n \n
\n\n
\n
\n
\n

\n Air Quality & Alerts\n

\n

\n Live monitoring for coastal neighborhoods\n

\n
\n \n {airQualityMetrics[0]?.status ?? \"Stable\"}\n \n
\n\n \n {airQualityMetrics.map((metric) => (\n \n
\n

\n {metric.label}\n

\n \n {metric.value}\n \n
\n

\n {metric.status}\n

\n

\n {metric.description}\n

\n \n ))}\n \n\n
\n

\n Local alerts\n

\n \n {alerts.map((alert) => {\n const Icon = alert.icon;\n return (\n \n \n \n \n
\n
\n

\n {alert.title}\n

\n \n {alert.severity}\n \n
\n

\n {alert.description}\n

\n
\n \n );\n })}\n \n
\n
\n \n \n
\n
\n );\n}\n", "type": "registry:component", "target": "components/uitripled/weather-dashboard-shadcnui.tsx" } ] }