refactor(MessageEditor): improve editor style (#8387)

This commit is contained in:
one 2025-07-23 10:06:17 +08:00 committed by GitHub
parent e688b2959c
commit eebed6d399
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -15,7 +15,7 @@ import { getFilesFromDropEvent, isSendMessageKeyPressed } from '@renderer/utils/
import { createFileBlock, createImageBlock } from '@renderer/utils/messageUtils/create' import { createFileBlock, createImageBlock } from '@renderer/utils/messageUtils/create'
import { findAllBlocks } from '@renderer/utils/messageUtils/find' import { findAllBlocks } from '@renderer/utils/messageUtils/find'
import { documentExts, imageExts, textExts } from '@shared/config/constant' import { documentExts, imageExts, textExts } from '@shared/config/constant'
import { Tooltip } from 'antd' import { Space, Tooltip } from 'antd'
import TextArea, { TextAreaRef } from 'antd/es/input/TextArea' import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
import { Save, Send, X } from 'lucide-react' import { Save, Send, X } from 'lucide-react'
import { FC, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { FC, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
@ -96,22 +96,13 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
} }
}, [couldAddImageFile, couldAddTextFile]) }, [couldAddImageFile, couldAddTextFile])
const resizeTextArea = useCallback(() => {
const textArea = textareaRef.current?.resizableTextArea?.textArea
if (textArea) {
textArea.style.height = 'auto'
textArea.style.height = textArea?.scrollHeight > 400 ? '400px' : `${textArea?.scrollHeight}px`
}
}, [])
useEffect(() => { useEffect(() => {
setTimeout(() => { setTimeout(() => {
resizeTextArea()
if (textareaRef.current) { if (textareaRef.current) {
textareaRef.current.focus({ cursor: 'end' }) textareaRef.current.focus({ cursor: 'end' })
} }
}, 0) }, 0)
}, [resizeTextArea]) }, [])
const onPaste = useCallback( const onPaste = useCallback(
async (event: ClipboardEvent) => { async (event: ClipboardEvent) => {
@ -123,11 +114,11 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
false, // 不需要 pasteLongTextAsFile false, // 不需要 pasteLongTextAsFile
pasteLongTextThreshold, pasteLongTextThreshold,
undefined, // 不需要text undefined, // 不需要text
resizeTextArea, undefined, // 不需要 resizeTextArea
t t
) )
}, },
[extensions, pasteLongTextThreshold, resizeTextArea, t] [extensions, pasteLongTextThreshold, t]
) )
// 添加全局粘贴事件处理 // 添加全局粘贴事件处理
@ -149,7 +140,6 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
if (mainTextBlock) { if (mainTextBlock) {
handleTextChange(mainTextBlock.id, translatedText) handleTextChange(mainTextBlock.id, translatedText)
} }
setTimeout(() => resizeTextArea(), 0)
} }
// 处理文件删除 // 处理文件删除
@ -246,7 +236,6 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
// set cursor position in the next render cycle // set cursor position in the next render cycle
setTimeout(() => { setTimeout(() => {
textArea.selectionStart = textArea.selectionEnd = start + 1 textArea.selectionStart = textArea.selectionEnd = start + 1
resizeTextArea() // trigger resizeTextArea
}, 0) }, 0)
} }
} }
@ -256,11 +245,17 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
return ( return (
<> <>
<EditorContainer className="message-editor" onDragOver={(e) => e.preventDefault()} onDrop={handleDrop}> <EditorContainer
className="message-editor"
direction="vertical"
size="small"
style={{ display: 'flex' }}
onDragOver={(e) => e.preventDefault()}
onDrop={handleDrop}>
{editedBlocks {editedBlocks
.filter((block) => block.type === MessageBlockType.MAIN_TEXT) .filter((block) => block.type === MessageBlockType.MAIN_TEXT)
.map((block) => ( .map((block) => (
<Textarea <TextArea
className={classNames('editing-message', isFileDragging && 'file-dragging')} className={classNames('editing-message', isFileDragging && 'file-dragging')}
key={block.id} key={block.id}
ref={textareaRef} ref={textareaRef}
@ -268,7 +263,6 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
value={block.content} value={block.content}
onChange={(e) => { onChange={(e) => {
handleTextChange(block.id, e.target.value) handleTextChange(block.id, e.target.value)
resizeTextArea()
}} }}
onKeyDown={(e) => handleKeyDown(e, block.id)} onKeyDown={(e) => handleKeyDown(e, block.id)}
autoFocus autoFocus
@ -282,12 +276,12 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
// 阻止事件冒泡,避免触发全局的 Electron contextMenu // 阻止事件冒泡,避免触发全局的 Electron contextMenu
e.stopPropagation() e.stopPropagation()
}} }}
autoSize={{ minRows: 3, maxRows: 15 }}
style={{ style={{
fontSize, fontSize
padding: '0px 15px 8px 15px'
}}> }}>
<TranslateButton onTranslated={onTranslated} /> <TranslateButton onTranslated={onTranslated} />
</Textarea> </TextArea>
))} ))}
{(editedBlocks.some((block) => block.type === MessageBlockType.FILE || block.type === MessageBlockType.IMAGE) || {(editedBlocks.some((block) => block.type === MessageBlockType.FILE || block.type === MessageBlockType.IMAGE) ||
files.length > 0) && ( files.length > 0) && (
@ -359,14 +353,9 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
) )
} }
const EditorContainer = styled.div` const EditorContainer = styled(Space)`
padding: 18px 0; margin: 15px 0 5px 0;
padding-bottom: 5px;
border: 0.5px solid var(--color-border);
transition: all 0.2s ease; transition: all 0.2s ease;
border-radius: 15px;
margin-top: 18px;
background-color: var(--color-background-opacity);
width: 100%; width: 100%;
&.file-dragging { &.file-dragging {
@ -385,6 +374,22 @@ const EditorContainer = styled.div`
pointer-events: none; pointer-events: none;
} }
} }
.editing-message {
background-color: var(--color-background-opacity);
border: 0.5px solid var(--color-border);
border-radius: 15px;
padding: 0.5em 1em;
flex: 1;
font-family: Ubuntu;
resize: none !important;
overflow: auto;
width: 100%;
box-sizing: border-box;
&.ant-input {
line-height: 1.4;
}
}
` `
const FileBlocksContainer = styled.div` const FileBlocksContainer = styled.div`
@ -397,21 +402,6 @@ const FileBlocksContainer = styled.div`
border-radius: 4px; border-radius: 4px;
` `
const Textarea = styled(TextArea)`
padding: 0;
border-radius: 0;
display: flex;
flex: 1;
font-family: Ubuntu;
resize: none !important;
overflow: auto;
width: 100%;
box-sizing: border-box;
&.ant-input {
line-height: 1.4;
}
`
const ActionBar = styled.div` const ActionBar = styled.div`
display: flex; display: flex;
padding: 0 8px; padding: 0 8px;