Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Week 7: Weather app #416

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
# Weather App

Replace this readme with your own information about your project.
Completed my first project, which involved integrating data from an open-source API into a weather application. This project provides a simple yet functional weather forecast for Dubai, for the upcoming five days. The forecast updates dynamically as new information is fetched from the API. In addition to the basic weather data, the app includes precise details about sunrise and sunset times for each day. From a design perspective, I incorporated an intuitive feature that allows users to toggle between a day and night mode, altering the visual theme to reflect different times of the day.

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.

## The problem

Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
## The Problem
I began the project by focusing on the design, utilising HTML and CSS to create a visually appealing layout. Once the core design was in place, I worked on making it responsive, ensuring it would display well across various devices. The most challenging part came when I transitioned into adding dynamic elements using JavaScript. Since I was new to working with APIs, fetching data from the open-source API was a learning curve. The biggest hurdle I encountered was correctly positioning and displaying the fetched data within the HTML structure. Replacing static elements with live API data proved to be quite tricky, as I had to ensure the content was dynamically updated while maintaining the integrity of the design.

## View it live

Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
https://nightcast.netlify.app
Binary file removed assets/design-1/Group16.png
Binary file not shown.
Binary file removed assets/design-1/Group34.png
Binary file not shown.
Binary file removed assets/design-1/Group36.png
Binary file not shown.
Binary file removed assets/design-1/Group37.png
Binary file not shown.
Binary file removed assets/design-1/Group38.png
Binary file not shown.
Binary file added assets/design-1/cloudy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/day-sky.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/day-weather-card.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/moon-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/night-sky.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/night-weather-card.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/rain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/search-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/storm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/sun-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/sunny.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-1/website-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 0 additions & 7 deletions assets/design-2/noun_Cloud_1188486.svg

This file was deleted.

23 changes: 0 additions & 23 deletions assets/design-2/noun_Sunglasses_2055147.svg

This file was deleted.

16 changes: 0 additions & 16 deletions assets/design-2/noun_Umbrella_2030530.svg

This file was deleted.

90 changes: 90 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather App</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link rel="icon" type="image/png" href="assets/design-1/website-icon.png"/>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="search-button">
<button id="search-btn">
<img src="assets/design-1/search-icon.png" alt="search icon">
</button>
<div class="search-bar-container">
<input type="text" id="search-bar" placeholder="Search location...">
</div>
</div>

<div class="toggle-container">
<input type="checkbox" id="theme-toggle" class="toggle-checkbox">
<label for="theme-toggle" class="toggle-label">
<div class="icon sun-icon"></div>
<div class="icon moon-icon"></div>
</label>
</div>

<div class="app">
<div class="weather-card">
<div class="location">
<h1>Dubai</h1>
</div>
<div class="current-temp">
<h2>16°C</h2>
</div>
<div class="details">
<p id="sunset-time"></p>
<p id="sunrise-time"></p>
<p id="weather-description"></p>
</div>
</div>

<div class="weekly-forecast">
<h3>Weekly Forecast</h3>
<div class="forecast-items">
<div class="forecast-item">
<div class="forecast-icon">
<img src="assets/design-1/cloudy.png" alt="cloudy">
</div>
<p>Monday</p>
<p>23°C</p>
</div>
<div class="forecast-item">
<div class="forecast-icon">
<img src="assets/design-1/sunny.png" alt="sunny">
</div>
<p>Tuesday</p>
<p>20°C</p>
</div>
<div class="forecast-item">
<div class="forecast-icon">
<img src="assets/design-1/cloudySun.png" alt="cloudy with sun">
</div>
<p>Wednesday</p>
<p>17°C</p>
</div>
<div class="forecast-item">
<div class="forecast-icon">
<img src="assets/design-1/storm.png" alt="storm">
</div>
<p>Thursday</p>
<p>16°C</p>
</div>
<div class="forecast-item">
<div class="forecast-icon">
<img src="assets/design-1/rain.png" alt="rainy">
</div>
<p>Friday</p>
<p>16°C</p>
</div>
</div>
</div>
</div>

<script src="script.js"></script>
</body>
</html>
144 changes: 144 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Wait for the DOM to fully load before selecting elements
document.addEventListener('DOMContentLoaded', () => {
// DOM Selectors
const toggle = document.getElementById('theme-toggle');
const weatherCard = document.querySelector('.weather-card');
const searchButton = document.getElementById('search-btn');
const searchBarContainer = document.querySelector('.search-bar-container');
const searchInput = document.getElementById('search-bar');
const location = document.querySelector(".location h1");
const currentTemp = document.querySelector(".current-temp h2");
const sunsetTime = document.getElementById("sunset-time");
const sunriseTime = document.getElementById("sunrise-time");
const weatherDescription = document.getElementById("weather-description");
const forecastItems = document.querySelectorAll(".forecast-item");

const apiKey = "6f10170466235746161a1b24e2d289bd";

// The toggle from night to day
toggle.addEventListener('change', () => {
if (toggle.checked) {
document.body.style.backgroundImage = "url('assets/design-1/day-sky.jpg')";
weatherCard.classList.add('day-mode');
} else {
document.body.style.backgroundImage = "url('assets/design-1/night-sky.jpg')";
weatherCard.classList.remove('day-mode');
}
});

// The search functionality
searchButton.addEventListener('click', () => {
searchBarContainer.classList.toggle('active');
if (searchBarContainer.classList.contains('active')) {
searchInput.focus();
}
});

// Function to fetch weather data for a given city
const fetchWeatherByCity = (city) => {
const apiURL = `https://api.openweathermap.org/data/2.5/forecast?q=${city}&appid=${apiKey}&units=metric`;

fetch(apiURL)
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then((data) => {
updateHtml(data); // Update the HTML with the fetched data
})
.catch((error) => {
console.error("Error fetching the weather data:", error);
alert('Unable to fetch data for the provided city. Please try another city.');
});
};

// Event listener for search input (trigger on 'Enter' key press)
searchInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
const city = event.target.value.trim();
if (city) {
fetchWeatherByCity(city); // Fetch weather for the searched city
} else {
alert('Please enter a valid city name');
}
}
});

// Initial fetch for default city (Dubai)
fetchWeatherByCity("Dubai");

// Function to format time for sunrise and sunset
const formatTime = (timestamp) => {
const date = new Date(timestamp * 1000); // Convert from seconds to milliseconds
return date.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
hour12: false
});
};

// Function to update the HTML with weather data
const updateHtml = (data) => {
// Update the location, temperature, and details in the weather card
location.textContent = data.city.name;
currentTemp.textContent = `${data.list[0].main.temp.toFixed(1)}°C`;

const sunset = formatTime(data.city.sunset);
const sunrise = formatTime(data.city.sunrise);

sunsetTime.textContent = `Sunset: ${sunset}`;
sunriseTime.textContent = `Sunrise: ${sunrise}`;

const weatherCondition = data.list[0].weather[0].main;
switch (weatherCondition) {
case "Clear":
weatherDescription.textContent = "A clear and sunny day ahead.";
break;
case "Clouds":
weatherDescription.textContent = "Clouds are covering the sky.";
break;
case "Rain":
weatherDescription.textContent = "Expect some rain showers.";
break;
case "Thunderstorm":
weatherDescription.textContent = "Thunderstorms expected, stay indoors!";
break;
}

updateWeeklyForecast(data.list);
};

// Function to update the weekly forecast
const updateWeeklyForecast = (forecastList) => {
const dailyForecast = forecastList.filter(forecast => {
const forecastDate = new Date(forecast.dt * 1000);
return forecastDate.getHours() === 12; // Picked 12:00 PM
}).slice(0, 5); // Get the first 5 days

dailyForecast.forEach((forecast, index) => {
const forecastTemp = forecast.main.temp.toFixed(1); // Round to 1 decimal place
const forecastWeather = forecast.weather[0].main;
const dayName = new Date(forecast.dt * 1000).toLocaleDateString("en-US", { weekday: "long" });

forecastItems[index].querySelector("p:nth-of-type(1)").textContent = dayName;
forecastItems[index].querySelector("p:nth-of-type(2)").textContent = `${forecastTemp}°C`;

const icon = forecastItems[index].querySelector("img");
switch (forecastWeather) {
case "Clear":
icon.src = "assets/design-1/sunny.png";
break;
case "Clouds":
icon.src = "assets/design-1/cloudy.png";
break;
case "Rain":
icon.src = "assets/design-1/rain.png";
break;
case "Thunderstorm":
icon.src = "assets/design-1/storm.png";
}
});
};
});
Loading