mirror of
https://github.com/ferdzo/iotDashboard.git
synced 2026-04-05 09:06:26 +00:00
Added Calendar viewer and Environment overview with AI, Health overviewer
This commit is contained in:
@@ -1,7 +1,118 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import type { WidgetConfig } from '../../hooks'
|
||||
import { weatherApi } from '../../api'
|
||||
|
||||
type IconProps = {
|
||||
className?: string
|
||||
}
|
||||
|
||||
const IconBase = ({ className, children }: IconProps & { children: ReactNode }) => (
|
||||
<svg
|
||||
className={className}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.7}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
{children}
|
||||
</svg>
|
||||
)
|
||||
|
||||
const SunIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<circle cx="12" cy="12" r="4" />
|
||||
<line x1="12" y1="2" x2="12" y2="5" />
|
||||
<line x1="12" y1="19" x2="12" y2="22" />
|
||||
<line x1="4.22" y1="4.22" x2="6.34" y2="6.34" />
|
||||
<line x1="17.66" y1="17.66" x2="19.78" y2="19.78" />
|
||||
<line x1="2" y1="12" x2="5" y2="12" />
|
||||
<line x1="19" y1="12" x2="22" y2="12" />
|
||||
<line x1="4.22" y1="19.78" x2="6.34" y2="17.66" />
|
||||
<line x1="17.66" y1="6.34" x2="19.78" y2="4.22" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const CloudIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M5 15a4 4 0 010-8 5 5 0 019.7-.7A4 4 0 0118 15H5z" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const PartlyCloudyIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<circle cx="8" cy="8" r="3" />
|
||||
<path d="M5 17a4 4 0 010-8 5 5 0 019.7-.7A4 4 0 0118 17H5z" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const FogIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M4 10h11a3 3 0 000-6 4.5 4.5 0 00-8.91 1" />
|
||||
<line x1="3" y1="15" x2="17" y2="15" />
|
||||
<line x1="5" y1="19" x2="19" y2="19" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const RainIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M5 15a4 4 0 010-8 5 5 0 019.7-.7A4 4 0 0118 15H5z" />
|
||||
<line x1="8" y1="17" x2="8" y2="21" />
|
||||
<line x1="12" y1="17" x2="12" y2="22" />
|
||||
<line x1="16" y1="17" x2="16" y2="21" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const SnowIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M5 14a4 4 0 010-8 5 5 0 019.7-.7A4 4 0 0118 14H5z" />
|
||||
<line x1="11" y1="16" x2="11" y2="22" />
|
||||
<line x1="8.5" y1="18" x2="13.5" y2="20" />
|
||||
<line x1="8.5" y1="20" x2="13.5" y2="18" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const ThunderIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M5 15a4 4 0 010-8 5 5 0 019.7-.7A4 4 0 0118 15H5z" />
|
||||
<polyline points="12 16 10 20 14 20 12 24" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const ThermometerIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M14 14.5V5a2 2 0 00-4 0v9.5a3.5 3.5 0 104 0z" />
|
||||
<line x1="12" y1="8" x2="12" y2="11" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const DropletIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M12 3.5s-4 5-4 8.5a4 4 0 108 0c0-3.5-4-8.5-4-8.5z" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const WindIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M3 12h9a3 3 0 10-3-3" />
|
||||
<path d="M5 18h11a3 3 0 11-3 3" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const CloudCoverIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M6 17a4 4 0 010-8 5 5 0 019.7-.7A4 4 0 0119 17H6z" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
const RainDropIcon = ({ className }: IconProps) => (
|
||||
<IconBase className={className}>
|
||||
<path d="M7 14a5 5 0 0010 0c0-4-5-9-5-9s-5 5-5 9z" />
|
||||
</IconBase>
|
||||
)
|
||||
|
||||
interface WeatherWidgetProps {
|
||||
config: WidgetConfig
|
||||
}
|
||||
@@ -45,19 +156,18 @@ export default function WeatherWidget({ config }: WeatherWidgetProps) {
|
||||
|
||||
if (!weather) return null
|
||||
|
||||
// Weather code to icon mapping
|
||||
const getWeatherIcon = (code: number) => {
|
||||
if (code === 0 || code === 1) return '☀️' // Clear/Mainly clear
|
||||
if (code === 2) return '⛅' // Partly cloudy
|
||||
if (code === 3) return '☁️' // Overcast
|
||||
if (code >= 45 && code <= 48) return '🌫️' // Fog
|
||||
if (code >= 51 && code <= 55) return '🌦️' // Drizzle
|
||||
if (code >= 61 && code <= 65) return '🌧️' // Rain
|
||||
if (code >= 71 && code <= 77) return '🌨️' // Snow
|
||||
if (code >= 80 && code <= 82) return '🌧️' // Rain showers
|
||||
if (code >= 85 && code <= 86) return '🌨️' // Snow showers
|
||||
if (code >= 95) return '⛈️' // Thunderstorm
|
||||
return '🌡️'
|
||||
if (code === 0 || code === 1) return <SunIcon className="w-16 h-16 text-warning" />
|
||||
if (code === 2) return <PartlyCloudyIcon className="w-16 h-16 text-primary" />
|
||||
if (code === 3) return <CloudIcon className="w-16 h-16 text-primary" />
|
||||
if (code >= 45 && code <= 48) return <FogIcon className="w-16 h-16 text-primary" />
|
||||
if (code >= 51 && code <= 55) return <RainIcon className="w-16 h-16 text-primary" />
|
||||
if (code >= 61 && code <= 65) return <RainIcon className="w-16 h-16 text-primary" />
|
||||
if (code >= 71 && code <= 77) return <SnowIcon className="w-16 h-16 text-primary" />
|
||||
if (code >= 80 && code <= 82) return <RainIcon className="w-16 h-16 text-primary" />
|
||||
if (code >= 85 && code <= 86) return <SnowIcon className="w-16 h-16 text-primary" />
|
||||
if (code >= 95) return <ThunderIcon className="w-16 h-16 text-primary" />
|
||||
return <ThermometerIcon className="w-16 h-16 text-primary" />
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -66,7 +176,7 @@ export default function WeatherWidget({ config }: WeatherWidgetProps) {
|
||||
<h2 className="card-title text-sm truncate">{config.title}</h2>
|
||||
<div className="flex flex-col items-center justify-center flex-1">
|
||||
{/* Weather Icon */}
|
||||
<div className="text-5xl mb-1">{getWeatherIcon(weather.weather_code)}</div>
|
||||
<div className="mb-1 text-primary">{getWeatherIcon(weather.weather_code)}</div>
|
||||
|
||||
{/* Temperature */}
|
||||
<div className="text-3xl font-bold">{weather.temperature.toFixed(1)}°C</div>
|
||||
@@ -82,20 +192,20 @@ export default function WeatherWidget({ config }: WeatherWidgetProps) {
|
||||
{/* Additional Info */}
|
||||
<div className="grid grid-cols-2 gap-2 mt-2 w-full text-xs">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="opacity-60">💧</span>
|
||||
<DropletIcon className="w-4 h-4 opacity-70" />
|
||||
<span>{weather.humidity}%</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="opacity-60">💨</span>
|
||||
<WindIcon className="w-4 h-4 opacity-70" />
|
||||
<span>{weather.wind_speed.toFixed(1)} km/h</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="opacity-60">☁️</span>
|
||||
<CloudCoverIcon className="w-4 h-4 opacity-70" />
|
||||
<span>{weather.cloud_cover}%</span>
|
||||
</div>
|
||||
{weather.precipitation > 0 && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="opacity-60">🌧️</span>
|
||||
<RainDropIcon className="w-4 h-4 opacity-70" />
|
||||
<span>{weather.precipitation} mm</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user