Kaynağa Gözat

fix(enterprise): message nav hovercard and active state (#23964)

OpeOginni 2 ay önce
ebeveyn
işleme
14e9e5d9d6

+ 6 - 0
packages/enterprise/src/routes/share/[shareID].tsx

@@ -323,6 +323,12 @@ export default function () {
                                       current={activeMessage()}
                                       size="compact"
                                       onMessageSelect={setActiveMessage}
+                                      getLabel={(message) =>
+                                        data()
+                                          .part[message.id]?.find((part) => part.type === "text")
+                                          ?.text.trim()
+                                          .split("\n")[0]
+                                      }
                                     />
                                   </Show>
                                   <SessionTurn

+ 12 - 8
packages/ui/src/components/message-nav.css

@@ -7,7 +7,7 @@
   list-style: none;
 
   &[data-size="normal"] {
-    width: 240px;
+    width: 200px;
     gap: 4px;
   }
 
@@ -39,6 +39,7 @@
 
   &[data-active] [data-slot="message-nav-tick-line"] {
     background-color: var(--icon-strong-base);
+    height: 2px;
     width: 100%;
   }
 }
@@ -62,11 +63,11 @@
   align-items: center;
   align-self: stretch;
   width: 100%;
-  column-gap: 12px;
+  column-gap: 10px;
   cursor: default;
   border: none;
   background: none;
-  padding: 4px 12px;
+  padding: 4px 10px;
   border-radius: var(--radius-sm);
 }
 
@@ -81,9 +82,15 @@
 
   &[data-active] {
     color: var(--text-strong);
+    font-weight: 500;
   }
 }
 
+[data-slot="message-nav-item"]:has([data-slot="message-nav-title-preview"][data-active])
+  [data-slot="message-nav-message-button"] {
+  background-color: var(--surface-base-active);
+}
+
 [data-slot="message-nav-item"]:hover [data-slot="message-nav-message-button"] {
   background-color: var(--surface-base);
 }
@@ -95,18 +102,15 @@
   color: var(--text-base);
 }
 
-.message-nav-tooltip {
+[data-slot="message-nav-hovercard-content"] {
   z-index: 1000;
-}
-
-[data-slot="message-nav-tooltip-content"] {
   display: flex;
   padding: 4px 4px 6px 4px;
   justify-content: center;
   align-items: start;
   border-radius: var(--radius-md);
   background: var(--surface-raised-stronger-non-alpha);
-  max-height: calc(100vh - 6rem);
+  max-height: min(480px, calc(100vh - 6rem));
   overflow-y: auto;
   overflow-x: hidden;
 

+ 30 - 20
packages/ui/src/components/message-nav.tsx

@@ -1,7 +1,7 @@
 import { UserMessage } from "@opencode-ai/sdk/v2"
-import { ComponentProps, For, Match, Show, splitProps, Switch } from "solid-js"
+import { HoverCard } from "@kobalte/core/hover-card"
+import { ComponentProps, For, Match, Show, createSignal, splitProps, Switch } from "solid-js"
 import { DiffChanges } from "./diff-changes"
-import { Tooltip } from "./tooltip"
 import { useI18n } from "../context/i18n"
 
 export function MessageNav(
@@ -14,18 +14,24 @@ export function MessageNav(
   },
 ) {
   const i18n = useI18n()
-  const [local, others] = splitProps(props, ["messages", "current", "size", "onMessageSelect", "getLabel"])
+  const [local, others] = splitProps(props, ["messages", "current", "size", "onMessageSelect", "getLabel", "class"])
+  const [hovercardOpen, setHovercardOpen] = createSignal(false)
 
-  const content = () => (
-    <ul role="list" data-component="message-nav" data-size={local.size} {...others}>
+  const selectMessage = (message: UserMessage) => {
+    setHovercardOpen(false)
+    local.onMessageSelect(message)
+  }
+
+  const content = (className?: string) => (
+    <ul role="list" data-component="message-nav" data-size={local.size} class={className} {...others}>
       <For each={local.messages}>
         {(message) => {
-          const handleClick = () => local.onMessageSelect(message)
+          const handleClick = () => selectMessage(message)
 
           const handleKeyPress = (event: KeyboardEvent) => {
             if (event.key !== "Enter" && event.key !== " ") return
             event.preventDefault()
-            local.onMessageSelect(message)
+            selectMessage(message)
           }
 
           return (
@@ -70,23 +76,27 @@ export function MessageNav(
   return (
     <Switch>
       <Match when={local.size === "compact"}>
-        <Tooltip
+        <HoverCard
+          open={hovercardOpen()}
+          onOpenChange={setHovercardOpen}
           openDelay={0}
+          closeDelay={120}
           placement="right-start"
-          gutter={-40}
-          shift={-10}
-          overlap
-          contentClass="message-nav-tooltip"
-          value={
-            <div data-slot="message-nav-tooltip-content">
-              <MessageNav {...props} size="normal" class="" />
-            </div>
-          }
+          gutter={8}
+          overflowPadding={24}
+          fitViewport
         >
-          {content()}
-        </Tooltip>
+          <HoverCard.Trigger as="div" data-component="message-nav-hovercard" class={local.class}>
+            {content()}
+          </HoverCard.Trigger>
+          <HoverCard.Portal>
+            <HoverCard.Content data-slot="message-nav-hovercard-content">
+              <MessageNav {...props} size="normal" class="" onMessageSelect={selectMessage} />
+            </HoverCard.Content>
+          </HoverCard.Portal>
+        </HoverCard>
       </Match>
-      <Match when={local.size === "normal"}>{content()}</Match>
+      <Match when={local.size === "normal"}>{content(local.class)}</Match>
     </Switch>
   )
 }