From a430284aa21e3ae1f0d5654e55b2ad2852519cc2 Mon Sep 17 00:00:00 2001 From: wwf <yearningwang@iqtogether.com> Date: 星期三, 04 六月 2025 15:17:49 +0800 Subject: [PATCH] 初始化 --- app/components/base/chat/chat/question.tsx | 129 ++---------------------------------------- 1 files changed, 7 insertions(+), 122 deletions(-) diff --git a/app/components/base/chat/chat/question.tsx b/app/components/base/chat/chat/question.tsx index 8fc49d1..7052c1f 100644 --- a/app/components/base/chat/chat/question.tsx +++ b/app/components/base/chat/chat/question.tsx @@ -4,169 +4,54 @@ } from 'react' import { memo, - useCallback, - useEffect, - useRef, - useState, } from 'react' import type { ChatItem } from '../types' import type { Theme } from '../embedded-chatbot/theme/theme-context' import { CssTransform } from '../embedded-chatbot/theme/utils' -import ContentSwitch from './content-switch' import { User } from '@/app/components/base/icons/src/public/avatar' import { Markdown } from '@/app/components/base/markdown' import { FileList } from '@/app/components/base/file-uploader' -import ActionButton from '../../action-button' -import { RiClipboardLine, RiEditLine } from '@remixicon/react' -import Toast from '../../toast' -import copy from 'copy-to-clipboard' -import { useTranslation } from 'react-i18next' -import cn from '@/utils/classnames' -import Textarea from 'react-textarea-autosize' -import Button from '../../button' -import { useChatContext } from './context' type QuestionProps = { item: ChatItem questionIcon?: ReactNode theme: Theme | null | undefined - enableEdit?: boolean - switchSibling?: (siblingMessageId: string) => void } - const Question: FC<QuestionProps> = ({ item, questionIcon, theme, - enableEdit = true, - switchSibling, }) => { - const { t } = useTranslation() - const { content, message_files, } = item - const { - onRegenerate, - } = useChatContext() - - const [isEditing, setIsEditing] = useState(false) - const [editedContent, setEditedContent] = useState(content) - const [contentWidth, setContentWidth] = useState(0) - const contentRef = useRef<HTMLDivElement>(null) - - const handleEdit = useCallback(() => { - setIsEditing(true) - setEditedContent(content) - }, [content]) - - const handleResend = useCallback(() => { - setIsEditing(false) - onRegenerate?.(item, { message: editedContent, files: message_files }) - }, [editedContent, message_files, item, onRegenerate]) - - const handleCancelEditing = useCallback(() => { - setIsEditing(false) - setEditedContent(content) - }, [content]) - - const handleSwitchSibling = useCallback((direction: 'prev' | 'next') => { - if (direction === 'prev') - item.prevSibling && switchSibling?.(item.prevSibling) - else - item.nextSibling && switchSibling?.(item.nextSibling) - }, [switchSibling, item.prevSibling, item.nextSibling]) - - const getContentWidth = () => { - if (contentRef.current) - setContentWidth(contentRef.current?.clientWidth) - } - - useEffect(() => { - if (!contentRef.current) - return - const resizeObserver = new ResizeObserver(() => { - getContentWidth() - }) - resizeObserver.observe(contentRef.current) - return () => { - resizeObserver.disconnect() - } - }, []) - return ( - <div className='mb-2 flex justify-end last:mb-0'> - <div className={cn('group relative mr-4 flex max-w-full items-start pl-14', isEditing && 'flex-1')}> - <div className={cn('mr-2 gap-1', isEditing ? 'hidden' : 'flex')}> - <div - className="absolute hidden gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm group-hover:flex" - style={{ right: contentWidth + 8 }} - > - <ActionButton onClick={() => { - copy(content) - Toast.notify({ type: 'success', message: t('common.actionMsg.copySuccessfully') }) - }}> - <RiClipboardLine className='h-4 w-4' /> - </ActionButton> - {enableEdit && <ActionButton onClick={handleEdit}> - <RiEditLine className='h-4 w-4' /> - </ActionButton>} - </div> - </div> + <div className='flex justify-end mb-2 last:mb-0 pl-14'> + <div className='group relative mr-4 max-w-full'> <div - ref={contentRef} - className='w-full rounded-2xl bg-[#D1E9FF]/50 px-4 py-3 text-sm text-gray-900' + className='px-4 py-3 bg-[#D1E9FF]/50 rounded-2xl text-sm text-gray-900' style={theme?.chatBubbleColorStyle ? CssTransform(theme.chatBubbleColorStyle) : {}} > { !!message_files?.length && ( <FileList - className='mb-2' files={message_files} showDeleteAction={false} showDownloadAction={true} /> ) } - { !isEditing - ? <Markdown content={content} /> - : <div className=" - flex flex-col gap-2 rounded-xl - border border-components-chat-input-border bg-components-panel-bg-blur p-[9px] shadow-md - "> - <div className="max-h-[158px] overflow-y-auto overflow-x-hidden"> - <Textarea - className={cn( - 'body-lg-regular w-full p-1 leading-6 text-text-tertiary outline-none', - )} - autoFocus - minRows={1} - value={editedContent} - onChange={e => setEditedContent(e.target.value)} - /> - </div> - <div className="flex justify-end gap-2"> - <Button variant='ghost' onClick={handleCancelEditing}>{t('common.operation.cancel')}</Button> - <Button variant='primary' onClick={handleResend}>{t('common.chat.resend')}</Button> - </div> - </div> } - { !isEditing && <ContentSwitch - count={item.siblingCount} - currentIndex={item.siblingIndex} - prevDisabled={!item.prevSibling} - nextDisabled={!item.nextSibling} - switchSibling={handleSwitchSibling} - />} + <Markdown content={content} /> </div> <div className='mt-1 h-[18px]' /> </div> - <div className='h-10 w-10 shrink-0'> + <div className='shrink-0 w-10 h-10'> { questionIcon || ( - <div className='h-full w-full rounded-full border-[0.5px] border-black/5'> - <User className='h-full w-full' /> + <div className='w-full h-full rounded-full border-[0.5px] border-black/5'> + <User className='w-full h-full' /> </div> ) } -- Gitblit v1.8.0