mirror of https://github.com/msgbyte/tailchat
feat: 消息回复与显示
parent
312d96fb7a
commit
acceba8726
@ -0,0 +1,50 @@
|
|||||||
|
import React, { useCallback, useContext, useState } from 'react';
|
||||||
|
import _noop from 'lodash/noop';
|
||||||
|
import type { ReplyMsgType } from '../utils/msg-helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个消息盒的上下文
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface ChatBoxContextProps {
|
||||||
|
replyMsg: ReplyMsgType | null;
|
||||||
|
setReplyMsg: (msg: ReplyMsgType | null) => void;
|
||||||
|
}
|
||||||
|
const ChatBoxContext = React.createContext<ChatBoxContextProps>({
|
||||||
|
replyMsg: null,
|
||||||
|
setReplyMsg: _noop,
|
||||||
|
});
|
||||||
|
ChatBoxContext.displayName = 'ChatBoxContext';
|
||||||
|
|
||||||
|
export const ChatBoxContextProvider: React.FC = React.memo((props) => {
|
||||||
|
const [replyMsg, setReplyMsg] = useState<ReplyMsgType | null>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChatBoxContext.Provider
|
||||||
|
value={{
|
||||||
|
replyMsg,
|
||||||
|
setReplyMsg,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</ChatBoxContext.Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ChatBoxContextProvider.displayName = 'ChatBoxContextProvider';
|
||||||
|
|
||||||
|
export function useChatBoxContext(): ChatBoxContextProps & {
|
||||||
|
hasContext: boolean;
|
||||||
|
clearReplyMsg: () => void;
|
||||||
|
} {
|
||||||
|
const context = useContext(ChatBoxContext);
|
||||||
|
const clearReplyMsg = useCallback(() => {
|
||||||
|
context.setReplyMsg(null);
|
||||||
|
}, [context.setReplyMsg]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
hasContext: context.setReplyMsg !== _noop,
|
||||||
|
replyMsg: context.replyMsg,
|
||||||
|
setReplyMsg: context.setReplyMsg,
|
||||||
|
clearReplyMsg,
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
import type { ChatMessage } from '../model/message';
|
||||||
|
|
||||||
|
const replyMsgFields = ['_id', 'content', 'author'] as const;
|
||||||
|
export type ReplyMsgType = Pick<ChatMessage, typeof replyMsgFields[number]>;
|
@ -0,0 +1,22 @@
|
|||||||
|
import { Skeleton } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const ChatBoxPlaceholder: React.FC = React.memo(() => {
|
||||||
|
const paragraph = { rows: 1 };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="px-2 w-2/3">
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
<Skeleton className="mb-2" avatar={true} paragraph={paragraph} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ChatBoxPlaceholder.displayName = 'ChatBoxPlaceholder';
|
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { t, useChatBoxContext } from 'tailchat-shared';
|
||||||
|
import _isNil from 'lodash/isNil';
|
||||||
|
import { getMessageRender } from '@/plugin/common';
|
||||||
|
import { UserName } from '../UserName';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
|
||||||
|
export const ChatReply: React.FC = React.memo(() => {
|
||||||
|
const { replyMsg, clearReplyMsg } = useChatBoxContext();
|
||||||
|
|
||||||
|
if (_isNil(replyMsg)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute bottom-0 left-0 right-0 py-1 px-4">
|
||||||
|
<div className="rounded bg-white p-2 max-h-44 overflow-auto shadow-sm relative">
|
||||||
|
<span className="align-top">
|
||||||
|
{t('回复')}{' '}
|
||||||
|
{replyMsg.author && <UserName userId={replyMsg.author} />}:{' '}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>{getMessageRender(replyMsg.content)}</span>
|
||||||
|
|
||||||
|
<Icon
|
||||||
|
className="absolute right-1 top-0.5 text-lg cursor-pointer opacity-60 hover:opacity-80"
|
||||||
|
icon="mdi:close-circle-outline"
|
||||||
|
onClick={clearReplyMsg}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ChatReply.displayName = 'ChatReply';
|
Loading…
Reference in New Issue