Deze commit verbetert de laadtijden en responsiviteit van de Adhaan-webapp door verschillende optimalisaties. Er is een verbetering in de structuur van HTML en JavaScript. De expliciete onclick-attributen zijn vervangen door event listeners, caching van DOM-elementen is geïntroduceerd, en er zijn debouncing-technieken toegevoegd voor efficiëntere updates van weer- en hadithgegevens. Verder is er sprake van een herschikking van de countdown-timer en andere UI-elementen om logischer te werken, zoals het verbergen van de inhoud om FOUC te voorkomen totdat alles geladen is. Deze wijzigingen samen dragen bij aan een soepeler gebruikerservaring.
404 lines
15 KiB
HTML
404 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Gebedstijden Display</title>
|
|
<link rel="stylesheet" href="/static/style.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=Cairo:wght@700&family=Lato:wght@400;700&display=swap" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
<script>
|
|
// Voorkom FOUC (Flash of Unstyled Content)
|
|
document.documentElement.style.visibility = 'hidden';
|
|
window.addEventListener('load', function() {
|
|
document.documentElement.style.visibility = 'visible';
|
|
});
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div class="app">
|
|
<!-- Dark/Light toggle -->
|
|
<button id="themeToggle" title="Schakel modus"><span id="themeIcon" class="material-icons">brightness_6</span></button>
|
|
|
|
<div class="left">
|
|
<div class="overlay">
|
|
<div class="tijdstip">
|
|
<div class="tijd-weer-row">
|
|
<div class="tijd-column">
|
|
<div id="current-time">--:--</div>
|
|
</div>
|
|
<div class="weer-column">
|
|
<!-- Weer sectie naast de tijd -->
|
|
<div class="weather-section-left">
|
|
<div class="weather-info">
|
|
<div class="weather-main">
|
|
<span class="weather-temp">{{ weather.temperature }}°C</span>
|
|
<span class="weather-desc">{{ weather.description }}</span>
|
|
</div>
|
|
<div class="weather-details">
|
|
<span class="weather-detail">Voelt als {{ weather.feels_like }}°C</span>
|
|
<span class="weather-detail">Vochtigheid {{ weather.humidity }}%</span>
|
|
<span class="weather-detail">Wind {{ weather.wind_speed }} km/h</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="datum-sectie">
|
|
<div class="gregorian-datum">{{ date_info.gregorian_full }}</div>
|
|
<div class="hijri-datum-arabic">{{ date_info.hijri_arabic }}</div>
|
|
<div class="hijri-datum-dutch">{{ date_info.hijri_dutch }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Huidig gebed sectie onderaan -->
|
|
<div class="huidig-gebed-bottom">
|
|
<div class="naam">{{ next_name }}</div>
|
|
<div id="countdown">--:--:--</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Zijmenu met hadith sectie -->
|
|
<div class="right new-layout">
|
|
<div class="hadith-tijden-row">
|
|
<!-- Hadith sectie met witte achtergrond -->
|
|
<div class="hadith-center">
|
|
<blockquote>
|
|
"{{ hadith.text }}"
|
|
<footer>— {{ hadith.bron }}</footer>
|
|
</blockquote>
|
|
</div>
|
|
|
|
<!-- Compact zijmenu -->
|
|
<div class="vertical-tijden">
|
|
<ul class="tijden-en-icoontjes">
|
|
{% for naam, tijd in gebedstijden.items() %}
|
|
<li class="tijden-rij">
|
|
<span class="naam">{{ naam }}</span>
|
|
<span class="tijd">{{ tijd[:5] }}</span>
|
|
</li>
|
|
{% endfor %}
|
|
<li><a href="/instellingen" title="Instellingen" class="icoon-link"><span class="material-icons">settings</span></a></li>
|
|
<li><a href="#" id="muteBtn" title="Mute" class="icoon-link"><span id="muteIcon" class="material-icons">volume_off</span></a></li>
|
|
{% if settings.debug_mode %}
|
|
<li><a href="/debug" title="Debug Mode" class="icoon-link"><span class="material-icons">bug_report</span></a></li>
|
|
{% endif %}
|
|
<li><a href="/quran" title="Quran Speler" class="icoon-link"><span class="material-icons">menu_book</span></a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<audio id="adhanAudio" src="/static/clips/{{ settings['audio_clip'] }}" preload="auto"></audio>
|
|
|
|
<!-- Adzkaar Modal -->
|
|
<div id="adzkaarModal" class="adzkaar-modal" style="display: none;">
|
|
<div class="adzkaar-container">
|
|
<button class="close-button" onclick="closeAdzkaar()" title="Sluiten">
|
|
<span class="material-icons">close</span>
|
|
</button>
|
|
|
|
<div class="countdown-timer" id="countdownTimer">
|
|
5:00
|
|
</div>
|
|
|
|
<div class="adzkaar-header">
|
|
<h1 class="adzkaar-title">أذكار بعد الصلاة</h1>
|
|
<p class="adzkaar-subtitle">Adzkaar na het Gebed</p>
|
|
</div>
|
|
|
|
<div class="adzkaar-content">
|
|
<div class="dhikr-navigation">
|
|
<button class="nav-btn" id="prevBtn" onclick="previousDhikr()" disabled>
|
|
<span class="material-icons">arrow_back</span>
|
|
</button>
|
|
|
|
<div class="dhikr-counter">
|
|
<span id="currentDhikr">1</span> / <span id="totalDhikr">6</span>
|
|
</div>
|
|
|
|
<button class="nav-btn" id="nextBtn" onclick="nextDhikr()">
|
|
<span class="material-icons">arrow_forward</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="dhikr-container" id="dhikrContainer">
|
|
<div class="dhikr-item active" data-index="0">
|
|
<div class="dhikr-arabic">أَسْتَغْفِرُ اللَّهَ</div>
|
|
<div class="dhikr-transliteration">Astaghfirullah</div>
|
|
<div class="dhikr-translation">Ik vraag Allah om vergeving</div>
|
|
<div class="dhikr-count">3x</div>
|
|
</div>
|
|
|
|
<div class="dhikr-item" data-index="1">
|
|
<div class="dhikr-arabic">اللَّهُمَّ أَنْتَ السَّلاَمُ وَمِنْكَ السَّلاَمُ تَبَارَكْتَ يَا ذَا الْجَلاَلِ وَالإِكْرَامِ</div>
|
|
<div class="dhikr-transliteration">Allahumma anta as-salamu wa minka as-salamu, tabarakta ya dhal-jalali wal-ikram</div>
|
|
<div class="dhikr-translation">O Allah, U bent de Vrede en van U komt de vrede. Gezegend bent U, O Bezitter van Majesteit en Eer</div>
|
|
<div class="dhikr-count">1x</div>
|
|
</div>
|
|
|
|
<div class="dhikr-item" data-index="2">
|
|
<div class="dhikr-arabic">سُبْحَانَ اللَّهِ</div>
|
|
<div class="dhikr-transliteration">Subhan Allah</div>
|
|
<div class="dhikr-translation">Glorie zij Allah</div>
|
|
<div class="dhikr-count">33x</div>
|
|
</div>
|
|
|
|
<div class="dhikr-item" data-index="3">
|
|
<div class="dhikr-arabic">الْحَمْدُ لِلَّهِ</div>
|
|
<div class="dhikr-transliteration">Alhamdulillah</div>
|
|
<div class="dhikr-translation">Alle lof zij Allah</div>
|
|
<div class="dhikr-count">33x</div>
|
|
</div>
|
|
|
|
<div class="dhikr-item" data-index="4">
|
|
<div class="dhikr-arabic">اللَّهُ أَكْبَرُ</div>
|
|
<div class="dhikr-transliteration">Allahu Akbar</div>
|
|
<div class="dhikr-translation">Allah is de Grootste</div>
|
|
<div class="dhikr-count">34x</div>
|
|
</div>
|
|
|
|
<div class="dhikr-item" data-index="5">
|
|
<div class="dhikr-arabic">لاَ إِلَهَ إِلاَّ اللَّهُ وَحْدَهُ لاَ شَرِيكَ لَهُ لَهُ الْمُلْكُ وَلَهُ الْحَمْدُ وَهُوَ عَلَى كُلِّ شَيْءٍ قَدِيرٌ</div>
|
|
<div class="dhikr-transliteration">La ilaha illa Allah wahdahu la sharika lah, lahu al-mulku wa lahu al-hamdu wa huwa 'ala kulli shay'in qadir</div>
|
|
<div class="dhikr-translation">Er is geen god behalve Allah alleen, Hij heeft geen partner. Aan Hem behoort de heerschappij en aan Hem behoort alle lof, en Hij heeft macht over alle dingen</div>
|
|
<div class="dhikr-count">1x</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Cache DOM elementen
|
|
const currentTimeEl = document.getElementById('current-time');
|
|
const countdownEl = document.getElementById('countdown');
|
|
const muteBtn = document.getElementById('muteBtn');
|
|
const muteIcon = document.getElementById('muteIcon');
|
|
const adhanAudio = document.getElementById('adhanAudio');
|
|
const adzkaarModal = document.getElementById('adzkaarModal');
|
|
|
|
// Prayer times data from server
|
|
window.prayerTimes = [
|
|
{% for naam, tijd in gebedstijden.items() %}
|
|
"{{ tijd[:5] }}"{% if not loop.last %},{% endif %}
|
|
{% endfor %}
|
|
];
|
|
window.prayerNames = [
|
|
{% for naam, tijd in gebedstijden.items() %}
|
|
"{{ naam }}"{% if not loop.last %},{% endif %}
|
|
{% endfor %}
|
|
];
|
|
const nextPrayerTime = "{{ next_time }}";
|
|
const hadithInterval = {{ settings.hadith_interval_seconds or 30 }} * 1000;
|
|
|
|
// Debounce functie voor betere performance
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
// Optimize weather updates
|
|
const updateWeather = debounce(async function() {
|
|
try {
|
|
const response = await fetch('/api/weather');
|
|
const data = await response.json();
|
|
updateWeatherUI(data);
|
|
} catch (error) {
|
|
console.error('Fout bij ophalen weerdata:', error);
|
|
}
|
|
}, 1000);
|
|
|
|
// Optimize hadith updates
|
|
const updateHadith = debounce(async function() {
|
|
try {
|
|
const response = await fetch('/api/hadith');
|
|
const data = await response.json();
|
|
updateHadithUI(data);
|
|
} catch (error) {
|
|
console.error('Fout bij ophalen hadith:', error);
|
|
}
|
|
}, 1000);
|
|
|
|
// Initialize on load
|
|
window.addEventListener('load', function() {
|
|
updateCurrentTime();
|
|
setInterval(updateCurrentTime, 60000);
|
|
setupThemeToggle();
|
|
startCountdowns(window.prayerTimes, window.prayerNames);
|
|
|
|
// Update weerdata elke 10 minuten
|
|
updateWeather();
|
|
setInterval(updateWeather, 600000);
|
|
|
|
// Update hadith elke X seconden
|
|
updateHadith();
|
|
setInterval(updateHadith, hadithInterval);
|
|
|
|
// Setup event listeners
|
|
setupEventListeners();
|
|
});
|
|
|
|
// Setup event listeners
|
|
function setupEventListeners() {
|
|
if (muteBtn) {
|
|
muteBtn.addEventListener('click', toggleMute);
|
|
}
|
|
}
|
|
|
|
// Toggle mute state
|
|
function toggleMute() {
|
|
const isMuted = adhanAudio.muted;
|
|
adhanAudio.muted = !isMuted;
|
|
muteIcon.textContent = isMuted ? 'volume_off' : 'volume_up';
|
|
|
|
// Update mute state in settings
|
|
fetch('/api/mute', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ mute: !isMuted })
|
|
}).catch(error => console.error('Fout bij updaten mute state:', error));
|
|
}
|
|
|
|
// Theme toggle icon dynamisch aanpassen
|
|
function updateThemeIcon() {
|
|
const html = document.documentElement;
|
|
const icon = document.getElementById('themeIcon');
|
|
if (html.className === 'light') {
|
|
icon.textContent = 'dark_mode';
|
|
} else {
|
|
icon.textContent = 'light_mode';
|
|
}
|
|
}
|
|
updateThemeIcon();
|
|
document.getElementById('themeToggle').addEventListener('click', updateThemeIcon);
|
|
|
|
// Adzkaar Modal Functionaliteit
|
|
let countdownSeconds = 5 * 60; // 5 minuten standaard
|
|
let countdownInterval;
|
|
let currentDhikrIndex = 0;
|
|
const totalDhikrs = 6;
|
|
let autoSwitchInterval;
|
|
|
|
function showAdzkaarModal(durationMinutes = 5) {
|
|
countdownSeconds = durationMinutes * 60;
|
|
currentDhikrIndex = 0;
|
|
|
|
// Toon modal
|
|
document.getElementById('adzkaarModal').style.display = 'flex';
|
|
|
|
// Reset dhikr display
|
|
showDhikr(0);
|
|
|
|
// Start countdown
|
|
countdownInterval = setInterval(updateAdzkaarCountdown, 1000);
|
|
updateAdzkaarCountdown();
|
|
|
|
// Start automatische wissel elke 30 seconden
|
|
autoSwitchInterval = setInterval(autoSwitchDhikr, 30000);
|
|
|
|
// Auto-close na ingestelde tijd
|
|
setTimeout(closeAdzkaar, countdownSeconds * 1000);
|
|
}
|
|
|
|
function updateAdzkaarCountdown() {
|
|
const minutes = Math.floor(countdownSeconds / 60);
|
|
const seconds = countdownSeconds % 60;
|
|
const display = `${minutes}:${seconds.toString().padStart(2, '0')}`;
|
|
document.getElementById('countdownTimer').textContent = display;
|
|
|
|
if (countdownSeconds <= 0) {
|
|
closeAdzkaar();
|
|
return;
|
|
}
|
|
|
|
countdownSeconds--;
|
|
}
|
|
|
|
function closeAdzkaar() {
|
|
clearInterval(countdownInterval);
|
|
clearInterval(autoSwitchInterval);
|
|
document.getElementById('adzkaarModal').style.display = 'none';
|
|
}
|
|
|
|
function showDhikr(index) {
|
|
// Verberg alle dhikr items
|
|
document.querySelectorAll('.dhikr-item').forEach(item => {
|
|
item.classList.remove('active');
|
|
});
|
|
|
|
// Toon de geselecteerde dhikr
|
|
const targetDhikr = document.querySelector(`[data-index="${index}"]`);
|
|
if (targetDhikr) {
|
|
targetDhikr.classList.add('active');
|
|
}
|
|
|
|
// Update counter
|
|
document.getElementById('currentDhikr').textContent = index + 1;
|
|
|
|
// Update navigation buttons
|
|
document.getElementById('prevBtn').disabled = index === 0;
|
|
document.getElementById('nextBtn').disabled = index === totalDhikrs - 1;
|
|
}
|
|
|
|
function nextDhikr() {
|
|
if (currentDhikrIndex < totalDhikrs - 1) {
|
|
currentDhikrIndex++;
|
|
showDhikr(currentDhikrIndex);
|
|
}
|
|
}
|
|
|
|
function previousDhikr() {
|
|
if (currentDhikrIndex > 0) {
|
|
currentDhikrIndex--;
|
|
showDhikr(currentDhikrIndex);
|
|
}
|
|
}
|
|
|
|
function autoSwitchDhikr() {
|
|
if (currentDhikrIndex < totalDhikrs - 1) {
|
|
currentDhikrIndex++;
|
|
showDhikr(currentDhikrIndex);
|
|
} else {
|
|
// Als we bij de laatste dhikr zijn, begin opnieuw
|
|
currentDhikrIndex = 0;
|
|
showDhikr(currentDhikrIndex);
|
|
}
|
|
}
|
|
|
|
// Keyboard navigation voor modal
|
|
document.addEventListener('keydown', function(event) {
|
|
const modal = document.getElementById('adzkaarModal');
|
|
if (modal.style.display === 'flex') {
|
|
if (event.key === 'ArrowRight' || event.key === ' ') {
|
|
event.preventDefault();
|
|
nextDhikr();
|
|
} else if (event.key === 'ArrowLeft') {
|
|
event.preventDefault();
|
|
previousDhikr();
|
|
} else if (event.key === 'Escape') {
|
|
closeAdzkaar();
|
|
}
|
|
}
|
|
});
|
|
|
|
// Maak functies globaal beschikbaar
|
|
window.showAdzkaarModal = showAdzkaarModal;
|
|
window.closeAdzkaar = closeAdzkaar;
|
|
window.nextDhikr = nextDhikr;
|
|
window.previousDhikr = previousDhikr;
|
|
</script>
|
|
<script src="/static/countdown.js"></script>
|
|
</body>
|
|
</html>
|