3 KiB
3 KiB
Settings UI Design — kafka
Date: 2026-03-22 Status: Approved
Overview
A lightweight preferences popover anchored to the top-right, just below the header. Triggered by a gear icon, it lets users adjust theme, enabled engines, and search defaults without leaving their current page. All changes auto-save to localStorage on every interaction.
Layout & Structure
- Trigger: Gear icon (⚙️) in the top-right header, aligned with the header's right edge
- Panel: 280px wide, max-height 420px, scrollable internally, rounded corners, subtle shadow, anchored top-right (drops down from trigger, like a dropdown)
- Close: × button in panel header, click outside the panel, or pressing Escape
- No Save button — every interaction immediately writes to
localStorage
Interaction Flow
- User clicks ⚙️ → panel drops down from top-right (200ms ease)
- User toggles/clicks → changes apply instantly to DOM + write to
localStorage - User clicks × or outside or Escape → panel closes, settings persist
- Accessibility: Focus is trapped within the panel while open. Trigger button uses
aria-expandedandaria-controls. Escape key closes the panel.
Mid-Search Changes
When opened during an active search on results.html:
- Engine toggles update
localStorageimmediately, but current results remain unchanged - A subtle inline note below the engines section: "Engine changes apply to your next search"
Sections
Appearance
- Three theme buttons: ☀️ Light / 🌙 Dark / 💻 System
- Clicking immediately applies via
document.body.classList+ writes to localStorage - "System" reads
prefers-color-schemeand updates on change
Engines
- 2-column grid of toggle switches for all 9 engines
- Each row: engine name + toggle switch
- Enabled = filled accent color; Disabled = gray outline
Search Defaults
- Safe search: dropdown (Moderate / Strict / Off)
- Default format: dropdown (HTML / JSON / CSV)
Default State
const DEFAULT_PREFS = {
theme: "system",
engines: ["wikipedia", "arxiv", "crossref", "braveapi", "qwant", "duckduckgo", "github", "reddit", "bing"],
safeSearch: "moderate",
format: "html"
};
Persistence
// Written on every interaction
localStorage.setItem('kafka_prefs', JSON.stringify({ ... }));
// Read on page load — merge with DEFAULT_PREFS
const saved = JSON.parse(localStorage.getItem('kafka_prefs') || '{}');
const prefs = { ...DEFAULT_PREFS, ...saved };
Responsive Behavior
- Mobile (<768px): Panel becomes a bottom sheet — 100% width, slides up from the bottom, top corners rounded, max-height 70vh. Trigger moves to a fixed bottom-right FAB button.
- Panel never covers the search input
Applied to Existing Code
base.html— add gear button in header, panel markup at end of<body>kafka.css— popover styles, toggle switch styles, bottom sheet styles for mobilesettings.js— localStorage read/write, theme application, panel toggle, aria attributes, focus trap