Ver código fonte

feat: code support copy (#1057)

Joel 1 ano atrás
pai
commit
e34dcc0406

+ 9 - 5
web/app/components/app/chat/copy-btn/index.tsx

@@ -8,32 +8,36 @@ import Tooltip from '@/app/components/base/tooltip'
 type ICopyBtnProps = {
   value: string
   className?: string
+  isPlain?: boolean
 }
 
 const CopyBtn = ({
   value,
   className,
+  isPlain,
 }: ICopyBtnProps) => {
   const [isCopied, setIsCopied] = React.useState(false)
 
   return (
     <div className={`${className}`}>
       <Tooltip
-        selector="copy-btn-tooltip"
+        selector={`copy-btn-tooltip-${value}`}
         content={(isCopied ? t('appApi.copied') : t('appApi.copy')) as string}
         className='z-10'
       >
         <div
           className={'box-border p-0.5 flex items-center justify-center rounded-md bg-white cursor-pointer'}
-          style={{
-            boxShadow: '0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)',
-          }}
+          style={!isPlain
+            ? {
+              boxShadow: '0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)',
+            }
+            : {}}
           onClick={() => {
             copy(value)
             setIsCopied(true)
           }}
         >
-          <div className={`w-6 h-6 hover:bg-gray-50  ${s.copyIcon} ${isCopied ? s.copied : ''}`}></div>
+          <div className={`w-6 h-6 rounded-md hover:bg-gray-50  ${s.copyIcon} ${isCopied ? s.copied : ''}`}></div>
         </div>
       </Tooltip>
     </div>

+ 37 - 8
web/app/components/base/markdown.tsx

@@ -8,6 +8,8 @@ import SyntaxHighlighter from 'react-syntax-highlighter'
 import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'
 import type { RefObject } from 'react'
 import { useEffect, useRef, useState } from 'react'
+import CopyBtn from '@/app/components/app/chat/copy-btn'
+
 // import { copyToClipboard } from "../utils";
 // https://txtfiddle.com/~hlshwya/extract-urls-from-text
 // const urlRegex = /\b((https?|ftp|file):\/\/|(www|ftp)\.)[-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/ig
@@ -61,6 +63,7 @@ const useLazyLoad = (ref: RefObject<Element>): boolean => {
 }
 
 export function Markdown(props: { content: string }) {
+  const [isCopied, setIsCopied] = useState(false)
   return (
     <div className="markdown-body">
       <ReactMarkdown
@@ -71,16 +74,42 @@ export function Markdown(props: { content: string }) {
         components={{
           code({ node, inline, className, children, ...props }) {
             const match = /language-(\w+)/.exec(className || '')
+            const language = match?.[1]
+            const languageShowName = (() => {
+              if (language)
+                return language.charAt(0).toUpperCase() + language.substring(1)
+
+              return 'Plain'
+            })()
             return (!inline && match)
               ? (
-                <SyntaxHighlighter
-                  {...props}
-                  children={String(children).replace(/\n$/, '')}
-                  style={atelierHeathLight}
-                  language={match[1]}
-                  showLineNumbers
-                  PreTag="div"
-                />
+                <div>
+                  <div
+                    className='flex justify-between h-8 items-center p-1 pl-3 border-b'
+                    style={{
+                      borderColor: 'rgba(0, 0, 0, 0.05)',
+                    }}
+                  >
+                    <div className='text-[13px] text-gray-500 font-normal'>{languageShowName}</div>
+                    <CopyBtn
+                      value={String(children).replace(/\n$/, '')}
+                      isPlain
+                    />
+                  </div>
+                  <SyntaxHighlighter
+                    {...props}
+                    style={atelierHeathLight}
+                    customStyle={{
+                      paddingLeft: 12,
+                      backgroundColor: '#fff',
+                    }}
+                    language={match[1]}
+                    showLineNumbers
+                    PreTag="div"
+                  >
+                    {String(children).replace(/\n$/, '')}
+                  </SyntaxHighlighter>
+                </div>
               )
               : (
                 <code {...props} className={className}>

+ 4 - 0
web/app/styles/markdown.scss

@@ -774,6 +774,10 @@
   border-radius: 6px;
 }
 
+.markdown-body pre {
+  padding: 0;
+}
+
 .markdown-body pre code,
 .markdown-body pre tt {
   display: inline-block;