Initial commit: Digital Home dashboard

This commit is contained in:
Cosmo
2026-04-15 20:31:28 +00:00
commit c5c4603903
33 changed files with 1384 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
"use client";
import { useEffect, useState } from "react";
import { Cloud, Thermometer, Wind, Droplets, RefreshCw } from "lucide-react";
interface WeatherData {
current_condition: Array<{
temp_C: string;
FeelsLikeC: string;
humidity: string;
windspeedKmph: string;
weatherDesc: Array<{ value: string }>;
}>;
}
export function WeatherWidget() {
const [data, setData] = useState<WeatherData | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const fetchWeather = async () => {
setLoading(true);
setError(false);
try {
const res = await fetch("/api/weather");
if (!res.ok) throw new Error();
const json = await res.json();
setData(json);
} catch {
setError(true);
} finally {
setLoading(false);
}
};
useEffect(() => { fetchWeather(); }, []);
const current = data?.current_condition?.[0];
return (
<div className="glass-card p-5">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<Cloud className="w-4 h-4 text-blue-400" />
<span className="text-sm font-medium text-slate-300">Погода</span>
</div>
<button onClick={fetchWeather} className="text-slate-500 hover:text-slate-300 transition-colors">
<RefreshCw className="w-3.5 h-3.5" />
</button>
</div>
{loading ? (
<div className="space-y-2 animate-pulse">
<div className="h-8 bg-slate-700/50 rounded w-24" />
<div className="h-4 bg-slate-700/50 rounded w-32" />
<div className="h-4 bg-slate-700/50 rounded w-40" />
</div>
) : error ? (
<div className="text-slate-500 text-sm">Не удалось получить данные</div>
) : current ? (
<div className="space-y-3">
<div className="flex items-baseline gap-2">
<span className="text-4xl font-bold text-white">{current.temp_C}°</span>
<span className="text-slate-400 text-sm">Санкт-Петербург</span>
</div>
<div className="text-slate-300 text-sm">{current.weatherDesc?.[0]?.value}</div>
<div className="grid grid-cols-3 gap-2 pt-1">
<div className="flex items-center gap-1 text-xs text-slate-400">
<Thermometer className="w-3 h-3 text-orange-400" />
<span>Ощущ. {current.FeelsLikeC}°</span>
</div>
<div className="flex items-center gap-1 text-xs text-slate-400">
<Droplets className="w-3 h-3 text-blue-400" />
<span>{current.humidity}%</span>
</div>
<div className="flex items-center gap-1 text-xs text-slate-400">
<Wind className="w-3 h-3 text-teal-400" />
<span>{current.windspeedKmph} км/ч</span>
</div>
</div>
</div>
) : null}
</div>
);
}