feat: code support copy (#1057)

This commit is contained in:
Joel 2023-08-30 18:08:47 +08:00 committed by GitHub
parent a834ba8759
commit e34dcc0406
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 13 deletions

View File

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

View File

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

View File

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