-
Notifications
You must be signed in to change notification settings - Fork 577
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
Emelie Nyberg Kedert #413
Open
EmelieNyberg
wants to merge
4
commits into
Technigo:master
Choose a base branch
from
EmelieNyberg:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Emelie Nyberg Kedert #413
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,26 @@ | ||
# Weather App | ||
|
||
Replace this readme with your own information about your project. | ||
|
||
Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. | ||
This project is a weather application that fetches and displays weather data from the OpenWeatherMap API. The main features include displaying the current weather conditions, temperature, and a four-day forecast, as well as providing sunrise and sunset times. The assignment required following a specific design and using JavaScript to retrieve and present the data dynamically. | ||
|
||
## 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 task was to build a weather app using the OpenWeatherMap API, focusing on presenting real-time weather data such as temperature, weather description, sunrise and sunset times, and a 4-day forecast. The main challenges were to fetch the data using JavaScript's `fetch()` function, dynamically inject it into the DOM, and style the app to fit the provided design. | ||
|
||
#### Approach | ||
I started by planning how to structure the application and which data points to display from the API. The first step was to set up the API connection using the provided API key and to fetch the weather data in JSON format. I used the `fetch()` method to get the data and implemented error handling with `.catch()` to handle any issues during the fetch request. | ||
|
||
To display the weather information, I extracted key elements from the API's JSON response, such as the city name, current temperature, weather description, and sunrise/sunset times. I used JavaScript to inject this information into the HTML elements. I also formatted the sunrise and sunset times into a more readable format using JavaScript's Date object. | ||
|
||
For the 4-day weather forecast, I filtered the API data to retrieve information for the same time (12:00) each day. This provided a consistent forecast and avoided overcrowding the display with too many data points. | ||
|
||
#### Tools and Techniques | ||
- **JavaScript:** Used `fetch()` to call the OpenWeatherMap API and manipulate the DOM to display the weather data. | ||
- **CSS:** Styled the app to match the provided design. I also added responsiveness to ensure it looks good on devices ranging from 320px to 1600px in width. | ||
- **HTML:** Used semantic elements and classes to structure the content and facilitate dynamic updates with JavaScript. | ||
|
||
#### Additional Thoughts | ||
If I had more time, I would have refactored the code to break out the HTML updates from the `fetch()` function into a separate function. This would have improved the code's readability and maintainability. Additionally, I would have liked to create my own design for the app to make it more personalized, as I use weather apps like SMHI frequently. Implementing more stretch goals, such as a city selection feature or dynamically changing the page's colors based on the weather conditions, would have been interesting to explore as well. | ||
|
||
## 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://weatherapp-ek.netlify.app/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<!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="stylesheet" href="style.css"> | ||
<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,300;1,100&display=swap" rel="stylesheet"> | ||
</head> | ||
|
||
<body> | ||
<div class="weather" id="weather"> | ||
<div class="weather-container" id="weatherContainer"> | ||
<div class="view-current-weather-icon" id="viewCurrentWeatherIcon"></div> | ||
|
||
<div class="view-current-temp" id="viewCurrentTemp"></div> | ||
|
||
<div class="view-current-city" id="viewCurrentCity"></div> | ||
|
||
<div class="view-current-weather-text" id="viewCurrentWeatherText"></div> | ||
|
||
<div class="view-sunrise-sunset" id="viewSunriseSunset"></div> | ||
</div> | ||
</div> | ||
|
||
<div class="forecast-container" id="forecastContainer"></div> | ||
|
||
<script src="script.js"></script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
## Netlify link | ||
Add your Netlify link here. | ||
PS. Don't forget to add it in your readme as well. | ||
|
||
https://weatherapp-ek.netlify.app/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
// DOM selectors | ||
const weather = document.getElementById('weather'); | ||
const viewCurrentWeatherIcon = document.getElementById('viewCurrentWeatherIcon'); | ||
const viewCurrentTemp = document.getElementById('viewCurrentTemp'); | ||
const viewCurrentCity = document.getElementById('viewCurrentCity'); | ||
const viewCurrentWeatherText = document.getElementById('viewCurrentWeatherText'); | ||
const viewSunriseSunset = document.getElementById('viewSunriseSunset'); | ||
const forecastContainer = document.getElementById('forecastContainer'); | ||
|
||
// API | ||
const API_KEY = '7438f6ff1587b542eeec76b91380b575'; | ||
const city = 'Stockholm'; | ||
const URL_WEATHER = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&APPID=${API_KEY}`; | ||
const URL_FORECAST = `https://api.openweathermap.org/data/2.5/forecast?q=${city}&units=metric&APPID=${API_KEY}`; | ||
|
||
const getTodaysWeather = () => { | ||
fetch(URL_WEATHER) | ||
// Reurn API-answere in JSON-format | ||
.then(response => response.json()) | ||
|
||
.then(data => { | ||
// Get API data | ||
const currentWeatherIcon = data.weather[0].icon; | ||
// Commented out this code, just to show how it looks if temperature is rounded to 1 decimal | ||
//const currentTemp = data.main.temp.toFixed(1); | ||
const currentTemp = Math.round(data.main.temp); | ||
const currentCity = data.name; | ||
const currentWeatherText = data.weather[0].description; | ||
|
||
// Convert the Unix timestamp returned by the OpenWeatherMap API to a readable date and time format | ||
const sunriseTime = new Date(data.sys.sunrise * 1000); | ||
const sunsetTime = new Date(data.sys.sunset * 1000); | ||
|
||
// To calculate sunset/sunrise | ||
const currentTime = new Date(); | ||
|
||
// Convert time to 00:00 format | ||
const sunriseTimeFormatted = sunriseTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); | ||
const sunsetTimeFormatted = sunsetTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); | ||
|
||
// When background for night/day should me shown | ||
if (currentTime >= sunriseTime && currentTime < sunsetTime) { | ||
weather.classList.add('daytime'); | ||
} else { | ||
weather.classList.add('nighttime'); | ||
} | ||
|
||
// Update HTML | ||
viewCurrentWeatherIcon.innerHTML = ` | ||
<img src="https://openweathermap.org/img/wn/${currentWeatherIcon}@2x.png" alt="Weather icon"> | ||
`; | ||
viewCurrentTemp.innerHTML = ` | ||
<h1>${currentTemp}</h1><h2>°C</h2> | ||
`; | ||
viewCurrentCity.innerHTML = ` | ||
<h3>${currentCity}</h3> | ||
`; | ||
viewCurrentWeatherText.innerHTML = ` | ||
<h4>${currentWeatherText}</h4> | ||
`; | ||
viewSunriseSunset.innerHTML = ` | ||
<h4>sunrise</h4> | ||
<h4>${sunriseTimeFormatted}</h4> | ||
<h4>sunset</h4> | ||
<h4>${sunsetTimeFormatted}</h4> | ||
`; | ||
}) | ||
|
||
// Catch logs and errors | ||
.catch((error) => { | ||
console.log('Error:', error); | ||
}); | ||
} | ||
|
||
// Call the function to get and show todays weather | ||
getTodaysWeather(); | ||
|
||
const getWeatherForecast = () => { | ||
fetch(URL_FORECAST) | ||
.then(response => response.json()) | ||
|
||
.then(data => { | ||
// Get unique days in the forecast (filtering by date without time)" | ||
const days = {}; | ||
data.list.forEach(item => { | ||
const date = item.dt_txt.split(' ')[0]; // Get only date | ||
if (!days[date]) { | ||
days[date] = []; // Create array for each date | ||
} | ||
days[date].push(item); // Add all weather entries for each date | ||
}); | ||
|
||
// Skip first day (index 0) | ||
const filteredDays = Object.keys(days).slice(1, 6); | ||
|
||
// Loop through filtred days and show the data | ||
filteredDays.forEach(date => { | ||
const dayForecast = days[date]; | ||
|
||
// Find highest and lowest temperature for each day | ||
const temps = dayForecast.map(item => Math.round(item.main.temp)); | ||
const maxTemp = Math.max(...temps); | ||
const minTemp = Math.min(...temps); | ||
|
||
// Get weahter icon at 12:00 for the specific day | ||
const middayForecast = dayForecast.find(item => item.dt_txt.includes('12:00:00')); | ||
const weatherIcon = middayForecast ? middayForecast.weather[0].icon : dayForecast[0].weather[0].icon; | ||
|
||
// Get the weekday (three letters) | ||
const dayOfWeek = new Date(date).toLocaleDateString('en-GB', { weekday: 'short' }); | ||
|
||
// Build HTML for every days forecast | ||
forecastContainer.innerHTML += ` | ||
<div class="forecast"> | ||
<p>${dayOfWeek}</p> | ||
<div class="forecast-icon-temp"> | ||
<img src="http://openweathermap.org/img/wn/${weatherIcon}.png" alt="Weather icon"> | ||
<p>${minTemp}° / ${maxTemp}°C</p> | ||
</div> | ||
</div> | ||
`; | ||
}); | ||
}) | ||
|
||
// Catch logs and errors | ||
.catch(error => { | ||
console.error('Error:', error); | ||
}); | ||
} | ||
|
||
// Call the function to get and show weather forecast | ||
getWeatherForecast(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
body { | ||
background-color: white; | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 300; | ||
font-style: normal; | ||
margin: 0; | ||
} | ||
|
||
h1 { | ||
font-size: 120px; | ||
margin: 0; | ||
} | ||
|
||
h2 { | ||
font-size: 40px; | ||
font-weight: 400; | ||
margin-top: 15px; | ||
} | ||
|
||
h3 { | ||
font-size: 34px; | ||
margin: 0; | ||
} | ||
|
||
h4 { | ||
font-size: 22px; | ||
margin: 0; | ||
} | ||
|
||
p { | ||
color: #707070; | ||
font-size: 20px; | ||
font-weight: 400; | ||
} | ||
|
||
.weather-container { | ||
color: white; | ||
margin: 0 30px; | ||
position: relative; | ||
} | ||
|
||
/* Day background styling (lightblue) */ | ||
.daytime { | ||
background: linear-gradient(to bottom right, #8589FF, #E8E9FF); | ||
clip-path: ellipse(130% 100% at 50% 0%); | ||
} | ||
|
||
/* Night background styling (darkblue) */ | ||
.nighttime { | ||
background: linear-gradient(to bottom right, #6264A2, #222350); | ||
clip-path: ellipse(130% 100% at 50% 0%); | ||
} | ||
|
||
/* Position of big weather icon */ | ||
.view-current-weather-icon { | ||
position: absolute; | ||
right: 70px; | ||
} | ||
|
||
/* Icon size */ | ||
.view-current-weather-icon img { | ||
width: 200%; | ||
} | ||
|
||
.view-current-temp { | ||
padding-top: 131px; | ||
display: flex; | ||
flex-direction: row; | ||
} | ||
|
||
/* View weather text with capitals */ | ||
.view-current-weather-text { | ||
text-transform: capitalize; | ||
} | ||
|
||
.view-sunrise-sunset { | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: space-between; | ||
padding: 10% 0 15% 0; | ||
} | ||
|
||
.forecast-container { | ||
margin: 0 30px; | ||
margin-top: 20%; | ||
margin-bottom: 10%; | ||
} | ||
|
||
.forecast { | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: space-between; | ||
} | ||
|
||
/* Styling for icon and temperature to be to the right */ | ||
.forecast-icon-temp { | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: space-between; | ||
width: 50%; | ||
} | ||
|
||
/* Make icon not streach */ | ||
.forecast-icon-temp img { | ||
object-fit: contain; | ||
} | ||
|
||
/* For tablets */ | ||
@media (min-width: 668px) and (max-width: 1024px) { | ||
|
||
.weather-container { | ||
margin: 0 100px; | ||
} | ||
|
||
.view-current-weather-icon { | ||
right: 100px; | ||
} | ||
|
||
.view-current-weather-icon img { | ||
width: 300%; | ||
|
||
} | ||
|
||
.forecast-container { | ||
margin: 100px 100px; | ||
} | ||
|
||
.forecast { | ||
margin: 3% 0; | ||
} | ||
} | ||
|
||
/* For screens */ | ||
@media (min-width: 1025px) { | ||
|
||
body { | ||
display: flex; | ||
justify-content: space-between; | ||
} | ||
|
||
.weather-container { | ||
margin: 0 100px; | ||
} | ||
|
||
.daytime, | ||
.nighttime { | ||
width: 50%; | ||
clip-path: none; | ||
height: 100vh; | ||
} | ||
|
||
.forecast-container { | ||
width: 50%; | ||
margin: 131px 100px; | ||
} | ||
|
||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍