Skip to content

Commit f58b721

Browse files
committed
add weather app II
1 parent 51a6774 commit f58b721

File tree

7 files changed

+303
-0
lines changed

7 files changed

+303
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ Welcome to the Mini Projects Showcase! This repository contains a collection of
3030
- Tabs
3131
- Todo App
3232
- Weather App
33+
- Weather App II
3334
- Word Counter

data.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,8 @@ const projects = [
107107
name: "Quiz App II",
108108
link: "quiz-app-II/index.html",
109109
},
110+
{
111+
name: "Weather App II",
112+
link: "weather-app-II/index.html",
113+
},
110114
];

weather-app-II/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Weather App
2+
3+
A simple weather application that allows users to check the current weather and a 5-day forecast for any city or their current location. This app uses the OpenWeatherMap API to fetch weather data and presents it in a user-friendly interface.
4+
5+
## Features
6+
7+
- **Search by City:** Enter a city name to get the current weather and a 5-day forecast.
8+
- **Use Current Location:** Automatically fetch the weather for your current location.
9+
- **Responsive Design:** The app is fully responsive, optimized for both desktop and mobile devices.
10+
11+
## Technologies Used
12+
13+
- **HTML5:** Structure and layout of the app.
14+
- **CSS3:** Styling the app, including media queries.
15+
- **JavaScript:** Fetching and handling data from the OpenWeatherMap API, dynamic content rendering.
16+
- **Bootstrap:** For responsive layout and styling.
17+
- **OpenWeatherMap API:** For fetching weather data (current weather and 5-day forecast).
18+
19+
## Acknowledgements
20+
21+
- **OpenWeatherMap API:** For providing weather data.
22+
- **Bootstrap:** For easy-to-use CSS.
23+
- **Google Fonts:** For the "Roboto Condensed" font used in the app.

weather-app-II/app.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Select DOM elements
2+
const searchBtn = document.querySelector(".search-btn");
3+
const currentLocationBtn = document.querySelector(".current-location-btn");
4+
const cityInput = document.querySelector(".city-input");
5+
const weatherCards = document.querySelector(".weather-cards");
6+
const todayWeatherCard = document.querySelector(".today-weather-card");
7+
8+
// Store API key
9+
const APIKEY = "c56c19f1c7c38425e05537cb48d74e41";
10+
11+
// Function to create a weather card
12+
const createWeatherCard = (cityName, weatherData, index) => {
13+
const tempCelsius = (weatherData.main.temp - 273.15).toFixed(2);
14+
const date = weatherData.dt_txt.split(" ")[0];
15+
const iconURL = `https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@4x.png`;
16+
const description = weatherData.weather[0].description;
17+
18+
if (index === 0) {
19+
return `<div class="d-flex flex-column gap-2">
20+
<p class="fs-3 fw-semibold">
21+
${cityName} (${date})
22+
</p>
23+
<p>Temperature: ${tempCelsius}°C</p>
24+
<p>Wind: ${weatherData.wind.speed} M/S</p>
25+
<p>Humidity: ${weatherData.main.humidity}%</p>
26+
</div>
27+
<div class="text-center icon-box">
28+
<img src="${iconURL}" alt="weather-conditions"/>
29+
<p>${description}</p>
30+
</div>`;
31+
} else {
32+
return `<div class="bg-secondary p-3 rounded-2 flex-grow-1 d-flex flex-column gap-1 weather-sub-card">
33+
<p>(${date})</p>
34+
<img src="${iconURL.replace(
35+
"@4x",
36+
"@2x"
37+
)}" alt="weather-conditions"/>
38+
<p>Temp: ${tempCelsius}°C</p>
39+
<p>Wind: ${weatherData.wind.speed} M/S</p>
40+
<p">Humidity: ${weatherData.main.humidity}%</p>
41+
</div>`;
42+
}
43+
};
44+
45+
// General function to fetch weather data
46+
const fetchWeatherData = async (url) => {
47+
try {
48+
const response = await fetch(url);
49+
return await response.json();
50+
} catch (error) {
51+
console.error(error);
52+
alert("An error occurred while fetching weather data.");
53+
}
54+
};
55+
56+
// Function to get weather information using city coordinates
57+
const getWeatherInfo = async (cityName, lat, lon) => {
58+
const WEATHER_API_URL = `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&appid=${APIKEY}`;
59+
const data = await fetchWeatherData(WEATHER_API_URL);
60+
61+
if (data) {
62+
const uniqueDays = new Set();
63+
const fiveDaysForecast = data.list.filter((forecast) => {
64+
const forecastDate = new Date(forecast.dt_txt).getDate();
65+
if (!uniqueDays.has(forecastDate)) {
66+
uniqueDays.add(forecastDate);
67+
return true;
68+
}
69+
return false;
70+
});
71+
72+
cityInput.value = "";
73+
todayWeatherCard.innerHTML = "";
74+
weatherCards.innerHTML = "";
75+
76+
// Use a DocumentFragment to batch DOM updates
77+
const todayCard = createWeatherCard(cityName, fiveDaysForecast[0], 0);
78+
todayWeatherCard.insertAdjacentHTML("beforeend", todayCard);
79+
80+
fiveDaysForecast.slice(1).forEach((weatherData, index) => {
81+
weatherCards.insertAdjacentHTML(
82+
"beforeend",
83+
createWeatherCard(cityName, weatherData, index + 1)
84+
);
85+
});
86+
}
87+
};
88+
89+
// Function to get city coordinates based on user input
90+
const getCityCoordinates = async () => {
91+
const cityName = cityInput.value.trim();
92+
if (!cityName) return alert("Input can't be empty !");
93+
94+
const GEOCODING_API_URL = `https://api.openweathermap.org/geo/1.0/direct?q=${cityName}&appid=${APIKEY}`;
95+
const data = await fetchWeatherData(GEOCODING_API_URL);
96+
97+
if (data && data.length > 0) {
98+
const { name, lat, lon } = data[0];
99+
getWeatherInfo(name, lat, lon);
100+
} else {
101+
alert(`No coordinates found for ${cityName}`);
102+
}
103+
};
104+
105+
// Function to get user coordinates and fetch weather data
106+
const getUserCoordinates = () => {
107+
navigator.geolocation.getCurrentPosition(
108+
async (position) => {
109+
const { latitude, longitude } = position.coords;
110+
const REVERSE_GEOCODING_URL = `https://api.openweathermap.org/geo/1.0/reverse?lat=${latitude}&lon=${longitude}&limit=1&appid=${APIKEY}`;
111+
const data = await fetchWeatherData(REVERSE_GEOCODING_URL);
112+
113+
if (data && data.length > 0) {
114+
const { name } = data[0];
115+
getWeatherInfo(name, latitude, longitude);
116+
} else {
117+
alert("Could not determine city from your location.");
118+
}
119+
},
120+
(error) => {
121+
if (error.code === error.PERMISSION_DENIED) {
122+
alert("Permission denied to access location.");
123+
}
124+
}
125+
);
126+
};
127+
128+
// Event listeners
129+
currentLocationBtn.addEventListener("click", getUserCoordinates);
130+
searchBtn.addEventListener("click", getCityCoordinates);
131+
cityInput.addEventListener(
132+
"keyup",
133+
(e) => e.key === "Enter" && getCityCoordinates()
134+
);

weather-app-II/index.html

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Weather App</title>
7+
<!-- Bootstrap CSS for styling -->
8+
<link
9+
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
10+
rel="stylesheet"
11+
/>
12+
<!-- Custom styles -->
13+
<link rel="stylesheet" href="style.css" />
14+
</head>
15+
<body>
16+
<!-- Main title -->
17+
<h1 class="text-center pt-3 fw-semibold">Weather App</h1>
18+
19+
<div class="d-flex flex-column flex-lg-row px-4 gap-4 gap-xl-5 py-3">
20+
<!-- Input box for city name or current location -->
21+
<div class="input-box">
22+
<h4 class="fw-semibold">Enter city name</h4>
23+
<input type="text" class="form-control city-input" placeholder="E.g. Mumbai, London, Delhi" />
24+
<button class="btn btn-primary w-100 mt-3 fs-5 search-btn">Search</button>
25+
<p class="fs-4 text-center">or</p>
26+
<button class="btn btn-secondary w-100 mt-1 fs-5 current-location-btn">
27+
Use current location
28+
</button>
29+
</div>
30+
31+
<!-- Weather information display -->
32+
<div class="output-box d-flex flex-column gap-3">
33+
<!-- Today's weather card -->
34+
<div
35+
class="bg-primary w-100 rounded-2 text-white p-3 fs-5 d-flex justify-content-between today-weather-card"
36+
>
37+
<div class="d-flex flex-column gap-2">
38+
<p class="fs-3 fw-semibold">_____ ( _____ )</p>
39+
<p>Temperature: __°C</p>
40+
<p>Wind: __ M/S</p>
41+
<p>Humidity: __ %</p>
42+
</div>
43+
</div>
44+
45+
<!-- 5-day forecast -->
46+
<h3 class="fw-semibold">5-day forecast</h3>
47+
<div class="w-100 d-flex flex-wrap gap-4 text-white fs-5 weather-cards">
48+
<!-- Each day’s forecast -->
49+
<div class="bg-secondary p-3 rounded-2 flex-grow-1 d-flex flex-column gap-1 weather-sub-card">
50+
<p>( _____ )</p>
51+
<p>Temp: __ C</p>
52+
<p>Wind: __ M/S</p>
53+
<p">Humidity: __ %</p>
54+
</div>
55+
<!-- Repeat similar cards for other days -->
56+
<div class="bg-secondary p-3 rounded-2 flex-grow-1 d-flex flex-column gap-1 weather-sub-card">
57+
<p>( _____ )</p>
58+
<p>Temp: __ C</p>
59+
<p>Wind: __ M/S</p>
60+
<p">Humidity: __ %</p>
61+
</div>
62+
<div class="bg-secondary p-3 rounded-2 flex-grow-1 d-flex flex-column gap-1 weather-sub-card">
63+
<p>( _____ )</p>
64+
<p>Temp: __ C</p>
65+
<p>Wind: __ M/S</p>
66+
<p">Humidity: __ %</p>
67+
</div>
68+
<div class="bg-secondary p-3 rounded-2 flex-grow-1 d-flex flex-column gap-1 weather-sub-card">
69+
<p>( _____ )</p>
70+
<p>Temp: __ C</p>
71+
<p>Wind: __ M/S</p>
72+
<p">Humidity: __ %</p>
73+
</div>
74+
<div class="bg-secondary p-3 rounded-2 flex-grow-1 d-flex flex-column gap-1 weather-sub-card">
75+
<p>( _____ )</p>
76+
<p>Temp: __ C</p>
77+
<p>Wind: __ M/S</p>
78+
<p">Humidity: __ %</p>
79+
</div>
80+
</div>
81+
</div>
82+
</div>
83+
84+
<!-- Link to the JavaScript file -->
85+
<script src="app.js"></script>
86+
</body>
87+
</html>

weather-app-II/style.css

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* Importing the "Roboto Condensed" font from Google Fonts */
2+
@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@100..900&display=swap");
3+
4+
/* Global reset for all elements */
5+
* {
6+
margin: 0;
7+
padding: 0;
8+
box-sizing: border-box;
9+
font-family: "Roboto Condensed", sans-serif;
10+
}
11+
12+
/* Set width and height to 100% for both html and body */
13+
html,
14+
body {
15+
width: 100%;
16+
height: 100%;
17+
}
18+
19+
body {
20+
background-color: rgb(210, 227, 248);
21+
}
22+
23+
p {
24+
margin: 0;
25+
}
26+
27+
.input-box {
28+
width: 25%;
29+
}
30+
31+
.output-box {
32+
width: 75%;
33+
}
34+
35+
.today-weather-card .icon-box img {
36+
max-width: 120px;
37+
}
38+
39+
.today-weather-card .icon-box p {
40+
text-transform: capitalize;
41+
}
42+
43+
.weather-sub-card img {
44+
max-width: 80px;
45+
}
46+
47+
/* Responsive styles for screens smaller than 992px (tablets and smaller devices) */
48+
@media (max-width: 992px) {
49+
/* Styles for screens below 768px */
50+
.input-box,
51+
.output-box {
52+
width: 100%;
53+
}
54+
}

weather-app-II/weather-app.png

208 KB
Loading

0 commit comments

Comments
 (0)