diff options
| author | Adam <[email protected]> | 2025-12-31 11:24:45 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-12-31 13:12:29 -0600 |
| commit | 3a1cfa6c731bc4c33348034cb918b7a4dbe2af8b (patch) | |
| tree | 48bb1174aaa7e7b8c0b9b7a69219e6c4a2338a3a | |
| parent | a2857bba8305976761c55fda269d7fb79c951b8c (diff) | |
| download | opencode-3a1cfa6c731bc4c33348034cb918b7a4dbe2af8b.tar.gz opencode-3a1cfa6c731bc4c33348034cb918b7a4dbe2af8b.zip | |
chore(app): keybind tooltip component
| -rw-r--r-- | packages/app/src/components/prompt-input.tsx | 14 | ||||
| -rw-r--r-- | packages/app/src/pages/layout.tsx | 38 | ||||
| -rw-r--r-- | packages/app/src/pages/session.tsx | 62 | ||||
| -rw-r--r-- | packages/ui/src/components/tooltip.css | 13 | ||||
| -rw-r--r-- | packages/ui/src/components/tooltip.tsx | 20 |
5 files changed, 66 insertions, 81 deletions
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 9cc1579fb..42a8e107a 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -11,7 +11,7 @@ import { useSync } from "@/context/sync" import { FileIcon } from "@opencode-ai/ui/file-icon" import { Button } from "@opencode-ai/ui/button" import { Icon } from "@opencode-ai/ui/icon" -import { Tooltip } from "@opencode-ai/ui/tooltip" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { IconButton } from "@opencode-ai/ui/icon-button" import { Select } from "@opencode-ai/ui/select" import { getDirectory, getFilename } from "@opencode-ai/util/path" @@ -1355,15 +1355,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { </div> </Match> <Match when={store.mode === "normal"}> - <Tooltip - placement="top" - value={ - <div class="flex items-center gap-2"> - <span>Cycle agent</span> - <span class="text-icon-base text-12-medium">{command.keybind("agent.cycle")}</span> - </div> - } - > + <TooltipKeybind placement="top" title="Cycle agent" keybind={command.keybind("agent.cycle")}> <Select options={local.agent.list().map((agent) => agent.name)} current={local.agent.current()?.name ?? ""} @@ -1371,7 +1363,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { class="capitalize" variant="ghost" /> - </Tooltip> + </TooltipKeybind> <Tooltip placement="top" value={ diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index a45c4d792..ce753ecc3 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -22,7 +22,7 @@ import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Button } from "@opencode-ai/ui/button" import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" -import { Tooltip } from "@opencode-ai/ui/tooltip" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { Collapsible } from "@opencode-ai/ui/collapsible" import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { Spinner } from "@opencode-ai/ui/spinner" @@ -709,17 +709,13 @@ export default function Layout(props: ParentProps) { </A> </Tooltip> <div class="hidden group-hover/session:flex group-active/session:flex group-focus-within/session:flex text-text-base gap-1 items-center absolute top-1 right-1"> - <Tooltip + <TooltipKeybind placement={props.mobile ? "bottom" : "right"} - value={ - <div class="flex items-center gap-2"> - <span>Archive session</span> - <span class="text-icon-base text-12-medium">{command.keybind("session.archive")}</span> - </div> - } + title="Archive session" + keybind={command.keybind("session.archive")} > <IconButton icon="archive" variant="ghost" onClick={() => archiveSession(props.session)} /> - </Tooltip> + </TooltipKeybind> </div> </div> </> @@ -787,17 +783,9 @@ export default function Layout(props: ParentProps) { </DropdownMenu.Content> </DropdownMenu.Portal> </DropdownMenu> - <Tooltip - placement="top" - value={ - <div class="flex items-center gap-2"> - <span>New session</span> - <span class="text-icon-base text-12-medium">{command.keybind("session.new")}</span> - </div> - } - > + <TooltipKeybind placement="top" title="New session" keybind={command.keybind("session.new")}> <IconButton as={A} href={`${slug()}/session`} icon="plus-small" variant="ghost" /> - </Tooltip> + </TooltipKeybind> </div> </Button> <Collapsible.Content> @@ -880,15 +868,11 @@ export default function Layout(props: ParentProps) { </A> </Show> <Show when={!sidebarProps.mobile}> - <Tooltip + <TooltipKeybind class="shrink-0" placement="right" - value={ - <div class="flex items-center gap-2"> - <span>Toggle sidebar</span> - <span class="text-icon-base text-12-medium">{command.keybind("sidebar.toggle")}</span> - </div> - } + title="Toggle sidebar" + keybind={command.keybind("sidebar.toggle")} inactive={expanded()} > <Button @@ -920,7 +904,7 @@ export default function Layout(props: ParentProps) { </div> </Show> </Button> - </Tooltip> + </TooltipKeybind> </Show> <DragDropProvider onDragStart={handleDragStart} diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 3e5884460..125dc19d3 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -21,7 +21,7 @@ import { DateTime } from "luxon" import { FileIcon } from "@opencode-ai/ui/file-icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { Icon } from "@opencode-ai/ui/icon" -import { Tooltip } from "@opencode-ai/ui/tooltip" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Tabs } from "@opencode-ai/ui/tabs" @@ -149,17 +149,9 @@ function Header(props: { onMobileMenuToggle?: () => void }) { /> </div> <Show when={currentSession()}> - <Tooltip - class="hidden xl:block" - value={ - <div class="flex items-center gap-2"> - <span>New session</span> - <span class="text-icon-base text-12-medium">{command.keybind("session.new")}</span> - </div> - } - > + <TooltipKeybind class="hidden xl:block" title="New session" keybind={command.keybind("session.new")}> <IconButton as={A} href={`/${params.dir}/session`} icon="edit-small-2" variant="ghost" /> - </Tooltip> + </TooltipKeybind> </Show> </div> <div class="flex items-center gap-3"> @@ -187,14 +179,10 @@ function Header(props: { onMobileMenuToggle?: () => void }) { </div> <div class="flex items-center gap-1"> <Show when={currentSession()?.summary?.files}> - <Tooltip + <TooltipKeybind class="hidden md:block shrink-0" - value={ - <div class="flex items-center gap-2"> - <span>Toggle review</span> - <span class="text-icon-base text-12-medium">{command.keybind("review.toggle")}</span> - </div> - } + title="Toggle review" + keybind={command.keybind("review.toggle")} > <Button variant="ghost" class="group/review-toggle size-6 p-0" onClick={layout.review.toggle}> <div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0"> @@ -215,16 +203,12 @@ function Header(props: { onMobileMenuToggle?: () => void }) { /> </div> </Button> - </Tooltip> + </TooltipKeybind> </Show> - <Tooltip + <TooltipKeybind class="hidden md:block shrink-0" - value={ - <div class="flex items-center gap-2"> - <span>Toggle terminal</span> - <span class="text-icon-base text-12-medium">{command.keybind("terminal.toggle")}</span> - </div> - } + title="Toggle terminal" + keybind={command.keybind("terminal.toggle")} > <Button variant="ghost" class="group/terminal-toggle size-6 p-0" onClick={layout.terminal.toggle}> <div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0"> @@ -245,7 +229,7 @@ function Header(props: { onMobileMenuToggle?: () => void }) { /> </div> </Button> - </Tooltip> + </TooltipKeybind> </div> <Show when={shareEnabled() && currentSession()}> <Popover @@ -1056,13 +1040,9 @@ export default function Page() { </For> </SortableProvider> <div class="bg-background-base h-full flex items-center justify-center border-b border-border-weak-base px-3"> - <Tooltip - value={ - <div class="flex items-center gap-2"> - <span>Open file</span> - <span class="text-icon-base text-12-medium">{command.keybind("file.open")}</span> - </div> - } + <TooltipKeybind + title="Open file" + keybind={command.keybind("file.open")} class="flex items-center" > <IconButton @@ -1071,7 +1051,7 @@ export default function Page() { iconSize="large" onClick={() => dialog.show(() => <DialogSelectFile />)} /> - </Tooltip> + </TooltipKeybind> </div> </Tabs.List> </div> @@ -1178,17 +1158,13 @@ export default function Page() { <For each={terminal.all()}>{(pty) => <SortableTerminalTab terminal={pty} />}</For> </SortableProvider> <div class="h-full flex items-center justify-center"> - <Tooltip - value={ - <div class="flex items-center gap-2"> - <span>New terminal</span> - <span class="text-icon-base text-12-medium">{command.keybind("terminal.new")}</span> - </div> - } + <TooltipKeybind + title="New terminal" + keybind={command.keybind("terminal.new")} class="flex items-center" > <IconButton icon="plus-small" variant="ghost" iconSize="large" onClick={terminal.new} /> - </Tooltip> + </TooltipKeybind> </div> </Tabs.List> <For each={terminal.all()}> diff --git a/packages/ui/src/components/tooltip.css b/packages/ui/src/components/tooltip.css index f7afe16aa..134de6f51 100644 --- a/packages/ui/src/components/tooltip.css +++ b/packages/ui/src/components/tooltip.css @@ -2,6 +2,19 @@ display: flex; } +[data-slot="tooltip-keybind"] { + display: flex; + align-items: center; + gap: 8px; +} + +[data-slot="tooltip-keybind-key"] { + color: var(--icon-base); + font-size: var(--font-size-small); + font-weight: var(--font-weight-medium); + line-height: var(--line-height-large); +} + [data-component="tooltip"] { z-index: 1000; max-width: 320px; diff --git a/packages/ui/src/components/tooltip.tsx b/packages/ui/src/components/tooltip.tsx index b3a2b628f..c38ee5847 100644 --- a/packages/ui/src/components/tooltip.tsx +++ b/packages/ui/src/components/tooltip.tsx @@ -8,6 +8,26 @@ export interface TooltipProps extends ComponentProps<typeof KobalteTooltip> { inactive?: boolean } +export interface TooltipKeybindProps extends Omit<TooltipProps, "value"> { + title: string + keybind: string +} + +export function TooltipKeybind(props: TooltipKeybindProps) { + const [local, others] = splitProps(props, ["title", "keybind"]) + return ( + <Tooltip + {...others} + value={ + <div data-slot="tooltip-keybind"> + <span>{local.title}</span> + <span data-slot="tooltip-keybind-key">{local.keybind}</span> + </div> + } + /> + ) +} + export function Tooltip(props: TooltipProps) { const [open, setOpen] = createSignal(false) const [local, others] = splitProps(props, ["children", "class", "inactive"]) |
