Recipes
Settings menus
Build nested, toggleable settings that update in place with ctx.render.
Settings are a great fit for the bar: users can change a preference without visiting a settings page. The trick is ctx.render, which re-renders the current view after a change so the checkmarks stay accurate.
import { grid, list, type ListView } from '@qikbar/qikbar'
function settingsView(): ListView {
const s = store.settings
const toggle = (key: keyof typeof s, label: string, icon: string) => ({
id: key,
title: label,
icon,
section: 'Preferences',
accessories: [{ tag: s[key] ? { value: 'On', color: 'green' } : { value: 'Off', color: 'gray' } }],
run: (ctx) => {
store.update({ [key]: !s[key] })
ctx.render(settingsView()) // re-render in place
return false // keep the bar open
},
})
return list({
title: 'Settings',
items: [
toggle('compactMode', 'Compact mode', 'list'),
toggle('emailDigest', 'Weekly email digest', 'mail'),
toggle('sounds', 'Sounds', 'bell'),
{
title: 'Language',
subtitle: s.language,
icon: 'languages',
section: 'Region',
view: grid({
title: 'Language',
columns: 4,
items: LANGUAGES.map((l) => ({
title: l.name,
subtitle: l.native,
icon: l.flag, // an emoji
run: (ctx) => {
store.update({ language: l.code })
ctx.pop()
return false
},
})),
}),
},
],
})
}
export const settingsCommand = { title: 'Settings', icon: 'settings', shortcut: 'mod+,', view: settingsView }
Because ctx.render keeps the query and selection, users can type “sound”, press ↵ repeatedly, and watch the toggle flip.
ctx.pop() followed by return false goes back one level and keeps the bar open. Omit return false to close the bar after the change.