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

Weather App #415

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
Binary file added .DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}
34 changes: 28 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
# Weather App
This is a dynamic weather app built using JavaScript that allows users to search for the current weather and a 4-day weather forecast for any city. The app fetches weather data from the OpenWeatherMap API and displays the current temperature, weather description, sunrise and sunset times, as well as a 4-day forecast with daily minimum and maximum temperatures. The app also adjusts its theme to display a day or night background based on the current time at the selected location.

Replace this readme with your own information about your project.
# Features
Search Weather by City: Users can search for the weather by entering a city name.

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.
Current Weather: Displays the current temperature, weather conditions, sunrise and sunset times.

## The problem
4-Day Forecast: Shows a 4-day weather forecast, including minimum and maximum temperatures for each day.

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?
Day/Night Theme: Changes the background color depending on whether it’s day or night at the selected location.

## View it live
Responsive Design: The app is mobile-friendly and adapts to various screen sizes.

# Technical Details
Weather Data: The app uses the OpenWeatherMap API to fetch current weather and forecast data.

JavaScript: The app uses fetch for asynchronous HTTP requests and updates the DOM dynamically based on the fetched data.

HTML & CSS: The layout is built using HTML and CSS. The app's design changes dynamically based on the time of day (i.e., day/night background).

Event Listeners: Includes functionality for toggling a search window, submitting a city name, and handling API responses.

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.
# File Structure
index.html: The main HTML structure of the weather app, including input forms and layout for displaying weather information.

style.css: The stylesheet for the app, responsible for styling the layout, background colors, icons, and responsiveness.

script.js: The JavaScript file that handles all the functionality of the app, such as fetching data from the OpenWeatherMap API, updating the UI, and managing events (searching for cities, toggling the search window, etc.).

# Improvements
Currently, the weather forecast is based on two time entry points (12 AM and 12 PM) to retrieve the temperature data. To enhance the accuracy of the displayed forecast, it would be beneficial to fetch data at more frequent intervals, such as every 3 or 6 hours, to provide a more detailed and precise temperature trend throughout the day. This would give users a clearer and more reliable forecast.

## View it live
https://gittes-weather-app.netlify.app
Binary file added assets/.DS_Store
Binary file not shown.
61 changes: 61 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie-edge">
<link rel="stylesheet" href="style.css">
<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:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
rel="stylesheet">
</head>

<body id="body">
<header class="day-theme" id="header">
<div class="menu" id="hamburgerMenu">
<div class="hamburger-layer"></div>
<div class="hamburger-layer"></div>
<div class="hamburger-layer"></div>
</div>

<!-- Window to search for town -->
<div id="searchLocationWindow" class="search-location-window">
<div class="searchLocationContainer">
<span class="close-window-button" id="closeWindow">X</span>
<p>Find current weather and four-day forecast</p>
<input type="text" id="searchCity" class="search-city" placeholder="enter a city"></input>
<button class="search-button" id="searchLocationButton">Search</button>
</div>
</div>

<div class="weather-container">
<div class="temperature-container">
<div>
<h1 class="temperature" id="temp">
</h1>
</div>
<h2 id="cityName"></h2>
<h3 id="weather"></h3>
</div>
<div class="current-weather-image" id="currentWeatherImage">
</div>
</div>
<div class="sunrise-sunset">
<p>sunrise</p>
<p id="sunrise"></p>
<p>sunset</p>
<P id="sunset"></P>
</div>
</header>
<main>
<div class="weather-forecast-container" id="forecastContainer">
</div>
</main>
<script src="./script.js"></script>
</body>

</html>
176 changes: 176 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
const BASE_URL = "https://api.openweathermap.org/data/2.5/"
const API_KEY = "72e635da2875c352d9f726550253e2db"

const menu = document.getElementById('hamburgerMenu')
const searchWindow = document.getElementById('searchLocationWindow')
const closeWindow = document.getElementById('closeWindow')
const searchButton = document.getElementById('searchLocationButton')
const cityInput = document.getElementById('searchCity')
const temperature = document.getElementById('temp')
const weather = document.getElementById('weather')
const cityName = document.getElementById('cityName')
const sunrise = document.getElementById('sunrise')
const sunset = document.getElementById('sunset')
const iconCurrent = document.getElementById('currentWeatherImage')
const header = document.getElementById('header')

// function to create new URL for forecast based on the users input
const createForecastURL = (cityName) => {
return `${BASE_URL}forecast?q=${cityName}&units=metric&APPID=${API_KEY}`
}

// function to create new URL for current weather based on the users input
const createURL = (cityName) => {
return `${BASE_URL}weather?q=${cityName}&units=metric&APPID=${API_KEY}`
}

// function to convert Unix-time into hours:minutes
const convertUnixToTime = (unixTime, timeZone) => {
const time = unixTime * 1000
const date = new Date(time)
const localTime = new Date(date.getTime() + timeZone * 1000)
const hours = localTime.getUTCHours()
const minutes = "0" + localTime.getUTCMinutes()
return `${hours}:${minutes.substr(-2)}`
}

// to get the weather data for the current weather
const fetchWeatherData = async (cityName) => {
const URL = createURL(cityName)
try {
const response = await fetch(URL)
if (!response.ok) {
throw new Error('Failed to fetch weather data')
}
const data = await response.json()
updateHTML(data)
} catch (error) {
console.log(error)
}
}

// to get the forecast weather data
const fetchForecastData = async (cityName) => {
const URLForecast = createForecastURL(cityName)
try {
const response = await fetch(URLForecast)
if (!response.ok) {
throw new Error('Failed to fetch forecast weather data')
}
const dataForecast = await response.json()
console.log(dataForecast)
updateForecastHTML(dataForecast)
} catch (error) {
console.log(error)
}
}

// update HTML current weather
const updateHTML = (data) => {
cityName.innerText = data.name
weather.innerText = data.weather[0].description

// method to round the temperatures
const roundedTemp = Math.round(data.main.temp)
temperature.innerText = `${roundedTemp}°C`

// the local time for the specific city
const sunriseTime = convertUnixToTime(data.sys.sunrise, data.timezone)
const sunsetTime = convertUnixToTime(data.sys.sunset, data.timezone)

sunrise.innerText = sunriseTime
sunset.innerText = sunsetTime

const currentTime = Math.floor(Date.now() / 1000)

// Icon
const iconCode = data.weather[0].icon
const iconUrl = `http://openweathermap.org/img/wn/${iconCode}@2x.png`

iconCurrent.innerHTML = `<img class="icon-big" src="${iconUrl}" alt="Weather Icon">`

// Day/Night Background Update
const nightBackground = (currentTime, sunriseTime, sunsetTime) => {
header.style.background = (currentTime < sunriseTime || currentTime > sunsetTime)
? "linear-gradient(90deg, #323667 50%, #6B6EA8 50%)"
: ""
}
nightBackground(currentTime, data.sys.sunrise, data.sys.sunset)
}

// update HTML for forecast weather
// Array with weekdays
const weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']

// Function for HTML inputs
const updateForecastHTML = (dataForecast) => {
const forecasts = dataForecast.list

// filters the forecast for 12 AM (midnight) each day
const filteredMinForecasts = forecasts.filter(minForecast => {
const dateTime = new Date(minForecast.dt_txt)
return dateTime.getHours() === 0
})

// filters the forecast for 12AM each day
const filteredMaxForecasts = forecasts.filter(maxForecast => {
const dateTime = new Date(maxForecast.dt_txt)
return dateTime.getHours() === 12
})
let forecastHTML = ''

// Loops
for (let i = 0; i < 4; i++) {
const minTemp = Math.round(filteredMinForecasts[i].main.temp)
const maxTemp = Math.round(filteredMaxForecasts[i].main.temp)

// Get the icon for the forecast
const iconCode = filteredMinForecasts[i].weather[0].icon
const iconUrl = `http://openweathermap.org/img/wn/${iconCode}@2x.png`

// get weekdays
const dateTime = new Date(filteredMaxForecasts[i].dt_txt)
const dayOfWeek = weekdays[dateTime.getDay()]

forecastHTML += `
<div class="weather-day">
<p class="weekday">${dayOfWeek}</p>
<div class="forecast-image">
<img class="forecast-icon "src="${iconUrl}" alt="Weather Icon">
</div>
<p class="forecast-temperature">${minTemp}° / ${maxTemp}°C</p>
</div>
`
}
forecastContainer.innerHTML = forecastHTML
}

// Event Listener to open the search window
menu.addEventListener("click", () => {
searchWindow.style.display = "block"
cityInput.value = ""
})

// To close the search window users can either click on the X or somewhere else on the window
closeWindow.addEventListener("click", () => {
searchWindow.style.display = "none"
})
searchWindow.addEventListener("click", (event) => {
if (event.target == searchWindow) {
searchWindow.style.display = "none"
}
})

// Event-Listener to be able to search a cities
searchButton.addEventListener("click", () => {
// gets the name of the city from the input field
const city = cityInput.value
console.log(city)
if (city) {
fetchWeatherData(city)
fetchForecastData(city)
searchWindow.style.display = "none"
} else (
console.log("please enter a city name")
)
})
Loading