update weather widget

This commit is contained in:
Quang Khai Nguyen committed 2026-10-20 09:07:49 +02:00
1 parent 8fe3eea7eb
commit 69c67976c7
3 files changed
+156 -10

No files matched your search

+100 -10
View File
@@ -11,6 +11,7 @@ const languageLocales = {
let currentLang = 'vi';
let currentWeatherCondition = 'weather_loading';
let tomorrowWeatherCondition = 'weather_loading';
function getWeatherPresentation(code) {
if (code === 0) return { key: 'weather_clear', icon: 'fa-sun', color: 'text-amber-500' };
@@ -29,25 +30,104 @@ function getWeatherPresentation(code) {
function renderWeatherCondition() {
const condition = document.getElementById('weather-condition');
if (condition) condition.textContent = translations[currentLang][currentWeatherCondition] || translations.en[currentWeatherCondition];
const currentForecastCondition = document.getElementById('weather-current-condition');
if (currentForecastCondition) {
currentForecastCondition.textContent = translations[currentLang][currentWeatherCondition] || translations.en[currentWeatherCondition];
}
const tomorrowForecastCondition = document.getElementById('weather-tomorrow-condition');
if (tomorrowForecastCondition) {
tomorrowForecastCondition.textContent = translations[currentLang][tomorrowWeatherCondition] || translations.en[tomorrowWeatherCondition];
}
}
async function loadCurrentWeather() {
function setWeatherRange(id, value) {
const element = document.getElementById(id);
if (element) element.textContent = Number.isFinite(value) ? `${Math.round(value)}°` : '--°';
}
function setWeatherIcon(id, presentation) {
const icon = document.getElementById(id);
if (icon) icon.className = `fa-solid ${presentation.icon} text-4xl ${presentation.color}`;
}
async function loadWeatherForecast() {
const temperature = document.getElementById('weather-temperature');
const icon = document.getElementById('weather-icon');
const currentForecastTemperature = document.getElementById('weather-current-temperature');
const tomorrowDate = document.getElementById('weather-tomorrow-date');
try {
const response = await fetch('https://api.open-meteo.com/v1/forecast?latitude=12.2388&longitude=109.1967&current=temperature_2m,weather_code&timezone=Asia%2FHo_Chi_Minh');
const response = await fetch('https://api.open-meteo.com/v1/forecast?latitude=12.2388&longitude=109.1967&current=temperature_2m,weather_code&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=Asia%2FHo_Chi_Minh&forecast_days=2');
if (!response.ok) throw new Error('Weather request failed');
const data = await response.json();
const presentation = getWeatherPresentation(data.current.weather_code);
temperature.textContent = `${Math.round(data.current.temperature_2m)}°C`;
icon.className = `fa-solid ${presentation.icon} text-2xl ${presentation.color}`;
currentWeatherCondition = presentation.key;
const current = data.current;
const daily = data.daily;
if (
!Number.isFinite(current?.temperature_2m)
|| !Number.isFinite(current?.weather_code)
|| !Array.isArray(daily?.time)
|| !Array.isArray(daily?.weather_code)
|| !Array.isArray(daily?.temperature_2m_max)
|| !Array.isArray(daily?.temperature_2m_min)
|| daily.time.length < 2
|| daily.weather_code.length < 2
|| daily.temperature_2m_max.length < 2
|| daily.temperature_2m_min.length < 2
|| !Number.isFinite(daily.weather_code[1])
|| !Number.isFinite(daily.temperature_2m_max[0])
|| !Number.isFinite(daily.temperature_2m_min[0])
|| !Number.isFinite(daily.temperature_2m_max[1])
|| !Number.isFinite(daily.temperature_2m_min[1])
|| !/^\d{4}-\d{2}-\d{2}$/.test(daily.time[1])
) {
throw new Error('Weather response is incomplete');
}
const currentPresentation = getWeatherPresentation(current.weather_code);
const tomorrowPresentation = getWeatherPresentation(daily.weather_code[1]);
const currentTemperature = `${Math.round(current.temperature_2m)}°C`;
if (temperature) temperature.textContent = currentTemperature;
if (currentForecastTemperature) currentForecastTemperature.textContent = currentTemperature;
if (icon) icon.className = `fa-solid ${currentPresentation.icon} text-2xl ${currentPresentation.color}`;
setWeatherIcon('weather-current-icon', currentPresentation);
setWeatherIcon('weather-tomorrow-icon', tomorrowPresentation);
setWeatherRange('weather-today-high', daily.temperature_2m_max[0]);
setWeatherRange('weather-today-low', daily.temperature_2m_min[0]);
setWeatherRange('weather-tomorrow-high', daily.temperature_2m_max[1]);
setWeatherRange('weather-tomorrow-low', daily.temperature_2m_min[1]);
if (tomorrowDate) {
const [year, month, day] = daily.time[1].split('-').map(Number);
const date = new Date(year, month - 1, day, 12);
tomorrowDate.dateTime = daily.time[1];
tomorrowDate.textContent = new Intl.DateTimeFormat(languageLocales[currentLang].replace('_', '-'), {
weekday: 'short',
month: 'short',
day: 'numeric'
}).format(date);
}
currentWeatherCondition = currentPresentation.key;
tomorrowWeatherCondition = tomorrowPresentation.key;
} catch {
temperature.textContent = '--°C';
icon.className = 'fa-solid fa-cloud text-2xl text-gray-400';
if (temperature) temperature.textContent = '--°C';
if (currentForecastTemperature) currentForecastTemperature.textContent = '--°C';
if (icon) icon.className = 'fa-solid fa-cloud text-2xl text-gray-400';
setWeatherIcon('weather-current-icon', { icon: 'fa-cloud', color: 'text-gray-400' });
setWeatherIcon('weather-tomorrow-icon', { icon: 'fa-cloud', color: 'text-gray-400' });
setWeatherRange('weather-today-high', NaN);
setWeatherRange('weather-today-low', NaN);
setWeatherRange('weather-tomorrow-high', NaN);
setWeatherRange('weather-tomorrow-low', NaN);
if (tomorrowDate) {
tomorrowDate.textContent = '';
tomorrowDate.removeAttribute('datetime');
}
currentWeatherCondition = 'weather_unavailable';
tomorrowWeatherCondition = 'weather_unavailable';
}
renderWeatherCondition();
@@ -108,6 +188,16 @@ function setLanguage(lang) {
document.getElementById('og-url').content = canonicalUrl;
document.getElementById('og-locale').content = languageLocales[lang];
renderWeatherCondition();
const tomorrowDate = document.getElementById('weather-tomorrow-date');
if (tomorrowDate.dateTime) {
const [year, month, day] = tomorrowDate.dateTime.split('-').map(Number);
tomorrowDate.textContent = new Intl.DateTimeFormat(languageLocales[lang].replace('_', '-'), {
weekday: 'short',
month: 'short',
day: 'numeric'
}).format(new Date(year, month - 1, day, 12));
}
}
function toggleMobileMenu() {
@@ -161,5 +251,5 @@ function closeModal() {
}
setLanguage(getRequestedLanguage() || getPreferredLanguage());
loadCurrentWeather();
setInterval(loadCurrentWeather, 30 * 60 * 1000);
loadWeatherForecast();
setInterval(loadWeatherForecast, 30 * 60 * 1000);