feat: 输入框粘贴上传图片

pull/13/head
moonrailgun 4 years ago
parent 1174a56de4
commit 5ffb5c1aee

@ -36,6 +36,7 @@
"k4603baea": "Create Group Panel",
"k47489688": "Group Service",
"k4d32a754": "Group Name",
"k50504f9e": "Upload picture to converse",
"k50d471b2": "Reset",
"k51243586": "Add friend",
"k517db7e5": "Text Channel",
@ -110,6 +111,7 @@
"kdc4b4f92": "Public",
"kdd4c838c": "Jump to Group",
"kdd6c18f8": "Service exception",
"ke17b2c87": "Do not upload pictures that violate local laws and regulations",
"ke187440d": "Panel type cannot be empty",
"kecbd7449": "Delete",
"ked2baf28": "Loading...",

@ -36,6 +36,7 @@
"k4603baea": "创建群组面板",
"k47489688": "群组服务",
"k4d32a754": "群组名称",
"k50504f9e": "上传图片到会话",
"k50d471b2": "重置",
"k51243586": "添加好友",
"k517db7e5": "文字频道",
@ -110,6 +111,7 @@
"kdc4b4f92": "公共",
"kdd4c838c": "跳转到群组",
"kdd6c18f8": "服务异常",
"ke17b2c87": "请勿上传违反当地法律法规的图片",
"ke187440d": "面板类型不能为空",
"kecbd7449": "删除",
"ked2baf28": "加载中...",

@ -0,0 +1,34 @@
export class ClipboardHelper {
data: DataTransfer;
constructor(e: { clipboardData: DataTransfer }) {
this.data = e.clipboardData;
}
hasImage(): File | false {
const image = this.isPasteImage(this.data.items);
if (image === false) {
return false;
}
const file = image.getAsFile();
if (file === null) {
return false;
}
return file;
}
private isPasteImage(items: DataTransferItemList): DataTransferItem | false {
let i = 0;
let item: DataTransferItem;
while (i < items.length) {
item = items[i];
if (item.type.indexOf('image') !== -1) {
return item;
}
i++;
}
return false;
}
}

@ -1,8 +1,12 @@
import { closeModal, openModal } from '@/components/Modal';
import { ImageUploadPreviewer } from '@/components/modals/ImageUploadPreviewer';
import { fileToDataUrl } from '@/utils/file-helper';
import { isEnterHotkey } from '@/utils/hot-key';
import { Input } from 'antd';
import React, { useCallback, useRef, useState } from 'react';
import { t } from 'tailchat-shared';
import { t, uploadFile } from 'tailchat-shared';
import { ChatInputAddon } from './Addon';
import { ClipboardHelper } from './clipboard-helper';
import { ChatInputActionContext } from './context';
interface ChatInputBoxProps {
@ -27,6 +31,33 @@ export const ChatInputBox: React.FC<ChatInputBoxProps> = React.memo((props) => {
[handleSendMsg]
);
const handlePaste = useCallback(
(e: React.ClipboardEvent<HTMLDivElement>) => {
const helper = new ClipboardHelper(e);
const image = helper.hasImage();
if (image) {
// 上传图片
e.preventDefault();
fileToDataUrl(image).then((imageLocalUrl) => {
const key = openModal(
<ImageUploadPreviewer
imageUrl={imageLocalUrl}
onConfirm={async () => {
const fileInfo = await uploadFile(image);
const imageRemoteUrl = fileInfo.url;
// TODO: not good
props.onSendMsg(`[img]${imageRemoteUrl}[/img]`);
closeModal(key);
}}
/>
);
});
}
},
[props.onSendMsg]
);
return (
<ChatInputActionContext.Provider value={{ sendMsg: props.onSendMsg }}>
<div className="px-4 py-2">
@ -38,6 +69,7 @@ export const ChatInputBox: React.FC<ChatInputBoxProps> = React.memo((props) => {
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyDown}
onPaste={handlePaste}
/>
<div className="px-2">

@ -0,0 +1,48 @@
import { ModalWrapper } from '@/plugin/common';
import { Button } from '@/plugin/component';
import React from 'react';
import { t, useAsyncFn } from 'tailchat-shared';
interface ImageUploadPreviewerProps {
imageUrl: string;
onConfirm: () => void;
}
export const ImageUploadPreviewer: React.FC<ImageUploadPreviewerProps> =
React.memo((props) => {
const { imageUrl } = props;
const [{ loading }, handleConfirm] = useAsyncFn(async () => {
if (typeof props.onConfirm === 'function') {
await Promise.resolve(props.onConfirm());
}
}, [props.onConfirm]);
return (
<ModalWrapper style={{ maxHeight: '60vh', maxWidth: '60vw' }}>
<div className="flex">
<div className="w-2/3 p-2.5 bg-black bg-opacity-20 rounded">
<img className="max-h-160" src={imageUrl} />
</div>
<div className="w-1/3 p-2 flex flex-col items-end justify-between">
<div className="text-right">
<div className="text-lg">{t('上传图片到会话')}</div>
<div className="text-sm text-gray-400">
{t('请勿上传违反当地法律法规的图片')}
</div>
</div>
<Button
className="mt-4"
type="primary"
loading={loading}
onClick={handleConfirm}
>
{t('确认')}
</Button>
</div>
</div>
</ModalWrapper>
);
});
ImageUploadPreviewer.displayName = 'ImageUploadPreviewer';

@ -59,6 +59,7 @@ module.exports = {
spacing: {
18: '4.5rem',
142: '35.5rem',
160: '40rem',
},
lineHeight: {
13: '3.25rem',

Loading…
Cancel
Save