diff --git a/client/components/command_palette.tsx b/client/components/command_palette.tsx index 7865501d..f2ab5400 100644 --- a/client/components/command_palette.tsx +++ b/client/components/command_palette.tsx @@ -47,7 +47,7 @@ export function CommandPalette({ ); } -function keyboardHint(def: Command): string | undefined { +export function keyboardHint(def: { key?: string | string[]; mac?: string | string[] }): string | undefined { const shortcuts: string[] = []; if (isMacLike && def.mac) { if (Array.isArray(def.mac)) { diff --git a/client/editor_ui.tsx b/client/editor_ui.tsx index 0ffca98a..b69e4e60 100644 --- a/client/editor_ui.tsx +++ b/client/editor_ui.tsx @@ -1,5 +1,8 @@ import { Confirm, Prompt } from "./components/basic_modals.tsx"; -import { CommandPalette } from "./components/command_palette.tsx"; +import { + CommandPalette, + keyboardHint, +} from "./components/command_palette.tsx"; import { FilterList } from "./components/filter.tsx"; import { AnythingPicker } from "./components/anything_picker.tsx"; import { TopBar } from "./components/top_bar.tsx"; @@ -488,18 +491,33 @@ export class MainUI { if (!featherIcon) { featherIcon = featherIcons.HelpCircle; } + // Build description with keyboard shortcut hint + let description = button.description || ""; + if (button.command) { + const cmd = viewState.commands.get(button.command); + if (cmd) { + const hint = keyboardHint(cmd); + if (hint) { + description = description + ? `${description} (${hint})` + : hint; + } + } + } + return { icon: mdiIcon ? mdiIcon : featherIcon, - description: button.description || "", + description, dropdown: button.dropdown, - callback: - button.run || - (() => { - this.flashNotification( - "actionButton did not specify a run() callback", - "error", - ); - }), + callback: button.command + ? () => this.client.runCommandByName(button.command!) + : button.run || + (() => { + this.flashNotification( + "actionButton did not specify a command or run() callback", + "error", + ); + }), href: "", }; }), @@ -620,11 +638,12 @@ export class MainUI { type ActionButton = { icon: string; description?: string; + command?: string; mobile?: boolean; standalone?: boolean; dropdown?: boolean; priority?: number; - run: () => void; + run?: () => void; }; function kebabToCamel(str: string) { diff --git a/libraries/Library/Std/APIs/Action Button.md b/libraries/Library/Std/APIs/Action Button.md index 8af8a19b..3f4e339e 100644 --- a/libraries/Library/Std/APIs/Action Button.md +++ b/libraries/Library/Std/APIs/Action Button.md @@ -10,21 +10,28 @@ APIs to more conveniently define action buttons (alternative to setting them via Keys to define: * `icon`: [feather icon](https://feathericons.com) to use for your button -* `run`: function to invoke once the button is pushed +* `command` (optional): command name to invoke when clicked. When set, the command's keyboard shortcut is automatically shown in the tooltip. Replaces `run`. +* `run` (optional): function to invoke once the button is pushed. Use this for custom logic that doesn't map to a single command. * `description` (optional): description of button (appears on hover) * `priority` (optional): determines priority of button (the higher, the earlier in the list) * `mobile`: when set to `true` this button will only appear on mobile devices * `standalone`: when set to `true` this button will only appear in standalone/PWA mode; when `false`, only in browser mode * `dropdown` (optional): when set to `false`, the button stays visible outside the dropdown menu on mobile (default: `true`) -# Example +Either `command` or `run` should be specified. + +# Examples ```lua --- Defines a new button that forces your UI into read-only mode +-- Bind a button to a command (keyboard shortcut shown on hover) +actionButton.define { + icon = "pen-tool", + description = "Start journaling", + command = "Journal: Today", +} + +-- Custom button with a run function actionButton.define { icon = "eye", - -- Uncomment the following line to only make this button appear - -- ONLY on mobile devices: - -- mobile = true, run = function() editor.setUiOption("forcedROMode", true) editor.rebuildEditorState() diff --git a/libraries/Library/Std/Config.md b/libraries/Library/Std/Config.md index 073b7a71..62922769 100644 --- a/libraries/Library/Std/Config.md +++ b/libraries/Library/Std/Config.md @@ -358,6 +358,10 @@ config.define("actionButtons", { type = "string", description = "Optional description of the action button" }, + command = { + type = "string", + description = "Optional command name to invoke when clicked (replaces run). The command's keyboard shortcut is automatically shown in the tooltip." + }, priority = { type = "number", description = "Optional priority: the higher the earlier the button will appear in the list" @@ -376,7 +380,7 @@ config.define("actionButtons", { }, run = schema.func(), }, - required = {"icon", "run"}, + required = {"icon"}, additionalProperties = false } }) @@ -399,28 +403,22 @@ config.set { { icon = "home", description = "Go to the index page", + command = "Navigate: Home", priority = 3, dropdown = false, - run = function() - editor.invokeCommand "Navigate: Home" - end }, { icon = "book", description = "Open page", + command = "Navigate: Page Picker", priority = 2, dropdown = false, - run = function() - editor.invokeCommand "Navigate: Page Picker" - end }, { icon = "terminal", description = "Run command", + command = "Open Command Palette", priority = 1, - run = function() - editor.invokeCommand "Open Command Palette" - end, }, { icon = "chevron-left", diff --git a/website/Guide/Journaling.md b/website/Guide/Journaling.md index f12be309..127b6819 100644 --- a/website/Guide/Journaling.md +++ b/website/Guide/Journaling.md @@ -31,9 +31,7 @@ Optionally, you may also create an [[^Library/Std/APIs/Action Button]] in your t actionButton.define { icon = "pen-tool", priority = 3, -- or whatever order puts it in the spot you like - run = function() - editor.invokeCommand "Journal: Today" - end + command = "Journal: Today", } ```