Add custom emojis
All checks were successful
Build and Release / build-and-release (push) Successful in 10m4s

This commit is contained in:
Bryan1029384756
2026-02-16 21:33:37 -06:00
parent 2b9fd4e7e0
commit b63c7a71e1
10 changed files with 663 additions and 73 deletions

View File

@@ -513,6 +513,7 @@ const ChatArea = ({ channelId, channelName, channelType, username, channelKey, u
const [mentionQuery, setMentionQuery] = useState(null);
const [mentionIndex, setMentionIndex] = useState(0);
const [unreadDividerTimestamp, setUnreadDividerTimestamp] = useState(null);
const [reactionPickerMsgId, setReactionPickerMsgId] = useState(null);
const messagesEndRef = useRef(null);
const messagesContainerRef = useRef(null);
@@ -536,6 +537,7 @@ const ChatArea = ({ channelId, channelName, channelType, username, channelKey, u
const members = useQuery(api.members.getChannelMembers, channelId ? { channelId } : "skip") || [];
const roles = useQuery(api.roles.list, channelType !== 'dm' ? {} : "skip") || [];
const myPermissions = useQuery(api.roles.getMyPermissions, currentUserId ? { userId: currentUserId } : "skip");
const customEmojis = useQuery(api.customEmojis.list) || [];
const { results: rawMessages, status, loadMore } = usePaginatedQuery(
api.messages.list,
@@ -765,6 +767,7 @@ const ChatArea = ({ channelId, channelName, channelType, username, channelKey, u
setEditingMessage(null);
setMentionQuery(null);
setUnreadDividerTimestamp(null);
setReactionPickerMsgId(null);
onTogglePinned();
}, [channelId]);
@@ -1013,7 +1016,7 @@ const ChatArea = ({ channelId, channelName, channelType, username, channelKey, u
if (!match) return;
const name = match[1];
const emoji = AllEmojis.find(e => e.name === name);
const emoji = customEmojis.find(e => e.name === name) || AllEmojis.find(e => e.name === name);
if (!emoji) return;
const img = document.createElement('img');
@@ -1278,7 +1281,7 @@ const ChatArea = ({ channelId, channelName, channelType, username, channelKey, u
deleteMessageMutation({ id: msg.id, userId: currentUserId });
break;
case 'reaction':
addReaction({ messageId: msg.id, userId: currentUserId, emoji: 'heart' });
setReactionPickerMsgId(msg.id);
break;
}
setContextMenu(null);
@@ -1382,6 +1385,7 @@ const ChatArea = ({ channelId, channelName, channelType, username, channelKey, u
isMentioned={isMentioned}
isOwner={isOwner}
roles={roles}
customEmojis={customEmojis}
isEditing={editingMessage?.id === msg.id}
isHovered={hoveredMessageId === msg.id}
editInput={editInput}
@@ -1389,7 +1393,7 @@ const ChatArea = ({ channelId, channelName, channelType, username, channelKey, u
onHover={() => setHoveredMessageId(msg.id)}
onLeave={() => setHoveredMessageId(null)}
onContextMenu={(e) => { e.preventDefault(); window.dispatchEvent(new Event('close-context-menus')); setContextMenu({ x: e.clientX, y: e.clientY, messageId: msg.id, isOwner, canDelete }); }}
onAddReaction={(emoji) => { addReaction({ messageId: msg.id, userId: currentUserId, emoji: emoji || 'heart' }); }}
onAddReaction={(emoji) => { if (emoji) { addReaction({ messageId: msg.id, userId: currentUserId, emoji }); } else { setReactionPickerMsgId(reactionPickerMsgId === msg.id ? null : msg.id); } }}
onEdit={() => { setEditingMessage({ id: msg.id, content: msg.content }); setEditInput(msg.content); }}
onReply={() => setReplyingTo({ messageId: msg.id, username: msg.username, content: msg.content?.substring(0, 100) })}
onMore={(e) => { const rect = e.target.getBoundingClientRect(); setContextMenu({ x: rect.left, y: rect.bottom, messageId: msg.id, isOwner, canDelete }); }}
@@ -1412,6 +1416,22 @@ const ChatArea = ({ channelId, channelName, channelType, username, channelKey, u
</div>
</div>
{contextMenu && <MessageContextMenu x={contextMenu.x} y={contextMenu.y} isOwner={contextMenu.isOwner} canDelete={contextMenu.canDelete} onClose={() => setContextMenu(null)} onInteract={(action) => handleContextInteract(action, contextMenu.messageId)} />}
{reactionPickerMsgId && (
<div style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, zIndex: 999 }} onClick={() => setReactionPickerMsgId(null)}>
<div style={{ position: 'absolute', right: '80px', top: '50%', transform: 'translateY(-50%)' }} onClick={(e) => e.stopPropagation()}>
<GifPicker
initialTab="Emoji"
onSelect={(data) => {
if (typeof data !== 'string' && data.name) {
addReaction({ messageId: reactionPickerMsgId, userId: currentUserId, emoji: data.name });
}
setReactionPickerMsgId(null);
}}
onClose={() => setReactionPickerMsgId(null)}
/>
</div>
</div>
)}
{inputContextMenu && <InputContextMenu x={inputContextMenu.x} y={inputContextMenu.y} onClose={() => setInputContextMenu(null)} onPaste={async () => {
try {
if (inputDivRef.current) inputDivRef.current.focus();