| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| import React, { useRef, useEffect, useCallback } from 'react';
|
| import { Toast } from '@douyinfe/semi-ui';
|
| import { useTranslation } from 'react-i18next';
|
| import { usePlayground } from '../../contexts/PlaygroundContext';
|
|
|
| const CustomInputRender = (props) => {
|
| const { t } = useTranslation();
|
| const { onPasteImage, imageEnabled } = usePlayground();
|
| const { detailProps } = props;
|
| const { clearContextNode, uploadNode, inputNode, sendNode, onClick } =
|
| detailProps;
|
| const containerRef = useRef(null);
|
|
|
| const handlePaste = useCallback(
|
| async (e) => {
|
| const items = e.clipboardData?.items;
|
| if (!items) return;
|
|
|
| for (let i = 0; i < items.length; i++) {
|
| const item = items[i];
|
|
|
| if (item.type.indexOf('image') !== -1) {
|
| e.preventDefault();
|
| const file = item.getAsFile();
|
|
|
| if (file) {
|
| try {
|
| if (!imageEnabled) {
|
| Toast.warning({
|
| content: t('请先在设置中启用图片功能'),
|
| duration: 3,
|
| });
|
| return;
|
| }
|
|
|
| const reader = new FileReader();
|
| reader.onload = (event) => {
|
| const base64 = event.target.result;
|
|
|
| if (onPasteImage) {
|
| onPasteImage(base64);
|
| Toast.success({
|
| content: t('图片已添加'),
|
| duration: 2,
|
| });
|
| } else {
|
| Toast.error({
|
| content: t('无法添加图片'),
|
| duration: 2,
|
| });
|
| }
|
| };
|
| reader.onerror = () => {
|
| console.error('Failed to read image file:', reader.error);
|
| Toast.error({
|
| content: t('粘贴图片失败'),
|
| duration: 2,
|
| });
|
| };
|
| reader.readAsDataURL(file);
|
| } catch (error) {
|
| console.error('Failed to paste image:', error);
|
| Toast.error({
|
| content: t('粘贴图片失败'),
|
| duration: 2,
|
| });
|
| }
|
| }
|
| break;
|
| }
|
| }
|
| },
|
| [onPasteImage, imageEnabled, t],
|
| );
|
|
|
| useEffect(() => {
|
| const container = containerRef.current;
|
| if (!container) return;
|
|
|
| container.addEventListener('paste', handlePaste);
|
| return () => {
|
| container.removeEventListener('paste', handlePaste);
|
| };
|
| }, [handlePaste]);
|
|
|
|
|
| const styledClearNode = clearContextNode
|
| ? React.cloneElement(clearContextNode, {
|
| className: `!rounded-full !bg-gray-100 hover:!bg-red-500 hover:!text-white flex-shrink-0 transition-all ${clearContextNode.props.className || ''}`,
|
| style: {
|
| ...clearContextNode.props.style,
|
| width: '32px',
|
| height: '32px',
|
| minWidth: '32px',
|
| padding: 0,
|
| display: 'flex',
|
| alignItems: 'center',
|
| justifyContent: 'center',
|
| },
|
| })
|
| : null;
|
|
|
|
|
| const styledSendNode = React.cloneElement(sendNode, {
|
| className: `!rounded-full !bg-purple-500 hover:!bg-purple-600 flex-shrink-0 transition-all ${sendNode.props.className || ''}`,
|
| style: {
|
| ...sendNode.props.style,
|
| width: '32px',
|
| height: '32px',
|
| minWidth: '32px',
|
| padding: 0,
|
| display: 'flex',
|
| alignItems: 'center',
|
| justifyContent: 'center',
|
| },
|
| });
|
|
|
| return (
|
| <div className='p-2 sm:p-4' ref={containerRef}>
|
| <div
|
| className='flex items-center gap-2 sm:gap-3 p-2 bg-gray-50 rounded-xl sm:rounded-2xl shadow-sm hover:shadow-md transition-shadow'
|
| style={{ border: '1px solid var(--semi-color-border)' }}
|
| onClick={onClick}
|
| title={t('支持 Ctrl+V 粘贴图片')}
|
| >
|
| {/* 清空对话按钮 - 左边 */}
|
| {styledClearNode}
|
| <div className='flex-1'>{inputNode}</div>
|
| {/* 发送按钮 - 右边 */}
|
| {styledSendNode}
|
| </div>
|
| </div>
|
| );
|
| };
|
|
|
| export default CustomInputRender;
|
|
|