Optimize landscape layout: 4-column grid, transport icons, improved sizing and spacing

This commit is contained in:
2025-12-31 16:27:55 +01:00
parent a0c997f7d4
commit 738a422dc9
14 changed files with 2173 additions and 1629 deletions

View File

@@ -131,11 +131,13 @@ class WeatherManager {
* Process current weather data from API response
*/
processCurrentWeather(data) {
const iconCode = data.weather[0].icon;
return {
temperature: Math.round(data.main.temp * 10) / 10, // Round to 1 decimal place
condition: data.weather[0].main,
description: data.weather[0].description,
icon: this.getWeatherIconUrl(data.weather[0].icon),
icon: this.getWeatherIconUrl(iconCode),
iconCode: iconCode, // Store icon code for classification
wind: {
speed: Math.round(data.wind.speed * 3.6), // Convert m/s to km/h
direction: data.wind.deg
@@ -155,11 +157,13 @@ class WeatherManager {
processForecast(data) {
// Get the next 7 forecasts (covering about 24 hours)
return data.list.slice(0, 7).map(item => {
const iconCode = item.weather[0].icon;
return {
temperature: Math.round(item.main.temp * 10) / 10,
condition: item.weather[0].main,
description: item.weather[0].description,
icon: this.getWeatherIconUrl(item.weather[0].icon),
icon: this.getWeatherIconUrl(iconCode),
iconCode: iconCode, // Store icon code for classification
timestamp: new Date(item.dt * 1000),
precipitation: item.rain ? (item.rain['3h'] || 0) : 0
};
@@ -173,6 +177,42 @@ class WeatherManager {
return `https://openweathermap.org/img/wn/${iconCode}@2x.png`;
}
/**
* Determine if icon represents sun (even behind clouds)
*/
isSunIcon(iconCode, condition) {
// Icon codes: 01d, 01n = clear, 02d, 02n = few clouds, 03d, 03n = scattered, 04d, 04n = broken clouds
const sunIconCodes = ['01d', '01n', '02d', '02n', '03d', '03n', '04d', '04n'];
return sunIconCodes.includes(iconCode) ||
condition.includes('Clear') ||
condition.includes('Clouds');
}
/**
* Check if icon is clear sun (no clouds)
*/
isClearSun(iconCode, condition) {
const clearIconCodes = ['01d', '01n'];
return clearIconCodes.includes(iconCode) || condition === 'Clear';
}
/**
* Check if icon is sun behind clouds
*/
isSunBehindClouds(iconCode, condition) {
const cloudIconCodes = ['02d', '02n', '03d', '03n', '04d', '04n'];
return cloudIconCodes.includes(iconCode) || (condition.includes('Clouds') && !condition.includes('Clear'));
}
/**
* Determine if icon represents snow
*/
isSnowIcon(iconCode, condition) {
// Icon code: 13d, 13n = snow
const snowIconCodes = ['13d', '13n'];
return snowIconCodes.includes(iconCode) || condition.includes('Snow');
}
/**
* Create default weather data for fallback
*/
@@ -182,6 +222,7 @@ class WeatherManager {
condition: 'Clear',
description: 'clear sky',
icon: 'https://openweathermap.org/img/wn/01d@2x.png',
iconCode: '01d',
wind: {
speed: 14.8,
direction: 270
@@ -209,9 +250,10 @@ class WeatherManager {
forecasts.push({
temperature: 7.1 - (i * 0.3), // Decrease temperature slightly each hour
condition: i < 2 ? 'Clear' : 'Partly Cloudy',
condition: i < 2 ? 'Clear' : 'Clouds',
description: i < 2 ? 'clear sky' : 'few clouds',
icon: i < 2 ? 'https://openweathermap.org/img/wn/01n@2x.png' : 'https://openweathermap.org/img/wn/02n@2x.png',
iconCode: i < 2 ? '01n' : '02n',
timestamp: forecastTime,
precipitation: 0
});
@@ -242,6 +284,18 @@ class WeatherManager {
if (iconElement) {
iconElement.src = this.weatherData.icon;
iconElement.alt = this.weatherData.description;
// Add classes and data attributes for color filtering
iconElement.setAttribute('data-condition', this.weatherData.condition);
iconElement.classList.remove('weather-sun', 'weather-snow', 'weather-clear-sun', 'weather-clouds-sun');
if (this.isSnowIcon(this.weatherData.iconCode, this.weatherData.condition)) {
iconElement.classList.add('weather-snow');
} else if (this.isClearSun(this.weatherData.iconCode, this.weatherData.condition)) {
iconElement.classList.add('weather-sun', 'weather-clear-sun');
} else if (this.isSunBehindClouds(this.weatherData.iconCode, this.weatherData.condition)) {
iconElement.classList.add('weather-sun', 'weather-clouds-sun');
} else if (this.isSunIcon(this.weatherData.iconCode, this.weatherData.condition)) {
iconElement.classList.add('weather-sun');
}
}
const temperatureElement = document.querySelector('#custom-weather .temperature');
@@ -255,16 +309,29 @@ class WeatherManager {
// Clear existing forecast
forecastContainer.innerHTML = '';
// Add current weather as "Now"
// Add current weather as "Nu" (Swedish for "Now")
const nowElement = document.createElement('div');
nowElement.className = 'forecast-hour';
const nowIcon = document.createElement('img');
nowIcon.src = this.weatherData.icon;
nowIcon.alt = this.weatherData.description;
nowIcon.width = 56;
nowIcon.setAttribute('data-condition', this.weatherData.condition);
if (this.isSnowIcon(this.weatherData.iconCode, this.weatherData.condition)) {
nowIcon.classList.add('weather-snow');
} else if (this.isClearSun(this.weatherData.iconCode, this.weatherData.condition)) {
nowIcon.classList.add('weather-sun', 'weather-clear-sun');
} else if (this.isSunBehindClouds(this.weatherData.iconCode, this.weatherData.condition)) {
nowIcon.classList.add('weather-sun', 'weather-clouds-sun');
} else if (this.isSunIcon(this.weatherData.iconCode, this.weatherData.condition)) {
nowIcon.classList.add('weather-sun');
}
nowElement.innerHTML = `
<div class="time">Now</div>
<div class="icon">
<img src="${this.weatherData.icon}" alt="${this.weatherData.description}" width="40" />
</div>
<div class="time">Nu</div>
<div class="icon"></div>
<div class="temp">${this.weatherData.temperature} °C</div>
`;
nowElement.querySelector('.icon').appendChild(nowIcon);
forecastContainer.appendChild(nowElement);
// Add hourly forecasts
@@ -274,13 +341,26 @@ class WeatherManager {
const forecastElement = document.createElement('div');
forecastElement.className = 'forecast-hour';
const forecastIcon = document.createElement('img');
forecastIcon.src = forecast.icon;
forecastIcon.alt = forecast.description;
forecastIcon.width = 56;
forecastIcon.setAttribute('data-condition', forecast.condition);
if (this.isSnowIcon(forecast.iconCode, forecast.condition)) {
forecastIcon.classList.add('weather-snow');
} else if (this.isClearSun(forecast.iconCode, forecast.condition)) {
forecastIcon.classList.add('weather-sun', 'weather-clear-sun');
} else if (this.isSunBehindClouds(forecast.iconCode, forecast.condition)) {
forecastIcon.classList.add('weather-sun', 'weather-clouds-sun');
} else if (this.isSunIcon(forecast.iconCode, forecast.condition)) {
forecastIcon.classList.add('weather-sun');
}
forecastElement.innerHTML = `
<div class="time">${timeString}</div>
<div class="icon">
<img src="${forecast.icon}" alt="${forecast.description}" width="40" />
</div>
<div class="icon"></div>
<div class="temp">${forecast.temperature} °C</div>
`;
forecastElement.querySelector('.icon').appendChild(forecastIcon);
forecastContainer.appendChild(forecastElement);
});
}