feat: 在消息输入框操作中添加发送图片选项

pull/13/head
moonrailgun 3 years ago
parent 3329382415
commit 40001997a9

@ -1,23 +1,40 @@
import { chatInputActions } from '@/plugin/common';
import { FileSelector } from '@/components/FileSelector';
import { pluginChatInputActions } from '@/plugin/common';
import { Icon } from '@iconify/react';
import { Dropdown, Menu } from 'antd';
import React from 'react';
import { t } from 'tailchat-shared';
import { useChatInputActionContext } from './context';
import { uploadMessageImage } from './utils';
export const ChatInputAddon: React.FC = React.memo(() => {
const actionContext = useChatInputActionContext();
if (chatInputActions.length === 0) {
return null;
}
if (actionContext === null) {
return null;
}
const handleSendImage = (files: FileList) => {
// 发送图片
const image = files[0];
if (image) {
// 发送图片
uploadMessageImage(image).then((imageRemoteUrl) => {
// TODO: not good, should bind with plugin bbcode
actionContext.sendMsg(`[img]${imageRemoteUrl}[/img]`);
});
}
};
const menu = (
<Menu>
{chatInputActions.map((item, i) => (
<FileSelector
fileProps={{ accept: 'image/*' }}
onSelected={handleSendImage}
>
<Menu.Item>{t('发送图片')}</Menu.Item>
</FileSelector>
{pluginChatInputActions.map((item, i) => (
<Menu.Item
key={item.label + i}
onClick={() => item.onClick(actionContext)}

@ -1,13 +1,11 @@
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, uploadFile } from 'tailchat-shared';
import { t } from 'tailchat-shared';
import { ChatInputAddon } from './Addon';
import { ClipboardHelper } from './clipboard-helper';
import { ChatInputActionContext } from './context';
import { uploadMessageImage } from './utils';
interface ChatInputBoxProps {
onSendMsg: (msg: string) => void;
@ -38,20 +36,9 @@ export const ChatInputBox: React.FC<ChatInputBoxProps> = React.memo((props) => {
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, should bind with plugin bbcode
props.onSendMsg(`[img]${imageRemoteUrl}[/img]`);
closeModal(key);
}}
/>
);
uploadMessageImage(image).then((imageRemoteUrl) => {
// TODO: not good, should bind with plugin bbcode
props.onSendMsg(`[img]${imageRemoteUrl}[/img]`);
});
}
},

@ -0,0 +1,27 @@
import { closeModal, openModal } from '@/components/Modal';
import { ImageUploadPreviewer } from '@/components/modals/ImageUploadPreviewer';
import { fileToDataUrl } from '@/utils/file-helper';
import React from 'react';
import { uploadFile } from 'tailchat-shared';
/**
*
*/
export function uploadMessageImage(image: File): Promise<string> {
return new Promise((resolve) => {
fileToDataUrl(image).then((imageLocalUrl) => {
const key = openModal(
<ImageUploadPreviewer
imageUrl={imageLocalUrl}
onConfirm={async () => {
const fileInfo = await uploadFile(image);
const imageRemoteUrl = fileInfo.url;
resolve(imageRemoteUrl);
closeModal(key);
}}
/>
);
});
});
}

@ -0,0 +1,53 @@
import React, { useCallback, useRef } from 'react';
import _isFunction from 'lodash/isFunction';
import _isNil from 'lodash/isNil';
/**
*
*/
interface FileSelectorProps {
fileProps?: React.DetailedHTMLProps<
React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>;
/**
*
*/
onSelected: (files: FileList) => void;
}
export const FileSelector: React.FC<FileSelectorProps> = React.memo((props) => {
const fileInputRef = useRef<HTMLInputElement>(null);
const handleSelect = useCallback(() => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
}, []);
const handleChange = useCallback(() => {
if (_isNil(fileInputRef.current)) {
return;
}
const files = fileInputRef.current.files;
if (_isNil(files)) {
return;
}
_isFunction(props.onSelected) && props.onSelected(files);
}, [props.onSelected]);
return (
<div onClick={handleSelect}>
{props.children}
<input
{...props.fileProps}
className="hidden"
type="file"
ref={fileInputRef}
onChange={handleChange}
/>
</div>
);
});
FileSelector.displayName = 'FileSelector';

@ -64,7 +64,7 @@ interface ChatInputAction {
onClick: (actions: ChatInputActionContextProps) => void;
}
export type { ChatInputActionContextProps };
export const [chatInputActions, regChatInputAction] =
export const [pluginChatInputActions, regChatInputAction] =
buildRegList<ChatInputAction>();
export { regSocketEventListener };

Loading…
Cancel
Save