From 193e4bd73b3e010d78ef3fddc8af76cd2641418d Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Fri, 6 Feb 2026 21:28:57 +1100 Subject: [PATCH] feat: implement `` and shortcut tooltip (#21971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #21650 This pull-request adds a `` with `` modifiers to the `Run Task` button describing the shortcut how to submit the prompt quickly without having to navigate to the `↑` button. CleanShot 2026-02-06 at 19 40 58@2x It should be noted that the [keyboard shortcut already existed](https://github.com/coder/coder/blob/jakehwll/21650-submit-prompt-shortcut/site/src/modules/tasks/TaskPrompt/TaskPrompt.tsx#L222-L227) so we don't need to implement that here. ```ts // L222-L227 const handleKeyDown = (e: React.KeyboardEvent) => { // Submit form on Cmd+Enter (Mac) or Ctrl+Enter (Windows/Linux) if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { onSubmit(e); } }; ``` --------- Co-authored-by: Danielle Maywood --- site/src/components/Kbd/Kbd.stories.tsx | 43 +++++++++++++++++ site/src/components/Kbd/Kbd.tsx | 27 +++++++++++ .../modules/tasks/TaskPrompt/TaskPrompt.tsx | 47 ++++++++++++------- site/src/utils/platform.ts | 14 ++++++ 4 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 site/src/components/Kbd/Kbd.stories.tsx create mode 100644 site/src/components/Kbd/Kbd.tsx create mode 100644 site/src/utils/platform.ts diff --git a/site/src/components/Kbd/Kbd.stories.tsx b/site/src/components/Kbd/Kbd.stories.tsx new file mode 100644 index 0000000000..913432ed80 --- /dev/null +++ b/site/src/components/Kbd/Kbd.stories.tsx @@ -0,0 +1,43 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { CommandIcon } from "lucide-react"; +import { Kbd, KbdGroup } from "./Kbd"; + +const meta: Meta = { + title: "components/Kbd", + component: Kbd, + args: { + children: "K", + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const WithIcon: Story = { + args: { + children: , + }, +}; + +export const Group: Story = { + render: () => ( + + + + + Enter + + ), +}; + +export const MultipleKeys: Story = { + render: () => ( + + Ctrl + Shift + P + + ), +}; diff --git a/site/src/components/Kbd/Kbd.tsx b/site/src/components/Kbd/Kbd.tsx new file mode 100644 index 0000000000..d08b0d8dd9 --- /dev/null +++ b/site/src/components/Kbd/Kbd.tsx @@ -0,0 +1,27 @@ +import { cn } from "utils/cn"; + +function Kbd({ className, ...props }: React.ComponentProps<"kbd">) { + return ( + + ); +} +function KbdGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( + + ); +} +export { Kbd, KbdGroup }; diff --git a/site/src/modules/tasks/TaskPrompt/TaskPrompt.tsx b/site/src/modules/tasks/TaskPrompt/TaskPrompt.tsx index a459baedaf..6c65144a96 100644 --- a/site/src/modules/tasks/TaskPrompt/TaskPrompt.tsx +++ b/site/src/modules/tasks/TaskPrompt/TaskPrompt.tsx @@ -11,6 +11,7 @@ import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Button } from "components/Button/Button"; import { ExternalImage } from "components/ExternalImage/ExternalImage"; import { displayError, displaySuccess } from "components/GlobalSnackbar/utils"; +import { Kbd, KbdGroup } from "components/Kbd/Kbd"; import { Link } from "components/Link/Link"; import { Select, @@ -34,6 +35,7 @@ import TextareaAutosize, { type TextareaAutosizeProps, } from "react-textarea-autosize"; import { docs } from "utils/docs"; +import { getOSKey } from "utils/platform"; import { PromptSelectTrigger } from "./PromptSelectTrigger"; import { TemplateVersionSelect } from "./TemplateVersionSelect"; @@ -373,23 +375,34 @@ const CreateTaskForm: FC = ({ templates, onSuccess }) => { /> )} - + + + + + + + {getOSKey()} + + + Enter + + + diff --git a/site/src/utils/platform.ts b/site/src/utils/platform.ts new file mode 100644 index 0000000000..a782c03d02 --- /dev/null +++ b/site/src/utils/platform.ts @@ -0,0 +1,14 @@ +/** + * Returns true if the current platform is macOS. + */ +function isMac(): boolean { + return !!navigator.platform.match("Mac"); +} + +/** + * Returns the platform-appropriate modifier key label: ⌘ on macOS, + * Ctrl on everything else. + */ +export function getOSKey(): string { + return isMac() ? "⌘" : "Ctrl"; +}