const THEME_KEY = 'gpa1-theme'; const FONT_ENG_KEY = 'gpa1-font-english'; const FONT_AR_KEY = 'gpa1-font-arabic'; const SIZE_ENG_KEY = 'gpa1-size-english'; const SIZE_AR_KEY = 'gpa1-size-arabic'; const ENGLISH_DEFAULT = 16; const ARABIC_DEFAULT = 24; const ENGLISH_MIN = 13; const ENGLISH_MAX = 22; const ARABIC_MIN = 18; const ARABIC_MAX = 36; const SIZE_STEP = 1; const englishFonts: Record = { systemSans: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', serif: 'Georgia, "Times New Roman", Times, serif', reading: 'Inter, Arial, Helvetica, sans-serif', }; const arabicFonts: Record = { arabicNaskh: '"Noto Naskh Arabic", "Amiri", "Scheherazade New", serif', arabicUi: 'Tahoma, "Arial", sans-serif', arabicSerif: '"Amiri", "Noto Serif", serif', }; function clamp(value: number, min: number, max: number) { return Math.min(max, Math.max(min, value)); } function getStoredString(key: string, fallback: string) { try { return window.localStorage.getItem(key) || fallback; } catch { return fallback; } } function getStoredNumber(key: string, fallback: number) { try { const value = Number(window.localStorage.getItem(key)); return Number.isFinite(value) ? value : fallback; } catch { return fallback; } } function setStoredValue(key: string, value: string) { try { window.localStorage.setItem(key, value); } catch { // Ignore storage failures gracefully. } } function applyTheme(theme: string) { const resolvedTheme = theme === 'dark' ? 'dark' : 'light'; document.documentElement.setAttribute('data-bs-theme', resolvedTheme); document.documentElement.setAttribute('data-gpa1-theme', theme); document.querySelectorAll('[data-setting-theme]').forEach((button) => { const isActive = button.dataset.settingTheme === theme; button.classList.toggle('active', isActive); button.setAttribute('aria-pressed', String(isActive)); }); } function applyEnglishFont(value: string) { const resolvedValue = value in englishFonts ? value : 'systemSans'; document.documentElement.style.setProperty('--gpa1-font-english', englishFonts[resolvedValue]); document.documentElement.setAttribute('data-gpa1-font-english', resolvedValue); const select = document.querySelector('[data-setting-font="english"]'); if (select) select.value = resolvedValue; return resolvedValue; } function applyArabicFont(value: string) { const resolvedValue = value in arabicFonts ? value : 'arabicNaskh'; document.documentElement.style.setProperty('--gpa1-font-arabic', arabicFonts[resolvedValue]); document.documentElement.setAttribute('data-gpa1-font-arabic', resolvedValue); const select = document.querySelector('[data-setting-font="arabic"]'); if (select) select.value = resolvedValue; return resolvedValue; } function applyEnglishSize(value: number) { const size = clamp(value, ENGLISH_MIN, ENGLISH_MAX); document.documentElement.style.setProperty('--gpa1-font-size-english', `${size}px`); document.documentElement.setAttribute('data-gpa1-size-english', String(size)); const output = document.getElementById('settings-size-english'); if (output) output.textContent = `${size}px`; return size; } function applyArabicSize(value: number) { const size = clamp(value, ARABIC_MIN, ARABIC_MAX); document.documentElement.style.setProperty('--gpa1-font-size-arabic', `${size}px`); document.documentElement.setAttribute('data-gpa1-size-arabic', String(size)); const output = document.getElementById('settings-size-arabic'); if (output) output.textContent = `${size}px`; return size; } function syncInitialState() { const initialTheme = getStoredString(THEME_KEY, document.documentElement.getAttribute('data-gpa1-theme') || 'light'); const initialEnglishFont = getStoredString(FONT_ENG_KEY, document.documentElement.getAttribute('data-gpa1-font-english') || 'systemSans'); const initialArabicFont = getStoredString(FONT_AR_KEY, document.documentElement.getAttribute('data-gpa1-font-arabic') || 'arabicNaskh'); const initialEnglishSize = getStoredNumber(SIZE_ENG_KEY, Number(document.documentElement.getAttribute('data-gpa1-size-english')) || ENGLISH_DEFAULT); const initialArabicSize = getStoredNumber(SIZE_AR_KEY, Number(document.documentElement.getAttribute('data-gpa1-size-arabic')) || ARABIC_DEFAULT); applyTheme(initialTheme); applyEnglishFont(initialEnglishFont); applyArabicFont(initialArabicFont); applyEnglishSize(initialEnglishSize); applyArabicSize(initialArabicSize); } function initSettingsPanel() { syncInitialState(); document.querySelectorAll('[data-setting-theme]').forEach((button) => { button.addEventListener('click', () => { const theme = button.dataset.settingTheme || 'light'; applyTheme(theme); setStoredValue(THEME_KEY, theme); }); }); document.querySelector('[data-setting-font="english"]')?.addEventListener('change', (event) => { const value = applyEnglishFont((event.currentTarget as HTMLSelectElement).value); setStoredValue(FONT_ENG_KEY, value); }); document.querySelector('[data-setting-font="arabic"]')?.addEventListener('change', (event) => { const value = applyArabicFont((event.currentTarget as HTMLSelectElement).value); setStoredValue(FONT_AR_KEY, value); }); document.querySelectorAll('[data-size-step]').forEach((button) => { button.addEventListener('click', () => { const direction = button.dataset.sizeStep; const target = button.dataset.sizeTarget; if (target === 'english') { const current = getStoredNumber(SIZE_ENG_KEY, ENGLISH_DEFAULT); const next = applyEnglishSize(current + (direction === 'up' ? SIZE_STEP : -SIZE_STEP)); setStoredValue(SIZE_ENG_KEY, String(next)); } if (target === 'arabic') { const current = getStoredNumber(SIZE_AR_KEY, ARABIC_DEFAULT); const next = applyArabicSize(current + (direction === 'up' ? SIZE_STEP : -SIZE_STEP)); setStoredValue(SIZE_AR_KEY, String(next)); } }); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initSettingsPanel, { once: true }); } else { initSettingsPanel(); }