-
+
Time:
-
-
-
-
+
+
:
-
-
-
+
:
-
-
-
+
-
+
Location name:
@@ -394,20 +474,21 @@
- Save settings
+ Save settings
-
+
This app works offline - add to your home screen to use as an app
- Reset settings
+ Reset settings
-
@@ -448,6 +529,36 @@
Solar Eclipse Countdown
let eclipseDate = new Date('2026-08-12T18:28:41Z');
let locationName = "Cascante";
let currentLanguage = "en";
+let isAnimating = false;
+let wakeLock = null;
+
+const requestWakeLock = async () => {
+ if (!('wakeLock' in navigator)) return;
+ try {
+ wakeLock = await navigator.wakeLock.request('screen');
+ wakeLock.addEventListener('release', () => {
+ console.log('Wake Lock was released');
+ });
+ console.log('Wake Lock is active');
+ } catch (err) {
+ console.error(`${err.name}, ${err.message}`);
+ }
+};
+
+const releaseWakeLock = async () => {
+ if (wakeLock !== null) {
+ await wakeLock.release();
+ wakeLock = null;
+ }
+};
+
+const handleVisibilityChange = async () => {
+ if (wakeLock !== null && document.visibilityState === 'visible') {
+ await requestWakeLock();
+ }
+};
+
+document.addEventListener('visibilitychange', handleVisibilityChange);
const translations = {
en: {
@@ -484,7 +595,7 @@ Solar Eclipse Countdown
hourlyAnimation: "Animacja co godzinę:",
saveSettings: "Zapisz ustawienia",
offlineInfo: "Aplikacja działa również offline - dodaj do ekranu głównego, aby korzystać jak z aplikacji.",
- resetSettings: "Resetuj ustawienia"
+ resetSettings: "Resetuj ustawienia"
},
es: {
title: "Cuenta atrás para el eclipse solar",
@@ -520,7 +631,7 @@ Solar Eclipse Countdown
hourlyAnimation: "Stündliche Animation:",
saveSettings: "Einstellungen speichern",
offlineInfo: "Diese App funktioniert offline - füge sie deinem Startbildschirm hinzu, um sie als App zu nutzen.",
- resetSettings: "Einstellungen zurücksetzen"
+ resetSettings: "Einstellungen zurücksetzen"
},
fr: {
title: "Compte à rebours pour l'éclipse solaire",
@@ -574,7 +685,7 @@ Solar Eclipse Countdown
hourlyAnimation: "Animação por hora:",
saveSettings: "Salvar configurações",
offlineInfo: "Este aplicativo funciona offline - adicione à sua tela inicial para usá-lo como um aplicativo.",
- resetSettings: "Redefinir configurações"
+ resetSettings: "Redefinir configurações"
},
is: {
title: "Niðurtalning til sólmyrkva",
@@ -592,568 +703,270 @@ Solar Eclipse Countdown
hourlyAnimation: "Klukkutíma animation:",
saveSettings: "Vista stillingar",
offlineInfo: "Þessi app virkar án nettengingar - bættu við á heimaskjá til að nota sem app.",
- resetSettings: "Endurstilla stillingar"
+ resetSettings: "Endurstilla stillingar"
}
};
const eclipseTimes = {
- oviedo: "2026-08-12T20:27:05+02:00",
- santander: "2026-08-12T20:26:57+02:00",
- bilbao: "2026-08-12T20:27:23+02:00",
- vitoria: "2026-08-12T20:27:43+02:00",
- leon: "2026-08-12T20:28:20+02:00",
- burgos: "2026-08-12T20:28:24+02:00",
- zamora: "2026-08-12T20:30:53+02:00",
- valladolid: "2026-08-12T20:29:53+02:00",
- zaragoza: "2026-08-12T20:29:02+02:00",
- castellon: "2026-08-12T20:31:19+02:00",
- palma: "2026-08-12T20:31:05+02:00",
- coruna: "2026-08-12T20:27:40+02:00",
- soria: "2026-08-12T20:29:06+02:00",
- tarragona: "2026-08-12T20:29:29+02:00",
- reykjavik: "2026-08-12T17:48:16+00:00",
- akranes: "2026-08-12T17:47:52+00:00",
- keflavik: "2026-08-12T17:48:05+00:00",
- olafsvik: "2026-08-12T17:45:54+00:00"
+ oviedo: "2026-08-12T20:27:05+02:00",
+ santander: "2026-08-12T20:26:57+02:00",
+ bilbao: "2026-08-12T20:27:23+02:00",
+ vitoria: "2026-08-12T20:27:43+02:00",
+ leon: "2026-08-12T20:28:20+02:00",
+ burgos: "2026-08-12T20:28:24+02:00",
+ zamora: "2026-08-12T20:30:53+02:00",
+ valladolid: "2026-08-12T20:29:53+02:00",
+ zaragoza: "2026-08-12T20:29:02+02:00",
+ castellon: "2026-08-12T20:31:19+02:00",
+ palma: "2026-08-12T20:31:05+02:00",
+ coruna: "2026-08-12T20:27:40+02:00",
+ soria: "2026-08-12T20:29:06+02:00",
+ tarragona: "2026-08-12T20:29:29+02:00",
+ reykjavik: "2026-08-12T17:48:16+00:00",
+ akranes: "2026-08-12T17:47:52+00:00",
+ keflavik: "2026-08-12T17:48:05+00:00",
+ olafsvik: "2026-08-12T17:45:54+00:00"
};
function updateLanguage(lang) {
currentLanguage = lang;
- document.getElementById('mainTitle').textContent = translations[lang].title;
- document.getElementById('daysLabel').textContent = translations[lang].days;
- document.getElementById('hoursLabel').textContent = translations[lang].hours;
- document.getElementById('minutesLabel').textContent = translations[lang].minutes;
- document.getElementById('secondsLabel').textContent = translations[lang].seconds;
- document.getElementById('locationLabel').textContent = translations[lang].location
+ const trans = translations[lang];
+ document.getElementById('mainTitle').textContent = trans.title;
+ document.getElementById('daysLabel').textContent = trans.days;
+ document.getElementById('hoursLabel').textContent = trans.hours;
+ document.getElementById('minutesLabel').textContent = trans.minutes;
+ document.getElementById('secondsLabel').textContent = trans.seconds;
+ document.getElementById('locationLabel').textContent = trans.location;
document.getElementById('locationName').textContent = locationName;
- document.getElementById('dateLabel').textContent = translations[lang].dateLabel;
- document.getElementById('timeLabel').textContent = translations[lang].timeLabel;
- document.getElementById('locationSelectLabel').textContent = translations[lang].locationSelect;
- document.getElementById('customOption').textContent = translations[lang].customOption;
- document.getElementById('customLocationLabel').textContent = translations[lang].customLocation;
- document.getElementById('keepAwakeLabel').textContent = translations[lang].keepAwake;
- document.getElementById('hourlyAnimationLabel').textContent = translations[lang].hourlyAnimation;
- document.getElementById('saveSettings').textContent = translations[lang].saveSettings;
- document.getElementById('offlineInfo').textContent = translations[lang].offlineInfo;
- document.getElementById('resetSettings').textContent = translations[lang].resetSettings;
+ document.getElementById('dateLabel').textContent = trans.dateLabel;
+ document.getElementById('timeLabel').textContent = trans.timeLabel;
+ document.getElementById('locationSelectLabel').textContent = trans.locationSelect;
+ document.getElementById('customOption').textContent = trans.customOption;
+ document.getElementById('customLocationLabel').textContent = trans.customLocation;
+ document.getElementById('keepAwakeLabel').textContent = trans.keepAwake;
+ document.getElementById('hourlyAnimationLabel').textContent = trans.hourlyAnimation;
+ document.getElementById('saveSettings').textContent = trans.saveSettings;
+ document.getElementById('offlineInfo').textContent = trans.offlineInfo;
+ document.getElementById('resetSettings').textContent = trans.resetSettings;
localStorage.setItem('language', lang);
}
function populateTimeDropdowns() {
- const hoursSelect = document.getElementById('eclipseTimeHours');
- const minutesSelect = document.getElementById('eclipseTimeMinutes');
- const secondsSelect = document.getElementById('eclipseTimeSeconds');
-
- hoursSelect.innerHTML = '';
- minutesSelect.innerHTML = '';
- secondsSelect.innerHTML = '';
-
- for (let i = 0; i < 24; i++) {
- const option = document.createElement('option');
- option.value = i;
- option.textContent = String(i).padStart(2, '0');
- hoursSelect.appendChild(option);
- }
+ const hSelect = document.getElementById('eclipseTimeHours');
+ const mSelect = document.getElementById('eclipseTimeMinutes');
+ const sSelect = document.getElementById('eclipseTimeSeconds');
+ hSelect.innerHTML = mSelect.innerHTML = sSelect.innerHTML = '';
+ for (let i = 0; i < 24; i++) hSelect.add(new Option(String(i).padStart(2, '0'), i));
for (let i = 0; i < 60; i++) {
- const minuteOption = document.createElement('option');
- minuteOption.value = i;
- minuteOption.textContent = String(i).padStart(2, '0');
- minutesSelect.appendChild(minuteOption);
-
- const secondOption = document.createElement('option');
- secondOption.value = i;
- secondOption.textContent = String(i).padStart(2, '0');
- secondsSelect.appendChild(secondOption);
+ mSelect.add(new Option(String(i).padStart(2, '0'), i));
+ sSelect.add(new Option(String(i).padStart(2, '0'), i));
}
}
function updateEclipseDateFromInput() {
- const eclipseDateInput = document.getElementById('eclipseDate').value;
- const hours = parseInt(document.getElementById('eclipseTimeHours').value) || 0;
- const minutes = parseInt(document.getElementById('eclipseTimeMinutes').value) || 0;
- const seconds = parseInt(document.getElementById('eclipseTimeSeconds').value) || 0;
-
- if (eclipseDateInput) {
- const dateParts = eclipseDateInput.split("-");
- const year = parseInt(dateParts[0]);
- const month = parseInt(dateParts[1]) - 1;
- const day = parseInt(dateParts[2]);
-
- const localDate = new Date(year, month, day, hours, minutes, seconds);
- const utcDate = new Date(localDate.getTime() - localDate.getTimezoneOffset() * 60000);
- eclipseDate = localDate;
+ const dateInput = document.getElementById('eclipseDate').value;
+ const h = parseInt(document.getElementById('eclipseTimeHours').value) || 0;
+ const m = parseInt(document.getElementById('eclipseTimeMinutes').value) || 0;
+ const s = parseInt(document.getElementById('eclipseTimeSeconds').value) || 0;
+ if (dateInput) {
+ const [y, mon, d] = dateInput.split("-").map(Number);
+ eclipseDate = new Date(y, mon - 1, d, h, m, s);
localStorage.setItem('eclipseDate', eclipseDate.toISOString());
}
}
-function setDefaultDateTimeValues() {
- const defaultDate = new Date('2026-08-12T18:28:41Z');
-
- const year = defaultDate.getFullYear();
- const month = String(defaultDate.getMonth() + 1).padStart(2, '0');
- const day = String(defaultDate.getDate()).padStart(2, '0');
- const hours = defaultDate.getHours();
- const minutes = defaultDate.getMinutes();
- const seconds = defaultDate.getSeconds();
-
- document.getElementById('eclipseDate').value = `${year}-${month}-${day}`;
- document.getElementById('eclipseTimeHours').value = hours;
- document.getElementById('eclipseTimeMinutes').value = minutes;
- document.getElementById('eclipseTimeSeconds').value = seconds;
- document.getElementById('customLocation').value = "Cascante";
-}
-
function loadSettings() {
const savedDate = localStorage.getItem('eclipseDate');
- const savedLocation = localStorage.getItem('locationName');
- const savedLanguage = localStorage.getItem('language');
+ const savedLoc = localStorage.getItem('locationName');
+ const savedLang = localStorage.getItem('language');
populateTimeDropdowns();
-
- if (savedLanguage && translations[savedLanguage]) {
- updateLanguage(savedLanguage);
- } else {
- updateLanguage("en");
- }
+ updateLanguage(savedLang && translations[savedLang] ? savedLang : "en");
if (savedDate) {
eclipseDate = new Date(savedDate);
- const dateObj = new Date(savedDate);
- const year = dateObj.getFullYear();
- const month = String(dateObj.getMonth() + 1).padStart(2, '0');
- const day = String(dateObj.getDate()).padStart(2, '0');
- const hours = dateObj.getHours();
- const minutes = dateObj.getMinutes();
- const seconds = dateObj.getSeconds();
-
- document.getElementById('eclipseDate').value = `${year}-${month}-${day}`;
- document.getElementById('eclipseTimeHours').value = hours;
- document.getElementById('eclipseTimeMinutes').value = minutes;
- document.getElementById('eclipseTimeSeconds').value = seconds;
} else {
- setDefaultDateTimeValues();
+ eclipseDate = new Date('2026-08-12T18:28:41Z');
}
- if (savedLocation) {
- locationName = savedLocation;
- document.getElementById('customLocation').value = savedLocation;
- document.getElementById('locationSelect').value = "custom";
+ const d = eclipseDate;
+ document.getElementById('eclipseDate').value = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
+ document.getElementById('eclipseTimeHours').value = d.getHours();
+ document.getElementById('eclipseTimeMinutes').value = d.getMinutes();
+ document.getElementById('eclipseTimeSeconds').value = d.getSeconds();
+
+ locationName = savedLoc || "Cascante";
+ document.getElementById('customLocation').value = locationName;
+ if (savedLoc) document.getElementById('locationSelect').value = "custom";
+
+ document.getElementById('locationName').textContent = locationName;
+
+ const savedKA = localStorage.getItem('keepAwake');
+ if (savedKA !== null) {
+ const isEnabled = savedKA === 'true';
+ document.getElementById('keepAwake').checked = isEnabled;
+ if (isEnabled) requestWakeLock();
} else {
- locationName = "Cascante";
- document.getElementById('customLocation').value = locationName;
+ // Default is checked
+ requestWakeLock();
}
- document.getElementById('locationLabel').textContent = translations[currentLanguage].location;
- document.getElementById('locationName').textContent = locationName;
- document.getElementById('locationSelect').dispatchEvent(new Event('change'));
+ const savedHA = localStorage.getItem('hourlyAnimation');
+ if (savedHA !== null) document.getElementById('hourlyAnimation').checked = savedHA === 'true';
}
function createStars() {
- const starsContainer = document.getElementById('stars');
- const numberOfStars = 400;
-
- for (let i = 0; i < numberOfStars; i++) {
+ const container = document.getElementById('stars');
+ const colors = ['#ffffff', '#fff4e6', '#e6f2ff', '#fff0f0', '#f0faff'];
+ for (let i = 0; i < 400; i++) {
const star = document.createElement('div');
- star.classList.add('star');
-
- const left = Math.random() * 100;
- const top = Math.random() * 100;
-
- const size = Math.random() * 3 + 1;
-
- star.style.left = `${left}%`;
- star.style.top = `${top}%`;
- star.style.width = `${size}px`;
- star.style.height = `${size}px`;
-
- starsContainer.appendChild(star);
+ star.className = 'star';
+ const size = Math.random() * 2 + 0.5;
+ const color = colors[Math.floor(Math.random() * colors.length)];
+ star.style.cssText = `left:${Math.random()*100}%; top:${Math.random()*100}%; width:${size}px; height:${size}px; background-color:${color}; box-shadow:0 0 ${size*2}px ${color};`;
+ if (Math.random() > 0.3) star.style.animation = `twinkle ${Math.random()*3+2}s infinite ease-in-out ${Math.random()*5}s`;
+ container.appendChild(star);
}
}
-let isAnimating = false;
+
function updateCountdown() {
const now = new Date();
const timeLeft = eclipseDate - now;
if (timeLeft <= 0) {
- document.getElementById('days').textContent = '0';
- document.getElementById('hours').textContent = '0';
- document.getElementById('minutes').textContent = '0';
- document.getElementById('seconds').textContent = '0';
+ ['days', 'hours', 'minutes', 'seconds'].forEach(id => document.getElementById(id).textContent = '0');
document.getElementById('moon').style.transform = 'translateX(0)';
- document.body.style.backgroundColor = '#070707';
+ document.getElementById('corona').style.opacity = '1';
+ document.getElementById('corona').style.animation = 'coronaFlare 10s infinite linear';
+ document.body.style.backgroundColor = '#050510';
document.getElementById('stars').style.opacity = '1';
+ document.getElementById('nebula').style.opacity = '0.5';
return;
}
- const days = Math.floor(timeLeft / (1000 * 60 * 60 * 24));
- const hours = Math.floor((timeLeft % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
- const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60));
- const seconds = Math.floor((timeLeft % (1000 * 60)) / 1000);
-
- document.getElementById('days').textContent = days;
- document.getElementById('hours').textContent = hours;
- document.getElementById('minutes').textContent = minutes;
- document.getElementById('seconds').textContent = seconds;
-
- const hourlyAnimationEnabled = document.getElementById('hourlyAnimation').checked;
-
- if (hourlyAnimationEnabled && minutes === 0 && seconds < 4 && days >= 30) {
- triggerHourlyAnimation();
+ const d = Math.floor(timeLeft / 86400000);
+ const h = Math.floor((timeLeft % 86400000) / 3600000);
+ const m = Math.floor((timeLeft % 3600000) / 60000);
+ const s = Math.floor((timeLeft % 60000) / 1000);
+
+ updateValue('days', d);
+ updateValue('hours', h);
+ updateValue('minutes', m);
+ updateValue('seconds', s);
+
+ function updateValue(id, val) {
+ const el = document.getElementById(id);
+ const valStr = String(val).padStart(2, '0');
+ if (el.textContent !== valStr) {
+ if (el.textContent === "--") {
+ el.textContent = valStr;
+ return;
+ }
+ el.style.transform = 'translateY(-10px)';
+ el.style.opacity = '0';
+ setTimeout(() => {
+ el.textContent = valStr;
+ el.style.transform = 'translateY(0)';
+ el.style.opacity = '1';
+ }, 150);
+ }
}
- const totalAnimationTime = 30 * 24 * 60 * 60 * 1000;
- let animationProgress = 0;
-
- if (timeLeft < totalAnimationTime) {
- animationProgress = 1 - (timeLeft / totalAnimationTime);
- const moonX = 200 - (animationProgress * 200);
- document.getElementById('moon').style.transform = `translateX(${moonX}px)`;
- } else {
- document.getElementById('moon').style.transform = 'translateX(200px)';
+ if (document.getElementById('hourlyAnimation').checked && m === 0 && s < 2 && d >= 1) {
+ triggerHourlyAnimation();
}
- const twentyDays = 20 * 24 * 60 * 60 * 1000;
- const tenDays = 10 * 24 * 60 * 60 * 1000;
-
if (!isAnimating) {
- if (timeLeft <= twentyDays) {
- const remainingFraction = timeLeft / twentyDays;
- const startColor = { r: 160, g: 160, b: 240 };
- const endColor = { r: 10, g: 10, b: 32 };
- const r = Math.floor(startColor.r + (endColor.r - startColor.r) * (1 - remainingFraction));
- const g = Math.floor(startColor.g + (endColor.g - startColor.g) * (1 - remainingFraction));
- const b = Math.floor(startColor.b + (endColor.b - startColor.b) * (1 - remainingFraction));
- document.body.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
+ const monthMs = 2592000000;
+ if (timeLeft < monthMs) {
+ const progress = 1 - (timeLeft / monthMs);
+ document.getElementById('moon').style.transform = `translateX(calc(var(--eclipse-offset) - (var(--eclipse-offset) * ${progress})))`;
} else {
- const hourOfDay = now.getHours() + now.getMinutes() / 60 + now.getSeconds() / 3600;
- const keyframes = [
- [3, [10, 10, 32]],
- [5, [32, 32, 64]],
- [5.5, [64, 64, 128]],
- [6.5, [180, 230, 255]],
- [19, [180, 230, 255]],
- [19.5, [255, 120, 80]],
- [20, [100, 80, 100]],
- [21, [10, 10, 32]],
- ];
- function interpolateColor(time, keyframes) {
- for (let i = 0; i < keyframes.length - 1; i++) {
- const [t1, c1] = keyframes[i];
- const [t2, c2] = keyframes[i + 1];
-
- if (time >= t1 && time < t2) {
- const ratio = (time - t1) / (t2 - t1);
- const r = c1[0] * (1 - ratio) + c2[0] * ratio;
- const g = c1[1] * (1 - ratio) + c2[1] * ratio;
- const b = c1[2] * (1 - ratio) + c2[2] * ratio;
- return [r, g, b];
- }
- }
- return keyframes[keyframes.length - 1][1];
- }
-
- const [r, g, b] = interpolateColor(hourOfDay, keyframes);
-
- document.body.style.backgroundColor = `rgb(${Math.floor(r)}, ${Math.floor(g)}, ${Math.floor(b)})`;
+ document.getElementById('moon').style.transform = 'translateX(var(--eclipse-offset))';
}
- }
- if (!isAnimating) {
- if (timeLeft <= tenDays) {
- const starOpacity = 1 - (timeLeft / tenDays);
- document.getElementById('stars').style.opacity = starOpacity.toFixed(2);
+ const last10d = 864000000;
+ if (timeLeft < last10d) {
+ const p = 1 - (timeLeft / last10d);
+ document.getElementById('stars').style.opacity = p;
+ document.getElementById('nebula').style.opacity = p * 0.5;
+ document.body.style.backgroundColor = `rgb(${10 + (20 * (1-p))}, ${10 + (20 * (1-p))}, ${32 + (100 * (1-p))})`;
} else {
- const hour = now.getHours();
- document.getElementById('stars').style.opacity = (hour >= 21 || hour < 5) ? '0.6' : '0';
+ const hr = now.getHours();
+ const isNight = hr >= 21 || hr < 5;
+ document.getElementById('stars').style.opacity = isNight ? '0.6' : '0';
+ document.getElementById('nebula').style.opacity = isNight ? '0.3' : '0';
+ document.body.style.backgroundColor = isNight ? '#050510' : '#1a1a2e';
}
}
}
-function getStarsOpacityBasedOnCountdown() {
- const now = new Date();
- const timeLeft = eclipseDate - now;
- const last10days = 10 * 24 * 60 * 60 * 1000;
- if (timeLeft < last10days) {
- const progress = 1 - timeLeft / last10days;
- return progress.toFixed(1);
- }
- return '0';
-}
-
function triggerHourlyAnimation() {
if (isAnimating) return;
isAnimating = true;
-
- const body = document.body;
- const stars = document.getElementById('stars');
- const sun = document.getElementById('sun');
- const moon = document.getElementById('moon');
- const originalBg = getComputedStyle(body).backgroundColor;
-
- body.style.transition = 'background-color 3s ease-in-out';
- stars.style.transition = 'opacity 3s ease-in-out';
- stars.style.opacity = '1';
-
- const styleSheet = document.createElement('style');
- document.head.appendChild(styleSheet);
- sun.style.animation = 'sunPulse 3s ease-in-out';
- moon.style.animation = 'moonSway 4s ease-in-out';
- body.style.backgroundColor = 'rgb(10, 10, 32)';
- setTimeout(() => {
- body.style.backgroundColor = originalBg;
- stars.style.opacity = getStarsOpacityBasedOnCountdown();
- }, 3000);
- setTimeout(() => {
- body.style.transition = '';
- stars.style.transition = '';
- sun.style.animation = '';
- moon.style.animation = '';
- document.head.removeChild(styleSheet);
- isAnimating = false;
- }, 6000);
-}
-
-let wakeLock = null;
-let wakeLockSupported = false;
-let activeWakeLock = false;
-wakeLockSupported = 'wakeLock' in navigator;
-
-async function keepScreenAwake(enabled) {
- if (!wakeLockSupported) {
- return;
- }
-
- if (enabled) {
- if (!activeWakeLock) {
- try {
- wakeLock = await navigator.wakeLock.request('screen');
- activeWakeLock = true;
- wakeLock.addEventListener('release', () => {
- activeWakeLock = false;
- });
-
- document.addEventListener('visibilitychange', handleVisibilityChange);
- } catch (err) {
- if (err.name === 'NotAllowedError') {
- }
- }
- }
- } else {
- if (wakeLock !== null && activeWakeLock) {
- try {
- await wakeLock.release();
- wakeLock = null;
- activeWakeLock = false;
- document.removeEventListener('visibilitychange', handleVisibilityChange);
- } catch (err) {
- }
- }
- }
-}
-
-async function handleVisibilityChange() {
- if (wakeLockSupported && document.getElementById('keepAwake').checked) {
- if (document.visibilityState === 'visible' && !activeWakeLock) {
- try {
- wakeLock = await navigator.wakeLock.request('screen');
- activeWakeLock = true;
- } catch (err) {
- }
- }
- }
-}
-
-
-function toggleFullscreen() {
- if (document.fullscreenElement) {
- document.exitFullscreen();
- } else {
- document.documentElement.requestFullscreen().catch(err => {
- });
- }
+ const body = document.body, stars = document.getElementById('stars'), nebula = document.getElementById('nebula'), sun = document.getElementById('sun'), moon = document.getElementById('moon'), corona = document.getElementById('corona'), dr = document.getElementById('diamondRing'), content = document.querySelector('.content-wrapper');
+ const origBg = body.style.backgroundColor;
+
+ body.style.backgroundColor = '#050510';
+ stars.style.opacity = '1'; nebula.style.opacity = '0.6'; content.style.opacity = '0.1';
+ moon.style.transition = 'transform 6s cubic-bezier(0.4, 0, 0.2, 1)';
+ setTimeout(() => moon.style.transform = 'translateX(0px)', 100);
+
+ setTimeout(() => { dr.style.left = 'calc(50% + (var(--eclipse-size)/2.6))'; dr.style.top = 'calc(25% - (var(--eclipse-size)/2.6))'; dr.style.opacity = '1'; }, 5400);
+ setTimeout(() => { dr.style.opacity = '0'; corona.style.opacity = '1'; corona.style.animation = 'coronaFlare 10s infinite linear'; sun.style.boxShadow = '0 0 2vmin #000'; }, 6000);
+ setTimeout(() => { dr.style.left = 'calc(50% - (var(--eclipse-size)/2.6))'; dr.style.top = 'calc(25% + (var(--eclipse-size)/2.6))'; dr.style.opacity = '1'; corona.style.opacity = '0'; sun.style.boxShadow = ''; }, 10000);
+ setTimeout(() => { dr.style.opacity = '0'; moon.style.transform = 'translateX(calc(-1 * var(--eclipse-offset)))'; }, 10800);
+ setTimeout(() => { body.style.backgroundColor = origBg; content.style.opacity = '1'; updateCountdown(); }, 12000);
+ setTimeout(() => { moon.style.transition = 'none'; moon.style.transform = 'translateX(var(--eclipse-offset))'; isAnimating = false; }, 17000);
}
+window.triggerHourlyAnimation = triggerHourlyAnimation;
-function setupSettingsPanel() {
- const settingsBtn = document.getElementById('settingsBtn');
- const closeBtn = document.getElementById('closeBtn');
- const settingsPanel = document.getElementById('settingsPanel');
- const saveBtn = document.getElementById('saveSettings');
- const locationSelect = document.getElementById('locationSelect');
- const customLocationFields = document.getElementById('customLocationFields');
- const keepAwakeToggle = document.getElementById('keepAwake');
- const fullscreenBtn = document.getElementById('fullscreenBtn');
- const languageSelect = document.getElementById('languageSelect');
- const resetBtn = document.getElementById('resetSettings');
-
- resetBtn.addEventListener('click', resetAllSettings);
+function setupUI() {
+ const panel = document.getElementById('settingsPanel'), sBtn = document.getElementById('settingsBtn');
+ sBtn.onclick = () => { panel.classList.add('open'); sBtn.classList.add('hide'); };
+ document.getElementById('closeBtn').onclick = () => { panel.classList.remove('open'); sBtn.classList.remove('hide'); };
+ document.getElementById('fullscreenBtn').onclick = () => { if (document.fullscreenElement) document.exitFullscreen(); else document.documentElement.requestFullscreen(); };
- if (currentLanguage && translations[currentLanguage]) {
- languageSelect.value = currentLanguage;
- }
-
- languageSelect.addEventListener('change', () => {
- const selectedLang = languageSelect.value;
- if (translations[selectedLang]) {
- updateLanguage(selectedLang);
- }
- });
-
- fullscreenBtn.addEventListener('click', toggleFullscreen);
-
- settingsBtn.addEventListener('click', () => {
- if (currentLanguage) {
- languageSelect.value = currentLanguage;
- }
-
- if (locationSelect.value === "custom") {
- document.getElementById('customLocationFields').style.display = 'block';
- } else {
- document.getElementById('customLocationFields').style.display = 'none';
- }
-
- settingsPanel.classList.add('open');
- settingsBtn.classList.add('hide');
- });
-
- closeBtn.addEventListener('click', () => {
- settingsPanel.classList.remove('open');
- settingsBtn.classList.remove('hide');
- });
-
- locationSelect.addEventListener('change', () => {
- const selected = locationSelect.value;
- const isCustom = selected === 'custom';
- const dateFields = [
- document.getElementById('eclipseDate'),
- document.getElementById('eclipseTimeHours'),
- document.getElementById('eclipseTimeMinutes'),
- document.getElementById('eclipseTimeSeconds')
- ];
- let locationText;
-
- if (isCustom) {
- customLocationFields.style.display = 'block';
- dateFields.forEach(field => field.disabled = false);
- } else {
- customLocationFields.style.display = 'none';
- dateFields.forEach(field => field.disabled = true);
-
- if (eclipseTimes[selected]) {
- const dateTimeStr = eclipseTimes[selected];
- const [datePart, timeWithOffset] = dateTimeStr.split('T');
- const [timePart] = timeWithOffset.split('+').length > 1
- ? timeWithOffset.split('+')
- : timeWithOffset.split('-');
- const [hours, minutes, seconds] = timePart.split(':');
- const [year, month, day] = datePart.split('-');
-
- document.getElementById('eclipseDate').value = `${year}-${month}-${day}`;
- document.getElementById('eclipseTimeHours').value = parseInt(hours);
- document.getElementById('eclipseTimeMinutes').value = parseInt(minutes);
- document.getElementById('eclipseTimeSeconds').value = parseInt(seconds);
- }
- locationText = locationSelect.options[locationSelect.selectedIndex].text;
- }
-
- document.getElementById('locationLabel').textContent = translations[currentLanguage].location;
- document.getElementById('locationName').textContent = locationText;
- });
-
- saveBtn.addEventListener('click', () => {
- const selectedCity = locationSelect.value;
- let newLocationName;
-
- if (selectedCity !== "custom" && eclipseTimes[selectedCity]) {
- newLocationName = locationSelect.options[locationSelect.selectedIndex].text;
- } else {
- newLocationName = document.getElementById("customLocation").value || "Custom";
- }
-
- locationName = newLocationName;
+ document.getElementById('locationSelect').onchange = (e) => {
+ const val = e.target.value;
+ const isC = val === 'custom';
+ document.getElementById('customLocationFields').style.display = isC ? 'block' : 'none';
+ if (!isC && eclipseTimes[val]) {
+ const d = new Date(eclipseTimes[val]);
+ document.getElementById('eclipseDate').value = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
+ document.getElementById('eclipseTimeHours').value = d.getHours();
+ document.getElementById('eclipseTimeMinutes').value = d.getMinutes();
+ document.getElementById('eclipseTimeSeconds').value = d.getSeconds();
+ }
+ };
+
+ document.getElementById('saveSettings').onclick = () => {
+ const locSel = document.getElementById('locationSelect');
+ locationName = locSel.value === 'custom' ? (document.getElementById('customLocation').value || "Custom") : locSel.options[locSel.selectedIndex].text;
localStorage.setItem('locationName', locationName);
-
- document.getElementById('locationLabel').textContent = translations[currentLanguage].location;
document.getElementById('locationName').textContent = locationName;
+ updateEclipseDateFromInput();
+ localStorage.setItem('language', document.getElementById('languageSelect').value);
+ updateLanguage(document.getElementById('languageSelect').value);
- if (selectedCity !== "custom" && eclipseTimes[selectedCity]) {
- eclipseDate = new Date(eclipseTimes[selectedCity]);
- localStorage.setItem('eclipseDate', eclipseDate.toISOString());
- } else {
- updateEclipseDateFromInput();
- }
-
- const selectedLang = languageSelect.value;
- if (translations[selectedLang]) {
- localStorage.setItem('language', selectedLang);
- }
-
+ const keepAwakeEnabled = document.getElementById('keepAwake').checked;
+ localStorage.setItem('keepAwake', keepAwakeEnabled);
+ if (keepAwakeEnabled) requestWakeLock(); else releaseWakeLock();
+
localStorage.setItem('hourlyAnimation', document.getElementById('hourlyAnimation').checked);
- keepScreenAwake(keepAwakeToggle.checked);
- localStorage.setItem('keepAwake', keepAwakeToggle.checked);
-
- settingsPanel.classList.remove('open');
- settingsBtn.classList.remove('hide');
- });
-
- const savedKeepAwake = localStorage.getItem('keepAwake');
- if (savedKeepAwake !== null) {
- keepAwakeToggle.checked = savedKeepAwake === 'true';
- keepScreenAwake(keepAwakeToggle.checked);
- }
-
- const savedHourlyAnimation = localStorage.getItem('hourlyAnimation');
- if (savedHourlyAnimation !== null) {
- document.getElementById('hourlyAnimation').checked = savedHourlyAnimation === 'true';
- }
-}
+ panel.classList.remove('open'); sBtn.classList.remove('hide');
+ };
-function initAdRemoval() {
- const isLikelyOnline = window.location.hostname !== 'localhost' &&
- window.location.hostname !== '127.0.0.1' &&
- !window.location.protocol.includes('file');
- if (isLikelyOnline) {
- const adObserver = new MutationObserver((mutations) => {
- const adElement = document.querySelector('div[style*="position: fixed"][style*="bottom: 0px"][style*="width: 100%"][style*="height: 55px"][style*="z-index: 9999"]');
-
- if (adElement) {
- adElement.remove();
- }
- });
-
- adObserver.observe(document.body, {
- childList: true,
- subtree: true
- });
-
- setTimeout(() => {
- adObserver.disconnect();
- }, 6000);
- }
+ document.getElementById('resetSettings').onclick = () => { localStorage.clear(); location.reload(); };
}
document.addEventListener('DOMContentLoaded', () => {
createStars();
- populateTimeDropdowns();
loadSettings();
- setupSettingsPanel();
+ setupUI();
updateCountdown();
setInterval(updateCountdown, 1000);
-
- document.getElementById('eclipseDate').addEventListener('change', updateEclipseDateFromInput);
- document.getElementById('eclipseTimeHours').addEventListener('change', updateEclipseDateFromInput);
- document.getElementById('eclipseTimeMinutes').addEventListener('change', updateEclipseDateFromInput);
- document.getElementById('eclipseTimeSeconds').addEventListener('change', updateEclipseDateFromInput);
- initAdRemoval();
});
-
-function resetAllSettings() {
- localStorage.removeItem('eclipseDate');
- localStorage.removeItem('locationName');
- localStorage.removeItem('language');
- localStorage.removeItem('hourlyAnimation');
- localStorage.removeItem('keepAwake');
- window.location.reload();
-}