var ALL_ENGINES = [ 'wikipedia', 'arxiv', 'crossref', 'braveapi', 'qwant', 'duckduckgo', 'github', 'reddit', 'bing' ]; var DEFAULT_PREFS = { theme: 'system', engines: ALL_ENGINES.slice(), safeSearch: 'moderate', format: 'html' }; var STORAGE_KEY = 'kafka_prefs'; function loadPrefs() { var stored = localStorage.getItem(STORAGE_KEY); var prefs = DEFAULT_PREFS; if (stored) { try { var parsed = JSON.parse(stored); prefs = { theme: parsed.theme || DEFAULT_PREFS.theme, engines: parsed.engines || DEFAULT_PREFS.engines.slice(), safeSearch: parsed.safeSearch || DEFAULT_PREFS.safeSearch, format: parsed.format || DEFAULT_PREFS.format }; } catch (e) { prefs = DEFAULT_PREFS; } } return prefs; } function savePrefs(prefs) { localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs)); } function applyTheme(theme) { if (theme === 'system') { document.documentElement.removeAttribute('data-theme'); } else { document.documentElement.setAttribute('data-theme', theme); } } function syncEngineInput(prefs) { var input = document.getElementById('engines-input'); if (input) { input.value = prefs.engines.join(','); } } function closePanel() { var popover = document.getElementById('settings-popover'); var trigger = document.getElementById('settings-trigger'); if (popover) { popover.setAttribute('data-open', 'false'); } if (trigger) { trigger.setAttribute('aria-expanded', 'false'); } if (trigger) { trigger.focus(); } } function openPanel() { var popover = document.getElementById('settings-popover'); var trigger = document.getElementById('settings-trigger'); if (popover) { popover.setAttribute('data-open', 'true'); } if (trigger) { trigger.setAttribute('aria-expanded', 'true'); } var firstFocusable = popover ? popover.querySelector('button, input, select, textarea, a[href], [tabindex]:not([tabindex="-1"])') : null; if (firstFocusable) { firstFocusable.focus(); } } function escapeHtml(str) { return String(str).replace(/&/g, '&').replace(//g, '>'); } function renderPanel(prefs) { var panel = document.getElementById('settings-popover'); if (!panel) return; var body = panel.querySelector('.settings-popover-body'); if (!body) return; var themeBtns = ''; ['light', 'dark', 'system'].forEach(function(t) { var icons = { light: '\u2600', dark: '\u263D', system: '\u2318' }; var labels = { light: 'Light', dark: 'Dark', system: 'System' }; var active = prefs.theme === t ? ' active' : ''; themeBtns += ''; }); var engineToggles = ''; ALL_ENGINES.forEach(function(name) { var checked = prefs.engines.indexOf(name) !== -1 ? ' checked' : ''; engineToggles += ''; }); body.innerHTML = '
' + '
Appearance
' + '
' + themeBtns + '
' + '
' + '
' + '
Engines
' + '
' + engineToggles + '
' + '

Engine changes apply to your next search.

' + '
' + '
' + '
Search Defaults
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
'; // Theme buttons var themeBtnEls = panel.querySelectorAll('.theme-btn'); for (var i = 0; i < themeBtnEls.length; i++) { themeBtnEls[i].addEventListener('click', (function(btn) { return function() { prefs.theme = btn.getAttribute('data-theme'); savePrefs(prefs); applyTheme(prefs.theme); syncEngineInput(prefs); renderPanel(prefs); }; })(themeBtnEls[i])); } // Engine checkboxes var checkboxes = panel.querySelectorAll('.engine-toggle input[type="checkbox"]'); for (var j = 0; j < checkboxes.length; j++) { checkboxes[j].addEventListener('change', (function(cb) { return function() { var checked = Array.prototype.slice.call(panel.querySelectorAll('.engine-toggle input[type="checkbox"]:checked')).map(function(el) { return el.value; }); if (checked.length === 0) { renderPanel(prefs); return; } prefs.engines = checked; savePrefs(prefs); syncEngineInput(prefs); }; })(checkboxes[j])); } // Close button var closeBtn = panel.querySelector('.settings-popover-close'); if (closeBtn) closeBtn.addEventListener('click', closePanel); } function initSettings() { var prefs = loadPrefs(); applyTheme(prefs.theme); syncEngineInput(prefs); renderPanel(prefs); var trigger = document.getElementById('settings-trigger'); var triggerMobile = document.getElementById('settings-trigger-mobile'); function togglePanel() { var popover = document.getElementById('settings-popover'); if (popover && popover.getAttribute('data-open') === 'true') { closePanel(); } else { openPanel(); } } if (trigger) { trigger.addEventListener('click', togglePanel); } if (triggerMobile) { triggerMobile.addEventListener('click', togglePanel); } } // Escape key handler document.addEventListener('keydown', function(e) { if (e.key === 'Escape') { var popover = document.getElementById('settings-popover'); if (popover && popover.getAttribute('data-open') === 'true') { closePanel(); } } }); // Click outside handler document.addEventListener('click', function(e) { var popover = document.getElementById('settings-popover'); var trigger = document.getElementById('settings-trigger'); if (popover && popover.getAttribute('data-open') === 'true') { if (!popover.contains(e.target) && (!trigger || !trigger.contains(e.target))) { closePanel(); } } }); // Focus trap document.addEventListener('keydown', function(e) { if (e.key === 'Tab') { var popover = document.getElementById('settings-popover'); if (popover && popover.getAttribute('data-open') === 'true') { var focusableElements = popover.querySelectorAll('button, input, select, textarea, a[href], [tabindex]:not([tabindex="-1"])'); var firstEl = focusableElements[0]; var lastEl = focusableElements[focusableElements.length - 1]; if (e.shiftKey && document.activeElement === firstEl) { e.preventDefault(); lastEl.focus(); } else if (!e.shiftKey && document.activeElement === lastEl) { e.preventDefault(); firstEl.focus(); } } } }); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initSettings); } else { initSettings(); } // Preferences page navigation function initPreferences() { var nav = document.getElementById('preferences-nav'); if (!nav) return; var sections = document.querySelectorAll('.pref-section'); var navItems = nav.querySelectorAll('.preferences-nav-item'); function showSection(id) { sections.forEach(function(sec) { sec.style.display = sec.id === 'section-' + id ? 'block' : 'none'; }); navItems.forEach(function(item) { item.classList.toggle('active', item.getAttribute('data-section') === id); }); } navItems.forEach(function(item) { item.addEventListener('click', function() { showSection(item.getAttribute('data-section')); }); }); // Load saved preferences var prefs = loadPrefs(); // Theme var themeEl = document.getElementById('pref-theme'); if (themeEl) { themeEl.value = prefs.theme || 'system'; themeEl.addEventListener('change', function() { prefs.theme = themeEl.value; savePrefs(prefs); applyTheme(prefs.theme); }); } // Safe search var ssEl = document.getElementById('pref-safesearch'); if (ssEl) { ssEl.value = prefs.safeSearch || 'moderate'; ssEl.addEventListener('change', function() { prefs.safeSearch = ssEl.value; savePrefs(prefs); }); } // Format (if exists on page) var fmtEl = document.getElementById('pref-format'); if (fmtEl) { fmtEl.value = prefs.format || 'html'; fmtEl.addEventListener('change', function() { prefs.format = fmtEl.value; savePrefs(prefs); }); } // Show first section by default showSection('search'); } document.addEventListener('DOMContentLoaded', initPreferences);