Files
byuiars-reop-net/script.js
T

187 lines
6.5 KiB
JavaScript
Raw Normal View History

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);
}
}