From 78f9b848509663c876aabb098e0fd4fb99d56835 Mon Sep 17 00:00:00 2001 From: heaven Date: Wed, 3 Jun 2026 13:25:41 +0300 Subject: [PATCH] feat(message): surface one-tap quick-reactions inline in the hover action rail --- src/app/features/room/message/Message.tsx | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/app/features/room/message/Message.tsx b/src/app/features/room/message/Message.tsx index ab2262ab..32c6ba20 100644 --- a/src/app/features/room/message/Message.tsx +++ b/src/app/features/room/message/Message.tsx @@ -116,6 +116,46 @@ export const MessageQuickReactions = as<'div', MessageQuickReactionsProps>( } ); +// Default reactions shown in the hover rail before a user has built up any +// recent-emoji history, so the "быстрый рельс" always offers one-tap reactions. +const RAIL_DEFAULT_REACTIONS: { unicode: string; shortcode: string }[] = [ + { unicode: '👍', shortcode: 'thumbsup' }, + { unicode: '❤️', shortcode: 'heart' }, + { unicode: '😂', shortcode: 'joy' }, +]; + +type RailQuickReactionsProps = { + onReaction: (key: string, shortcode?: string) => void; +}; +// Inline quick-reactions surfaced directly in the hover action rail — react in +// one tap without opening the emoji board. Mounts ONLY inside the +// conditionally-rendered rail (one row at a time), so there is no per-row cost. +function RailQuickReactions({ onReaction }: RailQuickReactionsProps) { + const mx = useMatrixClient(); + const recent = useRecentEmoji(mx, 3); + const items = + recent.length > 0 + ? recent.slice(0, 3).map((e) => ({ unicode: e.unicode, shortcode: e.shortcode })) + : RAIL_DEFAULT_REACTIONS; + return ( + <> + {items.map((emoji) => ( + onReaction(emoji.unicode, emoji.shortcode)} + > + {emoji.unicode} + + ))} + + ); +} + export const MessageAllReactionItem = as< 'button', { @@ -914,6 +954,14 @@ const MessageInner = as<'div', MessageProps>(
+ {canSendReaction && ( + { + const evtId = mEvent.getId(); + if (evtId) onReactionToggle(evtId, key, shortcode); + }} + /> + )} {canSendReaction && (