Skip to content

Cholpon - Weather app #439

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 8 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
# 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?
Weather app

## 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://cholpon-weather-app.netlify.app/
42 changes: 42 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!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">
</head>

<body>
<div class="weather-app">


<!-- Current Weather Section -->
<div class="weather-current">
<img id="weather-icon" alt="Weather icon" />
<h1 id="temperature">20°C</h1>
<h2 id="city">Stockholm</h2>
<p id="description">Clear</p>
<p id="local-time">Local Time: --:--</p>
<div class="sun-times">
<span id="sunrise">Sunrise: 22:30</span>
<span id="sunset">Sunset: 00:00</span>
</div>
</div>



<!-- Forecast Section -->
<div class="forecast-container">
<div id="forecast">
<!-- Forecast items will be inserted dynamically -->
</div>
</div>


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

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

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

14 changes: 14 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "project-weather-app",
"version": "1.0.0",
"description": "Weather app",
"main": "script.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"start": "vite preview"
},
"keywords": [],
"author": "",
"license": "ISC"
}
106 changes: 106 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
const apiKey = 'f9f6a2848b9884ac0094319bc7eaad1f';
const city = 'Stockholm';

async function fetchWeather() {
try {
const weatherResponse = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&APPID=${apiKey}`
);

const forecastResponse = await fetch(
`https://api.openweathermap.org/data/2.5/forecast?q=${city}&units=metric&APPID=${apiKey}`
);

const weatherData = await weatherResponse.json();
const forecastData = await forecastResponse.json();

displayCurrentWeather(weatherData);
displayForecast(forecastData);
} catch (error) {
console.error('Error fetching weather data:', error);
}
}

function displayCurrentWeather(data) {
const temperatureElement = document.getElementById('temperature');
const cityElement = document.getElementById('city');
const descriptionElement = document.getElementById('description');
const sunriseElement = document.getElementById('sunrise');
const sunsetElement = document.getElementById('sunset');
const localTimeElement = document.getElementById('local-time');
const weatherIconElement = document.getElementById('weather-icon');

const temperature = data.main.temp.toFixed(1);
const cityName = data.name;
const description = data.weather[0].description;
const sunrise = formatTime(data.sys.sunrise, data.timezone);
const sunset = formatTime(data.sys.sunset, data.timezone);
const iconCode = data.weather[0].icon;
const iconUrl = `https://openweathermap.org/img/wn/${iconCode}@2x.png`;

// Correct local time calculation
const localTimeFormatted = new Intl.DateTimeFormat('en-US', {
hour: '2-digit',
minute: '2-digit',
timeZone: `Etc/GMT${data.timezone / 3600 > 0 ? '-' : '+'}${Math.abs(data.timezone / 3600)}`,
}).format(new Date());

// Update DOM elements
temperatureElement.textContent = `${temperature}°C`;
cityElement.textContent = cityName;
descriptionElement.textContent = description;
sunriseElement.textContent = `Sunrise: ${sunrise}`;
sunsetElement.textContent = `Sunset: ${sunset}`;
localTimeElement.textContent = `Local Time: ${localTimeFormatted}`;

// Update weather icon
weatherIconElement.src = iconUrl;
weatherIconElement.alt = description;
}

function displayForecast(data) {
const forecastElement = document.getElementById('forecast');
const groupedForecasts = {};

// Group forecasts by date
data.list.forEach(item => {
const date = item.dt_txt.split(' ')[0]; // Extract date
if (!groupedForecasts[date]) {
groupedForecasts[date] = [];
}
groupedForecasts[date].push(item);
});

// Generate forecast display
forecastElement.innerHTML = ''; // Clear previous forecast
Object.entries(groupedForecasts).slice(0, 5).forEach(([date, forecasts]) => {
const day = new Date(date).toLocaleDateString('en-US', { weekday: 'short' });

// Calculate min/max temperatures for the day
const temps = forecasts.map(f => f.main.temp);
const tempMin = Math.min(...temps).toFixed(1);
const tempMax = Math.max(...temps).toFixed(1);

// Select the midday weather icon
const middayForecast = forecasts.find(f => f.dt_txt.includes('12:00:00')) || forecasts[0];
const iconCode = middayForecast.weather[0].icon;
const iconUrl = `https://openweathermap.org/img/wn/${iconCode}@2x.png`;

const forecastItem = document.createElement('div');
forecastItem.className = 'forecast-item';
forecastItem.innerHTML = `
<div class="day">${day}</div>
<img src="${iconUrl}" alt="Weather icon" class="icon" />
<div class="temp-range">${tempMin}° / ${tempMax}°</div>
`;

forecastElement.appendChild(forecastItem);
});
}

function formatTime(timestamp, timezoneOffset) {
const date = new Date((timestamp + timezoneOffset) * 1000);
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}

fetchWeather();
162 changes: 162 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/* General Reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: 'Arial', sans-serif;
background: linear-gradient(to bottom, #1E2749, #5A4B81);
color: white;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
text-align: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

/* Weather App Container */
.weather-app {
width: 350px;
max-width: 90%;
background-color: linear-gradient(to bottom, #1E2749, #5A4B81)4E;
border-radius: 20px;
overflow: hidden;
color: white;
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.4);
padding: 20px 15px;
}

/* Header */
header {
display: flex;
justify-content: flex-start;
padding: 10px;
font-size: 20px;
background: rgba(46, 59, 78, 0.8);
}

/* Current Weather Section */
.weather-current {
text-align: center;
padding: 30px;
background: linear-gradient(to bottom, #1E2749, #5A4B81);
color: white;
position: relative;
box-shadow: inset 0 -2px 5px rgba(0, 0, 0, 0.2);
}

.weather-current h1 {
font-size: calc(3rem + 1vw);
margin-bottom: 10px;
}

.weather-current h2 {
font-size: 1.5rem;
margin-bottom: 5px;
}

.weather-current #local-time {
font-size: 1.2rem;
margin-top: 15px;
color: #F9A826;
font-weight: bold;
}

#weather-icon {
width: 120px;
height: 120px;
margin: 15px auto;
display: block;
transition: transform 0.3s ease;
}
#weather-icon:hover {
transform: scale(1.1);
}

/* Forecast Section */
.forecast-container {
padding: 20px;
background: #1E2749;
border-top-left-radius: 20px;
border-top-right-radius: 20px;
}

.forecast-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background: linear-gradient(to bottom, #1E2749, #5A4B81);
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
transition: transform 0.2s ease, box-shadow 0.2s ease;
color: #D3D3D3;
}

.forecast-item:hover {
transform: scale(1.05);
background: linear-gradient(to bottom, #1E2749, #5A4B81);
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.4);
}

.forecast-item .day {
font-size: 1rem;
font-weight: bold;
color: #FFFFFF;
}

.forecast-item .icon {
width: 50px;
height: 50px;
filter: brightness(1.3);

}

.forecast-item .temp-range {
font-size: 0.9rem;
color: #F9A826;
}

/* Button Example */
.refresh-button {
padding: 10px 20px;
font-size: 1rem;
background-color: #F9A826;
color: #1E2749;
border: none;
border-radius: 10px;
cursor: pointer;
transition: background-color 0.3s ease;
margin-top: 20px;
}
.refresh-button:hover {
background-color: #FFB347;
}

/* Responsive Design */
@media (max-width: 768px) {
.weather-current {
padding: 20px;
}
.weather-current h1 {
font-size: calc(2.5rem + 1vw);
#weather-icon {
width: 80px;
height: 80px;
}
.forecast-item {
padding: 10px;
flex-direction: column;
text-align: center;
}
.forecast-item .day,
.forecast-item .temp-range {
font-size: 0.85rem;
}
}
}