This commit is contained in:
qiuchenfan 2025-11-14 18:44:51 +08:00
commit dea7e9349b
3 changed files with 165 additions and 0 deletions

View File

@ -0,0 +1,33 @@
import { WeathersearchForm } from "./WeatherSearchForm.tsx";
import { WeatherDisplay } from "./WeatherDisplay.tsx";
import { WeatherDetailsGrid } from "./WeatherDetailsGrid.tsx";
import { useWeatherStore } from "./WeatherStore.tsx";
import Cloud from "../../../assets/cloud.svg";
export function WeatherCard() {
const { currentWeather } = useWeatherStore();
return (
<div>
<WeathersearchForm />
{currentWeather ? (
<div className="P-4">
<WeatherDisplay />
<WeatherDetailsGrid />
</div>
) : (
<div className="flex flex-col items-center justify-center h-full">
<div className="animate-spin">
<div className="h-10 w-10 border-t-2 border-b-2 border-gray-900 rounded-full"></div>
<div className="h-10 w-10">
<Cloud/>
</div>
</div>
<h3 className="text-2xl font-bold text-slate-700 dark:text-slate-200 mb-2"></h3>
<p className="text-sm text-slate-500 dark:text-slate-400"></p>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,77 @@
import { Droplets,Wind,Gauge,Cloud,Eye,ThermometerSun} from "lucide-react";
import React from "react";
import { getWindDirection } from "@/lib/utils";
import {useWeatherStore} from "@/store/weatherStore";
interface WeatherInfoItemProps {
icon: React.ReactNode;
label: string;
value: string;
subtitle?: string;
}
function WeatherInfoItem({ icon, label, value, subtitle }: WeatherInfoItemProps) {
return (
<div className="group rounded-xl bg-slate-50/50 border border-slate-200/50 p-3 hover:bg-slate-100/50 hover:border-slate-300 transition duration-200 ">
<div className="flex items-start gap-2">
<div className="flex-shrink-0 w-9 h-9 rounded-full bg-white flex items-center justify-center group-hover:scale-100 transition-transform duration-200">{icon}</div>
<div className="flex-1 min-w-0">
<p className="text-xs text-slate-500">{label}</p>
<p className="text-sm font-semibold text-slate-900">{value}</p>
{subtitle && <p className="text-xs text-slate-500">{subtitle}</p>}
</div>
</div>
</div>
);
}
export function WeatherDetailsGrid() {
<>
<div className="grid grids-cols-2 md:grids-cols-3 gap-3 mb-4">
<WeatherInfoItem
icon={<Droplets className="w-4 h-4 text-blue-500"/>}
label="湿度"
value={'${currentWeather.current.humidity}%'}/>
<WeatherInfoItem
icon={<Wind className="w-4 h-4 text-green-500"/>}
label="风速"
value={'${currentWeather.current.wind_speed}%'}
subtitle={getWindDirection(currentWeather.current.wind_dir)}/>
<WeatherInfoItem
icon={<Gauge className="w-4 h-4 text-purple-500"/>}
label="气压"
value={'${currentWeather.current.humidity}%'}/>
<WeatherInfoItem
icon={<Cloud className="w-4 h-4 text-gray-500"/>}
label="云量"
value={'${currentWeather.current.cloudcover}%'}/>
<WeatherInfoItem
icon={<ThermometerSun className="w-4 h-4 text-orange-500"/>}
label="紫外线"
value={'${currentWeather.current.uv_index}%'}/>
</div>
<div className="pt-4 border-t border-slate-200">
<div className="flex items-center justify-center text-sm mb-2">
<div className="flex items-center gap-2 text-slate-600">
<Droplets className="w-4 h-4 text-blue-500"/>
<span><span className="font-semibold">{currentWeather.current.precip}mm</span></span>
</div>
<span className="text-xs text-center text-slate-500">{currentWeather.current.is_day==="yes"?'白天':'夜晚'}</span>
</div>
<p>{currentWeather.current.observation_time}</p>
</div>
</>
}

View File

@ -0,0 +1,55 @@
import REACT, { use, useEffect } from 'react'
import { Loader2 } from 'lucide-react';
import { WeatherCard } from './WeatherCard'
import { useWeatherstore } from './WeatherStore'
import { toast } from 'sonner'
export function meta() {
return [
{ title: "天气查询页面" },
{ name: "description", content: "查询天气信息" }
]
}
export default function Weather() {
const { currentWeather, isLoading, error, seterror } = useWeatherstore()
useEffect(() => {
if (error) {
toast.error(error)
seterror("")
}
}, [error, seterror])
return (
<div className="flex flex-col items-center justify-center h-screen">
<div className="flex flex-col items-center justify-center">
<header className="flex flex-col items-center justify-center">
<h1 className="text-4xl font-bold"></h1>
<p className="text-sm"></p>
</header>
{isLoading && !currentWeather && (
<div className="flex flex-col items-center justify-center">
<div className="flex flex-col items-center justify-center">
<div className='flex flex-col items-center justify-center'>
<div className="animate-spin rounded-full h-20 w-20 border-t-2 border-b-2 border-gray-900">
</div>
<div className="text-gray-900 text-lg font-bold">
<Loader2 className="h-10 w-10 animate-spin" />
</div>
</div>
<p className="text-gray-900 text-lg font-bold"> ...</p>
</div>
</div>
)}
{!isLoading || currentWeather ? (
<div className="flex flex-col items-center justify-center">
<WeatherCard />
</div>
) : null}
</div>
</div>
)
}