diff --git a/.env b/.env new file mode 100644 index 0000000..8e999b1 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +VITE_APP_ID="cefe612bcf0d2866aa80dbab07820af2" \ No newline at end of file diff --git a/App.css b/App.css new file mode 100644 index 0000000..b9d355d --- /dev/null +++ b/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/App.jsx b/App.jsx new file mode 100644 index 0000000..c6bcb9e --- /dev/null +++ b/App.jsx @@ -0,0 +1,13 @@ + +import React from 'react' +import Weather from './components/Weather' + +const App = () => { + return ( +
+ +
+ ) +} + +export default App diff --git a/assets/clear.png b/assets/clear.png new file mode 100644 index 0000000..458cd29 Binary files /dev/null and b/assets/clear.png differ diff --git a/assets/cloudy.png b/assets/cloudy.png new file mode 100644 index 0000000..c9907f3 Binary files /dev/null and b/assets/cloudy.png differ diff --git a/assets/drizzle.png b/assets/drizzle.png new file mode 100644 index 0000000..df7d8c2 Binary files /dev/null and b/assets/drizzle.png differ diff --git a/assets/humidity.png b/assets/humidity.png new file mode 100644 index 0000000..014ad02 Binary files /dev/null and b/assets/humidity.png differ diff --git a/assets/rain.jfif b/assets/rain.jfif new file mode 100644 index 0000000..e39c077 Binary files /dev/null and b/assets/rain.jfif differ diff --git a/assets/search.png b/assets/search.png new file mode 100644 index 0000000..b1645e9 Binary files /dev/null and b/assets/search.png differ diff --git a/assets/snow.jfif b/assets/snow.jfif new file mode 100644 index 0000000..e357ea2 Binary files /dev/null and b/assets/snow.jfif differ diff --git a/assets/windy.png b/assets/windy.png new file mode 100644 index 0000000..3dff3ed Binary files /dev/null and b/assets/windy.png differ diff --git a/components/Weather.css b/components/Weather.css new file mode 100644 index 0000000..c8a921a --- /dev/null +++ b/components/Weather.css @@ -0,0 +1,75 @@ +.weather{ + place-self:center; + padding:40px; + border-radius: 10px; + background-image: linear-gradient(135deg, rgb(88, 120, 88), #d4fc79, #96e6a1); + display: flex; + flex-direction: column; + align-items: center; +} + +.search-bar img { + width: 24px; + padding:15px; + border-radius: 50%; + background: #d5f9da; + cursor:pointer; +} + +.search-bar{ + display: flex; + align-items: center; + gap:12px; +} + +.search-bar input{ + height: 50px; + border: none; + outline: none; + border-radius: 40px; + padding-left: 25px; + color:#3f472a; + background-color: #d5f9da; + font-size: 18px; +} + +.weather-icon{ + width: 150px; + margin:30px 0; +} + +.temprature{ + color: #3f472a; + font-size: 80px; + line-height: 1; +} + +.location{ + color:#3f472a; + font-size: 40px; +} + +.weather-data{ + width: 100%; + margin-top: 40px; + color:#3f472a; + display: flex; + justify-content:space-between; +} + +.weather-data .col{ + display: flex; + align-items: flex-start; + gap:12px; + font-size: 22px; +} + +.weather-data .col span{ + display: flex; + font-size: 16px; +} + +.weather-data .col img{ + width: 25px; + margin-top: 9px; +} \ No newline at end of file diff --git a/components/Weather.jsx b/components/Weather.jsx new file mode 100644 index 0000000..3a82b9e --- /dev/null +++ b/components/Weather.jsx @@ -0,0 +1,109 @@ + +import React, { useEffect, useRef, useState } from 'react'; +import './Weather.css'; +import search_icon from '../assets/search.png'; +import clear_icon from '../assets/clear.png'; +import humidity_icon from '../assets/humidity.png'; +import windy_icon from '../assets/windy.png'; +import cloudy_icon from '../assets/cloudy.png'; +import drizzle_icon from '../assets/drizzle.png'; +import rain_icon from '../assets/rain.jfif'; +import snow_icon from '../assets/snow.jfif'; + +const Weather = () => { + const inputRef = useRef(); + const [weatherData, setWeatherData] = useState({}); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const allIcons = { + "01d": clear_icon, + "01n": clear_icon, + "02d": cloudy_icon, + "02n": cloudy_icon, + "03d": cloudy_icon, + "03n": cloudy_icon, + "04d": drizzle_icon, + "04n": drizzle_icon, + "09d": rain_icon, + "09n": rain_icon, + "10d": rain_icon, + "10n": rain_icon, + "13d": snow_icon, + "13n": snow_icon, + }; + + const search = async (city = 'London') => { + setLoading(true); + setError(null); // Reset error state + try { + const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=cefe612bcf0d2866aa80dbab07820af2`; + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + const data = await response.json(); + console.log('API Data:', data); // Log the response data + + if (data.weather && data.weather.length > 0) { + const icon = allIcons[data.weather[0].icon] || clear_icon; + setWeatherData({ + humidity: data.main.humidity, + windSpeed: data.wind.speed, + temperature: Math.floor(data.main.temp), // Temp is already in Celsius + location: data.name, + icon: icon + }); + } else { + throw new Error('Unexpected weather data format'); + } + } catch (error) { + console.error('Error fetching weather data:', error.message); + setError(error.message); + setWeatherData({}); // Clear weather data on error + } finally { + setLoading(false); + } + }; + + useEffect(() => { + search(); + }, []); + + return ( +
+
+ + Search search(inputRef.current.value)} /> +
+ {loading &&

Loading...

} + {error &&

Error: {error}

} + {!loading && !error && ( + <> + {weatherData.icon && Weather icon} + {weatherData.temperature !== undefined &&

{weatherData.temperature}°C

} + {weatherData.location &&

{weatherData.location}

} +
+
+ Humidity +
+

{weatherData.humidity}%

+ Humidity +
+
+
+ Wind Speed +
+

{weatherData.windSpeed} km/hr

+ Wind Speed +
+
+
+ + )} +
+ ); +}; + +export default Weather; + diff --git a/index.css b/index.css new file mode 100644 index 0000000..db47223 --- /dev/null +++ b/index.css @@ -0,0 +1,17 @@ +@import url('https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap'); + + + + +*{ + margin:0; + padding:0; + border: border-box; + font-family: "Kalam", cursive; +} + +.app{ + min-height: 100vh; + display: grid; + background: rgb(88, 120, 88); +} \ No newline at end of file diff --git a/main.jsx b/main.jsx new file mode 100644 index 0000000..54b39dd --- /dev/null +++ b/main.jsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.jsx' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')).render( + + + , +)