Ver código fonte

chore(app): keybind tooltip component

Adam 1 mês atrás
pai
commit
3a1cfa6c73

+ 3 - 11
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={

+ 11 - 27
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}

+ 19 - 43
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()}>

+ 13 - 0
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;

+ 20 - 0
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"])