Files

187 lines
6.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
document.addEventListener('DOMContentLoaded', () => {
initTheme();
initFooterYear();
initMobileMenu();
fetchPageData();
});
/* -------------------------------------------------------------------------- */
/* Theme / Dark Mode Management */
/* -------------------------------------------------------------------------- */
function initTheme() {
const isDarkStored = localStorage.theme === 'dark';
const noThemeStored = !('theme' in localStorage);
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (isDarkStored || (noThemeStored && prefersDark)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
updateThemeUI();
document.querySelectorAll('.theme-toggle').forEach(button => {
button.addEventListener('click', toggleDarkMode);
});
}
function toggleDarkMode() {
const isDark = document.documentElement.classList.toggle('dark');
localStorage.theme = isDark ? 'dark' : 'light';
updateThemeUI();
}
function updateThemeUI() {
const isDark = document.documentElement.classList.contains('dark');
document.querySelectorAll('.icon-sun').forEach(el => el.classList.toggle('hidden', !isDark));
document.querySelectorAll('.icon-moon').forEach(el => el.classList.toggle('hidden', isDark));
document.querySelectorAll('.theme-text').forEach(el => {
el.textContent = isDark ? '☀️ Light Mode' : '🌙 Dark Mode';
});
}
/* -------------------------------------------------------------------------- */
/* Footer Year Handler */
/* -------------------------------------------------------------------------- */
function initFooterYear() {
const yearEl = document.getElementById('current-year');
if (yearEl) {
yearEl.textContent = new Date().getFullYear();
}
}
/* -------------------------------------------------------------------------- */
/* Mobile Menu Toggle */
/* -------------------------------------------------------------------------- */
function initMobileMenu() {
const menuToggleBtn = document.getElementById('menu-toggle');
const mobileMenu = document.getElementById('mobile-menu');
const iconHamburger = document.getElementById('icon-hamburger');
const iconClose = document.getElementById('icon-close');
if (!menuToggleBtn || !mobileMenu) return;
menuToggleBtn.setAttribute('aria-expanded', 'false');
menuToggleBtn.addEventListener('click', () => {
const isHidden = mobileMenu.classList.toggle('hidden');
menuToggleBtn.setAttribute('aria-expanded', String(!isHidden));
iconHamburger.classList.toggle('hidden', !isHidden);
iconClose.classList.toggle('hidden', isHidden);
});
}
/* -------------------------------------------------------------------------- */
/* Async Data Fetching (Pages, Banner & Exam Schedule) */
/* -------------------------------------------------------------------------- */
async function fetchPageData() {
const currentPath = window.location.pathname;
// 1. Fetch Banner Data
try {
const bannerResp = await fetch(`/assets/banner.json?t=${Date.now()}`);
if (bannerResp.ok) {
const banner = await bannerResp.json();
if (banner && banner.title && banner.content) {
document.getElementById('banner-title').textContent = banner.title;
document.getElementById('banner-content').textContent = banner.content;
document.getElementById('banner').classList.remove('hidden');
}
}
} catch (err) {
console.error('Failed to load banner data:', err);
}
// 2. Fetch Navigation Links
try {
const navResp = await fetch('/assets/pages.json');
if (navResp.ok) {
const pages = await navResp.json();
renderNavigation(pages, currentPath);
}
} catch (err) {
console.error('Failed to load navigation data:', err);
}
// 3. Fetch Exam Schedule (only runs if the #exams-list element exists)
const examsContainer = document.getElementById('exams-list');
if (examsContainer) {
try {
const examResp = await fetch(`/assets/exams.json?t=${Date.now()}`);
if (examResp.ok) {
const exams = await examResp.json();
renderExams(exams, examsContainer);
}
} catch (err) {
console.error('Failed to load exam data:', err);
}
}
// 4. Fetch Net Check-In Data (only runs on pages containing #callsigns-list or #weekly-list)
const callsignsContainer = document.getElementById('callsigns-list');
const weeklyContainer = document.getElementById('weekly-list');
if (callsignsContainer || weeklyContainer) {
try {
const netResp = await fetch('/net/net.json');
if (netResp.ok) {
const data = await netResp.json();
renderNetStats(data, callsignsContainer, weeklyContainer);
}
} catch (err) {
console.error('Failed to load net statistics data:', err);
}
}
}
function renderNavigation(pages, currentPath) {
const desktopContainer = document.getElementById('desktop-links');
const mobileContainer = document.getElementById('mobile-links');
if (!desktopContainer || !mobileContainer) return;
desktopContainer.innerHTML = '';
mobileContainer.innerHTML = '';
pages.forEach(page => {
const desktopLink = document.createElement('a');
desktopLink.href = page.path;
desktopLink.textContent = page.name;
if (currentPath === page.path) desktopLink.classList.add('active');
desktopContainer.appendChild(desktopLink);
const mobileLink = document.createElement('a');
mobileLink.href = page.path;
mobileLink.textContent = page.name;
if (currentPath === page.path) mobileLink.classList.add('active');
mobileContainer.appendChild(mobileLink);
});
}
function renderExams(exams, container) {
container.innerHTML = '';
if (Array.isArray(exams) && exams.length > 0) {
exams.forEach(exam => {
const li = document.createElement('li');
li.append(`${exam.date}, ${exam.time} – ${exam.location} – `);
const link = document.createElement('a');
link.href = exam.register;
link.className = 'link';
link.target = '_blank';
link.rel = 'noopener';
link.textContent = 'Register here';
li.appendChild(link);
container.appendChild(li);
});
} else {
const li = document.createElement('li');
li.textContent = "We don't have any sessions scheduled right now, but if you're ready to test let us know and we'll set one up!";
container.appendChild(li);
}
}