Skip to content

Earth 2 PR #15

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 69 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
e3e1a21
Initial commit
casalm26 Mar 17, 2025
5731fba
Added js and ts files
LindaSchonfeldt Mar 17, 2025
cf8dc6f
Merge branch 'main' of https://github.com/casalm26/js-project-weather…
LindaSchonfeldt Mar 17, 2025
f2b6c5a
added images from figma
casalm26 Mar 17, 2025
96fad3f
boilerplate
casalm26 Mar 17, 2025
279c8dd
boilerple again since i missed a couple of things.
casalm26 Mar 17, 2025
6939ee6
env file och api tillagt
casalm26 Mar 17, 2025
afab28a
added css file and changed the url for the cloud image in the html
LindaSchonfeldt Mar 17, 2025
1e0edf7
added .env and my API-key
casalm26 Mar 17, 2025
43bcba9
foundational elements added
casalm26 Mar 17, 2025
6bb9125
added a dummy response from the api
casalm26 Mar 18, 2025
7d69b92
Fixed the name of the js file in the html
LindaSchonfeldt Mar 18, 2025
4490acc
Merge branch 'main' of https://github.com/casalm26/js-project-weather…
LindaSchonfeldt Mar 18, 2025
a63c689
fixed file names...
casalm26 Mar 18, 2025
79cd435
commit from mob session
casalm26 Mar 18, 2025
3aa317f
Second commit from mob session
casalm26 Mar 18, 2025
c382b76
Added an enum for weather states, funtionality for
LindaSchonfeldt Mar 18, 2025
752b738
.
LindaSchonfeldt Mar 18, 2025
eee5793
Caspian and Cathi fixing the fetch
casalm26 Mar 18, 2025
8dbdc15
merge from Schoenfeldt
casalm26 Mar 18, 2025
95fdf6a
commit from mob part 2
casalm26 Mar 18, 2025
277556d
missed a file
casalm26 Mar 18, 2025
7011e2a
Mob-session no xyz
casalm26 Mar 18, 2025
3c74ee7
.
LindaSchonfeldt Mar 18, 2025
920081e
created new branch, new forecast function
violacathrine Mar 18, 2025
6407669
Started on a geolocation function.
LindaSchonfeldt Mar 18, 2025
a099e3f
Render out info in divs weather-icon and weather-text. Not rendering…
HolaCarmensita Mar 18, 2025
04791ce
test
violacathrine Mar 18, 2025
b62c8c2
Start of geolocation functionality
LindaSchonfeldt Mar 18, 2025
5746589
Updated the geolocation function
LindaSchonfeldt Mar 19, 2025
e7080a4
test
violacathrine Mar 19, 2025
4fd679e
Added function to handle error messages
LindaSchonfeldt Mar 19, 2025
1fd4abb
Now the function render img tag and p tag inside of the iconTextXonta…
HolaCarmensita Mar 19, 2025
5bc754f
Now the functions takes icons from the new map of svg icons
HolaCarmensita Mar 19, 2025
50a0f08
commit search bar
casalm26 Mar 19, 2025
a3e61a7
merge of forecasts
casalm26 Mar 19, 2025
ef3e244
merge of weather-conditions
casalm26 Mar 19, 2025
1e398d3
merge of geolocation
casalm26 Mar 19, 2025
5be9f77
Merge remote-tracking branch 'origin/handle-error-messages' into dev-…
casalm26 Mar 19, 2025
2c0cd99
merged geolocations
casalm26 Mar 19, 2025
1884d83
merge av search-bar
casalm26 Mar 19, 2025
9a4cdf1
merge av iconAndText
casalm26 Mar 19, 2025
fcf9972
update
casalm26 Mar 19, 2025
b2474ce
started with css
violacathrine Mar 19, 2025
87b189d
start of mob to get the app working
casalm26 Mar 19, 2025
584bb99
commit because we forgot before
casalm26 Mar 19, 2025
ec6489e
got some elements to render now.
casalm26 Mar 19, 2025
8a222ed
got all elementd to work
casalm26 Mar 19, 2025
f81b37d
fixed weekdays names in English
casalm26 Mar 19, 2025
70b7235
css fix
violacathrine Mar 19, 2025
28bbdfb
merged styling and some css fixes
casalm26 Mar 19, 2025
1154ca1
got the text to render properly, and managed to style it
casalm26 Mar 19, 2025
3ebcc4a
changed name of assets and minor fixes on html
casalm26 Mar 20, 2025
87ec691
added function to update body class
LindaSchonfeldt Mar 20, 2025
8f00b2b
fixed the icons rendering
casalm26 Mar 20, 2025
a0a7e63
Merge remote-tracking branch 'origin/change-css' into dev-main
casalm26 Mar 20, 2025
d8bc751
merged css
casalm26 Mar 20, 2025
4a035c2
Fix of icons and some weathers not rendering
casalm26 Mar 20, 2025
6acae08
Fixed icon and some css
casalm26 Mar 20, 2025
cee181e
cleaned html
casalm26 Mar 20, 2025
8a91316
cleaned html
casalm26 Mar 20, 2025
50a65bc
added readme
casalm26 Mar 20, 2025
fa36748
Fixed title of page
casalm26 Mar 20, 2025
0bfa0fb
Fixed title of page
casalm26 Mar 20, 2025
7718b48
minor fixes before demo
casalm26 Mar 20, 2025
8479851
Cleanup and refactoring - removed ca 200 lines of TS code.
casalm26 Mar 21, 2025
bd22ff0
Added readme and footer
casalm26 Mar 21, 2025
958f87d
minor update to CSS
casalm26 Mar 21, 2025
8144207
fix for timezones
casalm26 Mar 26, 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
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
}
Binary file added Assets/Clear.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/GitHubLogo.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/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/clouds.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Assets/githublogo.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/rain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
# js-project-weather-app
# 🌦️ Project Weather App

We built a weather application that fetches real-time weather data from an external API. Users can search for any city and instantly get information about the current temperature, a weather description, and a matching icon. The app also displays a 4-day forecast with upcoming weather conditions.

The project is mainly developed using **TypeScript**, with some supporting **HTML structure** and **CSS styling** to create a responsive and user-friendly interface.

This was a group project where we used both **mob programming** and worked in smaller breakout groups to collaborate effectively. Along the way, we faced several challenges – from API issues to layout bugs – but we solved them together. It’s been a learning experience filled with hard work, teamwork, and a lot of fun.

We're proud of the result, but even more proud of how we worked together as a team.

🔗 [Live site](https://earth2weather.netlify.app)

---

© 2025 Project Weather App. All Rights Reserved.
**Developed & created by Casandra, Linda, Caspian & Cathrine**
186 changes: 186 additions & 0 deletions dist/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
"use strict";
// Function to get DOM elements by ID
const getElement = (id) => document.getElementById(id);
// DOM ELEMENTS
const elements = {
weatherContainer: getElement("weather-container"),
weatherContainerChild: getElement("weather-container-child"),
todaysWeatherContainer: getElement("todays-weather-container"),
iconTextContainer: getElement("iconText-container"),
searchForm: document.getElementById("search-form"),
searchInput: document.getElementById("search-input"),
lastSearched: document.getElementById("last-searched"),
searchStatus: document.getElementById("search-status"),
githubIcon: document.getElementById("github-icon")
};
// ENUMS
var WeatherState;
(function (WeatherState) {
WeatherState["Clear"] = "Clear";
WeatherState["Clouds"] = "Clouds";
WeatherState["Rain"] = "Rain";
WeatherState["Snow"] = "Snow";
})(WeatherState || (WeatherState = {}));
// GLOBAL VARIABLES
let weatherDescription = "";
// Use a hardcoded API key for now (you should move this to a secure configuration later)
const API_KEY = "081d5769835e0277d80d7efa7aca13c6"; // Replace with your actual API key
const BASE_URL = "https://api.openweathermap.org/data/2.5";
// Default city if no search is performed
const DEFAULT_CITY = "Stockholm";
// FUNCTIONS
const fetchWeatherData = (city) => {
return fetch(`${BASE_URL}/weather?q=${city}&units=metric&appid=${API_KEY}`)
.then((response) => {
if (!response.ok) {
throw new Error("Weather data fetch failed");
}
return response.json();
})
.then((data) => {
// Formats the time from Unix to local Swedish settings
const formatTime = (timestamp, timezoneOffset) => {
return new Date((timestamp + timezoneOffset) * 1000).toLocaleTimeString("sv-SE", {
hour: "2-digit",
minute: "2-digit",
timeZone: "UTC"
});
};
return {
cityName: data.name,
temperature: Math.round(data.main.temp),
weatherDescription: data.weather[0].main,
weatherId: data.weather[0].id,
sunrise: formatTime(data.sys.sunrise, data.timezone),
sunset: formatTime(data.sys.sunset, data.timezone)
};
})
.catch((error) => {
console.error("Error fetching weather data:", error);
throw error;
});
};
const fetchForecastData = (city) => {
return fetch(`${BASE_URL}/forecast?q=${city}&units=metric&appid=${API_KEY}`)
.then((response) => {
if (!response.ok) {
throw new Error("Forecast data fetch failed");
}
return response.json();
})
.then((data) => {
const processedForecasts = new Map();
// Get today's and tomorrow's dates for comparison
const today = new Date();
const todayString = today.toISOString().split("T")[0]; // YYYY-MM-DD
data.list.forEach((item) => {
const date = new Date(item.dt * 1000).toISOString().split("T")[0]; // YYYY-MM-DD
// Ignore today's forecasts, start from tomorrow
if (date > todayString && !processedForecasts.has(date)) {
processedForecasts.set(date, {
date: date, // Store in ISO format (YYYY-MM-DD)
temperature: Math.round(item.main.temp),
weatherDescription: item.weather[0].description,
weatherId: item.weather[0].id
});
}
});
return Array.from(processedForecasts.values()).slice(0, 4); // Ensure only 4 future days
})
.catch((error) => {
console.error("Error fetching forecast data:", error);
throw error;
});
};
const updateBodyClass = (weatherState) => {
const body = document.body;
const validClasses = ["clear", "rain", "clouds", "snow"];
// Remove old weather classes
body.classList.remove(...validClasses);
elements.githubIcon.classList.remove(...validClasses);
// Add the new class if it's valid
if (validClasses.includes(weatherState.toLowerCase())) {
body.classList.add(weatherState.toLowerCase());
elements.githubIcon.classList.add(weatherState.toLowerCase());
}
};
// Define catchyTextTemplate using city from API as a placeholder
const catchyTextTemplate = {
[WeatherState.Clear]: "Get your sunnies on. {city} is looking rather great today.",
[WeatherState.Rain]: "Don't forget your umbrella. It's wet in {city} today.",
[WeatherState.Clouds]: "Light a fire and get cosy. {city} is looking grey today.",
[WeatherState.Snow]: "Time for a snowball fight! {city} is covered in snow."
};
// Event handler for search that calls on every other function in the program
const runWeatherApp = async (event) => {
event.preventDefault();
const city = elements.searchInput?.value.trim() || DEFAULT_CITY;
try {
// Fetch both weather and forecast data
const [weatherData, forecastData] = await Promise.all([
fetchWeatherData(city),
fetchForecastData(city),
]);
// Get weather state from weather description
const weatherMain = weatherData.weatherDescription.toLowerCase();
const weatherState = weatherMain === "clear"
? WeatherState.Clear
: weatherMain === "rain"
? WeatherState.Rain
: weatherMain === "snow"
? WeatherState.Snow
: WeatherState.Clouds;
updateBodyClass(weatherState);
// Update today's weather
if (elements.todaysWeatherContainer) {
elements.todaysWeatherContainer.innerHTML = `
<p>${weatherState} | ${weatherData.temperature}°C</p>
<p>sunrise ${weatherData.sunrise}</p>
<p>sunset ${weatherData.sunset}</p>
`;
}
// Update icon and text
if (elements.iconTextContainer) {
elements.iconTextContainer.innerHTML = ""; // Clear previous content
const message = catchyTextTemplate[weatherState].replace("{city}", weatherData.cityName);
const iconUrl = `Assets/${weatherState}.png`;
elements.iconTextContainer.innerHTML = `
<img src="${iconUrl}" alt="${weatherState}" class="weather-icon">
<h1>${message}</h1>
`;
}
// Update forecast
const forecastContainer = document.getElementById("forecast-container");
if (forecastContainer) {
forecastContainer.innerHTML = ""; // Clear previous content
forecastData.forEach((day) => {
const row = document.createElement("div");
row.classList.add("forecast-row");
const dayName = new Date(day.date).toLocaleDateString("en-GB", {
weekday: "short"
});
row.innerHTML = `
<span class="day">${dayName}</span>
<span class="temp">${day.temperature}°C</span>
`;
forecastContainer.appendChild(row);
});
}
}
catch (error) {
console.error("Error fetching weather data:", error);
if (elements.todaysWeatherContainer) {
elements.todaysWeatherContainer.textContent = "Error loading weather data";
}
}
};
// Initialize the app
document.addEventListener("DOMContentLoaded", () => {
if (!elements.searchForm) {
console.error("Search form not found");
return;
}
elements.searchForm.addEventListener("submit", runWeatherApp);
// Trigger initial search for default city
runWeatherApp(new Event("submit"));
});
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>Set earth to the rain</title>
<link rel="stylesheet" href="./styles.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">
</head>

<body class="clear">
<div class="container">

<div id="todays-weather-container" class="todays-weather">
</div>

<section id="iconText-container"></section>

<section id="forecast-container" class="forecast">
<div class="forecast-row">
</div>
</section>

<div id="search">
<form id="search-form" class="search-form">
<input type="text" id="search-input" placeholder="Enter city name..." aria-label="Search for a city">
<button type="submit">Search</button>
</form>
</div>

<footer>Made by: Casandra, Linda, Caspian & Cathrine
<a href="https://github.com/casalm26/js-project-weather-app.git" alt="GitHubLogo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 96" id="github-icon" class="github-icon"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="currentColor"/></svg></a>
</footer>


<script type="module" src="dist/script.js"></script>
</body>

</html>
114 changes: 114 additions & 0 deletions node_modules/.package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions node_modules/@types/node/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading