mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
🆙 Added emoji to the chat
This commit is contained in:
@@ -11,9 +11,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.26.9",
|
"@babel/runtime": "^7.26.9",
|
||||||
|
"@emoji-mart/data": "^1.2.1",
|
||||||
|
"@emoji-mart/react": "^1.1.1",
|
||||||
"@tanstack/react-virtual": "3.2.0",
|
"@tanstack/react-virtual": "3.2.0",
|
||||||
"@types/react-transition-group": "^4.4.10",
|
"@types/react-transition-group": "^4.4.10",
|
||||||
"dompurify": "^3.1.5",
|
"dompurify": "^3.1.5",
|
||||||
|
"emoji-mart": "^5.6.0",
|
||||||
|
"emoji-toolkit": "10.0.0",
|
||||||
"framer-motion": "^11.2.12",
|
"framer-motion": "^11.2.12",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
"react-bootstrap": "^2.10.10",
|
"react-bootstrap": "^2.10.10",
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import data from '@emoji-mart/data';
|
||||||
|
import Picker from '@emoji-mart/react';
|
||||||
|
import { FC, useState } from 'react';
|
||||||
|
import { Popover } from 'react-tiny-popover';
|
||||||
|
|
||||||
|
interface ChatInputEmojiSelectorViewProps
|
||||||
|
{
|
||||||
|
addChatEmoji: (emoji: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChatInputEmojiSelectorView: FC<ChatInputEmojiSelectorViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { addChatEmoji = null } = props;
|
||||||
|
const [ selectorVisible, setSelectorVisible ] = useState(false);
|
||||||
|
|
||||||
|
const handleEmojiSelect = (emoji: any) =>
|
||||||
|
{
|
||||||
|
addChatEmoji(emoji.native);
|
||||||
|
setSelectorVisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleSelector = () => setSelectorVisible(prev => !prev);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Popover
|
||||||
|
containerClassName="z-[1070]"
|
||||||
|
content={ <Picker data={ data } onEmojiSelect={ handleEmojiSelect } /> }
|
||||||
|
isOpen={ selectorVisible }
|
||||||
|
positions={ [ 'top' ] }
|
||||||
|
onClickOutside={ () => setSelectorVisible(false) }
|
||||||
|
>
|
||||||
|
<div className="cursor-pointer text-lg select-none px-1" onClick={ toggleSelector }>🙂</div>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -4,6 +4,7 @@ import { createPortal } from 'react-dom';
|
|||||||
import { ChatMessageTypeEnum, GetClubMemberLevel, GetConfigurationValue, LocalizeText, RoomWidgetUpdateChatInputContentEvent } from '../../../../api';
|
import { ChatMessageTypeEnum, GetClubMemberLevel, GetConfigurationValue, LocalizeText, RoomWidgetUpdateChatInputContentEvent } from '../../../../api';
|
||||||
import { Text } from '../../../../common';
|
import { Text } from '../../../../common';
|
||||||
import { useChatInputWidget, useRoom, useSessionInfo, useUiEvent } from '../../../../hooks';
|
import { useChatInputWidget, useRoom, useSessionInfo, useUiEvent } from '../../../../hooks';
|
||||||
|
import { ChatInputEmojiSelectorView } from './ChatInputEmojiSelectorView';
|
||||||
import { ChatInputStyleSelectorView } from './ChatInputStyleSelectorView';
|
import { ChatInputStyleSelectorView } from './ChatInputStyleSelectorView';
|
||||||
|
|
||||||
export const ChatInputView: FC<{}> = props =>
|
export const ChatInputView: FC<{}> = props =>
|
||||||
@@ -119,6 +120,13 @@ export const ChatInputView: FC<{}> = props =>
|
|||||||
setChatValue(value);
|
setChatValue(value);
|
||||||
}, [ setIsTyping, setIsIdle ]);
|
}, [ setIsTyping, setIsIdle ]);
|
||||||
|
|
||||||
|
const addChatEmoji = useCallback((emoji: string) =>
|
||||||
|
{
|
||||||
|
setChatValue(prev => prev + emoji);
|
||||||
|
setIsTyping(true);
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, [ setIsTyping, inputRef ]);
|
||||||
|
|
||||||
const onKeyDownEvent = useCallback((event: KeyboardEvent) =>
|
const onKeyDownEvent = useCallback((event: KeyboardEvent) =>
|
||||||
{
|
{
|
||||||
if(floodBlocked || !inputRef.current || anotherInputHasFocus()) return;
|
if(floodBlocked || !inputRef.current || anotherInputHasFocus()) return;
|
||||||
@@ -235,13 +243,14 @@ export const ChatInputView: FC<{}> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
createPortal(
|
createPortal(
|
||||||
<div className="nitro-chat-input-container flex justify-center items-center relative h-10 border-2 border-black bg-gray-200 pr-2.5 w-full overflow-hidden rounded-lg">
|
<div className="nitro-chat-input-container flex justify-between items-center relative h-10 border-2 border-black bg-gray-200 pr-2.5 w-full overflow-hidden rounded-lg">
|
||||||
<div className="items-center input-sizer">
|
<div className="flex-1 items-center input-sizer">
|
||||||
{ !floodBlocked &&
|
{ !floodBlocked &&
|
||||||
<input ref={ inputRef } className="[font-size:inherit] placeholder-[#6c757d] bg-transparent border-none focus:border-current focus:shadow-none focus:ring-0 " maxLength={ maxChatLength } placeholder={ LocalizeText('widgets.chatinput.default') } type="text" value={ chatValue } onChange={ event => updateChatInput(event.target.value) } onMouseDown={ event => setInputFocus() } /> }
|
<input ref={ inputRef } className="[font-size:inherit] placeholder-[#6c757d] bg-transparent border-none focus:border-current focus:shadow-none focus:ring-0 " maxLength={ maxChatLength } placeholder={ LocalizeText('widgets.chatinput.default') } type="text" value={ chatValue } onChange={ event => updateChatInput(event.target.value) } onMouseDown={ event => setInputFocus() } /> }
|
||||||
{ floodBlocked &&
|
{ floodBlocked &&
|
||||||
<Text variant="danger">{ LocalizeText('chat.input.alert.flood', [ 'time' ], [ floodBlockedSeconds.toString() ]) } </Text> }
|
<Text variant="danger">{ LocalizeText('chat.input.alert.flood', [ 'time' ], [ floodBlockedSeconds.toString() ]) } </Text> }
|
||||||
</div>
|
</div>
|
||||||
|
<ChatInputEmojiSelectorView addChatEmoji={ addChatEmoji } />
|
||||||
<ChatInputStyleSelectorView chatStyleId={ chatStyleId } chatStyleIds={ chatStyleIds } selectChatStyleId={ updateChatStyleId } />
|
<ChatInputStyleSelectorView chatStyleId={ chatStyleId } chatStyleIds={ chatStyleIds } selectChatStyleId={ updateChatStyleId } />
|
||||||
</div>, document.getElementById('toolbar-chat-input-container'))
|
</div>, document.getElementById('toolbar-chat-input-container'))
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -159,4 +159,32 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
color: #419AD2;
|
color: #419AD2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nitro-chat-input-container {
|
||||||
|
.input-sizer {
|
||||||
|
display: inline-grid;
|
||||||
|
vertical-align: top;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
&::after,
|
||||||
|
input {
|
||||||
|
width: auto;
|
||||||
|
min-width: 1em;
|
||||||
|
grid-area: 1 / 2;
|
||||||
|
margin: 0;
|
||||||
|
resize: none;
|
||||||
|
background: none;
|
||||||
|
appearance: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: attr(data-value) ' ';
|
||||||
|
visibility: hidden;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user