added more design using tailwind classes
This commit is contained in:
@@ -8,7 +8,7 @@ type LayoutProps = {
|
|||||||
|
|
||||||
const Layout: React.FC<LayoutProps> = ({ children }) => {
|
const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-blue-100 to-blue-300 flex flex-col">
|
<div className="min-h-screen bg-gradient-to-br from-blue-100 via-blue-200 to-blue-400 flex flex-col">
|
||||||
<Header />
|
<Header />
|
||||||
<ToastContainer
|
<ToastContainer
|
||||||
position="top-right"
|
position="top-right"
|
||||||
@@ -22,7 +22,9 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
|||||||
pauseOnHover
|
pauseOnHover
|
||||||
theme="dark"
|
theme="dark"
|
||||||
/>
|
/>
|
||||||
<main className="flex-1 container mx-auto px-4 py-8">{children}</main>
|
<main className="flex-1 container mx-auto px-4 py-8 flex flex-col items-center justify-center">
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -12,16 +12,21 @@ const ChangeAPI: React.FC<Props> = ({ currentAPIKey }) => {
|
|||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<h2 className="text-2xl font-bold mb-2 text-blue-700">Change API Key</h2>
|
<h2 className="text-2xl font-bold mb-2 text-blue-700">Change API Key</h2>
|
||||||
<p className="mb-6 text-gray-600">
|
<p className="mb-2 text-gray-600">
|
||||||
Update your API key to fetch weather data.
|
Update your API key to fetch weather data.
|
||||||
</p>
|
</p>
|
||||||
<p className="mb-6 text-gray-600">
|
<div className="mb-6 flex items-center gap-2 text-gray-600">
|
||||||
We are using{" "}
|
<span>We are using</span>
|
||||||
<a href="https://openweathermap.org/api">
|
<a
|
||||||
<strong>OpenWeatherMap</strong>
|
href="https://openweathermap.org/api"
|
||||||
</a>{" "}
|
className="text-blue-600 font-semibold underline hover:text-blue-800"
|
||||||
API for fetching weather data.
|
target="_blank"
|
||||||
</p>
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
OpenWeatherMap
|
||||||
|
</a>
|
||||||
|
<span>API for fetching weather data.</span>
|
||||||
|
</div>
|
||||||
<form className="flex flex-col gap-4">
|
<form className="flex flex-col gap-4">
|
||||||
<label htmlFor="apiKey" className="font-medium text-gray-700">
|
<label htmlFor="apiKey" className="font-medium text-gray-700">
|
||||||
API Key:
|
API Key:
|
||||||
@@ -34,11 +39,11 @@ const ChangeAPI: React.FC<Props> = ({ currentAPIKey }) => {
|
|||||||
value={apiKey}
|
value={apiKey}
|
||||||
onChange={(e) => setApiKey(e.target.value)}
|
onChange={(e) => setApiKey(e.target.value)}
|
||||||
required
|
required
|
||||||
className="border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400"
|
className="border border-blue-300 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-400 bg-blue-50 text-blue-900 font-mono"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="bg-blue-600 text-white font-semibold px-4 py-2 rounded-lg shadow hover:bg-blue-700 transition"
|
className="bg-gradient-to-r from-blue-600 to-blue-400 text-white font-bold px-6 py-3 rounded-xl shadow-lg hover:from-blue-700 hover:to-blue-500 transition-all"
|
||||||
onClick={() => changeAPIcookie(apiKey)}
|
onClick={() => changeAPIcookie(apiKey)}
|
||||||
>
|
>
|
||||||
Update API Key
|
Update API Key
|
||||||
|
@@ -9,22 +9,40 @@ const Header: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header className="bg-blue-600 text-white shadow-md py-6 px-4 flex items-center justify-between">
|
<header className="bg-gradient-to-r from-blue-700 via-blue-600 to-blue-500 text-white shadow-lg py-8 px-6 flex items-center justify-between rounded-b-3xl">
|
||||||
<h1 className="text-3xl font-bold tracking-wide drop-shadow">
|
<div className="flex items-center gap-4">
|
||||||
|
<img
|
||||||
|
src="/favicon.ico"
|
||||||
|
alt="Weather App Logo"
|
||||||
|
className="w-10 h-10 drop-shadow-lg"
|
||||||
|
/>
|
||||||
|
<h1 className="text-4xl font-extrabold tracking-wide drop-shadow-lg">
|
||||||
Weather App
|
Weather App
|
||||||
</h1>
|
</h1>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
className="bg-white text-blue-600 font-semibold px-4 py-2 rounded-lg shadow hover:bg-blue-100 transition"
|
className="bg-white text-blue-700 font-bold px-6 py-3 rounded-xl shadow-lg hover:bg-blue-100 transition-all border border-blue-200"
|
||||||
onClick={() => setApiCard(true)}
|
onClick={() => setApiCard(true)}
|
||||||
>
|
>
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<svg
|
||||||
|
className="w-5 h-5"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path d="M12 4v16m8-8H4" />
|
||||||
|
</svg>
|
||||||
Set API Key
|
Set API Key
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
{apiCard && (
|
{apiCard && (
|
||||||
<div className="fixed inset-0 bg-gray-800 bg-opacity-40 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-gray-900 bg-opacity-60 flex items-center justify-center z-50 transition-all">
|
||||||
<div className="bg-white rounded-xl shadow-lg p-8 w-full max-w-md relative">
|
<div className="bg-white rounded-2xl shadow-2xl p-10 w-full max-w-md relative border-2 border-blue-200">
|
||||||
<button
|
<button
|
||||||
className="absolute top-4 right-4 text-gray-400 hover:text-blue-600 text-xl"
|
className="absolute top-4 right-4 text-gray-400 hover:text-blue-600 text-2xl font-bold"
|
||||||
onClick={() => setApiCard(false)}
|
onClick={() => setApiCard(false)}
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
>
|
>
|
||||||
|
@@ -13,24 +13,37 @@ const WeatherData: React.FC = () => {
|
|||||||
: "";
|
: "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center items-center min-h-[80vh]">
|
<div className="flex justify-center items-center min-h-[60vh]">
|
||||||
<div className="bg-white/80 p-8 rounded-xl shadow-lg min-w-[300px] text-center">
|
<div className="bg-white/90 p-10 rounded-2xl shadow-2xl min-w-[320px] text-center border-2 border-blue-200">
|
||||||
<h2 className="text-2xl font-semibold mb-2">{weatherData?.name}</h2>
|
<h2 className="text-3xl font-bold mb-2 text-blue-700 flex items-center justify-center gap-2">
|
||||||
<p className="text-4xl font-bold mb-2">{weatherData?.main?.temp} °C</p>
|
<svg
|
||||||
<p className="text-lg mb-4 capitalize">
|
className="w-7 h-7 text-blue-400"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path d="M3 12a9 9 0 0118 0A9 9 0 013 12z" />
|
||||||
|
</svg>
|
||||||
|
{weatherData?.name}
|
||||||
|
</h2>
|
||||||
|
<p className="text-5xl font-extrabold mb-2 text-blue-900">
|
||||||
|
{weatherData?.main?.temp} °C
|
||||||
|
</p>
|
||||||
|
<p className="text-lg mb-4 capitalize text-blue-600">
|
||||||
{weatherData?.weather?.[0]?.description}
|
{weatherData?.weather?.[0]?.description}
|
||||||
</p>
|
</p>
|
||||||
{iconUrl && (
|
{iconUrl && (
|
||||||
<img
|
<img
|
||||||
src={iconUrl}
|
src={iconUrl}
|
||||||
alt={weatherData?.weather?.[0]?.description}
|
alt={weatherData?.weather?.[0]?.description}
|
||||||
className="mx-auto mb-4 w-32 h-32"
|
className="mx-auto mb-4 w-32 h-32 drop-shadow-lg"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-col items-center gap-2 mb-2">
|
<div className="flex flex-col items-center gap-4 mb-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-3">
|
||||||
<img src={sunriseIcon} alt="Sunrise Icon" className="w-6 h-6" />
|
<img src={sunriseIcon} alt="Sunrise Icon" className="w-7 h-7" />
|
||||||
<span className="text-base">
|
<span className="text-base text-blue-700 font-semibold">
|
||||||
Sunrise:{" "}
|
Sunrise:{" "}
|
||||||
{weatherData?.sys?.sunrise
|
{weatherData?.sys?.sunrise
|
||||||
? new Date(weatherData.sys.sunrise * 1000).toLocaleTimeString(
|
? new Date(weatherData.sys.sunrise * 1000).toLocaleTimeString(
|
||||||
@@ -40,9 +53,9 @@ const WeatherData: React.FC = () => {
|
|||||||
: "--:--"}
|
: "--:--"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-3">
|
||||||
<img src={sunsetIcon} alt="Sunset Icon" className="w-6 h-6" />
|
<img src={sunsetIcon} alt="Sunset Icon" className="w-7 h-7" />
|
||||||
<span className="text-base">
|
<span className="text-base text-blue-700 font-semibold">
|
||||||
Sunset:{" "}
|
Sunset:{" "}
|
||||||
{weatherData?.sys?.sunset
|
{weatherData?.sys?.sunset
|
||||||
? new Date(weatherData.sys.sunset * 1000).toLocaleTimeString(
|
? new Date(weatherData.sys.sunset * 1000).toLocaleTimeString(
|
||||||
|
@@ -46,11 +46,26 @@ const WeatherCard: React.FC = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="w-full max-w-lg mx-auto bg-white/80 rounded-2xl shadow-xl p-8 mt-8">
|
||||||
<h2>Weather Card</h2>
|
<h2 className="text-3xl font-bold mb-4 text-blue-700 flex items-center gap-2">
|
||||||
<p>Current Weather will be displayed here</p>
|
<svg
|
||||||
<form onSubmit={handleSubmit}>
|
className="w-8 h-8 text-blue-400"
|
||||||
<label htmlFor="city">Enter City:</label>
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path d="M3 12a9 9 0 0118 0A9 9 0 013 12z" />
|
||||||
|
</svg>
|
||||||
|
Weather Card
|
||||||
|
</h2>
|
||||||
|
<p className="mb-2 text-gray-600">
|
||||||
|
Current weather will be displayed here.
|
||||||
|
</p>
|
||||||
|
<form onSubmit={handleSubmit} className="flex flex-col gap-4 mt-4">
|
||||||
|
<label htmlFor="city" className="font-medium text-gray-700">
|
||||||
|
Enter City:
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="city"
|
id="city"
|
||||||
@@ -59,11 +74,17 @@ const WeatherCard: React.FC = () => {
|
|||||||
value={city}
|
value={city}
|
||||||
placeholder="City Name"
|
placeholder="City Name"
|
||||||
required
|
required
|
||||||
|
className="border border-blue-300 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-400 bg-blue-50 text-blue-900 font-mono"
|
||||||
/>
|
/>
|
||||||
<button type="submit">Get Weather</button>
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="bg-gradient-to-r from-blue-600 to-blue-400 text-white font-bold px-6 py-3 rounded-xl shadow-lg hover:from-blue-700 hover:to-blue-500 transition-all"
|
||||||
|
>
|
||||||
|
Get Weather
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{weatherData && <WeatherData />}
|
{weatherData && <WeatherData />}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user