Added Calendar viewer and Environment overview with AI, Health overviewer

This commit is contained in:
2025-11-29 00:05:41 +01:00
parent 8c699bd121
commit ab72c01999
33 changed files with 4436 additions and 383 deletions

View File

@@ -1,8 +1,61 @@
import type { ReactNode } from 'react'
import { useQuery } from '@tanstack/react-query'
import { devicesApi } from '../../api'
import type { WidgetConfig } from '../../hooks'
import './widget-styles.css'
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 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 AirQualityIcon = ({ className }: IconProps) => (
<IconBase className={className}>
<path d="M4 12h9a3 3 0 10-3-3" />
<path d="M6 17h8a3 3 0 11-3 3" />
</IconBase>
)
const AcousticIcon = ({ className }: IconProps) => (
<IconBase className={className}>
<path d="M5 9v6h3l4 4V5l-4 4H5z" />
<path d="M16 9a4 4 0 010 6" />
<path d="M18 7a6 6 0 010 10" />
</IconBase>
)
const LightIcon = ({ className }: IconProps) => (
<IconBase className={className}>
<path d="M12 3a5 5 0 00-3 9v3h6v-3a5 5 0 00-3-9z" />
<path d="M10 18h4" />
<path d="M10 21h4" />
</IconBase>
)
interface ComfortIndexWidgetProps {
config: WidgetConfig
}
@@ -85,7 +138,7 @@ export default function ComfortIndexWidget({ config }: ComfortIndexWidgetProps)
<div className="grid grid-cols-2 gap-2 text-xs">
<div className="flex items-center justify-between p-2 bg-base-200 rounded">
<div className="flex items-center gap-1.5">
<span className="text-sm">🌡</span>
<ThermometerIcon className="w-4 h-4" />
<span className="truncate">Temperature</span>
</div>
<span className={`font-bold ${getScoreColor(data.components.temperature)}`}>
@@ -95,7 +148,7 @@ export default function ComfortIndexWidget({ config }: ComfortIndexWidgetProps)
<div className="flex items-center justify-between p-2 bg-base-200 rounded">
<div className="flex items-center gap-1.5">
<span className="text-sm">💧</span>
<DropletIcon className="w-4 h-4" />
<span className="truncate">Humidity</span>
</div>
<span className={`font-bold ${getScoreColor(data.components.humidity)}`}>
@@ -105,7 +158,7 @@ export default function ComfortIndexWidget({ config }: ComfortIndexWidgetProps)
<div className="flex items-center justify-between p-2 bg-base-200 rounded">
<div className="flex items-center gap-1.5">
<span className="text-sm">🌬</span>
<AirQualityIcon className="w-4 h-4" />
<span className="truncate">Air Quality</span>
</div>
<span className={`font-bold ${getScoreColor(data.components.air_quality)}`}>
@@ -115,7 +168,7 @@ export default function ComfortIndexWidget({ config }: ComfortIndexWidgetProps)
<div className="flex items-center justify-between p-2 bg-base-200 rounded">
<div className="flex items-center gap-1.5">
<span className="text-sm">🔊</span>
<AcousticIcon className="w-4 h-4" />
<span className="truncate">Acoustic</span>
</div>
<span className={`font-bold ${getScoreColor(data.components.acoustic)}`}>
@@ -125,7 +178,7 @@ export default function ComfortIndexWidget({ config }: ComfortIndexWidgetProps)
<div className="flex items-center justify-between p-2 bg-base-200 rounded col-span-2">
<div className="flex items-center gap-1.5">
<span className="text-sm">💡</span>
<LightIcon className="w-4 h-4" />
<span className="truncate">Lighting</span>
</div>
<span className={`font-bold ${getScoreColor(data.components.light)}`}>
@@ -137,7 +190,10 @@ export default function ComfortIndexWidget({ config }: ComfortIndexWidgetProps)
{/* Suggestions */}
{data.suggestions.length > 0 && (
<div className="mt-auto">
<div className="text-xs font-semibold mb-1">💡 Suggestions</div>
<div className="flex items-center gap-1 text-xs font-semibold mb-1">
<LightIcon className="w-3.5 h-3.5" />
<span>Suggestions</span>
</div>
<div className="space-y-1 max-h-20 overflow-y-auto">
{data.suggestions.map((suggestion, i) => (
<div key={i} className="text-xs bg-warning/10 p-1 rounded border-l-2 border-warning">