mirror of
https://github.com/wassname/chatGPTBox.git
synced 2026-07-25 13:10:34 +08:00
138 lines
4.5 KiB
React
138 lines
4.5 KiB
React
import { useState } from 'react'
|
|
import { ChevronDownIcon, XCircleIcon, SyncIcon } from '@primer/octicons-react'
|
|
import CopyButton from '../CopyButton'
|
|
import PropTypes from 'prop-types'
|
|
import MarkdownRender from '../MarkdownRender/markdown.jsx'
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
export function ConversationItem({ type, content, session, done, port, onRetry }) {
|
|
const { t } = useTranslation()
|
|
const [collapsed, setCollapsed] = useState(false)
|
|
|
|
switch (type) {
|
|
case 'question':
|
|
return (
|
|
<div className={type} dir="auto">
|
|
<div className="gpt-header">
|
|
<p>{t('You')}:</p>
|
|
<div className="gpt-util-group">
|
|
<CopyButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
|
|
{!collapsed ? (
|
|
<span
|
|
title={t('Collapse')}
|
|
className="gpt-util-icon"
|
|
onClick={() => setCollapsed(true)}
|
|
>
|
|
<XCircleIcon size={14} />
|
|
</span>
|
|
) : (
|
|
<span
|
|
title={t('Expand')}
|
|
className="gpt-util-icon"
|
|
onClick={() => setCollapsed(false)}
|
|
>
|
|
<ChevronDownIcon size={14} />
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{!collapsed && <MarkdownRender>{content}</MarkdownRender>}
|
|
</div>
|
|
)
|
|
case 'answer':
|
|
return (
|
|
<div className={type} dir="auto">
|
|
<div className="gpt-header">
|
|
<p style="white-space: nowrap;">
|
|
{session && session.aiName ? `${t(session.aiName)}:` : t('Loading...')}
|
|
</p>
|
|
<div className="gpt-util-group">
|
|
{!done && (
|
|
<button
|
|
type="button"
|
|
className="normal-button"
|
|
onClick={() => {
|
|
port.postMessage({ stop: true })
|
|
}}
|
|
>
|
|
{t('Stop')}
|
|
</button>
|
|
)}
|
|
{onRetry && (
|
|
<span title={t('Retry')} className="gpt-util-icon" onClick={onRetry}>
|
|
<SyncIcon size={14} />
|
|
</span>
|
|
)}
|
|
{session && (
|
|
<CopyButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
|
|
)}
|
|
{!collapsed ? (
|
|
<span
|
|
title={t('Collapse')}
|
|
className="gpt-util-icon"
|
|
onClick={() => setCollapsed(true)}
|
|
>
|
|
<XCircleIcon size={14} />
|
|
</span>
|
|
) : (
|
|
<span
|
|
title={t('Expand')}
|
|
className="gpt-util-icon"
|
|
onClick={() => setCollapsed(false)}
|
|
>
|
|
<ChevronDownIcon size={14} />
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{!collapsed && <MarkdownRender>{content}</MarkdownRender>}
|
|
</div>
|
|
)
|
|
case 'error':
|
|
return (
|
|
<div className={type} dir="auto">
|
|
<div className="gpt-header">
|
|
<p>{t('Error')}:</p>
|
|
<div className="gpt-util-group">
|
|
{onRetry && (
|
|
<span title={t('Retry')} className="gpt-util-icon" onClick={onRetry}>
|
|
<SyncIcon size={14} />
|
|
</span>
|
|
)}
|
|
<CopyButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
|
|
{!collapsed ? (
|
|
<span
|
|
title={t('Collapse')}
|
|
className="gpt-util-icon"
|
|
onClick={() => setCollapsed(true)}
|
|
>
|
|
<XCircleIcon size={14} />
|
|
</span>
|
|
) : (
|
|
<span
|
|
title={t('Expand')}
|
|
className="gpt-util-icon"
|
|
onClick={() => setCollapsed(false)}
|
|
>
|
|
<ChevronDownIcon size={14} />
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{!collapsed && <MarkdownRender>{content}</MarkdownRender>}
|
|
</div>
|
|
)
|
|
}
|
|
}
|
|
|
|
ConversationItem.propTypes = {
|
|
type: PropTypes.oneOf(['question', 'answer', 'error']).isRequired,
|
|
content: PropTypes.string.isRequired,
|
|
session: PropTypes.object.isRequired,
|
|
done: PropTypes.bool.isRequired,
|
|
port: PropTypes.object.isRequired,
|
|
onRetry: PropTypes.func,
|
|
}
|
|
|
|
export default ConversationItem
|