Style date time weather to fit in better

This commit is contained in:
2025-01-04 00:37:29 -05:00
parent a2eb5bfcd7
commit 194ac96732

View File

@@ -122,35 +122,37 @@ const DateTimeWeatherDisplay = ({ scaleFactor = 1 }) => {
if (!weatherCode) return <CircleAlert className="w-12 h-12 text-red-500" />; if (!weatherCode) return <CircleAlert className="w-12 h-12 text-red-500" />;
const code = parseInt(weatherCode, 10); const code = parseInt(weatherCode, 10);
const iconProps = small ? "w-8 h-8" : "w-12 h-12"; const iconProps = small ? "w-8 h-8" : "w-12 h-12";
const isNight = currentTime.getHours() >= 18 || currentTime.getHours() < 6;
switch (true) { switch (true) {
case code >= 200 && code < 300: case code >= 200 && code < 300:
return <CloudLightning className={cn(iconProps, "text-gray-700")} />; return <CloudLightning className={cn(iconProps, "text-yellow-300")} />;
case code >= 300 && code < 500: case code >= 300 && code < 500:
return <CloudDrizzle className={cn(iconProps, "text-blue-600")} />; return <CloudDrizzle className={cn(iconProps, "text-blue-300")} />;
case code >= 500 && code < 600: case code >= 500 && code < 600:
return <CloudRain className={cn(iconProps, "text-blue-600")} />; return <CloudRain className={cn(iconProps, "text-blue-300")} />;
case code >= 600 && code < 700: case code >= 600 && code < 700:
return <CloudSnow className={cn(iconProps, "text-blue-400")} />; return <CloudSnow className={cn(iconProps, "text-blue-200")} />;
case code >= 700 && code < 721: case code >= 700 && code < 721:
return <CloudFog className={cn(iconProps, "text-gray-600")} />; return <CloudFog className={cn(iconProps, "text-gray-300")} />;
case code === 721: case code === 721:
return <Haze className={cn(iconProps, "text-gray-700")} />; return <Haze className={cn(iconProps, "text-gray-300")} />;
case code >= 722 && code < 781: case code >= 722 && code < 781:
return <CloudFog className={cn(iconProps, "text-gray-600")} />; return <CloudFog className={cn(iconProps, "text-gray-300")} />;
case code === 781: case code === 781:
return <Tornado className={cn(iconProps, "text-gray-700")} />; return <Tornado className={cn(iconProps, "text-gray-300")} />;
case code === 800: case code === 800:
return currentTime.getHours() >= 6 && currentTime.getHours() < 18 ? ( return currentTime.getHours() >= 6 && currentTime.getHours() < 18 ? (
<Sun className={cn(iconProps, "text-yellow-700")} /> <Sun className={cn(iconProps, "text-yellow-300")} />
) : ( ) : (
<Moon className={cn(iconProps, "text-gray-500")} /> <Moon className={cn(iconProps, "text-gray-300")} />
); );
case code >= 800 && code < 803: case code >= 800 && code < 803:
return <CloudSun className={cn(iconProps, "text-gray-600")} />; return <CloudSun className={cn(iconProps, isNight ? "text-gray-300" : "text-gray-200")} />;
case code >= 803: case code >= 803:
return <Cloud className={cn(iconProps, "text-gray-200")} />; return <Cloud className={cn(iconProps, "text-gray-300")} />;
default: default:
return <CircleAlert className={cn(iconProps, "text-red-700")} />; return <CircleAlert className={cn(iconProps, "text-red-500")} />;
} }
}; };
@@ -159,66 +161,68 @@ const DateTimeWeatherDisplay = ({ scaleFactor = 1 }) => {
// Thunderstorm (200-299) // Thunderstorm (200-299)
if (code >= 200 && code < 300) { if (code >= 200 && code < 300) {
return "bg-gradient-to-br from-slate-900 via-purple-900 to-slate-800"; return "bg-gradient-to-br from-slate-900 to-purple-800";
} }
// Drizzle (300-399) // Drizzle (300-399)
if (code >= 300 && code < 400) { if (code >= 300 && code < 400) {
return "bg-gradient-to-br from-slate-700 via-blue-800 to-slate-700"; return "bg-gradient-to-br from-slate-800 to-blue-800";
} }
// Rain (500-599) // Rain (500-599)
if (code >= 500 && code < 600) { if (code >= 500 && code < 600) {
return "bg-gradient-to-br from-slate-800 via-blue-900 to-slate-700"; return "bg-gradient-to-br from-slate-800 to-blue-800";
} }
// Snow (600-699) // Snow (600-699)
if (code >= 600 && code < 700) { if (code >= 600 && code < 700) {
return "bg-gradient-to-br from-slate-200 via-blue-100 to-slate-100"; return "bg-gradient-to-br from-slate-700 to-blue-800";
} }
// Atmosphere (700-799: mist, smoke, haze, fog, etc.) // Atmosphere (700-799: mist, smoke, haze, fog, etc.)
if (code >= 700 && code < 800) { if (code >= 700 && code < 800) {
return "bg-gradient-to-br from-slate-600 via-slate-500 to-slate-400"; return "bg-gradient-to-br from-slate-700 to-slate-500";
} }
// Clear (800) // Clear (800)
if (code === 800) { if (code === 800) {
if (isNight) { if (isNight) {
return "bg-gradient-to-br from-slate-900 via-blue-950 to-slate-800"; return "bg-gradient-to-br from-slate-900 to-blue-900";
} }
return "bg-gradient-to-br from-sky-400 via-blue-400 to-sky-500"; return "bg-gradient-to-br from-blue-600 to-sky-400";
} }
// Clouds (801-804) // Clouds (801-804)
if (code > 800) { if (code > 800) {
if (isNight) { if (isNight) {
return "bg-gradient-to-br from-slate-800 via-slate-700 to-slate-600"; return "bg-gradient-to-br from-slate-800 to-slate-600";
} }
return "bg-gradient-to-br from-slate-400 via-slate-500 to-slate-400"; return "bg-gradient-to-br from-slate-600 to-slate-400";
} }
// Default fallback // Default fallback
return "bg-gradient-to-br from-slate-700 via-slate-600 to-slate-500"; return "bg-gradient-to-br from-slate-700 to-slate-500";
}; };
const getTemperatureColor = (weatherCode, isNight) => { const getTemperatureColor = (weatherCode, isNight) => {
const code = parseInt(weatherCode, 10); const code = parseInt(weatherCode, 10);
// Use dark text for light backgrounds // Snow - dark background, light text
if (code >= 600 && code < 700) { // Snow if (code >= 600 && code < 700) {
return "text-slate-900"; return "text-white";
} }
if (code === 800 && !isNight) { // Clear day // Clear day - light background, dark text
return "text-slate-900"; if (code === 800 && !isNight) {
return "text-white";
} }
if (code > 800 && !isNight) { // Cloudy day // Cloudy day - medium background, ensure contrast
return "text-slate-900"; if (code > 800 && !isNight) {
return "text-white";
} }
// Default to white text for all other (darker) backgrounds // All other cases (darker backgrounds)
return "text-white"; return "text-white";
}; };
@@ -236,213 +240,217 @@ const DateTimeWeatherDisplay = ({ scaleFactor = 1 }) => {
}; };
const WeatherDetails = () => ( const WeatherDetails = () => (
<div className="space-y-4 p-3"> <div className="space-y-4 p-3 bg-gradient-to-br from-slate-800 to-slate-700">
<div className="grid grid-cols-3 gap-2"> <div className="grid grid-cols-3 gap-2">
<Card className="p-2"> <Card className="bg-gradient-to-br from-slate-700 to-slate-600 backdrop-blur-sm p-2">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<ThermometerSun className="w-5 h-5 text-orange-500" /> <ThermometerSun className="w-5 h-5 text-yellow-300" />
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-xs text-muted-foreground">High</span> <span className="text-xs text-slate-300">High</span>
<span className="text-sm font-bold">{Math.round(weather.main.temp_max)}°F</span> <span className="text-sm font-bold text-white">{Math.round(weather.main.temp_max)}°F</span>
</div>
</div> </div>
</div> </Card>
</Card>
<Card className="p-2"> <Card className="bg-gradient-to-br from-slate-700 to-slate-600 backdrop-blur-sm p-2">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<ThermometerSnowflake className="w-5 h-5 text-blue-500" /> <ThermometerSnowflake className="w-5 h-5 text-blue-300" />
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-xs text-muted-foreground">Low</span> <span className="text-xs text-slate-300">Low</span>
<span className="text-sm font-bold">{Math.round(weather.main.temp_min)}°F</span> <span className="text-sm font-bold text-white">{Math.round(weather.main.temp_min)}°F</span>
</div>
</div> </div>
</div> </Card>
</Card>
<Card className="p-2"> <Card className="bg-gradient-to-br from-slate-700 to-slate-600 backdrop-blur-sm p-2">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Droplets className="w-5 h-5 text-blue-400" /> <Droplets className="w-5 h-5 text-blue-300" />
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-xs text-muted-foreground">Humidity</span> <span className="text-xs text-slate-300">Humidity</span>
<span className="text-sm font-bold">{weather.main.humidity}%</span> <span className="text-sm font-bold text-white">{weather.main.humidity}%</span>
</div>
</div> </div>
</div> </Card>
</Card>
<Card className="p-2"> <Card className="bg-gradient-to-br from-slate-700 to-slate-600 backdrop-blur-sm p-2">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Wind className="w-5 h-5 text-gray-500" /> <Wind className="w-5 h-5 text-slate-300" />
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-xs text-muted-foreground">Wind</span> <span className="text-xs text-slate-300">Wind</span>
<span className="text-sm font-bold">{Math.round(weather.wind.speed)} mph</span> <span className="text-sm font-bold text-white">{Math.round(weather.wind.speed)} mph</span>
</div>
</div> </div>
</div> </Card>
</Card>
<Card className="p-2"> <Card className="bg-gradient-to-br from-slate-700 to-slate-600 backdrop-blur-sm p-2">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Sunrise className="w-5 h-5 text-yellow-500" /> <Sunrise className="w-5 h-5 text-yellow-300" />
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-xs text-muted-foreground">Sunrise</span> <span className="text-xs text-slate-300">Sunrise</span>
<span className="text-sm font-bold">{formatTime(weather.sys?.sunrise)}</span> <span className="text-sm font-bold text-white">{formatTime(weather.sys?.sunrise)}</span>
</div>
</div> </div>
</div> </Card>
</Card>
<Card className="p-2"> <Card className="bg-gradient-to-br from-slate-700 to-slate-600 backdrop-blur-sm p-2">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Sunset className="w-5 h-5 text-orange-400" /> <Sunset className="w-5 h-5 text-orange-300" />
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-xs text-muted-foreground">Sunset</span> <span className="text-xs text-slate-300">Sunset</span>
<span className="text-sm font-bold">{formatTime(weather.sys?.sunset)}</span> <span className="text-sm font-bold text-white">{formatTime(weather.sys?.sunset)}</span>
</div>
</div> </div>
</div> </Card>
</Card>
</div>
{forecast && (
<div>
<div className="grid grid-cols-5 gap-2">
{forecast.map((day, index) => (
<Card key={index} className="p-2">
<div className="flex flex-col items-center gap-1">
<span className="text-sm font-medium">
{new Date(day.dt * 1000).toLocaleDateString('en-US', { weekday: 'short' })}
</span>
{getWeatherIcon(day.weather[0].id, new Date(day.dt * 1000), true)}
<div className="flex justify-center gap-1 items-baseline w-full">
<span className="text-sm font-medium">
{Math.round(day.main.temp_max)}°
</span>
<span className="text-xs text-muted-foreground">
{Math.round(day.main.temp_min)}°
</span>
</div>
<div className="flex flex-col items-center gap-1 w-full pt-1">
{day.rain?.['3h'] > 0 && (
<div className="flex items-center gap-1">
<CloudRain className="w-3 h-3 text-blue-400" />
<span className="text-xs">{day.rain['3h'].toFixed(2)}"</span>
</div>
)}
{day.snow?.['3h'] > 0 && (
<div className="flex items-center gap-1">
<CloudSnow className="w-3 h-3 text-blue-400" />
<span className="text-xs">{day.snow['3h'].toFixed(2)}"</span>
</div>
)}
{!day.rain?.['3h'] && !day.snow?.['3h'] && (
<div className="flex items-center gap-1">
<Umbrella className="w-3 h-3 text-gray-400" />
<span className="text-xs">0"</span>
</div>
)}
</div>
</div>
</Card>
))}
</div>
</div> </div>
)}
</div>
);
return ( {forecast && (
<div className="flex flex-col items-center w-full transition-opacity duration-300 ${mounted ? 'opacity-100' : 'opacity-0'}"> <div>
{/* Time Display */} <div className="grid grid-cols-5 gap-2">
<Card className="bg-gradient-to-br mb-[7px] from-slate-900 via-sky-800 to-cyan-800 dark:bg-slate-800 px-1 py-2 w-full hover:scale-[1.02] transition-transform duration-300"> {forecast.map((day, index) => {
<CardContent className="p-3 h-[106px] flex items-center"> const forecastTime = new Date(day.dt * 1000);
<div className="flex justify-center items-baseline w-full"> const isNight = forecastTime.getHours() >= 18 || forecastTime.getHours() < 6;
<div className={`transition-opacity duration-200 ${isTimeChanging ? 'opacity-60' : 'opacity-100'}`}> return (
<span className="text-7xl font-bold text-white">{hours}</span> <Card
<span className="text-7xl font-bold text-white">:</span> key={index}
<span className="text-7xl font-bold text-white">{minutes}</span> className={cn(
<span className="text-xl font-medium text-white/90 ml-1">{ampm}</span> getWeatherBackground(day.weather[0].id, isNight),
"p-2"
)}
>
<div className="flex flex-col items-center gap-1">
<span className="text-sm font-medium text-white">
{forecastTime.toLocaleDateString('en-US', { weekday: 'short' })}
</span>
{getWeatherIcon(day.weather[0].id, forecastTime, true)}
<div className="flex justify-center gap-1 items-baseline w-full">
<span className="text-sm font-medium text-white">
{Math.round(day.main.temp_max)}°
</span>
<span className="text-xs text-slate-300">
{Math.round(day.main.temp_min)}°
</span>
</div>
<div className="flex flex-col items-center gap-1 w-full pt-1">
{day.rain?.['3h'] > 0 && (
<div className="flex items-center gap-1">
<CloudRain className="w-3 h-3 text-blue-300" />
<span className="text-xs text-white">{day.rain['3h'].toFixed(2)}"</span>
</div>
)}
{day.snow?.['3h'] > 0 && (
<div className="flex items-center gap-1">
<CloudSnow className="w-3 h-3 text-blue-300" />
<span className="text-xs text-white">{day.snow['3h'].toFixed(2)}"</span>
</div>
)}
{!day.rain?.['3h'] && !day.snow?.['3h'] && (
<div className="flex items-center gap-1">
<Umbrella className="w-3 h-3 text-slate-300" />
<span className="text-xs text-white">0"</span>
</div>
)}
</div>
</div>
</Card>
);
})}
</div> </div>
</div> </div>
</CardContent> )}
</Card> </div>
);
{/* Date and Weather Display */} return (
<div className="h-[125px] mb-[6px] grid grid-cols-2 gap-2 w-full"> <div className="flex flex-col items-center w-full transition-opacity duration-300 ${mounted ? 'opacity-100' : 'opacity-0'}">
<Card className="h-full bg-gradient-to-br from-slate-900 via-violet-800 to-purple-800 flex items-center justify-center"> {/* Time Display */}
<CardContent className="h-full p-0"> <Card className="bg-gradient-to-br mb-[7px] from-indigo-900 to-blue-800 backdrop-blur-sm dark:bg-slate-800 px-1 py-2 w-full hover:scale-[1.02] transition-transform duration-300">
<div className="flex flex-col items-center justify-center h-full"> <CardContent className="p-3 h-[106px] flex items-center">
<span className="text-7xl font-bold text-white"> <div className="flex justify-center items-baseline w-full">
{dateInfo.day} <div className={`transition-opacity duration-200 ${isTimeChanging ? 'opacity-60' : 'opacity-100'}`}>
</span> <span className="text-6xl font-bold text-white">{hours}</span>
<span className="text-sm font-bold text-white mt-2"> <span className="text-6xl font-bold text-white">:</span>
{dateInfo.weekday} <span className="text-6xl font-bold text-white">{minutes}</span>
</span> <span className="text-lg font-medium text-white/90 ml-1">{ampm}</span>
</div>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
{weather?.main && ( {/* Date and Weather Display */}
<Popover> <div className="h-[125px] mb-[6px] grid grid-cols-2 gap-2 w-full">
<PopoverTrigger asChild> <Card className="h-full bg-gradient-to-br from-violet-900 to-purple-800 backdrop-blur-sm flex items-center justify-center">
<Card className={cn( <CardContent className="h-full p-0">
getWeatherBackground( <div className="flex flex-col items-center justify-center h-full">
weather.weather[0]?.id, <span className="text-6xl font-bold text-white">
datetime.getHours() >= 18 || datetime.getHours() < 6 {dateInfo.day}
), </span>
"flex items-center justify-center cursor-pointer hover:brightness-110 transition-all relative" <span className="text-sm font-bold text-white mt-2">
)}> {dateInfo.weekday}
<CardContent className="h-full p-3"> </span>
<div className="flex flex-col items-center"> </div>
{getWeatherIcon(weather.weather[0]?.id, datetime)} </CardContent>
<span className={cn( </Card>
"text-3xl font-bold ml-1 mt-2",
getTemperatureColor(
weather.weather[0]?.id,
datetime.getHours() >= 18 || datetime.getHours() < 6
)
)}>
{Math.round(weather.main.temp)}°
</span>
</div>
</CardContent>
{weather.alerts && (
<div className="absolute top-1 right-1">
<AlertTriangle className="w-5 h-5 text-red-500" />
</div>
)}
</Card>
</PopoverTrigger>
<PopoverContent
className="w-[450px]"
align="start"
side="right"
sideOffset={10}
style={{
transform: `scale(${scaleFactor})`,
transformOrigin: 'left top'
}}
>
{weather.alerts && (
<Alert variant="warning" className="mb-3">
<AlertTriangle className="h-3 w-3" />
<AlertDescription className="text-xs">
{weather.alerts[0].event}
</AlertDescription>
</Alert>
)}
<WeatherDetails />
</PopoverContent>
</Popover>
)}
</div>
{/* Calendar Display */} {weather?.main && (
<Card className="w-full"> <Popover>
<CardContent className="p-0"> <PopoverTrigger asChild>
<CalendarComponent <Card className={cn(
selected={datetime} getWeatherBackground(
className="w-full" weather.weather[0]?.id,
/> datetime.getHours() >= 18 || datetime.getHours() < 6
</CardContent> ),
</Card> "flex items-center justify-center cursor-pointer hover:brightness-110 transition-all relative backdrop-blur-sm"
</div> )}>
); <CardContent className="h-full p-3">
<div className="flex flex-col items-center">
{getWeatherIcon(weather.weather[0]?.id, datetime)}
<span className="text-3xl font-bold ml-1 mt-2 text-white">
{Math.round(weather.main.temp)}°
</span>
</div>
</CardContent>
{weather.alerts && (
<div className="absolute top-1 right-1">
<AlertTriangle className="w-5 h-5 text-red-500" />
</div>
)}
</Card>
</PopoverTrigger>
<PopoverContent
className="w-[450px] bg-gradient-to-br from-slate-800 to-slate-700 border-slate-600"
align="start"
side="right"
sideOffset={10}
style={{
transform: `scale(${scaleFactor})`,
transformOrigin: 'left top'
}}
>
{weather.alerts && (
<Alert variant="warning" className="mb-3 bg-amber-900/50 border-amber-700">
<AlertTriangle className="h-3 w-3 text-amber-500" />
<AlertDescription className="text-xs text-amber-200">
{weather.alerts[0].event}
</AlertDescription>
</Alert>
)}
<WeatherDetails />
</PopoverContent>
</Popover>
)}
</div>
{/* Calendar Display */}
<Card className="w-full bg-white dark:bg-slate-800">
<CardContent className="p-0">
<CalendarComponent
selected={datetime}
className="w-full"
/>
</CardContent>
</Card>
</div>
);
}; };
export default DateTimeWeatherDisplay; export default DateTimeWeatherDisplay;