From aaf8089ba6f1e146830b20dcebc7783630ed4bfd Mon Sep 17 00:00:00 2001 From: Max Litruv Boonzaayer Date: Wed, 13 May 2026 05:17:23 +1000 Subject: [PATCH] feat: Trim whitespace from message bodies and enhance emoji usage integration --- src/app/components/emoji-board/EmojiBoard.tsx | 25 +++++++++++++++++++ .../components/message/MsgTypeRenderers.tsx | 2 +- src/app/features/room/RoomInput.tsx | 4 +-- src/app/features/room/message/Message.tsx | 21 ++++++++++++++++ src/app/paarrot-api.ts | 2 +- 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/app/components/emoji-board/EmojiBoard.tsx b/src/app/components/emoji-board/EmojiBoard.tsx index bc358f6..825ef58 100644 --- a/src/app/components/emoji-board/EmojiBoard.tsx +++ b/src/app/components/emoji-board/EmojiBoard.tsx @@ -54,6 +54,7 @@ import { import { EmojiBoardTab, EmojiType } from './types'; import { VirtualTile } from '../virtualizer'; +const MOST_USED_GROUP_ID = 'most_used_group'; const RECENT_GROUP_ID = 'recent_group'; const SEARCH_GROUP_ID = 'search_group'; @@ -73,6 +74,7 @@ const useGroups = ( imagePacks: ImagePack[] ): [EmojiGroupItem[], StickerGroupItem[]] => { const mx = useMatrixClient(); + const { getTopEmojis } = useEmojiUsage(); const recentEmojis = useRecentEmoji(mx, 21); const labels = useEmojiGroupLabels(); @@ -81,6 +83,22 @@ const useGroups = ( const g: EmojiGroupItem[] = []; if (tab !== EmojiBoardTab.Emoji) return g; + // Add most-used emojis + const topShortcodes = getTopEmojis(21); + if (topShortcodes.length > 0) { + const mostUsedEmojis = topShortcodes + .map((shortcode) => emojis.find((e) => e.shortcode === shortcode)) + .filter((e): e is IEmoji => e !== undefined); + + if (mostUsedEmojis.length > 0) { + g.push({ + id: MOST_USED_GROUP_ID, + name: 'Most Used', + items: mostUsedEmojis, + }); + } + } + g.push({ id: RECENT_GROUP_ID, name: 'Recent', @@ -187,6 +205,13 @@ function EmojiSidebar({ activeGroupAtom, packs, onScrollToGroup }: EmojiSidebarP return ( + ; - const trimmedBody = trimReplyFromBody(body); + const trimmedBody = trimReplyFromBody(body).trim(); const urlsMatch = renderUrlsPreview && trimmedBody.match(URL_REG); const urls = urlsMatch ? [...new Set(urlsMatch)] : undefined; diff --git a/src/app/features/room/RoomInput.tsx b/src/app/features/room/RoomInput.tsx index 3927305..f5cf99f 100644 --- a/src/app/features/room/RoomInput.tsx +++ b/src/app/features/room/RoomInput.tsx @@ -407,8 +407,8 @@ export const RoomInput = forwardRef( if (plainText === '') return; - let body = plainText; - let formattedBody = customHtml; + let body = plainText.trim(); + let formattedBody = customHtml.trim(); // Apply emoticon conversion if enabled if (autoConvertEmoticons) { diff --git a/src/app/features/room/message/Message.tsx b/src/app/features/room/message/Message.tsx index 759c96d..45ee558 100644 --- a/src/app/features/room/message/Message.tsx +++ b/src/app/features/room/message/Message.tsx @@ -71,6 +71,8 @@ import { ReactionViewer } from '../reaction-viewer'; import { MessageEditor } from './MessageEditor'; import { UserAvatar } from '../../../components/user-avatar'; import { copyToClipboard } from '../../../utils/dom'; +import { useEmojiUsage } from '../../../hooks/useEmojiUsage'; +import { emojis } from '../../../plugins/emoji'; import { stopPropagation } from '../../../utils/keyboard'; import { getMatrixToRoomEvent } from '../../../plugins/matrix-to'; import { getViaServers } from '../../../plugins/via-servers'; @@ -774,6 +776,7 @@ export const Message = as<'div', MessageProps>( const useAuthentication = useMediaAuthentication(); const senderId = mEvent.getSender() ?? ''; const senderPresence = useUserPresence(senderId); + const { getMostUsedEmoji } = useEmojiUsage(); const [hover, setHover] = useState(false); const { hoverProps } = useHover({ onHoverChange: setHover }); @@ -975,6 +978,24 @@ export const Message = as<'div', MessageProps>(
+ {canSendReaction && (() => { + const mostUsedShortcode = getMostUsedEmoji(); + const mostUsedEmoji = mostUsedShortcode + ? emojis.find((e) => e.shortcode === mostUsedShortcode) + : null; + + return mostUsedEmoji ? ( + onReactionToggle(mEvent.getId()!, mostUsedEmoji.unicode)} + variant="SurfaceVariant" + size="300" + radii="300" + title={`Quick react with ${mostUsedEmoji.unicode}`} + > + {mostUsedEmoji.unicode} + + ) : null; + })()} {canSendReaction && (