├── 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 |
--------------------------------------------------------------------------------
/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;
--------------------------------------------------------------------------------