Skip to content

Weather App. Team: Darius, Therese, Tavan, Kasia, Jasmin #11

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

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
83f85cd
html structure
Mar 18, 2025
cbe403f
ignore typechecking
Mar 18, 2025
a6ccbb1
fetch + function
Mar 18, 2025
a30f6d4
adjusted fetch function weather + localstorage
Mar 19, 2025
fe6ffea
updated localstorage
Mar 19, 2025
c7ee945
added styling to HTML
Mar 19, 2025
de82ce0
added searchabr, display weather, storage
Mar 19, 2025
5503506
adding missing html and styling
Mar 19, 2025
f76de5d
added images to assets
Mar 19, 2025
9d675a4
Merge branch 'main' of https://github.com/JasminHed/newjs-project-wea…
Mar 19, 2025
8352def
added html and css
Mar 19, 2025
7440a9c
removed extra side button
Mar 19, 2025
587c168
updated error bracket
Mar 19, 2025
1060ae5
commented out forecast function
Mar 19, 2025
baf6a38
removed comments and old code
Mar 19, 2025
ab46f76
updated js
Mar 20, 2025
0153fbe
new html
Mar 20, 2025
d2cde95
new css
Mar 20, 2025
3b593fe
tweaked js
Mar 20, 2025
e8e88c8
removed the new script file
Mar 20, 2025
dac19ae
created TS
Mar 20, 2025
c5b04e4
updated ts file
Mar 20, 2025
5a1e3a7
compiled ts+js and added slidebutton
Mar 21, 2025
fde6dc8
added eventlistener to enter key
Mar 22, 2025
16b9e8c
removed old ts code
Mar 22, 2025
b13c6c4
updated all functions to same
Mar 24, 2025
435a337
added functions for getting api icons in weather + forecast, changed css
Mar 24, 2025
b465cc5
removed old code and comments
Mar 24, 2025
dc21e55
Update README.md
JasminHed Apr 8, 2025
0f95aef
screen reader labeling + focus for tabbing
Apr 9, 2025
b6b659f
Merge branch 'main' of https://github.com/JasminHed/newjs-project-wea…
Apr 9, 2025
9e4e688
removed redundant focus input+button
Apr 9, 2025
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.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# js-project-weather-app
# js-project-weather-app

nordicweatherapp.netlify.app
Binary file added assets/Brokenclouds.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/Cloudy.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/Fewclouds.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/Group 13.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/Group 15.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/Group 16.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/Night.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/Subtraction 2.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/Sunny.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/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/Sunrise.jpg.avif
Binary file not shown.
Binary file added assets/Sunset.jpg.avif
Binary file not shown.
Binary file added assets/searchglass.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/sun.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
190 changes: 190 additions & 0 deletions dist/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
"use strict";
// @ts-nocheck
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
document.addEventListener('DOMContentLoaded', function () {
// API information
const API_KEY = '3bad52890d7306cc268371520cbaace6';
const BASE_URL = 'https://api.openweathermap.org/data/2.5/forecast';
// List of default cities
const cities = ['Stockholm', 'Gothenburg', 'Oslo'];
let weeklyForecast = {};
let currentCityIndex = 0;
function fetchWeather(city) {
return __awaiter(this, void 0, void 0, function* () {
try {
const response = yield fetch(`${BASE_URL}?q=${city}&units=metric&appid=${API_KEY}`);
const data = yield response.json();
if (data.cod !== "200") {
throw new Error(data.message || "Failed to fetch weather data.");
}
return data;
}
catch (error) {
console.error(`Error fetching weather data for ${city}:`, error);
return null;
}
});
}
function getDayName(dateString) {
const date = new Date(dateString);
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
return days[date.getDay()];
}
function fetchAndStoreWeather(city) {
return __awaiter(this, void 0, void 0, function* () {
const data = yield fetchWeather(city);
if (!data || !data.list) {
return;
}
const todayData = data.list.find(entry => entry.dt_txt.includes("12:00:00")) || data.list[0];
const todayDate = todayData.dt_txt.split(" ")[0];
const sunriseTime = new Date(data.city.sunrise * 1000).toLocaleTimeString("sv-SE", { hour: "2-digit", minute: "2-digit" });
const sunsetTime = new Date(data.city.sunset * 1000).toLocaleTimeString("sv-SE", { hour: "2-digit", minute: "2-digit" });
const todayForecast = {
city: data.city.name,
day: getDayName(todayDate),
weather: todayData.weather[0].description,
icon: todayData.weather[0].icon,
temp: todayData.main.temp,
wind: todayData.wind.speed,
sunrise: sunriseTime,
sunset: sunsetTime,
};
const dailyForecasts = {};
data.list.forEach(entry => {
const date = entry.dt_txt.split(' ')[0];
const hour = entry.dt_txt.split(' ')[1].split(':')[0];
if (hour === '12' && date !== todayDate) {
dailyForecasts[date] = {
date: date,
day: getDayName(date),
icon: entry.weather[0].icon,
weather: entry.weather[0].description,
temp: entry.main.temp,
wind: entry.wind.speed,
};
}
});
const upcomingForecast = Object.values(dailyForecasts).slice(0, 4);
weeklyForecast[city] = {
today: todayForecast,
upcoming: upcomingForecast
};
localStorage.setItem("weatherData", JSON.stringify(weeklyForecast));
displayTodaysWeather(todayForecast);
displayWeeklyWeather(upcomingForecast);
updateBackground(todayForecast.weather, todayForecast.icon);
});
}
function displayTodaysWeather(forecast) {
const weatherContent = document.getElementById('weather-content');
if (!weatherContent)
return;
weatherContent.innerHTML = `
<div class="weather-icon">
<img id="main-icon" src="https://openweathermap.org/img/wn/${forecast.icon}@2x.png" alt="${forecast.weather}">
</div>
<p id="temperature">${Math.round(forecast.temp)}°C</p>
<p id="city">${forecast.city}</p>
<p id="weather">${forecast.weather}</p>
<div class="sunrise-sunset">
<p id="sunrise">Sunrise: ${forecast.sunrise}</p>
<p id="sunset">Sunset: ${forecast.sunset}</p>
</div>
`;
}
function displayWeeklyWeather(forecastList) {
const forecastTable = document.querySelector("#weather-forecast table");
if (!forecastTable)
return;
const rows = forecastTable.getElementsByTagName("tr");
if (!rows || rows.length === 0)
return;
forecastList.forEach((forecast, index) => {
if (index < rows.length) {
const dayCell = rows[index].querySelector(`#day${index + 1}`);
if (dayCell)
dayCell.textContent = forecast.day;
const iconCell = rows[index].querySelector(`#iconday${index + 1}`);
if (iconCell) {
iconCell.innerHTML = `<img src="https://openweathermap.org/img/wn/${forecast.icon}.png" alt="${forecast.weather}">`;
}
const tempCell = rows[index].querySelector(`#tempday${index + 1}`);
if (tempCell)
tempCell.textContent = `${Math.round(forecast.temp)}°C`;
const windCell = rows[index].querySelector(`#windday${index + 1}`);
if (windCell)
windCell.textContent = `${forecast.wind} m/s`;
}
});
}
function updateBackground(weatherDescription, iconCode) {
const container = document.querySelector('.container');
if (!container)
return;
container.classList.remove('rainy', 'cloudy', 'clear', 'snowy', 'daytime', 'nighttime');
const isDaytime = iconCode.endsWith('d');
container.classList.add(isDaytime ? 'daytime' : 'nighttime');
if (weatherDescription.includes('rain') || weatherDescription.includes('drizzle')) {
container.classList.add('rainy');
}
else if (weatherDescription.includes('cloud')) {
container.classList.add('cloudy');
}
else if (weatherDescription.includes('clear')) {
container.classList.add('clear');
}
else if (weatherDescription.includes('snow')) {
container.classList.add('snowy');
}
}
function cycleCity() {
currentCityIndex = (currentCityIndex + 1) % cities.length;
const city = cities[currentCityIndex];
fetchAndStoreWeather(city);
}
function initializeEventListeners() {
const searchButton = document.getElementById("search-button");
const inputField = document.getElementById("input-field");
const nextSideButton = document.getElementById('next-side-button');
if (searchButton) {
searchButton.addEventListener("click", function () {
if (inputField && inputField.value.trim()) {
fetchAndStoreWeather(inputField.value.trim());
}
});
}
if (inputField) {
inputField.addEventListener("keydown", function (event) {
if (event.key === "Enter" && inputField.value.trim()) {
fetchAndStoreWeather(inputField.value.trim());
}
});
}
if (nextSideButton) {
nextSideButton.addEventListener('click', cycleCity);
}
else {
console.error("Could not find button with ID 'next-side-button'");
}
}
initializeEventListeners();
fetchAndStoreWeather("Stockholm");
const savedData = localStorage.getItem("weatherData");
if (savedData) {
try {
weeklyForecast = JSON.parse(savedData);
}
catch (e) {
console.error("Failed to parse saved weather data:", e);
}
}
});
106 changes: 106 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta
name="viewport"
content="width=, initial-scale=1.0"
>
<link
rel="stylesheet"
href="style.css"
>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
>
<title>Weather App</title>
</head>

<body>

<div class="container">
<h1 class="sr-only">Weather App</h1>

<div class="overlay"></div>
<div class="input-container">
<label
for="input-field"
class="sr-only"
>Search city</label>
<input
type="text"
id="input-field"
placeholder="Search city"
>
<button
id="search-button"
aria-label="Search"
>
<i
class="fa-solid fa-magnifying-glass"
aria-hidden="true"
></i>
</button>
</div>

<div>
<div
class="weather-content"
id="weather-content"
>
</div>


<button
id="next-side-button"
aria-label="Show next City"
><i
class="fa-solid fa-angle-right"
aria-hidden="true"
></i></button>

<div
class="weather-forecast"
id="weather-forecast"
>
<h2 class="sr-only">Weather Forecast</h2>

<table>
<caption class="sr-only">4-day weather forecast</caption>
<tr>
<td id="day1"></td>
<td id="iconday1"></td>
<td id="tempday1"></td>
<td id="windday1"></td>
</tr>
<tr>
<td id="day2"></td>
<td id="iconday2"></td>
<td id="tempday2"></td>
<td id="windday2"></td>
</tr>
<tr>
<td id="day3"></td>
<td id="iconday3"></td>
<td id="tempday3"></td>
<td id="windday3"></td>
</tr>
<tr>
<td id="day4"></td>
<td id="iconday4"></td>
<td id="tempday4"></td>
<td id="windday4"></td>
</tr>
</table>
</div>
</div>



<script src="script.js"></script>

</body>

</html>
Loading