diff --git a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx index b43bc42fc6..a9ff63c3f1 100644 --- a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx +++ b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx @@ -8,6 +8,7 @@ import { PauseCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons' +import db from '@renderer/databases' import { useAssistant } from '@renderer/hooks/useAssistant' import { useSettings } from '@renderer/hooks/useSettings' import { useRuntime, useShowTopics } from '@renderer/hooks/useStore' @@ -120,6 +121,7 @@ const Inputbar: FC = ({ assistant, setActiveTopic }) => { const topic = getDefaultTopic() addTopic(topic) setActiveTopic(topic) + db.topics.add({ id: topic.id, messages: [] }) }, [addTopic, setActiveTopic]) const clearTopic = async () => { diff --git a/src/renderer/src/pages/home/Markdown/CodeBlock.tsx b/src/renderer/src/pages/home/Markdown/CodeBlock.tsx index 8693042899..1bb12a1409 100644 --- a/src/renderer/src/pages/home/Markdown/CodeBlock.tsx +++ b/src/renderer/src/pages/home/Markdown/CodeBlock.tsx @@ -3,7 +3,7 @@ import CopyIcon from '@renderer/components/Icons/CopyIcon' import { useTheme } from '@renderer/context/ThemeProvider' import { initMermaid } from '@renderer/init' import { ThemeMode } from '@renderer/types' -import React, { useState } from 'react' +import React, { memo, useState } from 'react' import { useTranslation } from 'react-i18next' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { atomDark, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism' @@ -17,34 +17,23 @@ interface CodeBlockProps { [key: string]: any } -const CodeBlock: React.FC = ({ children, className, ...rest }) => { +const CodeBlock: React.FC = ({ children, className }) => { const match = /language-(\w+)/.exec(className || '') - const [copied, setCopied] = useState(false) + const showFooterCopyButton = children && children.length > 500 const { theme } = useTheme() - const { t } = useTranslation() - - const onCopy = () => { - navigator.clipboard.writeText(children) - window.message.success({ content: t('message.copied'), key: 'copy-code' }) - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } - if (match && match[1] === 'mermaid') { initMermaid(theme) return } return match ? ( - <> +
{'<' + match[1].toUpperCase() + '>'} - {!copied && } - {copied && } + = ({ children, className, ...rest }) = }}> {String(children).replace(/\n$/, '')} - + {showFooterCopyButton && ( + + + + )} +
) : ( - - {children} - + {children} + ) +} + +const CopyButton: React.FC<{ text: string; style?: React.CSSProperties }> = ({ text, style }) => { + const [copied, setCopied] = useState(false) + const { t } = useTranslation() + + const onCopy = () => { + navigator.clipboard.writeText(text) + window.message.success({ content: t('message.copied'), key: 'copy-code' }) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } + + return copied ? ( + + ) : ( + ) } @@ -90,4 +100,19 @@ const CodeLanguage = styled.div` font-weight: bold; ` -export default CodeBlock +const CodeFooter = styled.div` + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + .copy { + cursor: pointer; + color: var(--color-text-3); + transition: color 0.3s; + } + .copy:hover { + color: var(--color-text-1); + } +` + +export default memo(CodeBlock) diff --git a/src/renderer/src/pages/home/Markdown/Markdown.tsx b/src/renderer/src/pages/home/Markdown/Markdown.tsx index 64959df080..8cd6525868 100644 --- a/src/renderer/src/pages/home/Markdown/Markdown.tsx +++ b/src/renderer/src/pages/home/Markdown/Markdown.tsx @@ -4,7 +4,7 @@ import { Message } from '@renderer/types' import { isEmpty } from 'lodash' import { FC, useMemo } from 'react' import { useTranslation } from 'react-i18next' -import ReactMarkdown from 'react-markdown' +import ReactMarkdown, { Components } from 'react-markdown' import rehypeKatex from 'rehype-katex' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' @@ -16,6 +16,14 @@ interface Props { message: Message } +const rehypePlugins = [rehypeKatex] +const remarkPlugins = [remarkGfm, remarkMath] + +const components = { + code: CodeBlock, + a: Link +} + const Markdown: FC = ({ message }) => { const { t } = useTranslation() @@ -26,22 +34,20 @@ const Markdown: FC = ({ message }) => { return content }, [message.content, message.status, t]) - return useMemo(() => { - return ( - - {messageContent} - - ) - }, [messageContent, t]) + return ( + } + remarkRehypeOptions={{ + footnoteLabel: t('common.footnotes'), + footnoteLabelTagName: 'h4', + footnoteBackContent: ' ' + }}> + {messageContent} + + ) } export default Markdown diff --git a/src/renderer/src/pages/home/Messages/Message.tsx b/src/renderer/src/pages/home/Messages/Message.tsx index 6d2db26d64..69abcfccd0 100644 --- a/src/renderer/src/pages/home/Messages/Message.tsx +++ b/src/renderer/src/pages/home/Messages/Message.tsx @@ -107,34 +107,6 @@ const MessageItem: FC = ({ message, index, showMenu, onDeleteMessage }) = [t, message] ) - const MessageItem = useCallback(() => { - if (message.status === 'sending') { - return ( - - - - ) - } - - if (message.status === 'error') { - return ( - {t('error.chat.response')}} - description={} - type="error" - style={{ marginBottom: 15, padding: 10, fontSize: 12 }} - /> - ) - } - - return ( - <> - - - - ) - }, [message, t]) - const showMiniApp = () => model?.provider && startMinAppById(model?.provider) if (message.type === 'clear') { @@ -175,8 +147,8 @@ const MessageItem: FC = ({ message, index, showMenu, onDeleteMessage }) = - - + + {showMenu && ( @@ -229,11 +201,41 @@ const MessageItem: FC = ({ message, index, showMenu, onDeleteMessage }) = )} - + ) } +const MessageContent: React.FC<{ message: Message }> = ({ message }) => { + const { t } = useTranslation() + + if (message.status === 'sending') { + return ( + + + + ) + } + + if (message.status === 'error') { + return ( + {t('error.chat.response')}} + description={} + type="error" + style={{ marginBottom: 15, padding: 10, fontSize: 12 }} + /> + ) + } + + return ( + <> + + + + ) +} + const MessageContainer = styled.div` display: flex; flex-direction: column; @@ -290,7 +292,7 @@ const MessageTime = styled.div` color: var(--color-text-3); ` -const MessageContent = styled.div` +const MessageContentContainer = styled.div` display: flex; flex: 1; flex-direction: column; diff --git a/src/renderer/src/pages/home/Messages/Messages.tsx b/src/renderer/src/pages/home/Messages/Messages.tsx index 9bae73d52e..3300d999a0 100644 --- a/src/renderer/src/pages/home/Messages/Messages.tsx +++ b/src/renderer/src/pages/home/Messages/Messages.tsx @@ -38,7 +38,7 @@ const Messages: FC = ({ assistant, topic, setActiveTopic }) => { (message: Message) => { const _messages = [...messages, message] setMessages(_messages) - db.topics.add({ id: topic.id, messages: _messages }) + db.topics.put({ id: topic.id, messages: _messages }) }, [messages, topic] ) @@ -142,7 +142,7 @@ const Messages: FC = ({ assistant, topic, setActiveTopic }) => { return ( - {lastMessage && } + {lastMessage && } {reverse([...messages]).map((message, index) => ( ))}