Weather

import React, { useState, useEffect, useMemo } from ‘react’; import { Search, MapPin, Cloud, Sun, CloudSun, CloudRain, Wind, Droplets, Thermometer, ArrowRight, Copy, Check, Menu, X, ChevronDown, ChevronUp, Eye, Sunrise, Sunset, Umbrella, Navigation, Share2, Code, Layout, Palette, Settings, MoreHorizontal } from ‘lucide-react’; /** * — MOCK DATA GENERATORS & MODELS — */ const CONDITIONS = [ { text: “Sunny”, icon: Sun, color: “text-yellow-400” }, { text: “Partly Cloudy”, icon: CloudSun, color: “text-yellow-200” }, { text: “Cloudy”, icon: Cloud, color: “text-gray-400” }, { text: “Rain Shower”, icon: CloudRain, color: “text-blue-400” }, { text: “Heavy Rain”, icon: CloudRain, color: “text-blue-600” }, ]; const generateWeather = (city) => { const currentCond = CONDITIONS[Math.floor(Math.random() * CONDITIONS.length)]; // Current Data const current = { temp: 72, feels_like: 75, condition_text: currentCond.text, icon: currentCond.icon, iconColor: currentCond.color, high: 78, low: 65, wind_speed: “8 mph”, wind_dir: “NW”, humidity: “45%”, dew_point: “58°”, pressure: “29.92 in”, uv_index: “6 of 10”, visibility: “10 mi”, sunrise: “6:23 am”, sunset: “8:14 pm”, moon_phase: “Waxing Gibbous”, outlook_text: `Expect ${currentCond.text.toLowerCase()} conditions to continue until late afternoon. Wind gusts may increase slightly.` }; // Hourly Data (Next 24h) const hourly = Array.from({ length: 24 }, (_, i) => { const hour = (new Date().getHours() + i) % 24; const timeLabel = hour === 0 ? “12 am” : hour > 12 ? `${hour – 12} pm` : `${hour} am`; const cond = CONDITIONS[Math.floor(Math.random() * CONDITIONS.length)]; return { timestamp: i, time: timeLabel, temp: 72 – Math.floor(Math.random() * 10) + (i > 6 && i < 18 ? 10 : 0), condition_text: cond.text, icon: cond.icon, precip_chance: Math.floor(Math.random() * 30) + "%", wind: `${5 + Math.floor(Math.random() * 10)} mph ${['N','NE','E','SE','S','SW','W','NW'][Math.floor(Math.random()*8)]}`, humidity: `${40 + Math.floor(Math.random() * 40)}%`, feels_like: `${70 + Math.floor(Math.random() * 10)}°`, uv_index: i > 6 && i < 18 ? Math.floor(Math.random() * 8) : 0, cloud_cover: `${Math.floor(Math.random() * 100)}%` }; }); // Daily Data (10 Days) const days = ["Today", "Fri 12", "Sat 13", "Sun 14", "Mon 15", "Tue 16", "Wed 17", "Thu 18", "Fri 19", "Sat 20"]; const daily = days.map((day, i) => { const cond = CONDITIONS[Math.floor(Math.random() * CONDITIONS.length)]; return { date: day, high: 70 + Math.floor(Math.random() * 15), low: 55 + Math.floor(Math.random() * 10), condition_text: cond.text, icon: cond.icon, precip_chance: Math.floor(Math.random() * 60) + “%”, wind: `${5 + Math.floor(Math.random() * 15)} mph`, humidity: `${50 + Math.floor(Math.random() * 30)}%`, sunrise: “6:25 am”, sunset: “8:10 pm” }; }); return { location: { name: city, id: city.toLowerCase() }, current, hourly, daily }; }; const SAMPLE_PROMPTS = [ { id: ‘p1’, title: ‘Morning Walk Planner’, description: ‘Determine the best time for a walk based on conditions.’, category: ‘Daily Planning’, tags: [‘health’, ‘active’], template: “Analyze the forecast for {{city}}. Given the current temp of {{temp}} and {{condition}}, suggest the best 1-hour window for a walk today.”, }, { id: ‘p2’, title: ‘Travel Commute Risk’, description: ‘Assess driving risks for the next 24 hours.’, category: ‘Travel’, tags: [‘safety’, ‘commute’], template: “I am driving in {{city}}. Review the hourly forecast. Are there any visibility ({{visibility}}) or precipitation risks I should know about?”, }, { id: ‘p3’, title: ‘Event Go/No-Go’, description: ‘Decision helper for outdoor events.’, category: ‘Events’, tags: [‘planning’, ‘outdoor’], template: “I have an outdoor event planned in {{city}}. With a high of {{high}} and precip chance of {{precip}}, should I move it indoors?”, }, { id: ‘p4’, title: ‘Allergy & Air Quality’, description: ‘Check air quality impact on health.’, category: ‘Health’, tags: [‘medical’, ‘wellness’], template: “Check the current humidity ({{humidity}}) and wind ({{wind}}) in {{city}}. Advise on allergy risks for today.”, }, ]; /** * — UTILITIES — */ const cn = (…classes) => classes.filter(Boolean).join(‘ ‘); /** * — COMPONENTS — */ // 1. HEADER const Header = ({ activeTab, onTabChange, onSearch, searchQuery, setSearchQuery, onOpenWidget }) => (
{/* Top Bar */}
{/* Logo */}
LuxHarbor Weather
{/* Search */}
{ e.preventDefault(); onSearch(searchQuery); }} className=”relative w-full md:w-96 group”> setSearchQuery(e.target.value)} className=”w-full bg-slate-800 border border-slate-700 text-slate-100 rounded-full py-2 pl-10 pr-4 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all” /> {/* Actions removed for visitor view */}
{/* Navigation Tabs */}
); // 2. TODAY VIEW const TodayView = ({ data, onNavigate }) => { const { current, location } = data; const Icon = current.icon; return (
{/* Location Header */}

{location.name}, US

As of {new Date().toLocaleTimeString([], {hour: ‘2-digit’, minute:’2-digit’})} EST
{/* Main Current Conditions Card */}
{/* Left: Big Temp & Condition */}
{current.temp}°
{current.condition_text} Day {current.high}° • Night {current.low}°
Feels Like {current.feels_like}
{/* Right: Grid of Metrics */}
{/* Outlook Strip */}

Outlook

{current.outlook_text}

{/* Content Blocks */}
Roads are dry with good visibility. No major weather-related delays expected on I-95 corridor this evening. Air quality is Moderate. Pollen counts are low, but sensitive groups should limit prolonged outdoor exertion.
); }; // 3. HOURLY VIEW const HourlyView = ({ data }) => { const [expandedRow, setExpandedRow] = useState(null); return (

Hourly Forecast

Next 24 Hours
{data.hourly.map((hour, idx) => { const isExpanded = expandedRow === idx; const Icon = hour.icon; return (
{/* Summary Row */}
setExpandedRow(isExpanded ? null : idx)} className=”flex items-center justify-between p-4 cursor-pointer hover:bg-slate-700/30 transition-colors” >
{hour.time}
{hour.temp}°
{hour.condition_text}
{hour.precip_chance}
{hour.wind}
{isExpanded ? : }
{/* Detailed Expansion */} {isExpanded && (
)}
); })}
); }; // 4. 10-DAY VIEW const TenDayView = ({ data }) => { const [expandedDay, setExpandedDay] = useState(null); return (

10-Day Forecast

{data.daily.map((day, idx) => { const isExpanded = expandedDay === idx; const Icon = day.icon; return (
setExpandedDay(isExpanded ? null : idx)} className=”flex items-center justify-between p-4 cursor-pointer hover:bg-slate-700/30 transition-colors” >
{day.date}
{day.high}° {day.low}°
{day.condition_text}
{day.precip_chance}
{isExpanded ? : }
{isExpanded && (
LuxHarbor Tip: A great day for outdoor activities in the morning before the heat sets in.
)}
); })}
); }; // 5. PROMPT LIBRARY const PromptLibrary = ({ prompts, onUse }) => { const [filter, setFilter] = useState(‘All’); const filtered = filter === ‘All’ ? prompts : prompts.filter(p => p.category === filter); return (

Weather Prompt Library

AI-ready templates that automatically adapt to the current forecast. Select a prompt to inject live data.

{[‘All’, ‘Daily Planning’, ‘Travel’, ‘Events’, ‘Health’].map(cat => ( ))}
{filtered.map(prompt => (
{prompt.category}

{prompt.title}

{prompt.description}

))}
); }; // 6. WIDGET BUILDER const WidgetBuilder = ({ weather }) => { const [config, setConfig] = useState({ theme: ‘dark’, // dark, light, transparent layout: ‘sidebar’, // sidebar, compact units: ‘F’ }); const embedCode = ``; return (
{/* Controls */}

Widget Builder

Customize and embed a free weather widget for your site.

{[‘dark’, ‘light’, ‘transparent’].map(t => ( ))}
{[‘sidebar’, ‘compact’].map(l => ( ))}
            {embedCode}
          
{/* Live Preview */}
{/* Mock Widget Iframe */}
Baltimore, US
72°
Partly Cloudy
{config.layout === ‘sidebar’ && (
Tomorrow 76°/62°
Saturday 70°/55°
Sunday 68°/54°
)}
Powered by LuxHarbor
); }; // HELPER COMPONENTS const MetricRow = ({ icon: Icon, label, value }) => (
{label} {value}
); const DetailBox = ({ label, value }) => (
{label} {value}
); const ContentCard = ({ title, children, type }) => (

{type === ‘travel’ ? : } {title}

{children}

); const FooterNote = () => (
Demo data only; connect to your preferred weather API for production use.
© 2025 LuxHarbor Weather.
); const InfoIcon = ({ className, size }) => ; const Info = ({ className, size }) => ( ); const PromptModal = ({ isOpen, onClose, prompt, weather }) => { if (!isOpen) return null; const interpolated = prompt.template .replace(‘{{city}}’, weather.location.name) .replace(‘{{temp}}’, weather.current.temp + ‘°’) .replace(‘{{condition}}’, weather.current.condition_text) .replace(‘{{humidity}}’, weather.current.humidity) .replace(‘{{wind}}’, weather.current.wind_speed) .replace(‘{{high}}’, weather.current.high + ‘°’) .replace(‘{{precip}}’, weather.daily[0].precip_chance) .replace(‘{{visibility}}’, weather.current.visibility); return (

Use Prompt

Current weather data for {weather.location.name} has been injected.