|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|