Command
A search field over every command, filtered as you type and run by Enter.
New page
Search pages
Change theme
Billing
Invite members
Nothing run yet
forSlots(CommandSlots)(Recipes.Command({}))
Usage
The function that drew the preview, over the theme module Create a theme writes. The preview passes it the style picked above instead of its default.
export const CommandStyle = forSlots(CommandSlots)(Recipes.Command({}))
/** The command menu's query and highlighted row, and the Messages that move them. */
export interface CommandState {
readonly query: string
readonly active: Option.Option<string>
readonly ran: Option.Option<string>
}
export interface CommandMessages<Message> {
readonly onQuery: (query: string) => Message
readonly onActive: (value: string) => Message
readonly onRun: (value: string) => Message
}
export const command = <Message>(
style: NamedStyle<typeof CommandSlots>,
state: CommandState,
messages: CommandMessages<Message>,
h: HtmlBuilder<Message>,
): Html =>
h.div(
[h.Style({ display: 'grid', gap: '0.75rem', justifyItems: 'start' })],
[
Command.view(
{
id: 'palette',
label: 'Search commands',
placeholder: 'Type a command or search…',
groups: [
{
heading: 'Suggestions',
items: [
{ value: 'new-page', label: 'New page', shortcut: '⌘N' },
{ value: 'search', label: 'Search pages', keywords: ['find'], shortcut: '⌘K' },
],
},
{
heading: 'Settings',
items: [
{ value: 'theme', label: 'Change theme', keywords: ['dark', 'light'] },
{ value: 'billing', label: 'Billing', disabled: true },
{ value: 'members', label: 'Invite members', keywords: ['team'] },
],
},
],
query: state.query,
onQuery: messages.onQuery,
active: state.active,
onActive: messages.onActive,
onRun: messages.onRun,
style,
},
h,
),
h.p(
[],
[
Option.match(state.ran, {
onNone: () => 'Nothing run yet',
onSome: value => `Ran ${value}`,
}),
],
),
],
)