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

Annas Weather App #418

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
752bb61
added HTML, CSS and API key + URL to JS
Anna2024WebDev Sep 26, 2024
77dea67
fetch and converted sunset/sunrise time and updated CSS
Anna2024WebDev Sep 26, 2024
d26b6f1
added function with if/else statements to change background color
Anna2024WebDev Sep 26, 2024
13730e4
added function to change color of background and fonts depending on w…
Anna2024WebDev Sep 27, 2024
87fb4f4
fetched forecast data and created a loop for the first 5 days weather…
Anna2024WebDev Sep 28, 2024
a104759
added search bar and added event listeners to search on click also ch…
Anna2024WebDev Sep 29, 2024
16a0a79
added more weather pictures and changed some texts in JS
Anna2024WebDev Sep 29, 2024
960089a
small adjustments
Anna2024WebDev Sep 29, 2024
fb67fca
small fix
Anna2024WebDev Sep 29, 2024
245d0f1
updated title and readme file
Anna2024WebDev Sep 29, 2024
a2089a5
updated color button in JS
Anna2024WebDev Sep 29, 2024
40a91b8
small fix button font
Anna2024WebDev Sep 29, 2024
9ccfec6
Update README.md
Anna2024WebDev Sep 29, 2024
7998b89
css fix
Anna2024WebDev Sep 30, 2024
6cef388
Merge branch 'master' of https://github.com/Anna2024WebDev/project-we…
Anna2024WebDev Sep 30, 2024
39c4131
fixed sunset/sunrise timezone offset
Anna2024WebDev Sep 30, 2024
7eb361b
added min/max temp
Anna2024WebDev Sep 30, 2024
03877ea
updated HTML and JS indentation, added new date object to be able to …
Anna2024WebDev Oct 3, 2024
2e24140
added function to capitalize letters in cities when fetching data
Anna2024WebDev Oct 4, 2024
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
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": 5502
}
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# 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 week the project was to create a weather app by using APIs and using different methods to retrieve and convert the data, such as fetch and convert unix time.

## 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?
I started with adding the HTML and CSS code. Then I moved on to JS where I added the API and console.logged it. Then I moved on to adding the DOM selectors and created the first function to fetch the current weather data and sunset/sunrise time. After this was achived I moved on to converting the sunset/sunrise time. I needed help from chatGPT to achieve this and also how to get the forecast data which was not as straight forward as the current weather data.

Then I also managed to change the background color, color (fonts) and images depending on weather description, for this I used if/if else statements.

If I had more time I would also look into the geolocation API.

## 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://checkthe-weather.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-2/moonlight.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions assets/design-2/sad-face-3.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/design-2/scattered.svg
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-2/snow.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-2/sunset.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-2/thunderstorm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather or Not</title>
<link rel="stylesheet" type="text/css" 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=Montserrat:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet">
<title>Check the Weather</title>
</head>

<body>
<main><!-- Temperature and Condition Info -->
<section class="weather-container" id="weatherContainer">
<div class="temperature-info">
<p id="condition"></p>
<p>|</p>
<p id="temperature"></p>
</div>
<!-- Sunset and Sunrise Info -->
<div class="sun-times">
<p>sunrise <span id="sunriseTime"></span></p>
<p>sunset <span id="sunsetTime"></span></p>
</div>
<img id="weatherImage" class="weather-img" src="" alt="Weather Image">
<p id="weatherMessage" class="weather-message"></p> <!-- Placeholder for dynamic weather message -->
<section class="forecast-wrapper" id="forecastWrapper">
<ul id="forecastList"></ul> <!-- List items will be dynamically added here -->
<div id="searchContainer">
<!-- <label for="cityInput">City:</label> -->
<input type="text" id="cityInput" placeholder="Type a city..">
<button id="searchButton">Search</button>
</div>
</section>
</main>
<script src="./script.js"></script>

<body>

</html>
2 changes: 1 addition & 1 deletion instructions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Instructions
Start out with signing up for a [free Open Weather Map](https://home.openweathermap.org/users/sign_up "free Open Weather Map") account, as it can take up to a few hours for the API key to be activated.
Start out with signing up for a [free Open Weather Map]( "free Open Weather Map") account, as it can take up to a few hours for the API key to be activated.

## Step by step instructions
### Step 1 - Get started with the weather API
Expand Down
215 changes: 215 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// True constants (SNAKECASE)
const API_KEY = "ea9a90c62aeaaa3811505087d195520e"
const BASE_URL = "https://api.openweathermap.org/data/2.5/weather?q="
const FORECAST_BASE_URL = "https://api.openweathermap.org/data/2.5/forecast?q="

let city = "Stockholm" // Dynamic city variable

// DOM Selectors
const temperatureDisplay = document.getElementById("temperature")
const conditionDisplay = document.getElementById("condition")
const sunriseDisplay = document.getElementById("sunriseTime")
const sunsetDisplay = document.getElementById("sunsetTime")
const weatherImg = document.getElementById("weatherImage")
const weatherMsg = document.getElementById("weatherMessage")
const forecastList = document.getElementById("forecastList")
const searchButton = document.getElementById("searchButton")
const cityInput = document.getElementById("cityInput")

// Function to fetch weather data
const fetchWeatherData = () => {
const URL = `${BASE_URL}${city}&units=metric&APPID=${API_KEY}`
const FORECAST_URL = `${FORECAST_BASE_URL}${city}&units=metric&APPID=${API_KEY}`

// Fetch current weather data
fetch(URL)
.then(response => response.json())
.then(data => {
if (!data || data.cod !== 200) {
throw new Error("City not found")
}
const stockholmTemp = data.main.temp
const weatherCondition = data.weather[0].description
const roundedTemp = Math.round(stockholmTemp)
const sunrise = data.sys.sunrise
const sunset = data.sys.sunset
const timezoneOffset = data.timezone // Timezone offset in seconds

temperatureDisplay.innerText = `${roundedTemp}°C`
conditionDisplay.innerText = `${weatherCondition}`

// Convert and display sunrise and sunset times with timezone offset
const sunriseTime = convertUnixToTime(sunrise, timezoneOffset)
const sunsetTime = convertUnixToTime(sunset, timezoneOffset)
sunriseDisplay.innerText = `${sunriseTime}`
sunsetDisplay.innerText = `${sunsetTime}`

updateUI(roundedTemp, weatherCondition, sunset)
})
.catch(error => {
console.error("Error fetching weather data:", error)
})

// Fetch 5-day forecast data
fetch(FORECAST_URL)
.then(response => response.json())
.then(forecastData => {
forecastList.innerHTML = ""
const today = new Date()

// Loop through the next 5 days
for (let i = 1; i <= 5; i++) {
const forecastDate = new Date(today)
forecastDate.setDate(today.getDate() + i)
const forecastDateString = forecastDate.toISOString().split("T")[0]

// Filter forecasts for this specific date
const dailyForecasts = forecastData.list.filter(item => {
const itemDate = new Date(item.dt * 1000).toISOString().split("T")[0]
return itemDate === forecastDateString
})

if (dailyForecasts.length > 0) {
// Initialize min and max temperature variables
let minTemp = Infinity
let maxTemp = -Infinity

// Calculate min and max temperatures for the day
dailyForecasts.forEach(item => {
const temp = Math.round(item.main.temp)
if (temp < minTemp) {
minTemp = temp
}
if (temp > maxTemp) {
maxTemp = temp
}
})

const weekDay = forecastDate.toLocaleDateString("en-US", {
weekday: "long",
})
const listItem = document.createElement("li")
listItem.innerHTML = `${weekDay} <span class="min-temp">${minTemp} / <span class="max-temp">${maxTemp}°C</span>`
forecastList.appendChild(listItem)
}
}
})
.catch(error => {
console.error("Error fetching forecast data:", error)
})
}

// Function to convert UNIX timestamp to readable time format (24-hour clock)
const convertUnixToTime = (unixTimestamp, timezoneOffset) => {
const date = new Date((unixTimestamp + timezoneOffset) * 1000)
const hours = date.getUTCHours()
const minutes = String(date.getUTCMinutes()).padStart(2, "0")
return `${hours}:${minutes}`
}

// Initial fetch for the default city
fetchWeatherData()

// Event listener for the search button
searchButton.addEventListener("click", () => {
city = cityInput.value.trim() // Update city variable with input value
if (city) {
city = capitalizeCityName(city) // Capitalize the first letter of each word
fetchWeatherData() // Fetch new weather data for the entered city
}
})

// Event listener for the Enter key in the input field
cityInput.addEventListener("keypress", (event) => {
if (event.key === "Enter") {
// Check if the pressed key is Enter
city = cityInput.value.trim()
if (city) {
city = capitalizeCityName(city) // Capitalize the first letter of each word
searchButton.click() // Trigger the click event of the search button
searchButton.click() // Trigger the click event of the search button
}
}
})

// Arrow function to capitalize the first letter of each word in the city name
const capitalizeCityName = (city) => {
return city
.split(" ") // Split the city name into an array of words
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize the first letter of each word
.join(" ") // Join the words back into a single string
}

const updateUI = (temperature, weatherDescription, sunsetTime) => {
const weatherContainer = document.getElementById("weatherContainer")
const searchButton = document.getElementById("searchButton")
const currentTime = new Date() // Get the current time
const sunset = new Date(sunsetTime * 1000) // Convert sunset time to Date object
let weatherMessage // Variable to store the weather message

// Check if it's after sunset
if (currentTime > sunset) {
// Night styling
weatherContainer.style.backgroundColor = "#001f3f" // Dark blue for night
weatherContainer.style.color = "#ffffff" // White text
searchButton.style.backgroundColor = "#164A68" // Light blue button color
weatherImg.src = "assets/design-2/moonlight.png" // Moon image for night
weatherMessage = `It's ${weatherDescription} in ${city}. Enjoy the evening and have a good night!`

} else {
// Update background and text color based on weather condition
if (
weatherDescription.toLowerCase().includes("rain") ||
weatherDescription.toLowerCase().includes("drizzle") ||
weatherDescription.toLowerCase().includes("mist")
) {
weatherContainer.style.backgroundColor = "#BDE8FA" // Blue for rain
weatherContainer.style.color = "#164A68" // Rainy font color
searchButton.style.backgroundColor = "#164A68"
weatherImg.src = "assets/design-2/noun_Umbrella.svg"
weatherMessage = `Don’t forget your umbrella.<br>It’s wet in ${city} today.`

} else if (weatherDescription.toLowerCase().includes("few clouds")) {
weatherContainer.style.backgroundColor = "#F7E9B9" // Yellow for few clouds
weatherContainer.style.color = "#2A5510" // Green font color
searchButton.style.backgroundColor = "#2A5510"
weatherImg.src = "assets/design-2/noun_Sunglasses.svg"
weatherMessage = `Get your sunnies on. There are a few clouds, but it's still a lovely day in ${city}.`

} else if (weatherDescription.toLowerCase().includes("scattered clouds")) {
weatherContainer.style.backgroundColor = "#F7E9B9" // Yellow for scattered clouds
weatherContainer.style.color = "#2A5510" // Green font color
searchButton.style.backgroundColor = "#2A5510"
weatherImg.src = "assets/design-2/noun_cloud.svg"
weatherMessage = `There are some scattered clouds, but it's still a lovely day in ${city}.`

} else if (weatherDescription.toLowerCase().includes("clear")) {
weatherContainer.style.backgroundColor = "#F7E9B9" // Yellow for clear sky
weatherContainer.style.color = "#2A5510" // Green font color
searchButton.style.backgroundColor = "#2A5510"
weatherImg.src = "assets/design-2/noun_Sunglasses.svg"
weatherMessage = `Get your sunnies on.<br>${city} is looking rather great today.`

} else if (
weatherDescription.toLowerCase().includes("clouds") ||
weatherDescription.toLowerCase().includes("fog") ||
weatherDescription.toLowerCase().includes("haze")
) {
weatherContainer.style.backgroundColor = "#FFFFFF" // White for cloudy
weatherContainer.style.color = "#F47775" // Orange font color
searchButton.style.backgroundColor = "#F47775"
weatherImg.src = "assets/design-2/noun_Cloud.svg"
weatherMessage = `Light a fire and get cosy.<br>${city} is looking grey today.`

} else if (weatherDescription.toLowerCase().includes("snow")) {
weatherContainer.style.backgroundColor = "#BDE8FA" // Blue for snow
weatherContainer.style.color = "#164A68" // Blue font color
searchButton.style.backgroundColor = "#164A68"
weatherImg.src = "assets/design-2/snowflake.png"
weatherMessage = `Wrap up warm! It's snowy in ${city}.`
}
}

// Update the DOM elements with weather message and image
weatherMsg.innerHTML = weatherMessage
}
Loading