feat: render markdown when show assistant prompt (#4365)

* feat: render markdown when show assistant prompt

* fix: polish user experience
This commit is contained in:
fullex 2025-04-04 09:37:29 +08:00 committed by GitHub
parent fb5ddaf9d5
commit 4d5cfe06f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 48 additions and 26 deletions

View File

@ -2,7 +2,7 @@ import 'emoji-picker-element'
import { CloseCircleFilled } from '@ant-design/icons' import { CloseCircleFilled } from '@ant-design/icons'
import EmojiPicker from '@renderer/components/EmojiPicker' import EmojiPicker from '@renderer/components/EmojiPicker'
import { Box, HStack } from '@renderer/components/Layout' import { Box, HSpaceBetweenStack, HStack } from '@renderer/components/Layout'
import { estimateTextTokens } from '@renderer/services/TokenService' import { estimateTextTokens } from '@renderer/services/TokenService'
import { Assistant, AssistantSettings } from '@renderer/types' import { Assistant, AssistantSettings } from '@renderer/types'
import { getLeadingEmoji } from '@renderer/utils' import { getLeadingEmoji } from '@renderer/utils'
@ -10,21 +10,23 @@ import { Button, Input, Popover } from 'antd'
import TextArea from 'antd/es/input/TextArea' import TextArea from 'antd/es/input/TextArea'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import ReactMarkdown from 'react-markdown'
import styled from 'styled-components' import styled from 'styled-components'
interface Props { interface Props {
assistant: Assistant assistant: Assistant
updateAssistant: (assistant: Assistant) => void updateAssistant: (assistant: Assistant) => void
updateAssistantSettings: (settings: AssistantSettings) => void updateAssistantSettings?: (settings: AssistantSettings) => void
onOk: () => void onOk?: () => void
} }
const AssistantPromptSettings: React.FC<Props> = ({ assistant, updateAssistant, onOk }) => { const AssistantPromptSettings: React.FC<Props> = ({ assistant, updateAssistant }) => {
const [emoji, setEmoji] = useState(getLeadingEmoji(assistant.name) || assistant.emoji) const [emoji, setEmoji] = useState(getLeadingEmoji(assistant.name) || assistant.emoji)
const [name, setName] = useState(assistant.name.replace(getLeadingEmoji(assistant.name) || '', '').trim()) const [name, setName] = useState(assistant.name.replace(getLeadingEmoji(assistant.name) || '', '').trim())
const [prompt, setPrompt] = useState(assistant.prompt) const [prompt, setPrompt] = useState(assistant.prompt)
const [tokenCount, setTokenCount] = useState(0) const [tokenCount, setTokenCount] = useState(0)
const { t } = useTranslation() const { t } = useTranslation()
const [showMarkdown, setShowMarkdown] = useState(prompt.length > 0)
useEffect(() => { useEffect(() => {
const updateTokenCount = async () => { const updateTokenCount = async () => {
@ -92,22 +94,39 @@ const AssistantPromptSettings: React.FC<Props> = ({ assistant, updateAssistant,
{t('common.prompt')} {t('common.prompt')}
</Box> </Box>
<TextAreaContainer> <TextAreaContainer>
<TextArea {showMarkdown ? (
rows={10} <MarkdownContainer onClick={() => setShowMarkdown(false)}>
placeholder={t('common.assistant') + t('common.prompt')} <ReactMarkdown className="markdown">{prompt}</ReactMarkdown>
value={prompt} <div style={{ height: '30px' }} />
onChange={(e) => setPrompt(e.target.value)} </MarkdownContainer>
onBlur={onUpdate} ) : (
spellCheck={false} <TextArea
style={{ minHeight: 'calc(80vh - 200px)', maxHeight: 'calc(80vh - 150px)' }} rows={10}
/> placeholder={t('common.assistant') + t('common.prompt')}
<TokenCount>Tokens: {tokenCount}</TokenCount> value={prompt}
onChange={(e) => setPrompt(e.target.value)}
onBlur={() => {
onUpdate()
}}
autoFocus={true}
spellCheck={false}
style={{ minHeight: 'calc(80vh - 200px)', maxHeight: 'calc(80vh - 200px)', paddingBottom: '30px' }}
/>
)}
</TextAreaContainer> </TextAreaContainer>
<HStack width="100%" justifyContent="flex-end" mt="10px"> <HSpaceBetweenStack width="100%" justifyContent="flex-end" mt="10px">
<Button type="primary" onClick={onOk}> <TokenCount>Tokens: {tokenCount}</TokenCount>
{t('common.close')}
</Button> {showMarkdown ? (
</HStack> <Button type="primary" onClick={() => setShowMarkdown(false)}>
{t('common.edit')}
</Button>
) : (
<Button type="primary" onClick={() => setShowMarkdown(true)}>
{t('common.save')}
</Button>
)}
</HSpaceBetweenStack>
</Container> </Container>
) )
} }
@ -135,15 +154,19 @@ const TextAreaContainer = styled.div`
` `
const TokenCount = styled.div` const TokenCount = styled.div`
position: absolute; padding: 2px 2px;
bottom: 8px;
right: 8px;
background-color: var(--color-background-soft);
padding: 2px 8px;
border-radius: 4px; border-radius: 4px;
font-size: 12px; font-size: 14px;
color: var(--color-text-2); color: var(--color-text-2);
user-select: none; user-select: none;
` `
const MarkdownContainer = styled.div`
min-height: calc(80vh - 200px);
max-height: calc(80vh - 200px);
padding-right: 2px;
overflow: auto;
overflow-x: hidden;
`
export default AssistantPromptSettings export default AssistantPromptSettings

View File

@ -114,7 +114,6 @@ const AssistantSettingPopupContainer: React.FC<Props> = ({ resolve, tab, ...prop
assistant={assistant} assistant={assistant}
updateAssistant={updateAssistant} updateAssistant={updateAssistant}
updateAssistantSettings={updateAssistantSettings} updateAssistantSettings={updateAssistantSettings}
onOk={onOk}
/> />
)} )}
{menu === 'model' && ( {menu === 'model' && (