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 str .replace(/&/g, '&') .replace(//g, '>'); } function renderPanel(prefs) { var themeIcons = { light: '☀️', dark: '🌙', system: '⌨' }; var safeOptions = ['moderate', 'strict', 'off']; var formatOptions = ['html', 'json', 'csv', 'rss']; var html = '
'; html += '

Settings

'; // Theme buttons html += '
Theme'; html += '
'; ['light', 'dark', 'system'].forEach(function(t) { var checked = prefs.theme === t ? ' checked' : ''; var icon = escapeHtml(themeIcons[t]); html += ''; }); html += '
'; // Engine checkboxes html += '
Engines'; html += '
'; ALL_ENGINES.forEach(function(engine) { var checked = prefs.engines.indexOf(engine) !== -1 ? ' checked' : ''; html += ''; }); html += '
'; html += '

Engine changes apply to your next search.

'; // Safe search dropdown html += ''; html += ''; // Format dropdown html += ''; html += ''; html += ''; html += '
'; document.body.innerHTML = html; // Attach listeners to theme buttons var themeButtons = document.querySelectorAll('input[name="theme"]'); themeButtons.forEach(function(btn) { btn.addEventListener('click', function() { var newPrefs = loadPrefs(); newPrefs.theme = btn.value; savePrefs(newPrefs); applyTheme(newPrefs.theme); }); }); // Attach listeners to engine checkboxes var engineCheckboxes = document.querySelectorAll('input[name="engine"]'); engineCheckboxes.forEach(function(cb) { cb.addEventListener('change', function() { var newPrefs = loadPrefs(); if (cb.checked) { if (newPrefs.engines.indexOf(cb.value) === -1) { newPrefs.engines.push(cb.value); } } else { newPrefs.engines = newPrefs.engines.filter(function(e) { return e !== cb.value; }); } savePrefs(newPrefs); syncEngineInput(newPrefs); }); }); // Attach listener to safe search dropdown var safeSelect = document.getElementById('safe-search-select'); if (safeSelect) { safeSelect.addEventListener('change', function() { var newPrefs = loadPrefs(); newPrefs.safeSearch = safeSelect.value; savePrefs(newPrefs); }); } // Attach listener to format dropdown var formatSelect = document.getElementById('format-select'); if (formatSelect) { formatSelect.addEventListener('change', function() { var newPrefs = loadPrefs(); newPrefs.format = formatSelect.value; savePrefs(newPrefs); }); } // Attach listener to close button var closeBtn = document.getElementById('settings-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(); }