07akioni 1 месяц назад
Родитель
Сommit
57d6d9ee1c
1 измененных файлов с 39 добавлено и 28 удалено
  1. 39 28
      packages/client/ui-conversation/src/client/chat/MessageItem.tsx

+ 39 - 28
packages/client/ui-conversation/src/client/chat/MessageItem.tsx

@@ -142,41 +142,52 @@ function projectUserText(text: string): ReactNode {
   return <>{parts}</>
 }
 
+/** Right-aligned bubble shared by user and steering rows (steering has no actions). */
+function UserStyleBubble({
+  content, actions, t,
+}: {
+  content: readonly unknown[]
+  /** Optional IconActions (or similar) below the bubble; receives the joined text. */
+  actions?: (text: string) => ReactNode
+  t: ChatViewSlotProps['t']
+}): ReactNode {
+  const { text, rest } = contentText(content)
+  const truncated = (total: number): string => t('json.truncated', { total })
+  return (
+    <div className={css.userRow}>
+      <div className={css.bubble}>
+        {projectUserText(text)}
+        {rest.map((block, i) => <JsonBlock key={i} label={t('message.extraBlock')} payload={block} truncatedLabel={truncated} />)}
+      </div>
+      {actions?.(text)}
+    </div>
+  )
+}
+
 export const MessageItem = memo(function MessageItem({
   node, retryActive = false, onFork, t,
 }: MessageItemProps) {
   const truncated = (total: number): string => t('json.truncated', { total })
   switch (node.kind) {
-    case 'user': {
-      const { text, rest } = contentText(node.content)
+    case 'user':
       return (
-        <div className={css.userRow}>
-          <div className={css.bubble}>
-            {projectUserText(text)}
-            {rest.map((block, i) => <JsonBlock key={i} label={t('message.extraBlock')} payload={block} truncatedLabel={truncated} />)}
-          </div>
-          <MessageIconActions
-            text={text}
-            time={node.time}
-            clock="start"
-            onBranch={onFork === undefined ? undefined : () => { onFork(node.seq) }}
-            className={css.actions}
-            t={t}
-          />
-        </div>
-      )
-    }
-    case 'steering': {
-      const { text, rest } = contentText(node.content)
-      return (
-        <div className={css.userRow}>
-          <div className={css.bubble}>
-            {projectUserText(text)}
-            {rest.map((block, i) => <JsonBlock key={i} label={t('message.extraBlock')} payload={block} truncatedLabel={truncated} />)}
-          </div>
-        </div>
+        <UserStyleBubble
+          content={node.content}
+          t={t}
+          actions={text => (
+            <MessageIconActions
+              text={text}
+              time={node.time}
+              clock="start"
+              onBranch={onFork === undefined ? undefined : () => { onFork(node.seq) }}
+              className={css.actions}
+              t={t}
+            />
+          )}
+        />
       )
-    }
+    case 'steering':
+      return <UserStyleBubble content={node.content} t={t} />
     case 'context':
       return (
         <ContextInjectionRow content={node.content} source={node.source} t={t} />