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 - Jenny A #431

Open
wants to merge 11 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.
10 changes: 2 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
# 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.

## 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 project was to build a simple weather dashboard that uses a weather API to tell today's weather and temperature and a 4-day forecast. A couple of different designers had a take on this project and it was a chance to practice to implement someone else's 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://whats-the-weather-jenny.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.
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.

Binary file added code/.DS_Store
Binary file not shown.
Binary file added code/assets/.DS_Store
Binary file not shown.
Binary file added code/assets/clear_sky_condition.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 code/assets/cloudy_condition.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 code/assets/default_condition.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 code/assets/misty_condition.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 code/assets/rainy_condition.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 code/assets/snowy_condition.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 code/assets/thunderstorm_condition.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 47 additions & 0 deletions code/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />

<title>Weather App</title>
<link rel="stylesheet" href="styles.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<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=Fredoka:[email protected]&family=Questrial&family=Urbanist:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
</head>
<body>
<div id="imageBackground" class="image-background">
<div id="weatherApp" class="weather-app">

<main class="current-weather">
<div class="temp-section">
<h1 id="temperature" class="temperature">??</h1>
<p id="celcius" class="celcius">°c</p>
</div>
<h2 id="location" class="location">??</h2>
<p id="time" class="time">??</p>
<div class="condition-container">
<div id="conditionIcon" class="condition-icon"></div>
<p id="condition" class="condition">??</p>
</div>

<div class="sun-times">
<p id="sunriseTime" class="sunrise-time">??</p>
<p id="sunsetTime" class="sunset-time">??</p>
</div>
</main>
</div>
</div>

<div id="forecast" class="forecast">


</div>



<script src="script.js"></script>
</body>
</html>
180 changes: 180 additions & 0 deletions code/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// Base URL
const BASE_URL = 'https://api.openweathermap.org/data/2.5/weather';

// API key
const API_KEY = '958c2b8d78ace5950d5c51dc2972950f';

// City and country for the weather forecast
let city = 'Stockholm';
let country = 'Sweden';
const units = 'metric'; // Use metric units (Celsius)

// Construct the URL for current weather data
const url = `${BASE_URL}?q=${city},${country}&units=${units}&APPID=${API_KEY}`;

// Construct the URL for forecast data
const FORECAST_URL = `https://api.openweathermap.org/data/2.5/forecast?q=${city},${country}&units=${units}&APPID=${API_KEY}`;

// DOMs
const temperatureElement = document.getElementById("temperature");
const locationElement = document.getElementById("location");
const conditionElement = document.getElementById("condition");
const conditionIconElement = document.getElementById("conditionIcon");
const sunriseElement = document.getElementById("sunriseTime");
const sunsetElement = document.getElementById("sunsetTime");
const timeElement = document.getElementById("time");
const forecastElement = document.getElementById("forecast");


// Function to fetch and display current weather data
const getWeatherData = () => {
fetch(url)
.then(response => response.json())
.then(json => {
// Get data from the API response
const temperature = Math.round(json.main.temp);
const location = json.name;
const condition = json.weather[0].description;
const iconCode = json.weather[0].icon;
const sunriseTime = new Date(json.sys.sunrise * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
const sunsetTime = new Date(json.sys.sunset * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });

// Get the current local time
const localTime = new Date();
const formattedTime = localTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });

// Update the HTML elements with the weather data
temperatureElement.textContent = `${temperature}`;
locationElement.textContent = `${location}`;
conditionElement.textContent = `${condition}`;
conditionIconElement.src = `http://openweathermap.org/img/wn/${iconCode}.png`;
conditionIconElement.alt = condition;
sunriseElement.textContent = `Sunrise: ${sunriseTime}`;
sunsetElement.textContent = `Sunset: ${sunsetTime}`;
timeElement.textContent = `Time: ${formattedTime}`;

// Set the background based on the weather condition
setWeatherBackground(json.weather[0].main);

});
}

// Function to set the background image based on weather condition
const setWeatherBackground = (weatherCondition) => {
const imageBackground = document.getElementById('imageBackground');

switch(weatherCondition.toLowerCase()) {
case 'clear':
imageBackground.style.backgroundImage = "url('assets/clear_sky_condition.jpg')";
break;
case 'clouds':
imageBackground.style.backgroundImage = "url('assets/cloudy_condition.jpg')";
break;
case 'rain':
case 'drizzle':
imageBackground.style.backgroundImage = "url('assets/rainy_condition.jpg')";
break;
case 'thunderstorm':
imageBackground.style.backgroundImage = "url('assets/thunderstorm_condition.jpg')";
break;
case 'snow':
imageBackground.style.backgroundImage = "url('assets/snowy_condition.jpg')";
break;
case 'mist':
case 'smoke':
case 'haze':
case 'fog':
imageBackground.style.backgroundImage = "url('assets/misty_condition.jpg')";
break;
default:
imageBackground.style.backgroundImage = "url('assets/default_condition.jpg')";
}
};


// Function to fetch and display forecast data
const getForecastData = () => {
fetch(FORECAST_URL)
.then(response => response.json())
.then(json => {
// Process the forecast data
let forecastData = processForecastData(json.list);
// If we don't have 5 days of forecast, fill in with additional data
if (forecastData.length < 5) {
forecastData = fillForecastData(forecastData, json.list);
}
// Display the processed forecast data
displayForecast(forecastData);
});
};

// Function to process the raw forecast data
const processForecastData = (list) => {
const today = new Date().getDate();

return list
// Transform each item into an object with the data we need
.map(item => ({
date: new Date(item.dt * 1000),
icon: item.weather[0].icon,
temp: Math.round(item.main.temp)
}))
// Filter out today's weather and nighttime forecasts
.filter(item => {
const hour = item.date.getHours();
return item.date.getDate() !== today && hour >= 6 && hour <= 18;
})
// Reduce to max 5 items, one per day
.reduce((acc, item) => {
if (acc.length < 5 && (acc.length === 0 || item.date.getDate() !== acc[acc.length - 1].date.getDate())) {
acc.push(item);
}
return acc;
}, []);
};
Comment on lines +112 to +134
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good way to use these methods. It is a bit advanced to do all this in one go like you are doing. I believe youi might have gotten help with structuring this code, which is totally fine. However it is superimportant that you really understand the code. So good that you have added comments to it, but also try to find the opportunity to actually explain this code to someone. Either in your team, in a short screen recording to the class, to a friend or family member (even though they might not understand coding) This will help you befästa kunskapen and also prepare you for upcoming technical interviews and demos "in real world"


// Function to fill in missing forecast days if there isn't 5
const fillForecastData = (forecast, list) => {
const today = new Date().getDate();
let i = 0;

while (forecast.length < 5 && i < list.length) {
const date = new Date(list[i].dt * 1000);
if (date.getDate() !== today && (forecast.length === 0 || date.getDate() !== forecast[forecast.length - 1].date.getDate())) {
forecast.push({
date: date,
icon: list[i].weather[0].icon,
temp: Math.round(list[i].main.temp)
});
}
i++;
}

return forecast;
};

// Function to display the forecast data in the HTML
const displayForecast = (forecastData) => {
// Clear any existing forecast
forecastElement.innerHTML = '';
const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

// Create and append a forecast item for each day
forecastData.forEach(day => {
const dayName = daysOfWeek[day.date.getDay()];
const forecastItem = document.createElement('div');
forecastItem.classList.add('forecast-item');
forecastItem.innerHTML = `
<div class="forecast-section">
<span class="forecast-day">${dayName}</span>
<img src="http://openweathermap.org/img/wn/${day.icon}.png" alt="Weather icon">
<span class="forecast-temp">${day.temp}°C</span>
</div>
`;
forecastElement.appendChild(forecastItem);
});
};

// Call both functions to initialize the weather app
getWeatherData();
getForecastData();
Loading