├── src ├── assets │ ├── rain.png │ ├── snow.png │ ├── wind.png │ ├── clear.png │ ├── cloud.png │ ├── search.png │ ├── drizzle.png │ └── humidity.png ├── App.jsx ├── index.css ├── main.jsx ├── App.css └── Component │ ├── Weather.css │ ├── Weather.jsx │ └── Modal.jsx ├── vite.config.js ├── .gitignore ├── index.html ├── package.json ├── public └── weather.svg └── README.md /src/assets/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhapraxAhmed/weather-app/HEAD/src/assets/rain.png -------------------------------------------------------------------------------- /src/assets/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhapraxAhmed/weather-app/HEAD/src/assets/snow.png -------------------------------------------------------------------------------- /src/assets/wind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhapraxAhmed/weather-app/HEAD/src/assets/wind.png -------------------------------------------------------------------------------- /src/assets/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhapraxAhmed/weather-app/HEAD/src/assets/clear.png -------------------------------------------------------------------------------- /src/assets/cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhapraxAhmed/weather-app/HEAD/src/assets/cloud.png -------------------------------------------------------------------------------- /src/assets/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhapraxAhmed/weather-app/HEAD/src/assets/search.png -------------------------------------------------------------------------------- /src/assets/drizzle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhapraxAhmed/weather-app/HEAD/src/assets/drizzle.png -------------------------------------------------------------------------------- /src/assets/humidity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhapraxAhmed/weather-app/HEAD/src/assets/humidity.png -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vite.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | 9 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import './App.css' 2 | import Weather from './Component/Weather' 3 | 4 | function App() { 5 | 6 | return (<> 7 |
8 | 9 |
10 | 11 | ) 12 | 13 | } 14 | 15 | export default App 16 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | font-family: "poppins", "sans-serif"; 8 | } -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import './index.css' 4 | import "bootstrap/dist/css/bootstrap.min.css"; 5 | import App from './App.jsx' 6 | 7 | createRoot(document.getElementById('root')).render( 8 | 9 | 10 | , 11 | ) 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Weather App 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | font-family: Arial, sans-serif; 4 | padding: 20px; 5 | } 6 | 7 | .weather-container { 8 | background: #f4f4f4; 9 | padding: 20px; 10 | border-radius: 10px; 11 | width: auto; 12 | margin: auto; 13 | box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); 14 | } 15 | 16 | input { 17 | padding: 10px; 18 | width: 80%; 19 | margin: 10px 0; 20 | } 21 | 22 | button { 23 | padding: 10px; 24 | background: blue; 25 | color: white; 26 | border: none; 27 | cursor: pointer; 28 | } 29 | 30 | .weather-info { 31 | margin-top: 20px; 32 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@radix-ui/react-dialog": "^1.1.6", 14 | "bootstrap": "^5.3.3", 15 | "framer-motion": "^12.6.2", 16 | "lucide-react": "^0.485.0", 17 | "react": "^19.0.0", 18 | "react-bootstrap": "^2.10.9", 19 | "react-dom": "^19.0.0" 20 | }, 21 | "devDependencies": { 22 | "@eslint/js": "^9.21.0", 23 | "@types/react": "^19.0.10", 24 | "@types/react-dom": "^19.0.4", 25 | "@vitejs/plugin-react": "^4.3.4", 26 | "eslint": "^9.21.0", 27 | "eslint-plugin-react-hooks": "^5.1.0", 28 | "eslint-plugin-react-refresh": "^0.4.19", 29 | "globals": "^15.15.0", 30 | "vite": "^6.2.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /public/weather.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Weather App 🌦️ 2 | 3 | A modern weather prediction app that provides real-time weather updates for any city worldwide. 4 | 5 | ## 🚀 Features 6 | 7 | - Real-time weather data: temperature, humidity, wind speed, and more 8 | - 5-day weather forecast with hourly breakdown 9 | - Search by city name or use geolocation for local weather 10 | - Clean, responsive, and mobile-friendly UI 11 | - Dark & light theme switcher 12 | - Error handling for invalid cities and network issues 13 | 14 | ## 🛠️ Tech Stack 15 | 16 | - **Frontend:** HTML5, CSS3, JavaScript (Vanilla / React / Vue) 17 | - **API:** OpenWeatherMap / WeatherAPI / Other (specify your weather data provider) 18 | - **Design:** Responsive CSS, Flexbox/Grid, custom icons (FontAwesome/Material Icons) 19 | - **Build Tools:** npm, Webpack, Babel (if used) 20 | - **Deployment:** GitHub Pages / Vercel / Netlify (add your deployment platform) 21 | 22 | ## 🔗 Demo 23 | 24 | [🌐 Live Demo](#) 25 | 26 | ## 📦 Installation 27 | 28 | ```bash 29 | git clone https://github.com/AhmedHussainCodes/weather-app.git 30 | cd weather-app 31 | npm install # If using npm 32 | npm start # Or open index.html in browser 33 | ``` 34 | 35 | ## 🔑 API Configuration 36 | 37 | 1. Register for an API key at [OpenWeatherMap](https://openweathermap.org/) or your chosen provider. 38 | 2. Add your API key to the project: 39 | - In `config.js` or wherever the API key is referenced: 40 | ```js 41 | const API_KEY = 'YOUR_API_KEY_HERE'; 42 | ``` 43 | 44 | ## 🧑‍💻 Contributing 45 | 46 | Contributions are welcome! 47 | To contribute: 48 | - Fork the repository 49 | - Create a new branch 50 | - Make your changes and commit them 51 | - Open a pull request 52 | 53 | ## 📝 License 54 | 55 | [MIT](LICENSE) 56 | 57 | ## 🙋‍♂️ Author 58 | 59 | - Ahmed Hussain ([GitHub](https://github.com/AhmedHussainCodes)) 60 | 61 | --- 62 | 63 | > Made with ❤️ for learning and sharing. 64 | -------------------------------------------------------------------------------- /src/Component/Weather.css: -------------------------------------------------------------------------------- 1 | .Container { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | height: auto; 6 | background-image: linear-gradient(45deg, #121212, #1e1e2e); 7 | padding: 40px; 8 | border-radius: 30px; 9 | flex-direction: column; 10 | place-self: center; 11 | box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); 12 | } 13 | 14 | .search { 15 | display: flex; 16 | align-items: center; 17 | background: #2a2a3c; 18 | padding: 12px 20px; 19 | border-radius: 50px; 20 | box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4); 21 | width: 400px; 22 | height: 65px; 23 | transition: all 0.3s ease-in-out; 24 | } 25 | 26 | .search input { 27 | border: none; 28 | outline: none; 29 | font-size: 20px; 30 | padding: 12px; 31 | flex: 1; 32 | background: transparent; 33 | color: #e0e0e0; 34 | font-weight: 500; 35 | } 36 | 37 | .search input::placeholder { 38 | color: #6b7280; 39 | font-size: 16px; 40 | font-weight: 400; 41 | } 42 | 43 | .search img { 44 | width: 28px; 45 | height: 28px; 46 | cursor: pointer; 47 | margin-left: 15px; 48 | transition: transform 0.3s ease, filter 0.3s ease; 49 | filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.5)); 50 | } 51 | 52 | .search img:hover { 53 | transform: scale(1.3); 54 | filter: brightness(1.4); 55 | } 56 | 57 | .weather-icon { 58 | width: 130px; 59 | height: 130px; 60 | margin-top: 10px; 61 | filter: drop-shadow(0px 5px 15px rgba(255, 255, 255, 0.2)); 62 | } 63 | 64 | .temp { 65 | font-size: 4rem; 66 | font-weight: bold; 67 | color: #e0e0e0; 68 | margin: 5px 0; 69 | text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.5); 70 | } 71 | 72 | .location { 73 | font-size: 3rem; 74 | font-weight: 700; 75 | color: #d1d5db; 76 | text-shadow: 2px 2px 10px rgba(0, 0, 0, 0.6); 77 | } 78 | 79 | .weather-data { 80 | display: flex; 81 | justify-content: space-around; 82 | align-items: center; 83 | width: 100%; 84 | max-width: 420px; 85 | background: rgba(30, 30, 46, 0.5); 86 | padding: 20px; 87 | border-radius: 15px; 88 | box-shadow: 0 6px 15px rgba(0, 0, 0, 0.4); 89 | backdrop-filter: blur(10px); 90 | } 91 | 92 | .col { 93 | display: flex; 94 | align-items: center; 95 | gap: 12px; 96 | } 97 | 98 | .col img { 99 | width: 42px; 100 | height: 42px; 101 | } 102 | 103 | .col div { 104 | display: flex; 105 | flex-direction: column; 106 | align-items: flex-start; 107 | } 108 | 109 | .col p { 110 | font-size: 20px; 111 | font-weight: bold; 112 | color: #e0e0e0; 113 | margin: 0; 114 | text-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5); 115 | } 116 | 117 | .col span { 118 | font-size: 15px; 119 | color: #9ca3af; 120 | } 121 | 122 | .modal-backdrop { 123 | position: fixed; 124 | top: 0; 125 | left: 0; 126 | width: 100%; 127 | height: 100%; 128 | background: rgba(0, 0, 0, 0.8); 129 | } 130 | 131 | .modal-content { 132 | background: linear-gradient(135deg, #1e1e2e, #2a2a3c); 133 | box-shadow: 0 12px 35px rgba(0, 0, 0, 0.5); 134 | border-radius: 15px; 135 | padding: 20px; 136 | } -------------------------------------------------------------------------------- /src/Component/Weather.jsx: -------------------------------------------------------------------------------- 1 | import './Weather.css' 2 | import CustomModal from "./Modal"; 3 | import search_icon from '../assets/search.png' 4 | import clear_icon from '../assets/clear.png' 5 | import cloud_icon from '../assets/cloud.png' 6 | import drizzle_icon from '../assets/drizzle.png' 7 | import humidity_icon from '../assets/humidity.png' 8 | import rain_icon from '../assets/rain.png' 9 | import snow_icon from '../assets/snow.png' 10 | import wind_icon from '../assets/wind.png' 11 | import { useEffect, useRef, useState } from "react"; 12 | 13 | const Weather = () => { 14 | 15 | const inputref = useRef() 16 | const [weatherdata, setweather] = useState(false) 17 | const [modalOpen, setModalOpen] = useState(false); 18 | 19 | const allicons = { 20 | "01d": clear_icon, 21 | "01n": clear_icon, 22 | "02d": cloud_icon, 23 | "02n": cloud_icon, 24 | "03d": cloud_icon, 25 | "03n": cloud_icon, 26 | "04d": drizzle_icon, 27 | "04n": drizzle_icon, 28 | "09d": rain_icon, 29 | "09n": rain_icon, 30 | "10d": rain_icon, 31 | "10n": rain_icon, 32 | "13d": snow_icon, 33 | "13n": snow_icon, 34 | } 35 | console.log("API Key:", import.meta.env.VITE_APP_ID); 36 | 37 | const weather = async (city) => { 38 | if (!city) { 39 | setModalOpen(true); 40 | return; 41 | } 42 | try { 43 | const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${import.meta.env.VITE_APP_ID}`; 44 | 45 | const response = await fetch(url); 46 | const data = await response.json(); 47 | console.log(data); 48 | if (!response.ok) { 49 | alert(data.setModalOpen(true)) 50 | return; 51 | } 52 | const icon = allicons[data.weather[0].icon] || clear_icon; 53 | setweather({ 54 | humidity: data.main.humidity, 55 | windSpeed: data.wind.speed, 56 | temperature: Math.floor(data.main.temp), 57 | location: data.name, 58 | icon: icon 59 | }) 60 | } 61 | catch (error) { 62 | setweather(false) 63 | console.error("Error in fetching the Data") 64 | } 65 | } 66 | useEffect(() => { 67 | weather("Berlin") 68 | }, []) 69 | return ( 70 |
71 | 72 | setModalOpen(false)} 75 | message="Please enter a city name!" 76 | 77 | /> 78 |
79 | 80 | weather(inputref.current.value)} /> 81 |
82 | {weatherdata ? <> 83 | 84 |

{weatherdata.temperature}°C

85 |

{weatherdata.location}

86 | 87 |
88 |
89 | 90 |
91 |

{weatherdata.humidity}%

92 | Humidity 93 |
94 |
95 |
96 | 97 |
98 |

{weatherdata.windSpeed} Km/h

99 | Wind 100 |
101 |
102 |
103 | : <>} 104 | 105 |
106 | 107 | ) 108 | } 109 | export default Weather -------------------------------------------------------------------------------- /src/Component/Modal.jsx: -------------------------------------------------------------------------------- 1 | import { Modal, Button } from "react-bootstrap"; 2 | import { motion } from "framer-motion"; 3 | 4 | const CustomModal = ({ isOpen, onClose, message }) => { 5 | return ( 6 | 13 | 24 | 25 | 45 |
58 | 59 |
60 | 61 | 67 | 79 | ☁️ 80 | 81 | 82 | Weather Alert 83 | 84 | 100 | 101 | 102 | 103 | 104 | 110 |

119 | {message} 120 |

121 | 122 |
132 | ☁ 133 |
134 |
144 | ☁ 145 |
146 |
147 |
148 | 149 | 150 | 154 | 167 | 168 | 169 |
170 | 171 |
183 | 184 | 185 | ); 186 | }; 187 | 188 | export default CustomModal; --------------------------------------------------------------------------------